Come combinare TDD e DDD rigorosi?


15

TDD riguarda la progettazione di codice, guidato da test.
Pertanto, i livelli tipici non vengono generalmente creati in anticipo; dovrebbero apparire leggermente attraverso i passaggi di refactoring.

La progettazione guidata dal dominio comprende molti modelli tecnici, che definiscono livelli ben consolidati come Livello applicazione, Livello infrastruttura, Livello dominio, Livello persistenza.

Per iniziare da zero la parte di codifica di un progetto DDD, come comportarsi?
Devo lasciare che il design emerga rigorosamente dai test, il che significa che non c'è separazione tra preoccupazioni (senza strati) e refactor per adattarsi ai modelli tecnici DDD?

O dovrei creare quei livelli vuoti (applicazione, entità / servizi di dominio, infrastruttura) e lasciare che TDD si adatti a ciascuno di essi in modo indipendente (usando i mock per isolare tra i livelli)?


Risposte:


12

Assicurati di rivedere i recenti commenti di zio Bob sul ruolo del design in TDD .

La progettazione guidata dal dominio comprende molti modelli tecnici, che definiscono livelli ben consolidati come Livello applicazione, Livello infrastruttura, Livello dominio, Livello persistenza.

Udi Dahan: "Dio, come odio la stratificazione." Trascorre un po 'di tempo a discuterne nel suo discorso CQRS - ma diverso (la stratificazione inizia a 18m30s)

Scriverei la tua frase in modo leggermente diverso; "DDD riconosce che esistono molte preoccupazioni comuni alla maggior parte delle applicazioni aziendali e che le soluzioni a tali preoccupazioni hanno una durata diversa" .

Ad esempio, i problemi di dominio, di norma, devono essere flessibili, soprattutto quando si personalizza una soluzione per un'azienda specifica. Dopotutto, il dominio riguarda il modo in cui l'azienda fa affari, vale a dire, come l'azienda fa soldi e essere in grado di fornire rapidamente miglioramenti aziendali è entrate gratuite.

D'altra parte, probabilmente non è necessario cambiare spesso la componente di persistenza. La soluzione di database che ha funzionato l'ultima versione probabilmente funzionerà anche questa versione.

Le preoccupazioni dell'applicazione sono da qualche parte nel mezzo; tendono ad essere stabili in modo che gli utenti non debbano imparare una nuova app ad ogni versione.

Inoltre, possono esserci più implementazioni per risolvere qualsiasi dato problema. Ad esempio, l'applicazione potrebbe richiedere solo un'istantanea del suo stato corrente: basterà semplicemente salvare un file su disco. E nelle tue prime iterazioni, potrebbe essere necessario anche tutto il dominio. Ma alla fine arriva una storia che richiede il supporto di query ad hoc e si riconosce che la configurazione di un database relazionale sarà molto più semplice rispetto all'implementazione da zero. E poi c'è questa caratteristica che funzionerebbe meglio in un database grafico.

Nel frattempo, il CTO vuole una versione dell'app che gira sul suo telefono; il CEO ha appena sentito da un ragazzo che pubblicare un'API è la cosa più importante.

Inoltre, il team di vendita utilizza un modello diverso, quindi forniscici la stessa app, con un modello diverso. Oh, ma stiamo viaggiando molto, quindi la nostra versione deve funzionare quando non siamo in linea e la sincronizzazione in seguito ...

In altre parole, applichi i modelli tattici di non implementando segnaposto vuoti e supponendo che verranno riempiti in seguito, ma riconoscendo invece quando attraversi i flussi "Ehi, questo è il codice di persistenza nel mio modello di dominio, non devo essere fatto refactoring ancora. "


11

Test Driven Development (TDD) non è un progetto. È un requisito che influisce sul tuo design. Proprio come se ti fosse richiesto di essere thread-safe, questo non è un design. Ancora una volta, è un requisito che influisce sul tuo design.

Se ignori allegramente tutte le altre preoccupazioni di progettazione e segui religiosamente le regole del TDD, non dare la colpa al TDD quando il tuo codice si trasforma in schifo. Sarà una merda testabile ma sarà una merda.

Una cosa bella delle cazzate testabili è che si tratta di una cagata refactorable, quindi per alcune persone è abbastanza buona. Ci immagineremo solo quando necessario. Altri lo odiano e danno la colpa a TDD. No. Questo sta facendo.

Domain Driven Design (DDD) è qualcosa che fai prima del ciclo di rifattori verde rosso di TDD.

