Devo refactificare il codice contrassegnato come "non modificare"?


148

Ho a che fare con una base di codice piuttosto grande e mi è stato dato qualche mese per refactoring il codice esistente. Il processo di refactor è necessario perché presto dovremo aggiungere molte nuove funzionalità al nostro prodotto e per ora non siamo più in grado di aggiungere alcuna funzionalità senza interrompere qualcos'altro. In breve: codice disordinato, enorme, difettoso, che molti di noi hanno visto nelle loro carriere.

Durante il refactoring, di tanto in tanto incontro la classe, il metodo o le righe di codice che hanno commenti simili

Timeout impostato per dare al Modulo A un po 'di tempo per fare cose. Se non è temporizzato in questo modo, si romperà.

o

Non cambiare questo. Fidati di me, spezzerai le cose.

o

So che usare setTimeout non è una buona pratica, ma in questo caso ho dovuto usarlo

La mia domanda è: devo refactificare il codice quando incontro tali avvertimenti da parte degli autori (no, non riesco a mettermi in contatto con gli autori)?


157
Congratulazioni! Ora sei l'autore del codice.

12
Non puoi risolverlo fino a quando non sai sia cosa dovrebbe fare e cosa fa effettivamente (devi conoscere quest'ultimo per capire le conseguenze complete delle tue modifiche.) Il problema sembra essere in sincronizzazione e rimuovere tali problemi dovrebbe essere il refactoring del lavoro n. 1, altrimenti le cose peggioreranno ad ogni cambiamento. La domanda che dovresti porre è come farlo. C'è una buona dose di dipendenza dalla lingua e dalla piattaforma in questa domanda. ad es . :
stackoverflow.com/questions/3099794/finding-threading-bugs

14
In seguito al commento di @sdenham: se non disponi già di unit test automatici che esercitano la tua base di codice, ti suggerisco di dedicare il tuo tempo a creare tali test unitari, invece di perdere tempo in una "caccia alle streghe refactoring" con AFAICT senza obiettivi chiari in mente. Una volta che hai una serie di unit test che esercitano a fondo la tua base di codice, avrai un modo oggettivo di sapere se il tuo codice funziona ancora se / quando devi riscriverne dei bit. Buona fortuna.
Bob Jarvis,

17
Se gli autori sono così paranoici che il codice si interromperà se qualcuno respira così vicino, probabilmente è già rotto e il comportamento indefinito sembra funzionare nel modo in cui lo desiderano al momento. Quella prima in particolare suona come se avessero una condizione di razza che loro avessero maltrattato, quindi funziona quasi sempre. sdenham ha ragione. Scopri cosa dovrebbe fare e non dare per scontato che sia quello che fa realmente.
Ray

7
@Ethan Potrebbe non essere così semplice. La modifica del codice può interromperlo in modi che non sono immediatamente evidenti. A volte si rompe molto tempo dopo aver dimenticato che questo attuale refattore potrebbe averlo causato, quindi tutto ciò che hai è un "nuovo" bug con una causa misteriosa. Ciò è particolarmente probabile quando è legato al tempismo.
Paul Brinkley,

Risposte:


225

Sembra che tu stia eseguendo il refactoring "per ogni evenienza", senza sapere esattamente quali parti del codebase in dettaglio verranno modificate quando avrà luogo lo sviluppo della nuova funzionalità. Altrimenti, sapresti se è davvero necessario riformattare i moduli fragili o se puoi lasciarli così come sono.

Per dirlo chiaramente: penso che questa sia una strategia di refactoring destinata a fallire . Stai investendo tempo e denaro della tua azienda per qualcosa in cui nessuno sa se restituirà davvero un vantaggio e stai per peggiorare le cose introducendo bug nel codice funzionante.

Ecco una strategia migliore: usa il tuo tempo per

  • aggiungere test automatici (probabilmente non unit test, ma test di integrazione) ai moduli a rischio. Soprattutto quei fragili moduli che hai citato avranno bisogno di una suite di test completa prima di cambiare qualcosa.

  • rifattorizzare solo i bit necessari per mettere in atto i test. Cerca di ridurre al minimo le modifiche necessarie. L'unica eccezione è quando i tuoi test rivelano bug, quindi correggili immediatamente (e rifletti nella misura in cui devi farlo in modo sicuro).

  • insegnare ai tuoi colleghi il "principio del boy scout" (AKA "refactoring opportunistico" ), quindi quando il team inizia ad aggiungere nuove funzionalità (o per correggere bug), dovrebbero migliorare e riformattare esattamente le parti della base di codice che devono cambiare, non meno, non di più.

  • ottenere una copia del libro di Feather "Lavorare efficacemente con il codice legacy" per il team.

Quindi, quando arriva il momento in cui si sa per certo che è necessario modificare e riformattare i moduli fragili (o a causa dello sviluppo di nuove funzionalità o perché i test aggiunti nel passaggio 1 rivelano alcuni bug), allora tu e il tuo team siete pronti a rifattorizzare i moduli e ignorare più o meno in modo sicuro quei commenti di avviso.

Come risposta ad alcuni commenti : ad essere onesti, se si sospetta che un modulo in un prodotto esistente sia la causa di problemi su base regolare, in particolare un modulo contrassegnato come "non toccare", sono d'accordo con tutti i voi. Dovrebbe essere rivisto, debug e molto probabilmente refactored in quel processo (con il supporto dei test che ho citato, e non necessariamente in questo ordine). I bug sono una forte giustificazione per il cambiamento, spesso più forte delle nuove funzionalità. Tuttavia, questa è una decisione caso per caso. Bisogna controllare attentamente se vale davvero la pena cambiare qualcosa in un modulo che è stato contrassegnato come "non toccare".


70
Sono tentato di sottovalutare, ma mi trattengo. Ho visto questa mentalità su più progetti portare a un prodotto molto peggio. Una volta che si verificano i guasti, sono spesso catastrofici e molto più difficili da risolvere a causa della loro presenza. Riparo regolarmente i fanghi che vedo e sembra che nella peggiore delle ipotesi causi quanti problemi risolve o nella migliore delle ipotesi non lascia problemi noti; è nel complesso un vantaggio enorme. E il codice è quindi migliore per lo sviluppo futuro. Un punto nel tempo salva nove, ma un problema ignorato può peggiorare.
Aaron,

98
Direi che qualsiasi codice contrassegnato con un commento "Timeout impostato per dare al Modulo A un po 'di tempo per fare cose. Se non è cronometrato in questo modo, si romperà" ha già un bug. È solo per fortuna che il bug non viene colpito.
17 del 26

10
@ 17of26: non necessariamente un bug. A volte, quando lavori con librerie di terze parti, sei costretto a fare tutti i tipi di concessioni di "eleganza" nell'obiettivo di farlo funzionare.
whatsisname

30
@ 17of26: se si sospetta che un modulo in gioco abbia dei bug, aggiungere test prima che qualsiasi tipo di refactoring sia ancora più importante. E quando quei test rivelano il bug, allora hai bisogno di cambiare quel modulo, e quindi una legittimazione a riformattarlo immediatamente. Se i test non rivelano alcun bug, meglio lasciare il codice così com'è.
Doc Brown,

17
@Aaron: non capisco perché pensi che aggiungere test o seguire il principio boy scout di conseguenza ridurrebbe la qualità del prodotto.
Doc Brown,

142

Sì, devi refactificare il codice prima di aggiungere le altre funzionalità.

Il problema con commenti come questi è che dipendono da particolari circostanze dell'ambiente in cui è in esecuzione la base di codice. Il timeout programmato in un punto specifico potrebbe essere stato veramente necessario al momento della programmazione.

Ma ci sono molte cose che potrebbero cambiare questa equazione: modifiche hardware, modifiche del sistema operativo, modifiche non correlate in un altro componente del sistema, modifiche nei volumi di dati tipici, il nome. Non vi è alcuna garanzia che al giorno d'oggi sia ancora necessario, o che sia ancora sufficiente (l'integrità della cosa che avrebbe dovuto proteggere potrebbe essere stata interrotta per lungo tempo - senza adeguati test di regressione non si potrebbe mai notare). Ecco perché programmare un ritardo fisso per consentire la chiusura di un altro componente è quasi sempre errato e funziona solo accidentalmente.

