Quando un GRANDE riscrive la risposta?


278

Ho appena letto la 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?



6
E 'vecchio, ma è un classico - di Joel "Le cose che non dovrebbe mai fare, Parte I" joelonsoftware.com/articles/fog0000000069.html
Mawg

Questa è un'ottima domanda Molto rilevante, questa situazione si verifica frequentemente nell'ingegneria del software.
Brad Thomas,

Risposte:


325

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 per accelerare un nuovo sviluppatore è necessario più tempo di sotto (per livello di esperienza), è necessario riprogettare il sistema. 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 non è mai una buona idea è sbagliato.

Se un sistema può essere ridisegnato 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
    • Non è possibile far comprendere agli sponsor 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 maggiore 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. Il buy-in esecutivo e 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 quando ne hai bisogno. Non iniziare con un po 'di I-ho trascorso 6 mesi a costruire questo framework che non ha mai visto un vero codice.
  • 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 farlo. Guadagna la loro fiducia mostrando loro che puoi dare loro ciò che vogliono meglio se segui buoni principi di progettazione.

25
Penso che il punto di Joel sia che, facendo una riscrittura, perdi le conoscenze accumulate nel vecchio codice.
quant_dev,

14
@quant_dev in parte sì, ma quando riscrivi a volte ti rendi conto che molti dei bug nel vecchio sistema erano dovuti al modo in cui funzionava il vecchio sistema, non strettamente logico su come dovrebbe funzionare il sistema ideale.
Tjaart,

13
Joel dice che fallirà perché, durante la riscrittura, non stai aggiungendo nuove funzionalità alla tua applicazione. L'unico scopo di una riscrittura è eliminare parte o tutto il debito tecnico. Certo, questo non è poco, ma è rischioso se i tuoi concorrenti aggiungono nuove funzionalità e funzionalità al loro software mentre ti stai semplicemente liberando del debito tecnico nei tuoi.
Robert Harvey,

25
Ho lavorato con una base di codice che si adatta a tutti questi criteri + e tuttavia un Big Rewrite ha ancora fallito e in qualche modo ha peggiorato le cose dandoci un codice "new deal" implementato per metà che era molto diverso dal vecchio caos ma non molto più gestibile. IMO, solo se diventa completamente impossibile eseguire il refactoring, dovresti rimuovere tutta l'attenzione dall'aggiunta di funzionalità e dalla correzione di bug che costano ai tuoi clienti oggi. A meno che tu non stia parlando di un codice davvero indecifrabile, un team che non è in grado di estrarre bit modulari per un riutilizzo più semplice mentre procedi probabilmente non può riprogettare abbastanza bene per il grande rw comunque.
Erik Reppen,

11
Questa è una risposta utile, ma lungi dall'essere fantastica, perché dà un'impressione sbagliata su alcune cose. Ad esempio, "Tieni presente che il costo totale della riprogettazione in modo incrementale è sempre maggiore rispetto a una riscrittura completa" - la parola "sempre" in quella frase è sbagliata, perché "la riprogettazione in modo incrementale" ti dà l'opportunità di riutilizzare almeno alcune parti del progetto esistente, mentre una "riscrittura completa" non te lo offre. So che di sicuro, visto che in realtà ero stato in quella situazione, in cui abbiamo riscritto un'applicazione LOC> 100K parzialmente in parte, in parte no.
Doc Brown,

109

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.


11
+1 per l'approccio refactor. Molte volte non c'è abbastanza tempo o ore per riscrivere E mantenere il sistema esistente.
Ryan Hayes,

Questo è attualmente utilizzato per un'app demo (nessun cliente l'ha acquistata di recente e ho pensato che fosse il momento migliore per ricrearla).
Jonn,

4
@Giovanni: In qualità di dirigente, avrei difficoltà a ottenere una riscrittura su un'applicazione per la quale il mio team di vendita non ha ancora trovato un cliente. In tutta onestà, gli concederei un certo periodo di tempo, e poi deciderei cosa fare. Se l'interesse non c'è, distruggerei tutto e sceglierei qualcos'altro da fare.
NotMe

4
Di recente ho riscritto un'applicazione Visual Basic in Java. Ciò ha consentito l'esecuzione come servizio in Windows (senza interfaccia grafica Java), a vantaggio del cliente.