DDD è lo sforzo di creare e preservare uno spazio nel codice in cui un esperto di dominio, che è in gran parte ignaro dei dettagli del sistema, può capire come controllarlo. Questo viene fatto per astrazione e modellizzazione di un dominio problematico in modo familiare.

Un sistema DDD può avere un'architettura simile a questa:

inserisci qui la descrizione dell'immagine

Questa architettura DDD ha molti nomi: Clean , Onion , Hexagonal , ecc

Ecco la disconnessione che vedo molte persone quando guardano questo design. Questo non è concreto. Posso seguire questo disegno e non ho mai scritto nulla che vedi qui schematicamente. Vedo che altri insistono sul fatto che ci deve essere un oggetto case use o una classe entity. Che cosa sono queste sono una serie di regole che ti dicono con chi puoi parlare e come.

Questo è tutto. Segui le regole di questo design e puoi TDD il tuo cuoricino fuori. A TDD non importa con chi parli. Si preoccupa che tutto ciò che fa qualcosa possa essere dimostrato di funzionare o meno con un clic di un pulsante. No, qualcosa da qualche parte è rotto. Ti dice esattamente cosa è rotto.

Ancora vago? Guarda il diagramma Controler- Use Case Interactor- Presenternell'angolo in basso a destra. Qui ci sono tre cose concrete che comunicano tra loro. Sicuro, questo è DDD, ma come si aggiunge TDD qui? Basta prendere in giro le cose concrete. Il relatore deve ricevere informazioni. Una PresenterMocklezione sarebbe un buon modo per verificare se sta ottenendo ciò che ti aspettavi. La mano Use Case Interactorl' PresenterMocke guidare il Use Case Interactorcome se tu fossi il Controllere si ha un bel modo per il test di unità Use Case Interactordal momento che il finto vi dirà se ha ottenuto quello che vi aspettavate esso per ottenere.

Bene guarda quello. TDD è soddisfatto e non abbiamo dovuto rinunciare al nostro design DDD. Come è successo? Abbiamo iniziato con un design ben disaccoppiato.

Se usi TDD per guidare il design (non semplicemente D Evelopment) otterrai un design che riflette lo sforzo che ci metti. Se è quello che vuoi bene. Ma questo non è mai stato pensato per TDD. Ciò che alla fine manca non è certamente colpa di TDD.

TDD non riguarda il design. Se è necessario apportare modifiche alla progettazione per utilizzare TDD, si verificano problemi maggiori rispetto ai test.


Non ho mai detto che TDD sia un design, ma riguarda il design.
Mik378,

1
Lo zio Bob ti stava dicendo di progettare. Non ti stava dicendo "hey se sei un test di lavoro che si preoccupa per il resto".
candied_orange

1
Come ho già detto, basta seguire le regole di chi ti è permesso parlare. L'architettura pulita non è qualcosa su cui discutere un BDUF. Basta identificare in quale parte ti trovi e pensare a chi e come dovresti comunicare. È più agile di quanto si possa pensare. Dopodiché chiedi se è testabile da TDD. Altrimenti hai fatto qualcosa di sbagliato. Se lo è, spero che tu stia prestando attenzione perché un buon design è più che testabile.
candied_orange

6
Ugh ... Non riesco proprio a sopportare il termine "Test Driven Design". Devi ancora progettare un po 'prima di iniziare a battere beatamente sulla tastiera, indipendentemente dal fatto che tu scriva o meno dei test.
RubberDuck,

1
Per citare lo zio Bob su questo punto esatto, "Devi progettare il periodo" . Fai clic lì e se sei troppo impaziente per leggere il tutto cerca quelle parole. Scoprirai che Mr Martin è abbastanza irremovibile che TDD non è un proiettile magico e che devi progettare non solo il tuo codice ma anche i tuoi test se non vuoi vivere in una base di codici molto fragile.
candied_orange

4

TDD assicura che il tuo codice abbia tutti i casi di test necessari scritti parallelamente allo sviluppo. Ciò non dovrebbe influire sulla progettazione di alto livello. Pensaci più nel lavoro in trincea.

DDD si basa su progetti di alto livello, linguaggio tra esperti e ingegneri di dominio, mappatura di contesto, ecc. Questo dovrebbe essere il driver della progettazione di alto livello dell'applicazione.

Queste sono entrambe spiegazioni superficiali di due potenti metodologie di programmazione. Ma alla fine realizzano due cose molto diverse.

Inizia con il linguaggio DDD e la mappatura del contesto, quindi alla fine quando vai a scrivere il codice inizia la pratica di TDD. Ma la pratica del TDD non dovrebbe influire sulla progettazione di alto livello, ma dovrebbe assicurare che le cose possano essere testate. C'è un piccolo avvertimento qui.

Penso che potrebbe essere importante notare: dovresti praticare DDD solo se l'applicazione è abbastanza complessa.


1
Non sono d'accordo, TDD non riguarda i test, ma la progettazione.
Mik378,

Sto basando tutto sulle 3 regole di TDD descritte da Zio Bob.
Matt Oaxaca,

Steve Freeman, autore del libro GOOS, ha dichiarato: non è necessario specificare alcun livello o infrastruttura prima di avviare i cicli TDD.
Mik378,

Non ho familiarità con quel libro, ma dovrei non essere d'accordo. Non voglio che TDD modelli il mio grafico DI e di classe.
Matt Oaxaca,

3
@ Mik378: TDD non riguarda i test, ma non riguarda principalmente la progettazione: l'unico design indotto da TDD è il design per l'unità di testabilità. Ogni altra parte del design deve provenire da qualche altra parte. Vedo TDD più come una tecnica di implementazione.
Doc Brown,

3

DDD riguarda la progettazione di software.
TDD riguarda la progettazione del codice.

In DDD, il "modello" rappresenta l'astrazione del dominio, tutte le conoscenze dell'esperto del dominio.

Potremmo usare TDD per il modello di progettazione del software iniziale del codice. Il dominio ha regole di business e modelli di dominio che il test scritto (primi) dovrebbe essere verde.

In effetti, possiamo codificare i test, dopo aver progettato un modello basato sul dominio.
Questo libro "Software orientato agli oggetti in crescita, guidato da test" link-for-buy
Adotta questo approccio, con uno scheletro ambulante , un'architettura esagonale e TDD.

Fonte da: DDD rapidamente - InfoQ


1
bene per me il software e il codice sono la stessa cosa
Konrad,

1
Potrebbe anche essere lo stesso. Ho provato a dire: software come "soluzione", "sistema", "alto livello" e codice come "implementazione", "basso livello", "dettagli".
JonyLoscal,

Penso che la cosa importante sia che "prima testiamo, ma abbiamo bisogno di uno scheletro minimo in cui inizieremmo i test". Fai?
JonyLoscal,

1

Devo lasciare che il design emerga dai test

No. (Domain Driven) Il design per definizione dovrebbe emergere dai requisiti del dominio. Questa è una cattiva idea di consentire a qualcos'altro di guidare la progettazione, che si tratti di suite di test, schema di database o ... (continua)

O dovrei creare quei livelli vuoti (applicazione, entità / servizi di dominio, infrastruttura) e lasciare che TDD si adatti a ciascuno di essi in modo indipendente

(continua) ... o alcuni strati canonici di classi / gerarchie di classi nella tua lingua preferita di OO preferita, anche se è molto matura e popolare (dopo tutto "milioni di mosche non possono essere sbagliate", giusto?) .

Quando si tratta di DDD, OOP non soddisfa i requisiti in forma leggibile dall'uomo, ovvero qualcosa che sarebbe più o meno chiaro per un non programmatore. Le lingue FP tipizzate in modo rigoroso fanno un lavoro migliore. Consiglio di leggere un libro su DDD usando la programmazione funzionale "Domain Modeling Made Functional" di Scott Wlaschin

https://pragprog.com/book/swdddf/domain-modeling-made-functional

Non devi usare il linguaggio FP per prendere in prestito alcune delle idee da lì (non tutte purtroppo), ma se lo leggi davvero probabilmente vorrai usare un linguaggio funzionale.

Risponderà anche alla tua domanda su come TDD si adatta all'immagine DDD. In breve, quando i requisiti sono codificati in stile funzionale, elimina la necessità di una grande quantità di test unitari poiché rende la maggior parte degli stati e scenari non validi rappresentabili / impossibili da compilare. Naturalmente, c'è ancora posto per i test automatizzati nel progetto FP, ma i test non guideranno in alcun modo le decisioni di progettazione importanti.

Per fare un cerchio completo, torniamo alla domanda del titolo, ad esempio "Come combinare TDD e DDD rigorosi?". La risposta è semplice: non c'è nulla da combinare / nessun conflitto di interessi. Progetta in base alle esigenze, sviluppa secondo la progettazione (scrivendo prima i test se vuoi davvero fare TDD)


+1 per il libro FPD DDD e spiegazione generale.
Roman Susi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.