Service-level requirements: soddisfare i requisiti non funzionali di una architettura software

L’architetto software è la figura professionale che ha l’obiettivo fondamentale di progettare l’architettura di un sistema software nel rispetto dei requisiti non funzionali (NFR)Di seguito, riporto un elenco generale di accorgimenti o best practices che occorre, o conviene, seguire per rispettare i requisiti di base quali performance, availability, reliability, extensibility, manageability, maintainability security.

Il seguente elenco è stato estratto da una lista di quesiti utili alla certificazione di JEE Architect (Oracle) che sto conseguendo; esso non è esaustivo e copre casi piuttosto generali. 

 

Come si può soddisfare la scalabilità del sistema (scalability)?

  • Creando una architettura ridondante, con l’applicazione di tecniche di clustering. I tier dovrebbero essere ridondanti: web tier, application tier, database, LDAP e load balancer, componenti di rete, ecc;
  • Load balancing: è la tecnica che permette di redirigere una richiesta ad uno dei tanti server disponibili in base ad un predeterminato algoritmo di load balancing. Il vantaggio è redistribuire il carico su differenti macchine, con prestazioni non eccessive, invece di avere una singola macchina ad alte prestazioni che gestisca tutte le richieste. In questo modo si risparmia sui costi e si ottimizza l’uso delle risorse computazionali. Per implementare il load balancing occorre scegliere l’appropriato algoritmo in base alle performance e alla disponibilità richieste. Un tipico algoritmo è il round-robin;
  • Riducendo il traffico di rete usando pattern, come DTO e Session Façade, ad esempio;
  • Valutando se scalare verticalmente o orizzontalmente (vertical scaling horizontal scaling). Per scalare un sistema occorre inserire hardware aggiuntivo: scalare verticalmente significa aggiungere risorse addizionali alla macchina, come processori, memoria o dischi; invece, scalare orizzontalmente significa aggiungere altre macchine all’architettura esistente, aumentando la capacità complessiva di sistema. La prima soluzione è più semplice, poiché non ha impatto sull’architettura: infatti, per scalare orizzontalmente l’architettura deve essere predisposta per supportare una cluster-based configuration e progettata in modo che i suoi componenti non dipendano dalla macchina su cui vengono eseguiti. La scelta, comunque, dipende dal costo dell’hardware richiesto per raggiungere i requisiti di performance e di scalabilità fissati col cliente;
  • Disegnando l’architettura in maniera modulare (modularity): conviene separare il sistema in componenti auto-consistente per poter scalare singolarmente le sue parti (web, business, integration tier, ad esempio);
  • Stateless architecture. Conviene utilizzare EJB di tipo stateless: l’utilizzo di stateful session bean comporta una scelta progettuale “povera” dal punto di vista della scalabilità. Inoltre, lo stato conversazionale dovrebbe essere mantenuto lato web (con l’uso di HttpSessionURL rewriting)
  • Usando un connection pooling per le connessioni al database. Inoltre, conviene minimizzare l’utilizzo di long transaction (in generale, l’uso delle transazioni dovrebbe avvenire solo se effettivamente necessario)

 

Come si possono ottimizzare le performance di un sistema?

  •  Attraverso la ridondanza (redundancy). La capacità del sistema può crescere attraverso il vertical scaling e solitamente viene definita height. La ridondanza è la dimensione che viene calcolata in base al numero di istanze configurate per svolgere in modo sincronizzato lo stesso lavoro (ad esempio, attraverso il load balancing): tale dimensione cresce quando si scala orizzontalmente e viene definita width. La ridondanza può migliorare le performance del sistema, oltre all’availability, alla reliability, alla scalability e alla extensibility, ma può comportare un peggioramento della security e della manageability.
  • Introducendo un meccanismo di caching dei dati, in modo da ridurre l’overhead computazionale e limitando il numero di richieste concorrenti. Si potrebbe introdurre un timeout sulle operazioni long-lasting, specialmente quelle che riguardano l’accesso a servizi esterni. In questo modo si migliora il system throughput.
  • Il caching si può introdurre anche grazie all’utilizzo di pattern, come Service Locator e Value List Handler, oppure Session Facade e DTO, che permettono di ridurre il traffico di rete, permettono di esporre servizi “a grana grossa” (course-grained services) che consentono di ridurre il round-trip time all’atto della chiamata ai servizi di business;
  • L’utilizzo delle transazioni deve essere effettuato solo se espressamente richiesto. In generale, peggiorano le performance complessive del sistema, ma ovviamente non si può evitare di utilizzarle, essendo necessarie per garantire la consistenza e l’integrità dei dati. Vanno valutati i singoli casi e fatte delle scelte, trovando il giusto trade-off;
  • Session management. Le specifiche Servlet consigliano di spostare la gestione della sessione lato web, attraverso l’uso della classe HttpSession. La memorizzazione degli oggetti in sessione deve essere ragionata: salvare oggetti onerosi, come collezioni di risultati di ricerca, è un conosciuto problema denominato “performance and scalability anti-pattern”. Conviene ridurre, dunque, i dati in sessione ed effettuare aggiornamenti “a grana grossa” (course grained update).
  • L’utilizzo di un algoritmo di load balancing, come Sticky sessionconsente di avere effetti benefici sulle performance e consente di evitare di avere frequenti sincronizzazioni di dati in sessione. Lo svantaggio è sulla availability: l’utente perde la sessione, ma il failover è più veloce. L’utilizzo di un elastic load balancing e di uno short duration time di sessione avita di avere una perdita di sessione.
  • Utilizzando Java Persistence API (JPA) in modalità lazy, in modo da evitare di caricare dati inutili in modo massivo quando si effettuano le query sui dati;
  • La replicazione passiva (passive replication) consente di avere un sistema poco sovraccarico e di evitare frequenti sincronizzazioni tra i nodi replicati.

 

