Quali cose suonano all'istante quando suona il codice? [chiuso]


98

Ho partecipato a un evento di artigianato del software un paio di settimane fa e uno dei commenti fatti è stato "Sono sicuro che tutti riconosciamo il codice errato quando lo vediamo" e tutti hanno annuito in modo sagace senza ulteriori discussioni.

Questo genere di cose mi preoccupa sempre perché c'è quel vero che tutti pensano di essere un guidatore sopra la media. Anche se penso di poter riconoscere il codice errato, mi piacerebbe saperne di più su ciò che gli altri considerano odori di codice poiché raramente è discusso in dettaglio nei blog delle persone e solo in una manciata di libri. In particolare, penso che sarebbe interessante sentire qualcosa che puzza di codice in una lingua ma non in un'altra.

Inizierò con uno semplice:

Codice nel controllo del codice sorgente che ha un'alta percentuale di codice commentato - perché è lì? doveva essere cancellato? è un lavoro a metà finito? forse non avrebbe dovuto essere commentato e fatto solo quando qualcuno stava testando qualcosa? Personalmente trovo questo tipo di cose davvero fastidioso anche se è solo la strana linea qua e là, ma quando vedi blocchi di grandi dimensioni intervallati dal resto del codice è totalmente inaccettabile. Di solito è anche un'indicazione che il resto del codice sarà probabilmente di dubbia qualità.


61
A volte incontro persone che commentano il codice, fanno il check-in e dicono "Potrei averne di nuovo bisogno in futuro - se lo rimuovo ora lo perderò". Devo contrastare con "Er, ... ma è a questo che serve il controllo del codice sorgente".
Talonx,

6
A volte, in particolare durante l'ottimizzazione, è utile lasciare il vecchio codice come commento, quindi sai cosa sostituisce il oscuro codice ottimizzato. Pensa di lasciare uno swap a 3 righe con temp in posizione quando lo sostituisci con uno swap a bit di una riga. (Anche se, non vedo la necessità di utilizzare una sola linea di swap - MAI, a meno che dimensione del programma è di importanza critica.)
Chris Cudmore

4
Sto mantenendo / ripulendo il codice scritto da uno dei nostri ingegneri, che ha codificato alcune cose utili ma ammette di non essere un programmatore. Mentre consolido le cose, commenterò il suo vecchio codice e poi esamineremo le modifiche e gli mostrerò come ho sostituito il suo con qualcosa di più piccolo / più efficiente / più facile da capire. Successivamente rimuovo quei blocchi e poi lo controllo. Avere il vecchio codice lì ha dei vantaggi perché vede come le cose possono essere fatte più semplicemente e mi ricordo perché ho cambiato le cose quando parliamo.
Tin Man,

8
Lascio cose che "potrebbero essere usate" per 1 commit, quindi se le cose non si rompono o non viene trovata un'esigenza, viene rimossa al successivo commit.
Paul Nathan,

24
Hmm. printf("%c", 7)di solito suona un campanello d'allarme per me. ;)

Risposte:


128
/* Fuck this error */

Tipicamente trovato all'interno di un try..catchblocco senza senso , tende ad attirare la mia attenzione. Quasi pure /* Not sure what this does, but removing it breaks the build */.

Un altro paio di cose:

  • Più ifistruzioni complesse nidificate
  • Blocchi Try-catch utilizzati per determinare un flusso logico su base regolare
  • Funzioni con nomi generici process, data, change, rework,modify
  • Sei o sette diversi stili di controventatura in 100 linee

Uno che ho appena trovato:

/* Stupid database */
$conn = null;
while(!$conn) {
    $conn = mysql_connect("localhost", "root", "[pass removed]");
}
/* Finally! */
echo("Connected successfully.");

Bene, perché dover forzare le tue connessioni MySQL è il modo giusto di fare le cose. Si scopre che il database stava avendo problemi con il numero di connessioni, quindi hanno continuato a scadere. Invece di eseguire il debug di questo, hanno semplicemente tentato ancora e ancora finché non ha funzionato.


19
Se solo potessi votare questo 6 volte! Tutti buoni esempi. Inoltre, non mi piacciono i commenti arroganti / divertenti (specialmente se includono la parolaccia): potrebbe essere leggermente divertente la prima volta che li leggi ma diventare molto vecchi (e quindi distrarre) molto rapidamente.
FinnNk,

5
Mi piace il tuo esempio, anche se direi che in determinati contesti, più annidate se le dichiarazioni sono inevitabili. Con molta logica aziendale, il codice può essere un po 'confuso, ma se l'azienda stessa è confusa per cominciare, semplificare il codice significherebbe modellare in modo meno accurato il processo. Come diceva Einstein: "Le cose dovrebbero essere il più semplici possibile e non un po 'più semplici".
Morgan Herlocker,

2
@Prof Plum - Che esempio puoi dare? Di solito l'alternativa a più if nidificati è di suddividerla in (molti) metodi. Gli sviluppatori junior tendono ad evitarlo come se fosse meno desiderabile dell'if; ma di solito quando vengono premuti dicono "se lo fanno in meno righe". Ci vuole qualcuno fiducioso in OOP per intervenire e ricordare loro che meno righe! = Codice migliore.
STW

