La copertura del codice evidenzia metodi inutilizzati: cosa devo fare?


59

Mi è stato assegnato il compito di aumentare la copertura del codice di un progetto Java esistente.

Ho notato che lo strumento di copertura del codice ( EclEmma ) ha evidenziato alcuni metodi che non sono mai stati chiamati da nessuna parte.

La mia reazione iniziale non è quella di scrivere unit test per questi metodi, ma di evidenziarli al mio responsabile / team di linea e chiedermi perché queste funzioni siano lì per cominciare.

Quale sarebbe l'approccio migliore? Scrivi test unitari per loro o chiedi perché sono lì?


1
I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
maple_shaft

Risposte:


118
  1. Elimina.
  2. Commettere.
  3. Dimenticare.

Fondamento logico:

  1. Il codice morto è morto. Per la sua stessa descrizione non ha scopo. Potrebbe aver avuto uno scopo ad un certo punto, ma è sparito, e quindi il codice dovrebbe essere sparito.
  2. Il controllo della versione assicura che nel raro ( unico nella mia esperienza) raro evento che qualcuno si presenti in seguito alla ricerca di quel codice possa essere recuperato.
  3. Come effetto collaterale, puoi migliorare istantaneamente la copertura del codice senza fare nulla (a meno che il codice morto sia testato, cosa che accade raramente).

Avvertenza dai commenti: la risposta originale presupponeva che tu avessi verificato accuratamente che il codice è, senza dubbio, morto. Gli IDE sono fallibili e ci sono molti modi in cui il codice che sembra morto potrebbe in effetti essere chiamato. Entra in un esperto se non sei assolutamente sicuro.


118
In generale, sarei d'accordo con questo approccio, ma se sei nuovo in un progetto e / o uno sviluppatore junior, è meglio chiedere al tuo mentore / superiore prima di eliminare. A seconda del progetto, alcuni metodi potrebbero non sembrare usati ma essere chiamati / utilizzati da un codice esterno non nel codice di progetto a cui si ha accesso. Potrebbe essere un codice generato automaticamente, quindi la tua rimozione non produrrà altro che rumore della cronologia dei registri. Il tuo IDE potrebbe non essere in grado di trovare l'accesso basato sulla riflessione all'interno del progetto. Ecc. Pp. Se non sei sicuro di tali casi angolari, chiedi almeno una volta.
Frank Hopkins,

11
Sebbene io sia d'accordo con il nocciolo di questa risposta, la domanda letterale era "dovrei chiedermi perché sono lì?" . Questa risposta potrebbe dare l'impressione che l'OP non dovrebbe chiedere al proprio team prima di essere eliminato.
Doc Brown,

58
Prima aggiungerei un passaggio: controlla il registro degli errori git per le righe di codice non utilizzate. Se riesci a trovare la persona che li ha scritti, puoi chiedere a cosa servono. Se le linee sono nuove allora c'è una buona probabilità che qualcuno abbia intenzione di usarle presto (nel qual caso probabilmente dovrebbero essere testate in unità ora).
bdsl,

10
Ci sono così tante cose sbagliate in questa risposta, come espresso nei commenti o in altre risposte, che non posso credere che questa sia la risposta più votata e accettata.
user949300,

11
@Emory Il modo migliore per iniziare in una nuova squadra è rompere la build eliminando incautamente le cose perché pensavi che nessuno ne avesse bisogno. Garantisce la tua popolarità dal primo giorno. Sicuramente potrebbe non essere necessario (perché ogni applicazione più grande e vecchia ha sempre tosse con copertura del codice del 100% ), ma è un ROI molto negativo.
Voo,

55

Tutte le altre risposte si basano sul presupposto che i metodi in questione siano realmente inutilizzati. Tuttavia, la domanda non specifica se questo progetto è autonomo o una libreria di qualche tipo.

Se il progetto in questione è una libreria, i metodi apparentemente inutilizzati potrebbero essere utilizzati al di fuori del progetto e rimuoverli potrebbe interrompere tali altri progetti. Se la biblioteca stessa viene venduta ai clienti o resa disponibile pubblicamente, potrebbe anche essere impossibile rintracciare l'utilizzo di questi metodi.

In questo caso, ci sono quattro possibilità:

  • Se i metodi sono privati ​​o pacchetto-privati, possono essere rimossi in modo sicuro.
  • Se i metodi sono pubblici, la loro presenza può essere giustificata anche senza un utilizzo effettivo, per completezza delle funzionalità. Dovrebbero essere testati però.
  • Se i metodi sono pubblici e non necessari, rimuoverli sarà una modifica sostanziale e se la libreria segue il controllo delle versioni semantico , ciò è consentito solo in una nuova versione principale.
  • In alternativa, i metodi pubblici possono anche essere deprecati e rimossi in seguito. Ciò concede un po 'di tempo ai consumatori di API per passare dalle funzioni obsolete prima che vengano rimosse nella prossima versione principale.

