Sono reduce da un corso su .NET 3.0 tenuto come al
solito in modo impeccabile dai ragazzi di DevLeap. Le 2 ore di viaggio di ritorno verso
casa sono state un momento di riflessione sui contenuti del corso, soprattutto
su WCF (spiegato magistralmente da Paolo
) e sulle sue
implicazioni, a mente "calda" e quindi probabilmente con un po' di confusione in testa.
Lentamente, ho iniziato a farneticare...
DIP, Dependency Inversion Principle: Abstractions should not depend upon
details. Details should depend upon abstractions. (cit. Robert C. Martin)
Supponiamo di seguire questo principio. Siamo in un contesto object oriented, e disegneremo
per esempio un servizio di gestione ordini. Siccome vogliamo applicare il
suddetto principio, definiamo interfacce opportune, per esempio:
public interface IOrder
{
string Id { get; }
string CustomerId { get; }
//...
}
public interface IOrderService
{
IOrder GetOrder(string id);
//...
}
Ora potremo creare le opportune implementazioni delle due interfacce. Potremo con semplicità avere
differenti implementazioni del servizio, differenti non solo dal
punto di vista funzionale ma soprattutto infrastrutturale, avendo magari opportuni
adapter dietro la stessa interfaccia che ci consentano di avere
il servizio reale in process, piuttosto che remoto via remoting, o ancora sotto COM+...
e anche in WCF, no?
Forse no, almeno non in modo "naturale"... Il
problema nasce da lontano, credo, ed è simile al più discusso problema di
"impedenza" tra il mondo object-oriented e quello entity-relationship ben
conosciuto da chi dibatte intorno agli ORM. WCF == SOA, e SOA != OO. Ma anche,
WCF == .NET, e .NET == OO. Per proprietà transitiva otteniamo un bel WCF != WCF
. Bel problema...
In WCF il codice precedente potrebbe diventare così
(chiedo scusa per eventuali imprecisioni, vado a memoria... )
public class Order
{
public string Id;
public string CustomerId;
//...
}
[ServiceContract]
public interface IOrderService
{
[OperationContract]
Order GetOrder(string id);
//...
}
Supponendo un
modello di servizio WCF di tipo RPC (col modello "data contract" dal punto di vista che cerco
di illustrare forse è anche peggio...), ecco che abbiamo 2
particolarità:
- non possiamo più
avere un interfaccia (IOrder) come valore di
ritorno, ma dobbiamo avere qualcosa di serializzabile (Order), quindi una classe concreta: il DIP va un po'
a farsi benedire, faccio dipendere un'astrazione da una classe concreta, per
di più di dominio e quindi potenzialmente instabile (= soggetta a cambiamenti), a meno che io
non la crei ad hoc per quest'unico scopo, quindi come
puro contenitore di campi senza logiche applicative, fattibile ma magari non bellissimo; e
comunque la cosa mi costringerebbe probabilmente ad istanziare oggetti ad hoc al
solo scopo di trasferire dati, quando magari io i miei dati potrei già
averli in una forma adatta ad essere "nascosta" dietro
un'interfaccia
- abbiamo gli attributi ServiceContract ed OperationContract
sulla definizione dell'interfaccia del servizio: se quest'interfaccia dovesse
essere la stessa dietro cui implemento anche versioni "non WCF"
del servizio, essa sarebbe "sporcata" da dettagli concreti, non astratti,
dipendenti dal framework applicativo in uso (WCF); di nuovo, un'astrazione che
dipende da dettagli concreti, per mantenere la situazione pulita ed
allo stesso tempo usare WCF dovrei avere due set paralleli di interfacce
di servizio, e di nuovo adattatori in mezzo...
Come dicevo prima, in realtà tutto credo nasca dal fatto che
ragionare SOA non è ragionare OO, ma che usiamo OO per implementare SOA.
Un'interfaccia OO non è un contratto SOA, ma la facciamo lavorare come se
lo fosse.
Nulla di
nuovo, va bene tutto, in fondo basta saperlo e gestirlo, no? Ma allora il dubbio
è: quando Microsoft dice che WCF unifica ASMX, WSE, COM+ e Remoting, in realtà ci
sta un po' sviando... io con Remoting posso avere il servizio remoto
usando il primo modello di interfacce, quello "ideale", con WCF no, quindi
WCF rimpiazza Remoting ma con i costi visti sopra, che non è detto che siano
sempre accettabili. Se poi l'esigenza non è interoperare, bensì remotizzare servizi (.NET su .NET) rimanendo
su una metafora d'uso che renda "trasparente" la posizione reale del servizio, allora in
definitiva WCF, che ha un milione di cose che vorrei poter usare, non riesco ad
usarlo se non attraverso "accrocchi", come due set di interfacce ed
un ulteriore livello di indirezione e quindi di serializzazione da creare per
ogni singolo servizio. Una situazione con application server fatto con IIS e
servizi ospitati via Remoting, è ovviamente realizzabile anche con WCF, ma a mio avviso
non ha la stessa "pulizia" se il cardine del problema
è la trasparenza della posizione del servizio rispetto al
client.
Insomma, a questo
punto, viva WCF ma... lunga vita anche a Remoting! Perchè Remoting vivrà ancora a lungo,
vero?? ...vero?????