Conciliare la regola del boy scout e il refactoring opportunistico con le revisioni del codice


55

Sono un grande sostenitore della regola del boy scout :

Controlla sempre un modulo in modo più pulito rispetto a quando lo hai verificato. "Indipendentemente da chi fosse l'autore originale, e se avessimo sempre fatto qualche sforzo, non importa quanto piccolo, per migliorare il modulo. Quale sarebbe il risultato? Penso che se noi tutti seguivano quella semplice regola, vedremmo la fine del continuo deterioramento dei nostri sistemi software. Invece, i nostri sistemi sarebbero gradualmente migliorati man mano che si evolvevano. Vedremmo anche i team che si occupano del sistema nel suo insieme, piuttosto di semplici persone che si prendono cura della propria piccola piccola parte.

Sono anche un grande sostenitore dell'idea correlata del refactoring opportunistico :

Sebbene ci siano posti per alcuni sforzi di refactoring programmati, preferisco incoraggiare il refactoring come attività opportunistica, eseguita ogni volta e ovunque il codice debba essere ripulito, da chiunque. Ciò significa che in qualsiasi momento qualcuno vede un codice che non è così chiaro come dovrebbe essere, dovrebbe cogliere l'occasione per risolverlo proprio lì e poi - o almeno entro pochi minuti

Si noti in particolare il seguente estratto dell'articolo di refactoring:

Sono diffidente nei confronti di eventuali pratiche di sviluppo che causano attrito per il refactoring opportunistico ... Il mio senso è che la maggior parte dei team non fa abbastanza refactoring, quindi è importante prestare attenzione a tutto ciò che scoraggia le persone dal farlo. Per aiutarti a risolvere questo problema, sii consapevole di ogni volta che ti senti scoraggiato dal fare un piccolo refactoring, uno che sei sicuro richiederà solo un minuto o due. Qualsiasi barriera di questo tipo è un odore che dovrebbe stimolare una conversazione. Quindi prendi nota dello scoraggiamento e portalo con la squadra. Almeno dovrebbe essere discusso durante la prossima retrospettiva.

Dove lavoro, c'è una pratica di sviluppo che causa un forte attrito: Code Review (CR). Ogni volta che cambio qualcosa che non rientra nell'ambito del mio "incarico", mi viene rimproverato dai miei revisori che sto rendendo più difficile rivedere la modifica. Ciò è particolarmente vero quando si tratta di refactoring, poiché rende difficile il confronto diff "riga per riga". Questo approccio è lo standard qui, il che significa che il refactoring opportunistico viene fatto raramente e solo il refactoring "pianificato" (che di solito è troppo piccolo, troppo tardi) ha luogo, se non del tutto.

Dichiaro che ne valgono i vantaggi e che 3 revisori lavoreranno un po 'più duramente (per capire effettivamente il codice prima e dopo, piuttosto che guardare la portata ristretta di quali linee sono cambiate - la recensione stessa sarebbe migliore solo per quello ) in modo che i prossimi 100 sviluppatori possano leggere e mantenere il codice. Quando presento questo argomento, i miei revisori affermano di non avere problemi con il mio refactoring, purché non si trovi nello stesso CR. Comunque sostengo che questo è un mito:

(1) La maggior parte delle volte ti rendi conto di cosa e come vuoi rifattorizzare quando sei nel bel mezzo del tuo incarico. Come afferma Martin Fowler:

Man mano che aggiungi la funzionalità, ti rendi conto che un po 'di codice che stai aggiungendo contiene una duplicazione con un po' di codice esistente, quindi devi riformattare il codice esistente per ripulire le cose ... Potresti ottenere qualcosa che funzioni, ma ti rendi conto che sarebbe meglio se l'interazione con le classi esistenti è stata modificata. Cogli l'occasione per farlo prima di considerarti finito.

(2) Nessuno ti guarderà favorevolmente rilasciando CR di "refactoring" che non avresti dovuto fare. Un CR ha un certo overhead e il tuo manager non vuole che "sprechi il tuo tempo" nel refactoring. Quando è associato alla modifica che dovresti fare, questo problema è ridotto al minimo.

Il problema è esacerbato da Resharper, poiché ogni nuovo file che aggiungo alla modifica (e non posso sapere in anticipo esattamente quali file finirebbero per essere modificati) è solitamente disseminato di errori e suggerimenti - molti dei quali sono esatti e totalmente meritevoli fissaggio.

Il risultato finale è che vedo un codice orribile e lo lascio lì. Ironia della sorte, ritengo che la correzione di tale codice non solo non migliorerà la mia posizione, ma in realtà li abbasserà e mi dipingerà come il ragazzo "sfocato" che perde tempo a sistemare le cose a cui nessuno importa invece di fare il suo lavoro. Mi dispiace perché disprezzo davvero il codice cattivo e non sopporto di guardarlo, figuriamoci chiamarlo dai miei metodi!

Qualche idea su come posso porre rimedio a questa situazione?


40
Mi sentirei a disagio a lavorare in un posto doveyour manager doesn't want you to "waste your time" on refactoring
Daenyth,

