Manutenzione del codice: mantenere un modello errato quando si estende il nuovo codice per renderlo coerente o no?


45

Devo estendere un modulo esistente di un progetto. Non mi piace il modo in cui è stato fatto (un sacco di anti-pattern coinvolti, come il codice copia / incollato). Non voglio eseguire un refactor completo per molte ragioni.

Dovrei:

  • creare nuovi metodi usando le convenzioni esistenti, anche se mi sembra sbagliato, per evitare confusione per il manutentore successivo ed essere coerenti con la base di codice?

o

  • provare a usare ciò che mi sento meglio anche se introduce un altro modello nel codice?

Precison modificato dopo le prime risposte:

Il codice esistente non è un disastro. È facile da seguire e capire. MA sta introducendo un sacco di codice del boilerplate che può essere evitato con un buon design (il codice risultante potrebbe diventare più difficile da seguire). Nel mio caso attuale è un buon vecchio modulo DAO JDBC (modello primavera incorporato), ma ho già riscontrato questo dilemma e sto cercando altri feedback degli sviluppatori.

Non voglio refactoring perché non ho tempo. E anche con il tempo sarà difficile giustificare la necessità di rifattorizzare un intero modulo perfettamente funzionante. I costi di refactoring saranno più pesanti dei suoi benefici. Ricorda: il codice non è disordinato o troppo complesso. Non posso estrarre pochi metodi lì e introdurre qui una classe astratta. È più un difetto nel design (risultato dell'estrema "Keep It Stupid Simple" penso)

Quindi la domanda può anche essere posta in questo modo:
Tu, come sviluppatore, preferisci mantenere un codice noioso stupido o O avere degli aiutanti che faranno il codice noioso stupido al tuo posto?

L'aspetto negativo dell'ultima possibilità è che dovrai imparare alcune cose e forse dovrai mantenere anche il codice stupido noioso e stupido fino a quando non viene eseguito un refactoring completo)


Domanda molto interessante!
Philippe,

1
Mantenere un codice stupido noioso e facile - è per definizione facile. Preferirei avere una vita facile e partire presto ogni giorno.
quick_now

Sì, ma sono troppo pigro per fare un codice noioso e stupido :) Preferirò lavorare sodo per 2 o 3 giorni per costruire qualcosa che farà questa parte per me!
Guillaume,

1
Quando lo stupido o il noioso sono stati confusi per facile?
Erik Reppen il

Ciao Erik, a volte un codice che avrebbe potuto essere fattorizzato è più semplice da leggere: è dozzina di volte la stessa cosa e il codice è semplice. Puoi leggerlo in fila senza pensarci e puoi eseguire il debug in modo lineare. Non c'è complessità nascosta.
Guillaume,

Risposte:


42

Il refactoring viene eseguito meglio in piccoli passaggi, e preferibilmente solo se si dispone di test unitari per coprire il codice. (Quindi se non hai ancora dei test, cerca di scriverli prima, e fino ad allora, segui i refactoring più semplici, più infallibili, preferibilmente automatizzati. Un grande aiuto in questo è Lavorare in modo efficace con il codice legacy di Michael Feathers.)

In generale, mira a migliorare un po 'il codice ogni volta che lo tocchi. Segui la regola del boy scout ( coniata da Robert C. Martin ) lasciando il codice più pulito di quello che hai trovato. Quando aggiungi un nuovo codice, prova a tenerlo separato dal codice errato esistente. Ad esempio, non seppellirlo nel mezzo di un metodo lungo, invece aggiungi una chiamata a un metodo separato e inserisci il tuo nuovo codice. In questo modo, si espandono gradualmente isole più grandi di codice pulito (er) all'interno della base di codice esistente.

Aggiornare

I costi di refactoring saranno più pesanti dei suoi benefici. [...] Tu, come sviluppatore, preferisci mantenere un codice noioso stupido o O avere degli aiutanti che faranno lo stupido codice noioso al tuo posto?

Ho sottolineato quale credo sia il punto chiave qui. Vale sempre la pena valutare i costi e i benefici del refactoring prima di iniziare . Come nel tuo caso, molti di noi hanno risorse limitate per il refactoring, quindi dobbiamo usarli con saggezza. Dedica quel poco tempo prezioso al refactoring dove porta i maggiori benefici con il minimo sforzo.

Come mente creativa, ovviamente preferirei produrre un codice perfetto, bello ed elegante e riscrivere tutto ciò che non assomiglia ai miei ideali :-) In realtà, però, sono pagato per produrre software che risolve problemi reali per i suoi utenti, quindi dovrebbero pensare a produrre il massimo valore per i loro soldi nel lungo periodo.

Il vantaggio del refactoring appare solo se vi sono risparmi sufficienti nel tempo e negli sforzi per comprendere, mantenere, correggere ed estendere il codice a lungo termine . Quindi se un pezzo di codice - per quanto brutto sia - viene raramente o mai toccato, non ci sono bug conosciuti in esso e non conosco alcuna funzionalità imminente nel prossimo futuro che mi richiederebbe di toccarlo, preferisco andarmene in pace.


7
È così facile cadere nella trappola di "il codice fa già schifo, può anche continuare ..." I bravi programmatori no. Bella risposta.
sevenseacat,

Sebbene questo sia probabilmente l'approccio più sicuro (il codice è garantito per funzionare grazie ai test), comporta comunque il problema menzionato nella domanda. Nel modello è stato introdotto un modello diverso. In generale, credo che dovresti cercare di prendere il tuo tempo per refactificare tutto in una volta (quando fai TDD, meglio con passaggi intermedi) in modo da non avere quello stato incoerente intermedio. Al termine, affidare il codice al controllo del codice sorgente.
Steven Jeuris,

2
@Steven, va bene riformattare tutto in una volta se te lo puoi permettere . Nella maggior parte dei progetti di vita reale, tuttavia, non puoi semplicemente fermare tutto e passare diversi giorni o settimane di fila solo per refactoring. Anche se sei fortunato ad avere un manager che lo supporta, il progetto deve ancora proseguire.
Péter Török,

1
@Steven, dipende - vedi il mio aggiornamento sopra.
Péter Török,

1
@Péter Török: bel aggiornamento! Perfetta descrizione dei fattori del mondo reale da tenere in considerazione.
Steven Jeuris,

4

Dal momento che non hai tempo di refactoring e il codice è gestibile, mantienilo coerente. La prossima volta assicurati di includere il refactoring nel preventivo.


3

Essere coerenti aiuta lo sviluppatore successivo solo quando il codice circostante è in buona forma. Pensa a quanto tempo hai impiegato per comprendere il codice a portata di mano e trovare i giusti "punti di estensione" per aggiungere le modifiche. Se segui la tendenza attuale, il ragazzo successivo deve capire il codice esistente e il tuo nuovo codice quando deve apportare modifiche.

Se si converte il codice in funzioni significative, il prossimo sarà più facile capire cosa sta succedendo e dovrà fare meno sforzi per aggiungere le sue modifiche. Pensare in questo modo. Supponi che il prossimo ragazzo sei tu. Cosa preferiresti vedere quando rivisiti questo blocco di codice, lo stesso casino che stai guardando ora o qualcosa di più logicamente costruito?


3

La coerenza ha un'alta priorità. Ovviamente tutti nella loro mente giusta preferirebbero un'elegante soluzione DRY ovunque anziché una piastra di cottura incollata ovunque, ma preferireste davvero due approcci diversi nella stessa base di codice per avere un'applicazione coerente? Cosa succede se qualcuno inventa una soluzione ancora più intelligente e la applica anche in modo incoerente? Quindi hai tre modi diversi di fare la stessa cosa.

Ho visto molto codice disordinato derivante dal fatto che gli sviluppatori hanno trovato un "modo migliore" per fare qualcosa, ma non lo hanno applicato in modo coerente su una base di codice. Se fa parte di una strategia pianificata e coordinata applicare gradualmente un nuovo modello nel tempo, potrebbe funzionare, ma ogni modello implementato in modo incoerente ha il rischio di peggiorare il sistema complessivo.

Forse potresti prendere in considerazione il refactoring in passaggi più piccoli, in modo tale che ogni passaggio possa essere applicato sull'intera base di codice in una volta sola. Per esempio. estrarre una parte più piccola della piastra della caldaia in una funzione di supporto in ogni iterazione. Con il passare del tempo finisci con tutte le piastre della caldaia in una classe di supporto. Può sembrare davvero brutto perché non è stato progettato ma cresciuto, ma puoi risolverlo ora perché hai tutto il codice in un unico posto.


+1 "Quindi hai tre modi diversi di fare la stessa cosa." L'ho visto in ogni progetto aziendale a cui ho lavorato. Direi che non provi nemmeno a refactoring fino a quando non avrai analizzato il codice per essere sicuro che non ci sia già un altro pezzo di codice che sta tentando di prendersi cura del brutto codice che hai deciso di voler refactoring. A volte è meglio attenersi alla convenzione di plateplate, almeno fino a quando non si è data una lettura approfondita al codice.
TK-421,

1

Qualsiasi refactoring che elimina il codice duplicato è un buon refactoring e non dovrebbe essere rinviato a meno che non sia imminente una scadenza. Il tempo impiegato per il refactoring una volta è facilmente compensato dal tempo vinto in future implementazioni. Grazie al refactoring i meccanismi interni non sono più visibili, quindi dovrebbe diventare più facile da capire, non più difficile da seguire.

