> INDICE DEL CORSO
Quanto segue deriva dalla mia esperienza nell'Ingegneria del Software per applicazioni mobili e dai miei tanti errori e correzioni di rotta...
Linee guida di base per la gestione della complessità in un progetto software
- Rapportati continuamente con gli stakeholder e con altri sviluppatori, prendi l'abitudine di usare in maniera proficua piattaforme di mutuo aiuto tra sviluppatori come StackOverflow e Github, costruisci rapporti umani di fiducia, cerca di far parte di un team in cui il tuo lavoro è apprezzato e valorizzato (cioè retribuito) e stai lontano da ambienti dove le relazioni umane invece di essere costruttive sono distruttive.
- Chiarisci il problema da affrontare, poi pensalo ad oggetti, lavoralo ad oggetti, struttura tutto ad oggetti. Scegli un linguaggio che ti direzioni correttamente e ordinatamente a lavorare ad oggetti (Java).
- Fa che i tuoi strumenti di lavoro riducano al minimo il tuo sforzo e che ti regalino la massima compatibilità multi-piafforma: un'eccellente scelta lato client è l'approccio "write once run anywhere" di Codename One, un'ottima scelta lato server è l'approccio "production-ready" di Spring Boot.
- Il codice deve essere organizzato secondo un approccio top-down, nella maniera più intuitiva possibile: parti da una visione globale del problema, struttura il codice in livelli diversi, in modo che ogni funzionalità complessa sia alla fine ridotta ad una sola riga di codice (o quasi), la cui implementazione sia la più generica possibile (finché ha senso generalizzare in base al contesto e finché è verosimile che sia utile). Seguire un approccio top-down significa anche fare in modo che i problemi implementativi siano il meno possibile bloccanti rispetto al progetto complessivo.
- Suddividi il lavoro in task programmabili: un approccio top-down rende realistica la creazione di una serie di compiti che possono essere programmati senza conoscerne ancora l’effettiva implementazione, permettendoti di avanzare con maggior sicurezza e senza perdere l’orientamento anche quando le cose da tenere a mente (ovvero le questioni aperte su cui stai lavorando) sono tante.
- Prima di scrivere il codice, valuta varie alternative, magari facendo grafici, disegni o procedure anche su carta, e scegli l’algoritmo meno incasinato e più vicino alla logica di funzionamento del tuo ambiente di sviluppo (ad es., il più vicino possibile alla logica delle API di Codename One).
- Tra le varie alternative di algoritmi, parti sempre dalla soluzione che ti pare più semplice e che “approssima” sufficientemente il problema, creando un apposito test case: l’aggiunta di dettagli o di perfezionamenti dovrebbe essere indipendente dal progetto complessivo, in modo da isolare le singole funzionalità, e dovrebbe avvenire solo quando il codice più semplice è sufficientemente collaudato.
- Ogni parte del codice deve essere autoesplicativa, si deve capire velocemente cosa fa: ne segue che non ci devono essere casini, cioè ogni codice che può apparire criptico va evitato, oppure, in casi particolari che proprio richiedono un codice non intuitivo, questo va isolato e adeguatamente documentato. Anche la scelta dei nomi dei package, dei nomi delle classi e della collocazione delle classi all'interno dei package dovrebbe essere autoesplicativa.
- L’aggiunta o la modifica di funzionalità dovrebbe essere agevole: ciò è una naturale conseguenza dei punti precedenti se applicati correttamente. Più è grande il progetto, infatti, e maggiore è il bisogno di rendere il codice manutenibile e comprensibile anche a distanza di tempo. Evitare grossi blocchi di codice, isolare i problemi e ridurre la ridondanza sono d'aiuto.
- In progetti complessi, i dettagli implementativi potrebbero essere inseriti in un apposito package diverso dal resto del progetto (una sorta di package che contiene solo utilities).
- L'esecuzione di test e lo sviluppo vanno di pari passo: fai i test di ogni pezzo di implementazione sia nel simulatore (di Codename One) sia sui target previsti dal tuo progetto (ad es. Android, iPhone, Web-App, ecc.). Soprattutto quando sviluppi multi-piattaforma, non dare per scontato che le cose funzionino sempre come previsto: per ogni modifica o aggiunta su cui hai dubbi, è sempre meglio fare verifiche su target diversi.
- Fai release frequenti del tuo lavoro e sottoponile agli stakeholder: ciò serve sia da testing, sia da costante verifica del corretto perseguimento degli obiettivi del progetto.
- Ogni volta che si verifica un imprevisto o un'anomalia non chiara, è meglio isolare il problema in un test case sufficiente a riprodurlo, usando il minimo strettamente indispensabile di righe di codice: ciò è molto utile anche per chiedere aiuto ad altri sviluppatori (anzi, di solito è l'unico modo proficuo per poter chiedere aiuto). Repetita iuvant: se qualcosa non va, ma il codice è corretto o ti sembra tale, isola il problema e chiedi ad altri sviluppatori, piuttosto che tentare di raggirare il problema inserendo ulteriore codice.
- Quando capitano cose che ti appaiono impossibili o insensate, è il momento di fare una pausa. Soprattutto quando sei assolutamente certo che il tuo codice deve fare una cosa e invece ne fa un'altra... spegni il computer e vai a fare altro.
- Quando per risolvere un problema semplice il tuo codice si fa via via sempre più complesso e ti sembra di aver perso il controllo di ciò che fa o di come interagisce con il resto dell'app, allora... calmati, accetta l'ipotesi che forse hai speso ore e ore nella direzione sbagliata e, a mente serena e riposata, affronta di nuovo il problema da capo.
- Usa un ambiente di sviluppo (IDE) che ti agevoli nel conservare copie del tuo lavoro risalenti a momenti diversi e che, ogni volta che sarà opportuno, ti permetta di annullare le modifiche per tornare a uno snapshot precendetemente salvato: una soluzione valida può essere Netbeans all'interno di un ambiente virtualizzato (ad es. con VirtualBox). Questo approccio dà grande libertà di sperimentare senza paura di far danni o di perdere il lavoro fatto.
Francesco Galgani,
1 maggio 2019