Confronto

Riscrivere Software da Zero: Quando Ha Senso e Quando No

Quando riscrivere software da zero ha senso e quando il refactoring incrementale è la scelta migliore. Criteri pratici per CTO e founder tecnici.

Albero decisionale per la scelta tra refactoring e riscrittura completa del software

In questo articolo:

“Riscriviamo tutto da zero” è una frase che molti sviluppatori e CTO pronunciano almeno una volta nella carriera. A volte è la scelta giusta. Spesso non lo è. Riscrivere software da zero è una delle decisioni più costose e rischiose nel ciclo di vita di un prodotto: richiede mesi di sviluppo senza rilascio di nuovo valore, introduce nuovi bug mentre si riscrivono funzionalità esistenti e mette a rischio la conoscenza del dominio accumulata nel codice esistente. In questo articolo analizziamo quando la riscrittura è giustificata e quando il refactoring incrementale è la strada corretta.

Il mito della riscrittura come soluzione

Netscape decise di riscrivere il proprio browser da zero nel 2000. Il progetto impiegò tre anni, durante i quali Mozilla non rilasciò una versione competitiva. Nel frattempo, Internet Explorer consolidò la propria posizione dominante. Joel Spolsky scrisse all’epoca un articolo rimasto famoso: “Things You Should Never Do”. Il messaggio era chiaro: il codice esistente, per quanto brutto, contiene anni di bugfix e conoscenza del dominio che non è visibile a prima vista.

Il problema con il codice legacy non è che è scritto male. Il problema è che è difficile da capire, da modificare e da testare. Questi sono problemi risolvibili con il refactoring. La riscrittura completa risolve il problema della leggibilità, ma introduce tutti i problemi che il codice esistente aveva risolto nel corso degli anni, spesso in silenzio.

Il bias cognitivo che spinge verso la riscrittura è il “not invented here”: il codice scritto da altri sembra sempre peggio di quello che potremmo scrivere noi oggi. Ma “oggi” non incorpora ancora i casi limite, i requisiti impliciti e le correzioni silenti che il codice precedente ha accumulato in anni di produzione.

Refactoring vs riscrittura software: le differenze operative

Refactoring vs riscrittura software non è solo una questione tecnica. È una questione di gestione del rischio e di continuità del servizio.

Il refactoring è un insieme di trasformazioni che migliorano la struttura interna del codice senza cambiarne il comportamento esterno. È incrementale, verificabile e reversibile. Ogni step di refactoring può essere fatto in parallelo con lo sviluppo di nuove feature. Il sistema rimane in produzione durante tutto il processo. I test esistenti (o quelli scritti prima del refactoring) garantiscono che il comportamento non sia cambiato.

La riscrittura è un progetto separato che porta alla costruzione di un sistema parallelo. Per tutta la durata del progetto, esistono due versioni del software: quella in produzione che riceve bugfix e quella nuova che non è ancora pronta. Questo ha un costo immediato: il team deve mantenere due codebase contemporaneamente. Quando la nuova versione è finalmente pronta, il rischio di regressioni è elevato perché la verifica dell’equivalenza funzionale è difficile senza una suite di test esaustiva.

In termini di tempi, il refactoring incrementale distribuisce il costo su mesi con valore continuo. La riscrittura concentra il costo in un periodo lungo con valore zero fino al rilascio.

Quando riscrivere il software ha davvero senso

Esistono scenari in cui riscrivere software da zero è la scelta corretta. Il primo è quando il cambio tecnologico è obbligatorio e la migrazione non è praticabile in modo incrementale. Un sistema scritto in un linguaggio che non ha più supporto, su un runtime che non può essere aggiornato, o su un’architettura hardware che viene dismessa, può richiedere una riscrittura completa.

Il secondo scenario è quando il codice è talmente degradato che il costo di comprensione supera il costo di riscrittura. Questo accade raramente, ma accade. Se un modulo critico non ha test, non ha documentazione, il suo autore originale ha lasciato l’azienda da anni e nessuno nel team è in grado di spiegare cosa fa esattamente, il refactoring diventa più rischioso della riscrittura.

Il terzo scenario è un cambio radicale di dominio o di modello di business. Se il prodotto deve cambiare in modo così profondo che il 90% del codice esistente non sarà più utilizzabile, costruire il nuovo sistema da zero è più efficiente che adattare il vecchio.

In tutti gli altri casi, il refactoring incrementale è preferibile.

Debito tecnico startup: il caso specifico

Il debito tecnico startup ha caratteristiche diverse rispetto al debito tecnico di un’azienda consolidata. Nelle startup, il debito tecnico è spesso una scelta esplicita: si sacrifica la qualità per andare veloci, nella consapevolezza che si ripagherà il debito quando il prodotto avrà trovato il suo mercato.

Il problema emerge quando la startup cresce e il debito non viene ripagato. Il codice scritto per il prototipo diventa la base dell’infrastruttura di produzione. I workaround diventano feature. Le assunzioni implicite si moltiplicano.

In questo contesto, la riscrittura è particolarmente rischiosa perché le startup hanno risorse limitate. Sei mesi di sviluppo senza rilascio di nuove feature può essere fatale. La strategia corretta per una startup con debito tecnico elevato è il refactoring incrementale guidato dal business: si parte dalle aree del codice che bloccano le feature di maggior valore, non da quelle che sembrano più brutte.

Per una valutazione del debito tecnico del tuo sistema, consulta il nostro servizio di Tech Debt Solution.

Come decidere: i criteri concreti

Decidere tra refactoring e riscrittura richiede di rispondere a quattro domande concrete.

Prima: il sistema è comprensibile? Se nessuno nel team è in grado di spiegare il comportamento di un modulo critico senza leggere il codice riga per riga, il costo di refactoring è molto alto.

Seconda: esistono test sufficienti? Il refactoring senza test è cieco. Se la copertura è inferiore al 30% sulle aree critiche, il refactoring deve iniziare con la scrittura dei test, non con la modifica del codice.

Terza: il cambio tecnologico richiesto è compatibile con l’evoluzione incrementale? Passare da PHP 5 a PHP 8 è un’evoluzione incrementale. Passare da un sistema batch monolitico a un’architettura event-driven non lo è.

Quarta: il team ha la bandwidth per gestire una riscrittura? Una riscrittura ben gestita richiede almeno il doppio delle risorse per un periodo prolungato. Se il team non ha questa capacità, la riscrittura si trasformerà in un progetto che non finisce mai.

Se la risposta a tre di queste domande è sfavorevole alla riscrittura, il refactoring incrementale è la strada corretta. Se tutte e quattro puntano verso la riscrittura, allora è il momento di pianificarla con attenzione.

Conclusione

Riscrivere software da zero è una decisione che va presa con dati alla mano, non con frustrazione davanti a un codebase difficile. Nella maggior parte dei casi, il refactoring incrementale permette di migliorare la qualità del sistema in modo controllato, mantenendo il servizio attivo e il team produttivo. La riscrittura ha il suo posto, ma richiede condizioni specifiche e una pianificazione rigorosa. La prima domanda non è “riscriviamo?”, ma “abbiamo i dati per giustificarlo?”

Hai un codebase con questi problemi? Parliamo del tuo sistema