Come posso evitare di sentirmi sempre come se avessi ricostruito completamente il mio programma da zero, lo farei molto meglio? [chiuso]


91

Ho imparato una notevole quantità di codice, tuttavia, è sempre stato in un ambiente scientifico (non informatica), completamente autodidatta senza che nessuno mi guidasse nella giusta direzione. Quindi, il mio viaggio di programmazione è stato ... disordinato. Ho notato ora che ogni volta che costruisco un qualche tipo di programma, alla fine, mi rendo conto di come avrei potuto farlo in modo molto più elegante, molto più efficiente e in un modo che è molto più flessibile e facile da gestire in futuro. In alcune circostanze, in realtà sono tornato indietro e ho ricostruito le cose da zero, ma di solito questo non è praticamente fattibile. Mentre la maggior parte dei miei programmi finora sono stati relativamente piccoli, sembra abbastanza ingombrante riscrivere completamente i programmi di grandi dimensioni ogni volta che crei qualcosa.

Mi sto solo chiedendo, è un'esperienza normale? In caso contrario, come evitare che ciò accada? Ho provato a pianificare le cose in anticipo, ma non riesco proprio a prevedere tutto fino a quando non inizierò a elaborare un po 'di codice.


87
è normale, programma di più
Ewan,



43
Benvenuti in programmazione. Se non guardi il vecchio codice e pensi "urgh", allora dovresti iniziare a preoccuparti perché significa che hai smesso di imparare.
Caltor,

9
Onestamente quando ho visto questa domanda, ho riso - perché letteralmente anche tutti i programmatori che abbia mai parlato, incluso me stesso, hanno questa sensazione, costantemente, in ogni momento. Se volevi andare in un campo in cui ti sentivi come se il prodotto finale che facevi non avesse difetti - la programmazione era il campo sbagliato da scegliere.
Zibbobz,

Risposte:


4

Questa sensazione è del tutto normale e attesa. Significa che stai imparando. Quasi ogni volta che inizio un nuovo progetto, inizio in una direzione e finisco per progettarlo diversamente alla fine.

È pratica comune sviluppare prima un prototipo prima di iniziare la cosa reale. È anche comune rivisitare il vecchio codice e riformattarlo . Questo è più semplice se il tuo design è modulare : puoi facilmente riprogettare bit e pezzi alla volta senza dover eliminare completamente il tuo vecchio design.

Per alcune persone, aiuta a scrivere prima lo pseudo-codice . Altri trovano utile iniziare a scrivere commenti che descrivono cosa farà il codice, quindi scrivere il codice una volta che la struttura generale è lì. Queste due cose ti aiuteranno a pianificare meglio il tuo progetto e potrebbero evitare la necessità di una riscrittura.

Se fai parte di un team, avere un processo di revisione è cruciale per il processo di progettazione. Chiedi a qualcuno di rivedere il tuo codice in modo da poter imparare a migliorare il tuo design.


100

Questa è un'esperienza molto comune

La maggior parte delle persone con cui interagisco, e anch'io, mi sento così. Da quello che posso dire una ragione per questo è che impari di più sul dominio e sugli strumenti che usi mentre scrivi il tuo codice, il che ti porta a riconoscere molte opportunità di miglioramento dopo aver già scritto il tuo programma.

L'altra ragione è che potresti avere un'idea sulla soluzione ideale di codice pulito e quindi il mondo reale e le sue confuse limitazioni ti ostacolano, costringendoti a scrivere soluzioni imperfette e hack che potrebbero lasciarti insoddisfatto.

"Ognuno ha un piano fino a quando non viene preso a pugni in faccia."

Cosa fare al riguardo

In una certa misura dovrai imparare ad accettare che il tuo codice non sarà mai perfetto. Una cosa che mi ha aiutato in questo è la mentalità di "Se odio il codice che ho scritto un mese fa, significa che ho imparato e diventare un programmatore migliore".

Un modo per alleviare il problema è quello di essere costantemente alla ricerca di potenziali miglioramenti mentre lavori e rifletti continuamente. Assicurati di trovare un buon equilibrio tra refactoring e aggiunta di nuove funzionalità / correzione di bug. Questo non aiuterà con grandi problemi di progettazione, ma in genere ti lascerà con una base di codice più raffinata di cui puoi essere orgoglioso.


