[Linq to SQL] Scenari Multi-Tier e SOA

Ispiratori di questo post sono non in ordine:
Una pizza con mozzarella di bufala con il Salta (ma non quella di ieri...quella dell'altra settimana...il che significa che abbiamo un po il vizio ultimamente...e se vedeste come è frequentato bene il locale...verrebbe il vizio a tutti)
Un thread di Guisa di qualche mese fa ormai.
E anche l'argomento Linq to SQL e WCF (...brrrr....).

Con Linq to SQL il nostro Domain Model può discostarsi anche enormemente dalla definizione del database. Si possono creare dei veri e propri grafi da dare in pasto al nostro buon DataContext e dire...tièè...sbrigatela tu.
Prendiamo ad esempio il solito schema di un Ordine e dei suoi dettagli:

image

Ricordiamoci che ci troviamo ora in un mondo Object Oriented, dove a farla da padrone sono proprio le reference/associazioni. Nulla ci vieta infatti (anzi è altamente consigliabile) di avere una associazione bidirezionale tra il parent (Ordine) e i figli (DettaglioOrdine).  Il parent ha una collezione, e ogni elemento della collezione ha una reference al padre.
L'espressività del modello e la potenza di interrogazione introdotta da questa associazione nei due sensi, è molto alta,  permettendo di scrivere query partendo dai child. Chiunque abbia lavorato con un ORM sa di cosa parlo e Linq to SQL non è da meno.

Compito dell'ORM in questione è fornire quante più opzioni possibili (leggasi strategie di fetching) per poter caricare totalmente o in parte il grafo, risparmiare select inutili sulle reference già caricate e così via.

Primo argomenti messo a segno:
1. Potenza del Grafo con associazioni unidirezionali e bidirezionali.
2. La circolarità (abusi a parte) nell'Object Model non è mai stata un problema.

Proiettiamoci nel mondo SOA.
Il nostro applicativo ha un presentation layer, che comunica con uno strato totalmente a servizi.
(Non vedo scenari multi-tier che non si basino su questo presupposto).

Abbiamo la necessità di creare all'interno di un processo, una vista su un Ordine, e in un altro step proporre dei cambiamenti.
Ci servirà un servizio che ci restituisca i dati essenziali dell'ordine al solo scopo di visualizzarli, ed un altro servizio che possa apportare le modifiche.
Domande...
1. Come modelliamo i nostri i contratti di questi due servizi?
2. Possiamo esporre tramite il servizio gli oggetti del Domain Model? Quelli direttamente gestiti da Linq to SQL? (..brrrr..)
3. Linq to SQL...dove sta? Dentro o fuori il servizio?

Facciamoci giudare dai principi SOA e da un po di buon senso.

1. Non si condividono classi, ma contratti. Altrimenti il basso accoppiamento ce lo scordiamo. 
2. Un grafo con reference circolari non può essere serializzato in XML.
3. E anche se si potesse serializzare, ha veramente senso passare dal servizio al presentation tutto il grafo di Ordine?

Analizziamo i due sensi:

Primo Processo
Richiedo una fattura da visualizzare
:

Creiamo un DataContract per il servizio che rappresenta un Ordine light, serializzabile, con una collection di oggetti senza reference al padre, ma soprattutto con dei dati denormalizzati (Magari per ogni articolo, ci portiamo dietro una descrizione, settore e categorie varie, in modo da appiattire il modello).
Dentro il servizio:
1. Usiamo tranquillamente Domain Model e Linq to SQL per caricare il grafo,
2. Utilizziamo un adapter che crei una istanza del DataContract. 
3. Esponiamo il DataContract

Fuori dal servizio non esistono ne Domain Model ne Linq to SQL.
Il presentation Layer non ha bisogno di altro per visualizzare l'ordine.

Secondo Processo
Propongo aggiornamenti sui dettagli dell'ordine, il servizio deve modificare, validare e confermare:

Domandiamoci adesso:
Se anche fosse possibile tecnicamente far viaggiare tutto il grafo...e se si potesse scambiare il grafo tra presentation e servizio...
Ha senso modificare una riga di ordine e far viaggiare per intero un ordine con magari 30 righe di dettaglio?
Per far sapere al servizio che ne è stata cancellata/editata/inserita una sola? 
Magari il tipo di modifica può riguardare solo alcune colonne dei dettagli (mi è capitato sempre) e noi ci portiamo dietro tutto.
Ovviamente non ha senso.

Che si fa? Dentro il servizio:
1. Creiamo un DataContract composto da una List di elementi che rappresentano esclusivamente le modifiche. Ogni elemento potrebbe memorizzare: Tipo Modifica, Quantica etc. Lo scambio dati è fortemente ottimizzato.
2. Quando viene chiamato il servizio, carichiamo il grafo di Ordine e sfruttiamo tutto il lazy possibile e immaginabile. Situazione diametralmente opposta alla precedente. Nel prmo esempio di servizio sappiamo a priori che dobbiamo caricare tutto, qui è tutto da vedersi. Se ci fossero solo inserimenti non dovremmo neanche caricare la collection per intero. Ecco perchè esiste in ogni ORM che si rispetti la possibilità di modificare la strategia di caricamento a runtime per lo stesso medesimo oggetto (LoadOption in Linq to SQL).
3. Snoccioliamo le modifiche sul nostro grafo e persistiamo, magari ci sarà una fase di validazione, notifiche e così via.

Anche in questo caso:
abbiamo sfruttato brillantemente l'object model con tutta la sua complessità all'interno del servizio, e creato un DataContrect leggero. solo con le modifiche. Fuori dal servizio non esiste Domain Model ne Linq to SQL. Internamente si può decidere di cambiare il grafo, magari ci inventiamo qualche altra associazione bidirezinoale (senza esagarare).Ma i contratti rimangono immutati.

Per i puristi SOA, chiedo di non storcere troppo il naso perchè i servizi assomigliano troppo a delle CRUD (definito come CRUDy Antipattern) ma e solo per semplicità di esempio (altrimenti questo post veniva lungo un kilometro).

Questo per me è lo scenario corretto di Linq to SQL in ambienti multi-tier.

Print | posted on martedì 27 novembre 2007 12:22

Comments on this post

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
aaaargh...sssshhht...
ovviamente è in preparazione...:-)
Left by Giancarlo Sudano on nov 27, 2007 11:37

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
Potresti corredare l'articolo con un semplice esempio "compilabile" :)
Left by Fabio on nov 27, 2007 12:48

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
Fabio, ottima idea...
ma questo post non lo chiamerei articolo...
l'ho scritto stamattina sul tram Gaggiano-Milano...
:-)
Left by Giancarlo Sudano on nov 27, 2007 1:01

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
Se provo ad immaginare questo scenario col mio ObjectModel composto da 450 entità... mi vengono i brividi!!! Ovviamente al momento uso un approccio alla Rialdi post.
Left by Tommaso Caldarola on nov 27, 2007 2:00

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
@GD. È proprio quello il problema. Il contratto WSDL è troppo debole per poter rappresentare un object model e credo che anche Janky si riferisse a questo.
Quando dico che in certi casi sono disposto a rinunciare al vero loosley coupled, intendo dire negli scenari dotnet su dotnet è assolutamente pensabile di creare un assembly condiviso tra i vari layer.
BTW la mia RafCollection implementa GetChanges, quindi il discorso di Janky riguardo al marshalling delle sole entities che hanno subito modifiche/inserimenti/cancellazioni è gestito decisamente meglio quando c'è un assembly condiviso (con la RafColletion:) )
Left by Raffaele Rialdi on nov 27, 2007 4:33

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
Solitamente se io sono sia il provider che il consumer, è perché la mia necessità non è quella di esporre servizi, ma voglio semplicemente rendere la mia applicazione distribuita.

