Mobile App Rewriting vs App Refactoring : quali sono le differenze?

Condividi questo articolo:


State lavorando su un grande progetto già da diversi anni, e durante questo tempo i membri del team sono andati e venuti e il vostro codice è diventato sempre più vago. In questo articolo rispondiamo a due domande: In quali casi dovreste riscrivere la vostra applicazione e quali parti possono essere rifatte? Come si dovrebbe procedere al refactor del codice?

Cos’è il rewriting?

Come il nome implica, riscrivere il codice significa scrivere di nuovo la tua applicazione completamente da zero, usando nuovi approcci e tecnologie. Una grande cosa della riscrittura è che si può essere completamente liberi da qualsiasi limitazione nel codice legacy che rimarrebbe se si rifacesse solo la propria applicazione.

Quando riscrivete la vostra applicazione, potete cambiare tutto, dai linguaggi ai framework. Hai anche la possibilità di evitare gli errori che hai fatto l’ultima volta e approcciare il processo di sviluppo e test con uno sguardo nuovo. Puoi coprire la tua applicazione con test unitari e renderla ben strutturata e unificata. Questo è il motivo per cui la maggior parte degli sviluppatori preferisce una riscrittura completa piuttosto che il refactoring.

Se scegliete il refactoring, avrete bisogno di supportare la vostra applicazione legacy mentre lavorate su una nuova, e potreste non avere le risorse per farlo

Ma per quanto una riscrittura possa sembrare impeccabile e bella nella vostra testa, non c’è garanzia che vada tutto liscio. Riscrivere è un processo ancora più lungo e difficile del refactoring. Tieni presente che avrai bisogno di supportare la tua app legacy mentre lavori su una nuova, e potresti non avere le risorse per farlo. La soluzione è assumere nuovi sviluppatori per lavorare sulla riscrittura, ma potrebbero mancare di esperienza, e questo porterà ad un’applicazione mal progettata e sviluppata.

Inoltre non è così facile tradurre la funzionalità tra due sistemi diversi. Ci sono alcune zone oscure in qualsiasi codice che nessuno conosce in dettaglio, e può essere una sfida per il debug e la trasposizione.

Per queste ragioni, anche se riscrivere completamente un’applicazione può sembrare un’ottima idea, alla fine può essere rischioso e più costoso, poiché richiederà molto tempo e nessuno può garantire che il nuovo sistema riscritto sarà perfetto.

Ora parliamo dell’alternativa al rewriting.

Quando dovresti riscrivere la tua app (rewriting)?

Se la vostra app non funziona affatto, allora questo è un chiaro segno che l’intera app ha bisogno di essere riscritta

In alcuni casi, riscrivere l’intera app da zero è l’unica opzione. Se il codice esistente è un completo casino, e vedete che provare a rifattorizzarlo  (refactor) è quasi impossibile, questo è un buon argomento per riscrivere. Tuttavia, dovreste ancora considerare un’altra opzione perché c’è una possibilità che siate solo spaventati da tutto il vostro codice legacy e non vogliate affrontarlo. Dobbiamo ammettere che questa decisione non è facile da prendere, e uno sviluppatore di solito non può essere sicuro al 100% che una riscrittura sia necessaria.

Tuttavia, se la vostra app non funziona affatto, allora questo è un chiaro segno che l’intera app ha bisogno di essere riscritta. Se ci sono così tanti bug che non puoi nemmeno stabilizzare la tua applicazione, dovresti riscriverla. Il refactoring è possibile solo se l’applicazione funziona per lo più correttamente.

Puoi anche scegliere entrambe le strade, iniziando a rifattorizzare la maggior parte del codice in componenti e incapsulandoli. Dopo di che, si può decidere tra refactoring e rebuilding per ogni componente.

Cos’è il refactoring?

