Nei post precedenti abbiamo visto cosa sia il debito tecnico e quali siano alcune tra le cause più comuni che portano alla generazione del debito, in particolare la forma indesiderata: quello involontario.
In questo post vedremo come gestirlo, poiché il debito di per se non è un male: il debito non gestito lo è. Tutti i sistemi hanno debito.
Individualo
La cosa, la piú importante, consiste nell’individuare il debito. Del resto se non si sa dov’è, non si puó intervenire per ripagarlo.
Se si tratta di debito contratto volontariamente, la cosa è ovvia: si sa già che si sta prendendo una scorciatoia e si sa anche dove e come si sta introducendo debito.
Discorso diverso quando parliamo di debito involontario, ad esempio su un sistema “ereditato” e privo di documentazione: in tal caso il traumatico risveglio dalla “beata ignoranza” avverrà quando il cliente infuriato per la scarsa produttività e qualità ci costringerà a correre ai ripari, impegnando tempo e risorse nell’individuazione dei punti critici.
Individuare i debiti nel codice, nell’architettura e nell’infrastruttura richiede un’analisi. I tool di analisi statica possono aiutare a trovare debiti nel codice (ad esempio ad individuare scarsa copertura di unit test) , ma solitamente non sono utili per le altre due forme di debito. Per queste, spesso un’occhio esterno, non polarizzato, può fornire risultati sorprendenti: le cose che abbiamo sotto il naso tutti i giorni appaiono invisibili, comprese le storture.
Che abbiamo un parere esterno o meno, un buon modo per trovare le aree di intervento consiste nel porsi delle domande.
- Quali sono gli obiettivi di business dietro al mio sistema?
- Quali sono i “pain point” (fatti) in relazione agli obiettivi di business?
- Quali domande mi sono utili per capire le cause dei pain point? Quali metriche mi sono utili per misurare il miglioramento?
esempio
Business goal: time to market
Pain point: La velocity cala, occorre un tempo spropositato per fare una modifica e testarla e non sappiamo perchè rallentiamo.
Domande utili: quanto è complesso il mio codice? quanto è automatizzato il test? Dove il team spende la maggior parte del tempo?
Chiaramente senza metriche e misure rispondere alle domande diventa difficile.
Non dimenticartene
Che il debito sia stato contratto volutamente o ricostruito ex-post, una volta individuato deve essere tracciato, cristallizzato in un’item che possiamo decidere di lavorare successivamente.
Un’item di debito tecnico dovrebbe contenere almeno 5 elementi:
Nome: breve descrizione dell’item
Descrizione: descrizione della natura del debito
Conseguenze: impatto della presenza del debito
Soluzione: descrizione delle attività necessarie a ripagare il debito
Assegnatario: membro del team che ha in carico la risoluzione.
Le item di debito tecnico rappresentano del lavoro da fare: come tali devono stare nel backlog e la loro lavorazione pianificata negli sprint (supponendo che il team usi scrum).
esempio
Nome: Mancanza di unit test nel modulo xyz
Descrizione: il modulo xyz ha una copertura di unit test dello 0%. La ragione è che si tratta di un modulo scritto in condizioni di emergenza e che si supponeva sarebbe stato rimosso dopo pochi giorni. Col passare del tempo il modulo è poi diventato dipendenza per molti altri moduli .
Conseguenze: le modifiche al modulo richiederanno regression test manuali, con conseguente rischio di errori e consumo di tempo.
Soluzione: scrivere unit test fino a raggiungere una copertura in linea con le guidelines interne per i moduli critici.
Assegnatario: Peppe Nappa
Dato l’esempio sopra, la domanda è: dovremmo ripagare il debito? Nel prossimo Sprint? Tra un mese? Mai? La risposta, come vedremo tra poco, è uno sconfortante “dipende”.
Decidi cosa ripagare
Come già detto negli articoli precedenti, non è detto che il debito debba essere ripagato.Nel caso in cui lo sia, proprio come la metafora suggerisce, non è detto che debba essere ripagato in una sola soluzione… si possono fare rate. Tuttavia, talvolta, ripagarlo è la strategia giusta. Ma quando ?
La risposta teorica è: quando non è più conveniente tenerlo. Ricordiamo infatti che un debito contratto volontariamente costituisce un vantaggio, in quanto permette di “avere qualcosa prima”: se questo elemento di convenienza non è presente, non è un debito tecnico ma solo… cattiva progettazione.
Il modo migliore per decidere quando ripagare un debito è effettuare un’analisi costo-beneficio.
Costo
Calcolare il costo è relativamente semplice. Occorre considerare tre elementi:
- il debito iniziale, cioè l’effort per sistemare la soluzione sub-ottimale iniziale.
- Gli interessi maturati, cioè l’effort per sistemare tutte le successive soluzioni sub ottimali derivanti dalla scelta iniziale.
- Il costo opportunità.
Quest’ultima voce rappresenta il “costo di non fare”: poiché ripagare il debito richiede lavoro, questo lavoro non potrà essere erogato per altre attività, ad esempio per aggiungere features o fixare bug. Quanto costa non avere una feature o averla in ritardo non è facile da stabilire. Ogni caso va trattato a sè.
Beneficio
Il beneficio è dato dalla riduzione di effort per le modifiche successive. Tale riduzione si esplica come maggior velocità e minor difettosità. Va da se quindi che ripagare un debito in un sistema che non evolve o in aree di un sistema che non sono soggette a cambiamento non porterà alcun beneficio in termini di velocità.
Avere una chiara idea dell’evoluzione del sistema costituisce quindi un prerequisito per una gestione razionale del debito, in assenza della quale si rischia di violare la buona pratica dello YAGNI.
Sulla carta suona molto semplice e razionale. Tuttavia quantificare costi e benefici è un esercizio di stima che, come tale, è soggetto a polarizzazioni, esperienza del valutante e meri interessi. Ciò nonostante, cercare di quantificare costi e benefici costituisce un esercizio valido per avere un argomento di discussione.
Crea spazio
Ripagare item di debito richiede lavoro. Se si segue una metodologia come Scrum, tutto il lavoro del team deve essere presente nel backlog, pertanto è li che vanno le item di debito tecnico. Se non si segue scrum, resta comunque valido il principio per cui… se il team fa una cosa, non potrà farne un’altra.
Analizziamo meglio caso Scrum. Il backlog già contiene, come minimo, le user stories e i bug.
In alcuni casi troviamo anche voci di miglioramento di requisiti non funzionali (Architettura) o di processo derivanti dalle retrospettive, chiamate talvolta “technical user stories”.
Aggiungendo le item di debito tecnico completiamo un quadro simmetrico molto elegante e comprensibile anche ad un audience poco tecnico:
- Le user stories costituiscono la parte visibile del prodotto che aggiunge valore al prodotto stesso.
- I bug costituiscono la parte visibile del prodotto che riduce il valore del prodotto stesso.
- Le technical user stories rappresentano la parte invisibile, non funzionale del prodotto ed aggiungono valore.
- Le item di debito tecnico sono altrettanto invisibili e riducono il valore del prodotto, o meglio, riducono la capacità di aumentare il valore del prodotto stesso.
Avere le item di debito tracciate nel backlog permette di inserire queste item nel normale ciclo di grooming, selezione e prioritizzazione e, in ultima analisi, di gestirle.
Conclusioni
Non esiste un sistema che sia privo di debito, ne è del tutto desiderabile come stato: il meglio è nemico del bene.
Il debito contratto in modo volontario è un valore, ma deve essere gestito. Gli aspetti più critici della gestione del debito sono la sua individuazione e la gestione del piano di rientro: trattandosi di aspetti non visibili esternamente, riuscire a convincere il team della necessità di rallentare temporaneamente l’aggiunta di features o la chiusura di bug richiede una fiducia che si trova solo nei team migliori.
Provare a quantificare il costo/beneficio aiuta a sostenere il caso per la riduzione del debito. Tracciarlo nel backlog aiuta a non dimenticarsene.