19
Oltre ad avere più CR, il punto chiave è che ogni commit dovrebbe essere per un unico scopo: uno per il refactor, uno per il requisito / bug / ecc. In questo modo, una revisione può distinguere tra il refactor e la modifica del codice richiesta. Direi anche che il refattore dovrebbe essere fatto solo se ci sono test unitari in atto che dimostrano che il tuo refattore non ha rotto nulla (lo zio Bob è d'accordo).

2
@ t0x1n Non lo vedo come diverso
Daenyth,

2
@ t0x1n sì, mi mancava quello. Stamattina non c'è abbastanza caffè. Nella mia esperienza ci sono alcuni modi per refactoring. Forse guardi il codice che devi modificare e sai immediatamente che deve essere pulito, quindi prima lo fai. Forse si deve a refactoring qualcosa al fine di rendere il vostro cambiamento, perché il nuovo requisito è incompatibile con il codice esistente. Direi che il refactor è intrinsecamente parte del tuo cambiamento e non dovrebbe essere considerato separato. Infine, forse vedi che il codice fa schifo a metà della tua modifica, ma puoi finirlo. Refactor dopo il fatto.

6
Il proiettile 1 non afferma che è impossibile separare i commit. Implica solo che non sai come farlo, o il tuo VCS lo rende difficile. Lo faccio sempre, anche prendendo un singolo commit e dividendolo dopo il fatto.
Inutile

Risposte:


18

OK, quindi ora ci sono più cose di quante siano adatte per un commento.

tl; dr

La tua intuizione su cosa dovresti fare (refactoring man mano che procedi) è corretta.

La tua difficoltà ad implementare questo - dato che devi aggirare un sistema di revisione del codice scadente - dipende dalla tua difficoltà a manipolare il tuo codice sorgente e VCS. Molte persone hanno detto che puoi e dovresti dividere le tue modifiche (sì, anche all'interno dei file) in più commit, ma sembra che tu abbia difficoltà a crederci.

Puoi davvero farlo. Questo è davvero ciò che stiamo suggerendo. Dovresti davvero imparare a ottenere il massimo dai tuoi strumenti di modifica, manipolazione del codice sorgente e controllo della versione. Se investi tempo nell'imparare a usarli bene, ti semplifica la vita.


Problemi di flusso di lavoro / politica dell'ufficio

Sostanzialmente suggerirei la stessa raccomandazione di GlenH7 di creare due commit: uno con solo refactoring e (chiaramente o ovviamente) nessun cambiamento funzionale, e uno con i cambiamenti funzionali in questione.

Può essere utile, tuttavia, se trovi molti errori, scegliere una singola categoria di errore da correggere all'interno di un singolo CR. Quindi hai un commit con un commento come "codice dedupe", "correggi errori di tipo X" o qualsiasi altra cosa. Poiché ciò comporta un singolo tipo di modifica, presumibilmente in più punti, dovrebbe essere banale rivedere. Significa che non puoi correggere tutti gli errori che trovi, ma può rendere meno doloroso passare di nascosto.


Problemi di VCS

Dividere le modifiche apportate alla tua fonte di lavoro in più commit non dovrebbe essere una sfida. Non hai detto cosa stai usando, ma i possibili flussi di lavoro sono:

  1. se stai usando git, hai strumenti eccellenti per questo

    • è possibile utilizzare git add -iper la stadiazione interattiva dalla riga di comando
    • puoi utilizzare git guie selezionare singoli hunk e linee per mettere in scena (questo è uno dei pochi strumenti della GUI correlati a VCS che in realtà preferisco alla riga di comando, l'altro è un buon editor di merge a 3 vie)
    • puoi effettuare molti piccoli commit (singole modifiche o correggere la stessa classe di bug in più punti) e quindi riordinarli, unirli o dividerli con rebase -i
  2. se non stai usando git, il tuo VCS potrebbe avere ancora degli strumenti per questo genere di cose, ma non posso consigliarlo senza sapere quale sistema usi

    Hai detto che stai usando TFS - che credo sia compatibile con Git dal TFS2013. Potrebbe valere la pena sperimentare l'uso di un clone git locale del repository su cui lavorare. Se questo è disabilitato o non funziona per te, puoi comunque importare il sorgente in un repository git locale, lavorare lì e usarlo per esporta i tuoi commit finali.

  3. puoi farlo manualmente in qualsiasi VCS se hai accesso a strumenti di base come diffe patch. È più doloroso, ma certamente possibile. Il flusso di lavoro di base sarebbe:

    1. apporta tutte le tue modifiche, test, ecc.
    2. utilizzare diffper creare un file di patch (contestuale o unificato) con tutte le modifiche dall'ultimo commit
    3. partizionalo in due file: finirai con un file patch contenente refactoring e uno con modifiche funzionali
      • questo non è del tutto banale - strumenti come la modalità diff di emacs possono aiutare
    4. eseguire il backup di tutto
    5. ripristinare l'ultimo commit, utilizzare patchper riprodurre uno dei file patch, eseguire il commit di tali modifiche
      • NB. se la patch non si applica in modo pulito, potrebbe essere necessario correggere manualmente gli hunk non riusciti
    6. ripetere 5 per il secondo file patch

Ora hai due commit, con le tue modifiche partizionate in modo appropriato.

Nota che probabilmente ci sono strumenti per rendere più semplice la gestione di questa patch - non li uso proprio perché git lo fa per me.


Non sono sicuro di seguirlo - il punto 3.3 assume che il refactoring e le modifiche funzionali risiedano in file diversi? Ad ogni modo, non lo fanno. Forse la separazione per linee ha più senso, ma non credo che abbiamo degli strumenti per questo nel nostro CVS (TFS). In ogni caso, non funzionerebbe per molti (la maggior parte?) Refactoring in cui i cambiamenti funzionali si basano sul cambiamento refactored. Ad esempio supponiamo che il metodo refactor Foo (che devo usare come parte del mio funzionale modificato) per prendere 3 parametri invece di 2. Ora il codice funzionale Imy si basa sul codice refactor, anche dividere per linea non aiuta.
t0x1n,

1
Linee diverse nello stesso file vanno bene nei flussi di lavoro forniti. E dato che i due commit sarebbero sequenziali , è perfettamente accettabile che il secondo commit (funzionale) dipenda dal primo. Oh, e TFS2013 supporta presumibilmente git.
Inutile

Usiamo anche TFS per il controllo del codice sorgente. Supponete che il secondo commit sarà quello funzionale, mentre in genere sarebbe l'opposto (visto che non posso dire in anticipo quale refactoring dovrebbe essere fatto). Suppongo che potrei fare tutto il mio lavoro di funzionale + refactoring, quindi sbarazzarmi di qualsiasi cosa funzionale e aggiungerlo nuovamente in un commit separato. Sto solo dicendo che è un sacco di seccature (e tempo) solo per rendere felici un paio di recensori. Un approccio più ragionevole alla mia mente è quello di consentire il refactoring opportunistico e in cambio accettare da soli tali cambiamenti CR (accettando la difficoltà aggiuntiva).
t0x1n,

3
Penso che davvero non mi capisci. La modifica delle origini e il raggruppamento delle modifiche in commit, sì anche le modifiche nello stesso file, sono attività logicamente separate. Se questo sembra difficile, devi solo imparare meglio gli strumenti di gestione del codice sorgente disponibili.
Inutile

1
Sì, la tua comprensione è corretta, avresti due commit sequenziali con il secondo (funzionale) a seconda del primo (refactoring). Il flusso di lavoro diff / patch sopra descritto è esattamente un modo per farlo che non richiede la cancellazione manuale delle modifiche e la loro riscrittura.
Inutile

29

Presumo che le richieste di modifica siano importanti e formali per la tua azienda. In caso contrario, apporta le modifiche (ove possibile) in molti piccoli commit (come dovresti fare).

Qualche idea su come posso porre rimedio a questa situazione?

Continua a fare quello che stai facendo?

Voglio dire, tutti i tuoi pensieri e le tue deduzioni sono del tutto corretti. Dovresti sistemare le cose che vedi. Le persone non eseguono abbastanza il refactoring pianificato. E questo beneficio per l'intero gruppo è più importante che scomodarne alcuni.

Ciò che può aiutare è essere meno combattivo. Le recensioni del codice non dovrebbero essere combattive "Perché l'hai fatto?", Dovrebbero essere collaborative "Ehi ragazzi, mentre ero qui ho sistemato tutte queste cose!". Lavorare (se possibile con il proprio responsabile / responsabile) per cambiare quella cultura è difficile, ma piuttosto vitale per creare un team di sviluppo altamente funzionante.

Puoi anche lavorare (con il tuo responsabile / responsabile se possibile) per far avanzare l'importanza di queste idee con i tuoi colleghi. Trasformati in te chiedendo "perché non vi preoccupate della qualità?" invece di chiedere "perché fai sempre queste cose inutili?".


5
Sì, i CR sono grandi e formali. Le modifiche vengono registrate, firmate e quindi inviate in una coda. Si suppone che piccole modifiche vengano aggiunte come iterazioni a un CR in corso anziché commesse separatamente. La WRT continua quello che sto facendo, che potrebbe davvero giovare al gruppo ma temo che non mi gioverà . Quelle persone che "inconveniente" sono probabilmente le stesse persone che mi valuterebbero nella revisione annuale. Il problema con il cambiamento della cultura è che i grandi capi ci credono. Forse ho solo bisogno di guadagnare più rispetto nei loro occhi prima di provare qualcosa del genere ...
t0x1n

13
@ t0x1n - Non guardarmi. Ho fatto una carriera facendo la cosa giusta di fronte alle persone ostinatamente guardate dal succhiare. Forse non sarebbe così redditizio come avrei potuto fare se avessi reso felici le persone, ma dormo bene.
Telastyn,

Grazie per essere onesti. È davvero qualcosa da contemplare.
t0x1n,

1
Mi capita spesso di imbattermi anche in questo. Assicurare di avere una patch "cleanup" e poi una patch di lavoro aiuta molto. Di solito combatto all'interno del sistema e poi vado a lavorare in un posto meno stressante. Detto questo, a volte ci sono ragioni valide per le preoccupazioni dei tuoi colleghi. Ad esempio se il codice entra rapidamente in produzione e non ci sono test sufficienti. Ho visto la revisione del codice come un tentativo di evitare i test. Non funziona. La revisione del codice aiuta a mantenere un corpo di codice uniforme. Fa poco per i bug.
Sean Perry,

1
@SeanPerry ha acconsentito - ma sto parlando di circostanze normali in cui esistono test, verranno eseguiti bug bug, ecc.
t0x1n

14

Ho molta simpatia per la tua situazione, ma alcuni suggerimenti concreti. Se non altro, forse ti convincerò che per quanto brutta sia una situazione, potrebbe andare peggio. Può SEMPRE essere peggio. :-)

Innanzitutto, penso che tu abbia (almeno) due problemi con la tua cultura, non solo uno. Un problema è l'approccio al refactoring, ma le revisioni del codice sembrano un problema distinto. Proverò a separare i miei pensieri.

Recensioni di codice

Ero in un gruppo che HATED recensioni di codice. Il gruppo è stato formato fondendo due gruppi da parti separate della società. Venivo dal gruppo che stava facendo revisioni del codice da diversi anni, con risultati generalmente buoni. Molti di noi credevano che le recensioni dei codici fossero un buon uso del nostro tempo. Ci siamo fusi in un gruppo più numeroso e, per quanto abbiamo potuto dire, quell'altro "gruppo" non aveva mai nemmeno sentito parlare di recensioni di codice. Ora lavoravamo tutti sulla "loro" base di codice.

Le cose non andavano bene quando ci siamo fusi. Le nuove funzionalità erano in ritardo di 6-12 mesi, anno dopo anno. L'arretrato di bug era enorme, crescente e svuotante la vita. La proprietà del codice era forte, specialmente tra i "guru" più anziani. I "rami delle funzioni" a volte duravano anni e riguardavano alcune versioni; a volte NESSUNO ma un singolo sviluppatore ha visto il codice prima che colpisse il ramo principale. In realtà "ramo delle caratteristiche" è fuorviante, poiché suggerisce che il codice era da qualche parte nel repository. Più spesso era solo sul sistema individuale dello sviluppatore.

Il management ha convenuto che dovevamo "fare qualcosa" prima che la qualità diventasse inaccettabilmente bassa. :-) La loro risposta è stata la recensione del codice. Code Review è diventato un articolo ufficiale "Thou Shalt", per precedere ogni check-in. Lo strumento che abbiamo usato era Review Board.

Come ha funzionato nella cultura che ho descritto? Meglio di niente, ma è stato doloroso e ci è voluto più di un anno per raggiungere una sorta di livello minimo di conformità. Alcune cose che abbiamo osservato:

  1. Lo strumento utilizzato tende a focalizzare le revisioni del codice in determinati modi. Questo può essere un problema. La scheda di revisione offre diff carine e colorate differenze riga per riga e consente di allegare commenti a una riga. Questo fa sì che la maggior parte degli sviluppatori ignori tutte le linee che non sono cambiate. Va bene per piccoli cambiamenti isolati. Non è così buono per grandi cambiamenti, grandi blocchi di nuovo codice o codice che ha 500 istanze di una funzione rinominata mista a 10 righe di nuove funzionalità.
  2. Anche se eravamo in una vecchia base di codice malata che per la maggior parte non era mai stata esaminata prima, è diventato "scortese" per un revisore commentare tutto ciò che NON era una linea di cambiamento, anche per evidenziare un errore evidente. "Non disturbarmi, questo è un check-in importante e non ho tempo per correggere i bug."
  3. Acquista un recensore "facile". Alcune persone guarderanno una recensione di 10 file con 2000 linee modificate per 3 minuti e fare clic su "Spedisci!". Tutti imparano rapidamente chi sono quelle persone. Se non vuoi davvero rivedere il tuo codice in primo luogo, invialo a un revisore "facile". Il check-in non verrà rallentato. Puoi restituire il favore diventando un revisore "facile" per il suo codice.
  4. Se odi le recensioni sui codici, ignora le e-mail che ricevi dalla Bacheca delle recensioni. Ignora i follow-up dei membri del tuo team. Per settimane. Fino a quando non avrai 3 dozzine di recensioni aperte nella coda e il tuo nome apparirà nelle riunioni di gruppo alcune volte. Quindi diventa un revisore "facile" e cancella tutte le tue recensioni prima di pranzo.
  5. Evitare di inviare il codice a un revisore "difficile". (Il tipo di sviluppatore che vorrebbe porre o rispondere a una domanda come questa.) Tutti imparano rapidamente chi sono i revisori "difficili", così come imparano quelli facili. Se le revisioni del codice sono un Waste Of Time (™), la lettura di feedback dettagliati sul codice PROPRIO è sia Waste Of Time (™) sia un insulto.
  6. Quando le revisioni del codice sono dolorose, le persone le rimandano e continuano a scrivere altro codice. Ottieni meno recensioni di codice, ma ognuna è GRANDE. Hai bisogno di più recensioni di codice più piccole, il che significa che il team deve capire come renderle il più indolore possibile.

Pensavo di scrivere alcuni paragrafi sulle Recensioni di Codice, ma risulta che stavo scrivendo principalmente sulla cultura. Immagino che si riduca a questo: le revisioni del codice possono essere buone per un progetto, ma un team ottiene solo i vantaggi che meritano di ottenere.

refactoring

Il mio gruppo disprezzava il refactoring anche più di quanto odiasse le revisioni del codice? Ovviamente! Per tutte le ovvie ragioni che sono già state menzionate. Stai sprecando il mio tempo con una revisione del codice icky e non stai nemmeno aggiungendo una funzione o risolvendo un bug!

Ma il codice aveva ancora un disperato bisogno di refactoring. Come procedere?

  1. Non mescolare mai una modifica di refactoring con una modifica funzionale. Alcune persone hanno menzionato questo punto. Se le revisioni del codice rappresentano un punto di attrito, non aumentare l'attrito. È più lavoro, ma dovresti pianificare una revisione separata e un check-in separato.
  2. Inizia in piccolo. Molto piccolo. Ancora più piccolo di così. Usa i refactoring molto piccoli per insegnare gradualmente alle persone che il refactoring e le revisioni del codice non sono puro male. Se riesci a intrufolarti in un piccolo refactoring a settimana senza troppi dolori, in un paio di mesi potresti riuscire a cavartene due alla settimana. E possono essere un po 'più grandi. Meglio di niente.
  3. Essenzialmente non abbiamo avuto test unitari. Quindi è vietato il refactoring, giusto? Non necessariamente. Per alcune modifiche, il compilatore è il test unitario. Concentrati sui refactoring che puoi testare. Evitare le modifiche se non possono essere testate. Magari potresti passare il tempo a scrivere unit test.
  4. Alcuni sviluppatori hanno paura del refactoring perché hanno paura di TUTTE le modifiche al codice. Mi ci è voluto molto tempo per riconoscere questo tipo. Scrivono un pezzo di codice, giocheranno con esso fino a quando non "funziona", e quindi non vogliono MAI cambiarlo. Non capiscono necessariamente PERCHÉ funziona. Il cambiamento è rischioso. Non si fidano di se stessi per fare QUALSIASI cambiamento, e certamente non si fideranno di te. Il refactoring dovrebbe riguardare piccoli cambiamenti sicuri che non alterano il comportamento. Ci sono sviluppatori per i quali l'idea stessa di un "cambiamento che non modifica il comportamento" è inconcepibile . Non so cosa suggerire in questi casi. Penso che tu debba provare a lavorare in aree che non gli interessano. Sono stato sorpreso quando ho scoperto che questo tipo può avere a lungo,

1
Questa è una risposta super premurosa, grazie! Concordo in particolare con il modo in cui lo strumento CR può influire sul focus della recensione ... riga per riga è la via d'uscita facile, che non implica realmente la comprensione di ciò che stava accadendo prima e di ciò che accade ora. E ovviamente il codice che non è cambiato è perfetto, non c'è bisogno di guardarlo mai ...
t0x1n

1
" Potrebbe essere peggio potrebbe essere Rainin'.. " Quando ho letto il tuo ultimo paragrafo (secondo punto # 4) Stavo pensando: hanno bisogno di più rivedere, codificatore revisione. E alcuni refactoring, come in: "yourSalary = 0"

Assolutamente perfetto su tanti fronti, risposta incredibile. Posso vedere totalmente da dove vieni: sono io stesso nella stessa situazione ed è incredibilmente frustrante. Sei in questa costante lotta per la qualità e le buone pratiche e non c'è supporto da parte non solo della direzione, ma soprattutto degli altri sviluppatori del team.
julealgon,

13

Perché non fai entrambe le cose, ma con commit separati?

I tuoi colleghi hanno un punto. Una revisione del codice dovrebbe valutare il codice che è stato modificato da qualcun altro. Non dovresti toccare il codice che stai recensendo per qualcun altro in quanto ciò pregiudica il tuo ruolo di revisore.

Ma se vedi una serie di problemi evidenti, ci sono due opzioni che puoi seguire.

  1. Se la revisione del codice andava diversamente, consenti il ​​commit della parte che hai esaminato e quindi rifattorizza il codice con un secondo check-in.

  2. Se la revisione del codice presentava problemi che necessitavano di correzione, richiedere allo sviluppatore di effettuare il refactoring in base alle raccomandazioni di Resharper.


Capisco dalla tua risposta che credi nella proprietà del codice forte. Ti incoraggio a leggere i pensieri di Fowler sul perché sia ​​una cattiva idea: martinfowler.com/bliki/CodeOwnership.html . Per affrontare in modo specifico i tuoi punti: (1) è un mito in quanto il refactoring avviene mentre stai apportando il tuo cambiamento - non prima o dopo in modo separato, pulito, non correlato come richiederebbero CR separati. (2) Con la maggior parte degli sviluppatori, non accadrà mai. Mai . La maggior parte degli sviluppatori non si preoccupa di queste cose, tanto meno quando proviene da un altro ragazzo che non è il loro manager. Hanno le loro cose che vogliono fare.
t0x1n,

8
@ t0x1n: se i tuoi manager non si preoccupano del refactoring e i tuoi colleghi sviluppatori non si preoccupano del refactoring ... allora quell'azienda sta lentamente affondando. Scappa! :)
logc,

8
@ t0x1n solo perché apporti le modifiche insieme, non significa che devi impegnarle insieme. Inoltre, è spesso utile verificare che il refactoring non abbia avuto effetti collaterali imprevisti separatamente dal controllare che il cambiamento funzionale abbia avuto l'effetto previsto. Ovviamente questo potrebbe non essere applicabile a tutti i refactoring, ma non è un cattivo consiglio in generale.
Inutile

2
@ t0x1n - Non ricordo di aver detto nulla sulla proprietà del codice forte. La mia risposta è stata quella di mantenere puro il tuo ruolo di revisore. Se un revisore introduce delle modifiche, non è più solo un revisore.

3
@ GlenH7 Forse c'è stato qualche malinteso qui - non sono il recensore. Sto solo codificando ciò di cui ho bisogno ed eseguo il codice che posso migliorare nel processo. I miei recensori poi si lamentano quando lo faccio.
t0x1n,

7

Personalmente odio l'idea di rivedere il codice post commit. La revisione del codice dovrebbe avvenire mentre si apportano modifiche al codice. Ciò di cui sto ovviamente parlando qui è la programmazione in coppia. Quando si accoppia, si ottiene la recensione gratuitamente e si ottiene una migliore revisione del codice. Ora, sto esprimendo la mia opinione qui, so che altri lo condividono, probabilmente ci sono studi che lo dimostrano.

Se riesci a far accoppiare i tuoi revisori del codice con te, l'elemento combattivo della revisione del codice dovrebbe evaporare. Quando inizi a fare un cambiamento che non è compreso, la domanda può essere sollevata nel punto di cambiamento, discussa e esplorate alternative che possono portare a migliori rifatturazioni. Otterrai una revisione del codice di qualità più elevata poiché la coppia sarà in grado di comprendere l'ambito più ampio del cambiamento e non concentrarti così tanto sulle modifiche linea per linea, che è ciò che ottieni con il confronto del codice affiancato.

Ovviamente questa non è una risposta diretta al problema dei refactoring al di fuori dell'ambito del cambiamento su cui si sta lavorando, ma mi aspetto che i tuoi colleghi possano comprendere meglio il ragionamento alla base dei cambiamenti se si trovassero lì quando hai apportato il cambiamento.

A parte questo, supponendo che tu stia facendo TDD o una qualche forma di refattore verde rosso, un modo per assicurarti di ottenere il coinvolgimento del tuo pari è usare la tecnica di accoppiamento del ping pong. Semplicemente spiegato come il driver viene ruotato per ogni fase del ciclo RGR, cioè la coppia 1 scrive un test fallito, la coppia 2 lo corregge, la coppia 1 refactor, la coppia 2 scrive un test fallito .... e così via.


Punti eccellenti. Sfortunatamente dubito sinceramente che sarò in grado di cambiare "il sistema". A volte i revisori provengono anche da fusi orari e posizioni geografiche diverse, quindi in questi casi non voleranno a prescindere.
t0x1n,

6

Probabilmente questo problema riflette un problema molto più grande con la cultura dell'organizzazione. La gente sembra più interessata a fare "il suo lavoro" nel modo giusto che a migliorare il prodotto, probabilmente questa azienda ha una cultura "da incolpare" invece di una cultura collaborativa e le persone sembrano più interessate a coprirsi piuttosto che ad avere una visione completa del prodotto / dell'azienda .

A mio avviso, hai perfettamente ragione, le persone che esaminano il tuo codice sono completamente sbagliate se si lamentano perché "tocchi" le cose al di fuori del "tuo incarico", provi a convincere quelle persone ma non sei mai contrario ai tuoi principi, per me questo è la qualità più importante di un vero professionista.

E se la cosa giusta ti dia dei cattivi numeri in un modo stupido per valutare il tuo lavoro, qual è il problema? Chi vuole "vincere" questo gioco di valutazione in una società folle? Prova a cambiarlo! E se impossibile o sei stanco, trova un altro posto, ma mai, mai contro i tuoi principi, è il migliore che hai.


1
Inizi a voler vincere il gioco di valutazione una volta che ti rendi conto che ti ricompensa con aumenti salariali, bonus e stock options :)
t0x1n

2
No. Stai scambiando denaro per principi @ t0x1n. Semplice come quella. Hai tre opzioni: lavorare per riparare il sistema, accettare il sistema, lasciare il sistema. Le opzioni 1 e 3 fanno bene all'anima.
Sean Perry,

2
non solo fa male all'anima, un'azienda con principi che si concentrano sui massimi locali è normalmente meno ottimale di un'azienda che si concentra sui massimi globali. Non solo, lavora non solo denaro, trascorri molto tempo ogni giorno nel tuo lavoro, sii comodo nel tuo lavoro, senti che stai facendo le cose giuste, probabilmente è molto meglio che un mucchio di dollari in più al mese.
AlfredoCasado,

1
Meh, le anime sono sopravvalutate;)
t0x1n