Il refactoring è una tecnica che gli sviluppatori usano per migliorare e ristrutturare il design del codice esistente senza cambiarne il comportamento. Il refactoring migliora gli attributi non funzionali del software. I principali vantaggi del refactoring sono:

  • Migliore leggibilità del codice
  • Riduzione della complessità del codice
  • Il refactoring può aiutarvi a trovare bug nascosti o vulnerabilità nel vostro codice e a semplificare la logica sbarazzandosi della complessità non necessaria
  • Il refactoring può rendere il codice più manutenibile ed estensibile, il che funziona alla grande nei casi in cui l’architettura o le tecnologie obsolete diventano un ostacolo all’ulteriore sviluppo.
  • Il refactoring di solito consiste in piccole attività che vengono eseguite una dopo l’altra, gradualmente e con attenzione. In questo modo uno sviluppatore cambia leggermente il codice senza cambiare il comportamento del software, o almeno senza influenzare la conformità del software con i requisiti funzionali.
  • C’è un rischio minore di fare errori o di rompere l’intero sistema se si esegue il refactoring in piccoli passi. Questo approccio permette di prendersi il proprio tempo per il refactoring. Mentre il refactoring è di solito un processo lungo, il vostro software continuerà a funzionare mentre lo fate.
  • Il refactoring può essere estremamente benefico se fatto correttamente. Può aiutarvi a trovare bug nascosti o vulnerabilità nel vostro codice e a semplificare la logica sbarazzandosi della complessità non necessaria. Tuttavia, se non si hanno le competenze per rifattorizzare correttamente un’applicazione, il refactoring può portare più male che bene. Per esempio, si possono introdurre ancora più bug nel codice o non riuscire a continuare a soddisfare i requisiti funzionali.

Di solito, il refactoring inizia con la revisione del codice e l’identificazione dei problemi che potrebbero essere risolti dal refactoring. Questi sono alcuni dei problemi principali che possono essere una luce verde per il refactoring.

Problemi principali del refactoring:

Codice duplicato – Se il codice si ripete in diverse parti della tua applicazione, dovresti trovare un modo per unificare queste strutture ripetute.

Metodi lunghi – Le procedure lunghe sono difficili da capire, e se un processo può essere compresso senza perdere funzionalità, dovrebbe esserlo. Pensa a nominare i metodi piccoli in modo che siano facili da capire anche senza guardare il corpo.

Classi grandi – Il codice duplicato si trova spesso in classi grandi. Evita troppe variabili di istanza e classi che fanno tutto.

Lunghe liste di parametri – Più dati servono, più si cambia la lista dei parametri, e questo continua fino al punto in cui è troppo difficile capire e usare la lista.

Cambiamento divergente – Questo si verifica quando una classe viene comunemente cambiata in modi diversi per ragioni diverse. Ogni oggetto viene cambiato solo come risultato di un tipo di cambiamento. Ogni cambiamento per gestire una variazione dovrebbe cambiare una singola classe, e tutta la digitazione nella nuova classe dovrebbe esprimere la variazione. Per pulire questo, si dovrebbe identificare tutto ciò che cambia per una particolare causa ed estrarre la classe per mettere insieme i cambiamenti.

Operazione Shotgun – Questo è l’opposto del cambiamento divergente. Ogni volta che fai un cambiamento, devi fare molti piccoli cambiamenti a molte classi diverse. Quando i cambiamenti sono dappertutto, sono difficili da trovare, ed è facile non cambiare qualcosa di importante.

Feature envy – Questo si verifica quando un oggetto esegue i calcoli per un altro oggetto piuttosto che chiedere all’altro oggetto di fare i calcoli da solo.

Data clumps  – Se alcuni pezzi di dati vanno sempre insieme, si dovrebbe estrarre una classe e farne un oggetto.

Primitive obsession – Questo si riferisce all’uso di tipi di dati primitivi per rappresentare le idee del dominio. Per esempio, usare una stringa per rappresentare un messaggio, un intero per rappresentare una somma di denaro, o un Struct/Dictionary/Hash per rappresentare un oggetto specifico.

Switch statements – Uno dei sintomi più ovvi del codice orientato agli oggetti è la sua relativa mancanza di dichiarazioni di switch (o case). Il problema con le dichiarazioni switch è essenzialmente quello della duplicazione. Spesso, si trova la stessa istruzione switch sparsa in un programma in posti diversi.

Parallel inheritance hierarchies -Queste sono davvero un caso speciale di operazioni shotgun. In questo caso, ogni volta che fate una sottoclasse di una classe, dovete anche fare una sottoclasse di un’altra. La strategia generale per eliminare la duplicazione è di assicurarsi che le istanze di una gerarchia facciano riferimento alle istanze dell’altra.

Lazy classes – Queste sono classi di cose che sono state pianificate ma non realizzate. Sbarazzatevene quando rifattorizzate.

Message chains – Quando un cliente chiede un oggetto dopo l’altro, si può ottenere una catena enorme.

I commenti sono buoni indicatori. Dopo il refactor, troverete che molti commenti che spiegano cosa fa una parte del codice sono inutili. Assicuratevi di rendere il vostro codice il più chiaro possibile in modo che non abbia nemmeno bisogno di commenti.

Processo di refactoring di una App

Il primo passo nel refactoring è sempre lo stesso. Hai bisogno di costruire un solido set di test per la sezione di codice che rifattorizzerai. Questi test sono essenziali anche se si seguono strutture di rifattorizzazione per evitare la maggior parte delle opportunità di introdurre bug.