2
@STW Questo è un buon punto, tuttavia, direi che dipende dalla profondità della nidificazione. Concordo certamente sul fatto che qualcosa di più di tre nidi in profondità abbia spesso bisogno di essere rifatturato, perché diventerà piuttosto peloso. La quotazione assicurativa, tuttavia, è un buon esempio in cui il multi-nesting può effettivamente modellare abbastanza bene il mondo reale. Con l'eccezione di determinate tariffe / premi, il manuale leggerà letteralmente qualcosa del tipo "se si tratta di una proprietà e se ha una tariffa minima inferiore a 5.6 e se si trova in NC e se ha un'imbarcazione in loco, quindi fare ciò e come." con molte altre opzioni.
Morgan Herlocker,

4
@josh, se "loro" sono colleghi, allora mediterei sul perché non hai detto "noi" ...

104

La bandiera rossa principale per me sono i blocchi di codice duplicati, perché mostra che la persona o non capisce i fondamenti della programmazione o era troppo spaventata per apportare le modifiche appropriate a una base di codice esistente.

Contavo anche la mancanza di commenti come una bandiera rossa, ma di recente ho lavorato su un ottimo codice senza commenti che ho rimandato.


1
+1: Ho visto del codice dal collega che si pubblicizzava come un esperto di Linux, che ha scritto una semplice applicazione di looping come una lunga funzione, il tutto ripetutamente in main (). Yikes.
KFro

4
@KFro, questo è lo svolgimento di loop. Ecco cosa fanno sempre i compilatori :) MOLTO efficiente!

3
@Thorbjorn: a volte, devi aiutare un po 'il compilatore; dopo tutto, sei l'umano intelligente ed è solo un computer stupido.
yatima2975,

3
Un altro motivo che ho visto: il consulente è stato pagato per implementare la funzionalità il più rapidamente possibile (ecco perché mancano anche i test e la documentazione). Copia / incolla è più veloce del pensare a come fare le cose nel modo giusto.
LennyProgrammers,

4
Evitare la duplicazione del codice può essere un'ossessione. In un linguaggio come il C ++, non è sempre facile come dovrebbe essere quello di scomporre le varie parti, ma ha comunque un codice robusto ed efficiente. A volte, un po 'di taglia e incolla è l'opzione più pratica. Inoltre, può essere applicato il principio di ottimizzazione: taglia e incolla può offrirti una soluzione semplice e veloce che puoi rifattorizzare in seguito, se necessario. Si può essere il risparmio un mal di testa di manutenzione per più tardi, ma si sa per certo che stai evitando ritardi al momento.
Steve314,

74

Codice che cerca di mostrare quanto sia intelligente il programmatore, nonostante non aggiunga alcun valore reale:

x ^= y ^= x ^= y;

12
Wow, è molto più leggibile diswap(x, y);
JBR Wilkinson,

8
se xey sono puntatori e questo incarico si svolge per un ragionevole lasso di tempo, rompe in modo sicuro i raccoglitori di rifiuti conservatori come Boehm GC.
SingleNegationElimination,

12
A proposito, questo codice non è definito in C e C ++ a causa di più modifiche senza un punto di sequenza intermedio.
Fredoverflow,

9
A questo proposito, l'unica cosa che mi è venuta in mente sono state le emoticon:^_^
Darien,

62
  • 20.000 funzioni di linea (esagerazione). Qualsiasi funzione che richiede più di un paio di schermate necessita di un nuovo factoring.

  • Sulla stessa linea, file di classe che sembrano andare avanti per sempre. Probabilmente ci sono alcuni concetti che potrebbero essere astratti in classi che chiarirebbero lo scopo e la funzione della classe originale e probabilmente dove viene usata, a meno che non siano tutti metodi interni.

  • variabili non descrittive, non banali o troppe variabili banali non descrittive. Questi fanno dedurre ciò che sta realmente accadendo un enigma.


9
Tendo a limitare le funzioni a 1 schermo ogni volta che è possibile.
Matt DiTrolio,

20
1 schermo è anche un tratto. Comincio a sentirmi sporco dopo circa 10 righe.
Bryan Rowe,

54
Ok, darò voce a quella che potrebbe essere un'opinione impopolare. Dico che è odore di codice scrivere funzioni che sono processi atomici dall'alto verso il basso che sono suddivisi in funzioni separate perché lo sviluppatore si aggrappa ad alcune "funzioni dovrebbero essere brevi". Le funzioni dovrebbero essere interrotte lungo le linee FUNZIONALI, non solo perché dovrebbero avere una mitica "giusta dimensione". Ecco perché si chiamano FUNZIONI.
Dan Ray,

7
@Dan, Le funzioni non dovrebbero essere brevi per essere brevi, ma ci sono così tante informazioni che puoi tenere in testa contemporaneamente. Forse ho un piccolo cervello, per me quel limite è un paio di schermi :). Rompere le funzioni in più funzioni quando iniziano a testare quel limite è necessario per evitare errori. Da un lato fornisce l'incapsulamento in modo da poter pensare a un livello superiore e dall'altro nasconde ciò che sta accadendo, rendendo più difficile capire come funziona la funzione. Penso che le funzioni di separazione dovrebbero essere fatte per aiutare la leggibilità, non per adattarsi a una "lunghezza perfetta".
Dominique McDonnell il

6
@Dominic, @ Péter, penso che noi tre stiamo effettivamente dicendo la stessa cosa. Quando c'è una buona ragione per fattorizzare il codice in una funzione più piccola, ci sono io. Quello che sto respingendo è la mancanza di valore per motivi di mancanza nel design delle funzioni. Sai, uno stack di chiamate che è tre volte più lungo di quanto deve essere, ma almeno quelle funzioni sono brevi. Preferirei eseguire il debug di una funzione alta che fa una cosa bene e chiaramente piuttosto che inseguire il percorso di esecuzione attraverso una dozzina di funzioni concatenate che sono chiamate solo dalla precedente.
Dan Ray,

61
{ Let it Leak, people have good enough computers to cope these days }

Quel che è peggio è che proviene da una biblioteca commerciale!


32
Questo non suona il campanello d'allarme. Ti prende praticamente a calci tra le gambe.
Steven Evers,

15
La figlia è una tossicodipendente. Chi se ne frega, almeno non diventerà obesa. :: sospiro ::
Evan Plaice,

17
Quando mi trovo nei momenti difficili, la mamma buntu viene da me. Parlando parole di saggezza, lascialo trapelare. LASCIARLO .. LASCIARLO. Lascialo perdere Oh lascialo perdere. Se perde solo una volta, non è un leaaaaaak. (se leggi fino a questo punto, +1). Ho davvero bisogno di prendere in considerazione il decaf.
Tim Post

13
"Con l'avvicinarsi della scadenza, LEAKS è tutto ciò che posso vedere, da qualche parte qualcuno sussurra, 'Scrivi in ​​C ...... eeeeee !!!'"
chiurox,

9
C'erano una volta due sistemi operativi. Uno è trapelato e si è schiantato se ha funzionato per più di 49 giorni, l'altro è stato perfetto e avrebbe funzionato per sempre. Uno è stato lanciato nel 1995 per un enorme fanfair ed è stato utilizzato da milioni di persone - l'altro non è mai stato spedito perché stanno ancora verificando che sia privo di bug. C'è una differenza tra filosofia e ingegneria.
Martin Beckett,

53

Commenti così dettagliati che se ci fosse un compilatore inglese, si compilerebbe ed eseguirà perfettamente, ma non descrive nulla che il codice non lo faccia.

//Copy the value of y to temp.
temp = y;
//Copy the value of x to y.
y = x;
//Copy the value of temp to x.
x = temp;

Inoltre, i commenti sul codice che avrebbero potuto essere eliminati se il codice avesse aderito ad alcune linee guida di base:

//Set the age of the user to 13.
a = 13;

15
C'è, si chiama COBOL :-)
Gaius

26
Il secondo caso non è il peggiore. Il peggio è: / * Imposta l'età dell'utente su 13 * / a = 18;
PhiLho,

4
@PhiLho - no, ancora peggio è quando il /dal */manca, quindi tutto il codice per la fine del prossimo */viene ignorato. Fortunatamente, l'evidenziazione della sintassi rende quel genere di cose rare al giorno d'oggi.
Steve314,

3
Peggio ancora, aper user_age? Veramente?
glasnt,

2
Avevo l'abitudine di mantenere un documento standard in codice presso un precedente datore di lavoro, una sezione della quale era un commento appropriato. Il mio esempio preferito è stato da MSDN:i = i + 1; //increment i
Michael Itzoe,

42

Codice che genera avvisi quando viene compilato.


1
C'è un candidato per aggiungere l'opzione del compilatore "Tutti gli avvisi come errori" al makefile / progetto.
JBR Wilkinson,

3
Immagino che potrebbe essere utile se sei in un progetto con più persone di cui semplicemente non ti fidi, anche se se dovessi unirmi a un progetto in cui è impostata quell'opzione, che di per sé mi farebbe preoccupare di quanto sia capace l'altro i programmatori lo sono.
Rei Miyasaka,

1
Non sono d'accordo con questo. Alcuni avvisi del compilatore (come il confronto tra firmato e non firmato, quando si conoscono entrambi i valori come non firmati, anche se i tipi sono diversi) sono preferibili ai rifiuti di codice con cast inutili. Se riduco il codice usando un intero con segno portatile che una funzione modifica solo se l'intero ha un valore senza segno, lo farò.
Tim Post

13
Preferirei ingombrare il mio codice con un quasi superfluo (unsigned int)piuttosto che ingombrare i miei elenchi di avvisi / errori con avvisi benigni. Odio che la lista di avvertimenti diventi un punto cieco. E 'anche molto più di una valle di lacrime per spiegare ad altre persone perché si sta ignorando un avvertimento di quello che è di spiegare il motivo per cui si sta facendo un cast di natura intsa unsigned ints.
Rei Miyasaka,

