Israel García

por Israel García

Consultor de desarrollo en Microsoft Servicios

http://blogs.technet.com/israelg

Diseño de Arquitectura en Proyectos Cortos

Hoy en día muchos proyectos tienen necesidades a cubrir en cortos plazos de tiempo y tratando de reducir los esfuerzos para que los clientes, nuestra empresa, etc., pueda hacer uso del software desarrollado lo antes posible. En muchos casos el uso de las herramientas adecuadas como Visual Studio junto con tecnologías como .NET nos ayuda en esta labor de acortar los plazos, pero muchas veces podemos estar en el camino equivocado al pensar que avanzar sin más es la mejor alternativa.

Los modelos de Arquitectura, históricamente se han visto como un elemento útil para grandes aplicaciones dentro de las organizaciones, y en el desarrollo de productos complejos, pero ha sido más difícil ver este nivel de modelado por las necesidades de tiempo en el negocio. La percepción es que el esfuerzo para este tipo de modelos es alto y que requiere mucho tiempo para obtener un beneficio en muchos casos a largo plazo, pero la pregunta que me hago en ciertos momentos es: ¿Cómo sé que este es el camino y que no tendré que volver hacia atrás?

 

¿Qué dice la experiencia del día a día?

Mi experiencia me dice que obtener el diseño perfecto es tan difícil como acertar en el diseño sobre la marcha, por lo que la opción parece pasar por encontrar el punto medio. Al fin y al cabo, si nos paramos un minuto a pensar, que costaría coger el código que hemos construido para una aplicación y organizarlo de manera que nos sea eficiente desde el punto de vista de diseño, ¡si el código va a ser el mismo!.

Como ejemplo de aplicación sencilla que no abordaríamos con un modelo de Arquitectura, podríamos escoger La Web del Video Club (un clásico), en donde la funcionalidad es muy concreta y la complejidad aparentemente baja:

La idea consiste en que desde la Web del Videoclub, un cliente pueda:

  • Consultar los títulos y su disponibilidad
  • Reservar uno o más títulos para una fecha.
  • Emitir el ticket de reserva para ir a recogerlos o enviarlos a casa.
  • Controlar que títulos tiene cada usuario.

A la hora de abordar esta aplicación podemos seguir el método directo en donde:

  • Construimos un Web Site
  • En dicho Web Site definimos las pantallas de consulta e introducción de datos.
  • Enlazamos dichas pantallas con una Base de Datos o un Web Service, ya sea directamente o mediante componentes que hacen determinadas tareas de lógica de negocio.
  • Codificamos las acciones de usuario contra los controles Web
  • Hacemos pruebas de la misma, y…
  • Ya tenemos nuestra aplicación.

Nuestros jefes estarían entusiasmados con su nueva aplicación, y todos son días felices hasta que…pasen algunas de estas 3 situaciones:

  • Nos llaman para decirnos que la aplicación está dando fallos o responde lentamente.
  • Nuestro jefe nos comenta que quiere algunas mejoras como la gestión de clientes, o nuevos productos, etc.
  • Un cliente nos llama para preguntarnos qué pasa con su pedido.

En ese momento, nos daremos cuenta de que nos faltaba algún mecanismo para controlar donde falla la aplicación (Instrumentación), o que ampliar la funcionalidad nos va a costar tener que modificar el modelo de datos y eso puede afectar a la aplicación, o que no podemos hacer seguimiento de los pedidos de un cliente, etc.

A esto, además, tenemos que añadirle, que cualquier cambio en nuestras capas de arquitectura puede afectar a las demás, lo que complica aún más el tomar decisiones, puesto que ya no tienes que tener en cuenta solo el cambio que vas a realizar, sino, si afectará a alguna funcionalidad de las existentes.

En definitiva, comienzan los problemas y nuestros días soleados se convierten en días y noches trabajando (porque además si lo hicimos tan rápido, no podemos tardar mucho) hasta conseguir lo que nos falta.

 

Ahora volvamos hacia atrás en el tiempo…

Imaginemos que empezamos de nuevo el desarrollo, y que tuviésemos en cuenta las siguientes premisas:

  • Cada módulo, servicio, componente o clase que desarrollemos solo debería ser responsable de una tarea dentro del sistema.
  • Detectar qué conceptos y qué funcionalidad es core de negocio y cual es una funcionalidad adyacente.
  • Aplicar patrones de diseño y refactoring, para desacoplar el diseño y facilitar los cambios.
  • Construir una implementación lo más sencilla posible.

Estas premisas no solo se alinean con paradigmas de Arquitectura como SOA, sino que están muy ligadas con modelos DDD en donde lo que importa es conocer el negocio, no como lo vamos a construir (la tecnología). Con estas premisas podremos definir los siguientes elementos dentro del diseño:

  • 3 Servicios: Control de Usuarios, Catálogo de Títulos (Consulta de Títulos, Añadir/Editar/Borrar un título), Control de Alquiler (Crear alquiler, Consulta de Alquiler, Eliminar Alquiler).
  • 4 Entidades de negocio: Titulo, Usuario, Alquiler, Tipos de Medios.
  • Las diferentes pantallas de usuario que cubren la funcionalidad.