Come si può soddisfare il requisito della disponibilità del sistema (availability)?

  • Realizzando una architettura ridondante; tutti i tier dovrebbero essere ridondanti (web tier, application tier, database, load balancer, componenti di rete, ecc.). Prevedendo ridondanzafailoverun componente singolo può essere indisponibile e avere un impatto negativo sulla reliability, ma il servizio continua ad essere disponibile grazie alla ridondanza;
  • Dunque, conviene prevedere un clustering con failover usando un hot stand-by server (con capacità extra), ossia un componente secondario che si attiva solo in caso di necessità (soluzione che comporta una spesa aggiuntiva per un componente che potrebbe non essere utilizzato se non in caso di inattività dei componenti principali – occorre valutare se conviene sostenere tale costo, con la garanzia di avere una architettura disponibile in caso di fallimento);
  • Prevedendo una configurazione in clustering e scegliendo un cluster software che permetta di amministrare il server group, rilevando softwarehardware failure e di gestire il failover, restartando i servizi in caso di fallimento. La configurazione two-node clusters (symmetric and asymmetric) è quella più comune: quella simmetrica prevede che entrambi i cluster siano attivi nello stesso istante, invece, quella asimmetrica prevede la presenza di un stand-by failover server.
  • Prevedendo una replicazione passiva (passive replication), dove lo stato dei componenti secondari viene sincronizzato con quello del componente principale, in caso di fallimento. Per il database, si potrebbe optare per una replicazione attiva (active replication), dove i componenti cluster sono tutti principali e si sincronizzano per gestire il carico (in questo modo non si ha una capacità extra inattiva in condizioni normali di funzionamento). Tuttavia, la replicazione attiva è onerosa poiché la sincronizzazione e il coordinamento tra i componenti aggiungono un certo overhead e complessità al sistema;
  • Attraverso la definizione di un piano di Disaster Recovery e di Service-Level Agreements (SLA) per i sistemi esterni da integrare. La definizione delle SLA deve essere concordata con il cliente e fissata in modo chiaro anche per il sistema che si intende progettare.


Come si garantisce il requisito di sicurezza del sistema (security)?

  • Con la ridondanza delle componenti di sistema, diminuisce anche la sicurezza. Questo perché potenzialmente si hanno più punti di vulnerabilità nel sistema;
  • Application security: la sicurezza applicativa si potrebbe soddisfare attraverso il transport level security (come SSL/TLS EAS 256 bit) o attraverso un message level security (come ad esempio, WS-Security). Inoltre, a livello applicativo occorrerebbe prevedere sempre una input validation, filtrando gli input inseriti dagli utenti sulle interfacce web, risolvendo ad esempio il problema del cross site scripting, e prevedendo un packet filtering firewall per evitare attacchi DDoS;
  • Si potrebbe prevedere una zona demilitarizzata (DMZ) per il web e per il business tier, in modo da proteggersi da attacchi esterni, usando il protocollo HTTPS, web server operanti come reverse proxy, una business DMZ accessibile solo attraverso web server “trusted”. Anche al database si dovrebbe accedere soltanto attraverso application server “trusted”.
  • Inoltre, applicando il principle of least privilege, secondo il quale si dovrebbe accedere solo alle informazioni e alle risorse necessarie. Tale principio prevede che utenti, amministratori, programmi, sistemi, ecc. dovrebbero possedere solamente i privilegi necessari per eseguire uno specifico task. Il principio dei privilegi minimi è un importante principio per limitare l’esposizione agli attacchi e per minimizzare i danni;  
  • Per l’integrazione di servizi esterni occorrerebbe utilizzare protocolli come SSL. Ad esempio, per l’accesso a Web Services si potrebbe utilizzare JAX-WS over SSL, in modo da sfruttare il message-level data integrity, grazie all’XML Signature, e il message-level and transport confidentiality, utilizzando l’encryption (WS-Security Specification)
  • Creando una architettura che separi i componenti funzionali o prevedendo delle security zone per ciascun componente: se un componente viene violato, viene compromesso solo tale componente e non tutti gli altri presenti nel sistema (punti di isolamento);
  • Con l’utilizzo di filtri (filter), componenti server-side ospitati dal web container, che permettono di intercettare le richieste in entrata prima che vengano ricevute dai rispettivi componenti target. I filtri sono utili per pre-processare le richieste, permettendo, ad esempio, di loggare eventi o validare le richieste (security checks);
  • Sfruttando la sicurezza messa a disposizione come servizio da un EJB container, facilmente configurabile anche a run-time;
  • Prevedendo un meccanismo di authorization (soltanto un utente valido e autenticato ha gli appropriati diritti per accedere ai dati e alle funzionalità di sistema), confidentiality (assicurando che i dati e le funzionalità di sistema siano protetti da accesso non autorizzati), integrity (assicurando che i dati di sistema non siano modificati o che ci siano interferenze da parte di componenti terzi, malintenzionati e non) e authentication (assicurando che l’identità di un utente che accede al sistema sia valida e corretta e che non possa essere impersonificata o compromessa in alcun modo). Per garantire tali requisiti, si potrebbe sfruttare Java Authentication and Authorization (JAAS);
  • Prevedendo un declarative security model, dove le regole di autorizzazione sono definite attraverso un file XML (deployment descriptor). Nel caso in cui occorra gestire una sicurezza “role-based” particolare, è possibile definire un programmatic security model.

 

Come si garantisce l’affidabilità (reliability) di un sistema?

  • La reliability assicura l’integrità e la consistenza dell’applicazione e di tutte le sue transazioni. Inoltre, definisce l’abilità di un sistema o di un componente di funzionare sotto determinate condizioni per un periodo di tempo specificato. E’ possibile garantire l’affidabilità del sistema utilizzando la ridondanza (redundancy): quando un server non risponde, altri possono lavorare al suo posto;
  • Utilizzando load balancing, failover e clustering;
  • Lo sticky session ha effetti negativi sulla reliability perché l’utente perde la sessione. Per ridurre tale effetto occorre prevedere uno short time session e un elastic load balancing
  • Anche la replicazione passiva ha un effetto negativo sulla reliability, perché ci potrebbe essere un tempo di indisponibilità del sistema (down time) in caso di fallimento e conseguente attivazione dello stand-by server.

 

