miércoles, 29 de mayo de 2013

JML (Java Modeling Language)

JML (Java Modeling Language)

JML es un lenguaje de modelado que permite realizar el Diseño por Contrato (Desing by Contract DBC) en java,  DBC es una metodología de desarrollo, que consiste en que  las clases y sus clientes tienen un contrato entre sí, los clientes antes de invocar un método de la clase deben garantizar ciertas condiciones de los datos de entrada y la clase debe garantizar cierto comportamiento y ciertas condiciones después de la ejecución de cada uno de sus  métodos, si alguno de los actores incumple con estas condiciones se produce un error o fallo del programa. Estas condiciones que el cliente y la clase deben cumplir se expresan en forma de Pre-Condiciones y Post-Condiciones en un lenguaje formal, por medio de anotaciones en el código java.

En resúmen, en la programación orientada por contrato, el cliente asegura la precondición y asume que la postcondición se cumple, y el método asume como cierta la precondición y asegura la postcondición.

Las especificaciones de JML, se escriben como comentarios especiales en java que empiezan con /@* y se cierran @*/, JML utiliza la cláusula requires para especificar las pre -condiciones u obligaciones del cliente y la cláusura ensures para las post-condiciones u obligaciones de la clase. JML debe validar que la pre-condición se cumpla  antes de llamar el método y garantizar qe la post-condición sea verdadera después de la ejecución del método. JML también permite expresar aserciones assert e invariantes invariant.

La sintaxis de JML es similar a la de java, y provee varios operadores que pueden ser utilizados: \result, \old, \sum, \forall 

JML también puede ser usado como documentación, puesto que la especificación escrita en JML, proporciona la claridad necesaria de lo que el método debe recibir y los resultados que debe arrojar, existe una herramienta denominada JML Doc, que genera la documentación con base en las anotaciones JML, una ventaja adicional de esta documentación además de ser breve y consistente, es que no tiene varias interpretaciones, puesto que la especificación formal no da lugar a ambigüedades.

JML evita la realización de validaciones innecesarias de los datos de entrada dentro de los métodos, puesto que la validez de los mismos están dados por las precondiciones establecidas, así mismo, facilita determinar si las fallas que se presentan corresponden a errores de implementación de los métodos o a fallas en los datos de entrada.


Conclusiones acerca de JML.

Aunque el alcance que se pretende obtener con la especificación del lenguaje JML, es muy amplio e interesante, las herramientas que lo implementan, aún son inmaduras y presentan muchos errores e inconsistencias, en el caso mío probé el plugin JML para eclipse y el verificador Z3_N3.

La verificación estática, puede detectar algunos posibles problemas en la codificación de los métodos, pero sigue siendo en tiempo de ejecución que se pueden detectar los errores de incumplimiento en los contratos de pre y/o post condiciones, lo cual no proporciona un valor agregado, puesto que sin el uso de JML, de todos modos el software lanzaría una excepción, lo que logramos en JML es cambiar la excepción que lanzaría el programa por una asociada a JML.

El ejercicio de escribir las condiciones del contrato, hace que el programador sea más conciente del comportamiento que debe tener la clase que va a desarrollar.

El uso de JML, invita a usar una metodología TDD, porque es muy importante escribir las pruebas o reglas del contrato de servicio de la clase en términos de pre y postcondiciones, antes de escribir el código que implementa la funcionalidad.

TDD, ATDD e Integración Continua

TDD (Test Driven Development)

TDD (Test Driven Development - Desarrollo Guiado por Pruebas), es una técnica de desarrollo de software, que consiste en iniciar el proceso escribiendo las pruebas que el software debe pasar, antes de empezar al escribir el código que las satisface, se diferencia del enfoque tradicional, en el cual primero se escribía y código y luego se escribían las pruebas para verificarlo.

