Ubiquitous Language

Domain-driven design (DDD) non è un argomento nuovo (Eric Evans ha formalizzato il concetto oltre un decennio fa). Tuttavia, è curioso come, fino ad oggi, i concetti di base sull’argomento suscitino interesse, specialmente nelle comunità .NET. Ancora più strano è come questi stessi concetti vengano male interpretati.

Il fondamento di DDD sta nel concetto di linguaggio onnipresente. Non sta nel determinare cosa sia un’entità, un oggetto valore, un aggregato, un servizio o un repository.

L’impressione che abbiamo è che chiunque inizi a studiare DDD legga le prime pagine del libro di Evans o del libro di Vernon e salti velocemente alle pagine che descrivono i pattern.

Parliamo spesso con persone IT che pensano che avere un linguaggio ubiquo definito significa che il nome delle classi e delle proprietà, scritto dai programmatori, sia conforme al vocabolario degli esperti di dominio. Tuttavia, questa è una grossolana semplificazione.

Per capire l’importanza del linguaggio ubiquo, cominciamo con l'”entità” elencata qui sotto:

public class Employee{ public string Id { get; set; } public string Name { get; set; } public string Cpf { get; set; } public decimal Salary { get; set; }}

Ecco un eccellente esempio di implementazione anemica! Ma prima di continuare a leggere, cercate di capire perché.

Nel nostro lavoro quotidiano, quando usiamo questo esempio, sentiamo suggerire che questa classe manca di comportamenti (il che è giusto!). Tuttavia, quando chiediamo quali sarebbero questi “comportamenti”, troviamo che le persone ripetono argomenti generici (da persone che non hanno nemmeno “capito” l’idea) e non possono identificare cosa c’è di sbagliato!

Uno degli argomenti più frequenti è che i setter delle proprietà dovrebbero essere privati. Al loro posto, dovremmo avere metodi “DefineXXX” che implementerebbero le validazioni. Questa idea non ha senso perché lo scopo dei setter è proprio quello di impostare i valori per le proprietà, e non ci sarebbe alcun problema ad implementare la logica di validazione in essi.

I metodi di un’entità dovrebbero spiegare le motivazioni dei suoi cambiamenti di stato. Inoltre, ci deve essere almeno un costruttore in grado di istanziare l’entità dall’inizio, in uno stato valido.

Non è raro trovare implementazioni di classi con proprietà che controllano, per esempio, se il valore che si sta cercando di impostare è non-null, anche quando queste stesse proprietà hanno null come valore predefinito. Qual è la logica qui?

Vedi un altro esempio di classe anemica:

public class Customer { public string Name { get; private set; } public string Email { get; private set; } public DateTime BirthDate { get; private set; } public Customer(Guid id, string name, string email, DateTime birthDate) { Id = id; Name = name; Email = email; BirthDate = birthDate; } }

Nella classe sopra, abbiamo un tipico “record” per un’implementazione funzionale. Ma in un linguaggio orientato agli oggetti, questo non è un’entità.

L’idea avrebbe anche senso in un linguaggio puramente funzionale dove l'”entità” è concettualmente distribuita in varie funzioni che definiscono il comportamento, ma in C#, non ha alcun senso.

Provo una seconda versione per la classe Employee:

public class Employee{ public string Id { get; private set; } public string Name { get; private set; } public string Cpf { get; private set; } public decimal Salary { get; private set; } public Employee(string name, string cpf) { //.. } public void RaiseSalary(decimal amount) { //.. }}

Questa volta l’entità è meno anemica. Dopo tutto, le motivazioni che guidano il cambiamento del valore della proprietà sono evidenti. Notate come anche il valore della scrittura dei test diventa più esplicito.

Ad ogni modo, abbiamo ancora problemi. Abbiamo chiamato il metodo “RaiseSalary”, tuttavia, questo non è il modo in cui gli esperti di dominio descrivono questa operazione. L’unico modo per definire i motivi reali per cambiare i valori delle proprietà è parlare con questi esperti.

Pensare a…

Identificare e implementare il linguaggio ubiquo non serve solo a definire i nomi delle classi o delle proprietà. Il linguaggio ubiquo deve essere rivelato soprattutto nelle motivazioni dei cambiamenti di stato delle nostre entità in modo esplicito.

Comprendere il linguaggio ubiquo è molto più importante che imparare gli standard. Senza una reale conoscenza del dominio, il valore dei design pattern è nullo.

Preoccupatevi prima di imparare il più importante. Prendetevi il tempo e lo sforzo di capire bene il dominio e di sillabare il suo linguaggio onnipresente. Allora potrebbe anche avere senso pensare di associare DDD a concetti tecnici più avanzati.

Si può pensare di associare DDD a concetti tecnici più avanzati.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.