![]() |
Dr. Carlo Pescio Design: Interfaccia Utente |
Pubblicato su Computer Programming No. 45
In questa puntata analizzeremo gli elementi fondamentali del dialogo
uomo-macchina, discuteremo i modelli di interfaccia e di interazione,
ed il progetto del componente di interfaccia.
Introduzione
In questa puntata analizzeremo alcuni degli elementi fondamentali
del quarto ed ultimo componente del design, ovvero l'interfaccia
con gli utenti del sistema. Si tratta in realtà di un grande
settore, che meriterebbe una lunga serie di articoli, ed al quale
sono stati dedicati interi volumi; in generale, infatti, lo studio
dell'interfaccia utente ricade sotto il più ampio ombrello
detto Human-Computer-Interaction, che a sua volta non è
che una specializzazione della disciplina del design: progettare
un'efficace interfaccia utente per un programma non è molto
diverso dal progettare un cruscotto di automobile, i controlli
di un apparato stereo o addirittura un rubinetto o una maniglia.
In tutti i casi, esistono considerazioni di immediatezza, usabilità,
idoneità, non-ambiguità, chiarezza, e così
via, che vanno attentamente vagliate se si desidera ottenere il
miglior risultato.
Proprio per questa ragione, sarebbe utile per ogni progettista
di interfacce, o aspirante tale, estendere la propria conoscenza
dell'interazione uomo-oggetti, anche al di fuori del settore informatico;
un testo fondamentale, ricco di esempi reali, è [1]; naturalmente,
è utile poter far riferimento anche a testi specializzati
sull'interazione uomo-computer, come [2], [3] e [4].
Modelli dell'interfaccia utente
Il progetto dell'interfaccia utente dovrebbe sempre essere ottenuto
come mediazione tra due modelli, spesso contrapposti: il modello
concettuale dell'utente ed il modello del programmatore; lo schema
risultante viene definito modello del progettista. Vediamo ora
nel dettaglio il significato e le caratteristiche dei diversi
modelli.
Il modello concettuale dell'utente è un modello mentale,
molto informale, formato da un insieme di relazioni (di cui l'utente
assume l'esistenza) tra un insieme di elementi. Queste relazioni
sono basate sia sull'esperienza quotidiana dell'utente, sia sulla
familiarità con il sistema e la somiglianza con altre applicazioni:
in effetti, gli esseri umani creano dei modelli mentali per le
nuove situazioni in gran parte basandosi sulla somiglianza con
situazioni pregresse. Ad esempio, l'icona di un fax verrà
associata all'idea di un programma o di un device per l'invio
di fax, in funzione del background dell'osservatore (che ad esempio,
potrebbe non avere mai visto un fax). È molto importante
cercare di avvicinarsi il più possibile allo schema mentale
dell'utente, perché ogniqualvolta si richiede l'adattamento
dell'utilizzatore ad un nuovo modello mentale, si rischia di vedere
la propria applicazione etichettata come "troppo complessa".
Sfortunatamente, gli utenti non sono normalmente in grado di descrivere
il loro modello mentale: in effetti, di norma non siamo neppure
consci di averlo; esistono molte strategie per "scoprire"
tale modello, tutte o quasi basate sui seguenti punti:
Modelli di interazione
Esistono due modelli fondamentali per l'interazione uomo-macchina,
che non di rado vengono utilizzati all'interno della stessa applicazione
in momenti diversi. Il primo modello, chiamato normalmente action-object,
è il più indicato per gli utenti inesperti od occasionali,
anche se inerentemente meno flessibile. Il secondo, detto object-action,
lascia molta libertà operativa all'utente, ma proprio per
questa ragione è più indicato per gli esperti,
che non necessitano di una impostazione rigida ma semplice da
seguire.
Il metodo action-object, come suggerisce il nome, consiste nello
scegliere l'azione da compiere, e poi l'oggetto sul quale compierla;
esistono molti esempi di applicazione del modello, ad esempio
l'apertura di un file all'interno di una applicazione: si seleziona
prima l'azione (File-Open) e poi l'oggetto (il file da aprire).
Notiamo che in questo caso il sistema ci può guidare, mostrando
ad esempio i soli file corrispondenti all'applicazione in uso,
posizionandosi in una directory predefinita per quel tipo di file,
e così via. In generale, il metodo action-object guida
il più possibile l'utente, che in seguito alla selezione
di una azione si trova di fronte una serie di scelte, quasi
tutte obbligate come la selezione di un oggetto o la compilazione
di una form, scelte che eseguite in sequenza portano al completamento
di una attività. Naturalmente, in questo caso il progettista
costringe l'utente ad operare secondo la propria visione dell'attività,
ovvero il proprio percorso logico per portarla a compimento; per
un utente occasionale del sistema, o per utenti inesperti, i benefici
di una interazione guidata passo-passo superano spesso il fastidio
di trovarsi costretti in una sequenza preordinata. Ciò
è tanto più vero quanto meno arbitraria è
la scelta dei singoli passi di interazione.
Il metodo object-action, al contrario, consiste nello scegliere
l'oggetto ed in seguito l'azione da compiere; esempi tipici sono
i browser/explorer o i programmi di disegno vettoriale. Nel primo
caso, possiamo navigare a piacere il disco, scegliendo in ogni
momento l'azione da applicare agli oggetti selezionati: aprire,
cancellare, spostare, eccetera. Nel secondo, possiamo selezionare
un qualunque oggetto grafico ed applicare qualche azione (ruotare,
ingrandire, cambiare il colore, eccetera). L'utente è totalmente
libero da costrizioni: nei limiti delle funzionalità previste
dal sistema, non vi sono imposizioni di sorta sulla sequenza delle
operazioni da utilizzare per il completamento di una attività;
l'utente esperto può adattare lo strumento alla propria
forma mentale ed alle proprie abitudini di lavoro, anziché
essere influenzato e guidato dallo strumento stesso. Viceversa,
l'utente un pò sprovveduto si troverà di fronte
così tante scelte da esserne intimidito e bloccato: non
a caso, in Windows 95 esiste ora il famoso bottone "Start",
che ha fatto sorridere molti utenti con un minimo di disinvoltura,
ma che ha fornito a tutti i nuovi utenti un "aggancio"
di partenza (action-object) verso un'interfaccia che viceversa,
nel momento iniziale, era proprio del tipo object-action.
Come scegliere il giusto modello? La scelta non può prescindere
dal tipo di applicazione e dall'abilità dell'utente; difficilmente
saremo in grado di fornire entrambe le possibilità, e dobbiamo
quindi tenere presente anche la rapidità di apprendimento
dell'utente sin dall'inizio.
In genere, se gli utenti seguono da tempo una procedura codificata,
è semplice replicare la stessa procedura in una struttura
action-object; in questo caso, difficilmente l'utente dimostrerà
in seguito insofferenza nei confronti del sistema. Lo stesso dicasi
di opzioni poco usate del programma, con le quali anche gli utenti
esperti saranno meno familiari: essere guidati passo passo in
una attività che si svolge una volta l'anno è in
genere ritenuto preferibile rispetto alla massima flessibilità.
Per contro, categorie di utenti notoriamente "svegli",
rapidi nell'apprendere, e con propensioni personali alla soluzione
dei problemi (in questa classe possiamo spesso inserire personale
tecnico, ma anche chi svolge attività creative ed artistiche)
si troveranno probabilmente più soddisfatti con uno strumento
che consenta di svolgere lo stesso compito in molti modi diversi,
senza sequenze preordinate.
Va osservato che l'approccio più complesso è quello
che sembra meglio adattarsi al paradigma object oriented: si seleziona
un oggetto, e poi una delle azioni che possiamo richiedergli di
svolgere. L'approccio action-object, come avremo occasione di
vedere più avanti, presenta invece un'interfaccia basata
sull'astrazione funzionale. Proprio la maggiore complessità
di un'interfaccia basata sul modello object-action, tuttavia,
dovrebbe ridimensionare le aspettative di chi punta troppo sulle
OOUI: l'apprendimento richiede spesso tempi più lunghi,
e non sempre il risultato è all'altezza delle premesse.
Lo stesso problema, in parte, è anche condiviso dall'approccio
document-centric: in molti casi, assumere che l'utente sappia
selezionare l'oggetto giusto al momento giusto non riflette le
reali capacità ed i reali desideri dell'utente stesso.
Esistono rimedi nel caso una applicazione basata sul modello object-action
si riveli troppo complessa per l'utilizzatore? Probabilmente,
una soluzione è un training migliore. Un'altra soluzione,
che ho avuto modo di sperimentare personalmente, consiste nel
sovraimporre una interfaccia action-object ad una object-action.
In una applicazione piuttosto complessa una parte di configurazione/design
è stata inizialmente sviluppata usando il modello object-action,
proprio per la flessibilità che era richiesta. Tuttavia,
essendo questa opzione usata di rado, gli utenti continuavano
a riportare una eccessiva difficoltà di utilizzo; naturalmente,
i più esperti ne erano invece molto soddisfatti. La soluzione
adottata è stata di sovraimporre un modello addizionale
action-object, molto simile ai wizard che consentono di
progettare le form in Access; notiamo che, anche nel caso di Access,
i wizard sovraimpongono un approccio action-object, dove l'utente
è guidato passo-passo, ad un processo inerentemente object-action
(il design della form o del report), lasciando poi all'utente
la possibilità di ritornare al modello object-action per
una personalizzazione più spinta.
Progettare l'interfaccia utente
La progettazione dell'interfaccia utente non può prescindere
dall'ambiente target, che ormai è sempre vincolato da un
insieme di linee guida per uniformare il più possibile
le applicazioni. In questa sede non vedremo quindi che i principi
più generali, applicabili nelle diverse situazioni.
Come abbiamo visto, il modello del programmatore è spesso
molto diverso dal modello utente, e scopo del modello introdotto
dal progettista è di mediare tra i due. Una tecnica spesso
utilizzata, che ha dimostrato la sua efficacia in numerosi progetti,
è quella di disaccoppiare i dati e l'interfaccia che agisce
su di essi; questo porta direttamente al paradigma Model-View-Controller
o Document/View, anche se interessanti generalizzazioni sono state
proposte in [5] e [6]. È necessario notare che questo disaccoppiamento,
per quanto possa risultare utile in fase di manutenzione e di
estensione, causa normalmente un aumento del lavoro di codifica:
ciò non deve stupire, in quanto svincolare i dati dalla
loro rappresentazione implica una moltiplicazione delle classi.
In effetti, molti dei prodotti RAD eliminano proprio questa fase,
ponendo forti legami tra l'interfaccia utente ed i dati manipolati,
proprio al fine di limare il più possibile i tempi di
sviluppo: sta a voi decidere quale approccio sia il più
indicato per la vostre applicazioni. Indipendentemente dal metodo
utilizzato, va sempre ricordato che non vi deve necessariamente
essere una corrispondenza biunivoca tra le classi dei dati e gli
oggetti esposti a livello utente; talvolta, l'approccio O.O. rischia
di influenzare in modo eccessivo la visione dell'interfaccia utente:
lo sviluppatore tende allora a esporre troppo gli oggetti, assumendo
che l'utente trovi naturale lavorare in termini di classi e polimorfismo.
Viceversa, in molti casi i concetti sottostanti di polimorfismo
e (soprattutto) di ereditarietà vanno abilmente nascosti,
o meglio presentati sotto aspetti più immediatamente fruibili
dall'utente: come vedremo più avanti, in molti casi un
raggruppamento di tipo funzionale è preferibile ad uno
basato su classi.
Un concetto fondamentale nella progettazione dell'interfaccia
utente è quindi la corretta esposizione delle funzionalità
sottostanti l'interfaccia stessa: in generale, infatti, l'utente
impartirà alcuni comandi, o in termini OO manderà
alcuni messaggi, attraverso alcuni elementi di interfaccia che
dovremo rendere disponibili. Notiamo che non vi è alcuna
differenza concettuale tra un'interfaccia a linea di comando,
una a menu, una a bottoni: si tratta di diverse tecniche attraverso
le quali l'utente invia dei messaggi al sistema. Anche la pressione
di un tasto all'interno di un word processor è un mezzo
per inviare un messaggio al sistema, che infatti reagirà
in modo anche molto diverso a seconda del tasto premuto.
Ciò che cambia è la struttura dell'interazione:
in una interfaccia a linea di comando, abbiamo il minimo di struttura,
e quindi il massimo carico di lavoro per l'utente. Una interfaccia
a menu successivi costituisce una struttura rigidamente gerarchica;
un'interfaccia a menu pull-down e bottoni è spesso una
mediazione tra le due tendenze, dove i menu impongono struttura
gerarchica, ma l'utente ha maggiore flessibilità nel navigare
la gerarchia. Questo significa però che il progettista
deve organizzare la gerarchia in modo corretto, viceversa l'applicazione
tenderà a combinare gli svantaggi delle soluzioni (complessità
e rigidità) piuttosto che i loro vantaggi (flessibilità
e semplicità).
Ha quindi senso chiedersi come i comandi esposti tramite menu
e bottoni debbano essere organizzati, strutturati e raggruppati.
È necessario seguire la struttura del modello object oriented,
raggruppando ad esempio i servizi di ogni classe in un menu, ed
esponendo il nome della classe come entry top-level? Oppure è
meglio utilizzare un diverso ordine, non strettamente basato sul
modello OO del dominio del problema? Come sempre, dipende dalla
singola applicazione; possiamo però identificare due casi
molto comuni, in cui esistono tecniche ben sperimentate:
1) menu popup attivati su un singolo oggetto: ad esempio, i popup
che si attivano con il right-click in molte applicazioni Windows,
o sugli oggetti grafici di OS/2. In questo caso, è più
che indicato aderire al modello object oriented: selezionando
un oggetto, l'utente indica implicitamente la classe dell'oggetto
e quindi quali funzionalità debbano essere esposte. L'ereditarietà
va comunque nascosta, ma in questo caso si tratta semplicemente
di replicare le azioni disponibili su oggetti della classe base.
2) menu pull-down, bottoni: in questo caso, ha più senso
organizzare secondo una astrazione di tipo funzionale: ad esempio,
l'entry top-level "Edit" indica un insieme di azioni,
poi dettagliate in "Copy", "Paste", eccetera.
In questo caso, raggruppiamo funzionalità simili, anche
se potenzialmente operanti su oggetti diversi. Spesso possiamo
nascondere in questo modo il polimorfismo: funzionalità
come Copy e Paste corrispondono a metodi virtuali nella visione
del programmatore, e ad "azioni generali" nella visione
dell'utente.
Naturalmente, è possibile avere un mix delle due tecniche:
ad esempio, l'entry standard "File" indica una classe,
e poi seguono i dettagli delle funzioni richiamabili su di essa,
anche se si tratta di un menu pull-down; tuttavia, l'applicazione
dei criteri su esposti porta molto spesso ad interfacce più
intuitive. Infine, esiste un modo per esporre il polimorfismo
a livello utente, semplificando peraltro la struttura dei menu:
se l'entry top-level identifica un oggetto, non ripetete
il nome dell'oggetto nella lista dei comandi; tornando all'esempio
"File", avremo poi "Open" e "New"
e non "Open File" e "New File". In questo
modo, l'utente verrà abituato ad una serie di comandi standard,
utilizzabili con lo stesso significato in altri contesti: ovvero,
al fatto che oggetti diversi possono rispondere allo stesso comando,
in modo "uguale" da un punto di vista astratto, pur
se con effetti concreti leggermente diversi (ereditarietà
e polimorfismo); naturalmente, dovete porre la dovuta attenzione
a non esagerare in astrazione.
Notiamo che un'interfaccia pensata secondo criteri OOUI farà
largo impiego di menu pop-up, attivati interagendo direttamente
con i vari oggetti. Se da un lato questo modello di interazione
auspica lo spostamento dell'attenzione utente, dall'applicazione
verso i compiti da svolgere, e quindi verso gli oggetti da usare
per svolgere tali compiti, il rischio è che l'interazione
diventi "più complessa", proprio perché
il modello ad oggetti è più facilmente implementabile
come object-action. In questo caso è spesso necessario
sviluppare un prototipo dell'interfaccia utente e verificarne
direttamente l'usabilità da parte degli utilizzatori; naturalmente,
un minimo di difficoltà è accettabile e spesso inevitabile,
ma il successo di una applicazione è normalmente legato
alla semplicità con la quale il nuovo utente riesce a padroneggiarla.
Non di rado, ciò che sembra elegante e rapido per uno sviluppatore
risulta scarno e complesso per l'utente finale: un prototipo,
così come lo studio dei metodi e delle applicazioni già
in uso presso l'utente, vi eviterà numerose modifiche successive.
In questo caso, è possibile utilizzare uno strumento RAD,
senza ripensamenti di sorta: il prototipo così sviluppato
potrà essere riutilizzato o gettato, in funzione della
qualità dello stesso, dei tempi disponibili, della vostra
politica di sviluppo. In ogni caso, vedere l'utente all'opera
è spesso uno spettacolo rivelatore: è difficile
immaginare in quanti modi un utente finale "abusi" delle
applicazioni, non appena vi è libertà di scelta;
non a caso, i grandi produttori di software filmano gli "usability
test" per poter rivedere le varie azioni svolte dall'utente,
capire come cerca di ottenere alcuni risultati usando il programma,
e così via.
Poiché difficilmente avremo a disposizione il budget di
Microsoft per gli usability test, esistono due tecniche molto
semplici per sfruttare i risultati delle grandi case produttrici,
a costo pressoché nullo. La prima tecnica è, ovviamente,
quella di "ispirarsi" all'interfaccia di una o più
applicazioni già in uso presso l'utente; se si tratta
di ambienti standard, come Windows, questo significa poco più
che rispettare le linee guida del produttore. Tuttavia, talvolta
anche la semplice somiglianza nei bottoni, lo stesso ordine nelle
righe dei menu, la scelta di termini analoghi ad una applicazione
già in uso (naturalmente, una apprezzata dall'utente!)
potranno fare una grande differenza. Ancora di più , tuttavia,
è ottenibile utilizzando le stesse tecniche di manipolazione
degli oggetti: nuovamente, gli standard tendono ad estendersi
rapidamente, ed ora azioni come (ad esempio) il drag-and-drop
vengono considerate uno standard in molti sistemi. Ciò
che è ancora possibile "carpire" da molte applicazioni
è l'uso del metodo action-object o object-action nelle
diverse situazioni, in modo da presentare all'utente degli scenari
il più possibile familiari.
In questo senso, la seconda tecnica estende la prima alla sua
conseguenza finale: immergere la nostra applicazione all'interno
di una già utilizzata dall'utente. In tal caso, l'utente
non abbandona mai la propria "applicazione favorita",
ma si limita ad utilizzarne delle estensioni. Se in passato questo
era visto come una "programmazione di serie b", spesso
svolta utilizzando qualche macro-linguaggio fornito dal prodotto,
oggi possiamo creare oggetti OLE2 o OpenDoc che possono essere
inseriti, manipolati e memorizzati come parte dei normali documenti
dell'utente. Considerando che una larghissima parte dei programmi
ha come scopo finale la generazione di qualche forma di report,
si può facilmente immaginare i possibili benefici conseguenti
dall'integrazione con (ad esempio) un word processor avanzato.
Sviluppare uno o più oggetti OLE2 anziché una applicazione
stand-alone è al momento una strategia relativamente nuova,
che tuttavia dovrebbe essere seriamente considerata prima di intraprendere
lo sviluppo di un nuovo programma; chi desidera percorrere questa
strada dovrà purtroppo affrontare temi di programmazione
non proprio banali: un ottimo testo per chi voglia approfondire
OLE2 è [7], per quanto chi voglia ottenere immediata soddisfazione,
ed utilizzi un framework come MFC, possa iniziare con un testo
più digeribile come [8] e solo in seguito, quando la necessità
o la curiosità lo richiederanno, passare a titoli più
corposi e dettagliati.
Consigli pratici In quanto segue, ho riportato alcuni spunti relativi al design delle interfacce utente, di stampo più pratico rispetto alle considerazioni precedenti.
The End
Ogni ciclo di lezioni ha una fine, ed "Object Oriented Technology"
termina qui; nei mesi passati, abbiamo considerato i punti fondamentali
dell'analisi e del design, e pur rimanendo a livello introduttivo
spero di aver dato ai lettori una visione abbastanza chiara del
mondo OOT.
Naturalmente, molti argomenti sono rimasti al di fuori della trattazione,
come il testing del codice OO, i framework, le metriche sul design,
la concorrenza, i sistemi distribuiti e gli strumenti CASE, e
molti altri sono stati appena accennati, come gli aspetti di human-computer
interaction visti in questa puntata. I lettori con un particolare
interesse per un argomento relativo alle tecnologie object oriented
possono comunque contattarmi via email: gli argomenti più
importanti o richiesti saranno oggetto di futuri articoli di
approfondimento.
Bibliografia:
[1] Donald Norman: "The Design of Everyday Things",
Doubleday, 1988. Tradotto come "La caffettiera del masochista",
Editrice Giunti.
[2] Brenda Laurel: "The Art of Human-Computer Interaction",
Addison-Wesley, 1990.
[3] Tony Rubin: "User Interface Design for Computer Systems",
Johm Wiley & Sons, 1988.
[4] Ben Schneiderman: "Designing the User Interface",
Addison-Wesley, 1987.
[5] D.D. Cowan, C.J.P. Lucena: "Abstract data views: a module
interconnection concept to enhance design for reusability",
Technical Report, Computer Science Department, University of Waterloo,
Canada, 1993.
[6] Sotirowsky, Kruchten: "Implementing Dialogue Independence",
IEEE Software, Novembre 1995.
[7] Kraig Brockshmidt: "Inside OLE 2, 2nd edition",
Microsoft Press, 1995.
[8] Steve Holzner: "Il Manuale OLE 2.0", McGraw-Hill,
1994.
[9] Apple Computers Inc.: "Human Interface Guidelines",
Addison Wesley, 1992.
[10] IBM Corporation: "Object Oriented Interface Design -
IBM CUA Guidelines", Que Corporation, 1992.
[11] Microsoft Corporation: "The Windows Interface: An Application
Design Guide", Microsoft Press, 1995.
[12] Maria R. Capucciati: "Putting Your Best Face Forward:
Designing an Effettive User Interface", Microsoft System
Journal, Febbraio 1993.
[13] Rainer Mauth: "Objects of Design", BYTE, Settembre
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.