Dr. Carlo Pescio
Model-View-Controller, Document-View, E/P-Glue: evoluzione di un paradigma

Pubblicato su Computer Programming No. 49


In questo articolo vedremo come è nato il paradigma Model-View-Controller, quali forze lo hanno trasformato nel Document/View e quali sono le sue più recenti evoluzioni, quando sia consigliato usarlo e quando sia invece sproporzionato per i fini prefissi.

Introduzione
Con lo sviluppo delle interfacce utente grafiche (GUI) dei primi anni 80, i progettisti ed i programmatori si sono trovati a riaffrontare vecchi problemi ed a confrontarsi con nuove sfide. Da un lato, il problema della portabilità dell'interfaccia utente, risolta in ambiente a caratteri attraverso standard come l'ANSI o la creazioni di librerie come Curses, basate su un database di terminali (il famoso termcap di Unix) si presentava ora in una luce ed una complessità completamente nuove. Dall'altro, nuovi problemi come la stabilità e l'espandibilità dell'applicazione cominciavano ad emergere, in quanto i nuovi ambienti grafici consentivano di scegliere tra una più ampia gamma di modelli di interazione, e lasciavano intravedere possibilità sempre nuove.
Modificare il look di una applicazione, pur lasciandone inalterate le funzionalità, diventava un problema sempre più sentito; non solo, anche la possibilità di rappresentare le stesse informazioni in modo diverso, sfruttando più a fondo le potenzialità della grafica, sembrava un problema difficile da affrontatare per chi proveniva dalla cultura dei terminali a carattere.
Il problema della portabilità è stato affrontato soprattutto in ambiente Unix, tradizionalmente attento allo sviluppo cross-platform: ciò ha portato alla creazione di piattaforme GUI come X Windows ed al concetto di toolkit, che in questo articolo verranno solo accennati.
Viceversa, i problemi di stabilità ed estendibilità hanno visto diversi tentativi di soluzione, di cui uno è stato particolarmente fortunato: il paradigma Model-View-Controller, introdotto da Trygve Reenskaug in Smalltalk nella prima metà degli anni 80, e poi trasformatosi nel paradigma Document/View che è ora alla base di diverse librerie commerciali come MFC ed OWL. In questo articolo vedremo come è nato il paradigma Model-View-Controller, quali forze lo hanno trasformato nel Document/View, e quali sono le più recenti evoluzioni del modello; naturalmente, nel fare questo vedremo anche quali sono i suoi punti di forza e le sue debolezze, quando sia consigliato usarlo e quando sia decisamente sproporzionato per i fini prefissi.

Model-View-Controller
Il paradigma Model-View-Controller [1] identifica tre componenti fondamentali di una applicazione interattiva:

  1. Il Modello, ovvero i dati che vogliamo rappresentare e che possono essere modificati dall'utente. Ad esempio, un record di anagrafica rappresenta il Modello di una persona, e può essere mostrato a video, stampato, modificato in vari modi, indipendenti dal contenuto del Modello stesso.
  2. Le Viste, ovvero le possibili rappresentazioni del modello, o di parte di esso. Un record di anagrafica può essere rappresentato tramite una form, ma potremmo anche essere interessati a rappresentare solo l'età dei soggetti tramite una barra di un istogramma.
  3. Le possibilità di interazione. All'interno di una form, ci si aspetta che certi standard di interazione vengano rispettati, come il passaggio da un campo all'altro con il tasto di tabulazione. Viceversa, potremmo voler conoscere i dati completi di un soggetto con un click su una barra dell'istogramma. Il Controllo dell'interazione forma il terzo componente del trittico Model-View-Controller.
