Dove il refactoring e l'ottimizzazione del codice dovrebbero rientrare in una linea temporale sia agile che a cascata?


10

Sembra esserci questa idea tra il team di gestione del progetto secondo cui "funziona" significa che dovrebbe essere considerato completo al 100%. Molti programmatori sanno che non è sempre così. Se sto provando approcci alternativi per far funzionare un pezzo di funzionalità, ciò non significa necessariamente che ho trovato la soluzione migliore, o che non richiederà alcune rilavorazioni dopo aver esaminato con altri sviluppatori. Spesso ho finito con qualcosa, faccio un passo indietro e poi mi chiedo cosa posso fare meglio dopo che le regole aziendali saranno soddisfatte. Questo tempo "Posso fare di meglio" dovrebbe davvero adattarsi da qualche parte all'interno della sequenza temporale? Sono dell'opinione che l'approccio migliore sia che lasci sempre il codice meglio di quando lo hai trovato (in una certa misura), il che potrebbe significare refactoring post lancio. Però,

Risposte:


13

Esiste un principio generale che regola la necessità di refactoring e ottimizzazione, sia in cascata che in Agile: YAGNI (Non ne avrai bisogno). Un secondo principio è il corollario del primo: "L'ottimizzazione prematura è la radice di tutti i mali", l'equivalente in codice del proverbio generale "il nemico dell'eccellenza è la perfezione".

Prendiamo i principi e li applichiamo. È necessario creare un algoritmo ETL che preleva un file di un tipo particolare, ne estrae le informazioni, quindi le inserisce in un database. Il tuo obiettivo per questa settimana (per i nostri scopi non importa se ti trovi in ​​un negozio Agile o SDLC) è quello di farlo.

Sei un tipo intelligente e ti è stato dato uno sguardo al quadro generale. Sai che questo non è l'unico tipo di file per il quale il progetto avrà bisogno di un ETL. Quindi, consideri l'implementazione di questo algoritmo ETL per funzionare anche su un altro tipo di file, che ha solo differenze minori. Ciò violerebbe YAGNI. Il tuo compito non è quello di sviluppare l'algoritmo per quell'altro file; è sviluppare l'algoritmo per il file necessario entro la fine della settimana. Per raggiungere questo obiettivo e superare i test di accettazione, è necessario sviluppare tale algoritmo e farlo funzionare correttamente. "Non avrai bisogno" del codice aggiuntivo per farlo funzionare con l'altro file. Potresti pensare che ti farà risparmiare tempo per incorporarlo ora, e potresti avere ragione, ma potresti anche essere terribilmente sbagliato; potrebbe essere necessario utilizzare l'algoritmo per l'altro file in un'area del sistema in cui il codice non può essere utilizzato, oppure i requisiti per il nuovo file potrebbero essere diversi da quelli per i tuoi in modi che non conosci (in Agile, quelli i requisiti potrebbero non esistere ancora). Nel frattempo, hai perso tempo e hai inutilmente aumentato la complessità del tuo algoritmo.

Ora è la prossima settimana e come dubbia ricompensa per il tuo eccellente lavoro sul primo algoritmo, ti è stato assegnato il compito di creare gli algoritmi per due nuovi tipi di file. Ora, hai bisogno di un codice aggiuntivo per far funzionare il tuo algoritmo con più file. È possibile estendere l'algoritmo esistente utilizzando un modello di metodo modello che utilizzerà un modello di base con passaggi individuali specifici del file oppure si può semplicemente derivare un'interfaccia comune dall'algoritmo esistente, svilupparne due nuovi che seguono l'interfaccia e collegarli a un oggetto che può scegliere quale algoritmo usare.

Durante lo sviluppo, sai di avere il requisito che il sistema sia in grado di elaborare 10 KB di dati non elaborati al secondo. Esegui un test di carico e scopri che l'algoritmo di bozza iniziale gestisce 8 KB / s. Bene, questo non supererà gli AAT. Dai un'occhiata e vedi che c'è qualche struttura ad anello di complessità O (mio Dio) nel tuo algoritmo; lo razionalizzi e ottieni 12KB / s. "Abbastanza buono", pensi, "ma se avessi un ciclo così scadente nel codice, cos'altro posso radere?". buzz Hai appena violato la regola dell '"ottimizzazione prematura". Il codice funziona e soddisfa tutti i requisiti. Hai "finito", fino a quando i requisiti non saranno aggiornati per richiedere 15 KB / s. Se e quando ciò accade, ALLORA si ripristina il codice e si cercano cose da migliorare.

Segui questo semplice processo durante lo sviluppo, sia in Agile che nei tradizionali SDLC: "Al primo passaggio, fallo funzionare. Al secondo passaggio, rendilo carino. Al terzo passaggio, rendilo SOLIDO". Ciò significa che, quando crei per la prima volta una riga di codice, fai in modo che quel codice faccia il suo lavoro correttamente e senza errori, ma non presta troppa attenzione alle regole di progettazione all'interno di questo codice, come per tutto quello che sai in questo momento ' Non toccherò mai più quest'area. La prossima volta che visiti quella riga di codice, ti sei appena dimostrato sbagliato; non è più un pezzo unico del sistema. Rifattatelo per leggibilità, concisione del codice e / o principi DRY (potreste aver incollato un po 'di codice per fare qualcosa cinque volte; trasformatelo in un ciclo e / o una chiamata di metodo). La terza volta che lavori all'interno o intorno a quella riga di codice,


3
+1 per O(my God)-complexityse non altro, mi ha fatto ridere!
Gioele C

+1 per farlo funzionare prima. Troppe persone cercano di scrivere schemi e ottimizzare prematuramente fuori dal pipistrello.
Justin Shield,

Trovo che questo sia uno dei problemi più difficili da superare come programmatore. Gli ingegneri hanno un innato desiderio di sperimentare, sviluppare e perfezionare, ma alla fine vieni pagato per la produttività. A che serve un prodotto perfetto se spendi così tanto tempo e / o denaro che viene annullato a causa di sovraccarichi?
ToddR,

Mi piace l'approccio pragmatico ma ho un problema con "Al secondo passaggio, rendilo carino": se il secondo passaggio è un anno dopo e non hai la certezza che i nomi delle variabili e dei metodi siano significativi e i numeri magici siano stati sostituiti da costanti simboliche probabilmente hai problemi a capire il codice. Come gestirlo? "Renderlo carino" 1 ora dopo "farlo funzionare" è molto più economico di "renderlo carino" dopo un mese o dopo un anno. Concordo sul fatto che "renderlo carino" quando il prossimo cambio di codice è necessario è utile se "renderlo carino" non è stato fatto in primo luogo.
k3b,

In Agile / TDD, è stata la mia esperienza che il secondo passaggio in genere avviene abbastanza presto dopo il primo. In SLDC Waterfall-ish, hai più ragione; la funzione tende a essere scritta una volta e poi rimane lì fino a quando non arriva il prossimo round di requisiti che tocca quel metodo. Quindi, alcune buone pratiche di codifica devono accadere la prima volta, come il codice di auto-documentazione, in modo che quando torni un anno dopo, puoi ricordare cosa fa il codice e perché l'hai scritto in quel modo.
KeithS

10

se funziona ed è stato testato, perché correggerlo?

Questo può andare contro il tuo temperamento personale come ingegnere / programmatore, ma se funziona, quale valore commerciale è per te per continuare a perfezionarlo? Sarà più facile da mantenere nel tempo? In tal caso, quindi lavorando con la metodologia agile, dovresti essere in grado di creare nuovi elementi nel tuo backlog per perfezionare e riformattare il tuo codice esistente, e questi sarebbero prioritari con gli altri elementi nel backlog. Fa parte del valore del processo agile: il team decide insieme cosa è più importante e cosa viene fatto dopo.

Il nostro team monitora anche ciò che chiamiamo "debito tecnico", quindi se fai funzionare qualcosa ma sai che potrebbe essere fatto meglio, lo registri come debito tecnico. Usiamo la mischia e a volte finirai tutto il lavoro in uno sprint in anticipo (dovresti finire un po 'in anticipo all'incirca la metà del tempo se sei abbastanza vicino con le stime), ma non hai abbastanza tempo per entrare in un completamente nuovo user story, quindi passiamo il tempo extra a tornare indietro e a ridurre il nostro debito tecnico. Non è tracciato formalmente come le storie degli utenti nel nostro backlog e possiamo praticamente lavorarci su ogni volta che abbiamo tempo a disposizione.

È anche più o meno una richiesta di giudizio da parte tua quando si chiama l'attività "completata"; se non ti senti a tuo agio con lo stato in cui si trova il tuo codice, non contrassegnare l'attività come completa.


2
Sono diventato un fan del concetto di "debito tecnico", +1 per averlo sollevato in questo contesto.
Patrick Hughes,

Dimenticato completamente l'idea del "debito tecnico"; buon termine. Ma mi è stato insegnato che tutto ciò che si qualificava come "debito tecnico", nel senso che avrebbe richiesto significativi cicli di sviluppo per il refactoring, doveva essere evitato; "do it light" significava ancora "do it right", basta non andare su "torre d'avorio" su un codice che potrebbe essere una tantum.
KeithS,

5

Questo tempo "Posso fare di meglio" dovrebbe davvero adattarsi da qualche parte all'interno della sequenza temporale?

Sì.

Poco prima di iniziare a scrivere la prossima versione.

Non refactoring basato su "intuizione".

Refactor basato sulle storie reali del prossimo sprint.


2

Non contrassegnare il codice come completo al 100% fino a quando non si è soddisfatti del refactoring. Devi solo valutare costantemente il costo / beneficio per il refactoring del codice perché se studi abbastanza vedrai sempre i modi per migliorare il codice.

Uso il metodo del rifrattore verde rosso di TDD. Quindi il mio refactoring è integrato nel mio sviluppo. Per i grandi refactoring come la modifica del modello sottostante o qualcosa di simile mi piacerebbe che il management acquistasse per passare il tempo prima.


1
Il codice non è "completo al 100%" fino a quando tutti i prodotti in cui risiede sono morti. Proprio come se non fossi "completo" come persona finché il tuo cuore non smette di battere permanentemente; assorbirai sempre nuove informazioni e ti verrà richiesto di fare cose specifiche che non hai mai fatto prima, o fare la stessa cosa in un modo nuovo, più efficiente o meno costoso. Allo stesso modo, la tua base di codice avrà SEMPRE bisogno di lavoro - nuove funzionalità e vecchie correzioni - finché nessuno utilizzerà più il software.
KeithS,

2

Il "refactoring post lancio" ha un costo nascosto nei test di regressione e nel tempo di controllo qualità che si sta ignorando, inoltre comporta il costo opportunità di non lavorare su bug segnalati e funzionalità e modifiche nuove / richieste. TANSTAAFL

Se vale la pena farlo, vale la pena fare un compito per ottenere la priorità tramite il normale processo e non come un'eccezione speciale. Dopotutto, fai parte di una squadra e stai lavorando su obiettivi comuni e estendi arbitrariamente il tuo programma per sistemare il codice di lavoro.

Quindi, per una vera risposta: se sai che vorrai fare il refactoring, pianifica quel tempo come parte dell'attività. Se stai eseguendo una mischia / agile, allora time box un'attività di pulizia. Se sei a cascata / spirale, fai in modo che il refactor faccia parte del processo per revisionare il codice e accettare i moduli.


0

Se sto provando approcci alternativi per far funzionare un pezzo di funzionalità, ciò non significa necessariamente che ho trovato la soluzione migliore,

... Nel qual caso non hai ancora finito al 100% ...

o non richiederà alcune rielaborazioni dopo la revisione con altri sviluppatori.

Se le revisioni del codice e le successive rielaborazioni fanno parte del ciclo di vita dello sviluppo, la funzione non viene eseguita fino a quando tutte queste non sono terminate.

Spesso ho finito con qualcosa, faccio un passo indietro e poi mi chiedo cosa posso fare meglio dopo che le regole aziendali saranno soddisfatte. Questo tempo "Posso fare di meglio" dovrebbe davvero adattarsi da qualche parte all'interno della sequenza temporale?

Dipende. Se significa refactoring, dovrebbe far parte dell'attività di sviluppo originale. Se ciò significa sperimentare un algoritmo potenzialmente migliore, potrebbe essere un'attività separata.

Sono dell'opinione che l'approccio migliore sia che lasci sempre il codice meglio di quando lo hai trovato (in una certa misura), il che potrebbe significare refactoring post lancio. Tuttavia, i team di progetto sono spesso estremamente a disagio con questo approccio perché, di nuovo, se funziona ed è stato testato, perché correggerlo?

In breve, perché il codice può essere infranto su molti livelli.

È una cosa che funziona in questo momento. È una cosa completamente diversa se è pulito, estendibile e mantenibile a lungo termine.

Per risposte più dettagliate, vedere questa discussione .


0

Per quanto posso vedere e aver letto, questa è una domanda irrisolta. Quindi, l'elusione risponde come "YAGNI" e le risposte fai-da-te per la prima volta. Il fatto è che non c'è posto in Agile per il refactoring - ma direi che dovrebbe esserci.

La migliore risposta finora menziona il debito tecnico. Questa, sfortunatamente, è una triste realtà del software in molte aziende, dove la fretta di ottenere le cose fuori dalla porta, sia in una metodologia agile o non agile, è tutto comune - ma sotto Agile le soluzioni veloci e sporche sono razionalizzati come qualcosa di buono: "soddisfa i requisiti minimi di business" e "YAGNI" (per quanto riguarda la pulizia del codice).

Sarebbe bello se tutti facessero TDD, e sarebbe bello se tutti gli sviluppatori rifattorizzassero la seconda o la terza volta come suggerito da una risposta. Ma questo non succede nel mondo reale. Gli sviluppatori di vari livelli di abilità hanno quasi sempre trovato angoli nella ricerca di soluzioni rapide. Di conseguenza il codice decade in montagne di codice non mantenibile che impiega giorni per i nuovi sviluppatori a decifrare, il che fa male alla produttività e ritarda le scadenze. Per "non mantenibile" intendo soluzioni di copia e incolla, 5000 classi di linee, ecc. E tutto questo codice e queste correzioni su correzioni sono fondamentali per il business! - In questi casi di soluzioni additive, direi, non esiste YAGNI! Avrai bisogno di un codice pulito, SEMPRE. Se il codice non è pulito sicuramente non ne avrai bisogno - vedi la profezia che si autoavvera? Gli sviluppatori farebbero di tutto per non usare quel codice perché è troppo doloroso da guardare. E il circolo vizioso continua all'infinito fino a quando l'intera grande palla di fango deve essere ridimensionata e riscritta.

Quindi dico - nonostante il refactoring del codice non sia un concetto Agile adeguato, distinto, degno di questo tipo di storia - dovremmo trovare il tempo di rifattorizzare. Alcuni negozi ora richiedono ai team di spendere il 20% dei loro sprint sul debito tecnico. Speriamo che i sostenitori agili cambieranno idea su YAGNI e creeranno un posto per il refactoring come attività separata assegnata nel tempo. E se hanno già e non ne ho sentito parlare, ti preghiamo di indicare dove è descritto perché sono molto interessato a saperlo.


"Il fatto è che non c'è posto in Agile per il refactoring" - Non credo sia una vera affermazione. In agile, c'è un posto per qualsiasi tipo di sviluppo, incluso il refactoring, purché ci sia un caso commerciale per questo. Se non esiste un caso aziendale, perché lo stai facendo?
Bryan Oakley,

Immagino che tu abbia un punto se un po 'semplicistico. In teoria uno sviluppatore potrebbe fabbricare un business case per correggere il codice scadente anche se non produce alcun cambiamento funzionale, ma ciò non gioverebbe con lo spirito di agilità - usando business come proxy per giustificare il lavoro. Direi quindi che l'attività di refactoring non rientra nel regno dell'agile, una sorta di attività del CYA, se possibile, che fissa il codice non sostenibile in modo che non costi il ​​business a lungo termine e che gli sviluppatori siano accusati. Chiamalo "sprint refactoring" o altro, ma deve esserci un posto formale per questo.
blindcodifier9734
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.