Nel tuo caso, non conosci le circostanze originali e non puoi nemmeno chiedere agli autori originali. (Presumibilmente anche tu non hai i test di regressione / integrazione adeguati, o potresti semplicemente andare avanti e lasciare che i tuoi test ti dicano se hai rotto qualcosa.)

Questo potrebbe sembrare un argomento per non cambiare nulla per prudenza; ma tu dici che ci saranno comunque dei cambiamenti importanti, quindi il pericolo di sconvolgere il delicato equilibrio che si raggiungeva in questo punto è già lì. È molto meglio sconvolgere il carrello delle mele ora , quando l'unica cosa che stai facendo è il refactoring ed essere sicuro che se le cose si rompono è stato il refactoring che lo ha causato, piuttosto che aspettare che tu stia facendo ulteriori modifiche contemporaneamente e mai assicurati.


46
La migliore risposta proprio qui; peccato che sia un perdente. La risposta accettata sopra non è un buon consiglio, in particolare l'enfasi sul "condannato". Ho trascorso l'ultimo anno a lavorare sul più grande (~ 10 ^ 6LOC solo per la mia sezione di esso), legacy-est, codice spaventoso che abbia mai visto, e ho l'abitudine di riparare i disastri del treno che vedo quando ho il tempo, anche se non fa parte del componente su cui sto lavorando. In questo modo ho trovato e corretto bug che il team di sviluppo non era nemmeno a conoscenza dell'esistenza (sebbene probabilmente i nostri utenti finali lo fossero). In effetti, mi viene chiesto di farlo. Il prodotto è migliorato di conseguenza.
Aaron,

