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 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 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: Class diagram

MVC: Sequence 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) 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) 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: Class diagram

MVP (variante Supervising Controller): Sequence diagram
MVP (variante Supervising Controller): Sequence diagram

MVP (variante Passive View): 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


Tags: MVC,patterns,architecture,mvp,UI

 
x