Come si garantisce l’estensibilità del sistema (extensibility)?

  • Avere un sistema flessibile significa che l’aggiunta di funzionalità o la modifica di quelle esistenti non hanno impatto sull’architettura del sistema. Tale misura dipende da come il sistema è stato progettato e da quanto precisi sono stati i service-level requirements stabiliti con il cliente. I principi base che occorre coprire per garantire la flessibilità del sistema sono: low coupling, interfaces encapsulation.
  • L’applicazione deve essere progettata rispettando il separation of concernsconviene prevedere differenti layer (presentation, business e data access layer). Ogni layer è debolmente accoppiato con gli altri (loose coupling), grazie all’utilizzo di pattern, interfacce, ereditarietà, incapsulamento e best practices della programmazione ad oggetti;
  • Utilizzando pattern per separare l’applicativo in concern e layer: ad esempio, utilizzando DAO, Value List Handler, Front Controller, MVC, Service to Worker;
  • Progettando un object model di alta qualità: basta applicare i principi della programmazione ad oggetti e i design pattern (ad esempio, l’MVC pattern disaccoppia i componenti di user interface dai componenti di business logic);
  • Definendo un service level agreement (SLA) con il cliente e cercando di anticipare le modifiche applicative; attraverso la definizione di SLA è possibile definire uno scope di progetto chiaro e preciso e anticipare inaspettate modifiche al sistema. Occorrerebbe identificare le possibili “changed area” del sistema (ad esempio, la tecnologia di user interface utilizzata) e isolare tali aree in componenti coerenti: in questo modo, si può prevenire che la propagazione degli effetti dei cambiamenti abbia sensibili ripercussioni in tutto il sistema;
  • La ridondanza (redundancy) e la modularità (modularity) consentono di migliorare anche l’estensibilità del sistema;

 

Come si garantisce la manageability del sistema?

  • La manageability è l’abilità di gestire il sistema per assicura di averlo in salute, grazie al monitoraggio dei QoS requirements (scalability, reliability, availability, performance, security). Inoltre, un’alta manageability consente di cambiare la configurazione del sistema per migliorare la QoS dinamicamente senza impattare l’architettura del sistema stesso;
  • La ridondanza ha effetti negativi sulla manageability e non solo sulla sicurezza;
  • Sticky session ha effetti negativi sulla manageability;
  • Utilizzando Java Management Extensions (JMX) e prevedendo differenti livelli di logging per monitorare condizioni di errore, fatali o di warning durante il funzionamento dell’applicativo;
  • Scegliendo un software idoneo di load balancer per il cluster management.

 

Come si garantisce la maintainability del sistema?

  • La maintainability è la capacità di correggere difetti nelle funzionalità esistenti senza impatti su altri componenti del sistema. Tale misura non si valuta a tempo di deploy, ma quando si progetta l’architettura e viene garantita se si rispettano i principi di low coupling, modularity e documentation. Grazie alla modularity, ogni layer è debolmente accoppiato agli altri (loosely coupling), e sfruttando i principi di separation of concerns, i design pattern, le interfacce e le best practices della programmazione ad oggetti, è possibile fare in modo che il sistema sia più manutenibile;
  • Grazie ad una buona documentazione dell’applicativo (architecture diagrams, Interface agreements con i sistemi esterni, class diagrams, sequence diagrams, Java doc, ecc.);
  • Utilizzando lo Standard JEE Stack, con tecnologie come JSF, EJB, JPA, JAAS, JTA in modo da manutenere una soluzione standard e non “specific vendor”. Ad esempio, i componenti JSF si possono riutilizzare e la stessa tecnologia JSF è definita “toolable”, grazie al supporto di IDE maturi come Eclipse, Netbeans e IntelliJ.

[UI] Software per la realizzazione di mockup per l’UI presentation

I mockup sono utili per capire cosa effettivamente vogliono i vostri clienti e per farsi una prima idea di progettazione della User Interface, sia essa web o mobile.
Infatti, è partendo da una rappresentazione grafica, magari di impatto, che il cliente riesce a “toccare con mano” ciò che vuole e su cui si può anche condurre una intervista per la raccolta dei requisiti di business.

Spesso si confondono le definizioni di mockup, wireframe e prototype; ecco un ottimo articolo che ne chiarisce le differenze: WireFrame, Prototype e Mockup – Dove sta la differenza.

Dunque, per la presentazione di mockup di una vostra applicazione, vi consiglio di utilizzare alcuni software, semplici ed immediati (alcuni li trovate negli articoli linkati in seguito in “Riferimenti utili”).

Per la realizzazione di un “concept” preliminare della user experience, capire dove posizionare gli elementi grafici sulle vostre pagine e come impostare la navigazione, è consigliabile realizzare un primo prototipo “statico” con Balsamiq Mockup. Questo utile software, free per il primo mese, ma accessibile come prezzo nella sua versione completa, vi permette di creare in pochi passi le varie schermate, mettendovi a disposizione dei widget abbastanza comuni nelle nuove applicazioni, sia web che mobile. Il risultato sarà un mockup statico, da esportare in PDF o in formato immagine.

20140216-204721.jpg

Esiste anche una ricca collezione di template condivisi da altri web designer e che potete consultare qui: MockupToGo Balsamiq.

Se la grafica dell’applicazione non è molto complessa, potete addirittura esportare il tutto in HTML, utilizzando un altro software, ossia Napkee. Quest’ultimo prende in input i sorgenti di Balsamiq ed esporta il tutto in formato HTML, generando anche i CSS e i Javascript e fornendo un minimo di interattività per alcuni componenti (come tab, accordion, select, link, ecc.). I risultati non sempre sono ottimi, anche perché Napkee è ancora in versione alfa. Può essere utile per pagine semplici e potete comunque agire su HTML e CSS/Javascript generati, modificandoli a mano.
Purtroppo, al momento si può soltanto partire dal sorgente statico Balsamiq, importarlo in Napkee e generare gli HTML, ma non il contrario.