10
Non lo definirei refactoring, ma correzione di bug, comunque.
Paŭlo Ebermann,

7
Migliorare la progettazione di una base di codice è refactoring. Se la riprogettazione rivela bug che possono essere corretti, questo è un bug-fixing. Il mio punto è che il primo porta spesso al secondo e che il secondo è spesso molto difficile senza il primo.
Kramii,

10
@Aaron sei fortunato ad avere il supporto della direzione / sviluppatore nel farlo. Nella maggior parte degli ambienti, i bug noti e sconosciuti causati da un design e un codice inadeguati sono accettati come ordine naturale delle cose.
Rudolf Olah,

5
@nocomprende Direi che se non capisci il sistema abbastanza bene da scrivere alcuni test, non puoi cambiare il modo in cui funziona.
Patrick M,

61

La mia domanda è: dovrei refactificare il codice quando incontro tali avvertimenti da parte degli autori

No, o almeno non ancora. Implichi che il livello dei test automatizzati sia molto basso. Hai bisogno di test prima di poter eseguire il refactoring con sicurezza.

per ora non siamo più in grado di aggiungere alcuna funzionalità senza interrompere qualcos'altro

In questo momento è necessario concentrarsi sull'aumento della stabilità, non sul refactoring. Potresti fare il refactoring come parte dell'aumento della stabilità, ma è uno strumento per raggiungere il tuo vero obiettivo: una base di codice stabile.

Sembra che questo sia diventato una base di codice legacy, quindi è necessario trattarlo in modo leggermente diverso.

Inizia aggiungendo test di caratterizzazione. Non preoccuparti di alcuna specifica, basta aggiungere un test che asserisce il comportamento attuale. Ciò contribuirà a impedire che i nuovi lavori interrompano le funzionalità esistenti.

Ogni volta che correggi un bug, aggiungi un caso di prova che dimostri che il bug è stato corretto. Questo impedisce regressioni dirette.

Quando aggiungi una nuova funzionalità, aggiungi almeno alcuni test di base per verificare che la nuova funzionalità funzioni come previsto.

Forse ottenere una copia di "Lavorare efficacemente con il codice legacy"?

Mi sono stati concessi alcuni mesi per il refactoring del codice esistente.

Inizia aumentando la copertura del test. Inizia con le aree che si rompono di più. Inizia con le aree che cambiano di più. Quindi, una volta identificati i progetti errati, sostituirli uno per uno.

Non hai quasi mai uno che fa un enorme refattore, ma invece un flusso costante di piccoli refattori ogni settimana. Un grande refattore ha un rischio enorme di rompere le cose ed è difficile testarlo bene.


