marți, decembrie 04, 2007

Cum combini SOA și OOP?

Am ajuns într-o dezbatere nouă pentru mine ca dezvoltator software. Bănuiesc că mulți dintre voi deja v-ați lovit de această problemă, deja aveți soluții..

Ideea este următoarea. Avem o aplicație Web (UI), construită peste un business layer, care la rândul său se bazează pe un data layer. Dorim să expunem logica aplicației ca un serviciu care să fie consumat de către clienți externi.

Cum modelăm entitățile aplicației? Cum definim aceste servicii și ce date expunem? Când mă refer la OOP, mă gândesc la relațiile dintre entități, 1-1 (Client - Contact), sau 1-* (Client - Report). Clasa Client expune o proprietate listă - Reports care se încarcă dinamic la cerere (lazy loading) cu rapoartele definite pentru instanța Client.

Ce se întâmplă dacă expunem un serviciu pentru entitatea Client, iar o aplicație externă cere o instanță Client și dorește să acceseze proprietatea Reports. Atunci când expui o entitate se presupune că nu expui și funcționalitatea sa. Să luăm cazul unui serviciu web..Știu, o să spuneți că nu mai definim proprietatea Reports și apelăm o metodă dintr-un manager (ReportManager.GetAllClientReport(Client)..).

Nu sunt sigur că am descris cel mai bine, dar rezum totul într-o singură întrebare. Cum modelați arhitectura unei aplicații web care să ofere un set de servicii, iar logica aplicației să respecte totuși avantajele OOP-ului (încapsularea datelor și a operațiilor asupra acestora).

Care e soluția ta?

15 comentarii:

Eugen Anghel spunea...

Daca serviciul web e RESTful ar merge expuse proprietatile obiectului (fieldurile) la un url si relatiile la un altul, mai jos.

De ex poti expune un client {id:5, name: 'Young&Dynamic'} la urlul
http://blablalb.com/clients/young%53dynamic
sau
http://blablalb.com/clients/5/

iar rapoartele sale la
http://blablalb.com/clients/5/Reports

Un prototip pentru ceva de genul asta nu ar trebui sa fie prea greu de implementat peste NHibernate :)

Daca ai trecut deja la .net 3.5 vezi Astoria, ar trebui sa rezolve problema oarecum similar.

Then again, daca e SOAP, you're screwed :D

Gabriel Enea spunea...

Dar daca e WCF?

Eugen Anghel spunea...

cred ca cea mai simpla modalitate de a obtine (cred) ce vrei tu e:
- faci un domain model normal, cu NHibernate sau DLinq sau ce ai tu, exact cum ai face fara webservice.
- faci un modul ASP.NET care "implementeaza" un serviciu web cu url-uri a-la-Astoria (e.g. /products/All, /products/1, /products/Filter/Color/Green/Tag/Kitchen) care practic transforma urlul cerut intr-un query (nh, linq, whatever) si intoarce obiectul serializat (JSON is nice!) doar cu campurile directe, adica fara relatii, fara liste de stuff.
- in fiecare tip de client (Javascript, Java, .NET) tratezi "invierea" entitatii separat.
- de ex pentru .NET: cand incarci o entitate din ws atribui fieldurilor care ar fi tinut relatii/colectii un proxy (Castle.DynamicProxy) care la primul acces apeleaza wsul si aduce entitatea/colectia din relatie. Asta merge pentru relatiile simple, de genul ***to-many. De asemenea, metode care tin de business logic (e.g. product.CanBEPurchased) pot fi facute virtuale si trecute prin proxy. Problema apare la metode statice care nu merg trecute prin proxy prin metode ortodoxe. De asemenea, mentinerea sesiunii ar putea fi o problema.

Florin Cardasim spunea...

Gabriel, faina dilema, ma chinuieste si pe mine de ceva timp.

Mai intai sa vad daca am inteles bine problema: ai un Business Logic layer, care e dezvoltat dupa paradigma OOP, care e folosit deja in aplicatii intranet si acum esti in situatia de a expune parte din functionalitate si pentru un alta gama de clienti. Corect? Eu in ideea asta am sa dau raspunsul, daca am inteles gresit te rog sa ma corectezi si ma mai gandesc...

Dupa parerea mea, acest BL layer nu trebuie expus direct in exterior. In schimb eu as face un layer de servicii peste el, dedicat celei de a doua categorii de clienti. Pentru scenariile intranet (pentru care BL a fost dezvoltat initial) as folosi BL exact asa cum e el, iar in exterior as expune functionalitatea prin niste servicii WCF care folosesc BL. Avantaje:
1. controlezi exact ce expui
2. ai sansa sa adaptezi comportamentul obiectelor si forma datelor pentru clientii din afara
Cei doi clienti (ma refer la utilizatorii layerului de business: clientii WEB de acum si ceilalti pe care vrei sa-i deservesti in viitor) vor avea cu siguranta nevoi diferite la un moment dat. De asta consider ca e bine sa te feresti de schimbari nedorite prin utilizarea acestui layer de servicii.

Un articol foarte fain care dezbate subiectul SOA - OOP (si anume faptul ca cele doua sunt complementare si ca in nici un caz SOA nu e un inlocuitor pentru OOP):
http://www.lhotka.net/weblog/SemanticCouplingTheElephantInTheSOARoom.aspx

gabriel enea spunea...

Multumesc Florin,

Chiar ma gandeam sa te intreb cat de bine poate inlocui WCF-ul un serviciu web? Lucrez la o aplicatie si incerc sa-i explic clientului ca in loc de servicii web (care le propune el) sa-i expunem serviciile prin WCF, astfel avand si servicii web - canal de comunicare.

Dar aici, am observat urmatorul lucru. Daca am o metoda int Add(int a, int b), clasa proxy generata pentru serviciul web WCF are in loc de 2 param, vreo 6, adica void Add(int a, bool isA, int b, isB, out int r, out bool isB)...sigur ceva nu cunosc despre WCF de se genereaza astfel clasa proxy.

Gabriel Enea spunea...

Pana la urma am decis..
BLL-ul va fi complet OOP..la baza va avea NHibernate :)
iar cand va fi timpul de expus functionalitatea ca servicii atunci vom aborda utilizarea BLL-ului din perspectiva SOA.

Pacat ca ADO.NET Entity Framework nu e final. Exista macar vreo distributie beta?

Eugen Anghel spunea...

Google zice ca e beta2: http://www.google.ro/search?q=ado.net+entity+framework+beta

Gabriel Enea spunea...

Ba zice Beta 3 :)

ADO.NET Entity Framework Beta 3
Date Published: 12/6/2007

http://www.microsoft.com/downloads/details.aspx?FamilyId=15DB9989-1621-444D-9B18-D1A04A21B519&displaylang=en

Florin Cardasim spunea...

Salut, Gabriel,

Scuze pentru raspunsul intarziat, sper sa fie inca de ajutor pentru tine.

Endpointurile unui serviciu WCF (mai concret contractele) pot fi expuse in asa fel incat sa fie folosite de mai multe tipuri de clienti cum ar fi SOAP, plain XML, AJAX, WCF. Lucrurile astea se controleaza declarativ prin atribute.
Mai multe aici:
http://msdn2.microsoft.com/en-us/library/bb412167(VS.90).aspx
sau
http://msdn2.microsoft.com/en-us/library/bb412196(VS.90).aspx

Daca ai un client tot dezvoltat cu WCF si Visual Studio, atunci proxiul se genereaza folsind Add Service Reference si nu Add Web Reference, care interpreteza "un pic" diferit metadata expusa de serviciul WCF.

Am reusit sa raspund la intrebare?

Florin Cardasim spunea...

In completare, mai multe detalii aici:
1. [WCF Services and ASP.NET]
http://msdn2.microsoft.com/en-us/library/aa702682.aspx

2.[How to: Expose WCF service also as ASMX web-service]
http://kjellsj.blogspot.com/2006/12/how-to-expose-wcf-service-also-as-asmx.html

Gabriel Enea spunea...
Acest comentariu a fost eliminat de autor.
Gabriel Enea spunea...

Multumesc Florin,

Clientul nu va fi WCF (adica asta e premiza de la care plec). Cum pot sa nu am semnatura metodei proxy cu parametrii asociati? Scopul initial al serviciilor oferite este sa fie dispnobile ca servicii web.
(am sters comentariul meu anterior fiindca nu era complet).

Florin Cardasim spunea...

Linkul asta nu te-a ajutat?

[How to: Expose WCF service also as ASMX web-service]
http://kjellsj.blogspot.com/2006/12/how-to-expose-wcf-service-also-as-asmx.html

Florin Cardasim spunea...

In .NET 3.5 poti expune si Servicii WEB RESTful, tot asa, cu ajutorul atributelor.
[Creating RESTful Web Services with Windows Communication Foundation]
http://www.developer.com/net/article.php/3695436

Gabriel Enea spunea...

M-am apucat ieri sa citesc articole de pe MSDN.
Ce pot sa-ti spun e ca WCF pare sa fie interesant, cel mai flexibil mod de comunicare si aici ma refer la faptul ca poti schimba forma mesajului, protocolul de transport fara sa afectezi modul cum e dezvoltata aplicatia..printre altele, clientul s-a hotarat ca vrea WCF (dupa ce i-am dat ceva materiale de studiu, ppt-uri), dar acum urmeaza sa vedem cum se mapeaza acesta peste aplicatia curenta care e dezvoltata pe .NET 2.0 si care trebuie sa ramana intact.

Multumesc Florin!