Software Engineering

Realizzazione del Back End Enterprise con DDD

A prescindere dalla tecnologia che state utilizzando, almeno una volta avrete sentito parlare di Domain-Driven Design.

Ma cos’è realmente il Domain-Driven Design?

 

Il DDD è un paradigma, un approccio che focalizza la sua forza nella comprensione condivisa delle esigenze del domain business e nella stesura di codice che le rifletta.

In questo articolo parleremo e approfondiremo un progetto reale, sviluppato da Team Scaling in collaborazione e per conto di Adrias Online, azienda specializzata nella creazione di siti web full responsive e marketing per il mondo del turismo.

Il sistema è stato progettato in modo da poter immagazzinare dati di navigazione forniti sia dai turisti che dalle diverse strutture ricettive, interagendo direttamente con varie tipologie di Campagne Marketing.

Continua a leggere l’articolo o guarda questo estratto dal talk tenuto da Giovanni Paolo Scioni, Back End Developer & System Administrator, per l’Università degli Studi di Urbino.

 

Obiettivi primari

In prima battuta abbiamo definito gli obiettivi primari assolutamente indispensabili in modo da ottenere un sistema:

 

  • Scalabile;
  • Manutenibile;
  • Altamente performante.

Grazie a un brainstorming preliminare abbiamo indirizzato la scelta verso l’utilizzo di un pattern architetturale a microservizi, in modo da garantire al progetto manutenibilità e alte performances.

Per la scalabilità, invece, si è optato per Serverless e Lambda.

 

Per lo sviluppo ci siamo orientati verso il Domain-Driven Design, un approccio fondamentale per la comprensione e la costruzione di progetti di alta qualità che apporta diversi vantaggi al fine di soddisfare gli obiettivi primari:

 

  1. Creare valore e concretezza grazie all’Ubiquitous Language;
  2. Fornire metodi chiari e precisi sulla progettazione dei modelli;
  3. Permettere il disaccoppiamento del codice della tecnologia d’ausilio utilizzata;
  4. Valorizzare le Best Practices ed il Clean Code;
  5. Favorire la semplificazione e la segregazione delle logiche di dominio.

 

Cos’è l’Ubiquitous Language? Unire esperti di dominio al team di sviluppo

Uno dei pilastri fondamentali del DDD fra tutti è l’Ubiquitous Language, necessario per far sì che Esperti di Dominio e Team di Sviluppo si comprendano.

L’Ubiquitous Language permette un costante rapporto di collaborazione, attraverso continui Event Storming in cui vengono definite le decisioni necessarie per lo sviluppo del progetto ed i suoi punti chiave.

 

Context Maps

Nello specifico Use Case di Adrias Online, grazie agli Event Stormingsiamo riusciti a definire e concettualizzare ogni tassello del progetto, mantenendo il focus sulle reali esigenze di dominio.

 

 

Esempio di struttura in DDD

 

Da questo esempio è possibile vedere come abbiamo suddiviso differenti Bounded Contexts mantenendo le logiche di dominio in cima alla scala d’importanza.

Come afferma Vaughn Vernon, rinomato esperto di Domain-Driven Design: “Ogni componente del software ha uno specifico significato e segue specifiche logiche.

Bounded Context sono tasselli autonomi che svolgono determinate attività seguendo logiche ben definite e le directories al loro interno sono i cosiddetti layers che compongono i Bounded Context.

 

Hexagonal Architecture

Conosciuto anche come ports & adaptersquello di Hexagonal Architecture è un pattern che permette di dividere il sistema in più elementi non accoppiati interscambiabili tra loro.

 

È stato creato da Alistair Cockburn nel 2005 per evitare limitazioni strutturali nella programmazione ad oggetti, come ad esempio dipendenze indesiderate tra diversi strati dell’applicazione e contaminazioni tra logiche di dominio e User Interface.

In verità l’esagono è puramente illustrativo, non importa quanti “lati” dichiariamo, quello che importa è che per ognuno di essi venga predisposto un port ed un rispettivo adapter.

Ma è davvero necessario per il nostro progetto? Assolutamente si. Quasi sempre è bene disaccoppiare e mantenere separati i diversi strati del software.

Nel nostro caso si è resa estremamente utile per contribuire attivamente alla manutenibilità e alla crescita del progetto.

 

Un pò di codice: esempio reale di DDD

 

Ecco un esempio di modello di dominio situato nel cuore della nostra applicazione.

Come potete notare esso contiene:

 

  1. Codice agnostico e indipendente;
  2. Classi e metodi mantengono fede all’Ubiquitous Language;
  3. Codice pulito e nomi parlanti.

Ma vediamo ora come questo modello comunica all’esterno, mettendo in pratica il concetto di Ports & Adapters.

ports sono solitamente interfacce che offrono agli adapters i metodi esatti per potersi collegare:

 

Esempio di adapter dell’entità di dominio Cluster che gestisce la persistenza dell’entità all’interno del database relazionale con l’utilizzo di Doctrine.

 

 

Application Service: il binario di comunicazione

Ora che abbiamo concretizzato il nostro modello di dominio e dichiarato in quale modo dovrà comunicare con lo strato infrastrutturale dovremo eseguire le logiche di input/output provenienti dallo strato esterno, ma in che modo?

Grazie agli Application Service comunicheremo con il Domain Core ed eseguiremo la business logic per la quale sono concepiti.

 

