


04/04/2025
Aquest article explora els principis fonamentals del Domain-Driven Design (DDD) i els seus patrons estratègics clau, com el llenguatge ubic i els contextos delimitats, per ajudar a alinear les aplicacions amb les necessitats del negoci, millorar la comunicació entre equips i gestionar la complexitat en sistemes de programari.
Històricament, el desenvolupament d’aplicacions s’havia vist com una activitat separada del negoci, en què hi havia una definició de requisits inicial per conèixer necessitats i el lliurament d’un producte final que no sempre complia les expectatives previstes, ja que amb aquesta forma de treballar (en cascada) hi havia poca o cap flexibilitat per introduir-hi canvis durant el projecte.
Ja el 2001, amb l’Agile Manisfesto es va començar a fer els desenvolupaments pensant en el canvi. Però encara calia superar un impediment: la diferència entre el negoci (entès com les entitats, les seves relacions entre si, les operacions que s’havien de fer sobre aquestes, etc.) i la manera en què aquest es veia reflectit en l’aplicació construïda.
Va ser a finals de l’any 2003 quan va aparèixer el llibre Domain-Driven Design: Tackling Complexity in the Heart of Software, escrit per Eric Evans, que oferia una forma diferent de fer les coses. El conegut com a «llibre blau del DDD» no era un llibre pràctic sobre patrons que calia aplicar, sinó que descrivia la manera d’aconseguir que l’aplicació modelés correctament el negoci i oferia un conjunt d’estratègies per assolir aquest objectiu.
El DDD (sigles de Disseny Orientat al Domini en anglès) adquireix un sentit especial quan afrontem el desenvolupament d’aplicacions sobre dominis de coneixement complexos. No sempre és la millor opció, ja que en dominis relativament senzills hi ha aproximacions més simples que ofereixen un equilibri entre la complexitat i el cost de construcció. En canvi, quan el domini és complex, fer un acostament d’aquest tipus permet aconseguir més estabilitat de l’aplicació davant els canvis que apareixen de forma natural a mesura que el negoci va evolucionant.
Tot seguit et donem algunes pautes per aplicar el DDD.
Utilitzar un llenguatge ubic
Moltes vegades, ens trobem que una aplicació té unes taules, un model de dades i uns noms que, al cap d’uns anys, ningú entén del tot què signifiquen, cosa que complica l’entesa entre totes les parts implicades.
Precisament, això és el que intenta evitar l’ús d’un llenguatge ubic (ubiquitous language en anglès).
El llenguatge ubic és un llenguatge comú entre tots els equips involucrats en un projecte i té com a objectiu evitar els malentesos i fomentar la col·laboració entre desenvolupadors i experts del domini.
Un llenguatge ubic ha de:
- Estar centrat en el domini: és a dir, s’ha de basar en la manera en què els experts del domini (les persones que tenen un coneixement profund de l’àrea de negoci o del problema que s’està resolent amb el programari) parlen de la seva feina. No té sentit que els desenvolupadors s’expressin en altres termes que poden dur a equívocs.
- Ser consistent: vol dir utilitzar sempre les mateixes paraules per referir-se als mateixos conceptes. Si hi ha diverses formes de referir-se a un concepte, se n’ha d’escollir una i utilitzar-la sempre de comú acord.
- Ser precís i clar: hem d’evitar les ambigüitats i no es pot utilitzar el mateix nom per referir-se a conceptes diferents.
- Ha d’integrar el programari i el negoci: quan els termes del llenguatge ubic s’utilitzen en el codi (en els noms de les classes, en els mètodes o en els mòduls), aconseguim que aquest sigui més fàcil de comprendre per totes les parts involucrades.
Amb aquest enfocament, aconseguim que hi hagi una forma de descriure els problemes del domini i que la solució proposada sigui comprensible per tots els equips. I el mateix passa amb el codi. Els desenvolupadors seran capaços de parlar del negoci en uns termes comuns.
Posem un exemple aclaridor:
- Els experts del domini ens expliquen que hi ha els Comptes Bancaris i que aquestes tenen un Titular, un Saldo i una DataValor per a aquest Saldo. En els Comptes Bancaris sempre s’hi pot Dipositar un import que se suma al Saldo i es pot Retirar un import que es resta del Saldo, sempre que aquest sigui inferior al Saldo existent. En tots dos casos, s’actualitza la DataValor
- Llavors, el codi hauria de ser alguna cosa de l’estil:
- Classe CompteBancari
- Titular
- Saldo
- DataValor
- I hauria de tenir mètodes d’aquest estil:
- Dipositar(import, data)
- Retirar(import, data)
- Un exemple en pseudocodi seria:
- Dipositar(import, data): Saldo = Saldo + import, DataValor = data
- Retirar(import, data): Si Saldo < import LlançarError Si no Saldo = Saldo – import, DataValor = data
- Classe CompteBancari
Prenent com a base aquest exemple, els experts del domini ara podrien demanar una llista mensual amb els comptes en què no hi ha hagut activitat durant l’últim mes i, per part seva, l’equip de desenvolupament podrà proposar seleccionar els CompteBancari en què la DataValor sigui anterior al mes en curs.
D’aquesta manera, el que es demana i el que s’implementa estarà perfectament alineat i tothom entendrà el que es farà i com funciona.
En general, el llenguatge ubic
- Millora la comunicació dins l’equip i evita malentesos
- Permet alinear negoci i tecnologia, ja que s’aconsegueix que el que s’implementa compleixi les necessitats reals
- Afavoreix un codi més llegible, precís i mantenible, i evita confusions durant el desenvolupament
- Millora la col·laboració entre àrees perquè fa que les discussions tècniques siguin més accessibles per a negoci
Context delimitat
Mitjançant la divisió de la nostra aplicació en diferents contextos, aconseguim dividir un sistema complex en peces més autònomes i més fàcils de mantenir.
La idea és que cada context tingui el seu propi llenguatge ubic i que el negoci es modeli per resoldre una part específica del problema global. En aquesta petita parcel·la, aconseguim que el domini tingui un significat específic, que sigui coherent i consistent amb les regles de negoci que pugui haver-hi en aquesta part del domini.
A aquests diferents contextos els anomenem «contextos delimitats» (o bounded contexts en anglès).
Una de les fortaleses més importants dels contextos delimitats és que tenen uns límits ben definits, que els permeten aïllar-se de la resta de l’aplicació i que els seus canvis no afectin la resta.
També hi ha patrons amb els quals afavorir la col·laboració entre diferents contextos delimitats mantenint l’aïllament entre aquests (ús d’API, d’esdeveniments, de capes d’anticorrupció, etc.).
Un exemple: en una entitat bancària pot haver-hi el context dels comptes bancaris i el context dels préstecs, i tots dos han de poder evolucionar de forma independent i, alhora, tenir relació.
A més, el concepte de «context delimitat» es pot explotar tant com calgui per reduir la complexitat fent que dins d’un mateix context hi hagi subcontextos més petits, que igualment estan cohesionats i en els quals es pot implementar una funcionalitat independentment de la resta del context.
En la pràctica, per identificar un context delimitat dins el nostre domini hem de buscar àrees en què s’utilitzi un conjunt únic de termes (el llenguatge ubic en aquest context) o regles úniques, àrees que tinguin uns requisits funcionals molt diferenciats de la resta o àrees que representin una separació natural del flux de treball o els processos de negoci.
Els contextos delimitats són de vital importància per impedir que el nostre sistema es converteixi en un monòlit, atès que divideixen de manera clara els diferents models que hi ha dins el negoci i permeten possibilitats tècniques com l’ús d’arquitectures distribuïdes.
Mapa de contextos
Tal com ja hem comentat, si separem el nostre sistema en diferents contextos delimitats, podem acabar amb molts contextos petits i hem de tenir clar com interactuaran entre si.
Per això utilitzem el mapa de contextos (o context map en anglès), que és una representació visual dels contextos delimitats i com interaccionen, ja sigui de forma jeràrquica o mitjançant col·laboració.
Si hi ha una relació jeràrquica entre contextos delimitats, el context dominant imposa els seus termes i els contextos subordinats s’hi solen adaptar.
En aquest tipus de relació, els patrons d’integració més comuns són el patró Conformista, el patró Capa d’Anticorrupció, el patró Nucli Compartit i el patró Client-Proveïdor.
De vegades, els contextos delimitats col·laboren entre si en plena igualtat de condicions, i llavors s’han d’utilitzar altres patrons. Aquests són el patró Associació, el patró Nucli Compartit (en efecte, aquest patró es pot utilitzar tant en interacció jeràrquica com en interacció col·laborativa), el patró Llenguatge Publicat i el patró Vies Separades.
La tria entre aquest conjunt de patrons forma part de l’art de fer un disseny guiat pel domini, però aquí tens unes quantes recomanacions:
- Si un context depèn completament d’un altre per funcionar correctament, és més convenient utilitzar un patró jeràrquic. Per exemple, el context de preus està subordinat al context de productes.
- Si tots dos contextos són autònoms i poden funcionar sense que un domini l’altre, és més convenient utilitzar un patró col·laboratiu. Per exemple, el context de comandes i el context d’enviaments, encara que estiguin relacionats, poden col·laborar independentment.
- Si un context sempre executa accions definides per un altre, ens trobem davant d’una relació jeràrquica. Però si els dominis només han de compartir informació, som davant d’una relació de col·laboració.
- Quan utilitzem un patró jeràrquic, si el domini subordinat pot adoptar el model del domini dominant, el més convenient és utilitzar el patró Conformista. Si, en canvi, volem que el domini subordinat mantingui el seu model i les seves regles per consistència interna, haurem d’utilitzar un patró com ara Capa d’Anticorrupció o Nucli Compartit.
- Si un domini influeix en la manera en què es dissenya un altre domini, és millor utilitzar patrons de col·laboració, com l’Associació.
Per fer un mapa de contextos, se solen utilitzar rectangles o caixes per als contextos i fletxes per indicar les relacions entre aquests. Aquestes fletxes poden ser unidireccionals, si la relació és jeràrquica, i bidireccionals, si la relació és col·laborativa. En aquestes fletxes se sol indicar el patró que volem aplicar (Conformista, Associació, etc.). També és habitual, si es té clar en el moment de fer el mapa, indicar el mecanisme que s’utilitza per a aquesta comunicació (API, esdeveniment, integració en codi, etc.).
Tot seguit descrivim breument els principals patrons.
> Patró Conformista
Aquest patró (Conformist en anglès) és jeràrquic i consisteix que el context subordinat accepta completament el model i les regles del context dominant. No intenta modificar-lo en absolut i ni tan sols s’hi adapta per mantenir un mateix propi. L’avantatge que ofereix és que és fàcil d’integrar, però redueix l’autonomia del context i es pot veure afectat per un canvi del context dominant.
> Patró Capa d'Anticorrupció
Aquest patró (Anticorruption Layer en anglès) és jeràrquic i consisteix a protegir el model propi respecte del model del context dominant utilitzant una capa de traducció que actua com a mediador. L’avantatge és que protegeix el context davant dels canvis que es puguin produir en el context dominant i permet mantenir un model independent, però requereix més esforç d’implementació i pot introduir problemes de rendiment pel fet que s’ha d’introduir la capa de traducció.
> Patró Nucli Compartit
Aquest patró (Shared Kernel en anglès) es pot considerar jeràrquic o col·laboratiu. Té una part del model que es comparteix entre tots dos contextos, però pot evolucionar independentment a la resta del model. L’avantatge és que redueix la duplicació dels conceptes comuns i permet consistència de les dades compartides, però els canvis en el nucli compartit afecten els dos dominis i requereix una alta col·laboració entre els equips de tots dominis.
> Patró Client-Proveïdor
Aquest patró (Customer-Supplier en anglès) és jeràrquic i fa que el context subordinat actuï com a client i el context dominant actuï com a proveïdor. En aquest sentit, el subordinat influeix en les decisions del dominant, ja que consumeix dades o funcionalitats adaptades a les seves necessitats. L’avantatge és que facilita la col·laboració i està ben adaptat a les necessitats del subordinat, però requereix una coordinació contínua i activa i, si el dominant té massa subordinats, pot generar feina addicional.
> Patró Associació
Aquest patró (Partnership en anglès) és col·laboratiu i convenient quan tots dos contextos treballen estretament com a socis igualitaris per aconseguir un objectiu comú. La coordinació entre els dos contextos és contínua per garantir la compatibilitat mútua. L’avantatge és que permet una evolució coordinada de tots dos contextos i la integració és la justa i necessària, però el desavantatge és, tal com ja hem indicat, la coordinació contínua. Si tots dos equips no tenen el mateix ritme de treball, pot provocar problemes.
> Patró Llenguatge Publicat
Aquest patró (Published Language en anglès) és col·laboratiu i consisteix a establir un protocol o una forma d’interaccionar per publicar el seu model de manera clara i consistent en altres contextos. Permet fàcilment relacions amb diversos contextos i no només un. L’exemple tècnic d’aquest patró és la publicació d’API amb missatgeries clarament definides mitjançant OpenAPI. Els avantatges són una alta claredat en la integració i que permet interaccionar amb múltiples contextos, però pot requerir canvis en els consumidors quan es canvia el llenguatge publicat i s’ha de mantenir actualitzat i documentat.
> Patró Vies Separades
Aquest patró (Separate Ways en anglès) és col·laboratiu i és convenient quan dos contextos no volen col·laborar de cap manera per, així, poder resoldre els seus problemes de forma independent. Aquest patró sol generar duplicitat de dades o de lògica de negoci, però fomenta l’autonomia i la independència i redueix el risc que un context afecti l’altre.
Conclusions
El Domain-Driven Design ofereix una estratègia per abordar la complexitat d’un sistema d’aplicacions.
Els contextos delimitats permeten dividir el domini en parts manejables i els patrons estratègics faciliten formes d’integrar-se clares i reconeixibles.
Adoptant aquestes pràctiques, es promouen l’autonomia dels equips i la flexibilitat en les aplicacions.
Però, sobretot, fomenta la comunicació clara entre els equips i permet que el model del domini evolucioni juntament amb les necessitats del negoci.
tags:
Comparteix: