DDD nel frontend: quando Domain-Driven Design ha senso | POLPROG Vai al contenuto

DDD nel frontend: quando Domain-Driven Design ha senso

Domain-Driven Design non è una convenzione di cartelle e non è riservato al backend. Il suo obiettivo è rendere gestibili domini di business complessi tramite linguaggio condiviso, modelli espliciti e confini di contesto chiari. Nel frontend, DDD può portare molto valore in grandi applicazioni di prodotto, ma può anche diventare sovra-architettura costosa. La domanda chiave è dove il client contiene vera complessità di dominio e dove invece svolge soprattutto un ruolo di presentazione.

Pubblicato Scritto da Tempo di lettura 9 min di lettura

Domain-Driven Design non è una convenzione di cartelle e non è riservato al backend. Il suo obiettivo è rendere gestibili domini di business complessi tramite linguaggio condiviso, modelli espliciti e confini di contesto chiari. Nel frontend, DDD può portare molto valore in grandi applicazioni di prodotto, ma può anche diventare sovra-architettura costosa. La domanda chiave è dove il client contiene vera complessità di dominio e dove invece svolge soprattutto un ruolo di presentazione.

In questa pagina
  1. 1DDD non inizia da una cartella `domain`
  2. 2DDD strategico e DDD tattico operano a livelli diversi
  3. 3Un Bounded Context non è un livello tecnico
  4. 4Quando DDD nel frontend ha senso
  5. 5Quando DDD diventa sovra-architettura
  6. 6Ubiquitous Language dovrebbe essere visibile anche nel codice UI
  7. 7Organizza un frontend grande per domini, non solo per tipi di file
  8. 8Separa comportamento di presentazione e comportamento di dominio
  9. 9Livelli pratici dentro un contesto frontend
  10. 10Modello API e modello di dominio frontend non devono essere identici
  11. 11Entities, Value Objects e Aggregates: usali in modo selettivo
  12. 12Stato UI e stato di dominio non sono la stessa cosa
  13. 13I confini vanno applicati, non solo documentati
  14. 14Frontend e backend possono condividere il dominio senza condividere un modello identico
  15. 15La testabilità è un forte argomento per isolare la logica di dominio
  16. 16Introdurre DDD in un frontend esistente senza un grande rewrite

DDD non inizia da una cartella `domain`

Eric Evans presenta DDD come un insieme di pattern e definizioni per lavorare con modelli di dominio, mentre Martin Fowler sottolinea la modellazione di domini complessi e lo sviluppo di un linguaggio condiviso tra sviluppatori ed esperti di business. [1][2][4]

Di conseguenza, una struttura `domain/application/infrastructure` non rende automaticamente un'applicazione DDD. Si possono avere cartelle perfettamente nominate e lavorare comunque solo con DTO e logica procedurale. Il DDD strategico può inoltre essere applicato senza una struttura canonica a livelli.

DDD strategico e DDD tattico operano a livelli diversi

Il DDD strategico riguarda la suddivisione di un dominio ampio in sottodomini e Bounded Contexts e le relazioni tra essi. Microsoft descrive l'analisi di dominio come identificazione di sottodomini e contesti, mentre Fowler considera Bounded Context un pattern centrale del DDD strategico. [3][7]

Il DDD tattico lavora all'interno di un contesto specifico e include pattern come Entities, Value Objects, Aggregates e Domain Services. Microsoft separa esplicitamente analisi strategica e modellazione tattica. [8]

Nel frontend conviene spesso iniziare dal livello strategico e decidere solo dopo quali contesti necessitano davvero di un modello tattico ricco.

Un Bounded Context non è un livello tecnico

Fowler descrive un Bounded Context come un confine entro cui un modello rimane coerente e i termini hanno significato non ambiguo. Lo stesso concetto, come `Customer` o `Product`, può avere significati diversi in contesti differenti. [3]

Per questo `frontend`, `backend`, `React app`, `route` o `micro-frontend` non sono automaticamente Bounded Contexts. I confini derivano dal modello e dal linguaggio del dominio, non dalla tecnologia. Anche guide pratiche sul DDD frontend sottolineano questa distinzione. [15][16]

Quando DDD nel frontend ha senso

SegnaleDirezionePerché
Molte regole di business variabiliDDDUn modello di dominio evita regole sparse
Gli stessi concetti hanno significati diversi nel prodottoDDDI Bounded Contexts mantengono più modelli coerenti
Più team ed esperti di dominio collaboranoDDDUbiquitous Language riduce l'ambiguità
CRUD semplice e formModularità più sempliceIl costo del DDD tattico può superare il beneficio
Il frontend rispecchia soprattutto un'APIModularità più sempliceC'è poca logica di dominio propria del client
Applicazione piccola con un dominio coerenteModularità più sempliceConfini e livelli aggiuntivi possono portare poco valore