9
Inoltre, se si tratta di una libreria, le funzioni sono lì per completezza
PlasmaHH,

Puoi approfondire come dovrebbero essere testati? Se non sai perché il metodo esiste, probabilmente non sai cosa dovrebbe fare.
No U,

I nomi dei metodi come filter_name_exists, ReloadSettingso addToSchema(scelti casualmente da 3 progetti arbitrari open source) dovrebbero fornire alcuni suggerimenti su cosa dovrebbe fare il metodo. Un commento javadoc può essere ancora più utile. Non è una specifica adeguata, lo so, ma potrebbe essere sufficiente per creare alcuni test che potrebbero prevenire almeno le regressioni.
Zoltan,

1
i metodi pubblici su una classe o interfaccia privata non devono essere considerati pubblici a questo scopo. allo stesso modo se una classe pubblica è nidificata all'interno di una classe privata, non è realmente pubblica.
emory

30

Prima controlla che il tuo strumento di copertura del codice sia corretto.

Ho avuto situazioni in cui non hanno rilevato i metodi chiamati tramite riferimenti all'interfaccia o se la classe è stata caricata in modo dinamico da qualche parte.


Grazie, lo farà. Su Eclipse, eseguo una ricerca su base di codice per la funzione e non viene visualizzato nulla. Se hai altri suggerimenti su come effettuare una ricerca più completa, ti sarei molto grato.
Lucas T,

3
sì, dovresti controllare altri progetti che potrebbero importare la classe come dll
Ewan,

7
Questa risposta sembra incompleta. "Prima controlla che il tuo strumento di copertura del codice sia corretto. Se lo è, allora .... [inserisci il resto della risposta] ". In particolare, l'OP vuole sapere cosa fare se lo strumento di copertura del codice è corretto.
Jon Bentley,

1
@jonbentley L'OP chiede l'approccio migliore al rapporto sugli strumenti. "Controlla manualmente" perché è abbastanza ovvio dal contesto che è errato
Ewan

15

Dato che Java è compilato staticamente, dovrebbe essere abbastanza sicuro rimuovere i metodi. La rimozione del codice morto è sempre buona. C'è qualche probabilità che esista un sistema di riflessione pazzo che li esegue in fase di esecuzione, quindi controlla prima con altri sviluppatori, ma altrimenti rimuovili.


9
+1 per il controllo con le persone, è un po 'seguendo il principio della minima sorpresa. Non vuoi che qualcuno passi troppo tempo a cercare il metodo appena lasciato lì qualche commit in precedenza. Inoltre, in alcuni casi limite, il codice morto potrebbe essere la nuova roba che è già stata archiviata ma non ancora cablata da nessuna parte (anche se in questo caso dovrebbe essere ben documentata con commenti e testata).
Frax,

4
Beh, a meno che il codice non usi il riflesso per chiamare i metodi "non utilizzati", ma in quel caso hai problemi molto più grandi, e non vediamo l'ora di vedere il codice su thefailywft.com (Fai un rapido test per vedere se un codice fa un ClassName. classe).
Mentre

2
È compilato staticamente, ma c'è anche l' invokedynamicistruzione, quindi, sai ...
corsiKa

@MTilsted: ci sono molti framework che chiameranno il codice usando le stringhe - posso pensare almeno a Spring e Hibernate dalla parte superiore della mia testa.
jhominal

9

Quale sarebbe l'approccio migliore? Scrivi test unitari per loro o chiedi perché sono lì?

L'eliminazione del codice è una buona cosa.

Quando non puoi eliminare il codice, puoi sicuramente contrassegnarlo come @Deprecated , documentando quale versione principale stai prendendo di mira per rimuovere il metodo. Quindi puoi eliminarlo "più tardi". Nel frattempo, sarà chiaro che non dovrebbe essere aggiunto alcun nuovo codice che dipende da esso.

Non consiglierei di investire in metodi deprecati, quindi nessun nuovo test unitario solo per raggiungere gli obiettivi di copertura.

La differenza tra i due è principalmente se i metodi fanno parte o meno dell'interfaccia pubblicata . L'eliminazione arbitraria di parti dell'interfaccia pubblicata può rappresentare una spiacevole sorpresa per i consumatori che dipendono dall'interfaccia.

Non posso parlare con EclEmma, ​​ma dalle mie esperienze una delle cose di cui devi fare attenzione è la riflessione. Se, ad esempio, usi i file di configurazione del testo per scegliere a quali classi / metodi accedere, la distinzione usata / non usata potrebbe non essere ovvia (ne sono stato bruciato un paio di volte).

Se il tuo progetto è una foglia nel grafico delle dipendenze, il caso della deprecazione è indebolito. Se il tuo progetto è una libreria, il caso della deprecazione è più forte.

Se la tua azienda utilizza un mono-repo , l'eliminazione comporta un rischio inferiore rispetto al caso multi-repo.

Come notato da l0b0 , se i metodi sono già disponibili nel controllo del codice sorgente, recuperarli dopo l'eliminazione è un esercizio semplice. Se eri davvero preoccupato di doverlo fare, rifletti su come organizzare i tuoi commit in modo da poter recuperare le modifiche cancellate se ne hai bisogno.

Se l'incertezza è abbastanza elevata, potresti considerare di commentare il codice , piuttosto che eliminarlo. È un lavoro extra nel percorso felice (in cui il codice eliminato non viene mai ripristinato), ma semplifica il ripristino. La mia ipotesi è che dovresti preferire una cancellazione diretta fino a quando non ne sei stato bruciato un paio di volte, il che ti darà alcune idee su come valutare "l'incertezza" in questo contesto.

domanda perché sono lì?

Il tempo impiegato per catturare la tradizione non è necessariamente perso. Sono stato conosciuto per eseguire una rimozione in due passaggi: in primo luogo, aggiungendo e facendo un commento che spiega ciò che abbiamo imparato sul codice, e successivamente cancellando il codice (e il commento).

Potresti anche usare qualcosa di analogo ai record di decisione dell'architettura come un modo per catturare la tradizione con il codice sorgente.


9

Uno strumento di copertura del codice non è onnisciente, onniveggente. Solo perché il tuo strumento afferma che il metodo non è chiamato, ciò non significa che non sia chiamato. C'è una riflessione e, a seconda della lingua, potrebbero esserci altri modi per chiamare il metodo. In C o C ++ potrebbero esserci macro che costruiscono nomi di funzioni o metodi e lo strumento potrebbe non vedere la chiamata. Quindi il primo passo sarebbe: eseguire una ricerca testuale per il nome del metodo e per i nomi correlati. Chiedi a colleghi esperti. Potresti scoprire che è effettivamente utilizzato.

Se non si è sicuri, inserire un assert () all'inizio di ciascun metodo "non utilizzato". Forse viene chiamato. O una dichiarazione di registrazione.

Forse il codice è effettivamente prezioso. Potrebbe essere un nuovo codice su cui un collega ha lavorato per due settimane e che avrebbe acceso domani. Non si chiama oggi perché la chiamata verrà aggiunta domani.

Forse il codice è in realtà prezioso parte 2: il codice potrebbe eseguire alcuni test di runtime molto costosi che sarebbero in grado di trovare le cose che non vanno. Il codice viene attivato solo se le cose effettivamente vanno male. È possibile che tu stia eliminando un prezioso strumento di debug.

È interessante notare che il peggior consiglio possibile "Elimina. Commit. Dimentica." è il più votato. (Revisioni del codice? Non esegui revisioni del codice? Cosa diavolo stai programmando se non esegui revisioni del codice?)


Non sono rispettosamente d'accordo sul fatto che "ELIMINA. IMPEGNA. DIMENTICATI" sia il peggior consiglio. (Penso che sia il migliore.) Anche il tuo approccio è OK. Penso che il peggior consiglio possibile sarebbe quello di scrivere unit test che esercitino il "codice morto" ma non facciano affermazioni. Lo strumento di copertura del codice verrà ingannato nel pensare che vengano utilizzati.
emory

3
Nulla nella risposta "Elimina. Impegna. Dimentica" dice di non eseguire la revisione del codice. È perfettamente possibile (e consigliabile, IMHO) rivedere il codice dopo che è stato eseguito il commit (ma prima della distribuzione :-)).
sleske,

@sleske Come rivedi il codice che non c'è più? Né quella risposta menziona "revisione".
user949300

@ user949300: se una modifica al codice deve essere esaminata o meno è una domanda separata e indipendentemente dal fatto che il codice venga aggiunto, modificato o eliminato (l'aggiunta di codice può essere ancora più disastrosa rispetto all'eliminazione, vedere ad esempio la vulnerabilità Heartbleed). Inoltre, la risposta (ora) dice di "attirare un esperto", che sembra abbastanza vicino a una revisione del codice.
sleske,

1
@ user949300: Quanto a "Come riesaminare il codice che non c'è più" - Spero sia ovvio: osservando la modifica dello strumento di controllo della versione prescelto. In quale altro modo rivedere le modifiche (eventuali modifiche)?
sleske,

6

A seconda dell'ambiente in cui viene eseguito il software, è possibile accedere se il metodo viene mai chiamato. Se non viene chiamato entro un periodo di tempo adeguato, il metodo può essere rimosso in modo sicuro.

Questo è un approccio più cauto rispetto alla semplice eliminazione del metodo e può essere utile se si esegue in un ambiente altamente sensibile ai guasti.

Accediamo a un #unreachable-codecanale dedicato dedicato con un identificatore univoco per ciascun candidato per la rimozione ed è stato dimostrato che è abbastanza efficace.



allora "un periodo di tempo adeguato" è più lungo (anche se a me piace un "uomo dopo mezzanotte")
Jamie Bull,
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.