Domanda

Una parte del design guidato dal 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 sembra che stia facendo molti progressi ...

Usano entità di dominio ogni volta che lo desiderano nei livelli di presentazione e interfaccia. Quando discuto con loro che dovrebbero usare modelli di visualizzazione o DTO per isolare il livello Dominio dal livello dell'interfaccia, ribattono che non vedono il valore aziendale nel fare qualcosa del genere, perché ora hai un oggetto UI da mantenere così come l'oggetto di dominio originale.

Quindi sto cercando alcuni motivi concreti che posso usare per eseguire il backup. In particolare:

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

Soluzione

Molto semplicemente, il motivo è di implementazione e deriva. Sì, il tuo livello di presentazione deve conoscere i tuoi oggetti business 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 vengono aggiunte da entrambi i lati. La presentazione cambia e le esigenze del livello di presentazione 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 hai il 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 avvicinarsi alle cose sia attraverso il paradigma dell'interfaccia rigorosamente applicato; ovvero, il livello dell'oggetto business espone un'interfaccia che è l'unico modo con cui può essere comunicata; non sono esposti dettagli di implementazione (ovvero oggetti di dominio) sull'interfaccia. Sì, questo significa che devi implementare gli oggetti del tuo dominio in due posizioni; il tuo livello di interfaccia e nel tuo livello BO. Ma quella reimplementazione, sebbene inizialmente possa sembrare un lavoro extra, aiuta a rafforzare il disaccoppiamento che salverà tonnellate di lavoro ad un certo punto in futuro.

Altri suggerimenti

Ho lottato con questo me stesso. Ci sono casi in cui un DTO ha senso usare nella presentazione. Diciamo che voglio mostrare un menu a discesa delle aziende nel mio sistema e ho bisogno del loro ID per associare il valore.

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

Ora fai 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 prendono tutti questi elementi e li riassumono (ogni stima potrebbe essere diversa con tipi diversi dei calcoli). Perché dovrei modellare questo oggetto due volte? Perché non posso semplicemente avere la mia UI enumerata nei calcoli e mostrarli?

In genere non uso 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 business è ridicola, non contaminare l'oggetto business.

L'idea che qualcuno avrebbe inserito la convalida nel proprio oggetto business? Bene, dico che questa è una buona cosa. L'interfaccia utente non dovrebbe avere la sola responsabilità di convalidare gli oggetti business. Il tuo livello aziendale DEVE eseguire la propria convalida.

Perché dovresti 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 sperate che trasformano i miei oggetti business in Xml, l'idea che devi separare i tuoi livelli per prevenire questo tipo di contaminazione è così estranea a me perché perché dovresti persino inserire il codice di generazione HTML in un oggetto business ...

Modifica Come penso un po 'di più, ci sono casi in cui le informazioni sull'interfaccia utente potrebbero appartenere al livello del dominio. E questo potrebbe offuscare quello che tu chiami un livello di dominio, ma ho lavorato su un'applicazione multi-tenant, che aveva un comportamento molto diverso sia nell'aspetto che nell'interfaccia utente e nel 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 (ad esempio Etichetta per campi generici).

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

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

Se mantieni solo un oggetto dominio, per l'uso nel livello presentazione E dominio, quell'oggetto diventa presto monolitico. Inizia a includere il codice di convalida dell'interfaccia utente, il codice di navigazione dell'interfaccia utente e il codice di generazione dell'interfaccia utente. Quindi, presto aggiungi tutti i metodi del livello aziendale. Ora il tuo livello aziendale e la tua UI sono tutti confusi e tutti si scherzano a livello di entità di dominio.

Vuoi riutilizzare quel widget elegante 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 85 altre classi non correlate perché sono referenziate nel livello aziendale, che si trova nello stesso file.

Non sono d'accordo.

Penso che il modo migliore per iniziare sia iniziare con gli oggetti di dominio nel tuo livello di presentazione FINO A CHE SIA SENSO FARE ALTRO.

Contrariamente a quanto si pensa, "Oggetti dominio" e " Oggetti valore " può coesistere felicemente nel livello di presentazione. E questo è il modo migliore per farlo: ottieni il vantaggio di entrambi i mondi, riduzione della duplicazione (e codice boilerplate) con gli oggetti del dominio; e la personalizzazione e la semplificazione concettuale dell'utilizzo di oggetti valore attraverso le richieste.

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

I problemi sono principalmente dovuti al fatto che il modello di dominio deve essere tagliato in pezzi più piccoli per poterlo serializzare senza che sia referenziato l'intero database. Ciò rende più difficile l'utilizzo 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à nell'interfaccia utente non si adattano davvero. Stiamo usando il databinding e molte entità hanno molte proprietà ridondanti solo a scopo di interfaccia utente. Inoltre ci sono molti 'BrowsableAttribute' e altri nel modello di entità. Questo è davvero negativo.

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

La risposta dipende dalla scala dell'applicazione.


Applicazione CRUD semplice (Crea, Leggi, Aggiorna, Elimina)

Per le applicazioni crud di base non hai alcuna funzionalità. L'aggiunta di DTO in cima alle 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 di applicazione avrai poche entità che hanno un vero ciclo di vita e alcune logiche aziendali associate ad esse.

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 l'entità ha. Incapsuli le entità
  • Nessun accoppiamento tra backend e frontent
  • Se hai metodi di business 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 aver bisogno di 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 la necessità di controllare la quantità di campi visibili per ciascun client. Avere un DTO separato per ciascun cliente ti aiuterà a scegliere ciò che dovrebbe essere visibile.

 inserisci qui la descrizione dell'immagine

Riguarda le dipendenze per la maggior parte. La struttura funzionale principale dell'organizzazione ha i suoi 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 adattarsi all'interfaccia utente. (Se deve accadere, di solito è un'indicazione che il core non è progettato per le proprietà.)

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

Fondamentalmente una persona ha un lavoro da svolgere. Il DDD dovrebbe corrispondere al flusso e al contenuto del lavoro. DDD mira a rendere espliciti tutti i lavori che devono essere svolti in modo completamente e indipendentemente possibile. Si spera quindi 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 viste fornite per il core funzionale adeguatamente modellato e invariante.

Dannazione, lo giuro questo diceva persistenza.

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, una società che mantiene i prezzi in euro e usa il francese negli uffici della società, ma vuole presentare i prezzi in dollari con il testo in mandarino. Il dominio è lo stesso; la presentazione può cambiare. Quindi, per ridurre al minimo la fragilità del sistema & # 8212; vale a dire, il numero di cose che devono essere cambiate per implementare un cambiamento nei requisiti & # 8212; separi le preoccupazioni.

La tua presentazione può fare riferimento al tuo livello di dominio, ma non ci dovrebbe essere alcun legame direttamente dalla tua interfaccia utente ai tuoi oggetti di dominio. Gli oggetti di dominio non sono destinati all'utilizzo dell'interfaccia utente poiché spesso, se correttamente progettati, si basano su comportamenti e non su 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 associare direttamente la tua interfaccia utente al dominio, probalberai molto mal di testa per te stesso. Hanno due scopi diversi.

Forse non stai concettualizzando il livello dell'interfaccia utente in termini abbastanza 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.).

Ora supponiamo che il motore vocale per il sistema di chiamata telefonica funzioni su un tipo di computer completamente diverso (ad esempio Mac) dal computer che gestisce il sito Web (forse Windows).

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

Vedi anche la sezione "Propagazione dei dati tra i livelli" nel seguito, che a mio avviso presenta argomenti convincenti:

http: // galaxy .andromda.org / docs / AndroMDA documentazione / AndroMDA-ottenere-iniziato-java / java / index.html

Con l'aiuto di uno strumento come " Value Injecter " e il concetto di "Mapper" nel livello di presentazione mentre si lavora con le viste, è molto più facile capire ogni pezzo di codice. Se hai un po 'di codice, non vedrai immediatamente 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 dello strato anticorruzione e vale il suo peso in oro in un progetto a lungo termine.

L'unico motivo per cui non vedo alcun vantaggio nell'uso del modello di visualizzazione è se il tuo progetto è abbastanza piccolo e abbastanza semplice da avere viste associate direttamente a ciascuna proprietà del tuo modello. Ma se in futuro, la modifica dei requisiti 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 vista in view-viewmodel e seguire il principio YAGNI senza aggiungere codice se non ne hai bisogno ma per me stesso, è molto più una buona pratica che devo seguire per aggiungere un livello di presentazione che espone solo oggetti modello vista.

Ecco un vero esempio del perché trovo buona prassi separare le entità di dominio dalla vista.

Alcuni mesi fa ho creato una semplice interfaccia utente per mostrare i valori di azoto, fosforo e potassio in un campione di terreno attraverso una serie di 3 calibri. Ogni indicatore aveva una sezione rossa, verde e rossa, vale a dire che potresti avere troppo o troppo poco di ogni componente, ma c'era un livello di verde sicuro nel mezzo.

Senza pensarci troppo, ho modellato la mia logica aziendale per fornire dati per questi 3 componenti chimici e una scheda dati separata, contenente i dati sui livelli accettati in ciascuno dei 3 casi (incluso quale unità di misura veniva utilizzata, ad esempio talpe 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 e i colori.

Ciò significava che quando in seguito ho dovuto mostrare 12 componenti, ho appena mappato i dati extra in 12 nuovi modelli di visualizzazione degli indicatori e sono apparsi sullo schermo. Significava anche che avrei potuto riutilizzare facilmente il controllo del misuratore e fargli visualizzare altri set di dati.

Se avessi accoppiato questi indicatori direttamente nelle entità del mio dominio, non avrei alcuna delle flessibilità di cui sopra e eventuali modifiche future sarebbero 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 incaricato di diventa rosso, non dovrebbe sapere perché.

L'unica ragione ragionevole per aggiungere un'ulteriore mappatura tra la semantica generalizzata e 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 su dominio funzionano meglio se utilizzati insieme a un set ortogonale di framework di domini funzionali (come ORM, GUI, Workflow, ecc.). Ricorda sempre che è solo nelle adiacenze del livello esterno che deve essere esposta la semantica del dominio. In genere si tratta del front-end (GUI) e del back-end persistente (RDBM, ORM). Tutti i livelli intermedi progettati in modo efficace possono e devono essere invarianti di dominio.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top