En la cancha

En la cancha
Historias desde el frente

Recetarios

Recetarios
Guías prácticas de certificación

Certificación Sun

Certificación Sun
Certificación Java EE

Certificación IBM

Certificación IBM
Certificación en UML, RUP y SOA

Arquitectura Java EE y Spring Framework

lunes 27 de diciembre de 2010

Hace unos meses -en mi anterior trabajo- realizé una presentación al equipo sobre fundamentos de arquitectura y su relación con Spring Framework. La presentación es fundamentalmente teórica así que van a encontrar poco código;  y consideré compartirla dado que estamos en campaña de resucitar el blog xD.

Saludos, y hasta otra!

GWT para novatos

jueves 23 de diciembre de 2010

GWT - Una introducción
View more presentations from Carlos Gavidia.

Me encargaron en el trabajo realizar una charla introductoria sobre GWT para el equipo. Después de leer durante algunos días -dado que soy un novato en la materia- preparé la presentación que adorna este post. La pongo a disposición de los interesados.

Saludos, y hasta otra!

Spring Community Day 2010

miércoles 24 de noviembre de 2010


Creo que debo empezar esto post disculpándome por la ausencia prolongada: He andado tan ocupado últimamente que hasta se han reducido mis horas de sueño. Sin embargo, prometo encontrar espacio para actualizar el blog y evitar que se llene de telarañas. Palabra.

Luego, quería invitar a los lectores peruanos al Spring Community Day 2010 que organiza  la comunidad Spring Perú. Habrá ponencias técnicas, presentación de casos prácticos, espacios de discusión y el infaltable coffee break (además, este blogger tendrá a su cargo una charla sobre Spring Web Services xD).

El evento se realizará el 27 de Noviembre (este sábado) en el Campus de la UPC. Para ingresar es necesario colaborar con 10 soles que serán destinados íntegramente a financiar una Misión de Navidad para los niños del Asentamiento Humano San Alvino.

Están todos cordialmente  invitados.

Cohesión y el principio de responsabilidad única

viernes 1 de octubre de 2010

Imaginemos que nuestro siempre creativo usuario nos solicita un proceso que genere cierto reporte Excel con información de base de datos y se lo coloquemos en un servidor FTP para que lo pueda descargar luego. Dado que -para variar- quiere el reporte para ayer, construimos la siguiente solución apresurada:

Diseño improvisado
Terminamos, el usuario lo prueba, mira que es bueno y nos felicita. 

Pasan unos días y el mismo usuario nos pide una aplicación para que pueda colocar algunos documentos PDF en el mismo  servidor FTP. ¿Por qué no utilizamos a nuestra clase AdministradorDeReportes junto a su método enviarArchivoFTP()? Podríamos hacerlo, pero nuestra clase para poder ser compilada depende también de POI y de JDBC lo que le daría una carga extra de 5 megas a nuestro sencilla aplicación para PDF's. Esto pone en evidencia que nuestro diseño original tiene algunos problemitas.

La cuestión es que nuestra clase AdministradorDeReportes tiene la responsabilidad de conectarse a base de datos, de generar un archivo Excel con esta data y de colocar el archivo en el servidor FTP; y si uno quiere reutilizar este componente pues no le queda otra que adquirir el paquete completo de responsabilidades que esta clase posee. ¿Y si queremos otra clase que genere el mismo reporte en HTML en un browser? Sería bastante conveniente utilizar el método obtenerInformacionBD ()de AdministradorDeReportes, pero una vez más tenemos el problema que esta clase tiene dependencias que no necesitamos (ni el API para conexión a FTP ni la generación de Excel). Dado que es obvio que nuestro diseño inicial tiene problemas, corregimos y planteamos lo siguiente:

Después de recapacitar, planteamos esto
Con esta nueva solución, la aplicación para transferir archivos PDF solamente debería utilizar la clase ClienteFTP sin la sobrecarga del resto de API's que no necesita; y si se requiere el reporte HTML que planteábamos sólo dependeríamos de la clase ExtractorDeDatos. Este diseño tiene la peculiaridad que nuestras clases están bastante especializadas y tienen una única responsabilidad específica: Por ejemplo, la clase ClienteFTP se ocupa de la conexión con el servidor FTP y nada más. Es esta especialización lo que nos da bastante flexibilidad para la reutilización, que es lo que trata de decirnos Robert C. Martin con su Principio de Responsabilidad Única:

“Nunca debe de haber más de una razón para que una clase sea modificada”

Si vemos nuestro diseño inicial, la clase AdministradorDeReportes debería modificarse si es que se requieren datos extra en el reporte. Esta clase también debería modificarse si quieren que el reporte Excel tenga otros colores. Y si quisiéramos optimizar la conexión con el servidor FTP nuestra clase AdministradorDeReportes también debería pasar por mantenimiento, por lo que tenemos un ejemplo bastante claro de como violentar este principio. Ahora, en nuestra versión mejorada del diseño hemos transferido estas responsabilidades a las clases ExtractorDeDatos, ClienteFTP y ReporteadorExcel; de modo que cada cambio que mencionábamos  ahora impacta solamente en una clase de nuestro programa.

Casos de uso y descomposición funcional

jueves 16 de septiembre de 2010

Imaginemos que estamos capturando requerimientos para una página web que tiene que incluir un foro. Hablamos con el usuario líder, y nos cuenta que es necesario que  el administrador del sistema esté en capacidad de bloquear el acceso a los usuarios que repetidamente muestren un comportamiento inadecuado en el foro (escriban en mayúsculas, resuciten threads antiguos, utilicen palabras malsonantes y otras exquisiteces de los foristas). Después de la entrevista vamos a nuestra oficina, iniciamos nuestra herramienta CASE y aplicamos la técnica de casos de uso según lo que nos enseñaron en la universidad para producir este diagrama:

Diagrama construido con StarUML

Esta primera versión tiene algunos inconvenientes. Por definición, un caso de uso debe producir valor para los actores con los que interactúa (según Kurt Bittner) y no creo que el Administrador encuentre mucho valor a la tarea de "Buscar Usuarios" o de "Mostrar Información de Usuario". A menos que se trate de reportes -y no es el caso- el Administrador del Foro no va a entrar a nuestra aplicación sólamente a realizar una búsqueda o a consultar información de un usuario, sino lo que desea es estar en capacidad de bloquear a los usuarios rebeldes. Por ahí ya tenemos problemas.

Ahora, tal vez nuestra intención inicial de agregar tantos casos era para poner en evidencia que para bloquear a un usuario es necesario primero buscarlo, luego mostrar un formulario con su información básica, después  ingresar los motivos por los que se le va a bloquear para finalmente realizar el bloqueo. Si ese fue el caso caimos en otro error, dado que los casos de uso no "invocan" a otros casos de uso y mucho menos se comunican entre ellos. Realizar esto es intentar convertir los casos de uso en funciones, lo que nos lleva al problema de la descomposición funcional: Descomponer un problema en partes pequeñas y aisladas entre sí, que trabajando juntas nos proveen de una funcionalidad del sistema.

La descomposición funcional de casos de uso hace que estos pierdan contexto, como el caso de uso "Asignar motivos de bloqueo" que no tiene sentido sin el resto de casos de uso del diagrama. También está el tema del valor para los actores que mencionábamos al inicio, el  mismo caso de uso "Asignar motivos de bloqueo" no le va a servir al Administrador si es que el usuario al final no termina bloqueado.

Ahora ¿qué hacemos para no caer en esto?. Navegando me topé con un documento de Kurt Bittner en el que nos sugiere tres cosas:

  1. Centrarse en casos de uso que provean valor real a los stakeholders. En el caso de nuestra administrador, buscando usuarios no gana mucho.
  2. Limitar el uso de "includes" sólamente para representar descripciones comunes entre caso de uso. Y usarlas con muchísimo cuidado.
  3. Limitar el uso de "extends" sólamente para agregar comportamientos opcionales a casos de uso existentes que por si mismos generen valor. Personalmente, no me gusta mucho utilizar esta relación.

Entonces, sabiendo esto borramos nuestro primer borrador defectuoso y lo cambiamos por este mucho más simple y elegante:

Este diagrama también lo hice con StarUML


En la especificación de caso de uso ya podemos explayarnos describiendo el flujo deseado.  Recuerden que un modelo de casos de uso es principal y mayoritariamente texto. Eso sería todo en esta entrega, hasta otra!

No hables con extraños, o la Ley de Deméter

martes 10 de agosto de 2010

Imagen: Autorretrato con Sombrero de Paul Gauguin

Desde los primeros cursos de orientación a objetos de la universidad he escuchado que al programar se debe procurar siempre "niveles bajos de acoplamiento y altos de cohesión". Recién ahora que estoy ojeando The Pragmatic Programmer de  Andrew Hunt y David Thomas el tema del acoplamiento me ha quedado claro y quería compartir con ustedes mis hallazgos.

Es más fácil entender este concepto si vemos un programa que no lo aplica. El libro propone este ejemplo:

          
     public void plotDate(Date aDate, Selection aSelection) { 
       TimeZone tz = aSelection.getRecorder().getLocation().getTimeZone(); 
       ... 
     } 

La clase que contiene al método plotDate está altamente acoplada, dado que su estructura actual depende de otras tres clases: Selection, Recorder y Location. Esto nos pone en una situación delicada, dado que un cambio en cualquiera de esas tres clases tendría impacto en nuestro programa. Por ejemplo, si Location hace que el método getTimeZone sea privado, nuestro método tendría que redefinirse, y lo mismo pasaría con modificaciones a cualquiera de las otras clases dependientes. Es por eso que se recomienda mantener los niveles de acoplamiento mínimos (es decir, depender del mínimo número de clases) para evitar que las ocurrencias del resto deshagan nuestro trabajo. Si bajamos el nivel de acoplamiento de clase de arriba, nos quedaría algo así:

      
     public void plotDate(Date aDate, TimeZone aTz) { 
       ... 
     } 

Ahora nuestro método espera que le llegue una instacia de TimeZone como parámetro y ya no la obtiene desde un objeto Selection. De este modo hemos reducido las dependencias de tres a una clase (sólamente TimeZone ), siendo responsabilidad de la clase cliente la obtención de la instancia de TimeZone que necesitamos. Esta clase cliente nos puede invocar de esta manera:

     plotDate(someDate, someSelection.getTimeZone()); 

El libro menciona que los síntomas clásicos de un programa altamente acoplado son que los cambios más simples impactan en componentes que no deberían, y que los programadores se resisten a darle mantenimiento al sistema por miedo a echar a perder algo.

Descrito al problema, ahora toca describir la solución.

La ley de Deméter -inventada en 1987 en la  Northeastern University - tiene como objetivo el minimizar las dependencias entre las clases de un programa dado, previniendo el acceso a objetos externos para consumir sus métodos. En resumen, la ley establece lo siguiente:

Cualquier método de un objeto debe invocar solamente a los siguientes métodos:

  • Sus propios métodos
  • Los métodos de los objetos que ha recibido como parámetros
  • Los métodos de los objetos que posee como atributos
  • Los métodos de los objetos declarados como variables locales 


Con esto aseguramos el mínimo de dependencias posibles. Los dejo con una imagen extraída del libro que ilustra el concepto:

Imagen tomada de The Pragmatic Programmer de Andrew Hunt y David Thomas

Hasta otra!