Richiamati dallo strato esterno dell’infrastruttura che contiene i Controllers:

 

 

Test, test e ancora test

Grazie all’atomicità del codice e al modello architetturale i test sono stati nostri compagni di viaggio per l’intero progetto.

I test vengono effettuati su 3 livelli, in prima fase su pre-commit, in seconda fase sulla build job nella creazione dell’artefatto ed infine in fase di deployment (inclusi i test e2e):

 

  • test unitari vengono eseguiti in modalità shuffle così da confermare l’effettivo isolamento;
  • test funzionali e di integrazione vengono eseguiti con l’ausilio di mock e stubs all’interno del codice, oltre che ad un mock server istanziato al momento dei test che emula la request/response di terzi servizi, oltre che la comunicazione interna tra diversi microservizi.

Grazie al Domain-Driven Design si è riuscito a raggiungere appieno tutti gli obiettivi preposti, garantendo al progetto un bassissimo tasso di debito tecnico, promuovendo l’utilizzo delle best practices e principi S.O.L.I.D. così da innalzare la qualità del software rilasciato.

* [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)
* [PHP CS Fixer configs](https://mlocati.github.io/php-cs-fixer-configurator)
* [Commitlint](https://commitlint.js.org/#/)
* [Commitlint rules](https://www.npmjs.com/package/@commitlint/config-conventional#rules)
* [Psalm](https://psalm.dev)
* [Symfony Lock](https://symfony.com/doc/current/components/lock.html)
* [Deptrac](https://github.com/qossmic/deptrac)

Grazie all’utilizzo di Deptrac, un tool di analisi codice statico, è stato possibile verificare, ad ogni commit, che ogni singolo layer non dipenda da parti di codice estranee al suo contesto.

In conclusione

Grazie al Domain-Driven Design si è riuscito a raggiungere appieno tutti gli obiettivi preposti, garantendo al progetto un bassissimo tasso di debito tecnico, promuovendo l’utilizzo delle best practices e principi S.O.L.I.D. così da innalzare la qualità del software rilasciato.

[/vc_column_text][/vc_column][/vc_row]Per questo progetto sono stati utilizzati diversi tools per garantire valore e stabilità.

* [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)
* [PHP CS Fixer configs](https://mlocati.github.io/php-cs-fixer-configurator)
* [Commitlint](https://commitlint.js.org/#/)
* [Commitlint rules](https://www.npmjs.com/package/@commitlint/config-conventional#rules)
* [Psalm](https://psalm.dev)
* [Symfony Lock](https://symfony.com/doc/current/components/lock.html)
* [Deptrac](https://github.com/qossmic/deptrac)

Grazie all’utilizzo di Deptrac, un tool di analisi codice statico, è stato possibile verificare, ad ogni commit, che ogni singolo layer non dipenda da parti di codice estranee al suo contesto.

In conclusione

Grazie al Domain-Driven Design si è riuscito a raggiungere appieno tutti gli obiettivi preposti, garantendo al progetto un bassissimo tasso di debito tecnico, promuovendo l’utilizzo delle best practices e principi S.O.L.I.D. così da innalzare la qualità del software rilasciato.

[/vc_column_text][/vc_column][/vc_row]

Per questo progetto sono stati utilizzati diversi tools per garantire valore e stabilità.

* [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)
* [PHP CS Fixer configs](https://mlocati.github.io/php-cs-fixer-configurator)
* [Commitlint](https://commitlint.js.org/#/)
* [Commitlint rules](https://www.npmjs.com/package/@commitlint/config-conventional#rules)
* [Psalm](https://psalm.dev)
* [Symfony Lock](https://symfony.com/doc/current/components/lock.html)
* [Deptrac](https://github.com/qossmic/deptrac)

Grazie all’utilizzo di Deptrac, un tool di analisi codice statico, è stato possibile verificare, ad ogni commit, che ogni singolo layer non dipenda da parti di codice estranee al suo contesto.

In conclusione

Grazie al Domain-Driven Design si è riuscito a raggiungere appieno tutti gli obiettivi preposti, garantendo al progetto un bassissimo tasso di debito tecnico, promuovendo l’utilizzo delle best practices e principi S.O.L.I.D. così da innalzare la qualità del software rilasciato.

[/vc_column_text][/vc_column][/vc_row]

 

Analisi del codice e tools

Per questo progetto sono stati utilizzati diversi tools per garantire valore e stabilità.

* [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)
* [PHP CS Fixer configs](https://mlocati.github.io/php-cs-fixer-configurator)
* [Commitlint](https://commitlint.js.org/#/)
* [Commitlint rules](https://www.npmjs.com/package/@commitlint/config-conventional#rules)
* [Psalm](https://psalm.dev)
* [Symfony Lock](https://symfony.com/doc/current/components/lock.html)
* [Deptrac](https://github.com/qossmic/deptrac)

Grazie all’utilizzo di Deptrac, un tool di analisi codice statico, è stato possibile verificare, ad ogni commit, che ogni singolo layer non dipenda da parti di codice estranee al suo contesto.

In conclusione

Grazie al Domain-Driven Design si è riuscito a raggiungere appieno tutti gli obiettivi preposti, garantendo al progetto un bassissimo tasso di debito tecnico, promuovendo l’utilizzo delle best practices e principi S.O.L.I.D. così da innalzare la qualità del software rilasciato.

[/vc_column_text][/vc_column][/vc_row]