In questi casi non vedo controindicazioni a condividere l'object model. Anzi, ne vedo parecchie a *NON FARLO* (classi duplicate, maggiore lavoro di manutenzione...).

Per l'applicazione che stiamo sviluppando in azienda (qualche migliaio di entities) la soluzione del DTO sarebbe completamente impraticabile.
Left by Marco De Sanctis on nov 28, 2007 2:40

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
Marco, ovviamente concordo ma bisogna stare molto attenti a non esagerare e ad evitare l'approccio della condivisione se non strettamente necessario.
Il vantaggio dell'approccio SOA va al di là dell'esposizione di un servizio loosely-coupled. Il vero vantaggio all'interno di una soluzione distribuita è di avere il legame più debole possibile tra i vari strati, rendendo versioning, manutenzione e threat model decisamente più semplici.
IMHO vano ben soppesati vantaggi e svantaggi prima di prendere una decisione.
Left by Raffaele Rialdi on nov 28, 2007 9:49

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
Secondo me il vantaggio di un applicazione in architettura SOA è che ci si può tenere la porta aperta verso consumer diversi, magari su piattaforme diverse. Concordo con Raffaele, uno strato di adapter che isola lo strato di Data contract dall'object model vero e proprio a costo dello sforzo iniziale ti ripaga in termini di mantenibilità apportando modifiche e correzioni mantenendo il tutto traparente a tutti i consumer (I confini sono espliciti :))
Left by Alessandro Damiani on nov 28, 2007 12:00

# re: [Linq to SQL] Scenari Multi-Tier e SOA

Requesting Gravatar...
@Raf sono d'accordo, in alcuni casi ci si possono fare degli sconti, nel mio esempio parto dal presupposto che si è già scelto (SOA)di alzare una barriera tra consumer e provider.
I due commenti di Marco e Tommaso sono la testimonanza di progetti grossi (mille entità), dove i DataContract possono portare notevole entropia, ma i problemi di quei progetti forti sono altri. Tu hai detto la parola magica "versioning", ma anche "threat model".
I componenti trasversali fortemente accoppiati uccidono i cicli di vita delle applicazioni, tempestano clamorosamente i repository di codice, levano la salute degli sviluppatori.
Un approccio SOA corregge questo, e il vantaggio nn lo si vede sulla singola applicazione ma sull'applicazione dei principi su tutto un IT.
Left by Giancarlo Sudano on nov 28, 2007 1:12
Comments have been closed on this topic.