Posso refactoring "in sicurezza" senza specifiche? [duplicare]

1

Ho ereditato una legacy applicazione web per molti anni che:

  • Non fa uso di principi orientati agli oggetti, anche se la lingua lo permetterebbe
  • Non ha test unitari, né alcun tipo di suite di test, automatizzata o meno
  • In genere ignora le varie best practice generali, rendendo il codice molto difficile da leggere e mantenere
  • Divide il suo funzionamento (incluso il codice per le regole aziendali) attraverso l'applicazione Web, le visualizzazioni del database e le stored procedure. Parte del codice è persino esternalizzata in quanto le applicazioni esterne (non sotto il controllo di me o del mio team) spesso leggono o scrivono direttamente nel database
  • Ha solo la documentazione più piccola (compresi alcuni che ho creato)
    • Nessuna specifica tecnica o funzionale documentata per parlare di
  • Ha cambiato le regole tante volte e così velocemente che nessuno sa veramente come dovrebbe funzionare più. Le regole sono impilate come funzionalità mancanti o casi specifici vengono scoperti su base giornaliera.
  • Diventa l'applicazione più business-critical dell'azienda
  • È ancora in continua evoluzione

Il refactoring viene quasi sempre accompagnato dal suggerimento principale di aggiungere test unitari per assicurarti di non rompere nulla. Come fai a farlo quando non sai nemmeno come dovrebbe funzionare la cosa (e nessun altro può dirti di sicuro )?

È un caso in cui dovresti tornare al punto 1 e lentamente, in modo iterativo, quando vengono richieste nuove funzionalità, chiedere le specifiche focalizzate sulla sezione modificata e refattore allora che cosa c'è? C'è un altro modo per affrontare questa situazione?

Questa domanda si concentra principalmente sulla mancanza di specifiche contrarie alla regola di sicurezza del refactoring di creare test unitari per garantire che le regole siano rispettate durante il refactoring.

Detto questo, qualche altro bit sulla situazione oltre la mancanza di specifiche:

  • La struttura di programmazione "migliore" trovata nel codice finora è la funzione. Tendono a non essere autosufficienti e richiedono numerose variabili globali (anche le variabili locali sono state impostate erroneamente come variabili globali a rischio di comportamenti imprevisti). Ho la sensazione che il primo passo potrebbe essere il refactoring questo per consentire anche il test dell'unità.
  • I problemi menzionati si applicano all'intera applicazione, alle procedure del database e persino alle applicazioni sorelle. Tutto è mescolato insieme e quasi mai attraverso interfacce. È ancora possibile trovare
  • Il codice tende a essere duplicato in vari punti. Succede con il codice delle regole aziendali, il che significa che potresti ottenere risultati diversi a seconda di dove nell'applicazione che invochi una funzione. Ovvia complessità e rischi di manutenzione.
posta leokhorn 22.07.2014 - 19:38
fonte

3 risposte

10

Se non esiste un elenco esplicito di difetti noti che la gestione vuole comunque essere riparato, dovresti assumere che il comportamento così com'è ora sia corretto, e dovresti sforzarti di mantenerlo invariato durante il refactoring.

In altre parole, assenza esplicita di una specifica esplicita, la semantica corrente del codice base è i requisiti. Questo potrebbe non essere vero sotto tutti gli aspetti, ma dal momento che l'applicazione nel suo complesso è percepita come dotata di valore aziendale (altrimenti nessuno sforzo sarebbe destinato a mantenerlo), presumibilmente fa più cose giuste che sbagliate. Quindi non dovresti passare il tuo tempo a capire cosa era corretto e cosa no; se qualcuno non è soddisfatto di ciò che fa la nuova versione, ti farà sapere abbastanza presto e che ha la possibilità di richiedere alcuni requisiti reali.

    
risposta data 22.07.2014 - 19:44
fonte
2

Questo è praticamente parola per parola come ho descritto un progetto che ho avuto circa un anno fa. E per quanto sfortunato - è una situazione abbastanza comune.

OK, quindi la prima cosa è la prima - Se si tratta di un tipo di modulo black-box che non è necessario correggere - non aggiustarlo. Prova a documentare il comportamento, aggiungi alcuni test ma non aggiusta qualcosa che non sai come risolvere o anche come funziona.

Ora, supponendo che questa cosa, in effetti, abbia bisogno di essere aggiustata. Il tuo primo passo è cercare di capire il pezzo di codice con cui stai lavorando, ma dopo ...

C'è un bug in esso:
I test unitari sono la prima priorità. Cerca di coprire la parte del codice e il codice che dipende da esso o utilizza i risultati da esso con i test per assicurarti che cambi solo la cosa che intendi modificare .

C'è una nuova funzionalità che deve essere inserita:
In questo caso userei di solito il minor numero possibile di codice esistente . Se qualcosa è chiaro, come le chiamate DB, va bene riutilizzarlo. Se qualcosa sta attraversando una logica di spaghetti grinder, prova ad avere una chiamata parallela alla tua logica in un punto singolo . Ciò non produrrà un buon codice, ma produrrà diversi "clear out" di codice, in cui la logica è solida, semplice, documentata e testata. Più ne avrai, più sarà facile quando ...

È così legato a tutto che deve solo andare:
Cerca di capire le cose che fai comprendono sul codice. Qualche funzione non banale di cui comprendi gli effetti collaterali e l'output. Un modulo standalone che è abbastanza separato da tutto il resto ed è più facile da intrecciare. Una serie di caratteristiche e specifiche che puoi ottenere da persone o documenti. Dividere e conquistare è la tua tattica migliore: più piccolo è il pezzo di codice di cui ti occupi in qualsiasi momento, maggiori sono le tue possibilità di comprenderlo bene . Una volta che hai conoscenza, test e documenti sull'intera cosa, puoi iniziare a lavorare sulla sua architettura.

    
risposta data 22.07.2014 - 20:05
fonte
1

Prefazione: +1 @Kilian_Foth

Citazione dal Test del master Gold che convalida automaticamente milioni di punti dati

Test master Gold

Gold master testing is common when working with legacy code. Rather than trying to specify all of the logical paths through an untested module, you can feed it a varied set of inputs and turn the outputs into automatically verifying tests. There’s no guarantee the outputs are correct in this case, but at least you can be sure they don’t change (which, in some systems is even more important).

For us, given that we have a relatively reliable and comprehensive set of unit tests for our analysis code, the situation is a bit different. In short, we find gold master testing valuable because of three key factors:

  1. The inputs and output from our analysis is extremely detailed. There are a huge number of syntactical structures in Ruby, and we derive a ton of information from them.
  2. Our analysis depends on external code that we do not control, but do want to update from time-to-time (e.g. RubyParser)
  3. We are extremely sensitive to any changes in results. For example, even a tiny variance in our detection of complex methods across the 20k repositories we analyze would ripple into changes of class ratings, resulting in incorrect metrics being delivered to our customers. These add up to mean that traditional unit and acceptance testing is necessary but not sufficient. We use unit and acceptance tests to provide faster results and more localized detection of regressions, but we use our gold master suite (nicknamed Krylon) to sanity check our results against a dozen or so repositories before deploying changes.

L'approccio Golden Master

Prima di apportare qualsiasi modifica al codice di produzione, fai quanto segue:

  • Crea il numero X di input casuali, sempre usando lo stesso seme casuale, in modo da poter generare sempre lo stesso set più e più volte. Probabilmente vorrai qualche migliaio di input casuali.
  • Bombarda la classe o il sistema sotto test con questi input casuali.
  • Cattura le uscite per ogni singolo input casuale

Quando lo esegui per la prima volta, registra le uscite in un file (o database, ecc.). Da quel momento in poi, puoi iniziare a cambiare il codice, eseguire il test e confrontare l'output di esecuzione con i dati di output originali che hai registrato. Se corrispondono, mantieni il refactoring, altrimenti ripristina le modifiche e dovresti tornare al verde.

    
risposta data 22.07.2014 - 20:11
fonte

Leggi altre domande sui tag