10
+1 per l'aggiunta di test di caratterizzazione. È praticamente l'unico modo per ridurre al minimo le regressioni quando si modifica il codice legacy non testato. Se i test iniziano a fallire una volta che si iniziano a apportare modifiche, è possibile verificare se il comportamento precedente era effettivamente corretto date le specifiche o se il nuovo comportamento modificato è corretto.
Leo,

2
Giusto. O se non ci sono specifiche utilizzabili controlla se il comportamento precedente è effettivamente desiderato dalle persone che pagano o hanno un interesse nel software.
bdsl,

Forse ottenere una copia di "Lavorare efficacemente con il codice legacy"? Quante settimane ci vorrà per leggere quel libro? E quando: durante l'orario di lavoro sul posto di lavoro, di notte quando tutti dormono?
Billal Begueradj,

23

Ricorda la recinzione del GK Chesterton : non abbattere una recinzione che ostruisce una strada finché non capisci perché è stata costruita.

Puoi trovare gli autori del codice e i commenti in questione e consultarli per ottenere la comprensione. Puoi esaminare i messaggi di commit, i thread di posta elettronica o i documenti, se presenti. Quindi sarai in grado di refactoring il frammento contrassegnato o annoti la tua conoscenza nei commenti in modo che la persona successiva a mantenere questo codice possa prendere una decisione più informata.

Il tuo obiettivo è quello di capire cosa fa il codice, e perché è stato contrassegnato con un avviso allora, e cosa accadrebbe se l'avviso fosse ignorato.

Prima di allora, non avrei toccato il codice che è contrassegnato come "non toccare".


4
OP dice "no, non riesco a mettermi in contatto con gli autori".
FrustratedWithFormsDesigner,

5
Non riesco a mettermi in contatto con gli autori né c'è documentazione.
Kukis,

21
@kukis: non riesci a contattare gli autori, nessun esperto di dominio e non riesci a trovare e-mail / wiki / documenti / casi di test relativi al codice in questione? Bene, allora è un progetto di ricerca in piena regola nell'archeologia del software, non un semplice compito di refactoring.
9000,

12
Non è insolito che il codice sia vecchio e che gli autori se ne siano andati. Se hanno finito per lavorare per un concorrente, discuterne potrebbe violare la NDA di qualcuno. In alcuni casi gli autori sono permanentemente non disponibili: non puoi chiedere a Phil Katz di PKzip perché è morto anni fa.
pjc50,

2
Se sostituisci "trovare l'autore" con "capire quale problema ha risolto il codice", questa è la risposta migliore. A volte questi frammenti di codice sono la soluzione meno orribile ai bug che hanno impiegato settimane o mesi di lavoro per trovare e rintracciare e gestire, spesso bug che i normali tipi di test unitari non riescono a trovare. (Anche se a volte sono il risultato di programmatori che non sapevano cosa stavano facendo. Il tuo primo compito è capire quale sia)
Grahamparks,

6

Il codice con commenti come quelli che hai mostrato sarebbe in cima alla mia lista di cose da refactificare se, e solo se ho qualche motivo per farlo . Il punto è che il codice puzza così tanto che lo senti persino attraverso i commenti. È inutile cercare di modificare qualsiasi nuova funzionalità in questo codice, tale codice deve morire non appena deve cambiare.

Si noti inoltre che i commenti non sono affatto utili: forniscono solo un avvertimento e nessun motivo. Sì, sono i segnali di avvertimento intorno a un carro armato di squali. Ma se vuoi fare qualcosa nelle vicinanze, ci sono piccoli punti per provare a nuotare con gli squali. Imho, dovresti prima sbarazzarti di quegli squali.

Detto questo, hai assolutamente bisogno di buoni casi di test prima di poter osare di lavorare su tale codice. Una volta che hai questi casi di test, assicurati di capire ogni piccola parte che stai cambiando, per assicurarti di non cambiare davvero comportamento. Rendi prioritario mantenere tutte le peculiarità comportamentali del codice fino a quando non puoi provare che non hanno alcun effetto. Ricorda, hai a che fare con gli squali - devi stare molto attento.

Quindi, nel caso del timeout: lasciarlo attivo fino a quando non si capisce esattamente cosa sta aspettando il codice, quindi correggere il motivo per cui è stato introdotto il timeout prima di procedere alla rimozione.

Inoltre, assicurati che il tuo capo capisca quale sforzo stai intraprendendo e perché è necessario. E se dicono di no, non farlo. Hai assolutamente bisogno del loro supporto in questo.


1
A volte il codice finisce per essere un pasticcio perché deve funzionare correttamente su campioni di silicio pre-produzione il cui comportamento effettivo non corrisponde alla documentazione. A seconda della natura delle soluzioni alternative, la sostituzione del codice può essere una buona idea se il codice non dovrà mai essere eseguito sui chip con errori, ma cambiare il codice senza il livello di analisi ingegneristica che sarebbe necessario per il nuovo codice non è probabilmente un buon idea.
supercat

@supercat Uno dei miei punti era che il refactoring doveva preservare perfettamente il comportamento. Se non preserva il comportamento, è più che un refactoring nel mio libro (ed è estremamente pericoloso quando si tratta di tale codice legacy).
cmaster

5

Probabilmente non è una buona idea refactificare il codice con tali avvisi, se le cose funzionano bene così come sono.

Ma se devi refactoring ...

Per prima cosa, scrivi alcuni test unitari e test di integrazione per verificare le condizioni che ti avvisano gli avvisi. Cerca di imitare il più possibile condizioni simili alla produzione . Ciò significa eseguire il mirroring del database di produzione su un server di prova, eseguire gli stessi altri servizi sulla macchina, ecc ... qualunque cosa tu possa fare. Quindi prova il refactoring (su un ramo isolato, ovviamente). Quindi esegui i test sul nuovo codice per vedere se riesci a ottenere gli stessi risultati dell'originale. Se puoi, probabilmente è OK implementare il refactoring nella produzione. Ma sii pronto a ripristinare le modifiche se le cose vanno male.


5

Dico di andare avanti e cambiarlo. Che ci crediate o no, non tutti i programmatori sono un genio e un avvertimento come questo significa che potrebbe essere un punto di miglioramento. Se scopri che l'autore aveva ragione, potresti (boccheggiare) DOCUMENTO o SPIEGARE il motivo dell'avvertimento.


4

Sto espandendo i miei commenti in una risposta perché penso che alcuni aspetti del problema specifico vengano trascurati o utilizzati per trarre conclusioni errate.

A questo punto, la domanda se refactoring è prematura (anche se probabilmente verrà data risposta da una specifica forma di "sì").

Il problema centrale qui è che (come notato in alcune risposte) i commenti che citate indicano fortemente che il codice ha condizioni di competizione o altri problemi di concorrenza / sincronizzazione, come discusso qui . Questi sono problemi particolarmente difficili, per diversi motivi. In primo luogo, come hai scoperto, modifiche apparentemente non correlate possono innescare il problema (anche altri bug possono avere questo effetto, ma gli errori di concorrenza quasi sempre lo fanno.) In secondo luogo, sono molto difficili da diagnosticare: il bug si manifesta spesso in un luogo che è distante nel tempo o nel codice dalla causa, e qualsiasi cosa tu faccia per diagnosticare potrebbe farla scomparire ( Heisenbugs). In terzo luogo, i test di concorrenza sono molto difficili da trovare nei test. In parte, ciò è dovuto all'esplosione combinatoria: è abbastanza male per il codice sequenziale, ma l'aggiunta dei possibili intrecci dell'esecuzione simultanea lo fa esplodere fino al punto in cui il problema sequenziale diventa insignificante in confronto. Inoltre, anche un buon caso di test può innescare il problema solo occasionalmente - Nancy Leveson ha calcolato che uno dei bug letali nel Therac 25si è verificato in 1 su circa 350 esecuzioni, ma se non si conosce quale sia il bug, o anche se ce n'è uno, non si sa quante ripetizioni rendono un test efficace. Inoltre, su questa scala è possibile solo il test automatico ed è possibile che il test driver imponga vincoli di temporizzazione sottili in modo tale da non innescare mai effettivamente il bug (Heisenbugs di nuovo).

Esistono alcuni strumenti per i test di concorrenza in alcuni ambienti, come Helgrind per il codice che utilizza pthreads POSIX, ma qui non conosciamo i dettagli. I test dovrebbero essere integrati con analisi statiche (o viceversa?), Se ci sono strumenti adatti per il tuo ambiente.

Per aggiungere alla difficoltà, i compilatori (e persino i processori, in fase di runtime) sono spesso liberi di riorganizzare il codice in modi che a volte rendono il ragionamento sulla sicurezza dei thread molto contro-intuitivo (forse il caso più noto è il doppio controllo blocca il linguaggio, sebbene alcuni ambienti (Java, C ++ ...) siano stati modificati per migliorarlo.)

Questo codice può avere un semplice problema che sta causando tutti i sintomi, ma è più probabile che tu abbia un problema sistemico che potrebbe portare i tuoi piani ad aggiungere nuove funzionalità a un arresto. Spero di averti convinto che potresti avere un grave problema tra le mani, forse anche una minaccia esistenziale per il tuo prodotto, e la prima cosa da fare è scoprire cosa sta succedendo. Se ciò rivela problemi di concorrenza, ti consiglio vivamente di risolverli prima di porre la domanda se si debba effettuare un refactoring più generale e prima di provare ad aggiungere altre funzionalità.


1
Dove vedi "condizioni di gara" nei commenti? Dove è anche implicito? Stai facendo moltissime ipotesi tecniche qui senza nemmeno il vantaggio di vedere il codice.
Robert Harvey,

2
@RobertHarvey "Timeout impostato per dare al Modulo A un po 'di tempo per fare cose." - praticamente la definizione di una condizione di gara, e i timeout non sono un modo efficace per gestirli. Non sono il solo a trarre questa inferenza. Se non c'è un problema qui, va bene, ma l'interrogante deve sapere, dato che questi commenti sono bandiere rosse per la sincronizzazione gestita male.
sdenham,

3

Ho a che fare con una base di codice piuttosto grande e mi è stato dato qualche mese per refactoring il codice esistente. Il processo di refactor è necessario perché presto dovremo aggiungere molte nuove funzionalità al nostro prodotto [...]

Durante il refactoring, di tanto in tanto incontro la classe, il metodo o le righe di codice che hanno commenti come ["non toccarlo!"]

Sì, dovresti refactoring specialmente quelle parti . Questi avvertimenti sono stati messi lì dagli autori precedenti per significare "non manomettere pigramente queste cose, è molto intricato e ci sono molte interazioni inaspettate". Poiché la tua azienda prevede di sviluppare ulteriormente il software e aggiungere molte funzionalità, ti hanno incaricato in modo specifico di ripulire queste cose. Quindi non lo manometti pigramente , sei deliberatamente incaricato del compito di ripulirlo.

Scopri cosa stanno facendo quei moduli complicati e suddividili in piccoli problemi (cosa avrebbero dovuto fare gli autori originali). Per ottenere codice manutenibile da un pasticcio, le parti buone devono essere rifattorizzate e le parti cattive devono essere riscritte .


2

Questa domanda è un'altra variante del dibattito su quando / come refattare e / o ripulire il codice con un trattino di "come ereditare il codice". Tutti abbiamo esperienze diverse e lavoriamo in organizzazioni diverse con team e culture diverse, quindi non esiste una risposta giusta o sbagliata tranne "fai quello che pensi di dover fare e fallo in modo da non farti licenziare" .

Non credo che ci siano molte organizzazioni che prenderebbero gentilmente il caso che un processo aziendale cada dalla sua parte perché l'applicazione di supporto necessitava di pulizia o refactoring del codice.

In questo caso specifico, i commenti sul codice stanno sollevando la bandiera che la modifica di queste sezioni di codice non dovrebbe essere eseguita. Quindi, se procedi, e l'azienda cade dalla sua parte, non solo non hai nulla da mostrare per supportare le tue azioni, c'è in realtà un artefatto che funziona contro la tua decisione.

Quindi, come sempre, è necessario procedere con attenzione e apportare modifiche solo dopo aver compreso ogni aspetto di ciò che si sta per cambiare e trovare modi per testarlo, prestando molta attenzione alla capacità, alle prestazioni e ai tempi a causa di i commenti nel codice.