18
L'unica cosa che aggiungerei a questa risposta è, imparare e seguire i principi TDD durante la scrittura del codice. Tali test forniscono quindi un ambiente sicuro per il refactoring e la riscrittura mentre continui a migliorare come sviluppatore e desideri apportare modifiche al codice esistente.
David Arno,

10
@DavidArno qual è il punto di refactoring con i test presenti? È come aggiornare un sistema e fare un backup prima di ... 0 divertimento.
Džuris,

3
@ Džuris, :) Vero, se ti piacciono le sfide, non scrivere test
David Arno,

6
@ Džuris È come saltare fuori da un aereo con il paracadute!
JollyJoker,

3
@jamesqf - Questa è una caratterizzazione errata di ciò che fanno TDD e unit test - ad esempio, possono dirti che il tuo modello o algoritmo è implementato correttamente e che non hai rotto nulla durante il refactoring. Non possono dirti che il tuo modello è effettivamente utile. Questo è vero in un ambiente scientifico come in qualsiasi altro.
Formica P

46

Impara il refactoring: l'arte di migliorare gradualmente il codice. Impariamo tutti continuamente, quindi è molto comune rendersi conto che il codice che hai scritto tu stesso potrebbe essere scritto in un modo migliore.

Ma dovresti essere in grado di trasformare il codice esistente per applicare questi miglioramenti senza dover ricominciare da capo.


4
Questa pratica ti aiuterà anche a imparare a scrivere codice che è modulare e può essere refactored più facilmente. Tutte le lezioni del mondo non mi hanno insegnato questa abitudine tanto quanto dover rompere le vecchie grandi funzioni in blocchi gestibili, quindi non avrei dovuto riscrivere da zero. Ogni nuovo progetto, lo faccio meglio.
JKreft,

Il miglior punto di partenza secondo me per conoscere il refactoring è: il refactoring riguarda nuove funzionalità
Wildcard,

9

Se hai eccellenti requisiti statici e li capisci bene e hai tempo per un'analisi dettagliata, hai la possibilità di trovare un buon design di cui sarai ancora felice quando hai finito.

Anche in questo caso felice, potresti imparare nuove funzionalità linguistiche che avrebbero aiutato a realizzare un design migliore.

Tuttavia, di solito, non sarai così fortunato: i requisiti saranno meno che stellari e incompleti e anche se pensavi di averli compresi, si scopre che ci sono aree sulle quali hai formulato ipotesi non valide.

Quindi, i requisiti cambieranno man mano che gli utenti daranno un'occhiata ai tuoi risultati finali. Quindi qualcosa che gli utenti non controllano cambierà, ad esempio, la legislazione fiscale.

Tutto ciò che puoi fare è progettare, supponendo che le cose cambieranno. Rifattorizza quando puoi, ma renditi conto che tempo e budget spesso significheranno che il tuo risultato finale non è così elegante come se avessi saputo all'inizio ciò che sai ora.

Con il passare del tempo, migliorerai nello scovare i requisiti che ricevi e otterrai un naso per il quale parti del tuo progetto avranno probabilmente bisogno di flessibilità per assorbire il cambiamento.

Alla fine, però, accetta che il cambiamento sia costante e ignora la fitta che dice "Avrei potuto farlo meglio". Sii orgoglioso e felice di aver consegnato una soluzione.


Oppure, mettiti in un altro modo: impara a progettare per la flessibilità fin dall'inizio, senza introdurre spese generali non necessarie. Idealmente, la flessibilità deriva dalla semplicità. Quindi il tuo progetto ha la possibilità di superare il test di modifica dei requisiti.
cmaster,

3

Come posso evitare di sentirmi sempre come se avessi ricostruito completamente il mio programma da zero, lo farei molto meglio?

Quello che potresti fare è creare un prototipo usa e getta, prima di iniziare a fare il progetto "reale". Veloce e sporco. Quindi, quando ottieni un prototipo per dimostrare un concetto, conosci il sistema e come fare le cose correttamente.