Se il mockup statico non basta e vi occorre realizzare un prototipo interattivo più complesso (prototype), allora smanettate a livello di codice. Cercate qualche libreria di stile, come Metro UI, set di widget in stile Windows 8, che utilizza Bootstrap e JQuery.

20140216-205423.jpg

 

Riferimenti utili:

Principi di buon design per progettare oggetti semplici e di facile uso

Caffettiera del masochista

“Quando cose semplici hanno bisogno di istruzioni per l’uso, è segno di un cattivo design.”

Una frase tratta da un saggio di scienze umane e un manuale indispensabile per il progettista. Questo è il libro di Donald A. NormanLa caffettiera del masochista – psicopatologia degli oggetti quotidiani“. Una riflessione sulla cattiva progettazione di oggetti che utilizziamo nella vita quotidiana, ma che ormai siamo abituati a maneggiare nel modo in cui ci è stato imposto e che spesso creano ripetute frustrazioni. Consigli su come evitare di commettere gli stessi sbagli quando li si realizza. Lettura indispensabile e mattone fondamentale per chi si occupa di design, di qualsiasi tipologia di oggetto, tangibile e non, reale o virtuale che sia. Si parla di psicologia dell’interazione tra persone e oggetti e di quella che è detta filosofia dei sistemi centrati sull’utente, di cui trovate un’altra mia riflessione qui: User-centered design: progettare considerando i bisogni degli utenti.  

La progettazione è l’applicazione successiva di vincoli e limitazioni finché quello che rimane è un prodotto unico.

La tesi centrale del libro è, appunto, quella di propugnare un design centrato sull’utente, una filosofia progettuale basata sui suoi bisogni edi interessi, che miri alla realizzazione di prodotti usabili e comprensibili.

“La gente si sente in colpa quando non riesce a usare le cose semplici, colpa che non è sua ma piuttosto dei progettisti e produttori degli oggetti”

Comics Easy to use

La colpa di una cattiva progettazione è dell’industrializzazione. Secondo Norman, lo studio del design degli oggetti è indissolubilmente legato a quello del funzionamento della mente umana (human information processing). Spesso vengono trascurati gli aspetti “naturali” e la rilevanza pratica, considerando soltanto quelli legati al fattore economico, alla semplicità nella produzione (come avviene in ambito industriale) e alla velocità di distribuzione sul mercato.  La maggior parte della colpa di una cattiva progettazione è dovuta proprio all’industrializzazione: le aziende vogliono qualcosa che possa essere prodotto in poco tempo e a basso costo.

Un progettista che si lascia influenzare da tali aspetti, si perde in dettagli inessenziali, dimentico dell’obiettivo a cui l’oggetto è destinato e “violenta” il normale processo di comprensione ed interpretazione delle procedure d’uso da parte degli utenti finali.

La colpa all’incentivazione della mal progettazione è anche nostra, perché se la gente continua ad acquistare prodotti progettati male, industriali e progettisti penseranno di aver fatto bene e continueranno a produrre le cose allo stesso modo.

 

Tenere conto di vincoli, condizioni ed istruzioni semplici. Quando si costruiscono gli oggetti occorre tenere imprescindibilmente in conto i vincoli ambientali e le condizioni d’uso, rendere le istruzioni semplici per l’utilizzatore finale, in modo da creare un prodotto pratico e semplice. E ancora, secondo Norman, la maggior parte degli errori che vengono commessi dall’uomo quotidianamente è dovuta ad una cattiva progettazione degli oggetti che utilizzano.

Un esempio emblematico è quello della porta: per capire come aprire una porta, le parti giuste devono essere visibili e devono trasmettere un giusto messaggio (i cosiddetti “segnali naturali“), come i cardini, la maniglia e il sostegno. Dove l’oggetto non è semplice da utilizzare, le istruzioni devono essere comprensibili e semplici. Inoltre, l’attenzione all’estetica può rendere cieco il progettista (e l’acquirente) alla scarsa funzionalità.

Affordance

Affordance degli oggetti. Indica le proprietà reali e percepite delle cose materiali che determinano come si potrebbe verosimilmente usare un oggetto in questione. Per esempio, quando vediamo una porta in vetro, è dallo spessore della maniglia che possiamo percepire quanta forza occorre applicare per poterla aprire.

Altra regola fondamentale: le cose complesse possono richiedere spiegazioni, ma quelle semplici non dovrebbero averne bisogno. Quando una cosa semplice esige figure, scritte o istruzioni, vuol dire che il design è sbagliato. E’ il progettista che deve essere abile a rendere chiaro il funzionamento della sua “creatura”, tenendo in considerazione la psicologia umana, ossia come un utente può desumere per proprio conto come “muoversi” (grazie ad una esperienza personale di come funzionano le cose del mondo esterno).

 

Principi di design per la comprensibilità e l’usabilità. Due sono i principi fondamentali per una buona progettazione:

  1. fornire un buon modello concettuale, grazie al quale possiamo prevedere gli effetti delle nostre azioni mentre utilizziamo un oggetto
  2. rendere visibili le cose. Il principio di visibilità è, secondo Norman, continuamente contraddetto negli oggetti quotidiani e, in molti schemi costruttivi, le parti cruciali sono accuratamente occultate.

Rendere le parti di un oggetto visibili, per renderne facile l’utilizzo. Ma non inserire troppe di queste parti, altrimenti l’oggetto stesso diventerebbe troppo complesso. Inoltre, l’affidamento eccessivo agli automatismi, può annullare la capacità di cavarsela in loro assenza.

Conceptual Models NormanPer capire la figura precedente, riporto la didascalia riportata nel libro, che ci fa ben capire qual è il “gap” che separa il progettista dall’utente finale.

“Il progettista deve costruire preventivamente un modello concettuale dell’oggetto, che dal suo punto di vista è detto modello progettuale, immaginando gli effetti e come gli utenti potrebbero utilizzare il suo prodotto e trarne beneficio. Il modello dell’utente è il modello mentale sviluppato attraverso l’interazione con il sistema. L’immagine del sistema risulta dalla struttura fisica che è stata costruita (compresa documentazione, istruzioni, etichette, ecc.). Il progettista si aspetta che il modello dell’utente sia identico al modello progettuale. Ma non parla direttamente con l’utente, visto che la comunicazione avviene attraverso l’immagine del sistema. Se l’immagine del sistema non rende chiaro e coerente il modello progettuale, l’utente finirà per formarsi un modello mentale sbagliato. ”

 

