¿Su código JavaScript se está convirtiendo en espagueti? Es hora de implementar DDD
\n\n¿Alguna vez se ha sorprendido pensando que su proyecto en JavaScript parece un plato de espagueti? Los métodos se arrastran unos tras otros, los cambios en un módulo rompen otros tres, y la lógica de negocio está dispersa entre controladores, servicios y utilidades. ¿Le suena familiar? Si su proyecto ha superado la etapa de "solo un prototipo", es momento de conocer Domain-Driven Design (DDD) — el diseño orientado al dominio.
\n\nMuchos piensan que DDD es solo para monstruos en Java o C#. Pero eso es un mito. Domain-Driven Design en proyectos JavaScript no solo es posible, sino increíblemente útil. Ayuda a que desarrolladores y negocio hablen el mismo idioma, y el código se vuelve predecible y resistente a los cambios. En este artículo, analizaremos DDD en la práctica, con ejemplos de código real, para que pueda aplicarlo hoy mismo.
\n\n¿Qué es DDD y por qué lo necesita un desarrollador JavaScript?
\n\nDDD no es una biblioteca ni un framework. Es un enfoque para el diseño de software que pone en el centro el dominio del negocio. En lugar de pensar en tablas de base de datos o APIs REST, usted piensa en las entidades del negocio: "Pedido", "Cliente", "Factura", "Regla de cálculo de descuento".
\n\nEl principal problema que resuelve DDD es la complejidad. Cuando la lógica de negocio vive en un lugar y los detalles técnicos en otro, el proyecto se vuelve frágil. DDD propone una arquitectura clara que separa el grano de la paja.
\n\nPara JavaScript, donde a menudo usamos tipado dinámico y prototipos, DDD aporta disciplina. Obliga a describir explícitamente los tipos de datos y las reglas para modificarlos, lo cual es crítico para aplicaciones escalables en Node.js o aplicaciones cliente complejas.
\n\nLos bloques de construcción fundamentales de DDD (con ejemplos en JS)
\n\nPasemos a lo más interesante: el código. Escribiremos un sistema simple pero ilustrativo de gestión de pedidos en una tienda en línea. Usaremos JavaScript moderno (ES6+).
\n\n1. Value Object (Objeto de valor)
\n\nEs un objeto inmutable que se define por sus atributos, no por su identidad. Dos Value Objects son iguales si tienen los mismos valores. Un ejemplo ideal es dinero, dirección, correo electrónico.
\n\n// value-objects/Money.js\nclass Money {\n constructor(amount, currency) {\n // La validación es una parte clave de DDD\n if (typeof amount !== 'number' || amount < 0) {\n throw new Error('El monto debe ser un número positivo');\n }\n if (!['USD', 'RUB', 'EUR'].includes(currency)) {\n throw new Error('Moneda no soportada');\n }\n\n this._amount = amount;\n this._currency = currency;\n // Congelamos el objeto para inmutabilidad\n Object.freeze(this);\n }\n\n get amount() { return this._amount; }\n get currency() { return this._currency; }\n\n // Método de negocio: suma de dinero\n add(otherMoney) {\n if (this.currency !== otherMoney.currency) {\n throw new Error('No se pueden sumar monedas diferentes');\n }\n return new Money(this.amount + otherMoney.amount, this.currency);\n }\n\n equals(other) {\n return this.amount === other.amount && this.currency === other.currency;\n }\n}\n\n// Uso\nconst price = new Money(100, 'USD');\nconst tax = new Money(20, 'USD');\nconst total = price.add(tax); // Money { _amount: 120, _currency: 'USD' }\nconsole.log(total);\n\n¿Por qué es genial? Ahora una suma de dinero no es solo un número, sino una entidad completa con reglas. No podrá sumar accidentalmente dólares con rublos ni hacer que el monto sea negativo.
\n\n2. Entity (Entidad)
\n\nA diferencia de Value Object, una Entidad tiene identidad. Puede cambiar con el tiempo, pero su ID permanece inalterable. Por ejemplo, un usuario o un pedido.
\n\n// entities/Order.js\nconst { v4: uuidv4 } = require('uuid'); // o crypto.randomUUID()\n\nclass Order {\n constructor(id