Ma non essere sorpreso, se dopo N anni torni a questo codice e pensi "che casino".


3
Oppure, mostri il prototipo al tuo capo, dice "Brillante, lo farà". ti sposta su un altro progetto e il tuo prototipo diventa produzione.
RyanfaeScotland,

2
Questo consiglio è così comune che c'è un detto al riguardo. "Costruisci uno da buttare via". E quel consiglio è talmente abusato che c'è un detto al riguardo: "Se ne costruisci uno da buttare via, probabilmente ne butterai via due".
Eric Lippert,

2
@EricLippert La mia esperienza è stata terribile nella direzione opposta: se ne costruiamo una da buttare via, viene inevitabilmente spedita al cliente.
Jon,

2
@Jon: Sì, può succedere, in particolare quando si verificano errori di gestione "l'interfaccia utente sembra funzionare" con il codice effettivamente presente. Detto questo, la mia esperienza è sempre stata, come diceva uno dei miei colleghi "abbiamo abbastanza tempo per sbagliarlo due volte ma non abbastanza per costruirlo subito". :-)
Eric Lippert,

@EricLippert Questo è esattamente il motivo per cui è stata creata la GUI per ultima e NON per la GUI per un prototipo;)
BЈовић,

3

Ricorda questo mantra:

Il perfetto è nemico del bene .

La soluzione perfetta non è sempre la soluzione ideale . La soluzione ideale è quella che raggiunge lo stato "abbastanza buono" con la minima quantità di lavoro.

  • Soddisfa tutti i requisiti relativi a funzionalità e prestazioni?
  • È privo di bug critici che non è possibile correggere nell'architettura attuale?
  • Stima la quantità di lavoro che investirai nel mantenimento di questa applicazione in futuro. Lo sforzo per la riscrittura sarebbe più di quello a lungo termine che risparmierebbe?
  • Esiste la possibilità che il tuo nuovo design possa effettivamente peggiorare le cose?

Se rispondi sì a tutte queste domande, il tuo software è "abbastanza buono" e non c'è motivo di riscriverlo da zero. Applica invece le lezioni di progettazione che hai imparato al tuo prossimo progetto.

È perfettamente normale che ogni programmatore abbia un paio di programmi disordinati nel proprio passato. È successo più volte nella mia carriera come sviluppatore di software che ho guardato un po 'di codice, mi chiedevo "Che idiota ha scritto questo casino?", Ho controllato la cronologia delle versioni e ho notato che ero io da diversi anni fa.


3

Ho provato a pianificare le cose in anticipo, ma non riesco proprio a prevedere tutto fino a quando non inizierò a elaborare un po 'di codice.

È allettante pensare che una pianificazione perfetta ti dia una progettazione / architettura del software perfetta, tuttavia, risulta categoricamente falso. Ci sono due grossi problemi con questo. In primo luogo, "sulla carta" e "il codice" raramente corrispondono, e il motivo è perché è facile dire come dovrebbe essere fatto invece di farlo effettivamente . In secondo luogo, cambiamenti imprevisti nei requisiti diventano evidenti alla fine del processo di sviluppo che non avrebbero potuto essere motivati ​​sin dall'inizio.

Hai sentito parlare del movimento Agile? È un modo di pensare in cui valutiamo "reagire al cambiamento" anziché "seguire un piano" (tra le altre cose). Ecco il manifesto (è una lettura veloce). Puoi anche leggere su Big Design Up Front (BDUF) e quali sono le insidie.

Sfortunatamente, la versione aziendale di "Agile" è un gruppo di falsi (maestri di scrum certificati, processi pesanti nel nome di "Agile", forzare la mischia, forzare una copertura del codice del 100%, ecc.) E di solito si traduce in cambiamenti del processo asinino perché i gestori pensa che Agile sia un processo e un proiettile d'argento (di cui non è nessuno dei due). Leggi il manifesto agile, ascolta le persone che hanno iniziato questo movimento come lo zio Bob e Martin Fowler e non farti risucchiare dalla versione senza senso di "corporativo Agile".

In particolare, di solito puoi cavartela semplicemente facendo TDD (Test Driven Development) su codice scientifico , e ci sono buone probabilità che il tuo progetto software finisca maledettamente bene. Questo perché il codice scientifico di successo ha per lo più interfacce ultra-utilizzabili, con le prestazioni come una preoccupazione secondaria (e talvolta in competizione), e quindi puoi cavartela con un design più "avido". TDD obbliga il tuo software a essere ultra-utilizzabile , perché scrivi come vuoi che le cose vengano chiamate (idealmente) prima di implementarle. Forza anche piccole funzioni con piccole interfacce che possono essere rapidamente chiamate in modo semplice, "input" / "output", e ti mette in una buona posizione per refactoring nel caso in cui i requisiti cambino.

Penso che possiamo essere tutti d'accordo sul fatto che numpysia un software di calcolo scientifico di successo. Le loro interfacce sono piccole, super utilizzabili e tutto gioca bene insieme. Si noti che numpyla guida di riferimento raccomanda esplicitamente TDD: https://docs.scipy.org/doc/numpy-1.15.1/reference/testing.html . Ho usato TDD in passato per il software di imaging SAR (Synthetic Aperature Radar): e posso anche affermare che funziona molto bene per quel particolare dominio.

Avvertenza: la parte di progettazione di TDD funziona meno bene nei sistemi in cui un refactoring fondamentale (come decidere che è necessario che il software sia altamente concorrenziale) sarebbe difficile, come in un sistema distribuito. Ad esempio, se dovessi progettare qualcosa come Facebook in cui hai milioni di utenti simultanei, fare TDD (per guidare il tuo design) sarebbe un errore (comunque va bene usarlo dopo averne uno preliminare , e fare semplicemente "test del primo sviluppo "). È importante pensare alle risorse e alla struttura dell'applicazione prima di passare al codice. TDD non ti condurrà mai a un sistema distribuito a disponibilità elevata.

Come posso evitare di sentirmi sempre come se avessi ricostruito completamente il mio programma da zero, lo farei molto meglio?

Alla luce di quanto sopra, dovrebbe essere in qualche modo evidente che un design perfetto è in realtà impossibile da raggiungere, quindi inseguire un design perfetto è un gioco folle. Puoi davvero solo avvicinarti. Anche se pensi di poter riprogettare da zero, probabilmente ci sono ancora requisiti nascosti che non si sono mostrati. Inoltre, le riscritture impiegano almeno il tempo necessario per sviluppare il codice originale. Quasi certamente non sarà più breve, dal momento che è probabile che il nuovo design abbia problemi propri, oltre a dover implementare nuovamente tutte le funzionalità del vecchio sistema.

Un'altra cosa da considerare è che il tuo design conta davvero solo quando cambiano i requisiti .Non importa quanto sia brutto il design se nulla cambia (supponendo che sia completamente funzionale per gli attuali casi d'uso). Ho lavorato su una linea di base con un'istruzione switch di 22.000 righe (la funzione era ancora più lunga). È stato un design terribile? Cavolo sì, è stato terribile. L'abbiamo risolto? No. Funzionava perfettamente così com'era, e quella parte del sistema non ha mai causato crash o bug. È stato toccato solo una volta nei due anni in cui ero al progetto e qualcuno, hai indovinato, ha inserito un altro caso nello switch. Ma non vale la pena prendersi il tempo di riparare qualcosa che viene toccato così raramente, semplicemente non lo è. Lascia che il design imperfetto sia così com'è, e se non si rompe (o si rompe costantemente), non correggerlo. Così forse si potrebbe fare di meglio ... ma varrebbe la pena riscrivere? Cosa guadagnerai?

HTH.


2

Sono pienamente d'accordo con la risposta fornita da Andreas Kammerloher, ma sono sorpreso che nessuno abbia ancora suggerito di imparare e applicare alcune migliori pratiche di codifica. Naturalmente questo non è un proiettile d'argento, ma l'uso di un approccio orientato all'open, i modelli di progettazione, la comprensione dell'odore del codice e così via ti renderanno un programmatore migliore. Scopri qual è il miglior uso di librerie, framework ecc. C'è sicuramente molto di più, sto solo grattando la superficie.