2
@SeanPerry Ho davvero provato a riparare il sistema ma è stato molto difficile. (1) Ero praticamente solo in questo, ed è difficile andare contro i grandi capi (sono solo un normale sviluppatore, nemmeno senior). (2) Queste cose richiedono tempo che semplicemente non avevo. C'è molto lavoro e l'intero ambiente richiede molto tempo (e-mail, interruzioni, CR, cicli di test falliti che è necessario correggere, riunioni, ecc. Ecc.). Faccio del mio meglio per filtrare ed essere produttivo, ma in genere riesco a malapena a finire il mio lavoro "prescritto" in tempo (avere standard elevati non aiuta qui), per non parlare del lavoro di modifica del sistema ...
t0x1n

5

A volte, il refactoring è una cosa negativa. Non per i motivi che stanno dando i vostri revisori del codice; sembra che a loro non importi davvero della qualità del codice, e te ne importa, il che è fantastico. Ma ci sono due motivi che dovrebbero impedirti di eseguire il refactoring : 1. Non puoi testare le modifiche apportate con test automatici (unit test o altro) o 2. Stai apportando modifiche ad alcuni codici che non capisci molto bene; cioè, non hai le conoscenze specifiche del dominio per sapere quali modifiche dovresti apportare.

1. Non effettuare il refactoring quando non è possibile verificare le modifiche apportate con i test automatici.

La persona che sta eseguendo la revisione del codice deve essere in grado di essere sicuro che le modifiche apportate non abbiano interrotto nulla di quello che funzionava. Questa è la ragione principale per lasciare solo il codice funzionante. Sì, sarebbe sicuramente meglio rielaborare quella funzione lunga 1000 righe (che è davvero un abominio!) In una serie di funzioni, ma se non riesci ad automatizzare i tuoi test, può essere davvero difficile convincere gli altri che hai fatto tutto giusto. Ho sicuramente fatto questo errore prima.

Prima di effettuare il refactoring, assicurarsi che ci siano test unitari. Se non ci sono test unitari, scrivine alcuni! Quindi rifatti e i tuoi revisori del codice non avranno scuse (legittime) per essere turbati.

Non refactificare parti di codice che richiedono conoscenze specifiche del dominio che non si dispone.

Il posto in cui lavoro ha un sacco di codice di ingegneria chimica pesante. La base di codice utilizza gli idiomi comuni agli ingegneri chimici. Non apportare mai modifiche idiomatiche a un campo. Potrebbe sembrare una grande idea di rinominare una variabile chiamata xa molarConcentration, ma indovinate un po '? In tutti i testi di chimica, la concentrazione molare è rappresentata da un x. Rinominarlo rende più difficile sapere cosa sta realmente succedendo nel codice per le persone in quel campo.

Invece di rinominare le variabili idiomatiche, basta inserire commenti che spiegano cosa sono. Se lo sono , non idiomatica, si prega di rinominarli. Non lasciare il i, j, k, x, y, ecc galleggianti intorno quando i nomi migliori funzionerà.

Regola empirica per le abbreviazioni: se, quando le persone parlano, usano un'abbreviazione, va bene usare quell'abbreviazione nel codice. Esempi dalla base di codice al lavoro:

Abbiamo i seguenti concetti che abbreviamo sempre quando ne parliamo: "Area di preoccupazione" diventa "AOC", "Esplosione di nuvole di vapore" diventa VCE, cose del genere. Nella nostra base di codici, qualcuno ha eseguito il refactoring di tutte le istanze chiamate aoc in AreaOfConcern, VCE in vaporCloudExplosion, nPlanes in confiningPlanesCount ... che ha reso il codice in realtà molto più difficile da leggere per le persone che avevano una conoscenza specifica del dominio. Sono stato anche colpevole di fare cose del genere.


Questo potrebbe non essere affatto applicabile nella tua situazione, ma ci sono i miei pensieri sulla questione.


Grazie Cody. Riguardo a "i tuoi revisori del codice non avranno scuse (legittime) per essere arrabbiati" - la loro scusa è già illegittima, poiché sono arrabbiati per la maggiore difficoltà di andare oltre le modifiche piuttosto che per correttezza, leggibilità o cose del genere.
t0x1n,

