Cosa fare quando il codice inviato per la revisione del codice sembra essere troppo complicato?


115

Il codice è difficile da seguire ma sembra (per lo più) funzionare bene, almeno con test superficiali. Potrebbero esserci piccoli bug qua e là, ma è molto difficile capire leggendo il codice se sono sintomatici di problemi più profondi o semplici correzioni. La verifica manuale della correttezza generale tramite la revisione del codice è tuttavia molto difficile e dispendiosa in termini di tempo, se possibile.

Qual è il miglior modo di agire in questa situazione? Insistere su un rifacimento? Rinnovo parziale? Prima il factoring? Risolvi solo i bug e accetta il debito tecnico ? Effettuare una valutazione del rischio su tali opzioni e poi decidere? Qualcos'altro?


4
Appare o è? Una rapida misurazione dei file di origine confermerà o smentirà i tuoi sospetti. Dopo aver misurato è sufficiente visualizzare i numeri di misurazione durante la revisione del codice e suggerire un refactoring per ridurre i numeri di complessità.
Jon Raynor,



4
Si prega di definire "troppo complicato". Il codice è troppo complicato perché utilizza modelli di progettazione noti che sono semplicemente sconosciuti al tuo team o perché non riesce a utilizzare modelli ben noti al tuo team? I motivi precisi per giudicare il codice "troppo complicato" sono essenziali per creare una valutazione corretta di come andare avanti. Un'affermazione semplice come "troppo complicata" su un'area di conoscenza profonda e complicata come la revisione del codice mi suggerisce una caccia alle streghe da parte dello sviluppatore.
Pieter Geerkens,

7
@PieterGeerkens O forse è troppo complicato perché risolve un problema complicato?
Casey,

Risposte:


251

Se non può essere esaminato, non può passare la revisione.

Devi capire che la revisione del codice non è per la ricerca di bug. Ecco a cosa serve il QA. La revisione del codice serve a garantire che sia possibile una futura manutenzione del codice. Se non riesci nemmeno a seguire il codice ora, come puoi in sei mesi quando ti viene assegnato il compito di migliorare le funzionalità e / o correggere i bug? Trovare bug in questo momento è solo un vantaggio collaterale.

Se è troppo complesso, sta violando un sacco di principi SOLIDI . Refactor, refactor, refactor. Suddividilo in funzioni correttamente denominate che fanno molto meno, più semplici. Puoi ripulirlo e i tuoi casi di test si accerteranno che continui a funzionare correttamente. Hai dei casi di test, giusto? In caso contrario, dovresti iniziare ad aggiungerli.


49
Questo molto. Ricorda che non sarai solo tu e lo scrittore a leggere questo codice. Tra 10 anni ci sarà anche uno stagista a caso, quindi vuoi assicurarti che abbia la possibilità di capire cosa sta succedendo.
David Grinberg,

2
buona risposta. dipende dallo scopo della "revisione del codice". la leggibilità è una cosa, strutturatene un'altra, ma la loro strettamente correlata. In seguito sto lavorando con alcuni open source scritti da MAJOR corps, ed è quasi illeggibile perché i nomi var e fn sono così difficili.

19
@DavidGrinberg A tutti gli effetti pratici, "tu in sei mesi" è una persona completamente diversa.
Chrylis

2
Metti via il codice per un po 'di tempo (abbastanza a lungo per non ricordare tutto). Chiedi al programmatore originale di rivederlo. Vedi se HE lo capisce.
Nelson,

4
Non sono d'accordo sul fatto che la recensione del codice "non" per la ricerca di bug. Spesso trova bug e questo è un aspetto molto potente e utile delle revisioni del codice. Meglio ancora, aiuta a trovare modi per evitare bug interamente nel codice futuro. Il punto è forse sopravvalutato e dovrebbe essere che non è solo per trovare bug!
Cody Grey,

45

Tutto ciò che menzioni è perfettamente valido per essere sottolineato in una recensione di codice.

Quando ricevo una revisione del codice, rivedo i test. Se i test non forniscono una copertura sufficiente, è qualcosa da sottolineare. I test devono essere utili per garantire che il codice funzioni come previsto e continuerà a funzionare come previsto nelle modifiche. In effetti, questa è una delle prime cose che cerco in una recensione di codice. Se non hai dimostrato che il tuo codice soddisfa i requisiti, non voglio investire il mio tempo a guardarlo.

Una volta che ci sono prove sufficienti per il codice, se il codice è complesso o difficile da seguire, è anche qualcosa che gli umani dovrebbero guardare. Gli strumenti di analisi statica possono indicare alcune misure di complessità e contrassegnare metodi troppo complessi, nonché trovare potenziali difetti nel codice (e dovrebbero essere eseguiti prima di una revisione del codice umano). Ma il codice viene letto e mantenuto dagli umani e deve prima essere scritto per essere manutenibile. Solo se c'è un motivo per usare un codice meno gestibile, dovrebbe essere scritto in quel modo. Se hai bisogno di un codice complesso o non intuitivo, dovrebbe essere documentato (preferibilmente nel codice) perché il codice è in quel modo e avere commenti utili per i futuri sviluppatori per capire perché e cosa sta facendo il codice.

Idealmente, rifiuta le recensioni di codice che non hanno test appropriati o che hanno un codice troppo complesso senza una buona ragione. Potrebbero esserci motivi commerciali per andare avanti e per questo dovresti valutare i rischi. Se vai avanti con un debito tecnico nel codice, metti immediatamente i biglietti nel tuo sistema di tracciamento dei bug con alcuni dettagli su ciò che deve cambiare e alcuni suggerimenti per cambiarlo.


30

La verifica manuale della correttezza generale tramite la revisione del codice è tuttavia molto difficile e dispendiosa in termini di tempo, se possibile.

Questo non è in remoto il punto di una revisione del codice. Il modo di pensare a una revisione del codice è di immaginare che ci sia un bug nel codice e devi risolverlo. Con questa mentalità, sfoglia il codice (in particolare i commenti) e chiediti "È facile capire il quadro generale di ciò che sta accadendo in modo da poter restringere il problema?" Se è così, è un passaggio. Altrimenti, è un fallimento. È necessaria almeno ulteriore documentazione, o forse è necessario il refactoring per rendere il codice ragionevolmente comprensibile.

È importante non essere perfezionisti a meno che non si sia sicuri di ciò che il datore di lavoro sta cercando. La maggior parte del codice fa così schifo che potrebbe essere facilmente rifattorizzato 10 volte di seguito, diventando ogni volta più leggibile. Ma il tuo datore di lavoro probabilmente non vuole pagare per avere il codice più leggibile al mondo.


4
Ottimo commento! "La maggior parte del codice fa così schifo che potrebbe essere facilmente riformulato 10 volte di seguito, diventando sempre più leggibile ogni volta" Ragazzo, sono stato colpevole di farlo :)
Dean Radcliffe,

1
"La maggior parte del codice fa così tanto schifo che potrebbe essere facilmente rifattorizzato 10 volte di seguito, diventando ogni volta più leggibile." Anzi, è così nel mondo reale.
Peter Mortensen,

@PeterMortensen È vero che ne trovi molto nel mondo reale. Ma non è nell'interesse di nessuno avere il codice scritto in quel modo. Penso che ci siano due ragioni per cui è così. L'educazione che gli sviluppatori ricevono ha fatto uno sforzo minimo nell'insegnare come scrivere codice leggibile. E in alcune aziende è percepito come una perdita di tempo: "Se lo sviluppatore ha già scritto un codice funzionante, perché dovrebbe importarci se è leggibile o no? Basta spedire la cosa".
Kasperd,

15

La verifica manuale della correttezza generale tramite la revisione del codice è tuttavia molto difficile e dispendiosa in termini di tempo, se possibile.

Molti anni fa, in realtà, il mio lavoro era fare esattamente questo valutando i compiti degli studenti. E mentre molti hanno fornito una qualità ragionevole con un bug qua e là, ce n'erano due che si sono distinti. Entrambi hanno sempre inviato codice privo di bug. Un codice inviato che ho potuto leggere dall'alto e dal basso ad alta velocità e contrassegnato come corretto al 100% senza sforzo. L'altro codice inviato era un WTF dopo l'altro, ma in qualche modo è riuscito a evitare eventuali bug. Un dolore assoluto da segnare.

Oggi il secondo avrebbe il suo codice rifiutato in una revisione del codice. Se verificare la correttezza è molto difficile e richiede molto tempo, allora questo è un problema con il codice. Un programmatore decente capirebbe come risolvere un problema (richiede tempo X) e prima di consegnarlo a un refattore di revisione del codice in modo che non faccia solo il lavoro, ma ovviamente lo faccia. Ciò richiede molto meno di X in tempo e fa risparmiare molto tempo in futuro. Spesso scoprendo i bug prima ancora di passare alla fase di revisione del codice. Quindi, rendendo la revisione del codice molto più rapida. E sempre in futuro, rendendo il codice più facile da adattare.

Un'altra risposta affermava che il codice di alcune persone poteva essere riformulato 10 volte, diventando ogni volta più leggibile. È solo triste. È uno sviluppatore che dovrebbe cercare un lavoro diverso.


Ci vuole molto meno tempo per refactificare il mio codice 10 volte, quindi mi ci vuole per scrivere la prima versione del codice. Se qualcun altro sa che ho fatto questo refactoring ho fallito.
Ian,

6

Questo vecchio codice è stato leggermente modificato? (100 righe di codice modificate in una codebase di 10000 righe sono ancora un leggero cambiamento) A volte ci sono vincoli di tempo e gli sviluppatori sono costretti a rimanere in un vecchio e scomodo framework, semplicemente perché una riscrittura completa richiederebbe ancora più tempo ed è fuori budget . + di solito c'è un rischio, che può costare milioni di dollari se valutato in modo errato. Se è un vecchio codice, nella maggior parte dei casi dovrai convivere con esso. Se non lo capisci da solo, parla con loro e ascolta quello che dicono, cerca di capire. Ricorda, può essere difficile da seguire per te, ma perfettamente bene per le altre persone. Prendi la loro parte, vedila dalla loro fine.

Questo nuovo codice è ? A seconda dei vincoli temporali, dovresti sostenere il refactoring il più possibile. Va bene dedicare più tempo alle revisioni del codice, se necessario. Non dovresti cronometrarti per 15 minuti, prendere l'idea e andare avanti. Se l'autore ha trascorso una settimana per scrivere qualcosa, va bene passare 4-8 ore per esaminarlo. Il tuo obiettivo qui è di aiutarli a refactoring. Non devi semplicemente restituire il codice che dice "refactor. Now". Scopri quali metodi possono essere scomposti, prova a trovare idee per introdurre nuove classi, ecc.


2
Non restituisci semplicemente il codice che dice "refactor. Now" - perché? Ho ricevuto tali commenti di recensione almeno una volta e l'ultima volta che ricordo che si è rivelato utile e corretto. Ho dovuto riscrivere un grosso pezzo di codice da zero e questa era la cosa giusta da fare perché guardando indietro ho visto da solo che il vecchio codice era un pasticcio invalicabile. Il recensore era semplicemente abbastanza qualificato per notare che (e apparentemente non lo ero)
moscerino del

4
@gnat: per uno, perché è scortese. Hai un aspetto migliore quando spieghi cosa non va nel codice e fai uno sforzo per aiutare l'altra persona a migliorarlo. In una grande azienda farlo altrimenti potrebbe farti uscire rapidamente dalla porta. Soprattutto se stai rivedendo il codice di una persona più anziana.
Neolisk,

quel caso che ho citato sopra, è stato in una grande azienda affermata che è capitato di essere abbastanza attento a non uscire dalla porta dei loro sviluppatori più qualificati, almeno non per motivi di condivisione diretta delle loro competenze tecniche quando richiesto
moscerino

1
@gnat: l'approccio "refactor. now" può funzionare verso il basso, cioè quando uno sviluppatore senior con oltre 10 anni di esperienza dice di refactoring a uno sviluppatore junior che è stato assunto 1 mese fa senza esperienza o situazione simile. Verso l'alto: potresti avere un problema. Poiché potresti non sapere quanta esperienza ha l'altro sviluppatore, è sicuro assumere il rispetto come comportamento predefinito. Non ti farà male di sicuro.
Neolisk,

1
@Neolisk: uno sviluppatore esperto che ha dovuto scrivere codice sotto la pressione del tempo e sa che non è abbastanza buono potrebbe essere troppo felice se rifiuti il ​​codice, dandogli tempo e una scusa per migliorarlo. Il PHB che decide che è abbastanza buono rende lo sviluppatore infelice; il recensore che decide che non è abbastanza buono lo rende felice.
gnasher729,

2

Spesso, patch / liste di modifiche "complicate" sono quelle che fanno molte cose diverse contemporaneamente. C'è nuovo codice, codice cancellato, codice refactored, codice spostato, test espansi; rende difficile vedere il quadro generale.

Un indizio comune è che la patch è enorme ma la sua descrizione è minuscola: "Implementa $ FOO".

Un modo ragionevole per gestire una tale patch è chiedere che sia suddiviso in una serie di pezzi più piccoli e autonomi. Proprio come il principio della responsabilità singola afferma che una funzione dovrebbe fare solo una cosa, una patch dovrebbe concentrarsi anche su una sola cosa.

Ad esempio, le prime patch potrebbero contenere refactoring puramente meccanici che non apportano modifiche funzionali, quindi le patch finali possono concentrarsi sull'attuazione e il test effettivi di $ FOO con meno distrazioni e aringhe rosse.

Per funzionalità che richiedono un sacco di nuovo codice, il nuovo codice può spesso essere introdotto in blocchi testabili che non modificano il comportamento del prodotto fino a quando l'ultima patch della serie non chiama effettivamente il nuovo codice (un flag flip).

Per quanto riguarda ciò, in modo tattico, di solito lo dico come un mio problema e quindi chiedo aiuto all'autore: "Ho problemi a seguire tutto ciò che accade qui. Potresti rompere questa patch in passaggi più piccoli per aiutarmi a capire come tutto si adatta insieme?" Talvolta è necessario fornire suggerimenti specifici per i passaggi più piccoli.

Una patch così grande come "Implement $ FOO" si trasforma in una serie di patch come:

  1. Introdurre una nuova versione di Frobnicate che richiede un paio di iteratori perché avrò bisogno di chiamarlo con sequenze diverse dal vettore per implementare $ FOO.
  2. Cambia tutti i chiamanti esistenti di Frobnicate per utilizzare la nuova versione.
  3. Elimina il vecchio Frobnicate.
  4. Frobnicate stava facendo troppo. Fattorizza il passo di aggiornamento nel proprio metodo e aggiungi i test per questo.
  5. Presenta Zerzify, con i test. Non ancora utilizzato, ma ne avrò bisogno per $ FOO.
  6. Implementa $ FOO in termini di Zerzify e il nuovo Frobnicate.

Si noti che i passaggi 1-5 non apportano modifiche funzionali al prodotto. Sono banali da revisionare, anche assicurandosi di avere tutti i test giusti. Anche se il passaggio 6 è ancora "complicato", almeno si concentra su $ FOO. E il registro ti dà naturalmente un'idea molto migliore di come è stato implementato $ FOO (e perché è stato cambiato Frobnicate).


Un approccio, se si utilizza Git, è comporre una richiesta pull di più commit. Ogni commit è il più atomico e autonomo possibile e ha una sua descrizione. Quindi, aggiungi una nota utile nel corpo PR che ogni modifica può essere rivista manualmente. In genere è così che gestisco PR di grandi dimensioni, come refactor globali o grandi cambiamenti di utensili non disponibili.
Jimmy Breck-McKye,

1

Come altri hanno sottolineato, la revisione del codice non è davvero progettata per trovare bug. Se durante la revisione del codice vengono rilevati dei bug, probabilmente significa che non si dispone di una copertura di test automatizzata sufficiente (ad es. Test di unità / integrazione). Se non c'è abbastanza copertura per convincermi che il codice fa quello che doveva , di solito chiedo altri test e sottolineo il tipo di casi di test che sto cercando e di solito non ammetto il codice nella base di codice che non ha una copertura adeguata .

Se l'architettura di alto livello è troppo complessa o non ha senso, di solito chiamo un incontro con un paio di membri del team per parlarne. A volte è difficile iterare su una cattiva architettura. Se lo sviluppatore era un principiante, di solito mi assicuro che passiamo in rassegna i loro pensieri in anticipo invece di reagire a una cattiva richiesta di pull. Questo di solito è vero anche con sviluppatori più esperti se il problema non ha una soluzione ovvia che sarà probabilmente scelta.

Se la complessità è isolata al livello del metodo che di solito può essere corretto in modo iterativo e con buoni test automatizzati.

Un ultimo punto. Come revisore devi decidere se la complessità del codice è dovuta a complessità essenziale o accidentale . La complessità essenziale riguarda le parti del software che sono legittimamente difficili da risolvere. La complessità accidentale si riferisce a tutte le altre parti del codice che scriviamo che è troppo complesso senza motivo e potrebbe essere facilmente semplificato.

Di solito mi assicuro che il codice con una complessità essenziale sia veramente questo e non possa essere ulteriormente semplificato. Miro anche a una maggiore copertura dei test e una buona documentazione per queste parti. La complessità accidentale dovrebbe essere quasi sempre ripulita durante il processo di richiesta pull perché sono la maggior parte del codice che trattiamo e possono facilmente causare incubo di manutenzione anche a breve termine.


0

Come sono i test? Dovrebbero essere chiari, semplici e facili da leggere con idealmente una sola affermazione. I test dovrebbero documentare chiaramente il comportamento previsto e i casi d' uso del codice.

Se non è ben testato, è un buon posto per iniziare la revisione.

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.