it-swarm.it

Quando un GRANDE riscrive la risposta?

Ho appena letto il domanda sui Big Rewrites e mi sono ricordato di una domanda a cui volevo rispondere da solo.

Ho un progetto orribile tramandato a me, scritto nella vecchia Java, usando Struts 1.0, tabelle con relazioni incoerenti, o nessuna relazione e persino tabelle senza chiavi primarie o campi intesi come chiavi primarie ma non sono affatto uniche. In qualche modo la maggior parte dell'app "funziona". La maggior parte delle pagine viene riutilizzata (copia codice incollato) e codificata. Chiunque abbia mai lavorato al progetto lo ha maledetto in un modo o nell'altro.

Ora avevo a lungo considerato di proporre al vertice aziendale una riscrittura totale di questa orrenda applicazione. Sto lentamente tentando di dedicarmi al tempo personale, ma sento davvero che questo merita alcune risorse dedicate per realizzarlo. Dopo aver letto gli articoli su grandi riscritture, ho ripensamenti. E non va bene quando voglio convincere i miei superiori a sostenere la mia riscrittura. (Lavoro in un'azienda abbastanza piccola, quindi la proposta ha la possibilità di essere approvata)

TL; DR Quando è importante riscrivere la risposta e quali argomenti è possibile utilizzare per supportarla?

288
Jonn

Siamo spiacenti, questo sarà lungo, ma si basa sull'esperienza personale di architetto e sviluppatore in più progetti di riscrittura.

Le seguenti condizioni dovrebbero farti considerare una sorta di riscrittura. Parlerò di come decidere quale fare dopo.

  • Il tempo di accelerazione dello sviluppatore è molto elevato. Se impiega più tempo di quanto sotto (per livello di esperienza) per accelerare un nuovo sviluppatore, il sistema deve essere riprogettato. Per tempo di accelerazione, intendo la quantità di tempo prima che il nuovo sviluppatore sia pronto per eseguire il primo commit (su una piccola funzione)
    • Appena uscito dal college - 1,5 mesi
    • Ancora verde, ma hanno lavorato su altri progetti prima di - 1 mese
    • Livello medio - 2 settimane
    • Esperto - 1 settimana
    • Livello senior - 1 giorno
  • La distribuzione non può essere automatizzata, a causa della complessità dell'architettura esistente
  • Anche le semplici correzioni di bug richiedono troppo tempo a causa della complessità del codice esistente
  • Le nuove funzionalità richiedono troppo tempo e costano troppo a causa dell'interdipendenza della base di codice (le nuove funzionalità non possono essere isolate e quindi influenzano le funzionalità esistenti)
  • Il ciclo di test formale richiede troppo tempo a causa dell'interdipendenza della base di codice esistente.
  • Troppi casi d'uso vengono eseguiti su un numero troppo limitato di schermate. Ciò causa problemi di formazione per utenti e sviluppatori.
  • La tecnologia in cui si trova l'attuale sistema lo richiede
    • Gli sviluppatori di qualità con esperienza nella tecnologia sono troppo difficili da trovare
    • È obsoleto (non può essere aggiornato per supportare piattaforme/funzionalità più recenti)
    • C'è semplicemente una tecnologia di livello superiore molto più espressiva disponibile
    • Il costo di mantenimento dell'infrastruttura della tecnologia precedente è troppo elevato

Queste cose sono abbastanza evidenti. Quando decidere su una riscrittura completa rispetto a una ricostruzione incrementale è più soggettivo, e quindi più politicamente carico. Quello che posso dire con convinzione è che affermare categoricamente che è mai una buona idea è sbagliata.

Se un sistema può essere riprogettato in modo incrementale e hai il pieno supporto della sponsorizzazione del progetto per una cosa del genere, allora dovresti farlo. Ecco il problema, però. Molti sistemi non possono essere riprogettati in modo incrementale. Ecco alcuni dei motivi che ho riscontrato per impedirlo (sia tecnico che politico).

  • Tecnico
    • L'accoppiamento dei componenti è così elevato che le modifiche a un singolo componente non possono essere isolate da altri componenti. Una riprogettazione di un singolo componente comporta una cascata di modifiche non solo ai componenti adiacenti, ma indirettamente a tutti i componenti.
    • Lo stack tecnologico è così complicato che la futura progettazione dello stato richiede molteplici modifiche all'infrastruttura. Ciò sarebbe necessario anche in una riscrittura completa, ma se è richiesto in una riprogettazione incrementale, perdi quel vantaggio.
    • La riprogettazione di un componente comporta comunque una completa riscrittura di quel componente, perché il design esistente è così fubar che non c'è nulla che valga la pena salvare. Ancora una volta, perdi il vantaggio se questo è il caso.
  • Politico
    • Gli sponsor non possono comprendere che una riprogettazione incrementale richiede un impegno a lungo termine per il progetto. Inevitabilmente, la maggior parte delle organizzazioni perde l'appetito per il continuo drenaggio del budget creato da una riprogettazione incrementale. Questa perdita di appetito è inevitabile anche per una riscrittura, ma gli sponsor saranno più inclini a continuare, perché non vogliono essere divisi tra un nuovo sistema parzialmente completo e un vecchio sistema parzialmente obsoleto.
    • Gli utenti del sistema sono troppo collegati con le loro "schermate correnti". In questo caso, non avrai la licenza per migliorare una parte vitale del sistema (il front-end). Una riprogettazione ti consente di aggirare questo problema, poiché stanno iniziando con qualcosa di nuovo. Insisteranno ancora per ottenere "gli stessi schermi", ma hai un po 'più di munizioni da respingere.

Tieni presente che il costo totale della riprogettazione in modo incrementale è sempre più elevato rispetto a una riscrittura completa, ma l'impatto sull'organizzazione è generalmente inferiore. Secondo me, se puoi giustificare una riscrittura e hai sviluppatori superstar, allora fallo.

Fallo solo se puoi essere certo che esiste la volontà politica di vederlo fino al completamento. Ciò significa sia il buy-in esecutivo che quello dell'utente finale. Senza di essa, fallirai. Suppongo che sia per questo che Joel dice che è una cattiva idea. Esecutivo e il buy-in dell'utente finale sembra un Unicorno a due teste per molti architetti. Devi venderlo in modo aggressivo e fare una campagna per la sua continuazione continuamente fino a quando non è completo. È difficile e stai parlando di puntare la tua reputazione su qualcosa che alcuni non vorranno vedere avere successo.

Alcune strategie per il successo:

  • Se lo fai, tuttavia, non provare a convertire il codice esistente. Progetta il sistema da zero. Altrimenti stai perdendo tempo. Non ho mai visto o sentito parlare di un progetto di "conversione" che non è finito miseramente.
  • Migra gli utenti nel nuovo sistema un team alla volta. Identifica i team che hanno PIÙ problemi con il sistema esistente e prima migrali. Lascia che diffondano la buona notizia con il passaparola. In questo modo il tuo nuovo sistema verrà venduto dall'interno.
  • Progetta il tuo framework di cui hai bisogno. Non iniziare con un po 'di I-ho trascorso 6 mesi a costruire questo framework che non ha mai visto codice reale.
  • Mantieni il tuo stack tecnologico il più piccolo possibile. Non progettare troppo. È possibile aggiungere tecnologie secondo necessità, ma eliminarle è difficile. Inoltre, più livelli hai, più lavoro è per gli sviluppatori. Non renderlo difficile fin dall'inizio.
  • Coinvolgi gli utenti direttamente nel processo di progettazione, ma non lasciare che dettino come a farlo. Guadagna la loro fiducia mostrando loro che puoi dare loro ciò che vogliono meglio se segui buoni principi di progettazione.
328
Michael Meadows

Ho partecipato a due grandi riscritture. Il primo era un piccolo progetto. Il secondo era il prodotto principale di una società di software.

Ci sono diverse insidie:

  • le riscritture richiedono sempre più tempo del previsto.
  • le riscritture non hanno effetti/benefici diretti per il cliente.
  • la capacità dedicata alla riscrittura non viene utilizzata per supportare il cliente.
  • perderai funzionalità con una riscrittura a meno che tu non abbia una documentazione al 100%.

Le riscritture raramente sono la vera risposta. Puoi riformattare gran parte del codice senza perdere nulla e senza molti rischi.

Le riscritture possono essere la risposta se:

  • stai passando a un'altra lingua o piattaforma.
  • stai cambiando framework/componenti esterni.
  • la base di codice esistente non è più gestibile.

Ma consiglio vivamente l'approccio lento usando il refactoring. È meno rischioso e fai felici i tuoi clienti.

112
Toon Krijthe

È tempo di riscrivere quando:

Il costo di riscrivere l'applicazione + mantenere l'applicazione riscritta è inferiore al costo di mantenere il sistema corrente nel tempo.

Alcuni fattori che rendono più costoso il mantenimento di quello attuale:

  • La lingua è così vecchia che devi pagare persone che sanno un sacco di soldi per programmarci (COBOL).
  • (per esperienza, sfortunatamente) Il sistema si basa su un'architettura hardware così vecchia che devono setacciare le parti Ebay e COLLECT per aggiungere alla macchina su cui è in esecuzione perché non sono più realizzate. Questo si chiama "supporto vita hardware" ed è costoso perché, man mano che le parti diventano più scarse, (possono) aumentare di prezzo o alla fine (assolutamente) si esauriranno.
  • È diventato così complesso che il //Here be dragons. il commento è in tutto il tuo codice.
  • Non puoi scrivere altri progetti e aggiungere nuovo valore all'azienda perché rattoppi sempre questa brutta bestia.
74
Ryan Hayes

Se è necessario un cambiamento fondamentale nell'architettura del progetto, è possibilmente il momento di ricominciare da capo.

Anche con ciò, ci saranno potenzialmente ampie fasce di codice che vale ancora la pena riutilizzare nel nuovo progetto.

Prestate attenzione, tuttavia. Un progetto attuale avrà le sue regole di business testate e perfezionate con innumerevoli ore di utilizzo effettivo, cosa che non sarà vera per un progetto avviato da zero.

Dubito che un lasso di tempo o un istinto sia una misura appropriata di una tale misura drastica. Devi avere chiaro, difendibile e ben compreso motivi per partecipare a questo corso d'azione.

17
Dan McGrath

Anche se sono d'accordo con la risposta di Kramii e l'opinione di Joel, ci sono momenti in cui è appropriato fare una riscrittura. Nelle applicazioni di lunga durata (sto parlando da 10-20 anni o più), la manutenzione diventa sempre più costosa nel tempo. Ciò è dovuto al fatto che il codice sta diventando sempre più spericolato poiché l'architettura originale viene sacrificata per le patch di manutenzione rapida. Inoltre, gli sviluppatori di tecnologie meno recenti diventano più rari e più costosi. Infine, l'hardware inizia a invecchiare e diventa sempre più difficile trovare nuovo hardware, sistemi operativi, framework, ecc. Su cui eseguire la vecchia applicazione. Inoltre, le aziende si evolvono e molto probabilmente un vecchio sistema non sarà in grado di soddisfare le esigenze aziendali dell'organizzazione, come potrebbe fare un sistema nuovo di zecca.

Quindi devi soppesare tutti i costi di manutenzione in corso, così come i potenziali benefici di un nuovo sistema per l'azienda, contro il costo di riscrivere la cosa da zero. Sii molto pessimista nelle tue stime sul costo di una riscrittura. Costa quasi sempre di più e richiede più tempo di quanto si pensi.

12
RationalGeek

Fermare! La riscrittura è quasi mai la risposta. Più spesso, il refactoring è una scommessa migliore.


Naturalmente, ci sono ci sono volte in cui una riscrittura è giustificata:

  • Stai passando a una nuova piattaforma in cui non esistono strumenti di migrazione (o non possono essere scritti abbastanza a buon mercato).
  • L'applicazione da riscrivere è banale.
  • Il codice sorgente per l'applicazione originale viene perso e il recupero è più costoso della riscrittura.
  • La stragrande maggioranza delle regole aziendali incapsulate dall'applicazione esistente non si applica più.
  • Esistono pochi utenti attivi del codice esistente.
  • Hai la risorsa (tempo, talento e strumenti) per intraprendere la riscrittura.
  • L'applicazione esistente non può essere eseguita in un ambiente di produzione, per motivi legali o pratici.

Per capire perché raccomando il refactoring rispetto alla riscrittura, considera ciò che è coinvolto in una riscrittura. Devi:

  1. Comprendi le sfumature di ciò che fa l'applicazione esistente. Questo di solito non è banale quando si prende in considerazione tutte le sottili regole aziendali che incapsula, l'ambiente (sia umano che tecnico) in cui opera e i vantaggi e gli svantaggi della soluzione attuale. Più spesso, l'unico posto in cui queste informazioni esistono (se ovunque) è nel codice sorgente dell'applicazione esistente. È un peccato che uno dei motivi principali per eseguire una riscrittura sia che il codice esistente è difficile da capire e mantenere.

  2. Riprodurre questa funzionalità (o una versione aggiornata di essa) in una nuova applicazione testata e affidabile. Il codice esistente potrebbe non essere compreso dagli sviluppatori, ma in genere è ben compreso dai suoi utenti. Potrebbe non soddisfare le loro attuali esigenze aziendali, ma possono almeno dirti cosa fa l'applicazione in varie circostanze.

I grandi vantaggi del refactoring sono che:

  • Puoi prendere le cose un piccolo pezzo alla volta.
  • Eventuali modifiche possono essere testate nel contesto dell'applicazione esistente e funzionante.
  • Le ipotesi sul funzionamento del codice esistente possono essere verificate apportando piccole modifiche e osservando cosa succede.
  • Le modifiche possono essere spesso fornite agli utenti in più fasi anziché in una sola volta.
  • Imparare dalle prime fasi del refactoring può informare le fasi successive del refactoring.
  • Se si abbandona il processo a metà strada, ci saranno comunque vantaggi in termini di una base di codice più pulita (al contrario di una riscrittura che deve essere completata per offrire vantaggi all'utente o agli sviluppatori).

Ricorda anche che, se esegui una riscrittura, sei sicuro di introdurre molti nuovi bug e pasticciare nella nuova base di codice.

11
Kramii

Questo elemento grafico può essere d'aiuto, è una funzione della qualità della base di codice e del valore commerciale dell'applicazione:

enter image description here

Il grafico finge di essere una guida su quando una reingegnerizzazione di software legacy è giustificata e quando non lo è. Ad esempio, se il software ha un alto valore commerciale e la qualità del codice è scarsa, è giustificata una riprogettazione.

10
Tulains Córdova

Penso di essere nella sola situazione della mia carriera in cui la grande riscrittura è la risposta:

Fusione aziendale, enorme sovrapposizione nella funzionalità dei sistemi. Molti, molti sistemi sono stati uniti e ritirati e altri ancora in corso.

Ho ereditato un sistema dall'altra società che vive ancora. Ha un'enorme base di codice, che in passato supportava più dipartimenti molto simili ai nostri, ma con un design e framework completamente diversi. È rimasto solo un settore commerciale che lo utilizza, il che fa abbastanza soldi per mantenere viva questa cosa in uno stato di zombi. Tutta la vecchia esperienza è sparita, non c'è documentazione. Il carico di supporto è elevato, con guasti ogni settimana. Non è stato unito ai sistemi delle nostre aziende, perché la nostra azienda non ha mai supportato questo particolare settore del business, quindi non abbiamo la funzionalità o l'esperienza.

Sembra che questo sia l'unico caso in cui è necessaria la riscrittura. Sembra che dovrò capire questo colosso, estrarre i pezzi di funzionalità dedicati a questo business e riscrivere i pezzi che devono essere aggiunti ai nostri sistemi esistenti. Una volta fatto ciò, i nostri sistemi esistenti possono supportare questo nuovo settore e questa bestia può essere eliminata dalla sua miseria. Altrimenti perderò la sanità mentale.

8
Jay

Ho lavorato per una piccola società di software che aveva un paio di applicazioni DOS che sono state aggiornate per gestire Y2K, riscritte come app di Windows a 16 bit e poi completamente riscritte come app a 32 bit con un'ulteriore funzione 'piccola' (utilizzata in ultima analisi da un cliente) che ha influenzato l'intera struttura.

Spostare il codice a 16 bit su 32 avrebbe potuto essere fatto in un mese da una persona, ma NOOOOOOOOO, abbiamo dovuto riscriverlo per rendere Soooooooooo molto meglio. Questa cosa potrebbe essere adattata per altri settori, avrebbe specifiche complete e psuedo-codice prima ancora di iniziare. Le specifiche sono state create, ma ci è voluto così tanto tempo che non c'era nemmeno il tempo di scrivere il vero codice. È stato rilasciato in ritardo, con più bug rispetto ai 16 bit "iniziati" con (era su v.3.0 e infine al punto in cui siamo quasi arrivati ​​una settimana senza che qualcuno avesse segnalato un nuovo bug).

Penseresti che riscrivere la stessa applicazione 3-4 volte comporterebbe alcuni miglioramenti, ma non credo che un front-end della GUI possa essere giustificato così tanto.

Questo è stato il mio primo lavoro IT come responsabile dell'assistenza tecnica. Dovrei scrivere un libro su come non sviluppare software per la distribuzione. Ovviamente abbiamo fatto molti errori, ma il fatto che abbiamo continuato a riscrivere le applicazioni ha aggravato l'incompetenza.

7
JeffO

Avevo un caso molto simile al tuo, solo il codice non utilizzava nemmeno Struts. Quello che ho fatto invece sono state le aree target che erano particolarmente scadenti e che causavano molti problemi. Questo approccio mirato ci ha migliorato progressivamente.

Per un periodo di 2 anni abbiamo lavorato sul refactoring di pezzi e pezzi insieme a lavori di miglioramento. Abbiamo sempre svolto un compito di "tempra" in un piano di progetto. Concentrandoci sulle aree specifiche che non hanno funzionato bene, abbiamo ottenuto il massimo profitto. Le cose che hanno funzionato l'abbiamo lasciata sola. Anche critico è che questo lavoro è stato fatto nel corso del normale sviluppo ed è stato rilasciato. Il problema con una grande riscrittura si risolve per un anno o più e poi quando torni ogni cosa è cambiata comunque e alcuni dei cattivi bug si sono risolti e hai perso il ROI.

Non abbiamo mai riscritto il tutto. Tuttavia, abbiamo smesso di usare quella piattaforma per nuovi lavori e abbiamo lanciato una nuova piattaforma per un nuovo grande progetto. Ciò è stato approvato e abbiamo consegnato un ottimo prodotto in un ragionevole lasso di tempo.

5
Bill Leeper

Quindi eccomi qui seduto alla mia scrivania, ho iniziato a riscrivere il codice per questo casino assoluto di un grosso file aspx, il database dietro di esso, e sostituendo l'interfaccia MS Access con MsSQL.

Questo programma asp è pieno di cose come

  • include(close.aspx) che all'interno ha una riga di codice che chiude l'ultima connessione aperta al database.
  • Codice legacy appena commentato in modo casuale
  • Nessuna considerazione per la sicurezza
  • Codice spaghetti, migliaia di righe. Tutto in un unico file.
  • Funzioni e variabili senza un chiaro significato dietro i loro nomi

Se mai dovessimo fare un piccolo cambiamento, è come giocare cinque partite simultanee di kal-toh in modalità incubo.

Sono stato assunto per replicare la funzionalità e creare un prodotto che potesse essere personalizzabile e vendibile ad altri nel settore. Il problema è che questa cosa è stata scritta negli ultimi 10 anni per soddisfare ogni singola esigenza aziendale (beh, direi comunque di cinque o sei sigma).

Se non volessimo vendere il prodotto, probabilmente non avrebbero avuto bisogno di una riscrittura poiché fa la maggior parte di ciò che vogliono-- forse non elegantemente, ma non è stato prudente spendere i soldi nel rendere Nice code 'fai la stessa cosa.'

5
Incognito

La soluzione esistente non si ridimensiona.

Ti sto guardando, MS Access.

4
user21007

Joel Spolsky ha un eccellente articolo su questo: Cose che non dovresti mai fare, Parte I

Dal titolo che puoi dire, è un po 'unilaterale (parla del perché non dovresti mai buttare il codice) IMO, c'è molta verità ad esso, di recente ho visto un video channel9 sul 25 ° anniversario di Excel in cui alcuni sviluppatori hanno detto, come anche oggi se guardassi alla fonte controllerai la revisione e finiresti per tornare al codice usato da Excel che è stato scritto 20 anni fa.

Non puoi essere sicuro al 100% (quando anche Netscape commette errori (dall'articolo Joels)), [~ # ~] i [~ # ~] mi è sembrato che l'articolo di Joel sia stato inviato da Dio, perché posso essere pessimista e amo buttare via il codice pensando di poterlo sempre scrivere meglio una seconda volta, ma ho capito solo ora che solo questo costa un lotto .

Per dare una risposta concreta, vorrei solo dire che devi fare un'analisi approfondita del costo rispetto al valore .

Il mio mondo reale: un'app di Silverlight Sto sviluppando v0.6 finora ha un casino di chiamate asincrone che rendono il codice così contorto. Da quando ho scoperto estensioni reattive questa settimana voglio davvero riscrivere la maggior parte del codice, ma ora cosa devo dire al mio cliente? Il programma funziona perfettamente (con qualche perdita di memoria) ma a loro non importa? Non posso assolutamente dirgli che mi sto prendendo altre 2-3 settimane perché voglio rifare qualcosa. Vado comunque a ramificare il codice e riscrivere /giocare con esso nel mio gratuito tempo.

Solo i miei 2 centesimi ok !?

4
gideon

C'è la classica battuta su "se avessi intenzione di X non sarei partito da qui".

Ho preso un lavoro una volta, dove la motivazione principale del datore di lavoro era quella di portare a bordo i talenti per lanciare una riscritta da tempo attesa di un'app critica per l'azienda. La domanda che non ho posto è stata: perché sei finito in questa situazione? Avrebbe dovuto essere una bandiera rossa, se la causa fosse

  • troppa pressione per aggiungere funzionalità per mantenere e riformattare in modo incrementale la bestia,

  • troppo poca abilità nel dipartimento,

  • troppo poco buy-in da parte dei clienti o della direzione per lavoro incrementale,

o qualsiasi altra cosa, e questo fa sì che si esaurisca fino a quando il problema non raggiunge un livello intollerabile.

Quindi concordo con Joel sul fatto che una massiccia riscrittura sia probabilmente una pessima idea - a meno che tu non abbia prove certe che tutte le ragioni sottostanti alla base di una riscrittura maggiore sembrano così necessarie sono state affrontate , con ogni probabilità ripeterai il problema a tempo debito.

2
Julia Hayward

È la risposta quando la riscrittura consente all'organizzazione di perseguire una strategia che offra un vantaggio competitivo o le consenta di servire meglio i propri clienti in un modo che l'architettura attuale non può accogliere.

Invece, le riscritture spesso accadono per alleviare le preoccupazioni della direzione:

  • tutto dovrebbe essere in .NET,
  • i nostri sviluppatori dicono che il nostro codice fa schifo,
  • siamo tecnicamente in ritardo,
  • non saremo in grado di trovare risorse per supportare il nostro sistema o, molto spesso,
  • sono passati dieci anni, quindi è il momento.

Molte di queste preoccupazioni non si materializzeranno e, se lo facessero, potrebbero essere gestite. Quest'ultimo, tuttavia, è il peggiore. È essenzialmente: non abbiamo un motivo.

Sì, come l'auto, un sistema inizierà a mostrare segni di usura. Questo può essere alleviato dalla manutenzione ordinaria. Sai cosa dicono di come una piccola manutenzione preventiva può fare molto. Come investimento, la manutenzione ordinaria (ovvero refactoring e standardizzazione) comporta quasi sempre un costo inferiore rispetto a una riscrittura.

Tuttavia, dobbiamo anticipare che alla fine sarà necessaria una riscrittura. Stabilisci le date e pianificalo provvisoriamente, ma man mano che la data si avvicina al ritardo in favore della realizzazione di altri obiettivi strategici fino a quando non hai un motivo convincente come ...

Negli ultimi anni abbiamo perso l'opportunità di vincere grandi conti perché non potevamo soddisfare le loro esigenze in modo tempestivo o costoso. Il nostro sistema verrà riscritto usando un'architettura estensibile che consente di collegare le personalizzazioni (e non codificarle come facciamo attualmente). Ciò ridurrà drasticamente i tempi e i costi di accomodamento dei clienti con esigenze speciali. Guadagneremo più account e soddisfare meglio le esigenze dei nostri attuali clienti.

2
Mario T. Lanza

Penso che il motivo principale che giustifica le riscritture sia dovuto ai cambiamenti della piattaforma. Ad esempio, se si dispone di un'applicazione GUI desktop di Windows e il proprietario dell'azienda decide che desidera che la versione successiva sia un'applicazione basata sul Web. Anche se non sempre, nella mia esperienza il più delle volte ciò richiederà una riscrittura, a meno che gli sviluppatori originali non abbiano scritto un codice molto modulare e riutilizzabile (difficilmente accade).

2
Craig

Secondo Joel, le grandi riscritture sono il singolo peggior errore strategico che un'azienda può fare:

Cose che non dovresti mai fare, Parte I

... È importante ricordare che quando inizi da zero non c'è assolutamente nessuna ragione per credere che stai andando a fare un lavoro migliore di quello che hai fatto la prima volta. Prima di tutto, probabilmente non hai nemmeno lo stesso team di programmazione che ha lavorato alla versione uno, quindi in realtà non hai "più esperienza". Farai di nuovo la maggior parte dei vecchi errori e introdurrai alcuni nuovi problemi che non erano presenti nella versione originale.

Il vecchio mantra creane uno da buttare via è pericoloso se applicato ad applicazioni commerciali su larga scala. Se stai scrivendo codice sperimentalmente, potresti voler riordinare la funzione che hai scritto la scorsa settimana quando pensi a un algoritmo migliore. Va bene. Potresti voler riformattare una classe per facilitarne l'uso. Anche questo va bene. Ma buttare via l'intero programma è una follia pericolosa, e se Netscape avesse effettivamente una supervisione da adulto con esperienza nell'industria del software, potrebbe non essersi sparato così tanto ai piedi.

2
user3287

Mai, sempre refactoring - la verità è che se il codice è stato scritto da te - non sarai in grado di fare di meglio.

A meno che tu non voglia cambiare tecnologia, il codice non ha alcuna struttura (l'ho visto molto tempo fa in alcuni PHP, l'autore ha appena copiato/incollato spahgetti invece di includere/class/function) o hai preso in consegna qualcosa da un'altra persona che è stata scritta molto male.

Tutto dovrebbe essere progettato come una blackbox. API modulari e semplici, cosa c'è dentro ... è meno importante :) Se hai degli spaghetti potresti forse chiuderli all'interno di una blackbox, in modo da non contaminare il buon codice.

2
Slawek

Quando si passa a una tecnologia completamente nuova, è necessario fornire la funzionalità desiderata.

"Completamente nuovo": se stai pianificando di riscrivere ma usi la stessa piattaforma, il refactoring e la ristrutturazione ragionevole sono quasi sicuramente la soluzione migliore. La "piattaforma", come usata qui, è piuttosto vaga - si consideri che includa il linguaggio e forse il sistema operativo (mi viene in mente l'estensione da Linux a Windows o viceversa), ma probabilmente non il framework (ad esempio, la sostituzione di Struts con Spring).

"Necessario per fornire la funzionalità desiderata": verso il 2000, ho avviato un progetto per riscrivere un componente server principale in Java da C++ per abilitare il threading out-of-the-box, una cache di oggetti, e transazioni controllate dal cliente. All'epoca esistevano più librerie di threading per C++ che avremmo dovuto supportare e la maggior parte del codice del nostro database avrebbe reso necessaria una riscrittura quasi totale, come per le transazioni controllate dal client. .. non accadrà con la vecchia architettura.

Anche allora, non sono sicuro che avrei fatto la riscrittura, tranne per il fatto che avevo una conoscenza dettagliata del comportamento del sistema attuale, ed era un codice relativamente pulito che non aveva sviluppato molte verruche nei suoi 11 anni di vita.

1
Anon

Bene, posso immaginare scenari ipotetici in cui potrei semplicemente buttare via la base di codice esistente (situazioni ipotetiche in cui le palle bucky hanno peso e volume pari a zero, in cui nessuno si preoccupa se perdiamo settimane o mesi di produttività mentre cerchiamo di aggiungere funzionalità e bug trascurati si risolve nel sistema, e dove il sistema è così banale e odiato da un'organizzazione che posso sostituire l'intera faccenda e l'esercito di server con Notepad ++ e un netbook in dieci minuti e aumentare la produttività e il morale di tutti su tutta la linea.)

Per quasi tutti gli scenari del mondo reale, però, consiglierei semplicemente il refactoring in atto. ^ _ ^. Ci sono troppi costi nascosti e imprevisti da riscrivere quando i requisiti legali e aziendali privi di documenti iniziano a comparire e l'ultimo minuto di hacking insieme all'ultimo minuto inizia a seguire.

== Refactoring in Place per maggior bene, e stuff ==

Refactoring codice legacy con il vecchio approccio incrementale regolare,

  1. Se hai la possibilità di convertirti in UML e documentare quale piccola architettura nodosa ci sia.
  2. Se hai il controllo della versione, cerca di generare alcuni rapporti di abbandono del codice e di capire quali file e sezioni di file sono stati modificati più frequentemente. Prendi nota di questi in quanto probabilmente saranno le aree che vorresti affrontare per prime.
  3. Prima di modificare qualsiasi codice, prova sempre ad aggiungere un po 'di copertura del test (anche i brutti test funzionali dello stack completo lo faranno). Se hai a che fare con una logica disordinata di estrazione di codice procedurale, intendi passare a un metodo o una funzione ragionevolmente nominati e, se possibile, aggiungere alcuni casi di test che verificano il tuo nuovo metodo. rendere qualunque hack terribile che devi fare e, se possibile, paramatizzare il cambiamento se si tratta di qualcosa di comunemente ottimizzato come larghezza del margine o titolo, quindi sarà un po 'più semplice aggiornare la prossima volta.
  4. Usa il modello dell'adattatore e cerca di nascondere i frammenti di codice legacy sotto un tappeto di classi e metodi con nomi logici in modo che per le attività più comuni che esegui tu e gli altri sviluppatori non dovrai preoccuparti dei bit spaventosi che stanno succedendo dietro le spalle dietro quei piccoli metodi e classi puliti che hai nascosto dietro quel codice legacy - come quelle belle famiglie che tengono deformi gli zombi omicidi ex membri della famiglia nei fienili in modo che non rovinino la vita quotidiana del azienda agricola . . . normalmente.
  5. Mentre continui a separarti e a ripulire le sezioni del codice, continua ad aumentare la copertura del test. Ora puoi scavare ancora di più e "riscrivere" ancora più codice quando necessario/desiderato con sempre maggiore sicurezza.
  6. Ripeti o applica ulteriori approcci di refactoring per continuare a migliorare la tua base di codice.

Branching by Abstraction

  1. Definire il punto problematico nel codice che si desidera rimuovere (il livello di persistenza, il generatore di pdf, il meccanismo di conteggio delle fatture, il generatore di widget, ecc.).
  2. eseguire (scrivere se necessario) alcuni casi di test funzionali (automatizzati o manuali ma si sa automatizzati) sulla base di codice che ha come target questa funzionalità insieme al comportamento generale.
  3. Estrai la logica relativa a quel componente dalla base sorgente esistente in una classe con un'interfaccia ragionevole.
  4. Verifica che tutto il codice ora stia utilizzando la nuova interfaccia per eseguire l'attività X che in precedenza era stata dispersa in modo casuale nel codice (Grep la base di codice, aggiungi una traccia alla nuova classe e verifica che le pagine che dovrebbero chiamarlo lo siano, ecc.), E che puoi controllare quale implementazione verrà utilizzata modificando un singolo file (registro oggetti, classe factory, qualunque sia IActivityXClass = Settings.AcitivtyXImplementer ();)
  5. rieseguire i casi di test funzionali che verificano che tutto funzioni ancora con tutte le attività X introdotte nella nuova classe.
  6. Scrivi test unitari ove possibile intorno alla nuova classe wrapper X di attività.
  7. implementare una nuova classe con una logica spaghetti meno folle rispetto all'implementazione legacy che aderisce alla stessa interfaccia della classe legacy.
  8. verificare che la nuova classe superi i test unitari scritti per la classe legacy.
  9. aggiorna il tuo codice modificando il registro/factorymethod/qualunque cosa per usare la nuova classe invece della vecchia.
  10. verifica che i test funzionali continuino a superare.

Principio aperto chiuso e logica comune/livello di persistenza

In una certa misura potresti riuscire a separare il tuo livello di presentazione, aziendale e di persistenza e scrivere una nuova app che è completamente retrocompatibile con la soluzione legacy, o almeno può ancora gestire i dati immessi dalla soluzione legacy. Probabilmente non consiglierei questo approccio, ma a volte è un ragionevole compromesso di tempo/pianificazione/risorse/nuove funzionalità richieste.

  • Separare almeno il livello di presentazione dai livelli di business e di persistenza.
  • implementare una nuova interfaccia utente e un migliore livello di presentazione che utilizza lo stesso livello aziendale e di persistenza comune.
  • Verifica che i dati creati con la nuova interfaccia utente non interrompano la vecchia interfaccia utente. (sarai in acqua calda se gli utenti del nuovo strumento interrompono gli utenti del vecchio strumento). Se stai cercando la piena compatibilità all'indietro, dovresti salvare tutto negli stessi livelli di persistenza. Se si desidera solo la compatibilità futura con il nuovo strumento, utilizzare un nuovo database e nuove tabelle o tabelle di estensione per tenere traccia dei dati non presenti nel sistema legacy.
  • Per nuove esigenze di funzionalità e livello di persistenza aggiungere nuove tabelle e metodi non modificare la logica legacy esistente o aggiungere colonne, vincoli a tabelle esistenti. per esempio. se devi iniziare a tracciare il contatto di emergenza dei datori di lavoro e alcuni altri campi non modificano la tabella dei dipendenti esistente (non abbiamo idea di quali ipotesi facciano i dati legacy su quella tabella) aggiungi una tabella di estensioni ID impiegato_piegato, impiegato_id, pronto_contatto_id, ecc.
  • Migra lentamente gli utenti sul nuovo sistema. se possibile, mettere il sistema legacy in modalità di sola lettura o semplicemente aggiungere un avviso per dire agli utenti che non sarà più disponibile dopo la data X.
  • implementare qualsiasi funzionalità mancata prioritaria o requisiti aziendali nel nuovo UI
  • passa sopra la base utenti.
  • continuare a ripulire la logica aziendale e gli utenti del livello di persistenza altre metodologie di refactoring.
0
Keith Brings

Direi che esiste una terza categoria nello spazio Refactor vs Rewrite ... E che sta aggiornando le tue versioni linguistiche, compilatori e librerie ... A volte l'adozione di moderne tecniche di codifica ha un grande vantaggio.

Prendiamo ad esempio C #, il codice v7 scrive in modo molto più pulito, più sicuro e più conciso rispetto alla v2 .. Cose come Elvis e l'operatore di coalescenza nulla aiutano molto.

Il cambio di compilatori potrebbe anche dare nuova vita a codice più vecchio. Quindi potrebbero esserci nuove biblioteche che potrebbero rendere le cose più facili da lavorare e implementare ... Il networking è un ottimo esempio di una serie di difficoltà di implementazione.

Inoltre, sistemi Linux incorporati ... Pensa all'installazione di nuovi strumenti: passa a git da svn. o aggiungi Vi al tuo sistema ecc. ecc.

Non deve sempre essere un refactor rispetto a riscrivere .. La tua architettura ha probabilmente bisogno di miglioramenti, ma funziona ... forse devi solo pensare a come è scritto il tuo codice ecc.

0
visc

Per decidere il punto in cui ricominciare, è necessario capire dove il valore di continuare sul progetto corrente non è all'altezza del valore nel ricominciare.

Il motivo per cui è così difficile è che si effettua una stima accurata della velocità di sviluppo del team sul nuovo progetto fino a quando non lo si avvia effettivamente. Detto questo, se, utilizzando una stima MOLTO prudente della tua velocità di sviluppo sul nuovo progetto, si stima che il progetto dia un utile ritorno sugli investimenti, allora hai un business case per ricominciare da capo.

0
Nobody

Con la mia metrica, devi soddisfare due condizioni per giustificare una riscrittura:

  1. Dopo la riscrittura le nuove funzionalità saranno più facili/veloci/meno buggy da scrivere
  2. La riscrittura impiegherà meno o uguale tempo rispetto all'aggiunta della nuova funzionalità corrente.

Anche allora vuoi limitare l'ambito della tua riscrittura. Ad esempio, in un'azienda avevamo software legacy scritto in C++ con la mentalità di un programmatore C che non conosceva la modularità. Il risultato finale è stato il codice speghetti sotto forma di una macchina a stati finiti che si estendeva su più classi e DLL. Avevamo un nuovo requisito che era molto diverso dalle ipotesi integrate nel codice e che avrebbe fatto parte del valore aggiunto brevettato della società per i suoi clienti.

Dopo aver trascorso del tempo con il codice che implementava altre funzionalità, avevo davvero una buona idea di quanto tempo ci sarebbe voluto per capire quale delle varie istruzioni switch avrei dovuto modificare, ecc. La mia proposta era di riscrivere la sezione di codice che era l'enorme macchina a stati finiti: dovrei impiegare meno tempo dell'estensione del codice esistente. Sono stato in grado di consolidare in uno DLL ciò che era un tempo tre, e fornire una struttura molto più orientata agli oggetti che avrebbe reso molto più facile fare le nuove funzionalità critiche insieme a rendere più facile aggiungi nuove funzionalità.

C'erano altre tre applicazioni che utilizzavano le librerie che avevano bisogno della riscrittura, quindi non volevo riscrivere completamente quei programmi. L'ambito era limitato alla biblioteca e ciò che era necessario per associare la biblioteca al software esistente. Le mie stime non erano di gran lunga fuori, e il lavoro ha pagato per se stesso. Poco dopo la riprogettazione, mi è stato assegnato il compito di aggiungere una nuova funzionalità. Ciò che mi avrebbe richiesto una settimana con la vecchia struttura mi ha richiesto solo un giorno con la nuova struttura.

0
Berin Loritsch

L'OP non indica lo scopo del progetto, ma il principale indizio che ho preso è stato "scritto in vecchio [linguaggio/dialetto] usando vecchi [libs]" che per me sono i driver principali di una riscrittura. In effetti, la maggior parte dei progetti su cui sono stato coinvolto in una significativa longevità del mercato alla fine si rendono conto che accogliere aggiornamenti per compilatori/interpreti/sistemi operativi è un compito importante nel mantenere la base di codice.

In breve, pianificherei la riscrittura in più fasi, dando priorità all'aggiornamento in libs. Potrebbe essere che, lungo la strada, puoi intrufolarti in altre ottimizzazioni, ma il fatto che prevedi di rinviare alcune modifiche a una fase successiva può essere un ottimo modo per rimanere nei tempi previsti ed evitare di rimanere "bloccato".

0
MarkHu