Traiga claridad a su monolito con Contextos delimitados

Vea el video de esta charla de ElixirConf 2017 a continuación

Las aplicaciones monolíticas son excelentes cuando comienza a construir su empresa, pero a medida que pasa el tiempo, se vuelven difíciles de mantener. Estas bases de código, a medida que crecen, se convierten fácilmente en Grandes Bolas de Barro.

 Indiana Jones Rock

Al crear aplicaciones grandes en marcos como Rails, los principios de diseño de convención sobre configuración que hicieron que el uso de Rails fuera tan agradable comienzan a interferir cuando la aplicación crece en alcance. Es posible que también experimente los mismos dolores si:

  • La refactorización es difícil y tediosa, porque los métodos y las clases dependen de demasiadas clases
  • Tiene una lista cada vez mayor de objetos de negocios que son difíciles de mantener en su cabeza. De hecho, nadie parece ser capaz de entender el sistema como un todo cohesionado
  • Cambiar el código en un área del código conduce a efectos secundarios inesperados e involuntarios en otras áreas del código, porque es fácil llamar a servicios y objetos globales

En nuestra última charla, discutimos el desarrollo de un lenguaje ubicuo junto con los expertos de negocios y su equipo de desarrollo para ayudar a su equipo a trabajar más estrechamente juntos. Hoy, vamos a construir sobre eso introduciendo nuevas herramientas de Diseño basado en Dominios (DDD). A continuación, introduciremos una nueva estructura de carpetas para tus aplicaciones Rails, preparándolas para un futuro en el que tu aplicación esté menos acoplada y más cohesionada. ¡Empecemos!

Let’s talk domains

Un principio clave en DDD es que el software que compila debe reflejar de cerca el dominio (empresarial) de la organización que lo compila. Por lo tanto, necesitamos hacer algunos deberes para comprender el dominio comercial de su software.

Un dominio es lo que hace la empresa y el contexto de cómo lo hace.

Revisemos nuestro ejemplo de Delorean de la publicación anterior. En él, la compañía se comercializa como Uber para viajes en el tiempo. Por lo tanto, su “dominio” (el “lo que hace”) es Compartir viajes en el Tiempo. También se incluye en el Dominio el “cómo” de cómo lo hace, asociando a los conductores que poseen vehículos Delorean que viajan en el tiempo con los pasajeros que desean hacer viajes en el tiempo.

Para obtener más matices en el dominio empresarial, DDD introduce otro concepto, llamado Subdominio:

Un Subdominio representa los grupos o unidades más pequeños de la empresa que colaboran en el día a día para lograr los objetivos de la empresa.

Delorean se divide en varios equipos dentro de la empresa. Echemos un vistazo a dos de ellos, y veamos de qué son responsables:

Equipo de Plataforma de Viaje Equipo de Operaciones Financieras
Misión Diseñar y dar soporte a los sistemas que enrutan los viajes y conectan a los conductores con los pasajeros Administrar los sistemas que involucran a instituciones financieras y procesadores de tarjetas de crédito
Responsabilidades
  • Conectar pasajeros con conductores
  • Dirigir al conductor a su próximo destino
  • Notificar a los pasajeros de los conductores que llegan
  • Alertar a los conductores de los nuevos pasajeros
  • Procesar pagos a conductores
  • Mantener el historial de transacciones de todo el sistema para auditar
  • Crear informes financieros
  • Procesar cargos de tarjetas de crédito a pasajeros

Cada uno de estos dos grupos anima una responsabilidad empresarial o subdominio. Vamos a nombrarlos Experiencia de Viaje Compartido y Comercio electrónico, respectivamente.

Ahora tenemos una ilustración general del negocio y dos de sus unidades que lo ayudan a funcionar en el día a día. El Dominio y el subdominio son formas de modelar el espacio problemático de su negocio y cómo actúa para cumplir con estos roles. Lo más probable es que su organigrama de negocio refleje de cerca los subdominios de su negocio. En el mundo real, las delineaciones pueden ser menos claras: los equipos pueden ser responsables de múltiples subdominios superpuestos.

Completemos este diagrama con algunos subdominios más en el negocio de Delorean:

  • Subdominio de atención al cliente: resolver los tickets de atención al cliente que llegan a través de correo electrónico
  • Subdominio de marketing: gestión de campañas de marketing por correo electrónico y códigos de cupones de marketing
  • Subdominio de identidad: Cómo el sistema rastrea a cada usuario y su información de identificación

Contextos delimitados en el espacio de soluciones

Este diagrama que tenemos delante refleja ahora los objetivos de negocio de la empresa, divididos en unidades lógicas que (con suerte) logran sus objetivos en el mundo real. Ahora vamos a superponer los sistemas de software que logran estos objetivos sobre este diagrama. Estos sistemas de software se describen como Contextos delimitados:

Un contexto delimitado es un sistema que cumple los objetivos del negocio en el mundo real.

Cualquiera de nuestros sistemas de software (como un servicio web o una aplicación web) que funcionan como instancias concretas en el Mundo Real se consideran Contextos limitados.

Técnicamente hablando, el Contexto Delimitado en lenguaje DDD es un límite específico dentro de su dominio que su Glosario de su Lenguaje Ubicuo solo puede aplicar, la idea es que diferentes Subdominios pueden tener definiciones de términos en competencia o en conflicto. Este post no profundizará en los matices lingüísticos del Contexto Limitado. Para más información, véase la explicación de Martin Fowler sobre Contextos Delimitados.

Ahora resulta que en Delorean, todos estos subdominios se implementan en un solo sistema: una Gran Bola de Monolito de Rieles de Barro. Dibujaremos una caja azul alrededor de los subdominios cuyas funciones son implementadas por el sistema de software. En este caso, comenzaremos con nuestro monolito de Rieles antes mencionado:

Como es el monolito, básicamente lo hace todo, y aquí se está comiendo todos los otros subdominios del diagrama.

No lo olvidemos, tenemos algunos otros sistemas de software que no hemos modelado aquí. ¿Qué pasa con todas las buenas integraciones de terceros que utiliza la empresa? Estos también son sistemas de software. Las dibujaremos como cajas azules.

Por cierto, lo que hemos dibujado aquí es un mapa de contexto, un diagrama que mezcla objetivos de negocio e implementaciones concretas de sistemas de software. Es útil para evaluar el terreno de sus sistemas de software y visualizar las dependencias entre equipos.

Ahora, esto es razonable y limpio, pero vivimos en el mundo real, y el software del mundo real rara vez sale con un aspecto consistente y coherente. Si ha creado su aplicación Rails siguiendo sus convenciones listas para usar, su aplicación carece internamente de los grupos necesarios para visualizar su aplicación en sus componentes constituyentes. En realidad, la base de código Delorean se parece más a esto:

El punto es que Rails no impone ninguna restricción organizativa en nuestros sistemas de software, lo que significa que las unidades de negocio lógicas (nuestros subdominios) que sugieren interfaces desacopladas no se materializan en el código, lo que lleva a la confusión y al aumento de la complejidad a medida que pasan los años.

La gran idea: Organizar el código Rails en módulos por subdominio de negocio

Aunque sus clases de Ruby en su aplicación probablemente vivan en el espacio de nombres global, se pueden extraer fácilmente en módulos. Nuestro objetivo es crear grupos lógicos de código de dominio que puedan aislarse en componentes autónomos.

De hecho, uno de los objetivos de los Diseños Basados en dominios es tener una asignación de uno a uno desde un Subdominio a un Contexto Delimitado.

OK, ¿qué significa esto? Entremos en algunas recomendaciones, junto con ejemplos.

Invertir estructuras de carpetas en un agrupamiento plano orientado a dominios

Puede recordar que las siguientes convenciones de Rails nos llevan a jerarquías de carpetas que agrupan clases por roles:

Movamos todo a una nueva estructura de directorios: en su lugar, agrupemos funcionalidades similares por dominio. Comenzaremos con una primera variación, que llamaré agrupación plana orientada a dominios.

Modularizar clases

A continuación, querrá modular las clases de lo que eran antes. Dado que la clase de conductor pertenece al dominio de viaje compartido, la agregaremos a un módulo de viaje compartido:

Querrá hacer esto para cada clase que mueva a la estructura de directorio plano app/domains.

Haga referencia a los modelos asociados por el nombre de clase completo

Además, deberá cambiar las asociaciones de modelos ActiveRecord para referirse a la clase por su ruta de acceso modulada completa:

Mantenga a los controladores actualizados sobre dónde encontrar sus vistas recién moduladas

También deberá insertar este pequeño bit para que las rutas del controlador sepan dónde buscar las vistas:

Aquí está lo bueno: No tienes que mover todo tu código a la vez. Puede elegir un pequeño dominio en su aplicación, el área más madura de su código o el área que mejor comprende, y comenzar a mover sus preocupaciones en una sola carpeta de dominio, todo mientras deja el código existente en reposo hasta que esté listo para moverse.

Ahora, hemos dado algunos pequeños pasos para lograr claridad arquitectónica en nuestra aplicación. Si miramos ahora, nuestras estructuras de carpetas modulares nos han ayudado a agrupar nuestro código de esta manera:

Debajo del capó, nuestra aplicación podría verse más como esto:

¿Qué funciona bien con este enfoque?

  1. Hay menos ruido en cada directorio de archivos: al agrupar archivos similares por especificidad de dominio, encontramos un punto organizativo natural
  2. Las entidades que permanecen en cada carpeta de dominio son altamente cohesivas: lo más probable es que tiendan a comunicarse entre sí de forma natural y aparezcan entre sí
  3. Las entidades que no pertenecen juntas ahora están separadas (acopladas más sueltas)
  4. Si tiene equipos de ingeniería que trabajan a lo largo de las responsabilidades de subdominio, estos ingenieros ahora pueden trabajar de una manera más ágil y aislada. El acoplamiento más flexible permite a estos equipos realizar cambios con la confianza de que no introducirán regresiones ni fusionarán conflictos de nuevo en la base de código
  5. El escenario ahora está listo a largo plazo para comenzar a mover cada una de estas carpetas de dominio a un servicio de software independiente (más sobre eso en una publicación de blog futura)

Si quieres más información sobre esta estructura de carpetas, he desarrollado una aplicación de ejemplo que muestra esta estructura de carpetas orientada al dominio: http://github.com/andrewhao/delorean. Echa un vistazo y hazme saber lo que piensas.

¿Qué hemos aprendido?

En nuestro tiempo juntos, aprendimos sobre conceptos de diseño basados en dominios en torno a Dominios y Subdominios. Aprendimos a visualizar nuestros sistemas de software como Contextos Delimitados en un Mapa de Contexto, que nos mostró las áreas del sistema que pertenecen juntas como partes coherentes.

Terminando en una nota práctica, ilustramos cómo los archivos y carpetas de Rails podrían “invertirse” y reinventarse como agrupaciones de dominio primero.

En mi próxima publicación, continuaremos nuestra discusión en una próxima publicación de blog sobre cómo desacoplar aún más nuestro código Rails orientado al dominio con eventos de dominio y, finalmente, abrirnos camino a la tierra de los microservicios.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.