Modelli spessi vs. Business Logic, dove si disegna la distinzione?

15

Oggi ho avuto un acceso dibattito con un altro sviluppatore della mia organizzazione su dove e come aggiungere metodi alle classi mappate al database. Utilizziamo sqlalchemy , e una parte importante della base di codice esistente nei nostri modelli di database è poco più di un sacco di proprietà mappate con un nome di classe, una traduzione quasi meccanica dalle tabelle del database agli oggetti python.

Nell'argomento, la mia posizione era che il valore primario dell'uso di un ORM era che è possibile associare comportamenti e algoritmi di basso livello alle classi mappate. I modelli sono prima le classi e secondariamente persistenti (potrebbero essere persistenti usando xml in un filesystem, non è necessario preoccuparsene). Il suo punto di vista era che qualsiasi comportamento fosse "business logic", e necessariamente appartiene a qualsiasi parte tranne che nel modello persistente, che deve essere usato solo per la persistenza del database.

Certamente penso che ci sia una distinzione tra ciò che è la logica aziendale, e dovrebbe essere separato, poiché ha un certo isolamento dal livello inferiore di come viene implementato, e la logica del dominio, che Credo che l'astrazione fornita dalle classi modello sia discussa nel paragrafo precedente, ma sto facendo fatica a mettere il dito su quello che è. Ho un'idea migliore di ciò che potrebbe essere l'API (che, nel nostro caso, è HTTP "ReSTful"), in quanto gli utenti invocano l'API con ciò che vogliono fare , distinti da ciò che sono permesso di fare e come si fa.

tl; dr: Quali tipi di cose possono o dovrebbero andare in un metodo in una classe mappata quando si usa un ORM e cosa dovrebbe essere lasciato fuori, per vivere in un altro livello di astrazione?

    
posta SingleNegationElimination 29.03.2012 - 06:05
fonte

4 risposte

10

Sono principalmente con te; sembra che il tuo collega stia discutendo sul modello di dominio anemico antipattern o per la duplicazione del modello in un "modello di persistenza" senza ovvio beneficio (sto lavorando ad un progetto Java dove è stato fatto questo, ed è un enorme mal di mantenimento, poiché significa tre volte il lavoro ogni volta che qualcosa cambia nel modello).

What kinds of things can or should go in a method in a mapped class when using an ORM, and what should be left out, to live in another layer of abstraction?

Regola empirica: la classe deve contenere una logica che descriva fatti di base sui dati che sono veri in tutte le circostanze. La logica specifica per un caso d'uso dovrebbe essere altrove. Un esempio è la convalida, c'è un interessante articolo di Martin Fowler in cui si afferma che dovrebbe essere considerato dipendente dal contesto.

    
risposta data 29.03.2012 - 09:38
fonte
3

Questo è un giudizio che dipende in realtà dalle dimensioni e dalle dimensioni previste di ciò che stai sviluppando. L'approccio più rigido consiste nel limitare i tipi di ORM a un componente di accesso ai dati e utilizzare i POCO in una libreria comune come tipi a cui si fa riferimento e utilizzati da tutti i livelli. Ciò consentirebbe una futura separazione fisica e una separazione logica. Potresti anche decidere che debba esistere un ulteriore livello tra l'interfaccia utente e il livello della business logic. Questo è solitamente chiamato un livello di facciata o di interfaccia aziendale. Questo livello aggiuntivo è il luogo in cui risiede il tuo "codice del caso d'uso". Il singolo codice liberamente associato viene chiamato dal livello Facade / BI (ad esempio, Facade ha una funzione ProcessOrder () che richiama nella logica aziendale 1: M volte per eseguire tutti i passaggi necessari per elaborare effettivamente l'ordine).

Tuttavia, tutto ciò è stato detto: molte volte questa quantità di architettura è semplicemente eccessivo. Ad esempio, codice specifico per un sito Web semplice in cui non si intende impacchettare i componenti per il riutilizzo. È perfettamente valido creare un sito Web MVC e utilizzare oggetti EF per questo tipo di soluzione. Se il sito ha bisogno di ridimensionare in un secondo momento, puoi esaminare il clustering o un processo spesso perso come "refactoring".

    
risposta data 29.03.2012 - 06:54
fonte
3

Ricorda al tuo collega che non hai bisogno di sovradimensionare i modelli come se si trattasse di un progetto Java. Voglio dire, il confronto tra due oggetti persistenti è il comportamento, ma non è specificato dal livello di persistenza. Quindi la domanda della 6 birra è: perché classi completamente estranee descrivono qualcosa sulla stessa cosa? Certo, la persistenza è un aspetto abbastanza grande di un modello da trattare separatamente, ma non abbastanza da garantire che venga trattato distinto da tutto il resto. Se guidi la tua auto, la lavi o la rompi, la tua manipolazione della tua auto per tutto il tempo.

Quindi, perché non comporre tutti questi diversi aspetti in una singola classe di modelli? Hai bisogno di un sacco di metodi di classe che si occupano di oggetti persistenti - mettili in una classe; hai un sacco di metodi di istanza che trattano della convalida - inseriscili in un altro. Infine, mescola i due in e voilà! Ti sei procurato una rappresentazione del modello intelligente, autocosciente e completamente contenuta.

    
risposta data 29.03.2012 - 09:00
fonte
1

Oltre alle altre risposte, fai attenzione ai grovigli nascosti quando usi modelli di dominio ricchi con un ORM.

Ho riscontrato problemi nell'iniettare servizi polimorfici nelle classi di modelli persistenti quando tentavo di ottenere qualcosa come il seguente pseudocodice:

Person john = new Person('John Doe')
Organisation company = organisation_repository.find('some id')
Employee our_collegue_john = company.hire(john)

In questo caso, un'organizzazione può richiedere un HRService come dipendenza del costruttore (per esempio). Di solito non puoi controllare facilmente l'instanciazione delle classi del tuo modello quando usi un ORM.

Stavo usando Doctrine ORM e il contenitore di servizi di Symfony. Ho dovuto riconoscere l'ORM in modo non troppo elegante e non ho avuto altra scelta che separare la persistenza e i modelli di business. Non ho ancora provato con sqlachemy, ho pensato. Python potrebbe dimostrarsi più flessibile di PHP per questa roba.

    
risposta data 18.01.2017 - 04:44
fonte

Leggi altre domande sui tag