La definición de las pruebas se hace con base en los requerimientos de la clase que se está implementando y las mismas se escriben utilizando herramientas de pruebas unitarias xUnit, luego se escribe la especificación de la clase acorde a la prueba diseñada, se ejecuta la prueba, la cual debe fallar, posteriormente se implementa el código, cuando se ejecuta nuevamente la prueba ésta debe pasar satisfactoriamente. El ciclo TDD se muestra en el siguiente diagrama de actividades:




El código debe pasar diferentes casos de prueba, el abordaje del desarrollo es ir implementando el código necesario, para ir pasando cada caso de prueba que se haya definido de forma gradual, esto hace necesario ir modificando el código desarrollado a medida que se van verificando cada uno de los casos de prueba, a este proceso de modificar el código sin cambiar la interfaz de los métodos o clases se denomina Refactorizar.

Qué se busca TDD.

  • Escribir la menor cantidad de código posible, puesto que solo se debe escribir el código necesario, para satisfacer las pruebas diseñadas.
  • Favorecer que el diseño de las clases, cumpla con los principios de alta cohesión  y bajo acoplamiento.
  • Garantizar la calidad del software que se produce.
  • Minimizar el esfuerzo de los desarrolladores, puesto que el esfuerzo de codificación se centra en escribir solo el código necesario para satisfacer las pruebas, sin distraerse en otros temas.
  • Propende por la obtención de un código de calidad, limpio, claro, cada pasada dentro del proceso de refactorización, debe ir acompañada de un refinamiento del código y del algoritmo que se está implementando.
  • Reducir a cero el uso de las herramientas de debug.
  • Proporcionar una retroalimentación temprana, para la detección y corrección, de errores de codificación y diseño.

Desventajas de TDD

Lo que escribo a continuación es una posición personal de reflexión acerca de TDD, lo que a mi juicio pueden ser las desventajas de este enfoque.


  • El hecho de escribir las pruebas antes que el código y hacer que éste último las satisfaga, no es garantía de que haya un sesgo tanto en la selección de las pruebas como en el desarrollo mismo del código, sobretodo si es  la misma persona quien realiza los dos procesos. Para evitar esto, se podría apoyar o más bien complementar con técnicas como eXtreme Programming, donde haya una segunda persona que diseñe las pruebas o que verifique que las mismas sean objetivas respecto al producto que se desea obtener.
  • Es una técnica que requiere disciplina por parte de quien decide aplicarla, y es muy fácil saltarla, o no aplicarla con la debida rigurosidad.
  • Para ciertas funcionalidades, es muy difícil hacer un set de pruebas suficiente, que garantice que todos los casos posibles están cubiertos, en estos casos aunque una adecuada selección de los casos de pruebas puede ayudar, no se puede garantizar un cubrimiento total ni descartar que el código es correcto para todos los casos.
  • En el caso de las interfaces de usuario, esta técnica no es de fácil aplicación, puesto que el diseño de estas pruebas, requiere de tiempo y herramientas especiales, y la idea de TDD como apoyo a las metodologías ágiles, es propender por ciclos cortos de desarrollo y pruebas.

ATDD (Aceptance Test Driven Development)


ATDD (Aceptance Test Driven Development - Desarrollo dirigido por Pruebas de Aceptación), también conocida como BDD (Behavior Driven Development - Desarrollo Dirigido por el comportamiento)  Es una práctica donde los criterios de aceptación del software, se socializan y discuten con todo el equipo de desarrollo, luego estos criterios se aterrizan en ejemplos concretos antes de abordar las tareas de diseño y codificación,  lo que se pretende es que todos los miembros del equipo tengan la misma percepción del problema y de la solución propuesta, eta técnica es fundamental cuando se aplican metodologías ágiles de desarrollo, porque el inicio de cada ciclo debería comenzar con una discusión acerca del problema, de las estrategias propuestas para abordarlo y de lo que se espera obtener al finalizar el ciclo de desarrollo.

