El disseny estratègic és la part del DDD que decideix com dividir un domini gran en peces manejables i coherents. A la lliçó anterior vam aprendre a classificar subdominis; ara traçarem els límits concrets del model dins del programari mitjançant el concepte més important de tot el DDD: el Bounded Context (context delimitat). Al costat d'ell estudiarem el Llenguatge Ubic, el vocabulari compartit que manté alineats negoci i desenvolupament. Aquesta lliçó és important perquè és on el DDD connecta directament amb l'arquitectura: els límits que tracem aquí determinaran, per exemple, les fronteres dels nostres microserveis. Equivocar-se en aquests límits és una de les causes més cares de fracàs en sistemes distribuïts.
Contingut
- El problema: un mateix terme, significats diferents
- Llenguatge Ubic
- Bounded Context (context delimitat)
- Relació entre Bounded Contexts i microserveis
- Exemple integrat en una asseguradora
- El problema: un mateix terme, significats diferents
En qualsevol organització mitjana, les mateixes paraules signifiquen coses diferents segons el departament. Pensem en la paraula "Client" en una asseguradora:
- Per a l'àrea Comercial, un Client és un lead amb dades de contacte i un historial d'interaccions de venda.
- Per a l'àrea de Subscripció, un Client és un perfil de risc amb edat, professió i sinistralitat prèvia.
- Per a l'àrea de Facturació, un Client és un compte amb domiciliació bancària, rebuts i deutes.
Si intentem crear una única classe Cliente gegant que serveixi a tothom, obtenim un objecte enorme, ple de camps que només alguns utilitzen, amb regles contradictòries i que ningú pot modificar sense por de trencar una altra àrea. Aquest és el clàssic "model únic per a tota l'empresa", i sempre fracassa en dominis complexos.
El DDD proposa el contrari: acceptar que el significat depèn del context i traçar límits explícits.
- Llenguatge Ubic
El Llenguatge Ubic (Ubiquitous Language) és un vocabulari comú, rigorós i compartit entre desenvolupadors i experts del domini, que s'usa a tot arreu: a les converses, a la documentació i —crucialment— al codi.
Principis:
- Cada terme té un significat únic i precís dins del seu context.
- Si el negoci diu "subscriure una pòlissa", el codi té un mètode
suscribir(), nocreate()nisave(). - El llenguatge evoluciona: quan es descobreix un matís, s'actualitzen alhora el llenguatge parlat i el codi.
Vegem la diferència que produeix en el codi:
// SENSE Llenguatge Ubic: noms tècnics genèrics
public class PolicyManager {
public void process(PolicyData data) { /* ... */ }
public void update(Long id, int status) { /* ... */ }
}Problemes del fragment anterior:
PolicyManager,processiupdateno diuen res del negoci. Què processa? Què actualitza?- L'estat es representa amb un
int: ningú sap què significastatus = 2. - Un expert del domini no podria llegir aquest codi ni validar que fa el correcte.
// AMB Llenguatge Ubic: el codi parla l'idioma del negoci
public class Poliza {
public void suscribir(Suscriptor suscriptor) { /* ... */ }
public void rechazarPorRiesgoExcesivo(MotivoRechazo motivo) { /* ... */ }
public void renovar() { /* ... */ }
}Aquí:
- Els noms
suscribir,rechazarPorRiesgoExcesivoirenovarsón exactament els verbs que usa el negoci. - Els tipus
SuscriptoriMotivoRechazosón conceptes del domini, no dades primitives soltes. - Un expert del domini pot llegir i entendre què fa la classe, cosa que permet detectar errors de modelatge en conversa, sense executar res.
El Llenguatge Ubic és el pont que elimina la traducció constant entre "el que diu el negoci" i "el que escriu el programador".
- Bounded Context (context delimitat)
Un Bounded Context és una frontera explícita dins de la qual un model de domini i el seu Llenguatge Ubic tenen un significat únic i consistent. Fora d'aquesta frontera, els mateixos termes poden significar una cosa diferent, i això està bé.
Cada Bounded Context té:
- El seu propi model de domini.
- El seu propi Llenguatge Ubic (la paraula "Client" es pot modelar de manera diferent en cadascun).
- Les seves pròpies regles de negoci i, normalment, la seva pròpia base de dades.
Tornant a l'exemple del "Client":
| Bounded Context | Com modela el "Client" | Atributs rellevants |
|---|---|---|
| Vendes | Lead / Prospecte |
Dades de contacte, fase de l'embut, comercial assignat |
| Subscripció | Assegurat / Perfil de Risc |
Edat, professió, historial de sinistralitat |
| Facturació | CompteDeClient |
Forma de pagament, rebuts, saldo pendent |
La idea radical és: no existeix un únic "Client". Existeixen tres models diferents, cadascun òptim per al seu context, que comparteixen una identitat referenciada (un identificador comú) però no la mateixa estructura. Com es comuniquen aquests contextos ho veurem a la lliçó 06-04 (Context Mapping).
graph LR
subgraph BC_Ventas[Bounded Context: Vendes]
L[Lead]
end
subgraph BC_Suscripcion[Bounded Context: Subscripcio]
A[Assegurat]
end
subgraph BC_Facturacion[Bounded Context: Facturacio]
C[CompteDeClient]
end
L -. mateix client real .-> A
A -. mateix client real .-> CSobre aquest diagrama Mermaid (graph LR, d'esquerra a dreta):
- Cada
subgraphrepresenta un Bounded Context amb la seva frontera explícita. - Dins de cada context viu un model diferent del "client":
Lead,Assegurat,CompteDeClient. - Les fletxes puntejades (
-.->) indiquen que es refereixen a la mateixa persona real, però no comparteixen el mateix model de codi: estan connectades per identitat, no per estructura.
- Relació entre Bounded Contexts i microserveis
Existeix una correspondència natural —però no obligatòria— entre els Bounded Contexts i els microserveis:
| Concepte | Bounded Context (DDD) | Microservei (arquitectura) |
|---|---|---|
| Naturalesa | Frontera lògica d'un model | Unitat física de desplegament |
| Defineix | Significat consistent dels termes | Procés independent, API, BD pròpia |
| Relació | És un bon candidat a microservei | Idealment, alinea la seva frontera amb un BC |
La bona pràctica és: un microservei hauria de contenir un o diversos Bounded Contexts complets, mai partir un Bounded Context entre diversos microserveis. Si parteixes un context, reparteixes el seu model i les seves regles entre serveis diferents, cosa que genera un acoblament fortíssim i comunicació constant.
Els Bounded Contexts ofereixen el criteri de descomposició que els equips de microserveis solen trobar a faltar. Sense DDD, molts parteixen els serveis per entitats tècniques ("servei d'usuaris", "servei de comandes") i acaben amb un monòlit distribuït.
Exemple de com un Bounded Context es tradueix en la configuració d'un microservei independent:
# desplegament del microservei que implementa el Bounded Context de Subscripcio
apiVersion: apps/v1
kind: Deployment
metadata:
name: suscripcion-service # un BC = un servei desplegable
spec:
replicas: 2
template:
spec:
containers:
- name: suscripcion
image: registry.fiatc/suscripcion:1.4.0
env:
- name: DB_URL
value: jdbc:postgresql://db-suscripcion:5432/suscripcion # BD pròpiaComentaris sobre aquest YAML de Kubernetes:
name: suscripcion-servicedeixa clar que el servei correspon a un únic Bounded Context (Subscripció).imagereferencia la imatge de contenidor d'aquest context, versionada de manera independent.- La variable
DB_URLapunta adb-suscripcion: una base de dades pròpia i exclusiva del context. Altres contextos no hi accedeixen directament; això preserva la frontera.
- Exemple integrat en una asseguradora
Posem-ho tot junt. Una asseguradora podria organitzar el seu sistema en aquests Bounded Contexts:
graph TD
V[Vendes] --> S[Subscripcio]
S --> P[Gestio de Polisses]
P --> SI[Gestio de Sinistres]
P --> F[Facturacio]
SI --> FLectura del diagrama:
- Vendes capta interessats; quan un accepta, passa a Subscripció.
- Subscripció avalua el risc i, si l'aprova, Gestió de Pòlisses crea la pòlissa.
- Gestió de Sinistres i Facturació depenen de la pòlissa vigent.
Cadascun d'aquests contextos té el seu propi Llenguatge Ubic: a Vendes es parla de "Lead" i "oportunitat"; a Sinistres, de "comunicat", "perit" i "indemnització". Forçar un vocabulari únic entre tots ells seria un error.
Errors Comuns i Consells
- El model únic corporatiu. Intentar que una sola classe
ClienteoProductoserveixi a tota l'empresa. Resultat: un objecte inmanejable. Accepta la multiplicitat de models. - Bounded Contexts massa petits. Si cada entitat és el seu propi context, tindràs centenars de serveis diminuts parlant entre si sense parar. El context ha de ser cohesionat, no atòmic.
- Confondre frontera lògica amb frontera física. Un Bounded Context és un concepte lògic del DDD; un microservei és una decisió de desplegament. Pots començar amb diversos contextos dins d'un mateix monòlit (un monòlit modular) i separar-los en serveis només quan calgui.
- No mantenir viu el Llenguatge Ubic. Si el negoci canvia un terme i el codi no, el pont es trenca. Refactoritza els noms quan canviï el llenguatge.
- Consell: organitza els teus paquets Java per Bounded Context (
com.fiatc.suscripcion,com.fiatc.siniestros), no per capa tècnica (controllers,services). El paquet ha de cridar el domini.
Exercicis
Exercici 1. Tria el terme "Producte" en una botiga en línia i descriu com el modelaries de manera diferent en com a mínim dos Bounded Contexts (per exemple, Catàleg i Inventari).
Exercici 2. Reescriu la següent signatura de mètode aplicant el Llenguatge Ubic del domini de sinistres: void update(Long id, int type, String text).
Exercici 3. Un equip ha dividit el seu sistema en "servei-base-de-dades", "servei-lògica" i "servei-frontend". Explica per què aquesta divisió no es correspon amb Bounded Contexts i proposa una alternativa.
Solucions
Solució 1. En el context de Catàleg, un Producte és contingut de màrqueting: nom, descripció, fotos, preu de venda, categories. En el context d'Inventari, el mateix producte és una ReferenciaDeStock: SKU, unitats disponibles, ubicació al magatzem, punt de reposició. Comparteixen l'identificador del producte, però els seus atributs i regles són diferents.
Solució 2. Una possible reescriptura: void registrarParteDeSiniestro(IdSiniestro id, TipoSiniestro tipo, DescripcionDanos descripcion). Els noms reflecteixen els conceptes del negoci i els tipus substitueixen els primitius genèrics.
Solució 3. Aquesta divisió és tècnica per capes, no per domini: cada "servei" necessita els altres per fer qualsevol cosa, cosa que produeix un acoblament total i comunicació constant (un monòlit distribuït). Una alternativa basada en Bounded Contexts seria dividir per capacitats de negoci —per exemple, "Subscripció", "Pòlisses", "Sinistres"— on cada servei conté la seva pròpia lògica, dades i interfície de la seva part del domini.
Conclusió
Hem vist que el disseny estratègic tracta de traçar fronteres: el Llenguatge Ubic garanteix que negoci i codi parlin el mateix idioma, i el Bounded Context delimita l'abast dins del qual aquest idioma i el seu model són consistents. Hem comprovat que un mateix concepte del món real ("Client", "Producte") es modela de manera diferent en cada context, i que aquests contextos són els millors candidats per definir les fronteres dels microserveis, evitant el temut monòlit distribuït.
A la lliçó següent, "Disseny Tàctic: Entitats, Agregats i Repositoris", baixarem del mapa estratègic al detall d'implementació: veurem amb codi Java com construir el model ric dins d'un Bounded Context usant els patrons tàctics del DDD.
Curs d'Arquitectura d'Aplicacions
Mòdul 1: Fonaments de l'Arquitectura d'Aplicacions
- Què és l'Arquitectura d'Aplicacions?
- El Rol de l'Arquitecte de Programari
- Atributs de Qualitat i Requisits No Funcionals
- Decisions Arquitectòniques i Compromisos (Trade-offs)
- Documentació d'Arquitectura: Vistes i el Model C4
Mòdul 2: Principis i Tàctiques de Disseny
- Acoblament, Cohesió i Separació de Responsabilitats
- Principis SOLID Aplicats a l'Arquitectura
- DRY, KISS, YAGNI i Altres Principis de Disseny
- Tàctiques Arquitectòniques per als Atributs de Qualitat
- Gestió del Deute Tècnic
Mòdul 3: Estils i Patrons Arquitectònics
- Arquitectura Monolítica
- Arquitectura en Capes (N-Tier)
- Arquitectura Client-Servidor
- Arquitectura Hexagonal (Ports i Adaptadors)
- Arquitectura Neta i Ceba (Clean & Onion)
Mòdul 4: Arquitectures Distribuïdes i Microserveis
- Introducció als Sistemes Distribuïts
- Arquitectura de Microserveis
- Descomposició de Serveis i Bounded Contexts
- API Gateway, Service Discovery i Comunicació entre Serveis
- Patrons de Resiliència: Circuit Breaker, Retry i Bulkhead
- El Teorema CAP i la Consistència de Dades
Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria
- Fonaments de l'Arquitectura Orientada a Esdeveniments
- Missatgeria Asíncrona: Cues i Brokers
- Patrons d'Esdeveniments: Event Sourcing i CQRS
- Gestió de Transaccions Distribuïdes: Patró Saga
- Streaming de Dades en Temps Real
Mòdul 6: Disseny Dirigit pel Domini (DDD)
- Conceptes Fonamentals del DDD
- Disseny Estratègic: Bounded Contexts i Llenguatge Ubic
- Disseny Tàctic: Entitats, Agregats i Repositoris
- Mapatge de Contextos (Context Mapping)
Mòdul 7: Dades i Persistència
- Estratègies de Persistència: SQL vs NoSQL
- Patrons d'Accés a Dades: Repository, Unit of Work i DAO
- Base de Dades per Servei i Gestió de Dades Distribuïdes
- Cau i Estratègies d'Invalidació
Mòdul 8: Arquitectura al Núvol i Desplegament
- Fonaments del Cloud Computing (IaaS, PaaS, SaaS)
- Contenidors i Orquestració amb Docker i Kubernetes
- Arquitectura Serverless
- Patrons de Disseny Cloud-Native
- Infraestructura com a Codi (IaC)
Mòdul 9: Qualitat, Seguretat i Observabilitat
- Escalabilitat: Horitzontal vs Vertical i Balanceig de Càrrega
- Alta Disponibilitat i Tolerància a Fallades
- Seguretat per Disseny i Autenticació/Autorització
- Observabilitat: Logging, Mètriques i Traçabilitat
- Rendiment i Proves de Càrrega
