El diseño basado en dominios (DDD) se opone a la idea de tener un único modelo unificado para todo el sistema; en su lugar, fomenta la división del sistema en contextos delimitados, cada uno de los cuales tiene su propio modelo. Durante la fase estratégica del diseño basado en dominios (DDD), se asigna el dominio empresarial y se definen los contextos delimitados para los modelos de dominio.
El diseño basado en dominios táctico consiste en definir los modelos de dominio con más precisión. Los patrones tácticos se aplican dentro de un único contexto delimitado. En una arquitectura de microservicios, en la que cada contexto delimitado es un candidato a microservicio, nos interesan especialmente los patrones de entidad y agregado. Aplicar estos patrones nos ayudará a identificar los límites naturales de los servicios de nuestra aplicación (consulte el siguiente artículo de esta serie). Como principio general, un microservicio no debe ser menor que un agregado ni mayor que un contexto delimitado. En primer lugar, revisaremos los patrones tácticos. A continuación, se podrán aplicar al contexto delimitado de envío, en la aplicación Drone Delivery.
Información general sobre los patrones tácticos
En esta sección se proporciona un breve resumen de los patrones tácticos del diseño basado en dominios, por lo que, si ya está familiarizado con él, podría omitir esta sección. Los patrones se describen con más detalle en los capítulos 5 y 6 del libro de Eric Evans, y en el libro Implementing Domain-Driven Design (Implementación del diseño basado en dominios) de Vaughn Vernon.
Entidades. Una entidad es un objeto con una identidad única que persiste en el tiempo. Por ejemplo, en una aplicación bancaria, las cuentas y los clientes serían entidades.
- Una entidad tiene un identificador único en el sistema, que se puede usar para buscar la entidad o para recuperarla. Eso no significa que el identificador siempre se exponga directamente a los usuarios. Podría ser un identificado único (GUID) o una clave principal de una base de datos.
- Una identidad puede abarcar varios contextos delimitados y puede durar más que la aplicación. Por ejemplo, los números de cuentas bancarias o los identificadores emitidos por entidades gubernamentales no están asociados a la duración de una aplicación en particular.
- Los atributos de una entidad pueden cambiar con el tiempo. Por ejemplo, el nombre o la dirección de una persona pueden variar, pero ella sigue siendo la misma.
- Una entidad puede contener referencias a otras entidades.
Objetos de valor. Un objeto de valor no tiene identidad. Se define únicamente mediante los valores de sus atributos. Los objetos de valor también son inmutables. Para actualizar un objeto de valor, siempre hay que crear una nueva instancia que reemplace a la anterior. Los objetos de valor pueden tener métodos que encapsulen la lógica del dominio, pero esos métodos no deben afectar al estado del objeto. Ejemplos típicos de objetos de valor son los colores, las fechas y horas, y los valores de divisa.
Agregados. Un agregado define un límite de coherencia alrededor de una o varias entidades. Una entidad exacta en un agregado es la raíz. La búsqueda se realiza con el identificador de la entidad raíz. Cualquier otra entidad en el agregado es secundaria de la raíz y se hace referencia a ella siguiendo punteros desde esta.
El propósito de un agregado es modelar las invariantes transaccionales. Las cosas en el mundo real tienen redes complejas de relaciones. Los clientes crean pedidos, los pedidos contienen productos, los productos tienen proveedores y así sucesivamente. Si la aplicación modifica varios objetos relacionados, ¿cómo podemos garantizar la coherencia? ¿Cómo se realiza el seguimiento de los elementos invariables y cómo se aplican?
A menudo, las aplicaciones tradicionales han usado las transacciones de base de datos para asegurar la coherencia. En una aplicación distribuida, sin embargo, eso a menudo no es factible. Una sola transacción comercial puede abarcar varios almacenes de datos, puede ser de ejecución prolongada o implicar a servicios de terceros. En última instancia, depende de la aplicación, no del nivel de datos, el aplicar los valores invariables necesarios para el dominio. Eso es lo que los agregados se supone que modelan.
Nota
Un agregado puede constar de una sola entidad, sin entidades secundarias. Lo que lo convierte en agregado es el límite transaccional.
Servicios de aplicación y de dominio. En la terminología del diseño basado en dominios, un servicio es un objeto que implementa alguna lógica sin mantener ningún estado. Evans distingue entre servicios de dominio, que encapsulan la lógica del dominio, y servicios de aplicación, que proporcionan la funcionalidad técnica, como la autenticación del usuario o el envío de un mensaje SMS. Los servicios de dominio a menudo se utilizan para modelar el comportamiento que abarca varias entidades.
Nota
El término servicio está saturado en el desarrollo de software. La definición aquí no está relacionada directamente con los microservicios.
Eventos de dominio. Los eventos de dominio se pueden utilizar para notificar a otras partes del sistema cuando sucede algo. Como sugiere su nombre, los eventos de dominio deben significar algo dentro del dominio. Por ejemplo, "se inserta un registro en una tabla" no es un evento de dominio. "Se canceló una entrega" es un evento de dominio. Los eventos de dominio son especialmente importantes en una arquitectura de microservicios. Dado que los microservicios se distribuyen y no comparten los almacenes de datos, los eventos de dominio proporcionan una manera de que los microservicios se coordinen entre sí. En el artículo Comunicación entre servicios se describe la mensajería asincrónica con más detalle.
Hay otros patrones del diseño basado en dominios que no se mencionan aquí, como son los generadores, los repositorios y los módulos. Pueden ser patrones útiles cuando se vaya a implementar un microservicio, pero son menos importantes al diseñar los límites entre microservicios.
Drone Delivery: aplicación de los patrones
Empezaremos con los escenarios que el contexto delimitado de envío debe controlar.
- Un cliente puede solicitar un dron para recoger las mercancías de una empresa que se registre en el servicio de entrega de drones.
- El remitente genera una etiqueta (código de barras o RFID) para colocar en el paquete.
- Un dron recogerá el paquete en la ubicación de origen y lo entregará en la ubicación de destino.
- Cuando un cliente programa una entrega, el sistema proporciona un tiempo estimado de llegada (ETA) según la información de la ruta, las condiciones meteorológicas y los datos históricos.
- Cuando el dron está en vuelo, el usuario puede realizar el seguimiento de la ubicación actual y del tiempo estimado de llegada más reciente.
- Hasta que un dron recoja el paquete, el cliente puede cancelar una entrega.
- Se notifica al cliente cuándo se completa la entrega.
- El remitente puede solicitar al cliente la confirmación de la entrega, en forma de una firma o de una huella digital.
- Los usuarios pueden ver el historial de una entrega completada.
En estos casos, el equipo de desarrollo identificó las siguientes entidades.
- Entrega
- Paquete
- Dron
- Cuenta
- Confirmación
- Notificación
- Etiqueta
Las cuatro primeras (entrega, paquete, dron y cuenta) son todos agregados que representan los límites de la coherencia transaccional. Las confirmaciones y las notificaciones son las entidades secundarias de las entregas y las etiquetas son las entidades secundarias de los paquetes.
Los objetos de valor en este diseño incluyen la ubicación (Location), el tiempo estimado (ETA), el peso del paquete (PackageWeight) y su tamaño (PackageSize).
Para ilustrar esto, se proporciona un diagrama UML del agregado de entrega. Tenga en cuenta que contiene referencias a otros agregados, como son la cuenta, el paquete y el dron.
Hay dos eventos de dominio:
Mientras un dron está volando, la entidad Dron envía eventos DroneStatus que describen la ubicación y el estado del dron (en vuelo, en tierra).
La entidad de entrega (Delivery) envía eventos de seguimiento de la entrega (DeliveryTracking) cada vez que cambia la fase de una entrega. Entre estos, se incluyen los de creación, reprogramación, preparada y completada (DeliveryCreated, DeliveryRescheduled, DeliveryHeadedToDropoff y DeliveryCompleted, respectivamente).
Tenga en cuenta que estos eventos describen aspectos significativos dentro del modelo de dominio. Describen algo sobre este y no están vinculados a una construcción de un lenguaje de programación determinado.
El equipo de desarrollo identificó un área más de funcionalidad, que no encaja claramente en ninguna de las entidades descritas hasta ahora. Una parte del sistema debe coordinar todos los pasos implicados en la programación o actualización de una entrega. Por lo tanto, el equipo de desarrollo agrega dos servicios de dominio al diseño: un programador (Scheduler) que coordina los pasos y un supervisor que supervisa el estado de cada paso, con el fin de detectar si en alguno se generó un error o se agotó su tiempo asignado. Esta es una variación del patrón Scheduler Agent Supervisor (supervisor del agente de programación).
Pasos siguientes
El siguiente paso consiste en definir los límites de cada microservicio.