Perché dovrei isolare le mie entità di dominio dal mio livello di presentazione?


85

Una parte della progettazione basata sul dominio su cui non sembrano esserci molti dettagli è come e perché dovresti isolare il tuo modello di dominio dalla tua interfaccia. Sto cercando di convincere i miei colleghi che questa è una buona pratica, ma non mi sembra di fare molti progressi ...

Usano entità di dominio dove vogliono nei livelli di presentazione e interfaccia. Quando sostengo loro che dovrebbero utilizzare modelli di visualizzazione o DTO per isolare il livello del dominio dal livello dell'interfaccia, rispondono che non vedono il valore aziendale nel fare qualcosa del genere, perché ora hai un oggetto dell'interfaccia utente da mantenere così come l'oggetto del dominio originale.

Quindi sto cercando alcuni motivi concreti che posso usare per sostenerlo. Nello specifico:

  1. Perché non dovremmo usare oggetti di dominio nel nostro livello di presentazione?
    (se la risposta è ovvia, "disaccoppiamento", spiega perché è importante in questo contesto)
  2. Dovremmo usare oggetti o costrutti aggiuntivi per isolare i nostri oggetti di dominio dall'interfaccia?

questa domanda dovrebbe essere in wiki.
Syed Tayyab Ali

@ m4bwav - Dovrebbe essere un wiki perché è formulato in modo tale da invitare la discussione piuttosto che una singola risposta corretta.
Rob Allen

1
@ m4bwav: Penso che la tua domanda sia venuta fuori più come un'opinione che come una vera domanda ... Ho provato a correggerlo (potresti volerlo modificare ulteriormente), ma tieni presente che senza la dovuta cura potrebbe sembrare essere trolling.
Shog9

5
Ok, backup, sto facendo una domanda legittima, come offenderebbe qualcuno? A chi mi rivolgo?
Mark Rogers

@ m4bwav: stai prendendo di mira il tuo uomo di paglia. Il "gran numero di persone" con cui discuti nella tua domanda.
Shog9

Risposte:


48

Molto semplicemente, il motivo è di implementazione e deriva. Sì, il tuo livello di presentazione deve conoscere i tuoi oggetti aziendali per poterli rappresentare correttamente. Sì, inizialmente sembra che ci sia molta sovrapposizione tra l'implementazione dei due tipi di oggetti. Il problema è che, col passare del tempo, le cose si aggiungono da entrambe le parti. La presentazione cambia e le esigenze del livello di presentazione si evolvono per includere elementi completamente indipendenti dal livello aziendale (colore, ad esempio). Nel frattempo, i tuoi oggetti di dominio cambiano nel tempo e se non disponi di un disaccoppiamento appropriato dalla tua interfaccia, corri il rischio di rovinare il tuo livello di interfaccia apportando modifiche apparentemente benigne ai tuoi oggetti di business.

Personalmente, credo che il modo migliore per affrontare le cose sia attraverso il paradigma dell'interfaccia rigorosamente applicato; ovvero, il livello dell'oggetto di business espone un'interfaccia che è l'unico modo con cui è possibile comunicare; non sono esposti dettagli di implementazione (cioè oggetti di dominio) sull'interfaccia. Sì, questo significa che devi implementare i tuoi oggetti di dominio in due posizioni; il tuo livello di interfaccia e nel tuo livello BO. Ma quella reimplementazione, anche se inizialmente può sembrare un lavoro extra, aiuta a rafforzare il disaccoppiamento che farà risparmiare TONNELLATE di lavoro ad un certo punto in futuro.


2
Cosa intendi per "implementare i tuoi oggetti di dominio in due posizioni?"
jlembke

10
Questo mi sembra sciocco. Perché il lavoro extra ora che POTREBBE risparmiare lavoro in futuro? 9 volte su 10 non avrai mai bisogno di apportare modifiche che risparmierebbero "TONNELLATE" di lavoro.
Beep beep

13
@LuckyLindy: 99 volte su 100 (anzi di più), indossare la cintura di sicurezza non è necessario per impedirmi di ferirmi. Tuttavia, nell'unico caso in cui ne ho davvero bisogno, (probabilmente) mi impedirà di essere ucciso o ferito gravemente. Un grammo di prevenzione vale una libbra di cura. Sospetto che la tua opinione su questo cambierà dopo che avrai più esperienza.
Paul Sonier

19

Ho lottato con questo da solo. Ci sono casi in cui è opportuno utilizzare un DTO nella presentazione. Diciamo che voglio mostrare un elenco a discesa di aziende nel mio sistema e ho bisogno del loro ID a cui associare il valore.

Bene, invece di caricare un CompanyObject che potrebbe avere riferimenti ad abbonamenti o chissà cos'altro, potrei rispedire un DTO con il nome e l'ID. Questo è un buon uso IMHO.

Ora prendi un altro esempio. Ho un oggetto che rappresenta una stima, questa stima potrebbe essere composta da manodopera, attrezzature ecc., Potrebbe avere molti calcoli definiti dall'utente che prende tutti questi elementi e li riassume (ogni stima potrebbe essere diversa con tipi diversi di calcoli). Perché dovrei modellare questo oggetto due volte? Perché non posso semplicemente fare in modo che la mia interfaccia utente enumeri i calcoli e li visualizzi?

In genere non utilizzo DTO per isolare il mio livello di dominio dalla mia interfaccia utente. Li uso per isolare il mio livello di dominio da un confine che è al di fuori del mio controllo. L'idea che qualcuno inserisca le informazioni di navigazione nel proprio oggetto aziendale è ridicola, non contaminare il proprio oggetto aziendale.

L'idea che qualcuno metta la convalida nel proprio oggetto aziendale? Bene, io dico che questa è una buona cosa. La tua interfaccia utente non dovrebbe avere la responsabilità esclusiva di convalidare i tuoi oggetti aziendali. Il tuo livello aziendale DEVE eseguire la propria convalida.

Perché inserire il codice di generazione dell'interfaccia utente in un oggetto busienss? Nel mio caso ho oggetti separati che generano il codice dell'interfaccia utente separatamente dall'interfaccia utente. Ho oggetti separati che rendono i miei oggetti business in Xml, l'idea che devi separare i tuoi livelli per prevenire questo tipo di contaminazione mi è così estranea perché perché dovresti anche inserire il codice di generazione HTML in un oggetto business ...

modificare Come penso un po 'di più, ci sono casi in cui le informazioni dell'interfaccia utente potrebbero appartenere al livello del dominio. E questo potrebbe offuscare quello che chiami un livello di dominio, ma ho lavorato su un'applicazione multi-tenant, che aveva un comportamento molto diverso sia dall'aspetto dell'interfaccia utente che dal flusso di lavoro funzionale. A seconda di vari fattori. In questo caso avevamo un modello di dominio che rappresentava i tenant e la loro configurazione. La loro configurazione includeva informazioni sull'interfaccia utente (etichette per campi generici ad esempio).

Se dovessi progettare i miei oggetti per renderli persistenti, dovrei anche duplicare gli oggetti? Tieni presente che se vuoi aggiungere un nuovo campo ora hai due posti per aggiungerlo. Forse questo solleva un'altra domanda se stai usando DDD, sono tutti oggetti di dominio di entità persistenti? So che nel mio esempio lo erano.


Il fatto che le etichette siano diverse per inquilini diversi non indicherebbero una lingua diffusa e diversa per ogni inquilino? Penso che ci debba essere il concetto di un meta-modello in cui un dominio è condiviso tra gli inquilini con uno strato di traduzione per la loro interpretazione del meta-modello.
Kell

16

Lo fai per lo stesso motivo per cui tieni SQL fuori dalle tue pagine ASP / JSP.

Se mantieni un solo oggetto dominio, da utilizzare nella presentazione E nel livello dominio, quell'oggetto diventa presto monolitico. Inizia a includere codice di convalida dell'interfaccia utente, codice di navigazione dell'interfaccia utente e codice di generazione dell'interfaccia utente. Quindi, presto aggiungi tutti i metodi del livello aziendale in cima a quello. Ora il tuo livello aziendale e l'interfaccia utente sono tutti confusi e tutti stanno scherzando a livello di entità di dominio.

Vuoi riutilizzare quell'elegante widget dell'interfaccia utente in un'altra app? Bene, devi creare un database con questo nome, questi due schemi e queste 18 tabelle. È inoltre necessario configurare Hibernate e Spring (o i framework di scelta) per eseguire la convalida aziendale. Oh, devi anche includere queste altre 85 classi non correlate perché sono referenziate nel livello aziendale, che si trova nello stesso file.


13

Non sono d'accordo.

Penso che il modo migliore per procedere sia iniziare con gli oggetti del dominio nel livello di presentazione FINO A QUANDO NON HA SENSO FARE ALTRIMENTI.

Contrariamente alla credenza popolare, "Oggetti di dominio" e "Oggetti di valore" possono coesistere felicemente nel livello di presentazione. E questo è il modo migliore per farlo: ottieni il vantaggio di entrambi i mondi, duplicazione ridotta (e codice standard) con gli oggetti del dominio; e la personalizzazione e la semplificazione concettuale dell'utilizzo di oggetti valore tra le richieste.


Grazie per il tuo contributo, vedo da dove vieni. Anche se non sto dicendo che questo non è un altro degli infiniti modi per creare un progetto di successo, sembra essere in contrasto con lo stile "Domain-Driven Design", che è per progetti più grandi e complessi che sono più difficili da mantenere a lungo termine.
Mark Rogers

No, questo è sbagliato, ed è esattamente il motivo per cui così tanti siti finiscono per essere vulnerabili all'iniezione sql.
Remi

7

La risposta dipende dalla scala della tua applicazione.


Semplice applicazione CRUD (Crea, Leggi, Aggiorna, Elimina)

Per le applicazioni crud di base non hai alcuna funzionalità. Aggiungere DTO sopra le entità sarebbe una perdita di tempo. Aumenterebbe la complessità senza aumentare la scalabilità.

inserisci qui la descrizione dell'immagine


Applicazione non CRUD moderatamente complicata

In questa dimensione dell'applicazione avrai poche entità che hanno un vero ciclo di vita e una certa logica di business ad esse associata.

L'aggiunta di DTO in questo caso è una buona idea per alcuni motivi:

  • Il livello di presentazione può vedere solo un sottoinsieme di campi di cui dispone l'entità. Incapsulate entità
  • Nessun accoppiamento tra backend e frontent
  • Se disponi di metodi aziendali all'interno delle entità, ma non in DTO, l'aggiunta di DTO significa che il codice esterno non può rovinare lo stato della tua entità.

inserisci qui la descrizione dell'immagine


Applicazione aziendale complicata

Una singola entità potrebbe richiedere più modi di presentazione. Ognuno di loro avrà bisogno di diversi set di campi. In questo caso si verificano gli stessi problemi dell'esempio precedente e in più è necessario controllare la quantità di campi visibili per ogni cliente. Avere DTO separato per ogni client ti aiuterà a scegliere cosa dovrebbe essere visibile.

inserisci qui la descrizione dell'immagine


4

Stiamo usando lo stesso modello nel server e nell'interfaccia utente. Ed è un dolore. Dobbiamo rifattorizzarlo un giorno.

I problemi sono principalmente perché il modello di dominio deve essere tagliato in pezzi più piccoli per poterlo serializzare senza avere referenziato l'intero database. Questo lo rende più difficile da usare sul server. Mancano collegamenti importanti. Alcuni tipi non sono inoltre serializzabili e non possono essere inviati al client. Ad esempio "Tipo" o qualsiasi classe generica. Devono essere non generici e il Tipo deve essere trasferito come stringa. Questo genera proprietà extra per la serializzazione, sono ridondanti e confuse.

Un altro problema è che le entità sull'interfaccia utente non si adattano davvero. Stiamo usando l'associazione dati e molte entità hanno molte proprietà ridondanti solo per scopi ui. Inoltre ci sono molti "BrowsableAttribute" e altri nel modello di entità. Questo è davvero brutto.

Alla fine, penso che sia solo questione di come è più facile. Ci potrebbero essere progetti in cui funziona bene e dove non è necessario scrivere un altro modello DTO.


2
Se intendi utilizzare l'associazione dati, esegui una query linq e collegala a un tipo anonimo. Ciò ti consente di appiattire e modificare la gerarchia. Puoi anche implementare il filtro e l'ordinamento molto bene con questo.
JoshBerke

@ Josh: grazie per il consiglio. Questo potrebbe funzionare parzialmente. Non sono un programmatore di GUI e non sono molto coinvolto nei concetti di GUI. Il problema sarà nei casi in cui i dati vengono manipolati e inviati al server.
Stefan Steinegger

3

Riguarda le dipendenze per la maggior parte. La struttura funzionale principale dell'organizzazione ha i propri requisiti funzionali e l'interfaccia utente dovrebbe consentire alle persone di modificare e visualizzare il nucleo; ma il core stesso non dovrebbe essere richiesto per ospitare l'interfaccia utente. (Se deve accadere, di solito è un'indicazione che il nucleo non è progettato per proprietà.)

Il mio sistema contabile ha una struttura e contenuti (e dati) che dovrebbero modellare il funzionamento della mia azienda. Questa struttura è reale ed esiste indipendentemente dal software di contabilità che utilizzo. (Inevitabilmente un determinato pacchetto software contiene struttura e contenuto fine a se stesso, ma parte della sfida è ridurre al minimo questo sovraccarico.)

Fondamentalmente una persona ha un lavoro da fare. Il DDD dovrebbe corrispondere al flusso e al contenuto del lavoro. DDD consiste nel rendere espliciti tutti i lavori che devono essere eseguiti in modo completo e indipendente possibile. Quindi si spera che l'interfaccia utente faciliti l'esecuzione del lavoro nel modo più trasparente possibile, nel modo più produttivo possibile.

Le interfacce riguardano gli input e le visualizzazioni forniti per il nucleo funzionale correttamente modellato e invariante.


3

Dannazione, giuro che questa ha detto tenacia.

Comunque, è un altro esempio della stessa cosa: la legge di Parnas dice che un modulo dovrebbe mantenere un segreto e il segreto è un requisito che può cambiare. (Bob Martin ha una regola che è un'altra versione di questo.) In un sistema come questo, la presentazione può cambiare indipendentemente dal dominio . Come, ad esempio, un'azienda che mantiene i prezzi in euro e utilizza il francese negli uffici dell'azienda, ma vuole presentare i prezzi in dollari con testo in mandarino. Il dominio è lo stesso; la presentazione può cambiare. Quindi, per ridurre al minimo la fragilità del sistema, ovvero il numero di cose che devono essere modificate per implementare un cambiamento nei requisiti, separare le preoccupazioni.


2

La tua presentazione potrebbe fare riferimento al tuo livello di dominio, ma non dovrebbe esserci alcun legame direttamente dalla tua ui agli oggetti del tuo dominio. Gli oggetti di dominio non sono destinati all'uso dell'interfaccia utente poiché sono spesso, se progettati correttamente, basati su comportamenti e non rappresentazioni di dati. Dovrebbe esserci un livello di mappatura tra l'interfaccia utente e il dominio. MVVM, o MVP, è un buon modello per questo. Se provi a collegare direttamente la tua interfaccia utente al dominio, probabilmente creerai un sacco di mal di testa per te stesso. Hanno due scopi diversi.


1

Forse non stai concettualizzando il livello dell'interfaccia utente in termini sufficientemente ampi. Pensa in termini di molteplici forme di risposta (pagine web, risposta vocale, lettere stampate ecc.) E in termini di più lingue (inglese, francese ecc.).

Supponiamo ora che il motore di sintesi vocale per il sistema di chiamata in ingresso venga eseguito su un tipo di computer completamente diverso (ad esempio Mac) dal computer che esegue il sito Web (forse Windows).

Ovviamente è facile cadere nella trappola "Ebbene nella mia azienda ci interessa solo l'inglese, gestiamo il nostro sito su LAMP (Linux, Apache, MySQL e PHP) e tutti usano la stessa versione di Firefox". Ma tra 5 o 10 anni?



1

Con l'aiuto di strumenti come " Value Injecter " e il concetto di "Mapper" nel livello di presentazione mentre si lavora con le visualizzazioni, è molto più facile comprendere ogni parte di codice. Se hai un po 'di codice, non vedrai subito i vantaggi ma quando il tuo progetto crescerà sempre di più, sarai molto felice mentre lavori con le viste per non dover entrare nella logica dei servizi, repository per comprendere il modello di visualizzazione. View Model è un'altra guardia nel vasto mondo del livello anti-corruzione e vale il suo peso in oro in un progetto a lungo termine.

L'unico motivo per cui non vedo alcun vantaggio nell'usare il modello di visualizzazione è se il tuo progetto è piccolo e abbastanza semplice da avere viste associate direttamente a ciascuna proprietà del tuo modello. Ma se nel futuro, il requisito cambia e alcuni controlli nelle viste non saranno vincolati al modello e non hai un concetto di modello di vista, inizierai ad aggiungere patch in molti punti e inizierai ad avere un codice legacy che non apprezzerai. Certo, puoi fare un po 'di refactoring per trasformare il tuo modello di visualizzazione in view-viewmodel e seguire il principio YAGNI senza aggiungere codice se non ne hai bisogno, ma per me è molto più una best practice che devo seguire per aggiungere un livello di presentazione che espone solo oggetti del modello di visualizzazione.


1

Ecco un esempio reale del motivo per cui trovo che sia una buona pratica separare le entità di dominio dalla vista.

Qualche mese fa ho creato una semplice UI per mostrare i valori di Azoto, Fosforo e Potassio in un campione di terreno attraverso una serie di 3 indicatori. Ogni indicatore aveva una sezione rossa, verde e rossa, cioè potresti avere troppo poco o troppo di ogni componente, ma c'era un livello verde sicuro nel mezzo.

Senza pensarci troppo, ho modellato la mia logica aziendale per fornire dati per questi 3 componenti chimici e una scheda tecnica separata, contenente i dati sui livelli accettati in ciascuno dei 3 casi (inclusa l'unità di misura utilizzata, cioè moli o percentuale). Ho quindi modellato la mia interfaccia utente per utilizzare un modello molto diverso, questo modello era preoccupato per le etichette degli indicatori, i valori, i valori limite ei colori.

Ciò significa che quando in seguito ho dovuto mostrare 12 componenti, ho semplicemente mappato i dati extra in 12 nuovi modelli di visualizzazione del misuratore e sono apparsi sullo schermo. Significava anche che potevo riutilizzare facilmente il controllo del misuratore e visualizzare altri set di dati.

Se avessi accoppiato questi indicatori direttamente nelle entità del mio dominio, non avrei avuto la flessibilità di cui sopra e qualsiasi modifica futura sarebbe stata un mal di testa. Ho riscontrato problemi molto simili durante la modellazione dei calendari nell'interfaccia utente. Se è necessario che un appuntamento del calendario diventi rosso quando ci sono più di 10 partecipanti, la logica aziendale per gestirlo dovrebbe rimanere nel livello aziendale e tutto il calendario nell'interfaccia utente deve sapere, è che è stato istruito a diventa rosso, non dovrebbe essere necessario sapere perché.


-1

L'unico motivo ragionevole per aggiungere un'ulteriore mappatura tra la semantica generalizzata e quella specifica del dominio è che hai (accesso a) un corpo di codice (e strumenti) esistente che si basa su una semantica generalizzata (ma mappabile) distinta dalla semantica del tuo dominio.

I progetti basati sul dominio funzionano meglio se utilizzati insieme a un set ortogonale di framework di dominio funzionale (come ORM, GUI, flusso di lavoro, ecc.). Ricorda sempre che è solo nelle adiacenze dello strato esterno che la semantica del dominio deve essere esposta. Tipicamente questo è il front-end (GUI) e il persistent back-end (RDBM, ORM). Tutti gli strati intermedi progettati in modo efficace possono e devono essere invarianti di dominio.


paragrafo 1: non creare astrazioni non necessarie (ad esempio componenti riutilizzabili) a meno che non vengano effettivamente condivise tra app distinte. paragrafo 2: Mi chiedo come funzionino le GUI generiche in così tanti domini diversi. Nota: questo settore è così rotto, non è nemmeno più divertente ...
alphazero
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.