Codice inutile nella tua fonte


34

Ho sentito storie di questo da programmatori senior e ne ho visto un po 'da solo. Sembra che ci siano più di alcuni casi di programmatori che scrivono codice inutile. Vedrò cose come:

  • Chiamate di metodo o funzione che non fanno nulla di valore.
  • Controlli ridondanti eseguiti in un file di classe, oggetto o metodo separato.
  • if dichiarazioni che valutano sempre come vere.
  • Discussioni che si staccano e non fanno nulla di interessante.

Solo per citarne alcuni. Mi è stato detto che ciò è dovuto al fatto che i programmatori vogliono intenzionalmente confondere il codice per accrescere il proprio valore per l'organizzazione o assicurarsi di ripetere gli affari in caso di lavoro contrattuale o esternalizzato.

La mia domanda è. Qualcun altro ha visto codice come questo? Qual è stata la tua conclusione sul perché quel codice era lì?

Se qualcuno ha scritto codice come questo, puoi condividere il perché?


4
if (false) {...}i blocchi sono ottimi per commentare il codice! </
sarcasm

18
Non attribuire mai alla cattiveria ciò che è adeguatamente spiegato dalla stupidità , specialmente nello sviluppo di software in cui raramente gli hack rapidi temporanei sono temporanei.
Wildpeaks

1
@ dlras2 twist della trama: #DEFINE false true :)
Silviu Burcea,

Risposte:


17

Ho sentito sviluppatori che provano a rendere i loro risultati in codice più complessi di quanto non siano in realtà. Non ho mai sentito nessuno ammetterlo, ma ho visto un codice che soddisfa i tuoi criteri creato intenzionalmente per fretta o per cattive pratiche e non per sabotaggio. Il codice che circonda il codice diffamato potrebbe essere stato modificato al punto in cui una particolare funzione non è più utile.

Qualcuno dovrebbe effettivamente vedere questo codice in prima persona prima di giungere alla conclusione che solo questo sviluppatore può gestire la complessità. La maggior parte dei manager e degli altri uomini d'affari giunge a questa conclusione perché non comprendono alcun tipo di codice e non vogliono riempire la posizione.


2
Sono propenso a darti la risposta corretta in questo caso perché parte del codice che vedo semplicemente non può essere involontario ... non a meno che qualcuno fosse alto quando ha programmato e pensato che sarebbe stato divertente! Credo che anche altri abbiano ragioni rilevanti per il codice inutile, ma il codice che vedo riguarda progetti su cui alcune persone hanno lavorato e sono il primo al di fuori del team di sviluppo originale che ci sta lavorando. Devo dire che sembra un caso di complessità aggiunto allo shock e al timore reverenziale.
Ali,

18
@Ali: non attribuire mai alla malizia ciò che è meglio spiegato dall'incompetenza. In altre parole, probabilmente il codice si è evoluto in questo tipo di pasticcio perché nessuno era abbastanza coraggioso da spendere il tempo per guardarlo e vedere cosa fa realmente. Tutto ciò suona come un mucchio di soluzioni rapide applicate, ancora e ancora, fino a quando tutto ciò che rimane è un mucchio di schifo.
quick_now