Al igual que TDD, ATDD exige la definición de las pruebas antes de empezar a codificar, pero estas pruebas se expresan en términos del comportamiento esperado del software, es decir, que se deben definir las pruebas de aceptación a nivel funcional antes de escribir el código. Para la codificación se sugiere que se apoye en la técnica TDD como un complemento de ATDD.


Figura que muestra el ciclo ATDD.


El ciclo ATDD consta de 4 fases:

1. Discusión: En las reuniones de planeación, se discute con el equipo de trabajo, las historias de usuario o casos de uso que se van abordar durante ese ciclo, de tal manera que todo el equipo conozca en detalle el producto que se espera obtener al finalizar el ciclo en términos de requerimientos funcionales. Como esta técnica es parte de las metodologías de desarrollo ágil, en estas reuniones de planeación, generalmente se evalúan los resultados del ciclo de desarrollo anterior, se hace la retroalimentación y se discuten los refinamientos funcionales del software que se abordarán en el ciclo que comienza.

2. Destilar:  Una vez se han discutido las pruebas funcionales de aceptación y el comportamiento esperado del software para el final del ciclo que comienza, se deben capturar estas en un formato de pruebas, para posteriormente ser aplicadas al software y verificar que él mismo las satisface, este formato debe ser público, compartido y aprobado por todo el equipo.

3. Desarrollar el código: Se debe abordar el desarrollo del código, éste puede estar apoyado en técnicas TDD con pruebas unitarias, pero el equipo de desarrollo, debe también ir verificando el software contra las pruebas funcionales diseñadas, si el software no cumple se debe refactorizar hasta que pueda pasar las pruebas funcionales.

4. Producir un Demo: Con una determinada frecuencia se debe integrar el código producido por los diferentes miembros del equipo de desarrollo, con el fin de producir una versión preliminar del software y aplicarle el set de pruebas diseñado previamente, para ver si pasa o no las pruebas funcionales de aceptación, si una o varias de las pruebas fallan, se vuelve al proceso de codificación para hacer los ajustes correspondientes, y se repite el proceso hasta que el software pase las pruebas de aceptación.

TDD y ATTD, son procesos similares, aunque con enfoques distintos, ATDD apunta al cumplimiento de requerimientos funcionales o de comportamiento del software de manera general, mientras que TDD está más orientado a las pruebas detalladas sobre los diferentes métodos de las clases, estas dos técnicas son complementarias y pueden o no ser aplicadas de forma simultánea.

La siguiente gráfica muestra la integración entre ATDD y TDD.









Continuous Integration (Integración Contínua)

La integración continua es una técnica que consiste en hacer integraciones de un proyecto con la mayor frecuencia posible, con el fin de detectar errores y problemas de forma temprana y tomar las acciones necesarias para corregirlas.  La integración consiste en la compilación de todo el proyecto y la ejecución de las pruebas sobre el mismo.

Para que la integración continua sea posible, se requiere de herramientas que permitan automatizar el proceso de integración, a estas herramientas se les conoce como servidores de integración continua, existen muchos como Jenkins, Hudson, Cruise Control, también se hace necesario un sistema de control de versiones que permita almacenar  de forma centralizada  las versiones que se van produciendo del software de tal forma que de ahí se pueda obtener la versión actualizada que va a ser compilada y probada. otro componente importante son las herramientas de pruebas que se integran a los servidores de integración continua, para permitir la automatización de las pruebas.

El proceso de integración continua, permite además detectar errores de integración de componentes, dependencias entre librerías y componentes, además que garantiza que desde etapas tempranas de desarrollo, se construyan los scripts de instalación del producto cuando este vaya a ser puesto en un ambiente de producción.

En la siguiente gráfica muestra el proceso de integración continua.



Aunque las tres técnicas mencionadas en este blog, pueden ser utilizadas de forma independiente, el uso de las tres de forma conjunta, se constituye en una buena práctica que permite garantizar que el software producido tenga una alta calidad y cumpla con las expectativas para las cuales fue construido. Estas técnicas, son fundamentales cuando se utilizan metodologías ágiles de desarrollo de software.



Referencias: