Nel mio paese non ce la farai a scuola senza leggere come si lamenta il Faust di Goethe, Ho studiato ora Filosofia - E Giurisprudenza, Medicina, - E anche, ahimè! Teologia - Tutto e per tutto con ardore appassionato! - Eccomi qui, povero pazzo.
Purtroppo, nessuno dei suoi sforzi e studi ha aiutato il medico a percepire ciò che tiene insieme il mondo nelle sue pieghe più interne.
Ed eccoci qui in IT: abbiamo studiato linguaggi e framework, librerie e persino - ahimè - l'IE! In tutto e per tutto con ardore appassionato. Ma quante volte ci siamo concentrati su ciò che tiene insieme l'applicazione nelle sue pieghe più interne? L'argomento di oggi è il dominio aziendale.
La logica aziendale è talvolta considerata unica, ed è per definizione! Se la logica di business di un'applicazione non fosse univoca, non sarebbe necessario scrivere un'applicazione, poiché esiste già una soluzione esistente (ad eccezione di quando esiste un'applicazione ma non è disponibile). Quindi, molti sviluppatori si vedono come pionieri, per andare audacemente dove nessun uomo è mai giunto prima. I romantici a parte, mentre la stessa logica di business può essere unica per un livello degno di nota, le tecniche per implementarlo non lo sono. Ecco perché sono stati invitati modelli di processo intelligenti come Rational Unified Process o Scrum insieme a tecniche come cicli di sviluppo iterativo e incrementale. Talenti architetti di software hanno anche approcci elaborati per la progettazione di software; tra loro Eric Evans chi ha coniato il termine Domain Driven Design nel suo libro con lo stesso titolo.
Gli sviluppatori vanno audacemente, dove nessun uomo è mai giunto prima.
Darò una panoramica su come Domain Driven Design può influenzare il processo di consulenza, così come i suoi concetti di base per la progettazione di un modello di dominio. Infine, discuteremo i requisiti di infrastruttura necessari per implementare un dominio con facilità.
Diciamo che sei un architetto software su un'applicazione non banale con un dominio non banale, come il motore principale di una grande azienda logistica. Molte persone si stanno unendo ai colloqui di pianificazione, tra cui project manager, account manager, marketing, consulenti e così via. Non tutti sono necessari per portare a termine il lavoro (non condividerò le mie opinioni su chi si applica), ma due persone giocheranno un ruolo cruciale durante il processo di ingegneria dei requisiti: tu, l'architetto e l'esperto del dominio.
UN architetto del software (almeno nel contesto aziendale) dovrebbe avere un'ottima comprensione astratta su come funzionano i processi, come sono progettati e ottimizzati.
Questo è vero perché le applicazioni aziendali riguardano principalmente la progettazione di equivalenti digitali efficienti e belli dei processi aziendali. UN esperto di dominio dovrebbe avere una conoscenza approfondita di un insieme specifico di processi, vale a dire i processi che avvengono nella società logistica e che dovrebbero essere riflessi dall'applicazione. Ho scoperto che i consulenti aziendali, il direttore delle vendite e gli esperti di marketing fanno alcuni buoni e preziosi punti lungo la strada, ma finché non si ha qualcuno nella squadra che si sporca le mani in anni di esperienza, il progetto fallirà. Ad esempio, il tuo esperto di dominio dovrebbe conoscere la larghezza della rampa di caricamento del depot e se c'è abbastanza spazio per installare uno scanner di codici a barre.
Quindi sei tu, specializzato in processi aziendali digitali, progettazione di software e [inserisci qui i tuoi strumenti preferiti] e un esperto di logistica con conoscenza dei clienti, dei dipendenti e della routine quotidiana dell'azienda. Le probabilità sono che parlerai a scopi incrociati. Domain Driven Design suggerisce alcune strategie che possono costituire un potente servizio di consulenza tecnica. Ecco il mio:
Sembra divertente! Entriamo nei dettagli.
In ogni settore, ogni gruppo di esperti ha una propria terminologia. È raffinato in ogni azienda e arricchito con termini speciali e nomi di prodotti dell'azienda. Pensa a IT: quando le persone come noi si incontrano per parlare sbrigativamente, chi altro potrebbe capire una parola? Lo stesso vale per il tuo dominio e la prima cosa da fare è definire un insieme di termini. Esaminare l'intero insieme di processi che il software dovrebbe riflettere e ascoltare attentamente come l'esperto di dominio lo descrive. Qualsiasi termine specifico per un dominio dovrebbe essere definito in un modo che i dizionari fanno. Dovresti essere consapevole delle parole che suonano familiari ma che non sono nel contesto dato. Alcune aziende non hanno mai fatto quel lavoro prima, anche se è utile per altre aree.
Crea un glossario dedicato ai tuoi termini onnipresenti, assicurati che venga approvato dal cliente e addebitalo per il processo di consulenza! Un glossario può assomigliare a questo:
Un estratto da un glossario.Si noti come un glossario ben definito imposta già dipendenze e associazioni. Come il ordine, che ospita più persone elementi. Avrai sicuramente lezioni per quelli nella tua logica di business! Il tuo Ordine
la classe avrà presumibilmente un metodo come getItems ()
. Senza tenere conto delle tecniche di programmazione, un glossario può impostare il lavoro di base per il tuo modello di dominio! Insieme a questo, stai costruendo un linguaggio che viene utilizzato nell'intero progetto: nelle mail, nelle riunioni e sicuramente nel codice! Il tuo codice dovrebbe riflettere il dominio; quindi, deve essere definito nel glossario. Ecco una regola generale: ogni volta che crei una classe che non ha un nome dopo una voce nel tuo glossario, la tua lingua ubiquitaria potrebbe non essere definita sufficientemente!
Sotto la copertura dell'oscurità abbiamo spostato la vista sui requisiti! Normalmente, un cliente descrive cosa dovrebbe fare il software da scrivere. Una descrizione tipica potrebbe essere: "Abbiamo bisogno di un modo per aggiungere note a un cliente e stamparle." Questo è un buon punto di partenza, ma non si concentra sul dominio aziendale. Introduce una sorta di interfaccia utente, funzionalità di stampa e molto altro ancora. Ne avrai sicuramente bisogno nella tua applicazione, ma non fa parte del dominio. Domain Driven Design si concentra sulla modellazione del vero scopo di un'applicazione: il dominio aziendale.
Tutto il resto dovrebbe sorgere da lì, una volta che il dominio è finito. Lo switch è il seguente: non implementare i processi e creare un dominio puro che rifletta le esigenze dei client negli oggetti. Un modo di visualizzare la descrizione del cliente superiore sarebbe come questo (getter e setter vengono aggiunti solo, se necessario per la comprensione):
Un semplice diagramma che riflette il dominio richiesto.Ora abbiamo un insieme di classi e associazioni che non fanno altro che riflettere le definizioni del nostro glossario. Questo modello è in grado di eseguire i compiti richiesti? Sicuro! Avrai bisogno di un PrinterService
e un'interfaccia utente da qualche parte nella tua app, ma hanno solo bisogno di prendere alcuni dati dal dominio. Non sono necessari in questo momento e la sua attuazione non sarà decisiva per il risultato.
La filosofia di DDD si basa sul presupposto che uno strato di dominio progettato con cura può eseguire con facilità tutti i processi necessari. Un modello di dominio è scalabile, in quanto non è costruito per soddisfare un determinato compito, è costruito per riflettere un concetto di business. È intercambiabile, in quanto non è legato a nessun software specifico, nemmeno all'interfaccia utente. È possibile utilizzare lo stesso modello nello scanner di codici a barre sulla rampa di carico del deposito! Come vedremo nel prossimo capitolo, non è nemmeno legato ad altri componenti che stanno costruendo la tua applicazione.
In uno dei miei articoli recenti, ho scritto sull'applicazione del principio KISS.
In uno dei miei articoli recenti, ho scritto sull'applicazione del principio KISS: molti sistemi funzionano meglio se vengono mantenuti semplici anziché complessi. Bene, quando si tratta di implementare un dominio basato sulla filosofia del DDD, è possibile incontrare un approccio piuttosto radicale nel mondo moderno di strutture, schemi e discipline; ad esempio, implementa un oggetto ordinario solo nel linguaggio semplice di tua scelta. Nessuna dipendenza da framework, nessuna convenzione di libreria, nessuna traccia di API, nessun nome di fantasia. Solo un semplice oggetto vecchio (dal momento che un concetto non è preso sul serio senza un nome di fantasia nel mondo di Java, ne ha ottenuto uno là).
Quando vogliamo riflettere il modello di dominio, un punto cruciale è definire il suo stato. Nella programmazione orientata agli oggetti, lo stato di un oggetto è definito dallo stato delle sue proprietà. Allo stesso modo, lo stato del modello di dominio è definito dallo stato dei suoi oggetti. Quindi, dobbiamo avere un modo per definire chiaramente lo stato degli oggetti. Se non potessimo farlo, falliremmo in casi di facile utilizzo come "Quanti ordini ci sono?" Perché la risposta richiede sempre la conoscenza dello stato di tutti Ordine
oggetti in un dominio e un modo per identificarli e distinguerli. DDD definisce due tipi di oggetti: entità e oggetti valore.
Un entità è un concetto familiare, se hai familiarità con i database relazionali.
Le tabelle in un database relazionale di solito hanno un identificativo univoco che distingue una riga da un'altra. Lo stesso vale per le entità. Un'entità deve avere un identificatore chiaro che è unico nell'intero sistema. Per un ordine, questa potrebbe essere una proprietà del tipo uint, denominata numero d'ordine
. Certo, esamineresti il tuo glossario, dove dovrebbe essere definito il termine corretto.
Un'entità rimane la stessa quando alcune proprietà cambiano. Ad esempio è possibile aggiungere o rimuovere articoli da un ordine, ma sarebbe lo stesso ordine. Cosa succede quando stai cambiando il numero d'ordine
? Bene, dal POV del tuo dominio, un ordine viene eliminato mentre ne viene creato un altro.
UN oggetto di valore è un semplice contenitore per informazioni. È immutabile una volta creato. Cambiare una proprietà significa che cambierai l'oggetto valore. Un oggetto valore è definito da tutte le sue proprietà; non ha bisogno di un identificatore univoco. L'intero oggetto è uno. Un esempio di oggetto valore sarebbe un OrderAddress
, come è definito dal nome, dall'indirizzo e dalla città del destinatario. Se dovessi cambiare una proprietà, ad esempio la città, il OrderAddress cambierebbe completamente.
Dividere gli oggetti in oggetti valore ed entità è importante per definire lo stato del tuo dominio - poiché questo è il lavoro di base per identificare i componenti. Ma è altrettanto importante definirli per avere un dominio gestibile scalabile. Le entità sono la rappresentazione di oggetti del mondo reale come persone, ordini o oggetti. Gli oggetti valore sono contenitori per informazioni come colori o indirizzi e sono riutilizzabili e condivisibili tra le entità o persino l'intero sistema. Definirli potrebbe richiedere un po 'di pratica, poiché dipende dal caso d'uso se si ha un oggetto valore o un'entità.
Quando torniamo indietro sull'astratto del nostro glossario, possiamo vedere le connessioni e le dipendenze tra i nostri oggetti nel livello del dominio. In DDD, questo è chiamato associazioni ed è il modello di interazioni che stanno avvenendo.
Ad esempio, gli articoli fanno parte dell'ordine. Se dovessimo processare contro un database relazionale, questa sarebbe una relazione uno-a-molti (o 1: n). Se ogni ordine avesse esattamente un OrderAddress, sarebbe una relazione uno-a-uno. Poiché non ci interessano i database relazionali e ci interessa solo finire il dominio, la relazione può essere facilmente espressa con due metodi nella classe Order: getItems ()
e getOrderAddress ()
. Nota, che il primo è plurale (dato che ci sono molti elementi) e il secondo è singolare. Se tu avessi una relazione molti-a-molti, daresti ad entrambe le classi un metodo getter. Certo, hai anche bisogno di setter - li ho omessi per mantenere gli esempi leggeri.
In DDD cerchiamo di evitare relazioni molti-a-molti, poiché tendono ad aggiungere complessità al dominio. Tecnicamente significa che due oggetti devono essere mantenuti sincronizzati durante il loro ciclo di vita e mantenere le cose in sincrono può portare alla violazione del principio di DRY. Ecco perché il processo di rifinitura del modello dovrebbe mirare alla semplicità. In molte occasioni, un'associazione è più forte in una direzione rispetto all'altra, ed è una buona idea ridisegnare la struttura in una relazione uno-a-molti. Controlla se l'associazione è rilevante per la logica di business della tua applicazione. Se si verifica solo in casi di utilizzo non essenziali e rari, potresti voler cercare un altro modo per ricevere le informazioni necessarie.
Le associazioni costruiscono un albero di oggetti e dovresti ritrovarti con un costrutto di associazione in cui ogni oggetto può essere recuperato attraverso i metodi getter. Questo è un costrutto genitore-figlio che alla fine conduce a un oggetto radice. Questo è chiamato aggregazione in DDD. Un buon design alla fine porta a un aggregato in grado di riflettere l'intero dominio. Al momento abbiamo solo esaminato una piccola parte del nostro glossario, ma sembra che un client sia il nostro aggregato di root:
L'oggetto client è il genitore di tutti i membri del dominio.Gli aggregati sono una parte importante, poiché DDD tenta di isolare il dominio dall'applicazione circostante. Se ci piace avere informazioni su un cliente, chiediamo un aggregato di root e possiamo attraversare i suoi figli per accedere alle informazioni attraverso una chiara interfaccia di getter e setter.
Il DDD è come le vendite, fornisce una faccia al cliente, l'aggregato al sistema circostante. Quindi, dà accesso a un insieme strutturato di processi, informazioni e metodi pertinenti; per esempio l'ordine.
Domain Driven Design è come le vendite, fornisce un volto al cliente.
L'applicazione circostante accede a un aggregato tramite repository, che sono fondamentalmente una sorta di facciata. In altre parole: un oggetto dominio è un aggregato se ha un repository. I repository forniscono metodi per interrogare gli aggregati. Gli esempi possono essere findClientByEmail (string email)
o semplicemente trova tutto()
. Sono anche aggiornamenti in esecuzione e stanno aggiungendo nuovi oggetti al dominio. Quindi, probabilmente hanno metodi come aggiungi (Client newClient)
o delete (Client toBeDeletedClient)
.
Con un aggregato stai accedendo ai bambini solo attraverso il suo genitore. Ad esempio, un aggregato di client ti dà accesso a tutti gli ordini da parte del cliente. Ma se hai bisogno di accedere ai dati da un'altra prospettiva rispetto a quella del cliente, puoi stabilire un secondo aggregato. Diciamo che vuoi avere un elenco di tutti gli ordini, indipendentemente da quale client sono stati inseriti. Un repository di ordini completerà il lavoro!
Il livello dominio e i suoi repository.Poiché il repository è il punto di ingresso per l'applicazione circostante al livello del dominio, è dove altri giocatori entrano nell'area. Ricorda che per ora abbiamo a che fare con oggetti semplici.
Ti sei chiesto come questo diventerà reale? Questa è stata l'infrastruttura. DDD è un compagno eccellente per i framework, poiché è costruito su oggetti semplici, con un semplice schema di oggetti valore, entità e aggregati. Tuttavia, poiché la semplicità è la potenza dell'IT, siamo ora in grado di esternalizzare l'intera parte dell'infrastruttura. Diamo un'occhiata sotto il cofano, e come DDD può essere diffuso intorno a un'applicazione.
Potresti aver notato che il nostro focus sul dominio escludeva un livello di persistenza e cose comuni come viste o controllori dalla nostra lista di cose da fare. L'intera applicazione può consistere in cose molto più complesse rispetto a semplici oggetti, e voglio sottolineare alcuni passaggi che devono essere fatti per collegare il dominio e l'app insieme, nonché le strategie di implementazione esistenti. Farò alcuni esempi basati su FLOW3, una struttura applicativa con l'obiettivo principale di fornire l'infrastruttura DDD. Non è necessario, ma non ti farà male se leggi la mia introduzione. Per applicare il dominio aziendale a un'applicazione, i passaggi seguenti sono comuni:
Quando dai un'occhiata ai commenti sull'articolo a Programmazione orientata all'aspetto (AOP), vedrai un'interessante discussione sull'opportunità o meno che un framework aggiunga il proprio footprint tramite annotazioni di commento. L'approccio in FLOW3 si basa su come viene implementato Domain Driven Design. Dai un'occhiata a questo codice:
/ ** * Un client * * @ FLOW3 \ Scope ("prototype") * @ FLOW3 \ Entity * / class Client / ** * Nome del client. * * @ FLOW3 \ Validate (type = "Text") * @ FLOW3 \ Validate (type = "StringLength", options = "minimum" = 1, "maximum" = 80) * @ORM \ Column (lunghezza = 80 ) * stringa @var * / nome $ protetto; / ** * Ottieni il nome del cliente * * @return string Il nome del cliente * / public function getName () return $ this-> Name; / ** * Imposta il nome di questo client * * @param stringa $ Nome Il nome del cliente * @return void * / public function setName ($ name) $ this-> name = $ name;
Questa è una classe molto semplice e non contiene molta logica aziendale, ma probabilmente cambierà una volta che l'applicazione sarà cresciuta. FLOW3 è presente attraverso alcune annotazioni di codice. Sta definendo la classe come un entità e aggiunge alcune regole di convalida da applicare (questo è facoltativo). Nota che c'è un'annotazione chiamata @ORM \ Colonna (lunghezza = 80)
. Questa è un'informazione per il livello di persistenza e torneremo su questo in un momento.
FLOW3 utilizza qui le annotazioni per mantenere pulito il dominio. Sei libero di usare la classe da qualsiasi altra parte, poiché è ancora un oggetto semplice. Puoi scegliere di passare a symfony framework, che usa lo stesso livello di persistenza (Doctrine), quindi il codice funzionerà quasi immediatamente. Spingendo la configurazione del framework al di fuori dell'ambito dell'interprete PHP, il dominio rimane un semplice oggetto PHP vecchio. Puoi riutilizzarlo anche senza alcun framework.
Ma ora che il framework è a conoscenza dell'oggetto, ora può calcolare i requisiti per una tabella di database MySQL. Per memorizzare le istanze del client di classe, FLOW3 (e Doctrine come framework di persistenza) eseguiranno i seguenti passaggi:
La definizione della proprietà per gli articoli nel nostro ordine potrebbe essere simile a questa:
/** * Gli oggetti. * * @ORM \ OneToMany (mappedBy = "order") * @ORM \ OrderBy ("price" = "ASC") * @var \ Doctrine \ Common \ Collections \ Collection<\LogisticApp\Domain\Model\Item> * / protetto $ articoli;
Si noti che questo restituisce una raccolta di Doctrine, che è una sorta di wrapper per un array, come ArrayLists in Java. Essenzialmente questo significa che tutti gli elementi devono essere del tipo dato, in questo caso Item. Ho deciso di aggiungere una dichiarazione d'ordine su come voglio organizzare la raccolta (in base ai prezzi degli articoli).
La controparte nella classe Item potrebbe essere:
/** * L'ordine. * * @ORM \ ManyToOne (inversedBy = "items") * @var \ LogisticApp \ Domain \ Model \ Order * / protected $ order;
È solo la punta di un iceberg, ma dovrebbe darti un'idea di come le cose possono essere automatizzate: Doctrine fornisce una potente strategia su come associare le associazioni alle tabelle in cui memorizza l'oggetto. Ad esempio, poiché gli elementi si tradurrebbero in una relazione uno-a-molti (un ordine potrebbe avere molti elementi) nel database, Doctrine aggiungerebbe silenziosamente una chiave esterna per l'ordine alla tabella degli articoli. Se si decide di aggiungere un repository per l'elemento (rendendolo un aggregato), è possibile accedere magicamente a findByOrder (ordine)
metodo. Questo è il motivo per cui non ci importava dei database o della persistenza durante la creazione del dominio: è qualcosa di cui un framework può prendersi cura.
Nel caso in cui si sia nuovi ai framework di persistenza, il modo di mappare gli oggetti a un database relazionale viene chiamato ORM (Object-Relational Mapping-). Ha alcuni svantaggi in termini di prestazioni, causati principalmente dai diversi approcci che i database relazionali e il modello di oggetti hanno. Ci sono lunghe discussioni a riguardo. Tuttavia, nelle moderne applicazioni CRUD (non solo basate su domini), ORM è la strada da percorrere, principalmente per motivi di manutenzione ed espandibilità. Tuttavia, dovresti conoscere il tuo ORM e avere una buona comprensione di come funziona. Non pensare più che non hai più bisogno di conoscere i database!
Come avrai notato, i tuoi oggetti possono essere silenziosi e avere una lunga traversata se hanno molti bambini, che a loro volta hanno molti figli.
Quindi, una volta che il repository recupera i dati da un database, devono essere trasformati in oggetti in modo intelligente. Dato che ora abbiamo uno strato di persistenza coinvolto, la trasformazione è molto più complessa della semplice istanziazione di un oggetto. Dobbiamo gestire la linea trasversale riducendo al minimo le chiamate pertinenti al database. Non tutti i bambini sono sempre necessari, quindi possono essere recuperati su richiesta.
Alcuni oggetti saranno oggetti valore che devono essere creati una sola volta, il che può far risparmiare molta memoria. Ecco perché, qualsiasi livello di dominio ha bisogno di una fabbrica intelligente che genera gli oggetti per te. Quindi, nei quadri moderni, il nuovo
l'operatore è considerato troppo basso per le applicazioni moderne. FLOW3 fa molto per fornire l'opportunità di creare un'istanza di oggetti con nuovo
parola chiave, ma la compilazione in background modifica automaticamente la creazione di oggetti in chiaro nella gestione di oggetti potenti. Alcune funzionalità di cui dovrebbe essere capace il tuo gestore oggetti / fabbrica, indipendentemente dal framework che usi, sono:
Potresti aver disapprovato l'ultima frase. In tutto l'articolo ho enfatizzato l'uso di oggetti semplici nel dominio e ho anche violato il paradigma "non ripeterti" e l'ho menzionato più volte perché è così importante per DDD. E ora ti sto dicendo che hai dipendenze e servizi che devono far parte del tuo dominio ...
C'è una triste verità nel mondo reale: non esiste una cosa come un dominio puro. Non incontrerai quasi mai un cliente che inizia da zero; quindi, devi soddisfare circostanze come i sistemi legacy. Potrebbero avere un'implementazione orribile, ma la compagnia non può liberarsene. Potrebbe essere necessario chiamare servizi e API e recuperare dati da varie terze parti e questi sistemi legacy influenzano il dominio aziendale.
Tutto ciò di cui abbiamo discusso finora è importante, ma la domanda su come un framework risolve la dipendenza da servizi non di dominio è fondamentale per un Domain Driven Design pulito. Questo è il motivo per cui il team di FLOW3 ha speso enormi sforzi per implementare l'orientamento all'aspetto; è un modo per introdurre servizi nel dominio senza toccare il codice senza violare la regola dei semplici vecchi oggetti. Esistono altri approcci, come lo spostamento delle dipendenze tra i servizi e il dominio nel controller, ma la programmazione orientata all'aspetto è di gran lunga il modo più elegante che conosca. Mi piacerebbe sentire le tue opinioni su questo argomento!
Un buon framework può darti molto supporto oltre ai punti che ho menzionato. Ad esempio, FLOW3 passa in modo trasparente gli oggetti del dominio nella vista con il suo motore di templatura notevolmente cool chiamato Fluid. Scrivere i modelli di fluido, una volta che il dominio è terminato, è rilassante come una giornata in spiaggia.
Questo articolo è solo un'introduzione a Domain Driven Design. Ho presentato alcuni concetti fondamentali, ma devo ammettere che potrebbe essere difficile cogliere solo la teoria. Voglio incoraggiarti a provare Domain Driven Design per il tuo progetto in un mondo reale. Sperimenterai che i concetti di dominio sono molto intuitivi da usare.
Sono stato catapultato in DDD come un pesce fuor d'acqua in un progetto extbase di grandi dimensioni, senza molta conoscenza preliminare dei concetti (extbase è un framework Domain Driven Design per la costruzione di estensioni per il CMS Typo3 ed è basato su FLOW3). Ha ampliato le mie prospettive su come pensare al design del software, e spero che allargherà anche la tua.