Refactoring a basso impatto e pulizia del codice del codice sciatto in attesa di requisiti


17

Ho ereditato una base di codice esistente per un prodotto che è riprovevolmente sciatto. Il design fondamentale è tristemente inadeguato, che sfortunatamente posso fare poco senza un refactor completo (accoppiamento HIGH, LOW coesione, duplicazione dilagante di codice, nessuna documentazione tecnica di progettazione, test di integrazione anziché test unitari). Il prodotto ha una storia, un'elevata esposizione ai clienti critici "cash-cow" con una tolleranza minima per il rischio, un debito tecnico che farà arrossire i greci, una base di codice MOLTO grande e complessità, e un approccio disfattista stanco della battaglia contro i bug da parte del team prima me.

Il vecchio team ha portato la nave in un'altra divisione in modo da avere l'opportunità di rovinare un altro progetto. È molto raro che si verifichi un fallimento del progetto di incompatibilità tecnica anziché un errore di gestione del progetto, ma questo è davvero uno di quei casi.

Per il momento sono da solo, ma ho molto tempo, libertà di decisione e direzione futura e la capacità di creare una squadra da zero per aiutarmi.

La mia domanda è quella di raccogliere opinioni sul refactoring a basso impatto su un progetto come questo quando hai del tempo libero durante la fase di raccolta dei requisiti funzionali. Esistono migliaia di avvisi del compilatore, quasi tutti importazioni non utilizzate, variabili locali non lette, assenza di verifica del tipo e cast non sicuri. La formattazione del codice è così illeggibile e sciatta che sembra che il programmatore abbia sofferto della malattia di Parkinson e non possa controllare il numero di volte in cui la barra spaziatrice è stata premuta su una determinata riga. Ulteriori risorse di database e file vengono in genere aperte e mai chiuse in modo sicuro. Argomenti del metodo inutili, metodi duplicati che fanno la stessa cosa, ecc.

Mentre aspetto i requisiti per la prossima funzione, mentre pulisco pulisco cose a basso impatto ea basso rischio e mi chiedo se sto perdendo tempo o facendo la cosa giusta. Cosa succede se la nuova funzionalità significa strappare il codice che ho trascorso tempo prima? Ho intenzione di iniziare un approccio Agile e capisco che questo è accettabile e normale refactificare costantemente durante lo sviluppo Agile.

Riesci a pensare a eventuali impatti positivi o negativi del mio fare ciò che vorresti aggiungere?


1
Salvare ciò che vale la pena salvare, riscrivere il resto ...
SF.

"È molto raro sperimentare un fallimento del progetto di incompatibilità tecnica anziché un fallimento della gestione del progetto [...]" Quanto è vero, +1.
Gregory Higley,

Risposte:


22

In primo luogo, vorrei sottolineare che i test unitari non sostituiscono i test di integrazione. I due devono esistere fianco a fianco. Sii grato di avere dei test di integrazione, altrimenti uno dei tuoi piccoli refactoring potrebbe far diventare balistiche una delle vacche in contanti a bassa tolleranza.

Vorrei iniziare a lavorare sugli avvisi del compilatore, sulle variabili e sulle importazioni inutilizzate. Ottieni prima una build pulita. Quindi iniziare a scrivere unit test per documentare il comportamento attuale, quindi avviare il refactoring reale.

Non riesco davvero a vedere alcun impatto negativo. Acquisirai molta conoscenza approfondita della base di codice, che ti aiuterà con i refactoring più grandi. È quasi sempre preferibile effettuare il refactoring piuttosto che riscriverlo, poiché durante il refactoring hai ancora un prodotto funzionante, mentre durante la riscrittura non lo fai. E alla fine le vendite del prodotto devono pagare il tuo stipendio.

Una volta che i requisiti stanno iniziando a venire, userei quello che chiamo l'approccio riflettore. Fai la solita cosa agile (dai la priorità, quindi taglia una piccola lastra per un'iterazione e risolvi il problema) e lascia un bel po 'di tempo per i miglioramenti del codice. Quindi rifletti dove stai lavorando comunque. Nel tempo questo coprirà vaste aree della base di codice senza che tu debba mai avventurarti in aree in cui avresti difficoltà a giustificare al management perché stai lavorando su quella parte del codice.


Mi piace molto questa risposta. Ho bisogno di una comprensione più approfondita della base di codice e le vacche in contanti pagano il mio stipendio e ci consentono anche di lavorare su nuovi progetti migliori per altri clienti in cui ho l'opportunità di iniziare da zero e farlo fin dall'inizio.
maple_shaft

10

Scrivere unit test potrebbe essere un uso più prezioso del tuo tempo: ti fornirà alcune intuizioni sul funzionamento corrente della base di codice e se dovessi decidere di iniziare da quello che hai piuttosto che riscrivere tutto da zero, avrai una solida base per apportare modifiche senza correre troppi rischi. È probabile che scrivendo unit test, anche tu modifichi la base di codice solo per renderlo in una forma verificabile; quelli sono buoni, perché l'unità testabile di solito significa anche modulare, incapsulato e per lo più indipendente dallo stato esterno. E, soprattutto, test unitari ben scritti sono una documentazione tecnica inestimabile. Con i test unitari in atto, sarai in grado di giudicare ciò che l'attuale base di codice può e non può fare, piuttosto che fare ipotesi selvagge o riscrivere le cose per ogni evenienza.


2
Iniziare con quelli facili e poi risalire?
martedì

2
Questo è sempre il problema nella mia esperienza - codice come questo non è mai stato scritto per consentire i test e finirai per dover fare enormi refactoring se non addirittura riscrivere il codice per consentire anche i test unitari in primo luogo.
Wayne Molina,

2
Se il codice non è stato progettato per i test, questo è un motivo in più per superarlo, ma in sicurezza. Leggi il libro di Michael Feathers "Lavorare efficacemente con il codice legacy"; ha ricette per rendere testabile il codice non testabile.
Joe White,

1
Sono d'accordo; dichiarando semplicemente la mia esperienza quando non ci sono test, dovresti iniziare un enorme refactoring per renderlo pronto per i test in primo luogo, il che porta a più refactoring "sprecato", il che rende più difficile scrivere test, che quindi rende molto più difficile il refactoring di qualcosa.
Wayne Molina,

1
Ci vuole esperienza e buon senso. Non tutto può (o dovrebbe) essere reso unitamente testabile.
martedì

1

Miscele di risposte - il mio pensiero sarebbe quello di fondere test e pulizia - forse 50/50? Se lavori in un'area facendo un tipo di approccio TDD - imposta i test devi sapere che l'unità e i test di integrazione sono come desideri e quindi iniziare a riparare. Andare avanti come il tempo lo permette.

Probabilmente significa che non farai altrettanto progressi, ma significa che avrai almeno una base di codice ben stabile in alcune aree e avrai una buona base di partenza.

Inizialmente la mia reazione istintiva è stata "può davvero far male ripulire il codice non funzionante?" (ovvero errori del compilatore), ma poi mi sono ricordato delle volte in cui la risoluzione del problema ha effettivamente interrotto la funzionalità in alcuni casi davvero strani perché, invece di morire un thread, ha lasciato la memoria in posti cattivi - essenzialmente una brutta pausa nascondeva un errore ancora peggiore. Può letteralmente essere una scatola di Pandora di spiacevoli sorprese.

Dato che lo stai facendo mentre aspetti più requisiti, penso che qualsiasi cosa tu possa diagnosticare il caos aumenterà notevolmente la tua sanità mentale a lungo termine.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.