Antes de leer este blog, te recomiendo que leas las dos entradas anteriores que le sirven de base a este: MVC, Delivery Mechanism and Domain Model y A Case for Outside-In Development.
Después de cierto tiempo, la mayoría de los proyectos de software son muy difíciles de mantener y evolucionar. Las empresas se quejan constantemente de que las cosas tardan una eternidad en ser entregadas. Los desarrolladores se quejan de que el código es un desastre y les cuesta entenderlo. Y señalan que el código está mal diseñado, que no refleja los conceptos empresariales ni sus respectivos flujos. Pero la mayoría de las veces, son ellos mismos quienes han escrito el código.
Normalmente, los equipos de desarrollo no tienen una forma eficaz de dividir las funciones empresariales, diseñar el software incrementalmente, y mantener la base de código alineada con los flujos empresariales.
Un buen proceso de diseño de software debería ayudar a los desarrolladores a representar claramente las áreas funcionales y los flujos de negocio en sus aplicaciones, alineando los cambios en el negocio con sus respectivos componentes de software. Sin embargo, el cambio de un área de la empresa no debería provocar cambios en múltiples áreas del sistema. Identificar el comportamiento del sistema debe ser sencillo y los nuevos desarrolladores no deberían tener problemas en entender el código.
Interaction-Driven Design (IDD)
El IDD es un enfoque iterativo para el diseño y desarrollo de software basado en el desarrollo Outside-In. Esto quiere decir que se centra en modelar el comportamiento según el uso externo del sistema, manteniendo al mismo tiempo una representación interna de componentes empresariales cohesivos.
La premisa del IDD afirma que una aplicación sólo debe existir para satisfacer las necesidades externas de los usuarios o servicios, denominados actores. Cada interacción entre un actor y la aplicación representa una necesidad del actor que debe ser satisfecha por la aplicación. El objetivo del IDD es diseñar y construir iterativamente aplicaciones que satisfagan esas necesidades.
Influencias del IDD
Construido sobre una base sólida de diseño de software, el IDD se inspira en algunas ideas del Responsibility Driven Design, el Domain Driven Design, el Behaviour Driven Development y muchos otros principios, patrones, metodologías y enfoques de diseño ya existentes.
El IDD reúne un conjunto cohesivo de métodos nuevos y existentes para crear un enfoque más prescriptivo, pero flexible, del diseño y desarrollo de software.
Ámbito de aplicación del IDD
El IDD se enfoca en el diseño y desarrollo de los aspectos funcionales de un sistema, incluyendo su arquitectura y su macro y micro-diseño.
Resumen del enfoque IDD
El IDD se enfoca en la interacción de los actores con la aplicación y los distintos comportamientos dentro de la aplicación. El comportamiento interno se descubre descomponiendo los comportamientos desencadenados por los actores. El proceso se repite para cada comportamiento identificado, descomponiéndolos en comportamientos más pequeños hasta que no exista ningún comportamiento divisible. Los comportamientos de grano grueso se convierten en clientes de los comportamientos de grano fino. Cada comportamiento se crea para satisfacer las necesidades de un comportamiento existente o una necesidad externa. Esto es a lo que llamamos diseño outside-in.
Descubrir comportamientos
El descubrimiento de comportamientos se produce a cinco niveles: funcionalidad multiaplicación, aplicación, función de aplicación, componente y unidad.
- Funcionalidad multiaplicación: es el comportamiento proporcionado por un grupo de aplicaciones, normalmente en una arquitectura de (micro)servicios distribuidos.
- Aplicación: colección de comportamientos proporcionados por una única aplicación a actores externos. Cada comportamiento proporcionado al mundo externo se considera una función.
- Función de aplicación: es el comportamiento que satisface una única necesidad de un actor. A menudo, una función orquesta el comportamiento de diferentes componentes (o áreas funcionales).
- Componente: conjunto de comportamientos relacionados a una única área funcional.
- Unidad: comportamiento no descomponible, parte de un componente.
Áreas funcionales
El término 'área funcional' se utiliza para definir un área de nuestro dominio empresarial. Ejemplos de áreas funcionales serían cosas como los productos, pagos, clientes o pedidos. En función del tamaño, la complejidad y el estilo de arquitectura utilizado, las áreas funcionales pueden asignarse a aplicaciones independientes (servicios) o a componentes empresariales dentro de una única aplicación.
Descubrir comportamientos de manera outside-in
Independientemente del nivel, el descubrimiento de comportamientos se realiza mayoritariamente a modo outside-in. La única diferencia reside en el nivel de abstracción utilizado.
En el caso de una funcionalidad multiaplicación en un entorno de microservicios, primero debemos elegir algunos flujos importantes (user journeys, flujos comerciales) desencadenados por los actores. Para cada uno de los flujos, hacemos lo siguiente:
- Definir la aplicación (servicio) que gestionará la solicitud del actor. Esta es la aplicación que "poseerá" la función multiaplicación.
- Luego, descomponemos el comportamiento principal en comportamientos más pequeños, asegurándonos de que todos tengan un nivel de abstracción similar.
- El siguiente paso es definir qué áreas funcionales serán las propietarias de los comportamientos más pequeños encontrados.
- Si ya existe un área funcional adecuada, el comportamiento se añade a ella. Si no, hay que crear una, ya que probablemente falte un concepto de dominio en nuestro dominio.
- Repite este proceso para cada comportamiento más pequeño hasta que no podamos descomponerlo más, o lleguemos a un nivel de abstracción que no sea relevante.
Este proceso debe realizarse en colaboración con todo el equipo, incluyendo los product owners y los testers. La mejor forma de representar este proceso de descubrimiento es dibujar diagramas de secuencia en una pizarra. Las áreas funcionales descubiertas, tras explorar unos cuantos flujos principales, pueden consolidarse y volverse candidatas naturales a ser convertidas en aplicaciones (o servicios) independientes.
El mismo proceso puede utilizarse para comportamientos de niveles inferiores, como los componentes. La diferencia es que en lugar de hablar de comportamientos de alto nivel, áreas funcionales y servicios, hablaríamos de comportamientos de bajo nivel, clases y métodos.
Para más detalles sobre el descubrimiento de comportamientos a distintos niveles visita nuestras entradas anteriores.
IDD y Desarrollo iterativo
El IDD aconseja que un equipo de software trabaje en un único tema de trabajo a la vez. De este modo, se minimizan las dependencias entre equipos, el equipo se centra en la entrega y el diseño de las distintas áreas de la aplicación se mantiene estable y coherente.
Cada tema de trabajo se divide en funcionalidades cuya prioridad se define en el backlog del equipo. El equipo trabaja de forma iterativa, enfocandose en una función a la vez. Cada función se divide en fragmentos verticales: desde el mecanismo de entrega hasta la persistencia o la integración con otras aplicaciones. Las funciones sencillas cuentan con un único fragmento, mientras que las complejas pueden dividirse en varios. El equipo trabaja en un fragmento a la vez y sólo pasa al siguiente una vez que el fragmento se despliegue a producción.
Antes de comprometerse con una función, el equipo debe comprender cómo interactuarán los actores con la aplicación para beneficiarse de ella. Antes de dividir una funcionalidad en pequeños fragmentos verticales, debe realizarse una exploración horizontal del mecanismo de entrega. La división de la funcionalidad debe hacerse desde fuera hacia dentro; es decir, desde el mecanismo de entrega a los puntos de persistencia o integración.
En futuras entradas describiremos distintas estrategias para trocear funciones.
Proceso de desarrollo de IDD y el establecimiento de prioridades
A la hora de crear software usando IDD, el primer paso consiste en identificar a los actores (usuarios u otros sistemas o servicios) que se beneficiarán de las funciones de nuestra aplicación. Cada función debe responder a las necesidades de uno o varios actores.
Una vez identificados los actores, analizamos las interacciones que el actor tendrá con el sistema. En este análisis no profundizamos en el comportamiento interno de la aplicación. Lo mantenemos superficial, centrándonos únicamente en la conversación entre el actor y la aplicación. Cada interacción entre el actor y la aplicación es una función. A este paso le llamamos exploración horizontal.
Al tener una lista de funciones a la mano, establecemos prioridades entre ellas y dividimos verticalmente en fragmentos la función de mayor prioridad.
Cada fragmento se desarrolla a modo outside-in, empezando por el mecanismo de entrega (interfaz de usuario, cola de entrada, punto final de API, controlador, etc.) y moviéndonos hacia dentro gradualmente hasta que implementemos todo el fragmento.
IDD: Diseño y Test direction
En IDD, empezamos a diseñar y testear desde el input (el exterior) hasta el output (el interior), siguiendo las necesidades externas de los usuarios u otros sistemas.
El IDD alinea el diseño y el test-driven development (TDD) con el flujo de ejecución.
Resumen
El IDD es una metodología de diseño de software "outside-in" que ayuda a los equipos de desarrollo a diseñar y construir software basado en la interacción de los actores con la aplicación y los comportamientos dentro de la aplicación.
El IDD promueve el desarrollo iterativo y una estrecha colaboración entre desarrolladores y empresa. La evolución sostenible del software y la entrega continua son algunos de los principales objetivos del IDD, y ambos se consiguen centrándose en el diseño de la aplicación y dividiendo el trabajo en pequeñas partes verticales.
En futuras entradas de blog describiré con mucho más detalle todos los elementos del IDD, como la recopilación de requisitos, la arquitectura, las pruebas, la organización del código, el corte de requisitos y mucho más.