Ahora procedemos a la implementación de nuestra aplicación:

  • Implementamos las pantallas, para que nuestro jefe la puedan ver y probar (Esto además nos servirá para crear las pertinentes pruebas funcionales Web)
  • Definimos e implementamos las interfaces de los servicios y las entidades.
  • Haciendo uso de Visual Studio y de Entity Framework, construimos cada servicio (no servicios Web) contra la BBDD (basado en procedimientos almacenados idénticos a los que ya teníamos en la opción anterior).
  • Conectamos nuestra aplicación Web con los servicios y delegamos la funcionalidad de cada pantalla contra la funcionalidad de los servicios.
  • Integramos la funcionalidad adyacente, como Seguridad (Logon en la aplicación por ahora) e Instrumentación, tanto técnica como de negocio (podemos hacer uso de Policy Injection).
  • Hacemos las pruebas, y…
  • Ya tenemos la aplicación lista!

Ahora volvemos a la parte en que nuestros jefes nos halagany están contentísimos, pero para no ser ventajistas nos vamos a situar en el momento en el que:

  • Ese cliente que quiere saber qué pasó con su pedido, ahora podrás contestarle con la información que has recopilado en el servicio de Alquiler, o mediante los mecanismos de Instrumentación.
  • Ese momento en el que tu jefe quiere más información de los clientes, y que puedes extraer del Servicio de Alquiler y del Catálogo de Usuarios.
  • Cuando la aplicación va lenta y vas a poder hacer pruebas por separado de cada módulo.
  • O rizando el rizo, cuando a tu jefe le da por crear una segunda tienda y le da por pedirte que quiere un solo sistema, ágil y escalable, y tú solo tendrás que convertir tu servicios en Web Services (algo sencillo gracias a WCF).

En base a mi experiencia en aplicar este modelo de trabajo, hemos podido construir soluciones que han evolucionado a partir de su diseño inicial, sin que por ello hayan requerido un mayor esfuerzo. Al fin y al cabo, el código que requiere nuestra solución es el mismo, la tecnología de base es la misma, el cambio principal es como lo organizamos y como se puede ver en el ejemplo dicho cambio tiene que ver más con entender los elementos del negocio.

 

Recursos de Apoyo: Patrones de Diseño, Refactoring, Pruebas

¿Qué pasos podemos dar con el fin de que nuestros diseños iniciales puedan evolucionar fácilmente y sin requerir grandes esfuerzos? Una vez que nuestra aplicación se ha construido y que tenemos un diseño de partida, podemos hacer uso de ciertos conceptos más avanzados, que pueden complementar y ayudar en el mantenimiento y evolución de nuestras aplicaciones:

  • Patrones de Diseño: Siendo un elemento bastante conocido y del que podemos encontrar multitud de referencias, en mi opinión, es más importante que conocerlos al detalle, entender su filosofía. Los Patrones de Diseño ayudan a desacoplar el código siguiendo diferentes estrategias, siempre que se usen con criterio y donde tienen sentido. El exceso como todo, puede ser dañino.
  • Refactoring: Mediante las técnicas de refactoring, podemos realizar cambios a la aplicación para mejorar su diseño una vez codificada, controlando el impacto de dichos cambios. El refactoring en combinación con los patrones de diseño, es una herramienta muy potente para evolucionar un diseño.
  • Pruebas: Las pruebas unitarias y funcionales son la base que nos permite saber que una aplicación funciona después de realizar algún cambio. Con la estrategia descrita, es fácil construir un modelo de pruebas en base a nuestra aplicación o en base a nuestros servicios que nos permitan verificar que todo funciona correctamente.

Con el fin de ayudarnos en el uso de estas técnicas, Visual Studio nos va proveyendo de herramientas, cada vez más completas que nos ayudan a utilizar dichas técnicas eficientemente. Además este método de trabajo se alinea muy bien con modelos de ciclo de vida de las aplicaciones por lo que estamos poniendo una buena base para el mantenimiento y evolución de una aplicación.

Por último, como todos somos humanos y podemos equivocarnos, es recomendable disponer de un control de código fuente para poder volver atrás en cualquier momento.

 

Conclusión

Lo rápido no siempre está alineado con lo eficiente, es por lo que la mejor forma de aprovechar tecnologías como .NET y herramientas como Visual Studio, es ir definiendo los pasos a seguir en su diseño y concepción sin que ello suponga pararse por completo hasta obtener el diseño “perfecto”.

En mi opinión, el modelo planteado se basa en tener claros los conceptos de negocio que los conceptos tecnológicos, sin perder por ello agilidad en el desarrollo de aplicaciones.

Información adicional

AOP, OO y SOA: Cada uno es responsable de lo suyo

Domain Driven Design Community

Refactoring by Martin Fowler

Patrones de Diseño

Antipatrones de Diseño