Codice di fantasia breve commentato rispetto a un codice più lungo non capitato e facile da capire - che è preferibile?

18

A volte un algoritmo può essere scritto in due modi:

  • Il modo breve, elegante; o
  • Il modo più lungo e facile da capire.

Ad esempio, ecco un modo più semplice e più lungo di copiare una stringa source in dest in C:

*dest = *source;
while (*source != '
// Copy string source to dest
while (*dest++ = *source++);
') { source++; dest++; *dest = *source; } (true);

Ed ecco un modo breve, elegante.

//direct formula for xoring all numbers from 1 to N
int Sum = (N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) ) );

Ho sempre sentito e letto che il codice di fantasia dovrebbe essere evitato, e sono tendenzialmente d'accordo. Ma cosa succede se prendiamo in considerazione i commenti? Supponiamo che, come negli esempi precedenti, abbiamo un codice non commentato, più lungo e apparentemente più facile da capire, e un codice ben organizzato, breve e di fantasia? Il codice non elegante è ancora preferito?

EDIT: molti hanno commentato nomi di variabili, quindi ho modificato il codice di esempio in modo da non renderlo un fattore quando preferisco l'altro. Ho provato a rimuovere il doppio incarico nel primo esempio, ma questo ha reso il codice meno leggibile.

Forse questo non era il migliore degli esempi perché molti trovano il codice "fantasioso" più leggibile e comprensibile rispetto al codice più lungo. L'idea era di avere un codice più lungo che fosse molto più facile da capire di un codice molto breve ma complicato.

EDIT2: Ecco un nuovo esame che ho ricevuto da SO :

Versione di fantasia commentata:

int Sum = 0;
for (int i = 1; i < N; ++i)
{
   Sum ^= i; //or Sum = Sum ^ i;
}

Versione lunga non commentata:

*dest = *source;
while (*source != '
// Copy string source to dest
while (*dest++ = *source++);
') { source++; dest++; *dest = *source; } (true);
    
posta gablin 04.10.2010 - 10:36
fonte

12 risposte

28

In genere preferirei estrarre il codice di fantasia nel suo metodo ..

Piuttosto che commentare il codice di fantasia, il suo nome di metodo dovrebbe essere tutto ciò di cui ha bisogno per chiarire le cose.

char *copy_string(char *s, const char *t) {    
    while (*s++ = *t++); 
    return s;
}
    
risposta data 04.10.2010 - 11:24
fonte
10

Sono tutto per la versione più lunga. Il problema con la versione breve del codice, oltre a essere più difficile da leggere per alcuni programmatori, è che la maggior parte delle volte è più difficile individuare gli errori semplicemente guardandoli.

Ho un esempio di vita reale. Nel nostro prodotto abbiamo avuto il seguente snippet di codice:

if (++someCounter < MAX_VALUE) {
    // Do something that has to be done only MAX_VALUE times
}

Questo codice sembra perfettamente ragionevole a prima vista, ma dopo un lungo periodo di tempo questo contatore trabocca e rompe la condizione (nello scenario reale abbiamo schiacciato il sistema di produzione del nostro cliente con una OOM). Questo codice è un po 'meno "sofisticato", ma è chiaro che fa ciò che dovrebbe fare:

if (someCounter < MAX_VALUE) {
    ++someCounter;
    // Do whatever it is we came here for
}

E potresti dire che lo sviluppatore che ha scritto questo codice non era abbastanza buono (il che non è vero, era un ragazzo piuttosto brillante), ma penso che se la tua tecnica di codifica richiede di essere super-duper esperti programmare GOD per ottenere il codice giusto, stai facendo qualcosa di sbagliato. Il tuo codice dovrebbe essere il più infallibile possibile per il tuo bene e per chi deve mantenere questo codice dopo di te (chi potrebbe non essere intelligente come te).

Quindi - Sono tutto per semplicità e chiarezza.

Modifica: Oh, e per quanto riguarda i commenti: non importa. Molte persone non leggeranno comunque i commenti ( link ) e coloro che non capiranno il tuo codice senza commenti , non lo capiranno abbastanza bene con loro in modo che possano mantenerlo. L'obiettivo è aiutare le persone vedere che alcuni codici sono "corretti", i commenti non possono essere d'aiuto.

    
risposta data 04.10.2010 - 11:22
fonte
6

Preferirei in genere la versione più lunga. Ci vengono in mente due ragioni principali:

  • È probabile che più persone lo capiscano con meno sforzo (supponendo che non sia un esempio "standard" come questa copia di stringa).
  • È possibile inserire punti di interruzione su singole istruzioni e procedere con un debugger.

Per il meglio di entrambi i mondi, avvolgi il codice in una funzione, il cui nome fa il commento per te:

void copy_string(char *s, char *t)
{
    *s = *t;
    while (*t != '
void copy_string(char *s, char *t)
{
    *s = *t;
    while (*t != '%pre%') {
        t++;
        s++;
        *s = *t;
    }
}
') { t++; s++; *s = *t; } }

L'unica ragione per non farlo sarebbe se le prestazioni fossero un problema e la creazione di profili mostrava in modo significativo il sovraccarico della funzione.

    
risposta data 04.10.2010 - 12:49
fonte
4

Qualunque sia la più chiara. Spesso questo è uno snippet di codice compatto e facile da capire che non richiede un commento ... come il tuo secondo esempio.

Generalmente frammenti di codice più brevi sono più facili da capire in quanto c'è meno per il lettore da tenere in testa alla volta. Ovviamente, c'è un limite quando il codice diventa eccessivamente offuscato e non intendo che la chiarezza che migliora lo spazio bianco debba essere ritagliata.

I commenti non dovrebbero mai indicare nulla di ovvio dal codice, che fa semplicemente leggere due volte la stessa cosa al lettore. Per me il primo frammento richiede chiarimenti. Perché lo sviluppatore non ha utilizzato un ciclo do...while per rimuovere il duplicato dell'assegnazione *s = *t; ? Devo analizzare più codice per capire che sta implementando una copia di stringa. Un commento sarebbe più utile su questo codice più lungo rispetto al codice più breve.

Il commento sul secondo frammento è quasi ridondante in quanto il ciclo while è praticamente idiomatico, ma dice cosa fa il codice a un livello più alto del codice stesso che lo rende un commento utile.

    
risposta data 04.10.2010 - 11:00
fonte
4

Il problema è che non esiste una definizione chiara di short fancy code poiché dipende molto dal livello del programmatore. Mentre alcune persone non hanno problemi a comprendere un'espressione while(*s++ = *t++); , altre lo faranno.

Personalmente trovo il while(*s++ = *t++); perfettamente leggibile e il più lungo uno più difficile da leggere. Altri potrebbero non essere d'accordo però.

Indipendentemente da ciò, è solo questione di usare il buon senso. La leggibilità dovrebbe sicuramente essere una priorità, ma c'è un punto in cui il codice più lungo diventa meno leggibile quando diventa più lungo. La verbosità spesso riduce la leggibilità dalla mia esperienza.

    
risposta data 04.10.2010 - 11:07
fonte
2

Non sono d'accordo con la maggior parte delle altre risposte qui - penso (almeno in questo caso) il codice più corto è migliore. Contrariamente alla tua richiesta, il codice più lungo è non "più semplice", almeno per un lettore. Semmai, sembra che tu sia uscito dalla tua voglia di farlo più a lungo, anche se rende il codice più difficile da capire e / o essere sicuro del corretto funzionamento.

In particolare, avendo l'assegnazione del primo byte della stringa fuori dal ciclo, separata dall'assegnazione per gli altri byte, significa che uno deve essere molto più attento nella lettura per essere sicuro che tutti i byte sono copiati correttamente. La sequenza di base delle azioni nella versione più breve è molto più semplice da verificare. Il suo unico vero problema è nella formattazione - quando hai un corpo di loop intenzionalmente vuoto, è meglio chiarirlo, qualcosa del tipo:

while (*dest++ = *source++)
    ;

o anche:

while (*dest++ = *source++)
    ; /* no body */

Alcune persone preferiscono usare le parentesi invece:

while (*dest++ = *source++)
    {}

Indipendentemente dall'esatta formattazione che preferisci, sono stati commessi abbastanza errori con cose come:

if (x>y);
     x = z;

... che è importante essere sicuri che 1) sia ovvio cosa sia effettivamente controllato da qualsiasi controllo di flusso, e 2) è ovvio che il codice è stato scritto conoscendo cosa era controllato da esso, quindi qualcuno a leggerlo non perde tempo a cercare di capire se ha appena trovato un bug.

    
risposta data 04.10.2010 - 18:08
fonte
2
Keep it simple, stupid!

Assicurati che qualsiasi altro programmatore possa capire che cosa fa il tuo codice, e ancora meglio se è a colpo d'occhio (è qui che i buoni nomi e i commenti arrivano) .

Il kung-fu e l'assemblaggio in serie sono fantastici in nome dell'ottimizzazione (forse inutile e prematura), ma quando non riesci a capire il codice hai scritto quando vieni attraverso un insetto in esso due mesi più tardi ... Qual era il punto? Ti costerà tempo e fatica.

Mi riferisco spesso al Zen di Python in queste situazioni. In particolare:

Explicit is better than implicit.
Simple is better than complex.
    
risposta data 15.10.2010 - 20:16
fonte
1

Non scrivere codice di fantasia nel software di produzione. So che è bello poterlo scrivere davvero ed è più breve. La scrittura di codice di fantasia aumenta significativamente il valore "WTF / minuto", in altre parole diminuisce la qualità.

    
risposta data 19.10.2010 - 12:24
fonte
1

Ovviamente dipende interamente dalle circostanze. ma in generale, trovo che questa sia una buona regola empirica:

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

~ Brian Kernighan

    
risposta data 16.05.2012 - 15:02
fonte
0

Nella mia esperienza, la vittoria più grande in termini di codice breve fantasia tende ad usare la ricorsione piuttosto che l'iterazione. È anche una delle cose più difficili da capire a colpo d'occhio, a parte il codice, a meno che tu non stia lavorando nel tipo di linguaggio in cui tutto è ricorsivo comunque. Lo apprezzerei comunque per l'eleganza e la velocità di sviluppo che offre, ma cerco di assicurarmi che abbia commenti dettagliati se sembra opaco ai futuri manutentori o al mio futuro io.

    
risposta data 04.10.2010 - 13:19
fonte
0

Sto iniziando a non fidarmi mai dei commenti. Troppo spesso, i commenti non vengono aggiornati quando il codice viene aggiornato e sono ampiamente obsoleti o rappresentano le regole dei clienti / gestione che non sono più rilevanti.

È arrivato al punto in alcuni casi in cui i commenti non corrispondono nemmeno al codice che stanno descrivendo più.

Se devo scegliere tra breve / fantasia e più lungo / più facile da capire, scelgo sempre quest'ultimo, a meno che non ci sia un buon motivo veramente .

    
risposta data 16.10.2010 - 00:57
fonte
0

La leggibilità e la manutenibilità sono fondamentali, e il tuo secondo esempio (vale a dire quello più lungo) è molto più di entrambi. Ma perché limitarti a due opzioni? Anche il codice più lungo è troppo complesso (IMHO) per non notare ulteriormente. Lo metterei in un metodo a sé stante con Javadoc appropriato (o qualsiasi altra cosa) e un nome di metodo adatto.

    
risposta data 18.10.2010 - 00:39
fonte

Leggi altre domande sui tag