Ciò non significa che non vedrai il tuo vecchio codice come una spazzatura totale (in realtà vedrai i programmi più vecchi anche più spazzatura di quanto tu faccia senza questa conoscenza) ma con ogni nuovo software che scrivi vedrai tu migliora. Nota anche che il numero delle migliori pratiche di codifica aumenta nel tempo, alcune semplicemente cambiano in modo da non arrivare mai alla perfezione. Accetta questo o piuttosto il percorso.

Un'altra cosa positiva è avere una revisione del codice. Quando lavori da solo è facile tagliare gli angoli. Se hai una seconda persona che sta esaminando il tuo codice, sarà in grado di indicare dove non segui queste best practice. In questo modo producerai un codice migliore e imparerai qualcosa.


1

Per aggiungere alle altre eccellenti risposte qui, una cosa che trovo utile è sapere dove vuoi arrivare .

È raro ottenere il via libera per un grosso pezzo di refactoring da solo. Ma spesso puoi fare piccoli pezzi di refactoring mentre vai avanti, "sotto il radar", mentre lavori su ciascuna area della base di codice. E se hai in mente un obiettivo, puoi sfruttare queste opportunità per muoverti, passo dopo passo, nella giusta direzione.

Potrebbe richiedere molto tempo, ma la maggior parte dei passaggi migliorerà il codice e ne varrà la pena il risultato finale.

Inoltre, sentirsi come se potessi fare di meglio è un buon segno ! Dimostra che ti preoccupi della qualità del tuo lavoro e che lo stai valutando in modo critico; quindi probabilmente stai imparando e migliorando. Non lasciare che queste cose ti preoccupino, ma non smettere di farle!


1

Ti sei imbattuto inavvertitamente in una delle più grandi sfide (avventure) dell'umanità, il ponte tra uomo e macchina. Il ponte tra l'uomo e la struttura fisica, ad esempio l'ingegneria civile, è in corso da circa 200 anni o più.

Poiché lo sviluppo del software è diventato davvero mainstream solo negli anni '90, ha circa 30 anni. Abbiamo imparato che non è tanto una disciplina ingegneristica quanto una scienza sociale, e abbiamo appena iniziato.

Sì, proverai TDD, refactoring, programmazione funzionale, modello di repository, sourcing di eventi, MV qualcosa, script Java (<- Fai questo, è pazzo), Model Binding, No Sql, Containers, Agile, SQL (<- fai questo è potente).

Non esiste una soluzione. Anche gli esperti stanno ancora afferrando le cannucce.

Benvenuto, e ti avverto, è un posto solitario; ma assolutamente affascinante.


1

Ho intenzione di andare un po 'contro il grano. Questo è incredibilmente comune , ma non è accettabile . Ciò indica che non stai riconoscendo i buoni modi di organizzare il codice mentre lo scrivi. La sensazione deriva dal fatto che il tuo codice non è semplice .

