SRP con ORM provoca SOA?

3

Ci scusiamo per le molte abbreviazioni nel titolo ... La mia osservazione è che le applicazioni create con una mappatura relazionale ad oggetti come Hibernate tendono a seguire un'architettura orientata ai servizi invece di una orientata agli oggetti.

Alcune persone (ad es. qui ) dicono il Single Principio di responsabilità suggerisce che occuparsi degli attributi di lettura / scrittura degli oggetti persistenti e della creazione e ricerca di questi oggetti è una responsabilità sufficiente per una classe. Qualsiasi logica di business che utilizza tale oggetto dovrebbe andare a classi separate. Questo ci porta a un progetto con due tipi distinti di classi: a livello statico, ma muti, mantenendo i registri, e logici ma privi di stato.

Ecco perché non mi piace questo tipo di design:

(1) Per me, questa separazione di dati e codice non è un obiettivo orientato agli oggetti, ma è la progettazione di un'architettura orientata ai servizi. OOD dice che le operazioni dovrebbero andare alle classi in cui gli attributi che usa sono definiti in.

(2) Inoltre, è una soluzione fasulla: ogni volta che cambia la struttura di una delle classi full-state, dovrò cambiare anche tutte le classi di servizio che la usano. Se avessi la logica dentro quelle classi, il cambiamento rimarrebbe in una classe.

(3) Sto usando un framework ORM che praticamente genera tutto il codice necessario per accedere ai dati persistenti per me in una classe. Se non aggiungessi la logica aziendale, la classe rimarrebbe piuttosto "vuota", cioè conterrà solo il codice generato.

So che molti programmatori seguono il design orientato al servizio, specialmente quando usano framework che lo suggeriscono, come Spring. Se usassi un simile framework, andrei anche con la separazione di codice e dati.

Non voglio provocare una discussione se la SOA è buona o no. Mi interessa sapere se è un buon OOD (come per SRP) separare la logica di business da classi che rappresentano entità.

    
posta Wolfgang 26.03.2012 - 11:07
fonte

2 risposte

3

TL; DR:

There is no silver bullet

Versione lunga:

Lo sfondo di SOA e ORM sembra relativamente inutile, quindi mi concentrerò solo su È una buona progettazione orientata agli oggetti separare la logica di business dalle classi che rappresentano le entità?

Cercherò semplicemente di ragionare su una situazione architettonica in cui I trovò personalmente utile avere classi di entità "sottili".

Situazione:

In un programma che attualmente sto sviluppando in privato sto progettando un modellatore di NHibernate; fai un diagramma visivo con scatole e linee e cose e alla fine viene tradotto in una forma di output riconoscibile da NHibernate.

Sistema principale:

  • Elementi del modello come valori mappati, has-many, has-one, many-to-many ecc.
  • Esegui l'output in classi POCO, classi NHibernate xmlfiles e / o Fluent NHibernate.

Quindi, cosa dovrebbe succedere per esempio ManyToManyRelation (cioè la relazione simmetrica con un'altra entità)?

Penso che sia non ovviamente possibile mettere sia la logica di visualizzazione, logica di output per POCO, logica di output per Fluent e logica di output per XML in ManyToManyRelation.

Visualizzare i dati per un elemento (cioè renderlo sullo schermo in x, y ecc.) è ortogonale ai dati relazionali. Deve essere persistente, ma non negli stessi file dei dati relazionali. Ciò rende naturale per me creare una qualche forma di classi esterne 'attributo' che mappano agli elementi, che sono persistibili ma completamente separate. Quindi visualizza dati e la logica non entra nelle classi di entità .

Abbiamo tre diversi formati di output, almeno . Dato che probabilmente siamo interessati a un solo tipo di output (XML vs Fluent) in una volta, ha molto senso separarlo per separare le classi di "servizio" con una qualche forma di interfaccia comune.

Inoltre, se rappresentiamo il modello come una qualche forma di grafico e consideriamo ManyToManyRelation, ci rendiamo conto che è simmetrico rispetto alle classi di entità - appartiene tanto all'Ente A quanto all'Entità B. Un modo per modellarlo è che entrambi Entità A e Entità B 'contiene' il ManyToManyRelation. Ma poi, quale di essi effettivamente disegna e produce questi oggetti di "proprietà condivisa"? Con la delega a una terza classe di "servizio" questo diventa un non-problema. Quindi la logica di output non va nelle classi di entità

Mi rendo conto che molti di questi problemi possono essere risolti in altri modi: questo non è il fulcro del mio ragionamento . Penso che sia del tutto ragionevole avere classi 'dati' sottili e quindi creare un'applicazione che agisca su questi dati. È anche del tutto ragionevole inserire almeno alcune logiche di base in queste classi. Tutto dipende dal dominio.

Se hai letto fino ad ora, congratulazioni, grazie e un cookie:)

    
risposta data 26.03.2012 - 12:25
fonte
0

È un buon progetto avere metodi di salvataggio e caricamento su una classe di dati? Sì, non vedo perché no. E 'un buon design per l'oggetto dati sapere come persistere se stesso? No, non credo.

Mi piace sempre la definizione di Robert Martin dell'SRP :

There should never be more than one reason for a class to change.

Questo è molto più chiaro che parlare in termini di responsabilità, che in realtà non significa nulla in termini di programmazione.

Quindi, se cambiamo le proprietà di una classe, dovremmo andare in quella classe per cambiarla. Quindi non ci dovrebbero essere altri motivi per cambiare quella classe. Se decidiamo che i file XML non lo stanno più riducendo e abbiamo bisogno di passare a un database, dovremmo andare in un'altra classe. Se cambiamo le regole di convalida per un oggetto, dovremmo andare in un'altra classe.

Significa che non possiamo avere un metodo di salvataggio o di validazione su una classe, passando la richiesta su una classe di repository o validatore? Niente affatto.

Uno dei famosi Bad Smells di Code di Martin Fowler (vedi Refactoring, 1999 ) è "Data Class". Suggerisce che, dove c'è un eccesso di getter e setter in una classe, dovremmo cercare di spostare i metodi che chiamano questi getter e setter nella classe stessa - l'intento è quello di rimuovere finalmente l'accesso ai dati e consentire solo operazioni su un oggetto.

Ma ciò non significa che Fowler crede che il principio di responsabilità unica sia privo di valore. Significa solo che ci sono linee sensibili da disegnare.

Allo stesso modo in cui abbiamo detto "Non dovrebbe mai esserci più di una ragione per cui una classe deve cambiare", dovremmo anche evitare di avere uno spaghetto di codice in cui una singola modifica richiede modifiche a molte, molte classi.

Nel precedente esempio di persistenza, potremmo obiettare che quando aggiungo una proprietà alla classe, devo anche cambiare il modo in cui è persistente. In quel caso, molti anni di esperienza combinata ci dicono che questo è abbastanza giusto. Sono fondamentalmente due cambiamenti (come viene percepito dall'applicazione e come viene mantenuto), quindi cambiare due classi è giusto.

Ma è tutto piuttosto soggettivo. Dobbiamo considerare ogni caso per i suoi meriti.

Gli ORM hanno davvero poco a che fare con questo, tranne che riducono il codice di caldaia tra i dati e lo spazio di archiviazione - questo dovrebbe suggerirci che avevamo ragione a scegliere questo come linea.

    
risposta data 26.03.2012 - 13:16
fonte

Leggi altre domande sui tag