Ma ancora, la tua direzione deve comprendere il rischio inerente a ciò che stai facendo e concordare sul fatto che ciò che stai facendo ha un valore commerciale che supera il rischio e che hai fatto ciò che può essere fatto per mitigarlo.

Ora, torniamo tutti ai nostri TODO e le cose che sappiamo possono essere migliorate nelle nostre creazioni di codice se solo ci fosse più tempo.


1

Si assolutamente. Queste sono chiare indicazioni che la persona che ha scritto questo codice non era soddisfatta del codice e probabilmente l'ha cercato fino a quando non è riuscito a farlo funzionare. È possibile che non capissero quali fossero i veri problemi o, peggio, li capissero ed erano troppo pigri per risolverli.

Tuttavia, è un avvertimento che saranno necessari molti sforzi per risolverli e che tali correzioni avranno dei rischi associati.

Idealmente, sarai in grado di capire quale fosse il problema e risolverlo correttamente. Per esempio:

Timeout impostato per dare al Modulo A un po 'di tempo per fare cose. Se non è temporizzato in questo modo, si romperà.

Ciò suggerisce fortemente che il Modulo A non indica correttamente quando è pronto per essere utilizzato o quando ha terminato l'elaborazione. Forse la persona che ha scritto questo non voleva preoccuparsi di riparare il Modulo A o non poteva per qualche motivo. Sembra un disastro in attesa di accadere perché suggerisce una dipendenza di temporizzazione gestita per fortuna piuttosto che un corretto sequenziamento. Se lo vedessi, vorrei davvero risolverlo.

Non cambiare questo. Fidati di me, spezzerai le cose.

Questo non ti dice molto. Dipenderebbe da cosa stava facendo il codice. Potrebbe significare che ha quelle che sembrano essere ovvie ottimizzazioni che, per un motivo o per l'altro, romperanno il codice. Ad esempio, è possibile che un ciclo lasci una variabile a un determinato valore da cui dipende un altro pezzo di codice. Oppure una variabile potrebbe essere testata in un altro thread e la modifica dell'ordine degli aggiornamenti delle variabili potrebbe interrompere tale altro codice.

So che usare setTimeout non è una buona pratica, ma in questo caso ho dovuto usarlo.

Sembra facile. Dovresti essere in grado di vedere cosa setTimeoutsta facendo e forse trovare un modo migliore per farlo.

Detto questo, se questo tipo di correzioni è al di fuori dell'ambito del tuo refactor, queste sono indicazioni che provare a refactoring all'interno di questo codice può aumentare significativamente l'ambito del tuo sforzo.

Come minimo, guarda attentamente il codice interessato e vedi se riesci almeno a migliorare il commento al punto che spiega più chiaramente qual è il problema. Ciò potrebbe salvare la persona successiva dall'affrontare lo stesso mistero che affronti.


2
È possibile che le condizioni siano cambiate al punto in cui i vecchi problemi non esistono più, e i commenti di avvertimento sono diventati come il posto su vecchie mappe che dicono "Ecco i draghi". Immergiti e scopri qual era la situazione o vedi che è passata alla storia.

2
Nel mondo reale, alcuni dispositivi non forniscono un'indicazione di disponibilità affidabile, ma specificano invece un tempo massimo di non-tempo. Le indicazioni di disponibilità affidabili ed efficienti sono buone, ma a volte si è bloccati nell'utilizzare le cose senza di esse.
supercat

1
@supercat Forse, forse no. Non possiamo dirlo dal commento qui. Quindi vale la pena indagare, se non altro, per migliorare il commento con specifiche.
David Schwartz,

1
@DavidSchwartz: il commento potrebbe sicuramente essere più utile, ma a volte non è chiaro quanto tempo un programmatore dovrebbe impiegare cercando di mappare tutti i modi precisi in cui un dispositivo non riesce a rispettare le sue specifiche, soprattutto se non è chiaro se il problema è previsto essere una cosa temporanea o permanente.
supercat

1