2

Questa domanda presenta ora due problemi distinti: facilità di revisione delle modifiche nelle revisioni del codice e tempo impiegato per il refactoring.

Dove lavoro, esiste una pratica di sviluppo che causa un forte attrito: la revisione del codice (CR). Ogni volta che cambio qualcosa che non rientra nell'ambito del mio "incarico", mi viene rimproverato dai miei revisori che sto rendendo più difficile rivedere la modifica.

Come hanno già detto altre risposte, puoi separare i check-in del refactoring dai check-in di modifica del codice (non necessariamente come revisioni separate)? A seconda dello strumento che stai utilizzando per eseguire la revisione del codice, dovresti essere in grado di visualizzare le differenze solo tra le revisioni specifiche (Atlassian's Crucible lo fa sicuramente).

(2) Nessuno ti guarderà favorevolmente rilasciando CR di "refactoring" che non avresti dovuto fare. Un CR ha un certo overhead e il tuo manager non vuole che "sprechi il tuo tempo" nel refactoring. Quando è associato alla modifica che dovresti fare, questo problema è ridotto al minimo.

Se il refactoring è semplice e semplifica la comprensione del codice (che è tutto ciò che dovresti fare se si tratta solo di refactoring), la revisione del codice non dovrebbe richiedere molto tempo per essere completata e dovrebbe avere un sovraccarico minimo che viene riconquistato quando qualcuno deve venire e guardare di nuovo il codice in futuro. Se i tuoi capi non sono in grado di farlo, allora potresti aver bisogno di spingerli delicatamente verso alcune risorse che discutono sul perché la regola del boy scout porta a una relazione più produttiva con il tuo codice. Se riesci a convincerli che lo "spreco [del] tuo tempo" ora farà risparmiare due, cinque o dieci volte più tardi quando tu / qualcun altro tornerà per fare più lavoro su quel codice, allora il tuo problema dovrebbe andare via.

Il problema è esacerbato da Resharper, poiché ogni nuovo file che aggiungo alla modifica (e non posso sapere in anticipo esattamente quali file finirebbero per essere modificati) è di solito pieno di errori e suggerimenti - molti dei quali sono esatti e meritano totalmente fissaggio.

Hai provato a portare questi problemi all'attenzione dei tuoi colleghi e a discutere sul perché valga la pena risolverli? E qualcuno di loro può essere risolto automaticamente (supponendo che abbiate una copertura di prova sufficiente per confermare che non avete rotto le cose con il refactoring automatizzato)? A volte non è "degno del tuo tempo" eseguire un refactoring se si tratta davvero di cose schizzinose. L'intero team utilizza ReSharper? In tal caso, disponi di una politica condivisa su quali avvisi / regole vengono applicati? In caso contrario, forse dovresti dimostrare dove lo strumento ti aiuta a identificare le aree del codice che sono possibili fonti di dolore futuro.


Per quanto riguarda la separazione CR, ho sottolineato nel mio post e in molti altri commenti perché ritengo impossibile.
t0x1n,

Non sto parlando di cose pignolose, sto parlando di problemi di prestazioni e correttezza reali, nonché di codice ridondante, codice duplicato, ecc. E questo è solo roba R #, c'è anche qualche codice veramente cattivo che posso facilmente risolvere . Sfortunatamente non tutto il mio team usa il resharper, e anche quelli che non lo prendono troppo sul serio. È necessario un enorme sforzo educativo e forse proverò a condurre qualcosa del genere. È difficile, dato che a malapena ho abbastanza tempo per il lavoro che devo fare, per non parlare dei progetti di istruzione secondaria. Forse devo solo aspettare un periodo di inattività per sfruttare.
t0x1n,

Ho intenzione di entrare e dire che non è assolutamente impossibile , visto che lo vedo sempre. Apporta il cambiamento che avresti fatto senza il refactoring, controllalo, quindi rifatti per ripulirlo e controllalo. Non è scienza missilistica. Oh, e preparati a difendere il motivo per cui ritieni che valga la pena dedicare del tempo al refactoring e alla revisione del codice refactored.
Eric King,

@EricKing Suppongo di poterlo fare. Tuttavia: (1) dovrei lavorare con un brutto codice e prendere nota di ciò che voglio migliorare fino a quando non avrò finito con i cambiamenti funzionali che fanno entrambi schifo e rallentano effettivamente i miei progressi funzionali (2) Una volta che invio i miei cambiamenti funzionali e rivisitare i miei appunti per il refactoring, questa sarà solo la prima iterazione e il completamento del refactoring potrebbe richiedere più tempo, il che, come mi hai suggerito, farebbe fatica a spiegare ai miei manager, visto che il mio lavoro è già "fatto".
t0x1n,

2
"Sto parlando di problemi di prestazioni e correttezza effettivi" - questo potrebbe allungare la definizione di refactoring; se il codice è effettivamente errato costituirebbe una correzione di bug. Per quanto riguarda i problemi di prestazioni, questo non è qualcosa che dovresti risolvere solo nell'ambito di una modifica delle funzionalità, è probabilmente qualcosa che necessita di misurazione, test approfonditi e revisione separata del codice.
Chris Cooper,

2

Ricordo che circa 25 anni fa "ripulivo" il codice su cui stavo lavorando per altri scopi, principalmente riformattando blocchi di commenti e allineamenti di tabulazioni / colonne per rendere il codice pulito e quindi più facile da capire (nessun cambiamento funzionale effettivo) . Mi piace che il codice sia pulito e ordinato. Bene, gli sviluppatori senior erano furiosi. Si è scoperto che hanno usato una sorta di confronto dei file (diff) per vedere cosa era cambiato, rispetto alle loro copie personali del file, e ora stava dando tutti i tipi di falsi positivi. Dovrei menzionare che la nostra libreria di codici era su un mainframe e non aveva alcun controllo di versione - fondamentalmente hai sovrascritto qualunque cosa fosse lì, e basta.

La morale della storia? Non so. Immagino che a volte non puoi piacere a nessuno tranne te stesso. Non stavo perdendo tempo (ai miei occhi) - il codice ripulito era più facile da leggere e capire. È solo che gli strumenti di controllo delle modifiche primitivi utilizzati da altri mettono un po 'di lavoro extra su di essi. Gli strumenti erano troppo primitivi per ignorare lo spazio / tabulazione e ridisegnare i commenti.


Sì, mi viene anche chiesto spazio, così come cose banali come il casting ridondante ecc. Tutto ciò che non è completamente richiesto dal mio cambiamento è il "rumore".
t0x1n,

2

Se puoi dividere la modifica richiesta e il refactor non richiesto in (molti) commit separati, come notato da @Useless, @Telastyn e altri, allora questo è il meglio che puoi fare. Lavorerai ancora su un singolo CR, senza il sovraccarico amministrativo di crearne uno "refactoring". Mantieni i tuoi impegni piccoli e concentrati.

Invece di darti alcuni consigli su come farlo, preferisco indicarti una spiegazione molto più ampia (in effetti, un libro) di uno specialista. In questo modo, sarai in grado di imparare molto di più. Leggi Lavorare in modo efficace con il codice legacy (di Michael Feathers) . Questo libro può insegnarti come eseguire il refactoring, intercalato con i cambiamenti funzionali.

Gli argomenti trattati includono:

  • Comprensione della meccanica del cambiamento del software: aggiunta di funzionalità, correzione di bug, miglioramento della progettazione, ottimizzazione delle prestazioni
  • Trasmissione del codice legacy in un cablaggio di prova
  • Scrivere test che ti proteggono dall'introduzione di nuovi problemi
  • Tecniche che possono essere utilizzate con qualsiasi linguaggio o piattaforma, con esempi in Java, C ++, C e C #
  • Identificare con precisione dove è necessario apportare modifiche al codice
  • Far fronte a sistemi legacy che non sono orientati agli oggetti
  • Gestire applicazioni che non sembrano avere alcuna struttura

Questo libro include anche un catalogo di ventiquattro tecniche di rottura delle dipendenze che ti aiutano a lavorare con gli elementi del programma in isolamento e apportare modifiche più sicure.


2

Anch'io sono un grande sostenitore di The Boyscout Rule e Opportunistic Refactoring. Il problema è spesso quello di ottenere il buy-in della direzione. Il refactoring comporta sia rischi che costi. Ciò che la direzione spesso trascura è che lo stesso vale per il debito tecnico.

È la natura umana. Siamo abituati a gestire problemi reali, non a cercare di prevenirli. Siamo reattivi, non proattivi.

Il software è immateriale ed è quindi difficile capire che, come un'auto, necessita di manutenzione. Nessuna persona ragionevole comprerebbe un'auto e non la assisterebbe mai. Accettiamo che tale negligenza ridurrebbe la sua longevità e, a lungo termine, sarebbe più costosa.

Nonostante il fatto che molti manager lo comprendano, sono ritenuti responsabili delle modifiche al codice di produzione. Ci sono politiche che rendono più facile andarsene abbastanza bene da solo. Spesso la persona che ha bisogno di convincere è in realtà al di sopra del tuo manager e semplicemente non vuole combattere per mettere in produzione le tue "grandi idee".

Ad essere onesti, il tuo manager non è sempre convinto che il tuo rimedio sia, in effetti, eccezionale quanto pensi che sia. (Olio di serpente?) C'è abilità di vendita. Il tuo compito è aiutarlo a vedere il vantaggio.

La direzione non condivide le tue priorità. Indossa il tuo cappello da manager e guarda con gli occhi del management. Molto probabilmente troverai l'angolo giusto. Sii persistente. Effettuerai più cambiamenti evitando che la prima risposta negativa ti scoraggi.


1

Se puoi dividere la modifica richiesta e il refactor non richiesto in due richieste di modifica separate, come notato da @ GlenH7, questo è il meglio che puoi fare. Non sei quindi "il ragazzo che perde tempo", ma "il ragazzo che lavora due volte tanto".

Se ti ritrovi spesso nella situazione in cui non puoi dividerli, perché il lavoro richiesto ora necessita del refactor non richiesto per la compilazione, ti suggerirei di insistere per avere strumenti per controllare automaticamente gli standard di codifica, usando gli argomenti descritti qui (il Resharper gli avvisi da soli possono essere un buon candidato, non ne ho familiarità). Questi argomenti sono tutti validi, ma ce n'è uno in più che puoi usare a tuo vantaggio: avere quei test ora ti rende il dovere di passare i test su ogni commit.

Se la tua azienda non vuole "perdere tempo nel refactoring" (un segnale scarso da parte sua), allora dovrebbe fornirti un file di "soppressione degli avvisi" (ogni strumento ha il suo meccanismo) in modo da non essere più infastidito da tali avvertimenti. Lo dico per offrirti opzioni per diversi scenari, anche nel caso peggiore. È anche meglio avere accordi chiaramente definiti tra te e la tua azienda, anche sulla qualità del codice prevista, piuttosto che ipotesi implicite su ogni lato.


Questo sarebbe un ottimo suggerimento per un nuovo progetto. Tuttavia, la nostra base di codice attuale è enorme e Resharper emette molti errori per la maggior parte dei file. È semplicemente troppo tardi per imporlo, e la soppressione degli errori esistenti rende ancora peggio - ti perderai il tuo nuovo codice. Inoltre ci sono molti errori, problemi e odori di codice che un analizzatore statico non può rilevare, stavo solo dando avvertimenti su Resharper come esempio. Ancora una volta avrei potuto formulare la "parte sprecata" un po 'troppo duramente, avrei dovuto dire qualcosa del tipo "tempo dedicato a qualcosa che non è una priorità".
t0x1n,

@ t0x1n: la regola del boy scout riguarda principalmente i moduli che stai toccando. Ciò può aiutarti a disegnare una prima linea di demarcazione. Sopprimere gli avvertimenti non è una buona idea, lo so, ma dal punto di vista dell'azienda, sopprimerli nel nuovo codice è corretto e seguendo le loro convenzioni - beh, forse mi sto facendo trascinare dalle mie stesse argomentazioni :)
logc

1
questa è la parte frustrante! Tocco solo i file che avrei toccato comunque come parte del mio compito, ma ricevo lo stesso reclamo! Gli avvisi di cui sto parlando non sono avvertimenti di stile, sto parlando di problemi di prestazioni e correttezza effettivi, nonché di codice ridondante, codice duplicato, ecc.
t0x1n

@ t0x1n: sembra davvero molto frustrante. Nota che non intendevo solo "analisi del codice statico" ma anche altri consigli, qualcosa di equivalente a Nexus. Naturalmente, nessuno strumento rileva la semantica al 100%; questa è solo una strategia di risanamento.
logc,
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.