Come faccio a superare la paralisi tramite analisi durante la codifica?

37

Quando avvii un nuovo progetto, spesso inizio a pensare immediatamente ai dettagli dell'implementazione. "Dove metterò il DataBaseHandler? Come dovrei usarlo? Le classi che vogliono usarlo si estendono da qualche superclasse astratta ...? Dovrei usare un'interfaccia? Che livello di astrazione userò nella mia classe che contiene metodi per inviare richieste e analizzare i dati? "

Finisco lo stallo per molto tempo perché voglio codice per estensibilità e riusabilità. Ma mi sembra quasi impossibile passare oltre pensando a come implementare perfettamente.

E poi, se provo a dire "fanculo, basta farlo!", ho colpito un muro di mattoni abbastanza velocemente perché il mio codice non è organizzato, ho mescolato livelli di astrazione, ecc.

Quali sono alcune tecniche / metodi che hai per lanciare in un nuovo progetto e anche impostare una struttura logica / modulare che si adatti bene?

- - EDIT - -

Bene, questo è già il tipo di domanda a cui è difficile accettare una risposta, ma volevo ottenere un ulteriore feedback, vedere se c'è un consenso. TDD suona molto bene e, francamente, ho intenzione di essere più veloce nell'usare JUnit, ecc. Allo stesso tempo, cosa pensano i fan di TDD del fatto che un punto legittimo in relazione al TDD risolve il mio problemi particolari, è che TDD non sembra davvero affrontare la questione del design. Certo, sono d'accordo che TDD mi aiuterà a definire ciò che voglio fare e poi a lavorare gradualmente su come, ma ci sono molti diversi modelli / strutture di design che potrebbero passare attraverso i test unitari. È proprio così: mette alla prova singole UNITÀ. Immagino di essere un po 'confuso ... non so. Forse sto solo cercando di procrastinare ancora di più cercando di capire qualche formula magica, ma mi piacerebbe sentire come alcuni dei veterani si avvicinano a quest'area ...

Grazie!

    
posta LuxuryMode 23.06.2011 - 05:22
fonte

9 risposte

16

Raccomando di utilizzare Test-Driven-Development , ci vuole un po 'per abituarsi soprattutto quando si lavora con un buon IDE come Eclipse, ma i vantaggi sono grandi.

Fondamentalmente quello che fai è scrivere i test sul tuo codice prima di scrivere il codice stesso. Quindi sei costretto a guardare il tuo codice dal punto di vista di come verrà utilizzato, il che significa che le tue interfacce si evolvono e più scenari vengono implementati.

Un'altra caratteristica è che si implementano in blocchi molto piccoli (diventano più grandi, più esperti si trovano nella tecnica e nella programmazione), quindi ti costringono a concentrarti su un problema molto piccolo e ben definito ogni volta.

E anche dal momento in cui scrivi per la prima volta un test e solo dopo esegui, hai davanti a te un test negativo. Quindi, se sei come la maggior parte dei programmatori, non ti lascerai trasportare da un'analisi pazza perché penserai: "Devo fare in modo che questo test funzioni".

Un breve esempio di java:
Diciamo che voglio sviluppare un programma che legge e scrive un messaggio da un db.

Quindi inizio con la prima azione ben definita, ho bisogno di un DB:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
}

ok, quindi qui vedo che ho bisogno di implementare la classe DbConnector.getDB in modo che restituisca il DB, fino a quando questo test fallisce. Vado a farlo ...

Non aggiungo la prossima cosa che voglio fare, carica il messaggio dal DB:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
}

Ora ho aggiunto un'altra piccola funzionalità al DB che è di recuperare un messaggio, vado a implementarlo, una volta terminato, continuo ad andare avanti di una funzione alla volta fino a raggiungere qualcosa di simile:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
  message = "foo bar";
  db.storeMessage(message);
  message = db.fetchMessage();
  assertEquals("foo bar", message);
}