Vale indubbiamente la pena di ritornare sul concetto di Controller, perché è indubbiamente il più ostico dei tre, soprattutto per chi è ormai abituato alla standardizzazione imposta dalle interfacce grafiche più diffuse. Quando il paradigma MVC è stato sviluppato, non vi era alcuno standard riconosciuto che determinasse, ad esempio, il comportamento "normale" di una listbox, ma neppure di una finestra; ad esempio, non vi era un metodo "codificato" per trasferire il focus della tastiera ad una finestra. Alcuni sostenevano la necessità di selezionare la finestra con un click del mouse, altri consideravano sufficiente spostare il cursore del mouse sopra una finestra per renderla attiva; questa situazione perdura tuttora in ambiente X Windows, dove in funzione del window manager selezionato cambia anche la politica di attivazione delle finestre.
Di conseguenza, separare il Controllo dell'interazione dalla Vista era non solo naturale, ma anche necessario per conseguire il requisito di stabilità dell'applicazione: per cambiare il comportamento di una parte, era sufficiente cambiarne il Controller. Notiamo che ogni parte, per quanto piccola, può avere il suo controller: ad esempio, la listbox aveva il suo controller, così come l'edit box ed ogni altro elemento di interazione.
Ciò può sembrare superfluo a chi si sia avvicinato solo di recente alla programmazione in ambienti grafici, ad esempio sotto la spinta di mercato che ha accompagnato la diffusione di Windows: in tale ambiente, una listbox "si comporta in un certo modo" e di rado vorremmo modificare tale comportamento. Al di là del riferimento ai problemi "storici" di cui sopra, vorrei far notare che l'eliminazione del controller (su cui torneremo più avanti) ha di fatto ridotto la flessibilità degli elementi di interfaccia utente: ad esempio, Windows consente di definire due tipi di listbox, a selezione singola o multipla. In entrambi i casi i dati (Model) sono gli stessi, ovvero stringhe, la rappresentazione grafica (View) è la stessa, ovvero una lista, e cambia solo la modalità di interazione, ovvero il Controller, che purtroppo è nascosto nell'implementazione ed inacessibile al programmatore. Tanto che non è neppure possibile trasformare una listbox a selezione singola in una a selezione multipla a run-time, operazione che in teoria si otterrebbe con semplicità cambiando dinamicamente il controller.

La fine del Controller
Il controller aggiungeva flessibilità, ma era anche fonte di complessità a volte eccessiva e rappresentava un severo impedimento alla standardizzazione: è stata in gran parte la spinta all'uniformità dell'interazione, inizialmente supportata soprattutto da Apple, a decretare il declino abbastanza repentino del controller. Naturalmente, il controller non è scomparso: è semplicemente diventato non-accessibile, cristallizzato in uno standard comune che definisce "il modello di interazione". Come sempre, la standardizzazione porta grandi benefici a livello di usabilità delle applicazioni, ma frena l'innovazione e rende più difficile, anche in semplici termini implementativi, cercare soluzioni alternative a problemi che mal si adattano al corpus codificato dello standard; chi ha dovuto crearsi da zero un elemento di interazione (ad esempio una scrollbar custom) semplicemente perché l'ambiente operativo non consentiva di modificarne il comportamento, neppure giocando con il subclassing, conosce sicuramente il lato oscuro degli standard, che ha avuto un ruolo determinante nell'eliminazione del controller.

Il paradigma Document/View
Eliminato il controller, restavano due elementi fondamentali del modello Model-View-Controller, ovvero i dati e le viste; la diffusione dell'informatica a livello di home e personal computer aveva del resto evidenziato come i "dati" più comuni fossero in qualche modo associati ad un concetto di documento: un testo scritto, un foglio elettronico, un diagramma di business graphics. "Modello" era ora un termine quasi arcaico, legato ad un mondo accademico più che a quello dello sviluppo e della programmazione: di conseguenza è stato semplicemente sostituito da un termine più adatto ai tempi, ovvero Documento. Era nato il paradigma Document/View, basato sulla dualità tra gli oggetti (documenti) e le loro rappresentazioni (viste).
D'altra parte, il paradigma Model-View-Controller si proponeva come fine essenziale la stabilità dell'applicazione di fronte a modifiche sul modello di interazione; con l'affermazione degli standard, il problema si è invece spostato sempre più verso l'espandibilità dell'applicazione in termini di viste multiple sui dati. Il paradigma Document/View si è facilmente adattato per supportare l'espandibilità delle viste in modo trasparente, ed a questo deve la sua attuale diffusione.

Supponiamo infatti di voler rappresentare graficamente un insieme di numeri (figura 1); vogliamo altresì che modificando un dato attraverso una delle viste, le viste ulteriori riflettano immediatamente la modifica. Supponiamo inoltre di voler aggiungere, in fasi successive, diversi altri tipi di rappresentazione sullo stesso insieme di dati; dobbiamo allora soddisfare i seguenti requisiti:
  1. Il Documento non può conoscere i dettagli delle singole viste, altrimenti non sarebbe possibile aggiungere nuovi tipi di vista senza modificare il documento.
  2. Le viste non possono comunicare tra loro, in quanto ciò impedirebbe nuovamente di aggiungere nuove viste.
  3. Deve comunque esistere un meccanismo per aggiornare tutte le viste quando una viene modificata.
  4. Le viste devono poter accedere ai dati concreti del documento, per poterli rappresentare ed eventualmente modificare. Ricordiamo che la modifica deve però essere immediatamente notificata a tutte le viste.