Anche la tua esperienza è stata mia per molto tempo, ma recentemente (negli ultimi due anni) ho prodotto più codice che non mi fa sentire come se avessi bisogno di buttare via tutto. Ecco all'incirca quello che ho fatto:

  1. Sii chiaro su quali ipotesi sta facendo un particolare blocco di codice. Genera errori se non sono soddisfatti. Pensa a questo da solo , senza dipendere dai dettagli su cosa sta facendo il resto del software. (Ciò che il resto del software sta facendo influenza le ipotesi che imposti e i casi d'uso che supporti, ma non influenza se si genera un errore in caso di violazione di un presupposto.)
  2. Smetti di credere che seguire regole, schemi e pratiche produrrà un buon codice. Butta via le mentalità e le pratiche che non sono ovvie e dirette. Questo è stato enorme. OO e TDD sono generalmente insegnati in un modo che non è fondato su considerazioni pratiche, come un insieme di principi astratti che dovresti seguire quando scrivi il codice. Ma questo è del tutto inutile per lo sviluppo di un buon codice. Se usi OO o TDD, dovrebbe essere usato come soluzione ai problemi che capisci di avere . In altre parole, dovrebbero essere usati solo quando si guarda un problema e si pensa "Ok, questo ha perfettamente senso ed è estremamente ovvio come una buona soluzione". Non prima.
  3. Quando scrivo codice, concentrati su due domande:
    • Sto usando funzionalità e librerie nel modo in cui sono state progettate per essere utilizzate ? Ciò include l'utilizzo per i tipi di problemi che si intendeva risolvere, o almeno quelli molto simili.
    • È semplice ? I miei colleghi e io saranno in grado di seguire facilmente la logica in seguito? Ci sono cose che non sono immediatamente evidenti dal codice?

Il mio codice ora è più "procedurale", con il quale intendo che è organizzato in base alle azioni da intraprendere piuttosto che alle strutture di dati che utilizza. Uso oggetti in linguaggi in cui le funzioni autonome non possono essere sostituite al volo (C # e Java non possono sostituire le funzioni al volo, Python può). Ho la tendenza a creare più funzioni di utilità ora, che spingono via un po 'di fastidioso piatto di caldaia in modo da poter effettivamente leggere la logica del mio codice. (Ad esempio, quando avevo bisogno di elaborare tutte le combinazioni di elementi in un elenco, ho spinto l'indice in loop verso un metodo di estensione che restituisceTuples in modo che la funzione originale non sia ingombra di quei dettagli di implementazione.) Passo molte più cose come parametri alle funzioni ora, invece di avere una funzione che raggiunga un altro oggetto per recuperarla. (Il chiamante lo prende o lo crea invece e lo passa.) Ora lascio altri commenti che spiegano cose che non sono ovvie solo guardando il codice , il che rende più facile seguire la logica di un metodo. Scrivo test solo in casi limitati in cui sono preoccupato per la logica di qualcosa che ho appena fatto, ed evito di usare derisioni. (Io lo faccio più input / output sul test pezzi isolati di logica.) Il risultato è il codice che non è perfetto , ma che in realtà sembra a posto, anche 2 o 3 anni dopo. È il codice che risponde abbastanza bene al cambiamento; le cose minori possono essere aggiunte o rimosse o modificate senza che l'intero sistema cada in pezzi.

In una certa misura, è necessario passare attraverso un periodo in cui le cose sono un disastro in modo da avere una certa esperienza di andare fuori di. Ma se le cose sono ancora così incasinate da voler buttare via tutto e ricominciare, qualcosa non va; non stai imparando.


0

Ricordando che il tempo è limitato. E anche il tuo tempo futuro è limitato. Che si tratti di lavoro, scuola o progetti personali, quando si tratta di codice di lavoro , devi chiederti "riscrivere questo è il miglior uso del mio tempo limitato e prezioso?". O forse "è questo l' uso più responsabile del mio tempo limitato"?

A volte la risposta sarà inequivocabilmente . Di solito no. A volte sarà sul recinto e dovrai usare la tua discrezione. A volte è un buon uso del tuo tempo semplicemente per le cose che imparerai facendo.

Ho molti progetti, sia di lavoro che personali, che trarrebbero beneficio da una porta / riscrittura. Ho anche altre cose da fare.


0

È una parte completamente normale dell'apprendimento. Ti accorgi degli errori mentre procedi.

Ecco come migliorare e non è qualcosa che dovresti evitare.


0

Puoi darti l'esperienza di sapere che l'impulso seducente di riscrivere è di solito improduttivo. Trova qualche progetto open source vecchio, peloso, inelegante di moderata complessità. Prova a riscriverlo da zero e guarda come stai.

  • Il tuo design da zero è finito elegante come speravi?
  • La tua soluzione è davvero allo stesso identico problema? Quali caratteristiche hai lasciato fuori? Quali casi limite ti sei perso?
  • Quali lezioni guadagnate duramente nel progetto originale hai cancellato nel perseguimento dell'eleganza?
  • Dopo aver aggiunto quei pezzi mancanti al tuo design, è pulito come era senza di loro?

Alla fine, il tuo istinto si sposterà dal pensare "Potrei riscrivere questo sistema molto meglio" al pensare "la crudeltà di questo sistema può essere indicativa di una complessità che non è immediatamente evidente".

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.