El Diseño Dirigido por el Dominio (DDD) fue creado en el año 2003 por el reconocido experto en software Eric Evans, quien lo presentó en su libro Domain-Driven Design: tackling complexity in the heart of software. Desde entonces, se ha convertido en una técnica popular para diseñar software de alta calidad y escalable.
En términos generales, el DDD consiste, principalmente, en dos procesos: el modelado del dominio y la implementación de la lógica del dominio.
Qué es Domain Driven Design
Domain Driven Design (DDD) se traduce al español como Diseño Dirigido por el Dominio. Es una técnica de diseño de software que se centra en el análisis y diseño del dominio del problema. Se utiliza para crear software de alta calidad que se ajuste a los requisitos del negocio; permite un uso eficiente del código y que el software sea fácil de mantener y modificar.
Ventajas y desventajas del DDD
Ventajas
- Ayuda a los desarrolladores a entender mejor el dominio del problema, lo que a su vez ayuda a crear soluciones más efectivas y específicas.
- Promueve una mejor colaboración entre los equipos de desarrollo y los expertos del dominio del problema.
- Permite una mejor mantenibilidad y evolución del código, ya que el diseño está más cercano al modelo mental del dominio del problema.
- Facilita la implementación de cambios y mejoras en el sistema, ya que el modelo del dominio es más fácil de entender y modificar.
- Fomenta el uso de un lenguaje común para todos los involucrados en el proyecto, lo que puede reducir la ambigüedad y mejorar la comunicación.
Desventajas
- Requiere de un mayor conocimiento y esfuerzo para implementar correctamente el modelo del dominio, lo que puede llevar a un mayor tiempo de desarrollo.
- Puede ser difícil de ejecutar en sistemas ya existentes, especialmente si el modelo del dominio no se ha definido previamente.
- Requiere de una mayor colaboración y comunicación entre los equipos de desarrollo y los expertos del dominio, lo que puede aumentar la complejidad de la coordinación.
- Puede llevar a una mayor complejidad del código si no se implementa correctamente.
- Puede ser difícil de aplicar en casos en los que el modelo del dominio es complejo o no está bien definido.
Para explicar el DDD, desarrollaremos un ejemplo sobre el funcionamiento de un restaurante, que a continuación te presentamos.
Proceso de modelado del dominio
El modelado del dominio se centra en comprender plenamente las reglas de negocio y la creación de una representación precisa del problema en cuestión. Esta parte consiste en identificar y representar en el software los conceptos y reglas del negocio que se encuentran en el dominio del problema. El objetivo es crear una representación del dominio que sea lo más cercana posible a la realidad, y que permita a los desarrolladores comprender y trabajar con el problema de manera más efectiva.
Realizar el modelado del dominio en el DDD, involucra las siguientes etapas:
1. Comprender el dominio del problema
Primero es necesario comprender profundamente el dominio del problema. Esto implica trabajar con expertos en el dominio para obtener información sobre el negocio, las reglas y las restricciones que inciden en el problema en cuestión.
¿Cuáles son los procesos, conceptos y entidades que son importantes en la gestión y funcionamiento de un restaurante, conforme con nuestro ejemplo? Podrían ser los platillos, los clientes, las reservas, el personal, los pedidos y las mesas, entre otros.
2. Identificar los conceptos clave
Una vez que comprendas el dominio del problema, identifica los conceptos clave que son necesarios representar en el software. Estos pueden incluir entidades, objetos de valor, servicios, eventos y otros elementos que sean relevantes para el problema.
¿Cuáles son las entidades y objetos que serán importantes en nuestro modelo del dominio? Algunos ejemplos de conceptos clave en un restaurante podrían ser: platos, menús, clientes, reservas, mesas, personal, órdenes y facturas.
3. Crear un modelo del dominio
El siguiente paso es crear un modelo del dominio que refleje los conceptos y reglas del negocio. Este modelo puede incluir diagramas, esquemas y otras representaciones visuales que muestren las relaciones entre los diferentes elementos del dominio.
4. Refinar el modelo del dominio
Después de crear un modelo del dominio inicial, refínalo de forma gradual. Para ello, puede ser necesario agregar, modificar o eliminar conceptos y reglas, así como ajustar el modelo para que sea más preciso y completo.
5. Comunicar el modelo del dominio
Finalmente, es importante comunicar el modelo del dominio a todos los miembros del equipo de desarrollo y a los expertos en el dominio. Esto puede implicar la elaboración de documentos, presentaciones y otros materiales que ayuden a los miembros del equipo a comprender el modelo del dominio y su relevancia para el problema.
Implementación de la lógica del dominio
La implementación de la lógica del dominio, por otro lado, se centra en la ejecución de los conceptos y las reglas de negocio en el código. Esto implica la creación de código que refleje el modelo del dominio. Significa que el código debe ser organizado en torno a los conceptos y reglas del negocio que se encuentran en el dominio del problema.
Implementar la lógica del dominio en el DDD, comprende las siguientes etapas:
1. Identificar los agregados
Un agregado es un conjunto de entidades y objetos de valor que se agrupan en una unidad coherente. En el DDD, los agregados son la unidad básica de transacción y consistencia. Es importante identificar los agregados del dominio para poder implementar la lógica del negocio de manera adecuada.
2. Crear las entidades y los objetos de valor
Una vez que se han identificado los agregados, se pueden crear las entidades y los objetos de valor que forman parte de ellos. Las entidades representan objetos que tienen identidad y se mantienen a lo largo del tiempo, mientras que los objetos de valor representan objetos que no tienen identidad propia y se utilizan para representar valores simples o compuestos.
3. Implementar la lógica del negocio
Después de crear las entidades y los objetos de valor, se puede implementar la lógica del negocio que se encuentra en el dominio. Esto puede incluir reglas de validación, cálculos, flujos de trabajo y otras funciones que sean relevantes para el negocio.
4. Manejar las transacciones y la consistencia
En el DDD, las transacciones y la consistencia se manejan a nivel de agregado. Esto significa que todas las operaciones que afecten a un agregado deben ser atómicas y consistentes. Para lograrlo, se puede utilizar el patrón de repositorio y otros patrones que permitan mantener la consistencia y la integridad de los datos.
5. Utilizar un lenguaje ubicuo
Es importante utilizar un lenguaje ubicuo en todo el código que se implemente en el DDD. Esto significa que el código debe reflejar el lenguaje utilizado por los expertos en el dominio y ser fácilmente comprensible por todos los miembros del equipo de desarrollo y los expertos en el dominio.
public class Restaurante { private String nombre; private String direccion; private String telefono; private List<Plato> menu; private List<Mesa> mesas; private List<Orden> ordenes; public Restaurante(String nombre, String direccion, String telefono) { this.nombre = nombre; this.direccion = direccion; this.telefono = telefono; this.menu = new ArrayList<>(); this.mesas = new ArrayList<>(); this.ordenes = new ArrayList<>(); } public void agregarPlato(Plato plato) { this.menu.add(plato); } public void eliminarPlato(Plato plato) { this.menu.remove(plato); } public void reservarMesa(Mesa mesa) { mesa.setDisponibilidad(false); } public void liberarMesa(Mesa mesa) { mesa.setDisponibilidad(true); } public void tomarOrden(Orden orden) { this.ordenes.add(orden); } } public class Plato { private String nombre; private String descripcion; private double precio;
public Plato(String nombre, String descripcion, double precio) { this.nombre = nombre; this.descripcion = descripcion; this.precio = precio; } public double calcularPrecio() { // lógica para calcular el precio del plato, posiblemente usando ingredientes return this.precio; } public void modificarPrecio(double nuevoPrecio) { this.precio = nuevoPrecio; } } public class Mesa { private int numero; private int capacidad; private boolean disponibilidad;
public Mesa(int numero, int capacidad) { this.numero = numero; this.capacidad = capacidad; this.disponibilidad = true; } public int getNumero() { return numero; } public int getCapacidad() { return capacidad; } public boolean isDisponible() { return disponibilidad; } public void setDisponibilidad(boolean disponibilidad) { this.disponibilidad = disponibilidad; } public void reservar() { // lógica para reservar la mesa } public void liberar() { // lógica para liberar la mesa } } public class Cliente { private String nombre; private String apellido; private String email; public Cliente(String nombre, String apellido, String email) { this.nombre = nombre; this.apellido = apellido; this.email = email; } } public class Orden { private Cliente cliente; private List<Plato> platos;
public Orden(Cliente cliente) { this.cliente = cliente; this.platos = new ArrayList<>(); } public void agregarPlato(Plato plato) { this.platos.add(plato); } public void eliminarPlato(Plato plato) { this.platos.remove(plato); } public double calcularTotal() { double total = 0; for (Plato plato : this.platos) { total += plato.calcularPrecio(); } return total; } } public class Pedido { private Restaurante restaurante; private Mesa mesa; private |
En el código anterior tenemos una clase Restaurante con atributos como nombre, dirección y teléfono, y métodos como agregarPlato, eliminarPlato, reservarMesa, etcétera. Además, podríamos tener una clase Plato con atributos como nombre, descripción, precio, y métodos como calcularPrecio, modificarPrecio, entre otros.
La relación entre Restaurante y Plato podría ser una relación de agregación, ya que un restaurante puede tener muchos platos, pero un plato solo pertenece a un restaurante. Entonces, en el diagrama de clases, se representaría con una línea con un rombo en el extremo de la clase Restaurante apuntando hacia la clase Plato.
Además, podríamos tener una clase Mesa con atributos como número, capacidad, disponibilidad, y métodos como reservar, liberar, etcétera. La relación entre Restaurante y Mesa podría ser una relación de composición, ya que un restaurante tiene muchas mesas y una mesa solo pertenece a un restaurante. Entonces, en el diagrama de clases, se representaría con una línea con un rombo lleno en el extremo de la clase Restaurante apuntando hacia la clase Mesa.
A manera de resumen
Para aplicar la técnica del DDD, puedes seguir los siguientes pasos:
- Identifica el dominio del problema: es importante comprender el negocio y los requisitos del problema para identificar el dominio del problema que se debe abordar en el diseño.
- Crea un modelo del dominio: a partir de la comprensión del dominio del problema, se debe crear un modelo del dominio que refleje los conceptos y las reglas de negocio. Este modelo puede incluir entidades, objetos de valor, servicios, eventos y otros elementos que sean relevantes para el problema.
- Desarrolla la lógica del dominio: esto puede involucrar la creación de clases, interfaces, métodos y otros elementos de código que representen los conceptos y las reglas del negocio.
- Usa patrones de diseño: el DDD utiliza muchos patrones de diseño para crear un software bien estructurado y mantenible. Algunos de los que puedes emplear en el desarrollo de software DDD en Java son el patrón de repositorio, el patrón de fábrica, el patrón de especificación y el patrón de estrategia.
- Aplica los principios SOLID: es importante aplicar los principios SOLID (Single Responsibility Principle, Open-Closed Principle, Liskov Substitution Principle, Interface Segregation Principle y Dependency Inversion Principle) para asegurar que el código sea mantenible, escalable y extensible.
Esperamos que esta introducción te inspire a utilizar la técnica DDD en tus proyectos. Revisa más de nuestro blog y explora así otros temas relacionados.