Mapping e feedback. Ecco altri principi a cui occorre rifarsi per una buona progettazione:

  • Mapping: indica la relazione fra i comandi previsti per un oggetto e i risultati che ne derivano nel mondo esterno. In pratica, occorre stare attenti a non inserire troppi comandi nel nostro oggetto e fare in modo che ad ognuno di essi sia associato un determinato comportamento/effetto. Evitare le combinazioni di comandi, altrimenti all’utente risulterà complicato eseguire determinate operazioni. Infatti, quando il numero delle funzioni e operazioni richieste eccede il numero dei comandi, il progetto diventa arbitrario, innaturale e complicato. Si rende così il dispositivo più difficile da usare ed imparare.
  • Feedback: indica l’informazione di ritorno che dice all’utente quale azione ha effettivamente eseguito, quale risultato si è realizzato, dandogliene un effetto e riscontro immediato e facendolo entrare in sintonia con l’oggetto.

Rispettando tali principi, l’utente può: 1) indovinare il da farsi, 2) capire che cosa sta succedendo, interpretando lo stato del sistema.

Per semplificare il processo di apprendimento ed interpretazione, avrebbe senso standardizzare tutta una serie di procedure che l’utente è abituato ad eseguire quotidianamente quando utilizza oggetti destinati allo stesso compito. Purtroppo, quest’ultimo punto è di difficile attuazione, visto che occorrerebbe mettere d’accordo i vari produttori.

 

Come può il design segnalare le azioni appropriate? Un insieme importante di segnali ci arriva attraverso i vincoli naturali degli oggetti, vincoli fisici che limitano le possibilità di azione. Un altro insieme di segnali viene da quelle che abbiamo chiamato affordance, gli inviti forniti dagli oggetti, che trasmettono messaggi circa i loro possibili usi, azioni e funzioni. Gli inviti d’uso suggeriscono la gamma delle possibilità, i vincoli limitano il numero delle alternative. L’uso intelligente di inviti e vincoli d’uso combinati nella progettazione fa sì che l’utente possa determinare prontamente il corso esatto delle azioni anche in una situazione del tutto nuova.

Dunque, per far sì che l’utente sappia cosa fare quando utilizzare l’oggetto occorre “imporre” i seguenti vincoli:

  • Vincoli fisici: sono i più utili ed efficaci perché sono facili da vedere e interpretare, e limitano l’insieme delle azioni prima ancora di eseguirle.
  • Vincoli semantici: si affidano al significato della situazione per circoscrivere l’insieme delle azioni possibili, basandosi sulla conoscenza del mondo e della situazione stessa.
  • Vincoli culturali: sono vincoli “imposti” da convenzioni culturali accettate. Ogni cultura ha un insieme di azioni permesse in varie situazioni sociali e gli oggetti devono rispettare degli “obblighi” culturali.
  • Vincoli logici: quando si crea un rapporto logico fra la disposizione spaziale o funzionale dei componenti e le cose da questi controllate (o da cui queste dipendono).

 

Evitare gli errori. I progettisti devono essere attenti affinché gli errori possibili non comportino gravi conseguenze.

Se un errore è possibile, qualcuno prima o poi lo farà. Il progettista deve partire dal presupposto che tutti i possibili errori saranno commessi e impostare il progetto in modo da ridurre al minimo le probabilità di errore in primo luogo, o i suoi effetti una volta che esso sia verificato. Gli errori devono essere facili da individuare, devono avere conseguenze minime e, se possibile, i loro effetti devono essere reversibili.

Per far ciò, occorre focalizzarsi sullo scopo dell’oggetto, sugli effetti che realizzerà nel mondo esterno e verificare tali effetti. In sintesi, occorre effettuare una esecuzionevalutazione degli effetti (ciclo dell’azione).

Human Error

Progettare in vista dell’errore. Il progettista fa lo sbaglio di non tener conto dell’errore. Ma ecco la prassi che dovrebbe seguire:

  1. Capire le cause di errore e impostare il progetto in modo da ridurle al minimo
  2. Rendere le azioni reversibili – dare la possibilità di annullare il già fatto – o rendere più difficili le azioni irreversibili
  3. Facilitare la scoperta degli errori che comunque avvengono e renderne più facile la correzione
  4. Cambiare l’atteggiamento verso gli errori. Pensare l’utente come una persona che cerca di eseguire un compito e che ci arriva attraverso approssimazioni. Non pensarlo come un soggetto che commette errori: pensare piuttosto le azioni che esegue come approssimazioni di quanto richiesto.

Si deve progettare il sistema in modo tale che ci sia un margine di errore, consapevoli che il comportamento normale non è sempre esatto. Il progetto dev’essere tale che gli errori siano facili da scoprire e suscettibili di correzioni.

Spesso per attuare quanto detto poc’anzi è indispensabili prevedere delle funzioni obbliganti, ossia una forma di vincolo fisico che “guidano” le azioni in modo tale che la mancata esecuzione di un passaggio impedisca il successivo, come per esempio:

  • interlock: obbliga le varie operazioni ad essere eseguite nella sequenza corretta
  • lockout:  dispositivo che impedisce certi comportamenti, come l’entrata in un ambiente pericoloso
  • lockin: mantiene in funzione un apparecchio, impedendo che qualcuno lo fermi prematuramente.

Un buon design esige spesso una funzione obbligante per minimizzare gli errori.

Consiglio. Partire dal presupposto che prima o poi ogni possibile contrattempo accadrà, e quindi prendere le giuste contromisure. Occorre far sì che le azioni siano reversibili.

 