Il segnale più forte è la presenza di regole di business complesse e mutevoli lato client: configuratori, processi multi-step, pricing, permessi, transizioni di stato, workflow o modelli diversi dello stesso concetto in aree differenti del prodotto.

DDD è utile anche quando più team lavorano su un grande prodotto e le stesse parole assumono significati diversi in aree differenti. I Bounded Contexts servono proprio a gestire più modelli coerenti. [3]

DDD Crew raccomanda prima di comprendere il dominio, identificare i sottodomini strategicamente importanti, definire le responsabilità dei Bounded Contexts e solo dopo codificare il modello. [10]

Quando DDD diventa sovra-architettura

Se il frontend principalmente recupera dati, li mostra, gestisce form e invia semplici comandi CRUD senza regole di business rilevanti lato client, l'intero insieme dei pattern tattici DDD raramente risolve un problema concreto.

Microsoft afferma esplicitamente che per un contesto CRUD semplice un modello dati anemico può essere sufficiente e pattern DDD più complessi possono non valere il costo. Un modello ricco è più utile quando esistono molte regole di business in continua evoluzione. [9]

Lo stesso criterio dovrebbe valere nel frontend: la sofisticazione dell'architettura deve seguire la complessità del dominio, non l'ambizione tecnica del team.

Ubiquitous Language dovrebbe essere visibile anche nel codice UI

Ubiquitous Language è un linguaggio comune e rigoroso costruito da sviluppatori ed esperti di dominio intorno al modello. Fowler sottolinea che deve evolvere insieme alla comprensione del dominio. [4]

Nel frontend, nomi di use case, azioni, tipi, moduli, schermate e stati dovrebbero quindi usare il vocabolario di business quando esprimono comportamento di dominio.

Se il business parla di `approveApplication` ma il codice usa `setFlag2` o `handleData`, il codice smette di essere una rappresentazione chiara del linguaggio del dominio.

Organizza un frontend grande per domini, non solo per tipi di file

Fowler osserva che una struttura top-level `view/model/data` può essere adeguata nei sistemi piccoli, ma crescendo è spesso meglio avere moduli top-level orientati al dominio che contengono internamente i propri livelli. [5]

La documentazione attuale di Nx segue una direzione simile: le cartelle possono diventare confini di ownership di dominio e le librerie interne possono essere classificate come `feature`, `ui`, `data-access` e `util`. [12]

Una struttura pratica può quindi usare `libs/orders/...`, `libs/billing/...`, `libs/identity/...` invece di un unico albero globale `components/`, `services/`, `models/`.

Separa comportamento di presentazione e comportamento di dominio

Fowler descrive la separazione tra presentazione, logica di dominio e accesso ai dati come una modularizzazione efficace. Osserva anche che il codice UI è spesso più difficile da testare, quindi mantenere la logica di dominio fuori dalla presentazione migliora la testabilità. [5][6]

Un componente frontend dovrebbe principalmente renderizzare, gestire eventi UI e delegare operazioni. Regole come se un ordine possa essere annullato, come calcolare uno sconto o quale transizione di stato sia valida dovrebbero avere una sede esplicita fuori da JSX, template o classi di componente.

Questo non vieta la logica di presentazione nei componenti. Validazione della vista, visibilità, focus locale o animazioni sono diverse dalle regole di business.

Livelli pratici dentro un contesto frontend

LivelloResponsabilitàEsempi
presentation / uiRendering e comportamento dell'interfacciacomponents, routes, view state
applicationCoordinamento dei casi d'usocommands, use cases, orchestration
domainRegole, concetti e invarianti di dominioentities, value objects, policies
infrastructure / data-accessIntegrazioni tecnicheHTTP, storage, SDKs, mappers

DDD non impone una struttura di cartelle obbligatoria. Separare `presentation`, `application`, `domain` e `infrastructure` è un'interpretazione pratica della separazione delle responsabilità, non un requisito formale di Evans. [1][5]

Il livello domain può contenere regole, concetti e comportamenti indipendenti dal framework; application coordina i use case; infrastructure adatta HTTP, storage e SDK esterni; presentation contiene componenti, routing e stato puramente UI.

Modello API e modello di dominio frontend non devono essere identici

Un Bounded Context può avere il proprio modello di un concetto e contesti diversi possono mappare rappresentazioni differenti. Fowler usa `Customer` e `Product` come esempi comuni di termini con significati diversi a seconda del contesto. [3]

Un DTO backend non deve quindi arrivare direttamente in ogni componente. Un mapper o adapter può trasformare il contratto di trasporto nel modello usato da uno specifico contesto frontend.

Questo confine è particolarmente utile quando un'API serve più client, è legacy, combina più domini o evolve indipendentemente. Per un endpoint CRUD semplice, un ulteriore livello di mapping può essere superfluo.

Entities, Value Objects e Aggregates: usali in modo selettivo

DDD distingue concetti come Entities, Value Objects, Services e Aggregates. Fowler li evidenzia come parte del vocabolario di Evans, mentre Microsoft descrive gli aggregati come pattern tattico per mantenere la coerenza del modello. [2][8]

Il frontend non dovrebbe copiare il modello backend uno a uno solo per avere le stesse classi. Un Value Object può essere utile per `Money`, `DateRange` o `Email` se protegge invarianti reali. Un Aggregate ha senso se il client deve davvero garantire regole di coerenza del modello.

Se un tipo è solo dati per renderizzare una tabella, un semplice tipo TypeScript può essere migliore di Entity, Factory, Repository e Service.

Stato UI e stato di dominio non sono la stessa cosa

React tratta l'organizzazione dello stato come un problema di progettazione e raccomanda di evitare stato ridondante o duplicato. È una buona base tecnica, ma reducer, store o signals non creano da soli un modello di dominio. [14]

Stato come `isModalOpen`, tab attiva o posizione di scroll appartiene alla presentazione. Il ciclo di vita di un ordine, le transizioni consentite o le regole di un configuratore possono appartenere al dominio.

Separare le due categorie evita store globali che mescolano dati server, comportamento di business e dettagli UI.

I confini vanno applicati, non solo documentati

Nx permette di definire tag di progetto e vincoli dichiarativi sulle dipendenze, per esempio bloccando import tra scope o tipi di libreria. `@nx/enforce-module-boundaries` può verificare gli import durante il lint. [11]

Nx supporta anche più dimensioni di tag, permettendo di modellare separatamente `scope`, tipo di libreria, stabilità o distinzione client/server. [13]

Le decisioni DDD possono quindi diventare regole CI: `billing` non importa gli interni di `identity`, `ui` non dipende da `data-access` e `domain` rimane indipendente dal framework.

Frontend e backend possono condividere il dominio senza condividere un modello identico

Un Bounded Context è un confine di modello e linguaggio e non dovrebbe quindi essere tracciato automaticamente sulla separazione di rete tra browser e server. Guide pratiche sul DDD frontend sottolineano che i contesti possono attraversare livelli tecnici ed essere implementati congiuntamente da frontend e backend. [15][16]

La rappresentazione client può comunque differire da quella server perché interazione, stato locale e presentazione hanno esigenze diverse. È importante preservare la semantica e mappare esplicitamente, non copiare classi.

Un micro-frontend non dovrebbe essere creato solo perché esiste un Bounded Context. Confine di dominio e confine di deployment sono decisioni separate.

La testabilità è un forte argomento per isolare la logica di dominio

Fowler indica la testabilità come beneficio della separazione tra presentazione e dominio. La logica fuori dalla UI può essere testata senza renderizzare componenti o dipendere da dettagli dell'interfaccia. [5][6]

Nel frontend questo consente test rapidi di regole, Value Objects, use case e transizioni di stato come normale TypeScript o JavaScript. I test dei componenti restano necessari, ma non devono essere l'unico luogo in cui verificare le regole di business.

Un segnale di allarme è quando ogni modifica a una regola richiede di montare un componente completo e mockare router, store, HTTP e API del browser.

Introdurre DDD in un frontend esistente senza un grande rewrite

DDD Crew raccomanda un processo iterativo: comprendere il dominio, identificare sottodomini importanti, definire le responsabilità dei Bounded Contexts e poi codificare il modello. [10]

In un frontend esistente è più sicuro scegliere un'area di business problematica, definirne linguaggio e confine, separare presentazione e regole, definire l'API pubblica del modulo e solo dopo migrare altre funzionalità.

Non serve migrare tutta l'applicazione. DDD può essere applicato dove la complessità di business ripaga il costo di modellazione, lasciando le aree semplici come moduli funzionali più leggeri.

  • Parti da un problema di business, non dalle cartelle.
  • Identifica termini, regole e concetti ambigui.
  • Definisci un Bounded Context e il suo contratto pubblico.
  • Separa regole di dominio, componenti e DTO di trasporto.
  • Aggiungi solo pattern tattici che risolvono una complessità concreta.
  • Trasforma i confini in regole di lint o CI.
  • Misura dipendenze, cicli, regressioni e costo dei cambiamenti trasversali.
  • Non migrare aree CRUD semplici solo per simmetria architetturale.

DDD nel frontend ha senso quando il client è parte di un prodotto complesso e non soltanto un renderer di dati. Il ritorno maggiore arriva spesso dal DDD strategico: linguaggio comune, confini di contesto e limiti modulari realmente applicati. I pattern tattici vanno aggiunti solo dove regole, invarianti e comportamenti giustificano un modello più ricco. Se l'applicazione è soprattutto CRUD, form e rendering diretto di API, una buona modularità e una separazione chiara tra presentazione e dati sono spesso preferibili a un DDD completo.

DDD Domain-Driven Design Frontend Architecture Software Architecture Bounded Context Ubiquitous Language TypeScript Nx React Angular

Domande frequenti

DDD ha senso nel frontend?

Sì, quando il frontend partecipa a un dominio complesso e beneficia di confini espliciti, linguaggio condiviso o regole di business lato client. DDD non è solo backend. [1][2][15]

Ogni frontend dovrebbe usare DDD?

No. Per applicazioni CRUD semplici, il DDD tattico completo può essere inutile. Microsoft afferma esplicitamente che un contesto CRUD semplice non richiede sempre un modello ricco. [9]

Il frontend è un Bounded Context separato?

Non automaticamente. Un Bounded Context è un confine di modello e linguaggio coerenti, non un confine tecnologico. [3][16]

Ogni Bounded Context dovrebbe diventare un micro-frontend?

No. Un confine di dominio non richiede un deployment separato. L'architettura micro-frontend è una decisione distinta. [3][15]

Serve una cartella domain?

No. DDD non prescrive una struttura obbligatoria. Una cartella può aiutare la separazione, ma non crea da sola un modello di dominio. [1][5]

Dove dovrebbe stare la logica di business nel frontend?

Fuori dalla presentazione pura, in un modello esplicito o in un livello di use case del contesto. Fowler raccomanda la separazione tra presentazione e dominio. [5][6]

Un DTO API può essere il modello di dominio?

In un caso banale può esserlo, ma non è obbligatorio. Contesti diversi possono modellare lo stesso concetto in modo differente, quindi il mapping è spesso appropriato. [3]

Repository ha senso nel frontend?

Solo se risolve un vero problema di astrazione nell'accesso al modello. Per un semplice fetch, un Repository aggiuntivo può essere superfluo. [1][9]

Redux, NgRx, Zustand o Signals fanno parte di DDD?

No. Sono meccanismi di gestione dello stato. Possono contenere stato di dominio, ma non definiscono modello, linguaggio o Bounded Context. [14]

Il modello di dominio frontend deve essere identico al backend?

No. Deve preservare la semantica corretta, ma la rappresentazione può adattarsi alle esigenze del client. [3]

Come imporre i confini di dominio in un monorepo?

Nx può usare tag e @nx/enforce-module-boundaries per bloccare automaticamente dipendenze non consentite. [11][13]

Da dove iniziare in un'applicazione esistente?

Da un'area di business complessa: comprenderne linguaggio, regole e confine. DDD Crew raccomanda un percorso iterativo dal dominio ai contesti e al codice. [10]

Fonti e riferimenti

  1. Eric Evans, DDD Reference12345
  2. Martin Fowler, Domain Driven Design123
  3. Martin Fowler, Bounded Context12345678
  4. Martin Fowler, Ubiquitous Language12
  5. Martin Fowler, Presentation Domain Data Layering123456
  6. Martin Fowler, Presentation Domain Separation123
  7. Microsoft Azure Architecture Center, Use Domain Analysis to Model Microservices
  8. Microsoft Azure Architecture Center, Use Tactical DDD to Design Microservices12
  9. Microsoft .NET, Design a microservice domain model123
  10. DDD Crew, DDD Starter Modelling Process123
  11. Nx, Enforce Module Boundaries12
  12. Nx, Monorepo Folder Structure
  13. Nx, Tag in Multiple Dimensions12
  14. React, Managing State12
  15. ANGULARarchitects, DDD in Angular & Frontend Architecture1234
  16. Tomasz Ducin, Your Frontend itself is NOT a Bounded Context123

È stato utile?

Ricevi i nuovi articoli via e-mail

Una breve e-mail per ogni nuovo articolo di Formazione. Niente spam, disiscriviti con un clic.

Usiamo la tua e-mail solo per inviare nuovi articoli. Nessuna condivisione con terze parti.

Torna alla Formazione