È utile il codice mini-refactoring nella speranza di migliorare la qualità, o è semplicemente "spostare il codice in giro" senza troppi vantaggi?

12

Esempio

Mi sono imbattuto in un codice monolitico che fa "tutto" in un unico punto: il caricamento dei dati dal database, la visualizzazione del markup HTML, il funzionamento come router / controller / azione. Ho iniziato ad applicare il codice del database di spostamento SRP nel proprio file, fornendo una denominazione migliore per le cose, e tutto sembrava buono, ma poi ho iniziato a dubitare del motivo per cui lo sto facendo.

Perché refactoring? Qual è lo scopo? È inutile? Qual è il vantaggio? Nota che per la maggior parte ho lasciato il file monolitico così com'è, ma ho rifattorizzato solo la parte più piccola che era rilevante per l'area in cui avevo bisogno di fare del lavoro.

Codice originale:

Per fare un esempio concreto, mi sono imbattuto in questo snippet di codice: carica le specifiche del prodotto o da un ID prodotto conosciuto o da un id della versione selezionata dall'utente:

if ($verid)
    $sql1 = "SELECT * FROM product_spec WHERE id = " . clean_input($verid);
else
    $sql1 = "SELECT * FROM product_spec WHERE product_id = " . clean_input($productid) ;
$result1 = query($sql1);
$row1 = fetch_array($result1);
/* html markup follows */

Refactoring:

Dato che sto facendo del lavoro che richiede di cambiare le cose in questa parte specifica del codice, l'ho modificato per usare il pattern di repository e l'ho aggiornato per usare le strutture MySQL orientate agli oggetti:

//some implementation details omitted 
$this->repository = new SpecRepository($mysql);
if ($verid)
    $row1 = $this->repository->getSpecByVersion($verid);
else 
    $row1 = $this->repository->getSpecByProductId($productid);
/* html markup follows to be refactored or left alone till another time*/

//added new class:
class SpecRepository extends MySqlRepository
{

    function getSpecByVersion(int $verid)
    {
        return $this->getMySql()->paramQuery("
            SELECT * FROM product_spec WHERE id = ?
        ", $verid)->getSingleArray();
    }

    function getSpecByProductId(int $productid)
    {
        return $this->getMySql()->paramQuery("
            SELECT * FROM product_spec WHERE product_id = ?
        ", $productid)->getSingleArray();
    }
}

Devo farlo?

Guardando indietro alle modifiche, il codice è ancora lì, codice con la stessa funzionalità, ma in file diversi, nomi diversi, luoghi, usando più stile orientato agli oggetti piuttosto che procedurale. In realtà è divertente notare che il codice refactored sembra molto più gonfio nonostante abbia la stessa funzionalità.

Prevedo alcune risposte che dicono "se non conosci i motivi per cui ti rifatti, non farlo", e forse potrei essere d'accordo. La mia ragione è migliorare la qualità del codice nel tempo (e la mia speranza è che lo farò seguendo SRP e altri principi).

Queste ragioni sono abbastanza buone o sto sprecando il mio tempo per "riorganizzare il codice" in questo modo? Il refactoring generale mi sembra un po 'come calpestare l'acqua per essere onesti - ci vuole tempo e diventa più "separato" per quanto riguarda l'SRP ma, nonostante le mie buone intenzioni, non mi sento di apportare miglioramenti sorprendenti. Quindi, discutendo se è meglio lasciare il codice come prima e non refactoring.

Perché ho fatto il refactoring in primo luogo?

Nel mio caso sto aggiungendo nuove funzionalità per una nuova linea di prodotti, quindi devo seguire la struttura di codice esistente per linee di prodotti simili o scrivere la mia.

    
posta Dennis 08.12.2017 - 16:50
fonte

5 risposte

13

Nell'esempio concreto che hai fornito, il refactoring potrebbe non essere stato necessario, almeno non ancora. Ma hai visto che in futuro c'era un potenziale per il codice di messier che avrebbe portato a un refactoring più lungo e noioso, quindi hai preso l'iniziativa e ripulito le cose adesso.

Direi anche che il vantaggio che hai ottenuto qui era un codice che è più facile da capire, almeno dal mio punto di vista, come qualcuno che non conosce il tuo codice base.

In generale:

Il refactoring facilita la comprensione del tuo codice da parte di altri sviluppatori?

Il refactoring facilita l'ottimizzazione del codice?

Il refactoring facilita la manutenzione del codice?

Il refactoring facilita il debug?

Se la risposta a qualcuno di questi era "sì", allora ne valeva la pena, ed era più che "spostare il codice in giro?

Se la risposta a tutti questi è "no", allora forse non ha bisogno di essere refactored.

La dimensione finale della base di codice potrebbe essere maggiore in termini di LoC (sebbene alcuni refactoring possano ridurre la base del codice ottimizzando il codice ridondante), ma questo non dovrebbe essere un fattore se ci sono altri guadagni.

    
risposta data 08.12.2017 - 17:33
fonte
9

Il refactoring gonfia se stai smontando un monolite.

Tuttavia, hai già trovato il vantaggio.

"Nel mio caso aggiungo nuove funzionalità per una nuova linea di prodotti."

Non è possibile aggiungere funzionalità a un monolite molto facilmente senza rompere le cose.

Hai detto che lo stesso codice sta ricevendo i dati e facendo il markup. Ottimo, fino a quando non desideri cambiare le colonne che stai selezionando e manipolando per mostrare in determinate condizioni. Improvvisamente, il tuo codice di markup smette di funzionare in un determinato caso e tu devi refactor.

    
risposta data 08.12.2017 - 16:58
fonte
2

Considero il refactoring se so che dovrò lavorare mesi o anni con quel progetto. Se devo fare un cambiamento qua e là, di resistere a me stesso la voglia di spostare il codice.

Il modo migliore di fare il refactoring è quando ho un codice base con una sorta di test automatici. Anche così devo stare molto attento a ciò che cambio per assicurarmi che le cose funzionino come prima. Perderai la fiducia molto presto se fornisci bug in altre aree oltre a quella che dovresti lavorare.

Apprezzo il refactoring per i seguenti motivi:

  • Capisco meglio il codice
  • Rimuovo il codice duplicato, quindi se ho un bug in un posto in cui non devo cacciare dove fosse il codice stato incollato
  • Creo le classi che hanno il loro ruolo ben definito. Ad esempio, posso riutilizzare lo stesso repository per idratare una pagina HTML, a Feed XML o un lavoro in background. Questo non sarebbe stato possibile se il codice di accesso al database è presente solo nella classe HTML
  • Ho cambiato il nome variabili, metodi, classi, moduli, cartelle se non corrispondono la realtà attuale; I comment del codice tramite nomi di variabili, nomi di metodi
  • Risolvo bug complessi con una combinazione tra test unitari e refactoring
  • Ho la flessibilità di sostituire interi moduli, pacchi. Se l'attuale ORM è obsoleto, difettoso o non mantenuto, quindi è più facile sostituirlo se non è diffuso su tutto il progetto.
  • Scopro nuove funzionalità o miglioramenti che portano a proposte per il cliente.
  • Ho creato componenti riutilizzabili. Questo è stato uno dei maggiori vantaggi perché il lavoro svolto in quel progetto avrebbe potuto essere riutilizzato per un altro cliente / progetto.
  • Spesso inizio con la soluzione più stupida, hardcoded, wacky e la riattribuisco più tardi una volta che ho imparato di più. Questo momento successivo potrebbe essere oggi o forse dopo diversi giorni. Non voglio passare troppo tempo a architect della soluzione. Ciò avverrà durante la scrittura, riscrivendo il codice avanti e indietro.

In un mondo perfetto i refactoring dovrebbero essere verificati da unit test, test di integrazione così via. Se non ce ne sono, prova ad aggiungerli. Anche alcuni IDE potrebbero aiutare molto. Di solito uso un plugin che costa soldi. Voglio passare un po 'di tempo con i refactoring ed essere molto efficiente a riguardo.

Ho anche introdotto bug. Posso capire perché alcuni QA stanno chiedendo are you guys doing refactoring? because everything stopped working! Questo è il rischio che il team deve abbracciare e dobbiamo sempre essere trasparenti al riguardo.

Nel corso degli anni ho scoperto che il refactoring continuo ha migliorato la mia produttività. Era molto più facile aggiungere nuove funzionalità. Anche le grandi ricostruzioni non richiedono una riscrittura completa, come spesso accade quando il codice base non è stato adattato all'evoluzione del prodotto. Inoltre è divertente.

    
risposta data 08.12.2017 - 23:17
fonte
1

Penso che la domanda che devi porci non sia tanto "C'è un vantaggio?" ma "Chi pagherà per questo lavoro?"

Tutti possiamo discutere sui benefici percepiti fino alla fine dei giorni, ma a meno che tu non abbia un cliente che crede in questi benefici e li valuta abbastanza per pagare le modifiche, non dovresti farle.

È fin troppo facile quando ci si trova in una squadra di sviluppo da qualche parte per vedere il codice e si vuole rifattorizzarlo per renderlo 'migliore'. Ma mettere un valore su "codice migliore" quando il prodotto funziona già è davvero difficile.

Cose come "lo sviluppo più rapido di nuove funzionalità" non lo riducono perché sono solo costi ridotti. Devi generare vendite.

    
risposta data 08.12.2017 - 16:58
fonte
1

Secondo me il refactoring è un buon investimento.

Altrimenti presto riceverai debiti tecnici (problemi irrisolti, codice errato che funziona solo in determinate condizioni, ecc.). I debiti tecnici diventeranno presto sempre più grandi, fino a quando il software non sarà più mantenibile.

Ma per fare lavori di refactoring, devi anche investire in test. Dovresti creare test automatici, idealmente dovresti avere test unitari e test di integrazione. Questo ti impedisce di rompere il codice esistente.

Se devi convincere il tuo capo oi tuoi colleghi, dovresti leggere alcuni libri sui metodi agili (ad esempio SCRUM) e sullo sviluppo basato su test.

    
risposta data 12.12.2017 - 19:52
fonte

Leggi altre domande sui tag