L’evoluzione naturale del design. Un progetto non rimane inalterato durante il suo ciclo di vita. Anzi, si scoprono e si modificano suoi problemi e difetti in corso d’opera, a seconda del tempo, dell’energia e delle risorse a disposizione. E’ ovvio che l’obiettivo dell’evoluzione è quella di correggere gli aspetti negativi e di lasciare inalterati quelli positivi (“ascensione“).

Una forza negativa è esercitata dalle esigenze di tempo: i nuovi modelli sono già in progettazione prima ancora che i vecchi siano stati consegnati. Inoltre, raramente esistono meccanismi per raccogliere le esperienze della clientela e farne tesoro. Un’altra forza è il bisogno di distinguersi, di creare modelli che appaiano diversi da tutto quanto c’è stato prima. Sono rarissime le aziende che si accontentano di mantenere in produzione così com’è un prodotto valido, o che lo lasciano perfezionare lentamente dall’evoluzione naturale. No, ogni anno deve uscire un modello “nuovo, migliorato”, di solito corredato di nuove caratteristiche che non prendono le mosse dal modello precedente. In troppi casi i risultati sono disastrosi per il consumatore.

Una volta ottenuto un prodotto soddisfacente, ulteriori cambiamenti possono essere controproducenti, specialmente se il prodotto ha successo così com’è. Bisogna sapere quando è il momento di fermarsi.

 

Il progettista: un utente atipico. Spesso il progettista considera se stesso un utente tipico del suo oggetto. Tuttavia, spesso non “vede” tutti gli aspetti degli utenti reali, o meglio, conosce già come funziona il suo oggetto, dando per scontato che anche gli altri possano comprenderlo. Una regola di base della progettazione è di conoscere e studiare i reali utenti, a partire dalle prime fasi del progetto stesso, alfine di evitare di apportare cambiamenti radicali all’oggetto alla fine dello sviluppo. C’è differenza tra la competenza richiesta per progettare un oggetto e quella necessaria ad usarlo.

“Nel loro lavoro, i progettisti spesso finiscono per diventare degli esperti del dispositivo al quale stanno lavorando. Gli utenti spesso sono invece esperti del compito da eseguire mediante quel dispositivo”

Altra difficoltà è data dal fatto che spesso i clienti del progettista possono non essere gli utenti del prodotto. In tal caso, un cattivo design è spesso sintomo dell’attenzione ai costi, senza prendere in considerazione la facilità di uso.

 

Sette principi per trasformare compiti difficili in compiti facili. Ricapitolando, sulla base di quanto su scritto, ecco i 7 principi per una buona progettazione degli oggetti quotidiani:

  1. Usare sia la conoscenza presente nel mondo esterno che la conoscenza interiorizzata
  2. semplificare la struttura dei compiti
  3. rendere visibili le cose
  4. impostare bene le correlazioni
  5. sfruttare i vincoli, sia naturali che artificiali
  6. lasciare un margine di errore
  7. quando tutto il resto non serve, standardizzare

La caffettiera del masochista

Cosa l’utente realmente voleva…la metafora dell’altalena

Chi ha studiato ingegneria del software si sarà sicuramente imbattuto in almeno una delle seguenti figure:

tireSwing-altalena la cruda realtà

 

La metafora dell’altalena dà bene l’idea del “gap” tra le esigenze dell’utente e quello che effettivamente viene realizzato da un progetto, quando le figure coinvolte diventano troppe e poco coordinate. Vi consiglio di leggere i seguenti articoli:

 

User-centered design: progettare considerando i bisogni degli utenti

Semplicemente stupendo il libro che sto leggendo e di cui scriverò in questi giorni una sintesi su questo blog. Il libro è di Donald A. Norman e si intitola La caffettieria del masochistaRiporto un suo estratto che si collega ad una considerazione personale che avevo pensato di scrivere nei giorni scorsi.

comic-ease-of-use

Questa è una sorta di autocritica per chi come me si occupa di progettazione e sviluppo di software. Ecco il passo del libro in questione:

“Ma i progettisti sembrano particolarmente dimentichi dei bisogni degli utenti, particolarmente inclini a cadere in tutti i trabocchetti del design. Gli specialisti del design non sono interpellati quasi mai per questo tipo di prodotti. La progettazione è lasciata invece tutta nelle mani di ingegneri e programmatori, persone che di solito non hanno alcuna esperienza né competenza specialistica nel campo del design.

Il carattere astratto del computer propone una sfida tutta particolare. Il funzionamento è elettronico, invisibile, senza alcun segno esterno delle azioni che vengono eseguite. E i comandi vengono impartiti mediante un linguaggio astratto, un linguaggio che specifica il flusso interno dell’informazione, con le relative istruzioni, ma che non è particolarmente tagliato a misura dei bisogni dell’utente.

I programmatori specializzati lavorano su questi linguaggi  per impartire al sistema le istruzioni necessarie per eseguire le operazioni richieste. E’ un compito complesso e i programmatori devono possedere un ampio repertorio di competenze e talenti naturali. La messa a punto di un programma esige infatti una combinazione di capacità specialistiche, della preparazione tecnica della conoscenza del compito, fino alla cognizione delle esigenze e delle capacità degli utenti.

Ai programmatori non dovrebbe essere addossata la responsabilità delle interazioni tra la macchina e gli utenti:non ne hanno la competenza specialistica, né dovrebbero averla. Molti dei programmi esistenti per le applicazioni da parte degli utenti di base sono troppo astratti, richiedendo manovre che hanno un senso per le esigenze del computer – e agli occhi dello specialista di computer – ma non sono coerenti, ragionevoli, necessarie o comprensibili per l’utilizzatore normale. Per rendere il sistema più facile da usare e capire ci vuole una gran quantità di lavoro in più. I programmatori hanno tutta la mia comprensione, ma tuttavia non posso scusare il generale disinteresse per i problemi degli utenti. ”

 

E ancora condivido la considerazione di Norman sulla poca presenza nei programmi universitari di materie relative all’usabilità e alla progettazione “usercentric” dei sistemi, non solo informativi. Il cosiddetto user-centered design.

” La scienza del computer ha lavorato finora allo sviluppo di potenti linguaggi di programmazione che permettono di risolvere i problemi tecnici di calcolo. Deboli sforzi sono stati compiuti in direzione di efficaci linguaggi interattivi. Ogni studente di un corso per programmatori viene istruito sugli aspetti computazionali dei computer, mentre sono rarissime invece le lezioni sui problemi che si pongono all’utente. In generale questo tipo di insegnamento non è richiesto nei piani di studio, né peraltro sarebbe facile fargli posto negli orari già fittissimi e massacranti cui devono sottoporsi gli studenti d’informatica. Il risultato è che la maggior parte dei programmatori sa scrivere programmi capaci di eseguire operazioni mirabili, ma inutilizzabili per chi non è uno specialistica del ramo. Quasi nessuno di loro pensa ai problemi che deve affrontare l’utilizzatore. Da qui la sincera sorpresa che li coglie quando scoprono che le loro creazioni sottopongono l’utente comune a una dispotica tirannia.”

 

E’ importante lavorare con persone creative. Ho conosciuto professionisti capaci di applicare principi di buon design e di usabilità nella progettazione di software, sia web che mobile. Dai grafici attenti a questi principi si impara e si trae una esperienza professionale positiva, oltre a produrre software di buona qualità e piacevole per l’utente.

La cosiddetta user experience merita un’attenzione particolare; dovrebbe essere un processo a parte nello sviluppo del software. Specie nelle società ICT italiane, spesso si confondono le figure di progettista, analista, sviluppatore, oltre a non esistere quelle di graphic o user experience designer. Ma per mantenere alto il livello di qualità e competitività del prodotto, occorre essere coscienti della forte specializzazione delle competenze da mettere in gioco.

Cito due massime efficaci per trarre le seguenti conclusioni:

  1. Chi nasce tondo, non muore quadrato” – dividiamo le competenze e le responsabilità delle figure coinvolte in un progetto.  Ognuno faccia il proprio mestiere, senza confondere le professionalità. Dalla interazione di queste professionalità, nasce il buon presupposto per realizzare un prodotto di successo.
  2. Lo sparagno (cit. risparmio) è mal guadagno” – il cosiddetto “triplo vincolo” di un progetto (costo, tempo, qualità), andrebbe spostato sempre più in direzione della qualità. Per far ciò occorre dotarsi di figure competenti per coprire i vari ambiti della progettazione software (analisti, grafici, sviluppatori, progettisti, ecc.). Provate a far fare ad uno sviluppatore la grafica, nella maggior parte dei casi produrrà qualcosa di poco piacevole ed usabile per l’utente finale.

[REST] La filosofia REST: il Web ha già tutto quello di cui si ha bisogno!

L’argomento stavolta è REST (REpresentational State Transfer), vera e propria filosofia informatica. Infatti, la prima volta di cui se ne parlò fu nel 2000, nel capitolo 5 della tesi di PhD in Filosofia Informatica di Roy Fielding, uno dei principali autori delle specifiche HTTP, dal titolo Architectural Styles and the Design of Network-based Software Architectures.

Ma cosa è veramente REST? Uno standard, un modello o cosa? Purtroppo non è ancora un vero e proprio standard e, forse, non è neanche giusto che lo sia. Definisce un modello di progettazione di architetture software o, elegantemente, uno “stile architetturale”. L’idea di base del REST è quella di vedere il Web (ma anche altri “sistemi”)  come una piattaforma per l’elaborazione distribuita dei dati. E il Web ha già tutto quello di cui si ha bisogno, ossia l’infrastruttura che si basa sul protocollo HTTP e le informazioni, che diventano vere e proprie risorse. Non ha senso inserire un overhead ulteriore e, dunque, uno strato software come avviene con i Web Services in SOAP.

Riporto un passo estratto dalla tesi di Fielding in cui si introduce il senso di questo stile:

The Representational State Transfer (REST) style is an abstraction of the architectural elements within a distributed hypermedia system. REST ignores the details of component implementation and protocol syntax in order to focus on the roles of components, the constraints upon their interaction with other components, and their interpretation of significant data elements. It encompasses the fundamental constraints upon components, connectors, and data that define the basis of the Web architecture, and thus the essence of its behavior as a network-based application. […]

REST emphasizes scalability of component interactions, generality of interfaces, independent deployment of components, and intermediary components to reduce interaction latency, enforce security, and encapsulate legacy systems. I describe the software engineering principles guiding REST and the interaction constraints chosen to retain those principles, contrasting them to the constraints of other architectural styles.

 

Questo stile è diventato molto in voga negli ultimi anni per la realizzazione di Web Services altamente scalabili ed efficienti. Per approfondire l’argomento e per esempi pratici, ecco il link alle lezioni di HTML.it: RESTful Web Services – La guida, da cui ho estratto gran parte delle informazioni qui di seguito riportate.

Ecco i 5 principi su cui si basa il REST:

  • identificazione delle risorse
  • utilizzo esplicito dei metodi HTTP
  • risorse autodescrittive
  • collegamenti tra risorse
  • comunicazione senza stato
Una risorsa è qualsiasi elemento oggetto su cui è possibile effettuare operazioni ed è identificabile univocamente (attraverso una URI – Uniform Resource Identifier).
Il primo passo consiste nell’individuare le risorse da esporre tramite il Web Service, dove la loro rappresentazione “esterna” verso il client non sempre rispecchia l’implementazione o il modello interno dell’applicazione web.
Gli URI devono essere autoesplicativi, per far capire di che risorsa si tratta. Dopo aver trovato il modo di identificare le risorse, occorre definire quali operazioni effettuare su di esse. Si sfrutta quello che già si ha, ossia i metodi HTTP come GET, POST, PUT e DELETE.

 

Semplici regole nella definizione delle URI:
  • preferire l’utilizzo di nomi a quello di verbi
  • contenere la lunghezza degli URI
  • preferire uno schema posizionale, ossia una struttura gerarchica di un percorso piuttosto che la presenza di più argomenti: http://www.mionegozio.com/ordini/2011/07/01 al posto di http://www.mionegozio.com/ordini/?anno=2001&mese=07&giorno=0
  • evitare le estensioni, che legano un Web Service alla sua implementazione: ad esempio, è da preferire un URI del tipo:
http://www.mionegozio.com/ordini/?id=123
ad uno del tipo:
http://www.mionegozio.com/ordini/ordine.php?id=123

 

REST, quindi, non fa altro che mappare uno a uno le tipiche operazioni CRUD (creazione, lettura, aggiornamento, eliminazione di una risorsa) e i metodi HTTP:
  • POST –> Create (Crea un nuova risorsa)
  • GET –> Read (Ottiene una risorsa esistente)
  • PUT –> Update (Aggiorna una risorsa o ne modifica lo stato)
  • DELETE –> Delete (Elimina una risorsa)
Il tipo di rappresentazione di una risorsa inviata dal Web Service al client è indicato nella stessa risposta HTTP tramite un tipo MIME e il client stesso può anche richiedere una risorsa in uno specifico formato sfruttando l’attributo Accept di una richiesta HTTP di tipo GET. Grazie alla possibilità di rappresentazioni multiple possiamo progettare una applicazione web offrendo un gli output di un servizio in formati differenti a seconda del client. Formati più utilizzati sono XML, (X)-HTML e JSON. Su quest’ultimo trovate anche un articolo su questo sito: [JSON] Introduzione al diffuso formato di scambio dei dati
Alcuni framework sono in grado di gestire in automatico la cosiddetta content negotiation, cioè la fornitura di una rappresentazione nel formato richiesto dal client.

 

Le interazioni tra client e server devono essere senza stato, rispettando la comunicazione stateless nativa del protocollo HTTP. La gestione dello stato (se necessaria) avviene sul client, ottimizzando le prestazioni del server che non deve curare lo stato di una sessione e può essere effettuato con l’uso di chiavi di sessione, come i cookie.
Il fatto che i principi REST escludano la gestione dello stato della comunicazione non deve però far pensare che i Web Service RESTful siano senza stato. L’acronimo REST sta per REpresentational State Transfer, sottolineando proprio la centralità della gestione dello stato in un sistema distribuito. Lo stato che REST prende in considerazione è però quello delle risorse e dell’intera applicazione.

  • Lo stato delle risorse è dato dall’insieme dei valori delle caratteristiche di una risorsa in un dato momento. Un Web Service è responsabile della gestione dello stato delle risorse. Un client può accedere allo stato di una risorsa tramite le diverse rappresentazioni della risorsa stessa e contribuire a modificarlo per mezzo dei metodi PUT, POST e DELETE dell’HTTP.
  • Lo stato del client è rappresentato dall’insieme del contesto e delle risorse ottenute in uno specifico momento. Il server può influenzare le transizioni di stato del client inviando differenti rappresentazioni in risposta alle sue richieste.
  • Lo stato dell’applicazione, cioè del risultato dell’interazione tra client e server, è dato dallo stato del client e delle risorse gestite dal server. Lo stato dell’applicazione determina le modalità di modifica dello stato delle risorse e del client.

A differenza di quanto avviene in buona parte delle applicazioni Web, dove lo stato dell’applicazione viene spesso mantenuto dal server insieme allo stato della comunicazione, lo stato dell’applicazione in un’architettura RESTful è il frutto della collaborazione di client e server, ciascuno con i propri ruoli e responsabilità.

Come da acronimo, una applicazione passa da uno stato all’altro, principio noto come HATEOAS, usando i collegamenti ipertestuali: una applicazione è intesa come rete di risorse in cui un client naviga seguendo i collegamenti ammissibili tra una risorsa e l’altra, come una macchina a stati finiti.

Un bel articolo sulle differenze tra SOAP e RESTful, lo potete leggere sempre su HTML.it:

RESTful VS. SOAP. REST propone una visione del Web incentrata sul concetto di risorsa mentre i SOAP Web Service mettono in risalto il concetto di servizio.

  • Un Web Service RESTful è custode di un insieme di risorse sulle quali un client può chiedere le operazioni canoniche del protocollo HTTP
  • Un Web Service basato su SOAP espone un insieme di metodi richiamabili da remoto da parte di un client

L’approccio dei SOAP Web service ha mutuato un’architettura applicativa denominata SOAService Oriented Architecture, a cui si è recentemente contrapposta l’architettura ROAResource Oriented Architecture, ispirata ai principi REST. SOAP utilizza HTTP come protocollo di trasporto, ma non è limitato né vincolato ad esso, dal momento che può benissimo usare altri protocolli di trasporto. SOAP non sfrutta a pieno il protocollo HTTP, utilizzandolo come semplice protocollo di trasporto. REST invece sfrutta HTTP per quello che è, un protocollo di livello applicativo, e ne utilizza a pieno le potenzialità.

È evidente che l’approccio adottato dai Web Service basati su SOAP è derivato dalle tecnologie di interoperabilità esistenti al di fuori del Web e basato essenzialmente su chiamate di procedura remota, come DCOM, CORBA e RMI. In sostanza questo approccio può essere visto come una sorta di adattamento di queste tecnologie al Web.

Inoltre i Web Service basati su SOAP prevedono lo standard WSDLWeb Service Description Language, per definire l’interfaccia di un servizio. Questa è un’ulteriore evidenza del tentativo di adattare al Web l’approccio di interoperabilità basato su chiamate remote. Infatti il WSDL non è altro che un IDL (Interface Description Language) per un componente software. Da un lato l’esistenza di WSDL favorisce l’uso di tool per creare automaticamente client in un determinato linguaggio di programmazione, ma allo stesso tempo induce a creare una forte dipendenza tra client e server.

REST non prevede esplicitamente nessuna modalità per descrivere come interagire con una risorsa. Le operazioni sono implicite nel protocollo HTTP. L’approccio REST tende a conservare e ad esaltare le caratteristiche intrinseche del Web evidenziandone la predisposizione ad essere una piattaforma per l’elaborazione distribuita. Quindi, non è necessario aggiungere nulla a quanto è già esistente sul Web per consentire ad applicazioni remote di interagire.