Mentre si esegue il refactoring, ci si appoggia a questi test. È essenziale per la rifattorizzazione avere buoni test. Vale la pena spendere il tempo per costruire i test perché i test ti danno la sicurezza di cui hai bisogno per cambiare il programma in seguito.

Quando si rifattorizza, si dovrebbe assolutamente usare i test unitari e l’integrazione continua. Senza eseguire questi test dopo ogni piccolo passo di rifattorizzazione, si rischia di introdurre bug.

Assicurarsi che non vengano create nuove funzionalità durante il refactoring

Dopo i test, potete fare una serie di piccoli cambiamenti, ognuno dei quali rende il codice esistente leggermente migliore pur lasciando il vostro programma funzionante. Non mischiare un mucchio di refactoring in un unico grande cambiamento.

Ci sono molte tecniche di rifattorizzazione del codice. Potete scegliere quelle che ritenete più utili per il vostro codice. Esempi di tecniche sono il modello di rifattorizzazione rosso-verde, la rifattorizzazione preparatoria, la composizione di metodi, la ramificazione per astrazione e la semplificazione delle chiamate di metodo.

Assicurarsi che non vengano create nuove funzionalità durante il refactoring. Non mischiare refactoring e sviluppo diretto di nuove funzionalità. Cercare di separare questi processi almeno entro i confini dei singoli commit.

Come stimare il tempo per il refactoring
Gli sviluppatori dovrebbero stimare il refactoring nello stesso modo in cui stimano qualsiasi caratteristica: esaminare i fatti della caratteristica/codice (che in questo caso includerebbe la relazione del codice duplicato) e fare una stima intuitiva di quanto tempo ci vorrà per fare il lavoro in qualsiasi unità si usi normalmente, per esempio ore, giorni, settimane ecc.

Se il refactoring può essere completato (implementato e consegnato) in pezzi, spezzare le caratteristiche in un problema per ogni pezzo e stimare quei pezzi.

Una stima dovrebbe trarre pieno vantaggio dalla conoscenza del codice da parte dello sviluppatore. Se lo sviluppatore non conosce bene il codice, la sua stima sarà meno accurata.

Per stimare lo sforzo di rifattorizzazione per un’intera base di codice, basate la stima o sui rapporti di qualità del codice per l’intera base di codice o su revisioni manuali di sezioni campione della base di codice.

Come per ogni progetto, se avere una stima è importante, rivisitare la stima periodicamente per tenere conto di ciò che si è imparato dal lavoro fatto finora.

Il refactoring non dovrebbe essere una fase separata; è parte dello sviluppo quotidiano.

Considerazioni finali

Decidere se riscrivere o rifattorizzare un’applicazione può essere difficile. Dalla nostra esperienza, diremmo che se potete rifattorizzare, probabilmente dovreste farlo. Probabilmente non avrete bisogno di rifattorizzare piccoli progetti, ma se il vostro progetto è grande, avrete bisogno di rivederlo e rifattorizzarlo periodicamente. Per esempio, ogni 200 ore di sviluppo il vostro team di sviluppo potrebbe rivedere il proprio codice e rifattorizzarlo se necessario. Questo aiuta a mantenere il vostro codice leggibile e mantenibile.

A volte, i nostri clienti non vedono l’importanza del refactoring. Ma noi garantiamo che a lungo termine farà risparmiare denaro. Più un progetto diventa vecchio, più difficile diventa la manutenzione. Si può paragonare la manutenzione di un prodotto software al prendersi cura dei propri denti: è meglio spazzolarli regolarmente e controllarli dal dentista piuttosto che spendere grosse somme per riempire cavità o rimuovere del tutto i denti.

Alcune aziende di sviluppo fanno regolari revisioni del codice; quelle che non lo fanno sarebbero meglio se lo facessero. Le revisioni del codice aiutano a diffondere la conoscenza attraverso un team di sviluppo. Le revisioni aiutano gli sviluppatori più esperti a passare la conoscenza agli sviluppatori meno esperti. Aiutano più persone a capire più aspetti di grandi sistemi software. Sono anche molto importanti per scrivere codice chiaro. Il codice può sembrare chiaro ad un singolo sviluppatore, ma non al suo team.

In Immaginet Srl, prendiamo sul serio la manutenibilità del codice e cerchiamo di far risparmiare tempo e denaro ai nostri clienti. Se hai bisogno di aiuto per mantenere la tua applicazione esistente o se vuoi essere sicuro che l’app che sviluppi non sarà abbandonata, contattaci.


Per ulteriori informazioni visita il sito: immagi.net

Condividi questo articolo: