Come superare la programmazione per coincidenza? [chiuso]

24

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

Do you ever watch old black-and-white war movies? The weary soldier advances cautiously out of the brush. There's a clearing ahead: are there any land mines, or is it safe to cross? There aren't any indications that it's a minefield—no signs, barbed wire, or craters. The soldier pokes the ground ahead of him with his bayonet and winces, expecting an explosion. There isn't one. So he proceeds painstakingly through the field for a while, prodding and poking as he goes. Eventually, convinced that the field is safe, he straightens up and marches proudly forward, only to be blown to pieces.

The soldier's initial probes for mines revealed nothing, but this was merely lucky. He was led to a false conclusion—with disastrous results.

As developers, we also work in minefields. There are hundreds of traps just waiting to catch us each day. Remembering the soldier's tale, we should be wary of drawing false conclusions. We should avoid programming by coincidence—relying on luck and accidental successes—in favor of programming deliberately...

Ma non sono molto soddisfatto del modo in cui descrivono il problema "come superarlo". Sì, devi pensare al futuro prima di scrivere il codice, ma come esercitarlo? L'unica cosa che posso pensare è aggiungere funzionalità a progetti Open source esistenti, in cui è necessario avere conoscenza sia del "cosa sto facendo ora" sia del "come funzionano gli altri pezzi di codice", e non è così pertinente quando stai scrivendo i tuoi progetti.

EDIT:

un riepilogo dai tuoi post:

  • Non indovinare la tua prossima mossa, dimostra che è corretta
  • Test unitario e refactor il più possibile, quando necessario
  • Aggiungi funzioni-prova-compila 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:)

    
posta py_script 19.06.2013 - 08:25
fonte

5 risposte

26

Non devi pensare al futuro, 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 quello che fanno, fare ciò che dicono e non avere dipendenze nascoste. Quindi qualcuno che li chiama può più facilmente ragionare su ciò che faranno.

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

Scrivi test unitari. I test unitari sono ottimi per catturare l'effettivo comportamento del codice 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 test male, allora le probabilità sono che si comporterà in modo diverso da quello che pensi. Quindi "lo aggiusti" con qualche cambiamento casuale, e hai la risposta giusta per il momento, ma non hai idea di come sia realmente successo. Ora stai programmando per coincidenza. Ma quando aggiungi 5 linee e poi esegui il test, le probabilità che tu abbia la risposta giusta perché funziona come pensi che funzioni è molto meglio. Posso dire per esperienza che 5 blocchi di 10 linee ciascuno, testati individualmente, sono una bestia molto diversa da 50 righe di codice testate tutte insieme.

Refactor spietatamente. Molte volte ho individuato un refactoring che renderà il mio codice un po 'più semplice, ma mi prendo un sacco di lavoro che non volevo fare. Dopo aver iniziato deliberatamente a trattare questi refactoring come una priorità, ho scoperto che di solito si ripaga da solo nel giro di un mese. Ma nota la chiave, i refactoring su cui mi concentro sono quelli che semplificano la vita quotidiana, e non quelli che soddisfano qualche estetica arbitraria di migliore o più generale. Quei refactors che ho imparato a essere molto più cauti con.

Nessuna di queste cose richiede una pianificazione anticipata. Ma semplificano la comprensione del codice esistente e rendono semplice implementare il tuo prossimo blocco in modo deliberato.

    
risposta data 19.06.2013 - 09:32
fonte
40

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

Questo vale soprattutto per la modifica del codice esistente, ma anche per un codice nuovo di zecca, perché nessuno inizia veramente da zero. Stai sempre costruendo su librerie standard, sistemi operativi o almeno architetture di processore.

In altre parole, non hai finito finché non sai perché la tua correzione funziona. Il percorso che prendi per arrivarci non ha importanza. Talvolta le permutazioni casuali possono essere utili per restringere un bug difficile da diagnosticare, a patto che ci si dedichi in seguito a chiedersi: "Ok, cambiando vero a falso, ma perché?"

    
risposta data 19.06.2013 - 17:56
fonte
16

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

Do not touch this. It works. We don't know how or why, but it works.1

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

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

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

    
risposta data 19.06.2013 - 09:35
fonte
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 per tentativi ed errori. Prova qualcosa; se funziona, ottimo, se non, prova qualcos'altro.

Nella programmazione, specialmente quando si usa 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.

In alcune occasioni ho istruito nuovi programmatori e la tendenza a provare a digitare cose casuali per vedere se funziona è comune. Scriveranno una riga, quindi si rivolgono a me e chiedono: "Funzionerebbe in questo modo?" mentre era chiaro che non avevano assolutamente alcun indizio se potesse.

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

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

    
risposta data 19.06.2013 - 16:57
fonte
2

È fin troppo facile codificare, testare e risolvere "sulla linea di regata". Hai alcune funzionalità che hanno dato X & Y, produce Z. Ma cosa succede se X è corrotto e Y non è disponibile? Cosa succede se non riesci a produrre Z? Ricorda sempre cosa può andare storto e prendine nota per il ciclo di test.

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

Il metodo significativo, i nomi di classi e variabili aiutano a migliorare la leggibilità.

Se ti imbatti in un odore di codice, allora FERMA. È improbabile che quell'odore se ne vada e in seguito un piccolo sforzo potrebbe salvarti un'enorme quantità di dolore in seguito.

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

Resisti all'impulso di aggiungere funzionalità straordinarie (a meno che non sia il tuo progetto preferito). Qualsiasi codice aggiuntivo deve essere progettato, scritto, testato e mantenuto. Se non è richiesto dal cliente / azienda, rischi di diventare un enorme drenaggio delle tue risorse.

    
risposta data 19.06.2013 - 11:00
fonte

Leggi altre domande sui tag