A seguito di tali requisiti, la struttura più comune del modello Document/View è quella di figura 2, dove viene rappresentata usando la notazione di Booch [2]. Vediamo nel dettaglio i singoli partecipanti: Rimane ancora in sospeso la discussione del requisito (3), ovvero come le viste vengano aggiornate senza essere a conoscenza l'una dell'altra. Questo è facilmente rappresentato attraverso un diagramma degli eventi, come in figura 3: quando si modifica lo stato di un documento concreto, viene chiamato il metodo Update della classe Document, e questo a sua volta chiama il metodo Update di ogni View collegata. Tale metodo (virtuale puro in una visione C++), ridefinito opportunamente in ogni vista concreta, fondamentalmente richiederà lo stato al documento concreto e aggiornerà la vista come necessario.

Infine, va osservato che talvolta si elimina dal documento la responsabilità di gestire la lista delle viste associate, spostando tale compito in una classe DocumentManager, cui talvolta sono demandate anche altre funzionalità dipendenti dalla libreria (ad esempio, la creazione, apertura, e memorizzazione dei documenti). Si tratta di un dettaglio che in ogni caso non influisce in modo sostanziale sulla struttura discussa in questa sede.

Limiti del paradigma
L'uso sempre più diffuso del paradigma Document/View ha portato rapidamente ad evidenziarne non solo i pregi, ma anche i difetti; uno dei primi ad emergere è stato quello della portabilità delle applicazioni. I lettori familiari con il sistema X Windows saranno al corrente dell'esistenza di altri modelli di astrazione (toolkit, toolkit virtuali), basati in gran parte sul modello di Seeheim [3] anziché sul Document/View, ed il cui scopo è proprio di isolare l'applicazione dal particolare toolkit utilizzato: per fare ciò, la presentazione (analogo della view nel modello Document/View) ed il dialogo (assente nel Document/View, rappresenta la sequenza dei comandi atomici, come gli eventi di tastiera e mouse, che composti realizzano un'operazione di alto livello, come l'apertura di un file) vengono separati dall'applicazione (che contiene tra l'altro i dati, ovvero il documento) attraverso dei layer di virtualizzazione. Viceversa, nel modello Document/View, gli step ed i meccanismi di interazione con l'utente (dialogo) sono distribuiti uniformemente a molti livelli, ed è estremamente complesso portare una simile applicazione su una piattaforma diversa. Va detto comunque che esistono librerie portabili che supportano il Document/View, introducendo quindi anche in tale modello un layer di virtualizzazione; molto spesso tali librerie supportano in modo portabile solo un sottoinsieme comune di funzionalità, mentre l'uso di caratteristiche peculiari di un sistema è normalmente consentito ma non supportato.
Inoltre, il modello si rivela decisamente sproporzionato in casi semplici, in cui il requisito di estendibilità visto in precedenza gioca un ruolo molto limitato: ad esempio, in molte applicazioni form-based, come i front-end per i database. In questi casi, è più che accettabile avere una classe per i dati ed una o più classi, direttamente accoppiate anche tramite ereditarietà, che si occupano della visualizzazione dei dati stessi; in tal modo si eliminano le classi astratte viste in figura 2, e molto spesso è possibile eliminare la gestione di una lista di viste, in quanto ad ogni istante vi è al più una vista associata ad ogni documento concreto. Questo modello è normalmente utilizzato per semplici dialog box, dove non di rado si immergono addirittura i dati e la vista in un'unica classe.

Evoluzione del paradigma
Il paradigma Model-View-Controller non ha seguito la sola linea evolutiva che ha portato al Document-View: almeno altri tre modelli sono nati dallo stesso progenitore. Non tutti hanno avuto fortuna, ed in questa sede ci limiteremo ad accennarne le caratteristiche principali, rimandando alla bibliografia per eventuali approfondimenti.
Il modello Presentation-Application-Control, abbreviato normalmente in PAC [4] ha seguito il percorso opposto al Document/View, ovvero il potenziamento del controller; poiché definire il controllo è spesso un'operazione complessa, il modello PAC applica sé stesso al suo componente di controllo, suddividendolo ricorsivamente in una presentazione, un'applicazione ed un controllo sino a raggiungere una dimensione più facilmente gestibile. Questa idea, che in sé non ha avuto molto successo, è stata invece recuperata in modo indiretto in altri modelli di interazione: ad esempio, un documento OLE 2 trasferisce di fatto il controllo ai suoi componenti quando questi vengono attivati, e questi possono a loro volta trasferirlo a sottocomponenti. Presumibilmente, OLE 2 è arrivato ad includere alcuni principi del PAC in modo del tutto indipendente, ma è interessante notare la convergenza di uno sforzo molto recente (OLE 2, ma anche OpenDoc) con proposte vecchie di una decina di anni.
Un ulteriore approccio è quello delle Abstract Data View [5], che si propongono di risolvere un problema ancora più generale: in questo caso, infatti, abbiamo un Abstract Data Object (ADO) che prende il posto del documento, ed una Abstract Data View (ADV), che è collegata ad un ADO e ne fornisce una visione particolare. Una ADV non è necessariamente una "vista" nel senso del Document/View: può ad esempio essere una classe adattatore, che permette di interfacciare un ADO con altre classi che richiedono il rispetto di un particolare protocollo (ad esempio, far "vedere" una periferica come un file o come una superficie di disegno, cambiando semplicemente ADV). Il metodo ADV non è quindi limitato alla progettazione di interfacce utente, ma può essere usato anche in altri contesti, ed è coadiuvato da una notazione ed una semantica formale, basata su pre/postcondizioni, che permettono di definire formalmente il comportamento del modello prima di passare all'implementazione.
Infine (ma vi sono numerosi altri paradigmi di interazione), citiamo il modello di E/P/T-Glue [6], che si è evoluto nell'ambito dei sistemi interattivi per il controllo di volo. L'idea di base dell'E/P/T-Glue è di separare il modello dei dati dalla presentazione in modo bidirezionale, mentre il Document/View si preoccupa soprattutto di isolare il documento dallle viste ma non viceversa. Di conseguenza, dati e viste vengono "incollati" insieme attraverso delle classi chiamate "existential glue" (colla esistenziale), che trasferisce la creazione di oggetti dal dominio dei dati a quello della visualizzazione, e di una "property glue" (colla di proprietà) che trasferisce la modifica di proprietà dal dominio dei dati a quello della visualizzazione. Infine, un terzo tipo di colla ("transitional glue", o colla di transizione) si occupa di mappare le modifiche utente dalla presentazione al modello dei dati. In ambienti real-time, spesso la t-glue è asincrona e le operazioni richieste possono fallire, riportando quindi la presentazione allo stato originale. Rispetto al Document/View, questo ultimo modello è più flessibile, ma anche molto più complesso da implementare, e valgono quindi in misura ancora maggiore le controindicazioni viste in precedenza: se non è necessaria una totale indipendenza, nei due versi, tra dati e presentazione, l'uso dell'E/P/T-Glue è decisamente sconsigliabile; nei casi di reale utilità, la possibilità di usare lo stesso codice di presentazione per dati anche molto diversi può invece ridurre drasticamente la complessità di un progetto.

Reader's Map
Molti visitatori che hanno letto
questo articolo hanno letto anche:

Bibliografia
[1] Krasner, Pope: "A Cookbook for Using the Model-View-Controller User Interface Paradigm in Smalltalk-80", Journal of Object Oriented Programming, August/September 1988.
[2] Carlo Pescio: "La Rappresentazione Grafica dei Modelli", Computer Programming No 37, Marzo 1995.
[3] M. Green: "Report on Dialogue Specification Tools", User Interface Management Systems, Springer-Verlag, 1985.
[4] J, Coutaz: "PAC, An Implementation Model for Dialog Design", Proceedings of Interact'87, September 1987.
[5] Cowan, Lucena: "Abstract Data Views: An Interface Specification Concept to Enhance Design for Reuse", IEEE Transactions on Software Engineering, Vol 21 No 3, March 1995.
[6] Sotirowsky, Kruchten: "Implementing Dialogue Independence", IEEE Software, November 1995.
[7] Kazman, Bass: "Software Architecture for Human-Computer Interaction: Analysis and Construction", Technical Report, University of Waterloo, 1995.

Biografia
Carlo Pescio (pescio@acm.org) svolge attività di consulenza in ambito internazionale nel campo delle tecnologie Object Oriented. Ha svolto la funzione di Software Architect in grandi progetti per importanti aziende europee e statunitensi. È incaricato della valutazione dei progetti dal Direttorato Generale della Comunità Europea come Esperto nei settori di Telematica e Biomedicina. È laureato in Scienze dell'Informazione ed è membro dell'ACM, dell'IEEE e della New York Academy of Sciences.