Secondo me è un'idea sbagliata comune che il codice refactored sia più difficile da seguire. Questo di solito è un argomento di persone che hanno familiarità solo con ciò che viene refactored e non con il risultato refactored. Per i nuovi arrivati, il risultato refactored sarà più chiaro.

Eventuali bug / funzionalità possono essere corretti / implementati in una posizione centrale in un secondo momento e sono automaticamente disponibili ovunque nell'applicazione. Questo è un enorme guadagno che di solito è molto sottovalutato. In generale un refactoring totale di un componente non richiede così tanto tempo. (giorni anziché mesi) Quando si confronta questo con il tempo perso a causa di bug, dovendo capire il codice che avrebbe potuto essere refactored, il costo del refactoring diventa minimo.

Aggiornamento relativo alla risposta di Péter Török: Non è forse rinviando il refactoring "perché richiede tempo", aumenta il tempo di refactoring in un secondo momento? Il refactoring non dovrebbe richiedere molto tempo, se fatto più spesso.

Come spiegare al tuo capo che passerai qualche giorno a scrivere codice che non aggiunge nulla al prodotto, è difficile ed è una domanda completamente diversa. :)


1
"Come spiegare al tuo capo che passerai qualche giorno a scrivere codice che non aggiunge nulla al prodotto, è difficile ed è una domanda completamente diversa." Bel tentativo ;-) Purtroppo nella vita reale dobbiamo risolvere anche questo. Ecco perché è più pratico fare piccoli passi. Mezz'ora di refactoring può essere eseguita come parte di un'attività di due ore, senza che il tuo manager debba nemmeno saperlo. OTOH due giorni interi di refactoring raramente passa inosservato.
Péter Török,

@Péter Török: ho aggiornato un po 'il post. Ovviamente hai ancora situazioni del mondo reale in cui non ti è permesso di prenderti il ​​tempo per il refactoring. Ma credo fermamente che in teoria sia sempre tempo guadagnato. (a meno che tu non sappia che il codice su cui stai lavorando non sarà più supportato nel prossimo futuro)
Steven Jeuris,

come si suol dire, in teoria non c'è molta differenza tra pratica e teoria. Tuttavia, in pratica ... :-) Nella vita reale potresti non sempre recuperare i costi spesi per il refactoring. Ho esteso la mia risposta su questo.
Péter Török,

1
Il refactoring che rimuove il codice duplicato non è sempre buono; è possibile che due metodi possano essere identici secondo le regole commerciali di oggi, ma non quelle di domani. Ad esempio, AcmeLockerBankuno potrebbe avere un getRow(int itemIndex)metodo che ritorna index % 5e un AcmeButtonPanelpotrebbe avere un metodo identico perché sia ​​l'armadietto che le schede pulsanti numerano le cose allo stesso modo; se nessuno dei banchi di armadi di oggi ha articoli con un indice superiore a 1000, ma alcuni pannelli pulsanti lo fanno, e i futuri armadietti usano una spaziatura di riga diversa per gli indici nell'intervallo 1000-1999 ...
supercat

1
... aggiungere il comportamento aggiuntivo ai banchi di armadietti sarà facile se i banchi di armadietti e le banche di pulsanti hanno getRowmetodi distinti , ma può essere più difficile se le funzioni sono state unite a un metodo comune.
supercat,

0

Non puoi creare una nuova interfaccia / classi che funziona come una facciata rispetto al vecchio codice, introducendo il tuo nuovo codice nel tuo stile che può essere facilmente esteso?


0

Fallo bene andando avanti. Usa le funzioni invece di tagliare e incollare. Ciò non richiede il refactoring, ma ti dà l'inizio di una fondazione per il refactoring futuro.


0

Tu, come sviluppatore, preferisci mantenere un codice noioso e stupido O avere degli aiutanti che faranno lo stupido codice noioso al tuo posto?

Non capisco la domanda rivista. Penso che la maggior parte delle persone, come me, preferirebbe non mantenere lo "stupido codice noioso". Non so cosa intendi per aiutante, scusa.

Il poster ha risposto alla propria domanda non apportando grandi cambiamenti in questo momento. Bella scelta. Ho problemi con l'arroganza di uno sviluppatore che sanno cosa è meglio per l'azienda. Un grosso refactoring di nascosto ... perché conosci meglio del tuo capo? Qualsiasi manager capace può valutare i benefici.

Se il refactoring non è un'opzione, allora la domanda diventa più una discussione sull'ora, il luogo, ecc. Corretti per farlo. La coerenza è molto importante. Tuttavia il codice longevo spesso beneficia del "rinnovo". Altri hanno discusso di questo ...

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.