Potrebbe sembrare un esempio molto semplice, ma funziona anche per compiti più complessi. So che all'inizio è molto dispendioso in termini di tempo, ma appena ci si abitua, si vede che in effetti è molto più efficiente. Per esempio si evita la paralisi per analisi e per un altro si ottiene un codice molto più robusto che di solito ha meno bug e passa attraverso meno iterazioni.

    
risposta data 23.06.2011 - 05:56
fonte
10

Questo mi succede, quindi ho preso l'abitudine di accettare (e abbracciare) una mentalità di continuo refactoring. Faccio la cosa più semplice che possa funzionare, quindi pulisco, organizzo, disaccoppia, testalo e proseguo.

Questo non vuol dire che non ci sia molta pianificazione in corso, ma accade molto rapidamente e di più, spesso come scarabocchi su scarti o nella mia testa. Tutto sommato, a volte chiamo questo piccolo processo di micro-iterazioni perché impiegano 5-20 minuti ciascuna e dall'esperienza occorrono 2-3 per finire quello a cui sto lavorando (a seconda di quello che sto facendo, ovviamente).

Come nota a margine: ho istruito un numero di persone in diverse forme di scrittura (rapporti, saggi e scrittura tecnica in generale) e questo è lo stesso modo in cui li faccio scrivere cose per superare il blocco dello scrittore. "Spiega tutto ciò che ti viene in mente sulla pagina, poi ne ricaviamo un senso e lo separiamo in paragrafi e controlliamo il flusso: se necessario, lo riscriveremo anche".

    
risposta data 23.06.2011 - 05:55
fonte
2

