Come superare la programmazione per coincidenza? [chiuso]


24

Nel libro The Pragmatic Programmer , gli autori menzionano il concetto di programmazione per coincidenza . Spiega cos'è, perché è causato, quali sono i pericoli che potresti incontrare e si confronta con un campo minato in una guerra.

Hai mai visto vecchi film di guerra in bianco e nero? Il soldato stanco avanza cautamente dalla spazzola. C'è una radura in vista: ci sono mine terrestri o è sicuro attraversare? Non ci sono indicazioni che si tratti di un campo minato: nessun segno, filo spinato o crateri. Il soldato colpisce il terreno davanti a sé con la sua baionetta e sussulti, aspettandosi un'esplosione. Non ce n'è uno. Quindi procede minuziosamente attraverso il campo per un po ', stimolando e frugando mentre procede. Alla fine, convinto che il campo sia sicuro, si raddrizza e marcia orgogliosamente in avanti, per poi essere fatto a pezzi.

Le prime sonde del soldato per le mine non rivelarono nulla, ma questo fu semplicemente fortunato. Fu condotto a una falsa conclusione, con risultati disastrosi.

Come sviluppatori, lavoriamo anche nei campi minati. Ci sono centinaia di trappole che aspettano solo di prenderci ogni giorno. Ricordando la storia del soldato, dovremmo essere cauti nel trarre conclusioni false. Dovremmo evitare la programmazione per coincidenza - basandoci sulla fortuna e sui successi accidentali - a favore della programmazione deliberatamente ...

Ma non sono molto soddisfatto del modo in cui descrivono il problema "come superarlo". Sì, devi pensare in anticipo prima di scrivere il codice, ma come esercitarlo? L'unica cosa che posso pensare è l'aggiunta di funzionalità ai progetti Open source esistenti, in cui è necessario conoscere sia il "cosa sto facendo ora" sia il "Come funzionano gli altri pezzi di codice", e non è così applicabile quando scrivi i tuoi progetti.

MODIFICARE:

un riassunto dei tuoi post:

  • Non indovinare la tua prossima mossa, dimostra che è corretta
  • Unit test e refactor il più possibile, quando necessario
  • Aggiungi funzionalità – compila – prova spesso
  • Se non riesci a spiegare il codice a un noob, probabilmente stai programmando per coincidenza.

A proposito, è difficile accettare una risposta, è davvero difficile. Tutte le risposte sono davvero fantastiche :)


6
Aiuterebbe le persone che potrebbero non leggere il libro da molto tempo avere un link come pragprog.com/the-pragmatic-programmer/extracts/coincidence .
btilly

A meno che tu non abbia una carriera di programmazione molto breve (o non sia un one man shop), è probabile che ti imbatti in codice che sembra stranamente familiare e un po 'di code-walking più tardi, il centesimo scende: è tuo. Non è solo una considerazione Open Source ...
Robbie Dee,

@Robbie Dee. puoi chiarirlo un po 'di più? Non ti capisco. In effetti, ho una breve carriera di programmatore e questo è il motivo del tag junior-programmatore.
py_script il

2
@py_script Stavo solo sottolineando che puoi facilmente imbatterti nel tuo codice anni dopo (ed esserne confuso) come quello di qualcun altro. Quindi, se inizi con buone abitudini, pagherai dividendi in seguito.
Robbie Dee,

Risposte:


26

Non devi pensare in anticipo, devi solo essere molto chiaro su ciò che è stato fatto ed essere molto chiaro su ciò che stai facendo in questo momento.

Le subroutine dovrebbero dire ciò che fanno, fare ciò che dicono e non avere dipendenze nascoste. Quindi qualcuno che li chiama può più facilmente ragionare su cosa faranno.

Evita lo stato globale. (Variabili, caratteri singoli, ecc.) Più stato devi avere nella tua testa per capire cosa fanno le cose, più difficile è capire cosa dovrebbe succedere e trovare i casi limite.

Scrivi unit test. I test unitari sono ottimi per catturare l'effettivo comportamento del codice che hai appena scritto, piuttosto che il comportamento ideale che speri di trovare.

Riduci il ciclo di modifica / compilazione / test. Quando aggiungi una grande porzione di codice e fai un test scadente, allora le probabilità sono che si comporterà in modo diverso da quello che pensi. Quindi lo "aggiusti" con qualche cambiamento casuale e hai ottenuto la risposta giusta per il momento, ma non hai idea di come sia realmente successo. Ora stai programmando per coincidenza. Ma quando aggiungi 5 righe e poi esegui il test, le probabilità che tu abbia ottenuto la risposta giusta perché funziona come pensi che funzioni molto meglio. Posso dire per esperienza che 5 blocchi di 10 righe ciascuno, testati singolarmente, sono una bestia molto diversa rispetto a 50 righe di codice testate tutte in una volta.

Refactor spietatamente. Molte volte ho individuato un refactor che renderà il mio codice un po 'più semplice ma richiederebbe un sacco di lavoro che non volevo fare. Dopo aver iniziato ad affrontare deliberatamente quei refattori come una priorità, ho scoperto che di solito si ripaga da solo entro un mese. Ma nota la chiave, i refactor su cui mi concentro sono quelli che rendono la vita quotidiana più semplice, e non quelli che incontrano qualche estetica arbitraria di migliore o più generale. Quei refactor con cui ho imparato ad essere molto più cauto.

Nessuna di queste cose richiede una pianificazione anticipata. Ma tutti rendono più semplice la comprensione del codice esistente e quindi semplificano l'implementazione del prossimo piccolo pezzo in modo deliberato.


Grazie, risposta davvero buona. Penso che la parte del ciclo sia davvero preziosa. Puoi darmi esempi di refactoring che dovresti fare loro, ma ci vorrà molto tempo per implementarli e questo potrebbe scoraggiare qualcuno?
py_script il

1
Ho molti esempi. In un progetto C ++ ho creato classi senza metodi di stringificazione. Dopo averlo creato, il debug è diventato più semplice e lo sviluppo ha accelerato. In un progetto Perl avevamo un hash di configurazione in cui ogni sviluppatore aveva la propria copia ottimizzata di ogni nuova configurazione. L'aggiunta di parametri di configurazione è stata una seccatura perché dovevi modificare tutte le configurazioni degli sviluppatori. Ho scritto un sistema di template per gli hash e questo è diventato più facile. In un sistema di reporting ho aggiunto una funzione per mostrare risultati intermedi. Il mio sviluppo ha accelerato e ho anche ricevuto una segnalazione di bug da parte dell'utente ...
btilly

1
dove il dipartimento delle finanze aveva tracciato la mia logica e trovato la domanda esatta su cui avevo sbagliato e quale fosse il mio bug. (Stavo accidentalmente schiacciando le righe duplicate con UNIONdove avevo bisogno UNION ALL.) E così via.
btilly

1
Entro un mese? Di solito trovo che ogni volta che tocco il codice che ritengo debba essere sottoposto a refactoring, ma non ho effettuato il refactoring, ci vuole quasi il tempo necessario per riformattarlo.
Amy Blankenship,

1
@AmyBlankenship Sì. Entro un mese. A volte ridicolmente dentro, a volte no. La cosa del file di configurazione che ho menzionato sopra è un esempio di "a volte no". Mi ci sono voluti alcuni giorni per scrivere, documentare e testare un nuovo motore di template. Quindi riscrivi la configurazione esistente per usarla ed essere molto più breve, ma produce la stessa esatta struttura dati. (Questa è stata la parte più difficile del progetto.) Quindi ... giorni sprecati, senza risultati assolutamente visibili. Eppure lo sforzo è stato ripagato in poco meno di un mese, ma da allora ha guadagnato interesse.
btilly

41

Si riduce praticamente a non indovinare . Principalmente i nuovi programmatori lo fanno, ma ho visto farlo anche i veterani, perché pensano che risparmi tempo di ricerca. Qualcosa non funziona, quindi aggiungi a +1o a -1, cambia a truein falseo viceversa, riordina alcune istruzioni, aggiungi o modifica ritardi, cambia priorità di thread e altre piccole trasformazioni, fondamentalmente testando permutazioni casuali fino a quando non funziona.

Ciò si applica principalmente alla modifica del codice esistente, ma è anche un fattore nel codice nuovo di zecca, perché nessuno inizia veramente da zero. Ti stai sempre basando su librerie standard, sistemi operativi o almeno architetture di processori.

In altre parole, non hai finito finché non sai perché la tua correzione funziona. Il percorso che prendi per arrivarci non ha molta importanza. Anche le permutazioni casuali a volte possono essere utili per restringere un bug che è difficile da diagnosticare, fintanto che ti prendi il tempo successivo per chiederti: "Okay, cambiando vero in falso corretto, ma perché?"


1
Ottimo punto +1. Da nessuna parte questo vale più delle correzioni di codice ...
Robbie Dee,

Vero anche per me, sfortunatamente. Ad essere onesti ci sono difficoltà oggettive come la mancanza di documentazione a volte. Oggi correggevo un po 'il mio codice e mi sono reso conto che non sapevo a cosa servisse un parametro, perché mancava la documentazione. Sappiamo solo che è un numero.
py_script il

Lo ammetto. Di fronte alla sindrome dello stuzzicadenti pendente, può essere più semplice impilare gli s finché non funziona piuttosto che capire quanti strati di fuga stai combattendo con ...
btilly

16

Il commento più spaventoso che abbia mai incontrato in un programma è stato

Non toccarlo. Funziona. Non sappiamo come o perché, ma funziona. 1

ed è spaventoso solo perché riconosce che il pezzo di codice è stato il risultato della programmazione per coincidenza .

Per evitare la programmazione per coincidenza, dovresti essere in grado di spiegare (a un collega, te stesso o un'anatra di gomma ) esattamente cosa fa il codice e perché funziona. I proiettili per la programmazione deliberatamente sono principalmente di aiuto per raggiungere l'obiettivo di essere in grado di spiegare il codice.


1 Per contesto, questo commento è apparso nel codice che gestisce i cambi di contesto in un sistema operativo primitivo. Il codice era già in produzione da diversi anni quando l'ho incontrato.


2
questo è anche chiamato voodoo chicken coding c2.com/cgi/wiki?VoodooChickenCoding
menoSeven

1
Anche se il programmatore ritiene che sia vero, quel tipo di commento non è di grande aiuto. Il codice potrebbe essere stato complesso, ma se dovessi leggere il codice in altro modo, potresti pensare che fosse diretto. Tutto il commento fa è aumentare la paranoia!
Robbie Dee,

3
Questo può accadere anche quando si mantiene una vecchia base di codice, in una lingua la maggior parte dell'attuale team di sviluppo non è molto a suo agio.
pcurry

Quindi l'anatra di gomma non è solo per il debug. Bello ... Penso che stiamo lavorando sulla stessa azienda, abbiamo molti commenti come questo: P
py_script

ci sono situazioni in cui una correzione funziona solo a causa di un problema tecnico in un'API e non esiste una correzione migliore e logica. Il debug di alcune librerie compilate di terze parti può arrivare fino al debug del kernel. E anche se hai riscontrato il problema, dopo ore di debug c'è poco che puoi fare. Quindi affronti il ​​problema in modo diverso. Adotti il ​​modello "scatola nera" che ti costringe a programmare per coincidenza. Giochi con lo strano comportamento della scatola nera e se riesci a farlo funzionare come desideri, GRANDE, aggiungi un commento con "La magia non toccare" e vai avanti.
Radu Simionescu,

7

Per i nuovi programmatori, la parte più importante del superamento di questo è capire veramente cosa stanno facendo.

In molte aree, quando non sai come fare qualcosa, vai semplicemente per tentativi ed errori. Prova qualcosa; se funziona, ottimo, in caso contrario, prova qualcos'altro.

Nella programmazione, specialmente quando si utilizza un linguaggio che ha il concetto di comportamento indefinito (come C o C ++), questo approccio semplicemente non funziona, perché il successo non è più una decisione booleana. Puoi avere cose che "tipo di" funzionano, che a volte funzionano, che funzionano per alcuni input ma non per altri.

A volte ho istruito nuovi programmatori e la tendenza a provare a scrivere cose casuali per vedere se funziona è comune. Digitavano una riga, quindi si rivolgevano a me e chiedevano "Funzionerebbe in questo modo?" mentre era chiaro che non avevano assolutamente idea se potesse.

L'asporto è che come nuovo programmatore devi davvero essere in grado di spiegare cosa fa il tuo codice. Devi imparare a leggere il codice, non solo a scriverlo.

(Naturalmente questo vale anche per programmatori esperti, ma la mia esperienza qui è stata principalmente con nuovi principianti completi.)


<< Devi imparare a leggere il codice, non solo a scriverlo. >> Quindi, riguardo alla mia domanda iniziale, pensi che mi aiuterà ad aggiungere funzionalità ai progetti open source?
py_script il

2

È troppo facile codificare, testare e correggere "sulla linea di corsa". Hai alcune funzionalità che danno X e Y, produce Z. Ma cosa succede se X è corrotto e Y non è disponibile? Cosa succede se non riesci a produrre Z? Tieni sempre presente cosa può andare storto e prendine nota per il ciclo di prova.

Mantieni le tue routine brevi e descrittive: il codice migliore richiede pochi (se presenti) commenti.

Metodi, nomi di classi e variabili significativi contribuiscono notevolmente alla leggibilità.

Se ti imbatti in un odore di codice, STOP. È improbabile che quell'odore scompaia e un piccolo sforzo ora potrebbe farti risparmiare un sacco di dolore in seguito.

Includi i test nel tuo processo di sviluppo. Suggerirei l'uso di BDD piuttosto che TDD in quanto ti costringe a descrivere ciò che stai mirando a realizzare piuttosto che affidarti ciecamente a una serie di test che potrebbero darti un falso senso di sicurezza.

Resisti alla tentazione di aggiungere funzionalità extra (a meno che non sia il tuo progetto per animali domestici). Qualsiasi codice aggiuntivo deve essere progettato, scritto, testato e mantenuto. Se non richiesto dal cliente / azienda, si rischia che ciò diventi un enorme drenaggio delle risorse.

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.