Pattern architetturali – prima parte
Scritto da
Marco Amendola
il
mercoledì 17 novembre 2010
Linguaggio:
•
Framework:
•
Livello: 200
Introduzione
Un'applicazione (anche di medie dimensioni) è una struttura
complessa, la cui costruzione non deve essere affidata al caso:
come in una qualsiasi organizzazione, le varie parti devono
interagire correttamente e in modo controllabile; ciascun
componente deve svolgere le attività di propria competenza e non
interferire con le competenze altrui. Questo principio progettuale
è noto come "Separation of Concerns".
Nel corso del tempo intorno a questa tematica si sono affermati
differenti pattern, quali, ad esempio, MVC
(Model-View-Controller), MVP
(Model-View-Presenter) e MVVM (Model-View-View
Model).
Si tratta di soluzioni con importanti differenze ma che
sostanzialmente ruotano intorno ad una suddivisione dei componenti
applicativi in tre sottosistemi fondamentali (la cosiddetta
"triade"):
- Model: è la parte che implementa e incapsula
la logica "business", ovvero quell'insieme di regole e
comportamenti che attengono puramente al dominio del problema
trattato (algoritmi di calcolo, validazione dei dati, ecc.).
I componenti del Model prescindono (quasi) totalmente dal tipo di
tecnologia utilizzata per la costruzione dell'interfaccia utente, e
non intervengono nella presentazione dei dati; si occupano, al
contrario, del modo in cui i dati vengono prelevati, elaborati o
salvati in un archivio persistente.
- View: è la parte costituita dai componenti
preposti alla presentazione dei dati e in generale a tutte le
attività che riguardino puramente l'interazione con l'utente.
Specialmente nelle operazioni assimilabili a dei comandi (es. clic
su un pulsante salvataggio di un form di dati) è molto importante
che la sfera di competenza di questo sottosistema si limiti, al
massimo, a riconoscere l'azione effettuata dall'utente, mentre
l'effettiva esecuzione dell'operazione dovrebbe essere delegata
all'esterno (in genere al terzo sottosistema);
- Controller/Presenter/View Model: è la parte
che svolge il ruolo di coordinamento e mediazione degli altri
componenti. Si occupa, infatti, di "dare esecuzione" alle richieste
dell'utente predisponendo i dati alla visualizzazione, organizzando
la raccolta dei dati dall'interfaccia utente e smistando le
attività inerenti la logica business verso il Model.
E' spesso, inoltre, la parte preposta a guidare il flusso delle
maschere dell'applicazione attraverso i vari possibili
percorsi.
Al di là delle esigenze di ordine, la separazione delle
responsabilità ha il grande vantaggio di consentire il test dei
vari componenti in isolamento.
Inoltre lo spostamento della maggior parte della logica
applicativa "importante" al di fuori della View consente in molti
scenari di evitare o ridurre al minimo il test dell'interfaccia
utente, che è generalmente piuttosto complesso da eseguire in modo
automatico e costoso da manutenere durante l'evoluzione
dell'applicazione; il test può così concentrarsi sulla reale logica
applicativa che "guida" l'interfaccia utente.
Differenze
Vaso di Rubin
Pur senza entrare troppo nei dettagli per ragioni di spazio
(rimando, per maggiori informazioni e commenti, ai riferimenti
indicati a fine articolo), credo sia tuttavia utile evidenziare le
differenze concrete tra questi pattern per meglio comprenderne
l'evoluzione e il funzionamento.
La classificazione qui proposta, tra l'altro, è basata sulla
nomenclatura "storica" di queste architetture, che è probabilmente
la più nota ma piuttosto imprecisa e sfumata (essendo nata da
successive evoluzioni nel corso del tempo) [1].
I differenti pattern sono caratterizzati dal ruolo del terzo
sottosistema, che funge da collante fra i primi due e dalle
modalità con cui i tre componenti interagiscono.
Come nella notissima illustrazione qui a fianco, i contorni dei
primi due elementi possono essere ben individuati per contrasto con
la forma dell'ultimo.
Model-View-Controller
Nel MVC, il Controller assume il ruolo più complesso: si occupa
di interpretare e mediare l'interazione dell'utente con la UI e
indirizzarla verso le corrispondenti funzionalità applicative,
tipicamente supportate dal Model per quanto attiene gli aspetti del
dominio business.
Alla View, invece, è affidata solo la rappresentazione dei
risultati, ottenuti accedendo direttamente al Model in risposta
alle notifiche che quest'ultimo (o un suo intermediario) fornisce
al variare del proprio stato.
Lo scopo principale è quindi distinguere due fasi e
responsabilità distinte:
- interpretazione delle richieste dell'utente (Controller);
- presentazione dei dati all'utente (View).
Il tipico processo di attivazione è quindi il seguente:
Schema di
interazione in MVC
- l'utente interagisce con la View (ad es.: clic su un
pulsante);
- il Controller riceve notifica di questo evento
(1) attraverso un callback oppure mediante un meccanismo di
attivazione di specifiche "azioni";
- il Controller, in base all'azione attivata, al contesto e agli
eventuali parametri ricevuti, agisce sul Model (2) allo scopo
di fargli eseguire le opportune operazioni nel dominio
business;
- la View osserva costantemente il Model (3) e aggiorna la
rappresentazione in caso di notifica di variazioni (4); in alcune
implementazioni il Controller, dopo aver ottenuto i risultati dal
Model, avvia le operazioni di rappresentazione dei risultati nella
View.
MVC si adatta molto bene alla natura
"stateless" del web, supportandone la netta separazione (anche
temporale) fra le fasi elaborative che coinvolgono il server e le
fasi di pura presentazione dei dati che hanno in effetti luogo sul
client; in questa accezione, il pattern è in realtà il MODEL 2
definito da Sun per le applicazioni web in Java (con il quale MVC
viene spesso erroneamente identificato).
Pur essendo originariamente utilizzato in applicazioni "rich
client", la sua applicazione "rigorosa" in questi contesti non
consente di sfruttare appieno la potenza delle moderne
infrastrutture di UI; esso viene pertanto frequentemente declinato
in altre varianti (come MVP o MVVM) delle quali costituisce il
fondamento concettuale.
Di seguito i grafici UML relativi alla struttura delle classi in
gioco e delle interazioni fra le istanze:

MVC: Class diagram

MVC: Sequence diagram
Model-View-Presenter
Con il progredire delle tecnologie di interfaccia utente, sono
stati introdotti controlli (widget) sempre più autonomi
nell'interpretazione delle gestures dell'utente; sono
inoltre nati potenti meccanismi di databinding dichiarativo.
Tutto questo ha reso il ruolo originario del Controller in MVC
sempre più trascurabile ed è stato quindi utile spostare una parte
delle responsabilità di presentazione a carico della View;
parallelamente, però, si è reso necessario introdurre dei
meccanismi per consentire l'azione diretta sulla View allo scopo di
rimuovere da quest'ultima (e in molti casi dal Model, che doveva
supportarla) la logica di presentazione, necessaria ad esempio per
modificare dinamicamente lo stato dei controlli.
Nel MVP, quindi, il Presenter ha un ruolo di coordinamento in
risposta alle azioni dell'utente nei punti critici del flusso
applicativo (caricamento dei dati, conferma delle modifiche, ecc.)
e in presenza di interazioni complesse.
Anche nei momenti in cui interviene, il Presenter può limitarsi
a indirizzare la sequenza di azioni per poi delegare la maggior
parte delle attività di presentazione dei dati del Model alla View,
purché quest'ultima possa espletarli con logiche semplici (ad es.
mediante databinding dichiarativo) che non richiedano test
specifici.
Nel caso di interazioni più complesse, il Presenter può comunque
prendere il controllo e guidare direttamente la visualizzazione o
l'aggiornamento dei dati, generalmente sempre riferendosi alla View
mediante un'astrazione [2].
Il tipico processo di interazione è:
Schema di interazione in MVP (variante
Supervising Controller)
- l'utente interagisce con la View;
- il Presenter viene notificato di questo evento (1) attraverso
una delega diretta da parte della View oppure attraverso un
callback;
- il Presenter agisce sul Model (2) allo scopo di fargli eseguire
le opportune operazioni nel dominio business;
- la View aggiorna, tipicamente in virtù del binding (3) la
rappresentazione visuale dei dati esposti dal Model (4);
- in alternativa il Presenter può agire sulla View (3a) per
rappresentare alcuni cambiamenti di stato complessi che non è
possibile esprimere in forma dichiarativa.
Schema di interazione in MVP (variante Passive
View)
Laddove invece sia necessario avere una maggiore copertura di
test della parte attinente alla View oppure sia utile una maggiore
astrazione rispetto alla tecnologia di UI utilizzata, il pattern
MVP può essere declinato nella variante "Passive View".
Tale variante toglie alla View l'onere di aggiornarsi
automaticamente mediante la diretta osservazione dei cambiamenti
del Model e pone questa responsabilità nel Presenter che dirige
completamente il processo di presentazione dei dati nella View
(3).
Di seguito i grafici UML relativi alla
struttura delle classi in gioco e delle interazioni fra le
istanze:

MVP: Class diagram

MVP (variante Supervising Controller): Sequence
diagram

MVP (variante Passive View): Sequence diagram
[1] Mi preme
specificare che considero le classificazioni utili soprattutto ad
orientarsi ed a facilitare la comunicazione; quello che ritengo
importante è la "filosofia" di fondo di ciascun pattern. La
classificazione seguita, quindi, non dà completamente conto delle
numerose piccole varianti e differenti implementazioni di ciascun
pattern.
[2] Allo scopo di
non introdurre dipendenze "forti" fra diversi componenti, è pratica
consolidata nel design object oriented quella di definire
delle interfacce che identifichino un'astrazione del componente che
si vuole isolare. In questo modo le altre parti del sistema possono
comunicare ed interoperare senza conoscerne l'implementazione
concreta, la quale sarà fornita dall'infrastruttura al momento
opportuno.
Riferimenti e risorse
- Trygve Reenskaug
- Govind Seshadri
- Mike Potel
- Andy Bower, Blair McGlashan
- Martin Fowler
- Jeremy D. Miller
- Aviad Ezra
- Oliver Steele
- Derek Greer
Tags: MVC,patterns,architecture,mvp,UI