Alcune cose che potrebbero funzionare:

  • Identifica il problema principale che stai cercando di risolvere: qual è il vero cuore della cosa che vuoi fare? Implementa proprio questo, e il minimo indispensabile del codice di supporto per farlo funzionare. Una volta che funziona in modo soddisfacente, costruisci iterativamente, rifattorici senza pietà ad ogni passo.
  • Verifica se altri paradigmi di programmazione funzionano per te. Nonostante tutti i suoi meriti, la programmazione orientata agli oggetti non è la risposta a tutti i problemi, e non tutti i cervelli dei programmatori lavorano in questo modo. Scegli un linguaggio (puro) funzionale; scrivere un codice procedurale; immergersi fino al livello hardware e fare qualche C o forse anche assemblatore; ecc. Alcune lingue che potrebbero sconvolgerti (supponendo che tu stia utilizzando qualcosa come C ++ / Java / C # / VB / ...): Haskell, ML, Lisp (vari dialetti tra cui scegliere), Erlang, Prolog, Smalltalk, Javascript (se si lascia andare cercando di farlo comportarsi come Java e invece abbracciare la sua natura di chiusura), C, Pascal, awk e probabilmente una dozzina di altri. La caratteristica fondamentale è che devono essere molto diversi da quelli che usi ora. Questo non è qualcosa che vuoi fare su un grande progetto con molto in palio, ma farlo per progetti collaterali (personali o legati al lavoro) ti darà nuove conoscenze.
  • Utilizza un metodo di progettazione radicalmente diverso. Vedi se riesci a riprendere il disegno da una diversa angolazione. Presumo che di solito inizi a disegnare stendendo le tue lezioni; che ne dici di iniziare con le strutture dati per un cambiamento? O perché non progettare l'interfaccia utente prima, disegnando letteralmente i moduli di input prima di progettare qualsiasi funzionalità?
risposta data 23.06.2011 - 07:57
fonte
1

Per molte decisioni di progettazione può aiutare a fare un "picco" che è un breve sforzo di ricerca limitato nel tempo in cui è possibile esplorare alcune opzioni di architettura o di progettazione mediante la codifica di un prototipo di lancio. Ad esempio potresti esplorare l'uso di alcune librerie open source o come organizzerai le tue classi e interfacce. La chiave è di mantenerla breve in modo da poter provare un altro approccio se il primo è insoddisfacente e si spera che acquisirai una conoscenza sufficiente nell'esercizio per prendere meglio le decisioni architettoniche o per dimostrare il concetto. L'esercizio in sé comporta un coding immediato che aiuta a uscire dal "blocco degli scrittori" senza necessariamente impegnarsi a fare il "git 'er" troppo presto.

Dopo questo è utile utilizzare l'approccio TDD o BDD che Asaf ha menzionato per portare avanti l'implementazione del progetto.

    
risposta data 23.06.2011 - 06:36
fonte
1

Non ne avrai bisogno , quindi non pensare troppo all'inizio.

Investi più tempo a definire, a capire l'obiettivo e il problema.

"Estensibilità e riusabilità" sono i risultati naturali del ciclo di vita dei programmi software ben scritti.

    
risposta data 23.06.2011 - 10:21
fonte
0

Suppongo che stiamo guardando un progetto di medie dimensioni.
Comincerei andando sul tavolo da disegno. Dovresti avere i tuoi requisiti funzionali e non funzionali pronti prima di farlo. Per prima cosa dovresti elaborare l'architettura del software, ovvero guardare tutti gli schemi architettonici che si adattino alle tue esigenze. Una volta che hai deciso come appare l'architettura, dovresti entrare nel design di basso livello, e guardare tutte le entità, classi e funzionalità. Qui, proverai nuovamente a identificare i modelli di progettazione che si adattano. Nel processo, saprai quali sono le tue classi base e le interfacce di cui avresti bisogno
Puoi quindi costruire il framework ed eseguire alcuni test rapidi per vedi se questo soddisfa tutti i tuoi requisiti non funzionali
Vorrei quindi andare con Test Driven Development come suggerito da @Asaf.

Ricorda che, nonostante il tempo dedicato al design e all'architettura, è sempre disposto a rivedere l'architettura in caso di necessità.

    
risposta data 23.06.2011 - 07:38
fonte
0

Penso che questa sia una grande domanda e nulla funzionerà per tutti. Penso che una tale paralisi sia un naturale sottoprodotto di diventare sempre più competente nel tuo campo. Detto questo, ecco alcune cose che aiuto, ma non risolvono il problema:

  • Metti da parte il tuo progetto incontaminato e lavora sulla versione fugly. Questa è la versione in cui ti dici: un. Il codice non dovrebbe essere carino. In realtà, dì a te stesso, non è consentito apportare importanti refactoring e riformattare. Lascia che sia assolutamente disorganizzato e liberati dai vincoli del buon codice. b. Deve solo funzionare. c. È sempre sorprendente per me ciò che apprendo sullo spazio del problema quando butto fuori tutte le altre preoccupazioni. Finisco anche con piccole curiosità che spesso mi aiutano a trovare il design giusto in un modo più illuminato.

  • Metti da parte un intervallo di tempo decente in cui sei nel progetto, solo senza un computer. Cerca di concettualizzare ciò che stai cercando di realizzare e cercare quello zen magico che trascende la follia OO / Design Pattern.

risposta data 23.06.2011 - 07:39
fonte
0

Dai un'espressione concreta ai tuoi pensieri: scrivi / scrivi, disegna o qualsiasi altra cosa. Questo ti aiuterà a rivisitare i tuoi pensieri quando necessario; ti impedirà di andare in circolo; ti aiuta a pensare in modo più chiaro.

Ogni volta che mi vedo andare da nessuna parte e dappertutto a pensare a qualcosa, le digito e mi aiuta a pensare chiaramente.

    
risposta data 23.06.2011 - 09:19
fonte
0

Di solito inizio da zero, creare il prototipo più semplice possibile e ottenere qualcosa in esecuzione. Utilizza il prototipo per decodificare i casi di test percorso felice, i casi di test per guidare le interfacce e poi pensare ai contratti pre / post per aiutare a costruire la copertura del test.

Non preoccuparti dell'astrazione, dell'ottimizzazione o della verifica finché il problema non è stato completamente compreso.

    
risposta data 25.10.2011 - 11:35
fonte