Occasionalmente, devi lavorare con un'API che emette errori qualunque cosa tu faccia. Esempi classici sono quelli in cui l'API è definita in termini di cose che sono state interrotte in base alla progettazione (alcune vecchie costanti ioctl () erano così, e talvolta gli sviluppatori di sistemi operativi insistono nell'usare il tipo sbagliato nelle loro intestazioni) o dove hanno deprecato qualcosa senza lasciando un buon sostituto (grazie, Apple).
Donal Fellows il

36

Funziona con numeri nel nome invece di avere nomi descrittivi , come:

void doSomething()
{
}

void doSomething2()
{
}

Per favore, fai in modo che i nomi delle funzioni significino qualcosa! Se doSomething e doSomething2 fanno cose simili, utilizzare nomi di funzioni che differenziano le differenze. Se doSomething2 è una rottura delle funzionalità di doSomething, chiamalo per la sua funzionalità.


Allo stesso modo @Parm per SQL
Dave,

2
+1 - Invio mshtml- mi spezza gli occhi :(
Kyle Rozendo il

3
L'eccezione a questo sarebbe il codice GUI. Ad esempio, se un modulo di posta ordinaria aveva due indirizzi; address1 e address2 sono più ragionevoli di address e alternateAddress. Anche le etichette spurie che sono solo statiche sono una ragionevole eccezione.
Evan Plaice,

@Evan - abbastanza giusto, anche se stavo facendo più una distinzione in termini di funzionalità.
Wonko the Sane,

1
+1 - L'ho persino visto usato come metodo di controllo della pseudo-versione.
EZ Hart,

36

Numeri magici o stringhe magiche.

   if (accountBalance>200) { sendInvoice(...); }

   salesPrice *= 0.9;   //apply discount    

   if (invoiceStatus=="Overdue") { reportToCreditAgency(); }

4
Non è poi così male con i secondi due, almeno lo sconto è spiegato, e "In ritardo" è intuitivo. La 200, d'altra parte ...
Tarka

9
@Slokun - Intuitivo non è tanto il punto quanto la manutenibilità e la fragilità. Ad esempio, considera cosa succede quando l'importo dello sconto cambia e 0.9 è codificato in sei punti diversi. Inoltre, l'utilizzo di stringhe anziché costanti / enumerazioni richiede problemi in lingue con stringhe maiuscole / minuscole.
JohnFx,

+1 Ho appena trascorso troppo tempo a eseguire il debug di un problema che si è rivelato essere causato da una riga "timeout = 15;" sepolto in un programma.
aubreyrhodes,

Penso che l'ultimo a volte vada bene, a seconda della provenienza di tali dati per fatturaStatus. Se proviene da un'API pubblica che restituisce JSON che è stata appena decodificata, il controllo su una costante String con codice hard probabilmente va bene. Concordo però che "200" e "0.9" sono solo costanti magiche e non dovrebbero essere codificati in questo modo. Anche se vengono utilizzati solo in questo punto, la manutenzione è più semplice se li si definisce in una sezione di configurazione separatamente anziché intervallandoli nel codice logico. E se vengono utilizzati in più punti, la manutenzione diventa molto più semplice.
Ben Lee,

36
  • Forse non è il peggiore, ma mostra chiaramente il livello degli implementatori:

    if(something == true) 
  • Se una lingua ha un costrutto ciclo o iteratore, l'uso di un ciclo while dimostra anche il livello di comprensione della lingua da parte degli implementatori:

    count = 0; 
    while(count < items.size()){
       do stuff
       count ++; 
    }
    
    for(i = 0; i < items.size(); i++){
      do stuff 
    }
    //Sure this is not terrible but use the language the way it was meant to be used.
    
  • La cattiva ortografia / grammatica nella documentazione / nei commenti mangia quasi quanto il codice stesso. Il motivo è dovuto al fatto che il codice era destinato alla lettura umana e all'esecuzione delle macchine. Questo è il motivo per cui usiamo linguaggi di alto livello, se la tua documentazione è difficile da superare, mi fa preventivamente formare un'opinione negativa della base di codice senza guardarla.


29

Quello che noto immediatamente è la frequenza di blocchi di codice profondamente nidificati (if's, while's, ecc.). Se il codice frequentemente supera i due o tre livelli di profondità, questo è un segno di un problema di progettazione / logica. E se arriva come 8 nidi in profondità, è meglio che ci sia una buona ragione per non romperlo.


6
So che alcune persone hanno appreso che ogni metodo dovrebbe avere solo returnun'affermazione, ma quando causa più di 6 livelli di nidificazione di se / allora penso che stia facendo molto più male che bene.
Darien,

28

Durante la valutazione del programma di uno studente, a volte posso dire in un momento in stile "battito di ciglia". Questi sono gli indizi istantanei:

  • Formattazione scadente o incoerente
  • Più di due righe vuote di fila
  • Convenzioni di denominazione non standard o incoerenti
  • Codice ripetuto, più ripetute sono le parole, più forte è l'avvertimento
  • Quello che dovrebbe essere un semplice pezzo di codice è eccessivamente complicato (ad esempio, controllando gli argomenti passati al principale in modo contorto)

Raramente le mie prime impressioni sono errate e queste campane di avvertimento hanno ragione circa il 95% delle volte . Per un'eccezione, uno studente che non conosceva il linguaggio stava usando uno stile di un linguaggio di programmazione diverso. Scavare e rileggere il loro stile nel linguaggio dell'altra lingua mi ha rimosso i campanelli d'allarme e lo studente ha quindi ottenuto il pieno merito. Ma tali eccezioni sono rare.

Quando si considera un codice più avanzato, questi sono i miei altri avvertimenti:

  • La presenza di molte classi Java che sono solo "strutture" per contenere i dati. Non importa se i campi sono pubblici o privati ​​e utilizzano getter / setter, probabilmente non fa ancora parte di un progetto ben congegnato.
  • Classi che hanno nomi scadenti, come essere semplicemente uno spazio dei nomi e non c'è vera coesione nel codice
  • Riferimento a modelli di progettazione che non sono nemmeno utilizzati nel codice
  • Gestori di eccezioni vuoti senza spiegazione
  • Quando estraggo il codice in Eclipse, centinaia di "avvisi" gialli allineano il codice, principalmente a causa di importazioni o variabili non utilizzate

In termini di stile, in genere non mi piace vedere:

  • Commenti Javadoc che fanno solo eco al codice

Questi sono solo indizi per codice errato. A volte ciò che può sembrare un cattivo codice in realtà non lo è, perché non conosci le intenzioni del programmatore. Ad esempio, potrebbe esserci una buona ragione per cui qualcosa sembra eccessivamente complesso: potrebbe esserci stata un'altra considerazione in gioco.


Non riesco a vedere come usare lo stile da una lingua in un'altra sia un grave errore (2, 4, 8 spazi per trattino ...). Se lo studente ha poco altro stile da seguire, non c'è niente di sbagliato nell'essere autoconsistente. Come selezionatore vedi un miliardo di programmi, quindi sei all'estremità opposta di quello spettro, ma questo non è un motivo per respingere totalmente uno stile diverso (ma coerente).
Nick T,

18
Non vedo nulla di sbagliato nelle classi che semplicemente aggregano i dati, cioè le strutture. Questo è ciò che sono i Data Transfer Objects (DTO) e possono rendere il codice molto più leggibile di quanto si pensi, ad esempio passando 20 parametri a un metodo.
Nemi,

1
Il tuo commento sulle strutture è perfetto. Va bene quando i dati sono nella sua forma più grezza e non verranno modificati in alcun modo. Ma il 95% delle volte dovresti avere alcune funzioni nella classe per formattare / operare sui dati. Ho appena ricordato un po 'del mio codice che essenzialmente utilizza quel modello e dovrebbe essere migliorato.
DisgruntledGoat

2
+1 per lo stile incoerente e le interruzioni di riga extra (ho visto rientri casuali, nessun rientro, convenzioni di denominazione casuali e mutevoli e altro ancora - e questo nel codice di produzione!). Se non riesci nemmeno a preoccuparti di farlo bene, cos'altro non puoi essere disturbato a fare?
Dean Harding,

1
Cerco la linea di dichiarazione di un metodo indentato troppo rispetto al corpo. Questo è un segno che hanno copiato e incollato dal file di qualcun altro.
Barry Brown,

25

Preferito preferito / pipì dell'animale domestico: IDE ha generato nomi che vengono commessi. Se TextBox1 è una variabile importante e importante nel tuo sistema, hai un'altra cosa in arrivo la revisione del codice.


25

Variabili completamente inutilizzate , specialmente quando la variabile ha un nome simile ai nomi delle variabili utilizzati.


21

Molte persone hanno menzionato:

//TODO: [something not implemented]

Mentre vorrei che le cose fossero implementate, almeno hanno preso nota. Quello che penso sia peggio è:

//TODO: [something that is already implemented]

I Todo sono inutili e confusi se non ti preoccupi mai di rimuoverli!


1
Ho appena passato l'esercitazione di dover produrre un rapporto di tutti i TODO nel nostro prodotto di rilascio, oltre a un piano per dispositivi su di loro. Quasi la metà si è rivelata obsoleta.
AShelly,

1
-1 commenti TODO vengono utilizzati in MS Visual Studio per tenere traccia di parti del progetto che necessitano ancora di lavoro. Ad esempio, l'IDE mantiene un elenco che tiene traccia dei TODO in modo da poter fare clic su di essi e portarli direttamente alla linea in cui esiste il TODO. Preferirei vedere TODO posizionati in modo esplicito per vedere quale lavoro debba ancora essere fatto. Vedi dotnetperls.com/todo .
Evan Plaice,

3
@Evan Plaice: Wow, vuoi dire che VS IDE riconosce quando hai implementato qualcosa e rimuove il //TODOcommento? Eccezionale!
JBR Wilkinson,

4
@Prof Plum Perché non creare semplicemente una politica in cui la persona responsabile di un TODO inserisca il proprio nome nel commento. In questo modo, se ci sono alcuni avanzi esso
Evan Plaice

3
Pianifica meglio di // TODO , usa il tuo localizzatore di bug, ecco a cosa serve!
SingleNegationElimination,

20

Un metodo che mi richiede di scorrere verso il basso per leggere tutto.


14
Hmm .. questo dipende da ciò che viene implementato. Non sarebbe irragionevole che ciò accadesse durante l'implementazione di alcuni complicati algoritmi, poiché è così che vengono definiti. Naturalmente, se la maggior parte dei metodi è così, quella è una bandiera rossa.
Billy ONeal,

9
Come affermazione generale, quindi, non sono d'accordo, sprecare tempo costantemente refactoring in modo che tutto si adatti a questo tipo di regola autoimposta aumenta effettivamente il costo complessivo del progetto.
Tipo anonimo

1
Non sono d'accordo sul fatto che questa regola possa aumentare il costo complessivo di un progetto, ma immagino che sia soggettivo perché dipenderebbe dagli sviluppatori. Se si mantiene il principio generale di "separazione delle preoccupazioni" durante lo sviluppo, il rifattoraggio sarebbe meno di un compito se si scegliesse di farlo. Qualcosa da considerare è quanto costerebbe tre anni dopo che gli sviluppatori che non hanno codificato il progetto originale stanno cercando di correggere un mucchio di metodi con oltre 300 righe di codice? Quanto costa?
BradB,

18
Sono più seccato di scorrere a destra che di scorrere verso il basso. Whitespace è "gratuito".
Wonko the Sane,

4
Preferirei scorrere piuttosto che saltare tutto il file (o più file) per capire cosa sta facendo il codice.
TMN,

20

Congiunzioni nei nomi dei metodi:

public void addEmployeeAndUpdatePayrate(...) 


public int getSalaryOrHourlyPay(int Employee) ....

Chiarimento: il motivo per cui suona un campanello d'allarme è che indica che il metodo probabilmente viola il principio della singola responsabilità .


Hmmm ... se il nome della funzione definisce accuratamente cosa fa la funzione, allora non sono d'accordo. Se il metodo fa due cose separate che sarebbe meglio separare, allora potrei essere d'accordo, a seconda del contesto.
Wonko the Sane,

2
Questo è il punto. La congiunzione implica che è molto probabile che faccia più di una cosa. Per la domanda è solo qualcosa che aumenta la consapevolezza che qualcosa potrebbe essere sbagliato.
JohnFx,

3
E se dovessi aggiungere un dipendente e aggiornarne la velocità di pagamento in più punti? Se quel metodo contiene due chiamate di metodo ( addEmployee(); updatePayrate();), non penso che sia un problema.
Matt Grande,

13

Collegando ovviamente il codice sorgente di GPL in un programma commerciale, a codice chiuso.

Non solo crea un problema legale immediato, ma nella mia esperienza, di solito indica disattenzione o disinteresse che si riflette anche altrove nel codice.


6
Mentre il tuo punto è eccellente, il tuo tono non è necessario.
JBR Wilkinson,

@JBRWilkinson: Grazie, hai ragione. Mi scuso con tutti.
Bob Murphy,

Penso che la tua rubrica debba essere riscritta. Il collegamento statico e dinamico al codice sorgente di GPL è una violazione della GPL ...
Gavin Coates,

Punti buoni. Ho riscritto l'intero post. Grazie a tutti.
Bob Murphy,

9

Lingua agnostica:

  • TODO: not implemented
  • int function(...) { return -1; } (lo stesso di "non implementato")
  • Generare un'eccezione per un motivo non eccezionale.
  • Uso improprio o incoerente di 0, -1o nullcome valori di ritorno eccezionali.
  • Asserzioni senza un commento convincente che dice perché non dovrebbe mai fallire.

Specifico per la lingua (C ++):

  • Macro C ++ in minuscolo.
  • Variabili C ++ statiche o globali.
  • Variabili non inizializzate o non utilizzate.
  • Tutto array newciò che apparentemente non è sicuro per RAII.
  • Qualsiasi utilizzo di array o puntatori apparentemente non sicuro ai limiti. Questo include printf.
  • Qualsiasi utilizzo della parte non inizializzata di un array.

Specifico per Microsoft C ++:

  • Qualsiasi nome identificativo che si scontra con una macro già definita da uno qualsiasi dei file di intestazione di Microsoft SDK.
  • In generale, qualsiasi utilizzo dell'API Win32 è una grande fonte di campanelli d'allarme. Tenere sempre aperto MSDN e cercare gli argomenti / restituire le definizioni dei valori in caso di dubbio. (Modificato)

Specifico per C ++ / OOP:

  • Ereditarietà dell'implementazione (classe concreta) in cui la classe genitore ha metodi sia virtuali che non virtuali, senza una chiara distinzione concettuale evidente tra ciò che dovrebbe / non dovrebbe essere virtuale.

18
// TODO: Commenta questa risposta
johnc,

8
Immagino che "linguaggio agnostico" significhi "C / C ++ / Java" ora?
Inaimathi,

+1 "Lanciare un'eccezione per un motivo non eccezionale" non potrebbe essere più d'accordo!
billy.bob,

2
@Inaimathi: commenti TODO, matrici di funzioni, abuso di eccezione, confusione di semantica zero / null / vuoto e controlli di sanità mentale inutili sono inerenti a tutti i linguaggi imperativi / OOP e, in una certa misura, a tutti i linguaggi di programmazione in generale.
Rei Miyasaka,

Credo che le macro C preprocessore in minuscolo sono a posto, ma solo se valutano i loro argomenti solo una volta e si traducono in una sola dichiarazione.
Joe D

8

Bizzarro stile di rientro.

Ci sono un paio di stili molto popolari e le persone porteranno quel dibattito alla tomba. Ma a volte vedo qualcuno che usa uno stile di rientro davvero raro, o addirittura cresciuto in casa. Questo è un segno che probabilmente non hanno codificato con nessuno diverso da loro stessi.


2
o solo un segno che sono un talento individualista molto apprezzato che non è stato catturato dalla rete di pratiche di codifica omogonizzate che non sono in alcun modo legate alle "migliori pratiche".
Tipo anonimo

1
Spero che tu sia sarcastico. Se qualcuno sta codificando in un modo così insolito, ciò dovrebbe far scattare campanelli d'allarme. Possono essere artistici quanto vogliono, ma comunque ... campanelli d'allarme.
Ken,

2
C'è uno stile un po 'fuori dal comune (credo che si chiama stile Utrecht) che trovo molto utile nonostante sia estremamente raro al di fuori di Haskell / ML / F #. Scorri verso il basso fino a " Moduli modulo": learnyouahaskell.com/making-our-own-types-and-typeclasses . La cosa bella di questo stile è che non è necessario modificare il delimitatore nella riga precedente per aggiungerne uno nuovo, cosa che spesso dimentico di fare.
Rei Miyasaka,

@ReiMiyasaka Sette anni di ritardo, ma ... lo stile di Utrecht mi infastidisce davvero. Credo che sia un errore nelle specifiche Haskell non imporre un'altra "regola di layout" su elenchi organizzati verticalmente. In questo modo, il parser poteva rilevare una nuova voce di elenco semplicemente controllando il rientro, che è comunque il modo in cui tutti organizzano i propri elenchi.
Ryan Reich,

@RyanReich Weird, sette anni dopo, e mi piace ancora. Sono d'accordo, però; nonostante tutta la sua imbarazzo sintattica e i suoi fallimenti, F # consente anche agli oggetti di essere delimitati solo da una nuova riga e rientro (nella maggior parte dei casi), che rende il codice ordinato.
Rei Miyasaka,

8

Utilizzo di molti blocchi di testo anziché enumerazioni o variabili definite a livello globale.

Non bene:

if (itemType == "Student") { ... }

Meglio:

private enum itemTypeEnum {
  Student,
  Teacher
}
if (itemType == itemTypeEnum.Student.ToString()) { ... }

Migliore:

private itemTypeEnum itemType;
...
if (itemType == itemTypeEnum.Student) { ... }

O il migliore: usa il polimorfismo.
Lstor,

8

Parametri debolmente digitati o valori di ritorno sui metodi.

public DataTable GetEmployees() {...}

public DateTime getHireDate(DataTable EmployeeInfo) {...}

public void FireEmployee(Object EmployeeObjectOrEmployeeID) {...}

2
+1: Devo lavorare con alcuni servizi web “REST” che restituiscono tutto come tabelle pseudo-HTML, anche quando passi cose che sono un chiaro errore sintattico. Non autorizzato? Inserire junk completo? Server over capacity? 200 (più un messaggio in un formato orribile in una colonna, una tabella di riga). AAaaaaaaaargh!
Donal Fellows

7
  • Più operatori ternari uniti insieme, quindi invece di assomigliare a un if...elseblocco, diventa un if...else if...[...]...elseblocco
  • Nomi variabili lunghi senza sottolineatura o CamelCasing. Esempio da un codice che ho estratto:$lesseeloginaccountservice
  • Centinaia di righe di codice in un file, con pochi o nessun commento, e il codice è molto ovvio
  • ifDichiarazioni eccessivamente complicate . Esempio dal codice: a if (!($lessee_obj instanceof Lessee && $lessee_obj != NULL))cui mi sono concentratoif ($lessee_obj == null)

7

Odore di codice: non seguire le migliori pratiche

Questo genere di cose mi preoccupa sempre perché c'è quel vero che tutti pensano di essere un guidatore sopra la media.

Ecco un lampo di notizie per te: il 50% della popolazione mondiale è al di sotto della media dell'intelligence. Ok, quindi alcune persone avrebbero un'intelligenza esattamente nella media, ma non facciamoci schizzinosi. Inoltre, uno degli effetti collaterali della stupidità è che non puoi riconoscere la tua stessa stupidità! Le cose non sembrano così belle se si combinano queste affermazioni.

Quali cose suonano all'istante quando suona il codice?

Sono state menzionate molte cose positive e in generale sembra che non seguire le migliori pratiche sia un odore di codice.

Le migliori pratiche di solito non vengono inventate in modo casuale e spesso sono lì per un motivo. Molte volte può essere soggettivo, ma nella mia esperienza sono per lo più giustificati. Seguire le migliori pratiche non dovrebbe essere un problema, e se ti stai chiedendo perché sono come sono, cercalo piuttosto che ignorarlo e / o lamentarti di questo - forse è giustificato, forse no.

Un esempio di una buona pratica potrebbe essere l'uso dei ricci con ogni if-block, anche se contiene solo una riga:

if (something) {
    // whatever
}

Potresti non pensare che sia necessario, ma di recente ho letto che è una delle principali fonti di bug. Sempre utilizzando le parentesi sono stati discussi anche su Stack Overflow e verificare che le istruzioni if ​​abbiano parentesi è anche una regola in PMD , un analizzatore di codice statico per Java.

Ricorda: "Perché è la migliore pratica" non è mai una risposta accettabile alla domanda "perché lo stai facendo?" Se non riesci a capire perché qualcosa è una buona pratica, allora non è una buona pratica, è una superstizione.


2
Questo può essere pedante, ma penso che sia importante quale media scegli. Da quanto ho capito, il 50% della popolazione mondiale è al di sotto dell'intelligenza mediana (per definizione); ma le altre medie non funzionano allo stesso modo. Ad esempio, prendi la popolazione (1, 1, 1, 5) che ha una media aritmetica di 2.
flamingpenguin

ummm, hai citato il post "what-superstitions-do-programmers-have" in cui un utente ha fatto una dichiarazione audace su parentesi graffe senza fonte. Non lo vedo come un buon esempio di buone pratiche.
Evan Plaice,

@Evan: sì, hai ragione. Ho aggiunto qualcosa in più, spero che questo aiuti.
Vetle,

4
Il rovescio della medaglia di questo è che le persone seguono scrupolosamente le "migliori pratiche" senza alcun pensiero critico sul perché qualcosa sia una "migliore pratica". Questo è il motivo per cui non mi piace molto il termine "best practice", perché per alcune persone è una scusa per smettere di pensare e seguire la mandria. "Perché è la migliore pratica" non è mai una risposta accettabile alla domanda "perché lo stai facendo?" Se non riesci a capire perché qualcosa è una buona pratica, allora non è una buona pratica, è una superstizione.
Dan Dyer,

Ottimo commento, Dan! Ho aggiunto le ultime due righe alla risposta.
Vetle,

6

Commenti che dicono "questo perché il design del sottosistema Froz è totalmente interrotto".

Questo va avanti per un intero paragrafo.

Spiegano che deve avvenire il seguente refattore.

Ma non l'ha fatto.

Ora, avrebbero potuto dirgli che non potevano cambiarlo dal loro capo in quel momento, a causa di problemi di tempo o di competenza, ma forse era perché le persone erano meschine.

Se un supervisore pensa che j.random. il programmatore non può fare un refactoring, quindi il supervisore dovrebbe farlo.

Ad ogni modo ciò accade, so che il codice è stato scritto da una squadra divisa, con possibili politiche di potere, e non hanno riformattato i progetti del sottosistema corrotto.

Storia vera. Potrebbe succedere a te.


6

Qualcuno può pensare a un esempio in cui il codice dovrebbe legittimamente fare riferimento a un file in base al percorso assoluto?


1
Gli schemi XML contano?
Nick T,

1
File di configurazione del sistema. In genere dovrebbe essere impostato da ./configure, ma anche questo richiede un valore predefinito da qualche parte.
eswald,

4
/dev/nulle gli amici stanno bene. Ma anche cose del genere /bin/bashsono sospette - e se tu fossi uno di un sistema bizzarro che ha /usr/bin/bash?
Tom Anderson,

1
Il codice client del servizio Web generato dagli strumenti JAX-WS (almeno JBossWS e Metro) contiene un percorso assoluto cablato al file WSDL (due volte!). Che probabilmente è qualcosa di selvaggiamente inappropriato /home/tom/dev/randomhacking/thing.wsdl. È follemente folle che si tratti di un comportamento predefinito.
Tom Anderson,

4
about /dev/null: Ho l'abitudine, durante lo sviluppo su Windows, di tenere sotto app e librerie c:\dev. In qualche modo, una cartella nullviene sempre creata automaticamente all'interno di quella cartella. Giuro che non ho idea di chi lo faccia. (Uno dei miei bug / caratteristiche preferiti)
Sean Patrick Floyd,

6

Catturare le eccezioni generali:

try {

 ...

} catch {
}

o

try {

 ...

} catch (Exception ex) {
}

Uso eccessivo della regione

In genere, l'utilizzo di troppe regioni mi indica che le tue classi sono troppo grandi. È un flag di avvertimento che segnala che dovrei indagare di più su quel bit di codice.


La cattura di eccezioni generali è solo un problema se le si ripropone senza fare nulla. Davvero per la maggior parte delle cose sarebbe sufficiente una classe di eccezione. Tendo a usare runtime_error.
CashCow

+1 per l'esempio "prendi e butta via eccezione". Se non stai facendo nulla con l'eccezione, non prenderlo. Per lo meno, registralo. Per lo meno, inserisci un commento che spiega perché va bene catturare tutte le eccezioni e passare a quel punto nel codice.
EZ Hart,

5

Convenzioni di denominazione delle classi che dimostrano una scarsa comprensione dell'astrazione che stanno tentando di creare. O che non definisce affatto un'astrazione.

Un esempio estremo viene in mente in una classe VB che ho visto una volta che era intitolata Dataed era lunga più di 30.000 righe ... nel primo file. Era una classe parziale suddivisa in almeno mezza dozzina di altri file. La maggior parte dei metodi erano wrapper attorno a proc memorizzati con nomi come FindXByYWithZ().

Anche con esempi meno drammatici, sono sicuro che abbiamo appena "scaricato" la logica in una classe mal concepita, dato che ha un titolo del tutto generico, e se ne è pentita in seguito.


5

Funzioni che reimplementano le funzionalità di base della lingua. Ad esempio, se vedi mai un metodo "getStringLength ()" in JavaScript anziché una chiamata alla proprietà ".length" di una stringa, sai che sei nei guai.


5
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...

Naturalmente senza alcun tipo di documentazione e l'occasionale nidificato #defines


Ho visto esattamente questo "modello" ieri ... nel codice di produzione ... e ancora peggio ... nel codice di produzione C ++: - /
Oliver Weiler,
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.