Molte aziende lesinano sulla qualità del codice: richiede troppo tempo ed è troppo costoso. Questa argomentazione non è solo sbagliata, ma anche pericolosa a lungo termine.Immagino che tu conosca il fenomeno: stai lavorando a un progetto software e scopri un bug. Dovresti risolvere il problema subito, ma stai lavorando a una funzionalità che è già in ritardo. Per correggere il bug, dovresti anche aggiornare una dipendenza, ma non è facile perché richiederebbe di apportare modifiche ad alcune aree del codice.
Poiché sei già in ritardo, prendi l'unica decisione possibile: rimandare la correzione del bug a "più tardi". Il punto chiave, tuttavia, è che questo “dopo” non accade mai. Ciò significa che dopo un po' di tempo ti ritrovi con un'enorme montagna di debito tecnico e ti chiedi: come si è arrivati a questo punto?
La teoria delle finestre rotte
Questa situazione non è affatto nuova. Ha perfino un nome: " teoria delle finestre rotte ". Ciò non significa che il sistema operativo Windows sia di nuovo difettoso, ma il termine deriva dall'urbanistica. L'idea alla base è semplice ed efficace allo stesso tempo: riguarda il motivo per cui la criminalità sembra riuscire a diffondersi senza controllo in alcune zone della città. La teoria delle finestre rotte sostiene che ciò accade quando i quartieri vengono trascurati. Ad esempio, se gli edifici rimangono permanentemente vuoti e non vengono demoliti, come forse si sarebbe potuto pianificare da tempo.
Tolleranza zero per la qualità del software // Tedesco
Nei primi anni '80, i ricercatori sociali statunitensi James Wilson e George Kelling scelsero la finestra rotta come simbolo di questo fenomeno: se un vetro si rompe e nessuno lo sostituisce, significa che a nessuno importa. Tuttavia, poiché nessuno vuole vivere accanto a una casa vuota con una finestra irrimediabilmente rotta, i primi vicini se ne vanno presto.
Ciò si tradurrà in più case vuote e, prima o poi, qualcuno probabilmente romperà una finestra anche lì. Ciò crea lentamente una reazione a catena in cui il quartiere continua a deteriorarsi, la coesione sociale diminuisce e, a un certo punto, può diventare molto difficile cambiare qualcosa, anche se qualcuno lo volesse. Ciò abbassa la soglia di inibizione nei confronti del crimine, il che in ultima analisi non fa che accelerare l'intero processo.
New York negli anni '90
La questione cruciale ora è come si possa riportare sotto controllo un simile sviluppo. In effetti, esiste una risposta a questa domanda che ha funzionato in passato, ad esempio a New York negli anni '90. In questo caso, la situazione descritta all'inizio descriveva lo status quo in modo piuttosto accurato e il sindaco dell'epoca (dal 1994 al 2001 era Rudolph Giuliani, che forse conoscete come l'ex consigliere legale di Donald Trump) perseguì la cosiddetta strategia di "tolleranza zero al crimine".
Come suggerisce il nome, ciò significa non mostrare alcuna clemenza per nessuna violazione, nemmeno per infrazioni minori come il parcheggio illegale. Questa iniziativa ebbe successo in quanto il tasso di criminalità diminuì drasticamente negli anni successivi. Tuttavia, non bisogna dimenticare che questa presenza costante della polizia è stata a sua volta criticata perché alcuni ritenevano che andasse troppo oltre. Soprattutto negli Stati Uniti, sentiamo continuamente parlare di violenza da parte della polizia e di comportamenti razzisti, che ovviamente rappresentano un problema altrettanto grave. In sintesi, è difficile trovare il giusto equilibrio, ma una strategia di tolleranza zero può ovviamente contribuire notevolmente a frenare la criminalità dilagante.
La connessione allo sviluppo del software
Cosa c'entra questo con lo sviluppo del software? Bene, la teoria delle finestre rotte può essere facilmente applicata ai progetti software. In sintesi: ogni bug irrisolto è una finestra rotta. Ogni riga di codice che necessita di manutenzione ma non lo è è una finestra rotta. Qualsiasi dipendenza obsoleta che non viene aggiornata è una finestra rotta. E così via. In altre parole, se non ti prendi cura in modo coerente della tua base di codice con una strategia di tolleranza zero, ciò porterà inevitabilmente a una spirale discendente nel tuo progetto.
Perché? Perché errori e debiti tecnici si sommano. Ciò significa che lo sforzo necessario per risolverli a un certo punto aumenta costantemente. Allo stesso tempo aumenta anche il rischio di rompere qualcosa. Entrambe queste cose fanno sì che nessuno osi toccare il codice, il che a sua volta porta solo a più bug e a un debito tecnico ancora maggiore. In questo modo si crea una base instabile fin dall'inizio, sulla quale si continua a costruire, rendendo la struttura ancora più fragile, fino a trasformarla in un castello di carte destinato inevitabilmente a crollare.
A ciò si aggiunge il timore di dover adattare o estendere moduli già esistenti, perché non si sa se una funzione possa essere una carta di supporto a questa fragile costruzione. Di conseguenza, tutti lavorano sul codice esistente, rendendo lo sviluppo complicato, lento e costoso. E a causa di questa instabilità, nessuno vuole più rischiare dipendenze esterne perché ciò comporta uno sforzo. Quindi le persone preferiscono attenersi alle versioni che sembrano funzionare, ma a lungo andare questo limita la possibilità di aggiornamenti e porta rapidamente a falle di sicurezza o problemi irrisolti.
Ovviamente è rischioso non preoccuparsi della qualità del codice di un progetto. Ma c'è un altro fattore: chi sono i primi vicini ad andarsene da una zona con le finestre rotte? Sono sempre coloro che possono permetterselo facilmente. Di conseguenza, nei progetti software sono spesso gli sviluppatori più qualificati i primi ad andarsene e, sfortunatamente, sono proprio queste le persone di cui hai più bisogno per salvare la situazione, poiché hanno una vasta competenza ed esperienza.
Chiudi gli occhi?
Sembra davvero molto drammatico. Ma questa è la realtà. Ovviamente, puoi chiudere gli occhi e convincerti che tutto è completamente diverso con il tuo progetto. Probabilmente troverai anche numerose argomentazioni sul perché le cose non potrebbero andare diversamente per te. Ma è esattamente così che giustifichi la situazione. Chiudere gli occhi e credere che gli altri non saranno più in grado di vederti è un comportamento che potrebbe avere senso all'asilo, ma che semplicemente non funziona nello sviluppo di software. Trovo scioccante vedere quante aziende scelgano ripetutamente questo stesso approccio.
Ora potresti chiederti come puoi sapere con certezza che alcune finestre del tuo progetto software sono già state danneggiate. Per questo motivo vorrei illustrarvi alcuni segnali tipici. L'elenco non segue un ordine particolare, lo riporto semplicemente così come mi viene in mente.
I segnali di finestre rotte includono tempi di costruzione e distribuzione notevolmente lunghi e potenzialmente crescenti. Anche il codice che contiene sempre più commenti come "TODO" o "FIXME" dovrebbe farti riflettere. Se invece di risolvere completamente i problemi, si ricorre regolarmente a soluzioni alternative e improvvisate, questo è un segnale d'allarme. Se la copertura dei test diminuisce nel tempo, si ripresentano errori già corretti, la documentazione non esiste o è errata o obsoleta, allora questi sono tutti segnali di finestre rotte.
Se ci sono aree del codice che nessuno vuole toccare, se le dipendenze non sono aggiornate, se i ticket per attività tecniche continuano ad accumularsi, sono tutti segnali che qualcosa non va. E tutti questi incidenti sono come gli iceberg: ciò che si vede per primo è sempre solo la punta, e la vera portata resta nascosta. Quindi non sottovalutare la situazione liquidandola come un dettaglio irrilevante. Spesso il problema in realtà è molto più grande di quanto sembri a prima vista.
La prima tipica controargomentazione è:
"Oh, queste sono solo piccole cose!"
Avevo già previsto questa stessa obiezione. Ciò che è interessante, tuttavia, è che tali preoccupazioni sono numerose. È qui che molte aziende cercano di nascondere il problema. E quali sono le obiezioni più comuni?
Ad esempio, molto comune è:
"Sì, è tutto vero in linea di principio, ma non abbiamo tempo. Abbiamo una scadenza da rispettare."
Questa affermazione può essere solitamente ricondotta a due situazioni:
- Innanzitutto, qualcuno potrebbe aver promesso troppo rispetto a quanto invece viene effettivamente consegnato: il reparto Vendite, il reparto Marketing o magari anche il Product Owner. Se nessuno si fosse affrettato a promettere qualcosa che non è ancora stato realizzato, ora non ci sarebbero scadenze così ravvicinate. In questo senso, spesso si tratta di una scusa debole per una pianificazione fallimentare (o addirittura assente). E questa scarsa pianificazione sta ora mettendo a dura prova il team di sviluppo.
- In secondo luogo, potrebbe riguardare le scadenze legali, vale a dire gli adempimenti che devono essere attuati entro una certa data. Questo non rientra necessariamente nella tua sfera di influenza e quindi non è stato realizzato attivamente. Ma anche in questo caso le leggi di solito non cambiano da un giorno all'altro e spesso c'è almeno un certo lasso di tempo in cui, anche se non tutto, molto può essere previsto. Se si disponesse di una base di codice in cui le modifiche potessero essere apportate in modo rapido, semplice e mirato, ci sarebbero meno problemi. Ma se parti del progetto sono marce da anni, se i proverbiali vetri delle finestre sono rotti da secoli, allora sarà semplicemente evidente che questo specifico requisito legale è stato rispettato. Questo crea un problema che è stato ignorato per molto tempo, quindi ora bisogna conviverci.
Costi (presumibilmente) troppo alti
Un'altra controargomentazione comune è:
"Non possiamo permetterci una manutenzione regolare del codice, sarebbe troppo costosa!"
Anche questa tesi non è sostenibile, perché dimostra che il vero problema è iniziato diversi anni fa. La manutenzione del codice è costosa solo se ritardata per troppo tempo. Naturalmente, ci sono ambiti che richiedono più impegno, ma se li affronti tempestivamente fin dall'inizio, i costi saranno molto più bassi rispetto a quando li rimandi ripetutamente, per poi doverli affrontare a un certo punto, nel mezzo di altri compiti urgenti, senza tempo e senza pianificazione.
È paragonabile a una casa che non viene mai riordinata, sempre con la scusa che è troppo faticoso, finché a un certo punto non hai più piatti puliti e la casa si riempie di spazzatura, tanto che inciampi, cadi e ti fai male. Proprio in quel momento ti rendi conto che è appena scoppiato un incendio in cucina perché una pentola è stata lasciata incustodita sul fornello. E la cosa diventa molto costosa e potrebbe addirittura richiedere una ristrutturazione. Quindi il piano "ripulire subito è troppo faticoso" aveva davvero senso? Assolutamente no.
Non toccare mai un sistema in esecuzione
Si sostiene spesso anche:
"Nel complesso tutto funziona bene: interveniamo non appena qualcosa si rompe."
Questo concetto viene spesso sottolineato con la frase "Non toccare mai un sistema in funzione". Naturalmente, non dovresti modificare il codice funzionante senza una ragione specifica. Ma non si tratta solo di "smanettare", si tratta di saldare il debito tecnico esistente per evitare danni a lungo termine. Spesso questa obiezione è dovuta semplicemente al timore che durante i lavori di ristrutturazione si possa rompere qualcosa. E questa paura è, in una certa misura, giustificata. Ma da dove viene? È perché i test automatizzati sono troppo pochi? O forse nessuna? Non esiste un concetto di test strutturato?
In un simile contesto, nessuno rischierebbe di apportare modifiche inutili. Tuttavia, dovrebbe essere normale rivedere, rielaborare e adattare il codice. L'unico modo per garantire che nulla si rompa è effettuare test approfonditi, preferibilmente automatizzati, in modo che possano essere ripetuti in modo efficiente in qualsiasi momento. Il fatto che molti progetti ne facciano ampiamente a meno è spesso dovuto al fatto che qualcuno ha pensato che i test fossero troppo complessi e quindi non così importanti.
pressione del dipartimento
Un altro argomento comune è che il dipartimento esercita troppa pressione. Nella maggior parte dei casi si tratta semplicemente di aspettative irrealistiche, unite a una scarsa comprensione dei processi coinvolti nello sviluppo del software. In linea di principio è comprensibile: dopotutto, come potrebbe un reparto senza esperienza tecnica precedente saperlo? Spesso manca una persona che rappresenti adeguatamente gli interessi dello sviluppo e spieghi come funziona lo sviluppo del software.
Questo effetto è particolarmente evidente nelle aziende il cui core business non è lo sviluppo di software in sé, bensì nelle compagnie assicurative, nelle imprese edili, nel commercio al dettaglio e così via, dove il software è solo uno strumento necessario ma impopolare. In questo caso, di solito si applica il principio "le vendite precedono il principio". Spesso prevale il reparto specializzato, lasciando fuori lo sviluppo del software e i suoi standard qualitativi. Se questo non viene comunicato in modo chiaro, da questa parte si svilupperà una pressione enorme.
Pensiero a breve termine contro pensiero a lungo termine
L'elenco potrebbe continuare all'infinito, ma credo che qui emerga già uno schema. La tendenza è che troppo spesso le considerazioni a breve termine prevalgono su quelle a lungo termine. Troppo spesso ci si concentra sul completamento rapido ed economico, senza considerare la stabilità e la manutenibilità a lungo termine. Questo problema non si presenta gradualmente, ma solitamente si presenta fin dal primo giorno di un progetto software, anche se inizialmente passa inosservato.
Ogni passo che non tiene conto dello sviluppo futuro porta nella direzione sbagliata. Ciò comporta inevitabilmente la rottura delle finestre. Quando le cose si mettono davvero male, nessuno vuole fare brusca inversione a U, perché fino a ieri sembrava che tutto andasse bene. Quindi la procrastinazione continua e il problema peggiora ulteriormente. Solo quando diventa ovvio che le cose non possono continuare così, ecco che arrivano le grandi lamentele e la speranza di trovare una soluzione semplice. Ma una cosa del genere non esiste e, comprensibilmente, nessuno vuole sentirselo dire.
Un'impostazione di progetto molto rigorosa
Quale lezione possiamo imparare da tutto questo?
Innanzitutto, se sei abbastanza prematuro e il tuo progetto sta ancora partendo da zero, dovresti adottare un approccio di vera tolleranza zero alla qualità del codice fin dal primo giorno. Ciò significa che è necessaria un'impostazione del progetto estremamente rigorosa. Tra questi rientrano, ad esempio, regole di linter configurate in modo rigoroso, formattazione automatizzata, test appropriati e una pipeline CI/CD. Non si dovrebbero accettare avvisi provenienti dal linter o dal compilatore: o il codice è completamente privo di errori o la compilazione fallisce. Non c'è nulla in mezzo.
Allo stesso modo, il refactoring continuo dovrebbe essere una priorità elevata e gli errori dovrebbero essere corretti immediatamente. Naturalmente, non esisterà mai un software completamente privo di errori, ma una volta individuato un errore, la priorità assoluta è risolverlo. Finché questo bug non verrà corretto, non verrà sviluppata alcuna nuova funzionalità, nel rispetto del principio di "tolleranza zero".
Se ora qualcuno sostiene che questa è una licenza per lo sviluppo di perdersi nei dettagli, il vero problema non è la strategia di tolleranza zero, ma una radicata sfiducia nel senso di responsabilità degli sviluppatori. Si tratta di un problema molto più profondo che spesso viene ignorato perché sembra molto più facile combattere i sintomi che le cause.
Automatizzare tutto ciò che è possibile
In secondo luogo, dovresti automatizzare tutto il possibile: test, distribuzioni, aggiornamenti e così via. In definitiva, qui tutto è interconnesso. Immagina che appaia un aggiornamento per una dipendenza: per prima cosa, dovresti sapere che questo aggiornamento esiste. Quindi dovresti testarlo, controllare che tutto funzioni ancora, creare un ramo, inviarlo, inviarlo, creare una richiesta pull e trovare qualcuno che lo esamini e lo rilasci. Naturalmente nessuno vorrebbe prendersi questa briga regolarmente.
Tuttavia, se un bot invia automaticamente una richiesta pull, che poi avvia una pipeline CI/CD ed esegue tutti i test, vieni informato dei risultati e la tua unica azione (almeno nel 95 percento dei casi) è quella di approvare la richiesta pull riuscita, quindi il tuo investimento di tempo rimane minimo. Allo stesso tempo, le tue dipendenze rimangono aggiornate e ora hai il tempo di occuparti di quel 5 percento che richiede effettivamente un intervento manuale, ad esempio a causa di modifiche che interrompono il processo. Tuttavia, questo funziona solo se hai automatizzato i processi rilevanti di conseguenza.
revisioni del codice e programmazione in coppia
Questo mi porta all'ultimo punto che vorrei condividere con voi oggi: le revisioni del codice e il principio dei quattro occhi dal primo giorno. Questo è l'unico modo per garantire che ogni modifica venga verificata e che non vi siano conoscenze isolate. Dopo una revisione, almeno due persone hanno esaminato il codice e se ne sono occupate. In alternativa, è possibile ricorrere alla programmazione in coppia, che consiste sostanzialmente in una semplice revisione dal vivo. Probabilmente hai già sentito dire che sarebbe troppo costoso e che non ci sarebbe tempo a causa di scadenze, dipartimenti e così via. Ma forse questo post del blog ti fornirà qualche argomentazione per aiutarti ad affrontare tutto questo con maggiore sicurezza in futuro.
In conclusione, una manutenzione permanente e regolare del codice porta a progetti molto più stabili e quindi più economici nel lungo termine, anche se a prima vista può sembrare controintuitivo.
da