4
"le riscritture non hanno effetti / benefici diretti per il cliente" - questo è spesso un mito, poiché i nuovi framework forniscono "integrati" molti miglioramenti della produttività che sono impossibili o troppo costosi da implementare. Un esempio, l'aggiornamento di un'app vb6 a un'app .net consente agli utenti di aprire file più grandi (a causa di un'architettura a 64 bit), il che significa quindi che gli utenti finali non devono interrompere artificialmente il proprio lavoro.
Stephen

72

È tempo di riscrivere quando:

Il costo di riscrivere l'applicazione + mantenere l'applicazione riscritta è inferiore al costo di mantenere il sistema attuale 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 aggiungerle 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) salire di prezzo o alla fine (assolutamente) si esauriscono.
  • È diventato così complesso che il //Here be dragons.commento è in tutto il tuo codice.
  • Non puoi scrivere altri progetti e aggiungere nuovo valore all'azienda perché rattoppi sempre questa brutta bestia.

Questo è esattamente ciò che ha spinto la riscrittura a cui ho partecipato. Il codice era così fragile e il costo dell'aggiunta di nuove funzionalità era così elevato, che non riscrivere non era più un'opzione.
Frank Shearar,

16
Sto ridacchiando qui sul punto 2.
Paul Nathan,

4
@Paul: l'ho fatto anche quando un cliente mi ha detto che, poi ho scoperto che erano seri ... e che avrei fatto la raccolta dei requisiti per la riscrittura. Che giornata emozionante che è stata.
Ryan Hayes,

3
Il problema è come misurare i costi.

2
Mi piace questa risposta, divertente e vera. Vorrei aggiungere "quantificabilmente" proprio prima di "meno". Molte volte, è facile presentare la richiesta, ma è importante essere in grado di quantificare il tempo perso.
Kevin Hsu,

17

Se si richiede un cambiamento fondamentale nell'architettura del progetto, è probabilmente 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 corrente 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 ragioni chiare , difendibili e ben comprese per prendere parte a questo corso d'azione.


3
Devi stare molto attento a "riutilizzare ampie strisce di codice", questo può portare a codice legacy inutilizzato e struttura del codice scadente. Il refactoring è una soluzione migliore secondo me.
mrwooster,

1
Concordato. Parte di tale affermazione dovrebbe essere interpretata come "refattore" nel tuo "nuovo" progetto. Cioè, se davvero ti sei già impegnato in quel percorso drastico. Come menzionato da altri, questa è una rarità estrema che non dovrebbe quasi mai essere fatta.
Dan McGrath,

1
+1. Inoltre, la riscrittura richiederà tempo, durante il quale dovrà essere eseguita la manutenzione, ma sarà necessario apportare le stesse modifiche su entrambe le basi di codice.
Larry Coleman,

12

Anche se concordo 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 soddisferà le esigenze aziendali dell'organizzazione, così come un sistema nuovo di zecca potrebbe.

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.


+1 per menzionare la legge di Hofstadter .
Baelnorn,

11

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


Certo, ci sono momenti 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 di eseguire 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 esistono queste informazioni (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 spesso essere consegnate 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à, 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.


2
Potresti approfondire questa risposta spiegando perché il refactoring il più delle volte è meglio della riscrittura? E quando sarebbe una riscrittura essere la risposta?
gablin,

Dato che una riscrittura il più delle volte è lo stesso pasticcio in un abito diverso, hai ragione. Se riesci a eliminare quel singolo problema, allora ti sbagli. Non ci sono assoluti quando lo fanno le persone giuste.
JensG,

10

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

inserisci qui la descrizione dell'immagine

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.


4
Perché dovresti investire nella riscrittura di un progetto a basso valore commerciale? Scaricalo e basta!
Jørgen Fogh,

Ecco perché statess "sostituisci o ...". Puoi sostituirlo con qualcosa che abbia valore. O trasformalo in qualcosa che abbia valore. Ma hai ragione. Lo modificherò per aggiungere l'opzione "Scartalo".
Tulains Córdova,

8

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.


Sembra che il tuo datore di lavoro debba parlare con i clienti e spiegare la situazione per scoprire quale potrebbe essere il modo migliore per aiutarli, anche se ciò significa che devono pagare di più inizialmente, perché risparmieranno a lungo termine.

7

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 interessato 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' (era su v.3.0 e infine al punto in cui siamo quasi arrivati ​​a 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.


5

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

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 al suo 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 è prudente spendere soldi per fare un bel codice "fai la stessa cosa".


4

Joel Spolsky ha pubblicato 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, controlleresti 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 di Joels)), mi sentivo come se l'articolo di Joel fosse stato inviato da Dio, perché posso essere pessimista e amo buttare via il codice pensando di poterlo sempre scrivere meglio un secondo tempo, ma ho capito solo ora che costa solo molto .

Per dare una risposta concreta, direi solo che devi fare un'analisi approfondita del rapporto costo / 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 le estensioni reattive questa settimana, voglio davvero riscrivere la maggior parte del codice, ma ora cosa devo dire ai miei clienti? Il programma funziona perfettamente (con qualche perdita di memoria), ma a loro non importa? Non posso assolutamente dirgli che sto prendendo altre 2-3 settimane perché voglio rifare qualcosa. Ho intenzione di ramificare il codice e riscriverlo / giocarci nel mio tempo libero .

Solo i miei 2 centesimi ok !?


La tua prima implementazione è spesso non ottimale perché ci sono cose che non conosci ancora durante la progettazione. Questo di solito sarà trasformabile in forma anziché ricominciare da capo, poiché molto probabilmente hai fatto qualcosa di giusto. In caso contrario, è una prova di concetto e spesso devono essere scartati.

+1 per la ramificazione. Molte persone dicono "non riscrivere" perché sembra che tu stia gettando via il vecchio codice, ma non lo sei. Puoi avere basi di codice parallele.
lunchmeat317

Per essere onesti, se sei una persona che chiede consiglio a Joel Spolsky, allora non dovresti fare una riscrittura completa :-) E altrimenti, dovresti fare una riscrittura solo se riesci a convincere tutte le parti interessate perché gli argomenti di Joel non contano nel tuo caso specifico.
gnasher729,

3

La soluzione esistente non si ridimensiona.

Ti sto guardando, MS Access.


Non sono sicuro che tu stia guardando quello giusto. Jet Red non doveva mai ridimensionarsi, AFAIK.
JensG,

come risponde alla domanda posta?
moscerino

3

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

Cose che non dovresti mai fare, parte I.

... È importante ricordare che quando inizi da zero non c'è assolutamente motivo di credere che farai 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 costruirne uno da buttare è 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 di un adulto con esperienza nell'industria del software, potrebbe non essersi sparato così tanto ai piedi.


5
Si. Stavo cercando dei controargomenti. Deve essere fatto a volte.
Jonn,

3
Ogni argomento di riscrittura non è completo senza un riferimento all'articolo di Joel. Quello che dico, che l'articolo ha alcuni punti positivi, ma dannazione, pensa da solo. Forse dovresti dire perché sei d'accordo con l'articolo. Non concordo personalmente con Joel, semplicemente perché a volte è meglio scavare una nuova buca piuttosto che annoiarsi ulteriormente nella fossa senza fine. In ogni caso, una riscrittura, penso, porterebbe in superficie quei processi aziendali latenti per la rivalutazione.
Ahmad,

L'articolo di Joels è buono perché spiega attentamente come possono andare le cose cattive .

6
Joel usa un esempio del browser Netscape Navigator. Questo è un prodotto di consumo che si trovava nel mezzo di un'enorme curva di crescita che lavorava contro la concorrenza con un budget elevato. È stato un errore strategico per Netscape. D'altra parte, i progetti software "enterprise" personalizzati interni sono diversi. Non stai correndo per la quota di mercato. Non c'è pericolo che tutti i tuoi utenti lascino un prodotto competitivo. Dipende da una decisione aziendale: il costo di una riscrittura si ripaga da solo nel lungo periodo e / o è il modo migliore per raggiungere gli obiettivi aziendali?
Scott Whitlock,

Ho pensato che Joel avesse centrato il concetto chiave di "Non sai mai quali decisioni non sono state documentate che dovrai imparare nel modo più duro"
MathAttack,

2

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 siti Web PHP, l'autore ha appena copiato / incollato spahgetti invece di includere / class / function) o hai preso qualcosa da un'altra persona che è scritto 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.



+1 Mi piace la tua opinione, ti piacerebbe conoscere le tue opinioni sulla riscrittura su un nuovo set di API? (Vedi la mia risposta di seguito)
Gideon,

Sì, questi sono buoni punti. Microsoft ha riscritto il codice winXP e non sono stati nemmeno in grado di ottenere l'eliminazione / copia dei file nella prima versione di vendita al dettaglio di Vista. Mentre quando stavano semplicemente facendo progressi nella loro base di codice otteniamo costantemente una migliore qualità (W3.11 => W95 => W98 => ME => XP), Vista in cui riscrivono molte parti fondamentali è stato un disastro. Per la nuova API ... separerei il codice corrente per avere quanto più intatto e utilizzerei la nuova API su un livello superiore. Per esempio. le tue classi principali rimangono invariate, ma l'integrazione avviene tramite la nuova API. A meno che tutto sia così disordinato che non si potrebbe fare nient'altro che iniziare da 0.
Slawek

1
"... la verità è che se il codice è stato scritto da te, non potrai fare di meglio." Voterei questo post se avessi abbastanza rappresentante. Questo è il più disonesto, irrealistico e implica che in qualche modo le persone non possono progredire al punto in cui il codice che scrivono è un miglioramento del codice che hanno scritto in passato.
JᴀʏMᴇᴇ

1
@ JᴀʏMᴇᴇ: concordato - se non hai imparato nulla e non hai acquisito esperienza quando lo hai implementato la prima volta e / o se non riesci a fare un lavoro migliore ora che hai più conoscenza / esperienza / senno di poi; allora sei una patata e non un programmatore.
Brendan,

2

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

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

Ho preso un lavoro una volta, in cui la motivazione principale del datore di lavoro era 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 , è molto probabile ripetendo il problema a tempo debito.


2

È 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 pianificaci 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 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.


Sembra che dovresti essere in grado di refactoring in quella direzione. Quando esegui il refactoring, devi tenere a mente la flessibilità di cui hai bisogno in modo che la prossima funzione sia facile da scrivere.
Ian,

1

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 importante componente server in Java da C ++ per abilitare il threading out-of-the-box, una cache di oggetti e transazioni controllate dal client. All'epoca esistevano più librerie di threading per C ++ che avremmo dovuto supportare e l'abilitazione dei thread a gran parte del nostro codice di database avrebbe richiesto una riscrittura quasi totale. Per quanto riguarda le transazioni controllate dal cliente ... 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.


0

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

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 alcuni software legacy scritti 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 molto diverso dalle ipotesi integrate nel codice e che avrebbe fatto parte del valore aggiunto brevettato dell'azienda 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 una DLL quella che era una volta tre e di fornire una struttura molto più orientata agli oggetti che renderebbe molto più semplice eseguire le nuove funzionalità critiche e rendere più semplice l'aggiunta di 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

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 la 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

Bene, posso immaginare scenari ipotetici in cui potrei semplicemente buttare via la base di codice esistente (situazioni ipotetiche in cui le palline bucky hanno peso e volume pari a zero, in cui a nessuno importa 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 atto per maggior bene e cose ==

Refactoring del 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 come saranno probabilmente 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, hai intenzione di 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 tue 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 il giorno in giorno 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 approfondire ulteriormente 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.

Ramificazione per astrazione

  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 prende di mira 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 tuoi test funzionali continuino a superare.

Principio aperto aperto e logica aziendale / livello di persistenza comune

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 aziendale e di persistenza.
  • implementare una nuova interfaccia utente e un livello di presentazione migliore 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. ad es. se è necessario 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) aggiungere una tabella di estensione Employ_ext ID, employee_id, emergency_contact_id, ecc_id.
  • 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 nella nuova interfaccia utente
  • passa sopra la base utenti.
  • continuare a ripulire la logica aziendale e gli utenti del livello di persistenza altre metodologie di refactoring.

0

Direi che esiste una terza categoria nello spazio Refactor vs Rewrite ... E questo sta aggiornando le versioni linguistiche, i compilatori e le librerie ... A volte l'adozione delle 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.


-2

Non credo di aver mai visto persone riscrivere un'app legacy.

Quello che succede è che le persone stanno scrivendo app totalmente nuove con un'architettura, tecnologie, ecc. Diverse che hanno alcune caratteristiche in comune con la generazione precedente. E si chiama app 2.0, ma in realtà ha pochissime cose in comune con l'originale.

Ma questa non è in realtà una "riscrittura" dell'originale, nel senso che stai cercando di raggiungere la parità di funzionalità.

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.