Con questo post chilometrico voglio tirare le somme dal punto di vista tecnico, funzionale e di processo sull'ultimo progetto sul quale ho lavorato (J2EE), della durata di 6 mesi scarsi e che andrà in produzione nella seconda metà di aprile. Pur così lungo, in questo post non ho scritto tutto ciò che avrei voluto, spero di poterlo integrare in futuro con ulteriori pagine del diario.
Obiettivi e situazione iniziale:
* seguire come sempre un approccio di piccoli rilasci in test ogni settimana o due al massimo
* migrare le tecnologie utilizzate fino ad allora (applicazione J2EE con Struts, BC4J, Web Services, OracleDb ed Oracle Lite) a Spring, Hibernate, Web Services, JUnit, ANT, OracleDb ed Oracle Lite.
* volontà di migliorare il processo di sviluppo introducendo nuove pratiche:
1) test first per migliorare qualità del codice
2) planning game ogni settimana o due per monitorare in modo preciso l'evolversi del progetto dal punto di vista della funzionalità e dei tempi, e per massimizzare il feedback e la comunicazione
3) introduzione delle carte e di una lavagna dove esibirle per aumentare la trasparenza e rendere chiaro ad ogni membro del team ed al cliente cosa c'è da fare e su cosa si sta lavorando
* superare i problemi riscontrati fino ad allora con l'IDE utilizzata, soprattutto per quanto riguarda CVS, utilizzo delle risorse e stabilità
Questi i rischi a cui andavamo incontro:
* innovazione introdotta oltre il 30% delle tecnologie utilizzate
* conoscenza delle nuove tecnologie da adottare da parte di un solo membro del team
* rischi di bassa comunicazione: 4 sviluppatori più un esperto di dominio (e integration-man) e un story-tester in quattro uffici differenti (di cui 2 per gli sviluppatori).
* non tutti favorevoli ad abbandonare JDeveloper
* approccio Test Driven mai sperimentato
* cultura dei test automatici non completamente assimilata
* sovrapposizione, nelle varie funzionalità da implementare, di sezioni del dominio e derivante rischio di non parallelizzare efficamente gli sviluppi o di avere un implementazione del dominio non coerente, ridondante e con duplicazioni
* l'approccio a piccole iterazione minimizza il rischio di non affrontare in modo efficiente il cambiamento come modifica delle priorità o perché le funzionalità sono più difficili di quanto previsto, ad ogni modo questi sono rischi sempre presenti nei progetti informatici
* rischio che il team si smembri
COME E' ANDATA:
Iterazioni brevi e collaborazione del cliente:
Il primo rilascio in test è avvenuto dopo più di un mese, po' troppo ritardato a mio parere, forse rilasciando prima avremmo avuto un riciclo più breve. Le iterazioni seguenti sono invece state cadenzate ogni settimana o due, senza fissare sempre lo stesso giorno della settimana per il rilascio stesso. Forse fissare un giorno della settimana avrebbe facilitato la conoscenza del budget di ogni membro del team per l'iterazione seguente. Ad ogni modo con un cliente collaborativo come il nostro non ci sono stati problemi. In realtà è necessaria una breve precisazione. Il progetto ha due committenti, per i quali alcune richieste si sovrappongono, mentre altre sono peculiari per uno o per l'altro. Purtroppo non abbiamo riscontrato lo stesso livello di collaborazione da parte di entrambi i clienti. La (forte) speranza è che ovviamente ciò non avvenga in futuro. Ad ogni modo il progetto ha avuto successo perché abbiamo ben gestito i rilasci in test, facendo testare pesantemente le funzionalità al cliente più presente ed interessato.
A questo proposito vorrei citare uno studio che dimostra che il 20% dei requisiti genera l'80% del valore: è chiaro che è fondamentale saper identificare quel 20% e ciò è possibile solamente con un cliente collaborativo in grado di dare feedback molto frequente e di fornire delle priorità al fine di modificare lo scope alla luce di quanto appreso e toccato con mano fino a quel momento, in un processo tutto volto a rilasciare il più alto valore di business ad ogni iterazione.
Alle prossime settimane che ci dividono dalla produzione (per entrambi i clienti) l'ultima parola.
Smembramento del team:
Purtroppo dopo circa due mesi di lavoro, lo sviluppatore con la maggiore esperienza è stato sganciato dal team. La decisione del cliente è stata quella di non sostituirlo, ma di allungare i tempi.
Il team di sviluppo rimanente (3 sviluppatori), ha comunque reagito bene a questo cambiamento.
Test di unità:
approccio sistematico alla scrittura dei test non uniforme all'interno del team. Soprattutto inizialmente quando si sviluppava singolarmente ed in due uffici differenti. Problema risolto nel corso del progetto aumentando la comunicazione lavorando in un solo ufficio e introducendo il pair programming in modo sistematico. Il cliente ha accettato senza alcuna reticenza questa nuova pratica (grande Dario!). Alla fine il pair programming ha risolto il problema dei test di unità alla grande, con più del 70% dell'applicazione coperta da test automatici (430 test). Da circa un mese e grosso modo ogni settimana, mi occupo di stampare un report che riporti la percentuale di copertura del codice da parte degli unit test per tutta l'applicazione e per ogni package che la compone. Vedere una percentuale che sale settimana dopo settimana rende il team fortemente motivato su quanto fatto fino a quel momento, o in caso di rallentamento o regressione dà subito una visione di quali sono le zone di codice a più alto rischio di errori.
Nuove tecnologie:
si è fatta sentire la poca comunicazione iniziale tra tutti i membri del team, per cui alcuni problemi tecnologici hanno avuto soluzioni subottimali. Avrei dovuto percepire da subito l'importanza della comunicazione e del pair sistematico, mentre l'iniziale paura istintiva di rallentare lo sviluppo lavorando a coppie ha portato a scelte tecniche non pianemente condivise da tutto il tema. Ad ogni modo l'elevato spirito di team che ci ha sempre contraddistinto hanno portato ad una collaborazione come sempre fondamentale. Siamo inoltre stati molto bravi ad aver saputo affrontare il rischio derivante dall'avere introdotto in un nuovo progetto molto più del 50% di innovazione tecnologica rispetto al progetto precedente. Onore al merito va soprattutto a Spring, del quale spero di riuscire a tessere le lodi in un altro post. Ringrazio anche il mio amico Frank che per primo mi ha messo la pulce nell'orecchio.
Funzionalità e prestazioni lato mobile e lato sede:
La parte relavita all'applicazione client mobile su Oracle Lite ha subito profonde modifiche sia dal punto di vista delle funzionalità, sia dal punto di vista più tecnico delle performance. Infatti è stata estesa pesantemente la gestione delle consuntivazioni delle attività al fine di supportare la consuntivazione di oggetti di tipi differenti ma appartenenti alla stessa attività (estensione avvenuta anche per la parte sede J2EE).
Il radicamento della cultura dei test automatici ed una reale esigenza di miglioramento ci ha portato ad effettuare dei test di carico massivi al fine di migliorare le prestazioni di sincronizzazione del mobile verso la sede e viceversa. Il lavoro di tuning effettuato alla luce dell’analisi dei test ha dato risutalti davvero molto lusinghieri con sincronizzazioni che non superano mai i 2 minuti, e che nella stragrande maggioranza dei casi sono al di sotto del minuto.
L’applicazione lato sede è ora monitorata nelle prestazioni e nell’utilizzo della memoria per mezzo di JProfiler sull’Oracle IAS. Inoltre per quanto riguarda le funzionalità dell'applicazione è stato fatto un grande passo avanti, portando (ad esempio) le funzionalità prima fruibili solo dal client mobile, anche lato sede.
Possibili estensioni funzionali per l'applicazione lato sede sono la storicizzazione delle formazioni e rivedere lo strumento di schedulazione delle attività per renderlo più facilmente utilizzabile e mantenibile.
Carte (cosa è una carta?)
questa nuova pratica si è rivelata da subito molto condivisa.
Abbiamo utilizzato le carte per conoscere sempre in ogni momento ed in modo trasparente le storie da implementare ad ogni iterazione e per avere una reale visione di ciò che abbiamo fatto e di ciò che ci resta da fare. La comodità di poter staccare ed attaccare le storie, di poter portare le carte quando si effettuano degli incontri fuori sede e l'essenzialità delle descrizioni che implicano le carte stesse, sono state una delle grandi scoperte di questo progetto. Mi aspetto in futuro di poter sfruttare un'altra caratteristica delle storie scritte sulle carte: il tracciare sulle carte la stima del tempo per l'implementazione ed aggiornarle con il tempo effettivo impiegato servirà in futuro, come insegna Ron Jeffries, a fare stime più accurate. Inoltre la sensazione che deriva dal vedere più di 50 carte implementate ed una lavagna sempre colma di storie, è di orgoglio, trasparenza e motivazione a lavorare molto più forti da qualunque altro piano che non rispecchi l'andamento reale del progetto. A mio parere troppe storie sulle carte sono ancora troppo tecniche, mentre dovremmo cercare in futuro di renderle più comprensibili al cliente. Tanto altro avrei da dire su questi che sembrano semplici e forse anche ridicoli cartoncini, magari sarà argomento del prossimo post.
Planning game: (cosa è il planning game?)
abbiamo rilasciato nuove funzionalità da far testare al cliente ogni due settimane circa. Non siamo stati sempre molto precisi con i rilasci, nel senso che è capitato più di una volta di far slittare una scadenza di qualche giorno al fine di completare le storie pattuite, invece che tagliare su qualche aspetto funzionale da far rientrare poi nell'iterazione seguente. Il cliente (uno dei due) ha collaborato come sempre, e ho il proposito di farlo intervenire maggiormente e sistematicamente ad ogni planning game, definendo con lui test automatici, ora ancora esplorativi anche se fatti in modo davvero molto preciso e sistematico dal cliente stesso.
IDE (JDeveloper ed Eclipse):
Qui ci sono state le discussioni più animate.
Ho imparato infatti che la scelta dell'ambiente di sviluppo è una delle scelte che più toccano la sensibilità dello sviluppatore, probabilmente perché è il pane di ogni giorno. Siamo riusciti a risolvere questo problema adottando delle convenzioni di progetto che ci permettono di avere progetti cross-ide, rendendo libero ogni sviluppatore di utilizzare l'ide che preferisce. La soluzione tecnica che ci ha permesso di superare un problema di Rispetto reciproco è stato Ant.
Modellazione del dominio, aspetti di design:
Dal punto di vista tecnico è qui che a mio parere continuano ad esserci le maggiori sfide. Abbiamo cominciato lo sviluppo creando 4 progetti per ogni persona, e quindi 4 applicazioni a sè stanti. Procedendo con l'implementazione è emerso che c'erano molte aree di dominio comuni ai quattro progetti, ed il non avere adottato da subito il pair programming con la rotazione delle coppie unita al fatto di essere in uffici diversi ha portato una comunicazione non al massimo e ad avere duplicato la modellazione e l'implementazione di parti del dominio. L'avere utilizzato Spring ha incentivato moltissimo la scrittura di un buon design e ciò ha contribuito insieme agli unit test, a permetterci a metà progetto di unire i quattro sotto-progetti in un'unica applicazione, in modo da far emergere in modo chiaro le duplicazioni ed i punti in cui intervenire per rifattorizzare il modello. Come ho detto probabilmente una maggiore comunicazione per mezzo del pair programming avrebbe portato ad un risultato migliore. Resta comunque una grande sfida e sicuramente "la" grande sfida di ogni progetto quella di costruire un modello del dominio e una sua implementazione fortemente legati e dar vita a quel "supple design" di cui parla Eric Evans nel suo "Domain driven design". Infatti mentre per gli aspetti più tecnici legati al buon design, un refactoring continuo, ogni dieci quindici minuti, garantisce un design flessibile, trasparente, non immmobile e non fragile, ancor più difficile è riuscire ad avere "a supple design" da un punto di vista più concettuale, un design che sia come un libro aperto sul dominio modellato e con un linguaggio che permetta anche ad una persona non tecnica, ma esperta del dominio, di comprendere il codice e muovere critiche sul modello stesso. A questo proposito abbiamo ancora molto da imparare sia a livello di pratiche e di processo che permettano di arrivare a questo obiettivo in modo ripetibile, e sia a livello tecnico per allenare la nostra mente a pensare in questi termini. Continuos Integration!
Desiderata futuri:
- fare refactoring sul modello del dominio per rimuovere le duplicazioni ancora presenti. Problema è giustificare al cliente il tempo richiesto per tali operazioni. La mia proposta sarà di dedicare il 10% del tempo di ogni storia ad un refactoring costante di questo tipo.
- planning game sempre con il cliente presente, e a distanza di massimo due settimane.
- testare il flusso delle pagine web per quanto riguarda il passaggio dei parametri nella request: in questi 6 mesi è stata la parte più fragile ed il maggior numero di giorni spesi per ricicli (perché senza test automatici). Non penso possa essere utile testare le pagine visualizzate (ad esempio testare cosa c'è scritto nella pagina etc).
- altra causa che ha portato ad avere ricicli ancora troppo lunghi è stato il non esplicitare in maniera completa tutte le micro-funzionalità che compongono una storia, per cui, credendo di averne terminato l'implementazione, ci si accorgeva in fase di testing che invece mancava di alcuni requisiti.
- introdurre test di accettazione automatici, pur mantenendo i test esplorativi, in modo che uno completi l'altro. In questo modo portare nel processo tutti i vantaggi di avere test di accettazione automatici:
- chiarire i dubbi del cliente con esempi concreti e a lui comprensibili, facilitando al cliente stesso la comprensione di ciò che realmente vuole
- rendere gli sviluppatori sempre concentrati sul reale valore aggiunto dell’applicazione (le storie che il cliente chiede di implementare), minimizzando le energie spese per risolvere problemi tecnici non sempre ad alto valore di business;
- avere un catalogo consultabile da chiunque via web dei reali requisiti implementati dall’applicazione;
- avere una documentazione eseguibile dell’applicazione sempre aggiornata;
- avere test di regressione;
- aumentare la fiducia tra committente e sviluppatori.
- migliorare l'accuratezza delle nostre stime buttando giù in modo preciso i task di ogni storia ad ogni iteration planning
- affiancare ai report sulla copertura dei test anche report sulla qualità del codice misurata con le opportune metriche.
- continuare a percorrere quella path of improvement che ci ha portato fin qui