Molto probabilmente l'autore dei commenti non ha compreso appieno il codice . In realtà sapevano cosa stavano facendo, avrebbero scritto commenti davvero utili (o non avevano introdotto le condizioni di gara in primo luogo). Un commento del tipo " Fidati di me, spezzerai le cose " per me indica che l'autore cerca di cambiare qualcosa che ha causato errori imprevisti che non hanno compreso appieno.

Il codice è probabilmente sviluppato attraverso ipotesi e tentativi ed errori senza una piena comprensione di ciò che realmente accade.

Questo significa:

  1. È rischioso cambiare il codice. Ci vorrà del tempo per capire, ovviamente, e probabilmente non segue buoni principi di progettazione e può avere effetti e dipendenze oscuri. Molto probabilmente è insufficientemente testato e se nessuno capisce completamente cosa fa il codice, sarà difficile scrivere test per assicurarsi che non vengano introdotti errori o cambiamenti nel comportamento. Le condizioni di gara (come accennano i commenti) sono particolarmente onerose: questo è un posto dove i test unitari non ti salveranno.

  2. È rischioso non modificare il codice. Il codice ha un'alta probabilità di contenere bug oscuri e condizioni di gara. Se un bug critico viene scoperto nel codice, o una alta priorità forze del cambiamento requisito di business di cambiare questo codice con breve preavviso, ci si trova in profonda difficoltà. Ora hai tutti i problemi descritti in 1, ma sotto la pressione del tempo! Inoltre, tali "aree oscure" nel codice hanno la tendenza a diffondersi e infettare altre parti del codice che tocca.

Un'ulteriore complicazione: i test unitari non ti salveranno . Di solito l'approccio consigliato a tale codice legacy fisso consiste nell'aggiungere prima i test di unità o di integrazione, quindi isolare e refactor. Ma le condizioni di gara non possono essere rilevate da test automatizzati. L'unica soluzione è sedersi e riflettere sul codice fino a quando non lo si capisce, quindi riscrivere per evitare le condizioni di gara.

Ciò significa che l'attività è molto più impegnativa del semplice refactoring di routine. Dovrai programmarlo come un vero compito di sviluppo.

Potresti essere in grado di incapsulare il codice interessato come parte del refactoring regolare, quindi almeno il codice pericoloso è isolato.


-1

La domanda che vorrei porre è perché qualcuno ha scritto, NON MODIFICARE in primo luogo.

Ho lavorato su un sacco di codice e in parte è brutto e ci sono voluti molto tempo e sforzi per farlo funzionare, entro i limiti indicati in quel momento.

Scommetto che in questo caso è successo e la persona che ha scritto il commento ha scoperto che qualcuno lo ha cambiato e quindi ha dovuto ripetere l'intero esercizio e rimetterlo a suo modo, per far funzionare la cosa. Dopo questo, per frustrazione di taglio, hanno scritto ... NON MODIFICARE.

In altre parole, non voglio ripararlo di nuovo perché ho cose migliori da fare con la mia vita.

Dicendo DO NOT EDIT, è un modo per dire che sappiamo tutto ciò che avremo mai saputo in questo momento e quindi in futuro non impareremo mai nulla di nuovo.

Dovrebbe esserci almeno un commento sui motivi della mancata modifica. Come dire "Non toccare" o "Non entrare". Perché non toccare la recinzione? Perché non entrare? Non sarebbe meglio dire "Recinto elettrico, non toccare!" o "Miniere di terra! Non entrare!". Quindi è ovvio il perché, eppure puoi ancora entrare, ma almeno conosci le conseguenze prima di farlo.

Scommetto anche che il sistema non ha test intorno a questo codice magico e quindi nessuno può confermare che il codice funzionerà correttamente dopo qualsiasi modifica. Posizionare i test di caratterizzazione attorno al codice problema è sempre un primo passo. Vedi "Lavorare con il codice legacy" di Michael Feathers per suggerimenti su come rompere le dipendenze e ottenere il codice sotto test, prima di affrontare la modifica del codice.

Penso che alla fine sia miope mettere delle restrizioni al refactoring e lasciare che il prodotto si evolva in modo naturale e organico.


2
questo non sembra offrire nulla di sostanziale rispetto ai punti formulati e spiegati nelle precedenti risposte 9
moscerino del
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.