1
+1 per @quickly_now. Di solito è quello che finisce per succedere; tutti hanno paura di toccare qualsiasi cosa "funzioni" per paura di romperlo (o, il Cielo proibisce, impiegando più tempo a migliorare il codice! L'orrore!). Quindi il codice marcisce e si esaurisce e alla fine crolla molti anni lungo la strada.
Wayne Molina,

@Ali, ci sono stati casi in cui il codice che sembra il più semantico e ragionevole è stato descritto come probabilmente penso che sia divertente o in mostra. E viceversa con me vedere il codice di altre persone. Non sai mai chi è pazzo, e la maggior parte delle volte dipende solo dall'esperienza e dalle preferenze. (non parliamo di codice oggettivamente negativo qui, solo che tali descrizioni sono facilmente gettate in giro)
Mihail Malostanidis

73

Non ho visto il codice in questo modo, ma ho visto il codice che sembra inutile o inutile per gli altri motivi:

  1. Retrocompatibilità. Hai trovato un modo molto migliore di fare le cose ma devi mantenere le API / funzioni vecchie (e ormai non molto utili) perché alcuni moduli di terze parti potrebbero utilizzare questa API / funzione per qualcosa. Anche se la funzione non fa nulla di utile, la sua assenza potrebbe rompere un po 'di codice.

  2. Codifica difensiva. Sai che i controlli in questo codice sono inutili perché erano già stati controllati altrove. Ma cosa succede se qualcuno cambia questo codice altrove e rimuove o modifica i controlli in modo che non corrispondano più ai tuoi requisiti?

  3. Crescita organica. Nei grandi progetti, nel corso degli anni molte cose cambiano e si scopre che alcuni metodi che sono stati usati prima non vengono più utilizzati, ma nessuno si è preso la briga di rimuoverli poiché nessuno ha tenuto traccia di se questo metodo specifico è usato o no, hanno semplicemente refactored i loro pezzi di codice e per caso è successo che tutti si sono fermati a usare questo metodo. O condizioni che una volta avevano significato ma l'applicazione veniva rifattorizzata in altri luoghi in modo tale condizione diventasse sempre vera ma nessuno si prendeva la briga di rimuoverla.

  4. Over-progettazione. La gente potrebbe codificare alcune cose "nel caso in cui ne avessimo bisogno" e non ne abbia mai realmente bisogno. Come "generiamo un thread nel caso dovessimo fare un po 'di lavoro offline" e quindi nessuno chiede di fare qualcosa offline e il programmatore se ne dimentica e passa ad altri progetti (o forse anche un'altra società) e quel codice rimane lì per sempre perché nessuno sa perché è lì o se è sicuro rimuoverlo.

Quindi, anche se non l'ho mai visto fatto per cattiveria o approccio errato alla sicurezza del lavoro, ho visto tonnellate di volte in cui si verifica come risultato naturale dello sviluppo del software.


22
Penso che la crescita organica n. 3 spieghi gran parte del codice inutile che ho visto sul lavoro. Ma tutte e 4 queste ragioni assumono un programmatore intelligente. Alcuni codici inutili derivano da qualcuno che non capisce cosa deve accadere e cosa no e che lascia molto codice puramente per paura di cambiare ciò che (in qualche modo) funziona.
Bruce Ediger,

2
Ho visto il n. 4 nel mio progetto: spesso non è fatto apposta per avere più potere all'interno dell'azienda, piuttosto ci sono persone che cercano sempre di creare una soluzione più generale, anche se non è necessaria. Per quanto riguarda il n. 2, lo uso molto da solo per i motivi che hai spiegato: IMHO anche la funzione o il metodo più piccoli non dovrebbero fare ipotesi su come funziona il resto del codice o cambierà. Invece, il mio codice segue il modello semplice: "se input OK allora output altro errore". Ciò segue il principio generale di progettazione di minimizzare le dipendenze.
Giorgio,

3
Hai anche dimenticato: cattivi sviluppatori. Alcune persone che scrivono codice non dovrebbero esserlo e in molti negozi non esistono buoni processi di revisione.
Joe,

20

La mia domanda è. Qualcun altro ha visto codice come questo? Qual è stata la tua conclusione sul perché quel codice era lì?

1) Sì

2) Nei casi che ho visto, l'ho messo in modo diverso per:

  • Inesperienza del programmatore
  • Il programmatore non capisce un progetto particolarmente complicato e / o mal eseguito che sta tentando di modificare
  • Il programmatore viene interrotto nel mezzo di (diciamo) un refactor.
  • trascuratezza

Ora forse sono caritatevole al riguardo, ma il mio approccio generale è che è meglio essere indulgenti / non conflittuali su queste cose, piuttosto che puntare le dita e andare avanti con scarsa qualità. Ovviamente, le cose potrebbero diventare abbastanza grave che qualcosa deve essere fatto , ma un colpetto delicato nella giusta direzione è di solito sufficiente.

Ovviamente, non è possibile adottare un approccio così lassista se la qualità / gli errori avranno un impatto serio sul "business". Ma in quella situazione sono necessarie revisioni del codice obbligatorie e diligenti di tutto, combinate con una procedura di prova completa.


Nella mia esperienza, le persone tendono a "tenersi strette" riguardo al codice di scarsa qualità (almeno in parte) perché offende i loro standard personali. Va benissimo (personalmente) lottare per la perfezione, ma è un po 'irragionevole proiettare i propri standard personali su altre persone. Dai suoni delle cose (ad es. Dalla natura dei tuoi esempi), questo è ciò che stai facendo.

IMO, questo non è produttivo e non favorisce un buon rapporto di lavoro con i tuoi colleghi.


+1 Stavo scrivendo una risposta e ti ho trovato praticamente elencato tutti i motivi che avrei menzionato.
canadese

+1 per essere caritatevoli. Correggi gli errori di qualcuno senza puntare le dita e i tuoi colleghi rispetteranno sia le tue capacità tecniche che le tue abilità personali. Harangue l'autore per il loro codice schifoso e i tuoi colleghi si risentiranno del tuo approccio e ridurranno le tue abilità.
Caleb,

13

Tutti questi sono spesso sintomi dell'invecchiamento di un progetto.

 1. Chiamate di metodo o funzione che non fanno nulla di valore. Ci sono molte volte in cui un po 'di codice viene semplicemente lasciato com'è (si spera con un grande avviso deprecato , ma poiché la maggior parte delle lingue non ha quell'avviso, non viene sempre seguito ...) perché, a un certo punto, ha servito un po' vero scopo e nessuno sapeva cosa sarebbe potuto succedere se le linee offensive fossero state rimosse.

Mi sembra di ricordare questo da un dailywtf:

@deprecated // he might have been crazy enough to use reflection...
boolean getTrue() {
    return false; 
}

 2. Controlli ridondanti eseguiti in un file di classe, oggetto o metodo separato. Anche gli strati di comunicazione sono imperfetti (mai letto il Mese dell'uomo mitico? In caso contrario, cosa stai facendo al computer !? Vai! LEGGI!). Spesso, una persona lavorerà su qualcosa e poi lascerà il progetto, e poi il ragazzo successivo, trovando qualche bizzarro bug, lancia un controllo extra qua e là per cercare di eliminarlo. Quando il bug viene rimosso, i controlli non sono perché, beh, se non è rotto, non risolverlo.

 3. se dichiarazioni che valutano sempre come vere. Oh, l'ho fatto io. Ho avuto un progetto una volta, aveva una serie di blocchi probabilmente 10-15 if / else . Per cambiare il comportamento, ho semplicemente messo un true||al primo blocco. Solo dopo mesi (anni?) Sono tornato e ho detto: "Oh, wow, questo codice avrebbe dovuto essere distrutto ma non lo è mai stato"

 4. Discussioni che si staccano e non fanno nulla di importante. Posso immaginare una linea di pensiero che vada così:

  1. Lo so! Riesco a gestire questi due problemi in modo asincrono! Creerò discussioni foo e bar.
  2. (due mesi dopo) Eh, sai, la funzionalità da bar è un po 'meglio in foo. Ne sposterò un po '.
  3. (un anno dopo) Sai, mettere in ordine questa roba da bar a foo.
  4. (molti, molti anni dopo) "Ehi, questo barthread non sembra che stia facendo nulla, possiamo rimuoverlo?" "Meglio di no, è stato lì molti, molti anni ..."

5
+1 per "Meglio di no, è stato lì molti, molti anni ..." - questo succede ancora e ancora. Paura di rimuovere a causa della paura delle conseguenze ("Come testiamo che non abbiamo rotto qualcosa" - specialmente se non ci sono test unitari in giro).
quick_now

11

Sono un po 'più ottimista. Penso che ciò che hai descritto spesso si verifichi quando il codice viene refactored con noncuranza.


13
Sebbene sia difficile, non attribuire mai a Malice ciò che può essere spiegato dalla stupidità.
Bruce Ediger,

8

I vecchi colleghi mi hanno raccontato di un'epoca in cui i consulenti venivano pagati per il numero di righe di codice che producevano. E così hanno massimizzato i profitti usando costrutti incredibilmente lunghi.

Oggi presumo sempre che il ragazzo stia ancora imparando la lingua mentre fa il lavoro. E ha fretta.


Parla di tagliarti il ​​naso per far dispetto al tuo viso. Immagino sia ok se non dovessi mai più guardare il codice.
JeffO,

6

La maggior parte delle risposte si riduce a questi due semplici fatti:
[1] Il codice riflette la storia del codice e
[2] Il codice riflette il futuro atteso del codice.

Ho scritto funzioni che non fanno nulla di valore, NELL'AMBIENTE ATTUALE DELL'APPLICAZIONE date le SPECIFICHE ATTUALI, ma che potrebbero essere necessarie in futuro.

Ho scritto dichiarazioni if ​​che, AL PRESENTE, valutano sempre come vere. Ma forse in passato potrebbe essere falso.

Per quanto riguarda i controlli ridondanti, ehi, non mi fido di altro codice, non mi fido nemmeno del mio codice. Se un modulo dipende dal fatto che N sia 1 o 2 o 3 dannatamente bene, assicurati di farlo e, se non lo è, blocca in modo informativo. È illegittimo esplodere per il Modulo B perché il Modulo A ha sbagliato; è abbastanza legittimo per il Modulo B lamentarsi che il Modulo A abbia sbagliato. E ricorda che, il mese prossimo, quel parametro potrebbe provenire dal Modulo C. non ancora scritto.


1
Io chiamo quella cattiva codifica. Ti aspetti di averne bisogno in futuro, ma ciò accade raramente. YAGNI. Scrivere un if che valuta sempre come vero è uno sforzo sprecato e confuso la persona che deve aggiungere con tutta probabilità funzionalità diverse. Quel parametro che arriverà il prossimo mese può attendere fino al prossimo mese per essere aggiunto. Il codice di disordine ORA è inutile.
Andy,

1
if (language = 'en' o language = th ') - forse il mese prossimo proveremo il cinese? if (! isset ($ TITLE)) - tutti i moduli sono SUPPOSTI per impostare $ TITLE, ma forse un giorno qualcuno lo scriverà male. if (file_exists ($ TARGET)) - un buon codice avrà già creato il file, ma forse c'è un errore di sistema e non è stato creato. Il mio codice di interfaccia PHP / MySQL standard verifica sempre eventuali errori, anche se non ne ho ancora individuato uno.
Andy Canfield,

3

L'ho visto alcune volte, infatti proprio ieri, devo unire alcuni dei miei codici boss nella mia nuova app. Nel suo caso si tratta solo di una generale mancanza di abilità e comprensione e della convinzione di pensare di essere uno sviluppatore abbastanza abile.

"Chiamate di metodo o funzione che non fanno nulla di valore." e "se dichiarazioni che valutano sempre come vere" sono un grosso problema con il suo codice.


3

Ho il sospetto che, sebbene molti abbiano visto il codice che presenta questi problemi, pochi sarebbero disposti a scrivere lo stesso. Con ogni probabilità, quello che vedi è il marciume del software accumulato: qualcuno aggiunge qualcosa, che non funziona davvero, il manutentore successivo aggiunge un codice di protezione lungo la catena per proteggersi dalle condizioni che non sono state correttamente verificate nel primo posto; quindi qualcuno riceve una segnalazione di problemi e aggiunge ancora più armature contro una specifica istanza di un problema; un'altra persona aggiunge un controllo più generale e si dimentica di rimuovere parte del vecchio codice aggiunto in precedenza che si occupava di sintomi più specifici, ecc.

Poi c'è il problema della pulizia del codice: non c'è nessun particolare incentivo a rimuovere quello che sembra essere il codice morto, e tremenda incentivi non farlo, perché se non si capisce il codice completamente, la sua valutazione che il codice è "morto" volontà essere imperfetto e finirai per rompere il sistema.


2
  • Chiamate di metodo o funzione che non fanno nulla di valore.

Non necessariamente male. I metodi in una classe base spesso chiamano metodi vuoti intesi come punti di sostituzione per le sottoclassi. Esempio: UIView di Cocoa Touch ha un -didAddSubview:metodo documentato come non fare nulla nella versione predefinita. Il -addSubview:metodo di UIView deve chiamare -didAddSubview:anche se non fa nulla perché le sottoclassi possono implementarlo per fare qualcosa. I metodi che non fanno nulla e le relative motivazioni dovrebbero essere documentati, ovviamente.

Se una funzione / metodo vuoto o inutile è ovviamente lì per ragioni storiche, dovrebbe essere escesso. Dai un'occhiata alle versioni precedenti del codice nel repository del codice sorgente se non sei sicuro.

  • Controlli ridondanti eseguiti in un file di classe, oggetto o metodo separato.

Difficile dire se va bene senza un certo contesto. Se i controlli vengono eseguiti chiaramente per lo stesso motivo, ciò può significare che non esiste una chiara separazione delle responsabilità e si richiede un refactoring, specialmente quando entrambi i controlli comportano lo stesso intervento. Se l'azione risultante da entrambi i controlli non è la stessa, probabilmente i due controlli vengono eseguiti per motivi diversi anche se la condizione è la stessa, e probabilmente va bene.

  • se dichiarazioni che valutano sempre come vere.

C'è una grande differenza tra:

if (1) {
    // ...
}

e:

if (foo() == true) {
    // ...
}

dove foo()capita di tornare sempre true.

Il primo caso accade molto quando le persone eseguono il debug. E 'facile da usare un if (0) {...rimuovere temporaneamente un pezzo di codice mentre si sta cercando di isolare un bug, e quindi modificare il 0per 1ripristinare quel codice. L' ifdovrebbero essere rimossi una volta che il gioco è fatto, naturalmente, ma è facile dimenticare quel passo, o di perdere uno o due se avete fatto in più punti. (È una buona idea identificare tali condizionali con un commento che puoi cercare in seguito.) L'unico danno è la confusione che potrebbe causare in futuro; se il compilatore può determinare il valore della condizione al momento della compilazione, lo rimuoverà completamente.

Il secondo caso può essere accettabile. Se la condizione rappresentata foo()deve essere testata da diversi punti del codice, il factoring in una funzione o un metodo separato è spesso la cosa giusta da fare anche se foo()sembra essere sempre vero in questo momento. Se è concepibile che foo()alla fine potrebbe tornare false, isolare quella condizione in un metodo o una funzione è un modo per identificare tutti i luoghi in cui il codice si basa su quella condizione. Tuttavia , ciò comporta il rischio che la foo() == falsecondizione non venga testata e che possa causare problemi in un secondo momento; la soluzione è assicurarsi di aggiungere unit test che testano esplicitamente il falsecaso.

  • Discussioni che si staccano e non fanno nulla di interessante.

Sembra un artefatto della storia e qualcosa che potrebbe essere identificato durante una revisione del codice o attraverso la profilazione periodica del software. Suppongo che potrebbe essere creato intenzionalmente, ma ho difficoltà a immaginare che qualcuno lo farebbe apposta.


1

Succede. Abbastanza spesso in realtà.

A volte questi vicoli ciechi di codice sono più simili a vecchie scie di capre che sono cadute in rovina quando intorno a loro è stata installata un'autostrada più efficiente / moderna / veloce.

In altre occasioni (e probabilmente sono colpevole di questo), sono le basi per l'estensione del software quando viene richiesto un set di caratteristiche / funzioni breve ma non confermato. (A volte mettere un po 'di lavoro nella build iniziale fornendo maniglie e simili per il lavoro successivo che prevedi di "imbullonare" può rendere la vita più facile, quando succede, o più difficile / disordinata se il lavoro successivo non lo fa eventuate.)

E molto è direttamente dovuto al vecchio "Se non è rotto, non adattarlo." A volte strappare il codice che non si capisce o che non si ritiene inutilizzato può causare la versione di programmazione di "The Butterfly Effect". Anche questo è successo una o due volte.


1

A volte avrò un valore booleano globale impostato su true, e successivamente nel mio codice un if (bool), quindi durante il runtime, potrei impostare un punto di interruzione sull'istruzione if e cambiare il valore booleano per testare qualcosa.


0

Mi oppongo alle if truedichiarazioni di essere indiscriminatamente classificati come "codice inutile".

Esiste un caso legittimo per l'utilizzo di un if (1) { ... }blocco nel codice C che vuole essere compatibile con lo standard C che insiste sul fatto che le definizioni delle variabili siano all'inizio di una funzione, o semplicemente vuole che le variabili locali siano definite il più localmente possibile.

switch (i) {
    case 23:
        if (1) {
            /* I can declare a local var here! */
        }
        break;
}

5
Non è necessario il 'if (1)', perché non avere il blocco?
FigBug,

3
Sia C / C ++ che C #, e sono abbastanza sicuro che Java (così come probabilmente molti altri linguaggi simili) consentano blocchi di istruzioni anonime; nessuna necessità di un if, whileo costrutto simile. È improbabile che sia molto pulito, ma è certamente consentito in base alle specifiche della lingua.
un CVn il

0

Un mio professore ci raccontò una storia secondo cui un precedente datore di lavoro li avrebbe pagati in base al numero di righe completate. Quindi, hanno scritto diverse dozzine di funzioni allineate che non sono mai state chiamate. Sembra un ottimo motivo per scrivere codice inutile.


0

Come accennato da @Andy, un grande componente che ho visto sta rompendo YAGNI .

Qualcuno inizia con un'ipotesi su quali saranno tutti gli elementi invece di ciò di cui molti elementi potrebbero aver bisogno , il che è una confusione delle relazioni "è un" e "ha un" .

Questa confusione porta a una rigida struttura ereditaria e quindi sono metodi che non vengono implementati perché non vengono mai effettivamente chiamati, logica ripetuta in cui le parti devono essere modificate e flussi di lavoro generalmente strani che non si allineano al modello aziendale.

Come molti altri qui, non l'ho visto fatto maliziosamente, ma per mancanza di conoscenza del buon design e del tentativo di farlo sembrare così agli altri. Divertente, sembra che gli sviluppatori anche meno esperti sembrino fare meglio in questo senso, perché almeno il loro codice non finisce per essere troppo ingegnerizzato fino al naseo. ( Principio KISS )

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.