Migrazione Delphi a .NET: quando conviene e quanto costa
Matteo Migliore

Matteo Migliore è un imprenditore e architetto software con oltre 27 anni di esperienza nello sviluppo di soluzioni basate su .NET e nell'evoluzione di architetture applicative per imprese e organizzazioni di alto profilo.

Ha guidato progetti enterprise, formato centinaia di sviluppatori e aiutato aziende di ogni dimensione a semplificare la complessità trasformando il software in guadagni per il business.

Un'azienda di stampaggio di materie plastiche nel bresciano, 41 dipendenti e 14 milioni di fatturato, gestisce ordini, magazzino, distinte base, produzione e spedizioni con un programma scritto in Delphi 7 nel 2003. Lo usano 22 persone ogni giorno. Il programma è stato scritto e viene mantenuto da un consulente che oggi ha 61 anni, lavora 30 giornate l'anno per l'azienda e ha detto, con molta onestà, che tra cinque anni vorrebbe smettere. Il titolare ha una sola domanda: conviene fare la migrazione Delphi a .NET, o possiamo andare avanti così?

La risposta di solito è fra due estremi, entrambi sbagliati. Il primo è "Delphi è morto, riscriviamo tutto", detto da chi vende progetti di riscrittura. Il secondo è "funziona da vent'anni, non si tocca", detto da chi non vuole spendere o non vuole cambiare. Delphi non è morto: esiste una versione corrente, aggiornata ogni anno, e si possono tenere in vita programmi di quel tipo per molto tempo. Ma il fatto che un linguaggio sia vivo non dice niente su quel programma, scritto in quella versione, con quei componenti e quella persona sola a conoscerlo.

La decisione si prende su tre numeri che nessun preventivo scrive: quanti minuti perde ogni utente ogni giorno per aggirare i limiti del programma, quanti anni deve ancora servire, e quanto vale il rischio di una persona sola. Con il caso di Brescia, composto e non di un cliente reale, vedrai come si misurano in una settimana e che cosa dicono: a cinque anni la strada più economica è aggiornare Delphi, a otto anni resta tale, e la migrazione si giustifica per ragioni che non sono il prezzo.

Trovi i sette segnali che dicono che il programma Delphi è a rischio, l'inventario di che cosa contiene davvero, le quattro strade con i loro costi, il conto a uno, tre, cinque e otto anni, il modo di migrare un modulo per volta senza fermare l'azienda, un programma in C# che legge i dati vecchi senza farsi ingannare dalle date e dagli importi di Delphi, le regole nascoste nel codice e gli errori che ho visto ripetersi in ventisei anni di migrazioni.

Una premessa onesta. Scrivo software dal 1999 e ho costruito un gestionale legale multi-tenant, quindi so da che parte sta il mio interesse. Il caso di Brescia è composto, le ipotesi sono scritte una per una e il risultato include il caso in cui non conviene migrare né da me né da nessun altro. Un consiglio che non ti dice quando non spendere vale poco.

Quando serve una migrazione da Delphi a .NET?

Un programma Delphi in buono stato non è un problema. Il problema è l'insieme di condizioni che lo circondano, e ci sono sette segnali. Con tre o più siamo nella zona in cui il rischio comincia a costare più del cambio.

1. L'ambiente di sviluppo gira su una sola macchina

Delphi 7 è del 2002. Si installa su un computer vecchio o su una macchina virtuale che nessuno ha il coraggio di spegnere, con un installer su un CD e una licenza che nessuno trova. Se quel computer si rompe, l'azienda ha il programma compilato ma non riesce più a cambiarlo. A Brescia l'ambiente vive in una macchina virtuale su un server del 2017.

2. L'accesso ai dati usa una tecnologia senza futuro

Molti programmi Delphi di quegli anni parlano con il database tramite il BDE, il Borland Database Engine, che non esiste in versione a 64 bit e che Embarcadero ha dichiarato obsoleto da molti anni. Funziona finché funziona Windows a 32 bit, e Windows 11 lo esegue ancora. Il rischio non è che smetta domani, è che ogni aggiornamento di sistema sia una piccola scommessa e che nessuno possa più correggerlo se si rompe.

3. Il programma lo conosce una persona

È il segnale più serio e il meno discusso. Trecentomila righe di codice senza documentazione e senza test, scritte nell'arco di vent'anni da una persona sola, sono una conoscenza che vive in una testa. Se quella persona si ammala, cambia lavoro o va in pensione, l'azienda perde la possibilità di cambiare la propria attività, non solo il software.

4. Ci sono componenti di terzi senza i sorgenti

Le griglie, i generatori di report, le librerie per le etichettatrici e per le bilance erano spesso componenti commerciali. Alcuni produttori hanno chiuso o sono stati assorbiti, e il componente esiste solo come file compilato. A Brescia sono tre su quattordici. Finché il programma resta a 32 bit e sullo stesso Windows funziona, ma non si può più portare da nessuna parte.

5. Il database è vecchio e fragile

Firebird 1.5, Interbase, Paradox o un file DBF fanno il loro lavoro, ma senza aggiornamenti di sicurezza e con backup a mano. A Brescia il database pesa 6,4 GB e il backup è un file copiato di notte su un disco USB da un impiegato.

6. Le integrazioni sono tutte ripieghi

Fatturazione elettronica, portale del cliente, scambio ordini con un cliente dell'automotive, etichette per la logistica: ciascuna è stata aggiunta con un file di testo, uno script o un programmino a parte. Ogni nuova richiesta di un cliente importante è un'altra stampella. Quando un cliente chiede un collegamento in tempo reale, il programma non lo sa fare.

7. Nessuno può usarlo fuori dall'ufficio

Il programma si apre su un computer in rete locale. Per lavorare da casa, da un magazzino remoto o dal telefono, si usa il desktop remoto o una VPN con tutti i loro difetti. Non è un difetto del linguaggio, ma del modo in cui il programma è nato.

A Brescia i segnali veri sono cinque su sette: l'ambiente su una sola macchina, la persona sola, i componenti senza sorgenti, le integrazioni a stampella e l'accesso solo da ufficio. Con un esito così la domanda non è se pensarci, ma che cosa fare e quando. Per l'orizzonte generale del costo di un programma vecchio, la guida al costo del software legacy mostra come si fa il conto sul caso generico.

Che cosa c'è davvero dentro il tuo programma Delphi?

Prima di scegliere una strada serve un inventario, perché il prezzo di qualunque soluzione dipende da quello che c'è dentro, e il titolare di solito descrive solo quello che vede. Un'applicazione Delphi contiene cinque tipi di cose, e ciascuna si sostituisce in modo diverso.

  • Unit e form: il codice Pascal e le maschere. Le maschere si ridisegnano, il codice si legge per capire che cosa decide.
  • Accesso ai dati: query sparse nelle maschere, componenti di dati e, a volte, logica nei trigger e nelle procedure del database.
  • Report: le stampe, cioè conferme d'ordine, bolle, etichette. Sono quelle che il cliente finale vede.
  • Componenti di terzi: griglie, generatori di report, driver. Alcuni hanno un equivalente moderno, altri no.
  • Regole: sconti, blocchi, arrotondamenti, calcoli di tempi e di lotti. Sono il vero patrimonio, e sono scritte solo nel codice.

Nel caso di Brescia l'inventario, fatto leggendo il progetto in quattro giorni, dà questi numeri.

ElementoQuantitàChe cosa significa per il costo
Unit Pascal842 (310.000 righe)Da leggere tutte per trovare le regole, almeno con la ricerca delle decisioni
Maschere18752 usate ogni giorno, 71 una volta al mese, 64 mai: queste ultime non si migrano
Report6419 sono documenti per clienti e fornitori, da rifare con la stessa cura
Tabelle Firebird21234 senza scritture da tre anni; 58 trigger e procedure con logica
Componenti di terzi143 senza sorgenti, 2 con produttore chiuso: da sostituire
Regole di business nel codice235 sono diverse dalla prassi di oggi

Il numero che pesa di più non è quello che sembra più grande. Le 842 unit fanno impressione, ma il lavoro vero sta nelle 52 maschere usate ogni giorno, nelle 23 regole e nei 58 trigger che nascondono logica dentro il database, dove nessuno la cerca. Le 64 maschere mai aperte sono un risparmio: in quasi tutte le migrazioni che ho visto il 30-40% del programma non serve a niente da anni e si porta dietro solo per paura.

Il terzo numero da guardare sono i componenti di terzi. Una griglia per cui esiste un equivalente moderno costa qualche giornata di adattamento. Un driver per una bilancia, di cui nessuno ha più i sorgenti, può significare ricostruire il collegamento da zero, a volte leggendo il protocollo con un analizzatore di porta seriale. Quei tre componenti di Brescia valgono da soli 14 giornate nella stima, che vedi più avanti.

Quali sono le quattro strade, e che cosa comprano?

Le opzioni non sono "Delphi sì" o "Delphi no". Sono quattro, e la prima, che quasi nessuno scrive nel preventivo, è non fare niente.

Strada 0: non fare niente

Il programma resta com'è e continua a costare. A Brescia sono 30 giornate l'anno di manutenzione del consulente, cioè 12.600 euro, più il costo che non compare in nessun bilancio: i minuti persi dagli utenti e i fermi. Lo stimo qui sotto, con una tabella. Non è una strada "gratuita": è la più economica nel primo anno e la più rischiosa nel quinto.

Strada A: aggiornare Delphi, restare su Delphi

Il programma si porta a una versione corrente di Delphi, si sostituisce il BDE con un accesso ai dati moderno, si converte il codice a Unicode e si cambiano i componenti senza sorgenti. Si ottiene un programma che compila oggi, a 64 bit se serve, con un ambiente ricostruibile. Non cambia il modo di lavorare, e non ci sono utenti da riaddestrare.

Il lavoro costa 60 giornate: 14 per il passaggio a Unicode e al compilatore nuovo, 20 per sostituire il BDE, 14 per i componenti senza sorgenti e 12 per i test. A 420 euro al giorno sono 25.200 euro. Il costo fisso annuo sale a 16.600 euro, cioè 12.600 di manutenzione più 4.000 di licenze dell'ambiente e dei componenti.

Il limite è che la dipendenza dalla persona resta, e che Delphi su Windows resta un programma da ufficio: non diventa web né mobile. È la strada che compra tempo e ordine, non un nuovo futuro.

Strada B: migrare a .NET un modulo per volta (strangler fig)

Un guscio .NET nuovo si affianca al programma Delphi, che continua a funzionare. Un modulo per volta si riscrive in .NET e sostituisce il corrispondente di Delphi, finché del vecchio non resta niente. Il nome, strangler fig, viene dal rampicante che avvolge un albero e lo sostituisce lentamente, ed è il modo che uso quando il sistema non può fermarsi: lo spiego nel dettaglio nella guida allo strangler fig pattern.

Per Brescia la stima è di 455 giornate, cioè 191.100 euro: 40 di inventario e regole, 45 per i dati, 280 per i moduli, 45 per i test e il parallelo, 25 per la gestione del progetto e 20 per formazione e avvio. Durante i 14 mesi il vecchio programma va comunque mantenuto: sono 35 giornate, 14.700 euro. Quando ha finito, il costo annuo è di 12.480 euro, cioè 24 giornate di manutenzione (10.080 euro) più 2.400 euro di hosting.

Strada C: riscrivere tutto da capo

Un progetto nuovo, che sostituisce il vecchio in un giorno solo. Per Brescia sono 569 giornate, 238.980 euro, con 18 mesi in cui il vecchio programma vive in parallelo (18.900 euro). È la strada che i fornitori di riscritture amano, perché è un progetto grande. Ed è la più rischiosa: per diciotto mesi non si consegna valore, e il giorno del passaggio si scopre tutto insieme. Il confronto fra queste due logiche, e perché la seconda perde più spesso, è nella guida a riscrivere o rifattorizzare.

Un confronto sintetico, con le stesse ipotesi.

A. Aggiornare DelphiB. Strangler a .NETC. Riscrittura
Costo di avvio25.200 euro191.100 euro238.980 euro
Costo di doppio mantenimentonessuno14.700 euro18.900 euro
Costo annuo fisso16.600 euro12.480 euro12.480 euro
Tempo per essere in uso2-3 mesi14 mesi, a moduli18 mesi, tutto insieme
Dipendenza da una personaRestaSi riduce modulo dopo moduloSi riduce, con il rischio del giorno del passaggio
Accesso web e mobileNoSì, per i moduli nuoviSì
Quando ha sensoServe ordine e tempo, orizzonte cortoOrizzonte lungo, sistema che non può fermarsiQuasi mai

Se il percorso tecnico che ti serve è quello complessivo, con le decisioni sul database, sul codice e sui rischi, lo trovi nella pagina sulla modernizzazione del software legacy, che include i casi in cui la risposta è non toccare niente.

Quanto costa la migrazione Delphi a .NET rispetto a non farla: il conto a cinque e a otto anni

Il prezzo di avvio ti dice poco. Dopo cinque o otto anni quello che pesa è il costo di vita, e una voce che nessun preventivo scrive: i minuti che ogni utente perde ogni giorno perché il programma non fa quello che serve.

Per metterli in euro bastano tre numeri: 22 utenti, 220 giorni lavorativi e un costo orario aziendale di 32 euro. Ogni minuto perso ogni giorno da ogni utente vale 22 x 220 / 60 x 32 = 2.581 euro all'anno. Un fermo di mezza giornata, con tutti fermi, vale 4 ore x 22 utenti x 32 euro = 2.816 euro. Quanti sono, nel caso di Brescia?

  • Non fare niente: 10 minuti al giorno per utente, fra attese, doppie digitazioni e report che si fanno in Excel perché il programma non li produce. Fanno 25.813 euro l'anno. Più due fermi l'anno, 5.632 euro, e la manutenzione, 12.600. In tutto 44.045 euro l'anno.
  • Aggiornare Delphi: 6 minuti, perché la maggior parte dei difetti di interfaccia resta, e un fermo l'anno. Con 16.600 euro fissi sono 34.904 euro l'anno.
  • Migrare a .NET: 2 minuti, nessun fermo, 12.480 euro fissi. Sono 17.643 euro l'anno, a migrazione finita.
  • Riscrivere: lo stesso di B a regime, 17.643 euro l'anno.

I minuti sono stime e vanno sostituiti con misure vere, come spiego nell'ultima parte. Ma la struttura del conto regge: costo di avvio, costo di doppio mantenimento, costo fisso annuo e costo dei minuti persi, sommati in un orizzonte scelto.

OrizzonteNon fare nienteA. Aggiornare DelphiB. Strangler a .NETC. Riscrittura
1 anno44.045 euro60.104 euro223.443 euro275.523 euro
3 anni132.136 euro129.912 euro258.728 euro310.808 euro
5 anni220.227 euro199.720 euro294.013 euro346.093 euro
8 anni352.363 euro304.432 euro346.941 euro399.021 euro
Costo cumulato in otto anni di quattro scelte per un gestionale Delphi con ventidue utenti: non fare niente, aggiornare Delphi, migrare a .NET un modulo per volta e riscrivere tutto

Il risultato è meno ovvio di quanto un venditore vorrebbe, e va letto con onestà. Aggiornare Delphi costa meno della migrazione a 1, 3, 5 e anche a 8 anni: 199.720 euro contro 294.013 a cinque anni, 304.432 contro 346.941 a otto. Il pareggio fra aggiornare e migrare arriva solo dopo circa 10 anni e mezzo, perché la distanza di partenza è di 180.600 euro e il risparmio annuo della migrazione è di 17.261 euro. Aggiornare Delphi, invece, si ripaga rispetto al non fare niente in meno di tre anni.

Chi ti dice che la migrazione "si ripaga da sola" in tre anni sta omettendo qualcosa, o ha un costo di partenza molto più basso del tuo, o un sistema molto peggiore. Un programma di cui è difficile stimare i minuti persi si migra anche per un altro motivo, che nel conto non c'è ancora.

Il rischio di una persona sola, messo in euro

Il conto sopra tratta la persona sola come un costo ordinario. Non lo è: è un rischio, e si può dargli un valore. Ipotizza che il consulente smetta, si ammali o non sia più raggiungibile, con una probabilità del 10% l'anno. In quel caso l'azienda resta senza manutenzione per circa tre settimane, 15 giorni lavorativi, prima di trovare qualcuno che capisca il programma. Con 22 utenti a ritmo ridotto, il danno è di 22 x 15 x 8 x 32 = 84.480 euro. Il valore atteso è 8.448 euro l'anno.

Quel rischio pesa su "non fare niente" e su "aggiornare Delphi" (la persona resta), e si riduce sulla migrazione, dove il codice è documentato, testato e scritto in una tecnologia con milioni di sviluppatori. Aggiungendolo, aggiornare Delphi passa da 34.904 a 43.352 euro l'anno, e il pareggio con la migrazione scende da 10,5 a 7 anni. Con questa ipotesi, su un orizzonte di dieci anni la migrazione costa meno del solo aggiornamento.

Il 10% e le tre settimane sono ipotesi, da cambiare con le tue. Il punto è che il rischio della persona sola è numerabile, e metterlo nel conto è meglio che lasciarlo in una frase come "dipendiamo da lui".

Attenzione ai limiti: sotto i dieci utenti i minuti persi pesano meno della metà e la migrazione quasi mai si ripaga. Sopra i quaranta, e con un processo che è davvero un vantaggio competitivo, il conto cambia a favore di B. Per la logica dei costi di un gestionale su misura, con le soglie, c'è la guida a quanto costa un software gestionale su misura.

Come si decide: tre domande e una regola

Il conto serve a dare un ordine di grandezza. La decisione si prende con tre domande, nell'ordine in cui riducono il rischio.

Domanda 1: per quanti anni deve servire?

Se la risposta è "non lo so", è già un'informazione. Scrivi tre numeri: minimo, probabile e massimo. Un'azienda che prevede di cambiare sede o di essere venduta in tre anni non ha motivo di costruire niente. Un'azienda che ci sarà in dieci anni con lo stesso modo di lavorare ha ragione di considerare un sistema nuovo, perché è sull'orizzonte lungo che la migrazione recupera.

Domanda 2: la persona sola è un rischio che puoi accettare?

Una prova semplice: se domani quella persona non risponde più al telefono, quanto tempo serve per rimettere in piedi un'altra persona? Se la risposta è "mesi", il rischio ha un prezzo, e sono gli 84.480 euro di prima. Se il programma è documentato e un altro programmatore Delphi lo capirebbe in poche settimane, il rischio è più basso e la strada A diventa difendibile più a lungo.

Domanda 3: dove vivono le regole oggi?

Se stanno scritte in un documento o nella testa dei responsabili, si portano in qualsiasi sistema. Se stanno nel codice Pascal e nei trigger e solo lì, la prima spesa non è il sistema nuovo ma l'estrazione delle regole, e quella si fa in ogni caso. Non c'è strada senza questo passo, e conviene farlo prima di parlare con i fornitori.

La regola

SituazioneStrada
Orizzonte sotto i 3 anni, o azienda in venditaNon fare niente, o lo stretto necessario per un ambiente ricostruibile
Orizzonte fra 3 e 7 anni, persona sola ma documentabileAggiornare Delphi (A) e scrivere le regole
Orizzonte oltre 7-10 anni, componenti senza sorgenti, richieste di accesso webStrangler a .NET (B), a moduli
Più di 40 utenti e un processo che è il vantaggio dell'aziendaStrangler a .NET, con priorità ai moduli del vantaggio
Qualunque caso, con un progetto che non può fermarsi 18 mesiMai la riscrittura integrale (C)

Per Brescia il consiglio è in due tempi: aggiornare subito i punti rotti, cioè estrarre le 23 regole, rimettere l'ambiente in una macchina ricostruibile e sostituire i tre componenti senza sorgenti, e avviare in parallelo il primo modulo .NET sul punto che più ha richieste di cambiamento, gli ordini. Il resto si decide dopo il primo modulo, con un numero vero di minuti recuperati.

Se la scelta cade sulla costruzione, il modo di scegliere chi la scrive pesa quanto la scelta stessa: trovi le domande nella guida a come scegliere una software house.

Come funziona lo strangler fig applicato a Delphi

La migrazione un modulo per volta non è un'idea astratta. Con Delphi ha tre caratteristiche specifiche, e conviene conoscerle prima di firmare.

Il database è condiviso, almeno all'inizio

Il vecchio programma e i moduli nuovi leggono e scrivono lo stesso database Firebird. Non si copiano dati avanti e indietro: sarebbe la fonte di tutti i problemi. Il guscio .NET si collega allo stesso database con un provider ADO.NET (esiste quello ufficiale per Firebird) e passa dai dati un solo punto, che si chiama strato anti-corruzione e che vedi nel programma più sotto. Solo alla fine, quando l'ultimo modulo Delphi è spento, si migra il database su uno moderno, con la riconciliazione automatica che conosci dalla migrazione da Access.

Il programma nuovo avvia quello vecchio

Il guscio .NET ha il login, il menu e la finestra principale. Per i moduli non ancora migrati, apre la maschera Delphi corrispondente, come un eseguibile separato a cui passa l'utente e il contesto, per esempio il cliente selezionato. Per l'utente c'è un solo programma. Per te c'è un indice di migrazione: ogni voce del menu punta al vecchio o al nuovo, e si sposta con una riga di configurazione.

L'ordine dei moduli si sceglie con tre criteri

Non si parte dal più semplice né dal più grosso. Si parte da dove il cambiamento è più frequente e il rischio è più basso, nell'ordine.

  1. Quello che cambia di più: a Brescia sono ordini e preventivi, dove il commerciale chiede una modifica ogni mese. Lì il vantaggio arriva subito.
  2. Quello che serve fuori ufficio: l'accesso web per i commerciali in viaggio e per il portale cliente. È dove Delphi non può arrivare.
  3. Quello che rischia di più: il modulo con i componenti senza sorgenti, per esempio il collegamento con le bilance. Si toglie per primo il pezzo che può rompersi.

Il resto, cioè anagrafiche, magazzino e distinte base, segue l'ordine delle dipendenze. Fatturazione e chiusure contabili vanno per ultime, perché sbagliare lì ha il costo più alto e perché hanno più regole.

Ordine di migrazione dei moduli da Delphi a .NET in quattordici mesi: dati e regole, guscio e anagrafiche, ordini e preventivi, magazzino e distinte, produzione e spedizioni, fatturazione e spegnimento

Il piano di Brescia è di 14 mesi con due sviluppatori e un coordinatore a tempo parziale. Nei mesi 1-2 si fanno inventario, regole e bonifica dei dati. Nei mesi 3-4 si costruiscono il guscio e le anagrafiche. I mesi 5-7 sono per ordini e preventivi, il primo modulo con valore visibile. I mesi 8-10 per magazzino e distinte base. I mesi 11-12 per produzione e spedizioni. I mesi 13-14 per fatturazione, migrazione finale del database e spegnimento di Delphi.

La regola che tengo da sempre: ogni modulo va in produzione da solo, con il vecchio disponibile per tornare indietro entro la sera. Se un modulo non è pronto, non blocca gli altri. E ogni modulo si chiude con un parallelo di una settimana su due utenti pilota, perché è l'unico modo per scoprire le regole che nessuno ha ricordato. Se l'azienda ha anche una parte di interfaccia desktop da portare, il confronto fra tenerla, portarla o riscriverla è nella guida a Windows Forms nel 2026.

Come si leggono i dati di Delphi senza farsi ingannare

I dati di un programma Delphi nascondono tre stranezze che producono errori silenziosi, di quelli che si scoprono tre mesi dopo, e conviene conoscerle prima di scrivere una riga.

  • Le date sono numeri: il tipo TDateTime di Delphi è un numero decimale che conta i giorni dal 30 dicembre 1899, con le ore come parte frazionaria. In .NET lo stesso valore si legge con DateTime.FromOADate, ma se qualcuno lo tratta come intero perde l'ora, e se lo confronta senza conversione ottiene date sbagliate di un secolo.
  • Gli importi sono in virgola mobile: molti programmi di quegli anni salvano gli importi come numeri double. Un totale di 10,005 euro diventa 10,0049999 e l'arrotondamento al centesimo cambia. Quello di Delphi arrotonda nel modo che il commercialista aspettava, quello predefinito di .NET è diverso: va indicato di proposito.
  • Il testo dipende dal set di caratteri: un database creato senza indicarlo contiene byte in Windows-1252, e se il programma nuovo non lo sa mostra "perché" come "perché". Nella stringa di connessione si indica il set di caratteri della colonna, e si controlla su un campione con gli accenti.

La soluzione è mettere tutto questo in un posto solo: uno strato che parla con il database vecchio e consegna al codice nuovo oggetti puliti, con date vere e importi in decimal. Il programma qui sotto ne è un esempio ridotto. Funziona con qualunque provider ADO.NET (si passa una DbConnection), compila con .NET 10 e non richiede pacchetti oltre a quello del provider.

using System.Data.Common;
using System.Runtime.CompilerServices;

public sealed record Ordine(int Id, string Cliente, DateTime Data, decimal Totale);

public static class OrdiniLegacy
{
    // Delphi salva le date come TDateTime: un double con i giorni dal 30/12/1899.
    public static DateTime DaTDateTime(double valore) => DateTime.FromOADate(valore);

    // Importi in virgola mobile: si arrotondano a due decimali come fa il commercialista
    // (0,5 verso l'alto), non con l'arrotondamento al pari che .NET usa di default.
    public static decimal DaImporto(double valore) =>
        Math.Round((decimal)valore, 2, MidpointRounding.AwayFromZero);

    public static async IAsyncEnumerable<Ordine> LeggiAsync(
        DbConnection cn, DateTime dal, [EnumeratorCancellation] CancellationToken ct = default)
    {
        await using var cmd = cn.CreateCommand();
        cmd.CommandText = "SELECT ID, CLIENTE, DATA_ORDINE, TOTALE FROM ORDINI WHERE DATA_ORDINE >= @dal ORDER BY ID";
        var p = cmd.CreateParameter();
        p.ParameterName = "@dal";
        p.Value = dal.ToOADate();
        cmd.Parameters.Add(p);

        await using var r = await cmd.ExecuteReaderAsync(ct);
        while (await r.ReadAsync(ct))
        {
            yield return new Ordine(
                r.GetInt32(0),
                r.GetString(1).TrimEnd(),
                DaTDateTime(r.GetDouble(2)),
                DaImporto(r.GetDouble(3)));
        }
    }
}

Il codice assume che, in questo database, le date degli ordini siano salvate come numeri, come capita in molti programmi di quel periodo; se sono colonne di tipo data, la conversione non serve. Il resto vale in ogni caso: i moduli nuovi non conoscono Delphi, conoscono solo Ordine. Quando il database sarà migrato, si riscrive questa classe e il resto del programma non se ne accorge.

Sul database vecchio il primo giro di prova a Brescia ha trovato 1.340 ordini con la data a zero, che Delphi mostrava come "30/12/1899" e che nessuno aveva mai notato perché il programma li nascondeva con un filtro. Sono dati veri, e vanno decisi uno per uno con il cliente: ignorarli, correggerli o conservarli come storico.

Le regole nascoste nel codice Pascal: come si estraggono

È la parte che decide se la migrazione ha successo. Un'applicazione Delphi non è un insieme di maschere: è un insieme di maschere e di comportamenti, e i comportamenti stanno nel codice e nei trigger. Portare le maschere senza le regole produce un sistema che sembra funzionare e dà numeri sbagliati.

Il metodo che uso ha quattro passi, e a Brescia ha richiesto otto giorni di lavoro.

1. Cercare le decisioni, non leggere tutto

Leggere 310.000 righe non è possibile. Si cercano le parole che indicano una decisione: if, case, i messaggi all'utente (ShowMessage, MessageDlg) e le uscite anticipate (Abort, Exit). Il progetto di Brescia ha dato circa 4.100 punti di decisione, di cui la maggior parte è interfaccia. A queste si aggiungono i 58 trigger e le procedure del database, che si leggono tutti.

2. Classificare ogni decisione

Ogni condizione finisce in una di tre categorie: regola di business (lo sconto, il blocco, il calcolo), regola di interfaccia (il campo che si nasconde, il colore) e rimedio a un limite (il controllo che evita un errore del componente). Le prime vanno portate, le seconde si decidono per il sistema nuovo, le terze di solito spariscono.

3. Scrivere ogni regola in una frase e un esempio

Un esempio da Brescia. Nel codice Pascal c'è questo.

if (Cliente.AnniAttivita >= 3) and (Cliente.Fatturato12Mesi >= 80000)
   and (Articolo.Famiglia <> 'STAMPI') then
  Sconto := 0.04
else if Ordine.QuantitaLotto >= Articolo.LottoMinimo * 5 then
  Sconto := 0.02;

In italiano diventa: "Ai clienti con almeno tre anni di rapporto e 80.000 euro di fatturato negli ultimi dodici mesi si applica il 4% di sconto, tranne sugli stampi. Se non si ha diritto a quello, un ordine pari ad almeno cinque lotti minimi ha il 2%. Esempio: ordine di 12.000 euro da un cliente con quattro anni e 95.000 euro, sconto 480 euro". Una frase e un caso con numeri sono ciò che permette poi di scrivere un test e di far leggere la regola a chi la conosce davvero.

4. Farla confermare da chi lavora

Le 23 regole sono state lette ad alta voce al commerciale, al magazzino e all'amministrazione. Cinque erano diverse dalla prassi: il codice faceva una cosa, ma la prassi era cambiata da anni e nessuno aveva toccato il codice. In un caso, un blocco sui clienti con pagamenti scaduti, il programma lo ignorava per una scorciatoia aggiunta nel 2011 e nessuno lo sapeva. È il risultato più prezioso dell'inventario: le regole nel codice sono spesso diverse da quelle che l'azienda crede di avere.

Il bonus dell'operazione è il test. Ogni regola scritta con il suo esempio diventa un test automatico, che da quel momento protegge il sistema nuovo da ogni modifica. Lo stesso metodo vale per qualsiasi applicazione desktop vecchia: lo trovi applicato nella guida alla migrazione da VB6 a .NET, dove l'architettura a maschere è molto simile, e in quella sulla migrazione da .NET Framework a .NET 10, per chi parte da un programma già scritto in .NET ma vecchio.

I componenti di terzi senza sorgenti: che cosa si fa

È la parte tecnica più fastidiosa, perché non si risolve leggendo il codice: il codice non c'è. Ci sono quattro casi, e ciascuno ha la sua soluzione.

Il componente ha un successore. Le griglie e i generatori di report di quegli anni hanno quasi sempre un equivalente moderno, a volte dello stesso produttore. Si sostituisce, si adattano le maschere e il costo è di qualche giornata per componente. A Brescia è il caso di 7 componenti su 14.

Il componente si può rimpiazzare con una libreria standard. Per esempio un componente per generare file PDF o per leggere file Excel, oggi coperti da librerie diffuse e mantenute. Si scrive un piccolo adattatore e si sostituisce. Sono 4 componenti.

Il componente parla con una macchina. Una bilancia, un lettore di codici, una etichettatrice. Lì non si cerca un successore: si legge il protocollo, spesso un semplice scambio di byte su porta seriale o di rete, e si riscrive in poche centinaia di righe. Si tiene la macchina e si butta il componente. Sono 2 componenti, e le 14 giornate stimate sono quasi tutte per loro, perché serve la macchina vera davanti per provare.

Il componente fa qualcosa di cui nessuno ricorda lo scopo. È più comune di quanto si pensi. Prima di sostituirlo, si disattiva in una copia e si guarda che cosa smette di funzionare. A Brescia un componente sconosciuto risultò essere il controllo delle licenze di un altro programma, e fu spento.

La regola generale: un componente senza sorgenti è un debito con la data di scadenza ignota. Va sostituito prima che si rompa, nel momento in cui si mette mano al modulo che lo usa, non il giorno in cui smette di funzionare.

Quali errori ho visto fare più spesso?

Le migrazioni da Delphi sbagliano in pochi modi, sempre gli stessi. Li scrivo perché evitarli vale più di qualsiasi scelta tecnica.

Convertire il codice Pascal in C# con uno strumento automatico. Esistono strumenti che traducono riga per riga, e il risultato è un programma che compila e che porta con sé tutte le abitudini di Delphi: variabili globali, accesso ai dati dentro le maschere, nessun test. Si è cambiato il linguaggio e non l'architettura. Il debito resta, scritto in un'altra sintassi.

Fidarsi del "ci pensa il fornitore". Un fornitore di migrazione non conosce le tue 23 regole. Se non le scrivi prima, quelle dimenticate emergono nei primi tre mesi sotto forma di errori. Il documento delle regole è tuo, non del fornitore.

Migrare tutto, compreso quello che non serve. Le 64 maschere mai aperte non vanno nel nuovo sistema. Ogni elemento portato dietro costa giornate di test e aumenta la superficie dei problemi. Chiedi agli utenti che cosa usano davvero.

Dimenticare i report. Gli utenti dicono "gestionale" ma pensano ai documenti: la conferma d'ordine con il suo aspetto, l'etichetta che il cliente scansiona. Se il nuovo sistema non produce un documento uguale o migliore, sembrerà un passo indietro anche se tutto il resto funziona.

Migrare i dati una volta sola, alla fine. È la tentazione dei progetti a cascata. Se i dati si provano solo l'ultimo mese, i problemi (le 1.340 date a zero di prima) emergono quando non c'è più tempo. I dati si migrano in prova ogni due settimane, dal primo mese.

Saltare il parallelo per fretta. Costa una settimana di doppio inserimento per due persone, circa 2.560 euro. Gli errori che trova costano un multiplo di quella cifra, e arrivano quando i clienti li vedono.

Tenere la persona sola come unico riferimento. Il consulente che ha scritto il programma deve partecipare all'inventario, dove la sua conoscenza è preziosa, e deve farlo con un compenso adeguato e con la certezza che non sarà escluso. Un consulente che si sente sostituito ritarda, non coopera. Ma la responsabilità del sistema nuovo deve stare in un posto che non dipende da una sola persona, e la prima cosa che si scrive è la documentazione.

Non pianificare la formazione. Ventidue persone abituate a un'interfaccia da vent'anni non passano a un'altra in un pomeriggio. A Brescia le 20 giornate di formazione e avvio sono il 4% del costo e determinano l'adozione: un sistema bello che non viene usato è un costo fisso.

Come si decide in una settimana?

La scelta non richiede un progetto. Richiede cinque giorni di lavoro di una persona interna e un confronto con chi può consigliarti.

  • Giorno 1: l'orizzonte e i segnali. Scrivi per quanti anni deve servire il programma e conta quanti dei sette segnali si applicano. Annota la versione di Delphi, la tecnologia di accesso ai dati e dove vive l'ambiente di sviluppo.
  • Giorno 2: l'inventario. Elenca unit, maschere, report, componenti e tabelle. Per ogni maschera, scrivi chi la usa e con quale frequenza. Metti da parte quelle mai usate.
  • Giorno 3: le regole. Cerca le decisioni nel codice e nei trigger, e scrivi le prime dieci regole con un esempio ciascuna. Se il consulente collabora, fai questo giorno con lui.
  • Giorno 4: i minuti persi e il rischio. Per ogni utente, tre osservazioni in giornate diverse: quanto tempo perde in attese, doppie digitazioni, ricopiature. Moltiplica per 220 giorni e per il costo orario. Poi scrivi quanto tempo servirebbe a rimettere in piedi il programma se la persona sola sparisse.
  • Giorno 5: il confronto. Con questi numeri, chiedi un'offerta per l'aggiornamento e una per la migrazione a moduli, sulla stessa lista di moduli. Inserisci i valori nel modello e leggi i quattro scenari.

Il primo passo è sempre piccolo e annullabile. Se i segnali sono sul versante dell'ambiente (segnali 1, 2 e 4), è mettere il programma su una macchina ricostruibile e sostituire il BDE e i componenti senza sorgenti. Se il segnale più forte è la persona sola, è scrivere le regole e farle leggere a un secondo programmatore. Se il segnale più forte sono le richieste che il programma non sa soddisfare, è un primo modulo .NET su quel solo punto, in tre mesi.

Alla fine della settimana hai quattro cose che prima non avevi: un orizzonte in anni, un elenco di regole, una cifra di minuti persi e un valore del rischio. Con queste, la discussione non è più "Delphi sì o no", ma "quale riduce il costo e il rischio nei prossimi anni".

Che cosa farebbe oggi l'azienda di Brescia?

Torno allo stampaggio. Il titolare aveva una domanda e un consulente che parla di pensione. Con il conto in mano avrebbe visto che il "non fare niente" costa 44.045 euro l'anno fra manutenzione, minuti persi e fermi, che aggiornare Delphi costa meno della migrazione a otto anni, e che il pareggio della migrazione arriva a 7 anni solo dando un valore al rischio della persona sola.

Avrebbe quindi deciso in due tempi. Subito, circa 60 giornate: estrarre le 23 regole in un documento, mettere l'ambiente su una macchina ricostruibile, sostituire il BDE e i tre componenti senza sorgenti. Costa 25.200 euro, si ripaga in meno di tre anni e toglie il rischio più urgente. In parallelo, il primo modulo .NET su ordini e preventivi, perché è il punto dove l'azienda chiede più cambiamenti e dove un sistema nuovo restituisce valore visibile in pochi mesi. Con quel modulo in produzione, la decisione sul resto si prende con minuti recuperati misurati e non stimati.

La migrazione completa a .NET, 191.100 euro, diventa la scelta giusta se l'azienda pensa di restare con lo stesso gestionale per dieci anni o più, se i clienti chiedono accesso web e collegamenti in tempo reale, o se il consulente smette prima del previsto. Non è la scelta giusta se il motivo è "Delphi è vecchio": quel motivo, da solo, non è un numero.

In ogni caso avrebbe deciso con un numero e non con la simpatia di un venditore, e avrebbe ancora aperta la strada giusta fra due anni. È questa la differenza, e vale più dell'esito.

Se hai un programma Delphi e vuoi sapere in quale zona cade la tua azienda, il percorso comincia dalla pagina sulla modernizzazione del software legacy, che include anche i casi in cui la risposta è non toccare niente. Se il punto di partenza è un file Access e non Delphi, la guida a sostituire Access con un gestionale fa lo stesso conto. E se ti serve una persona che guardi i numeri con te, c'è la consulenza software. Per chi ha anche applicazioni scritte con interfacce a oggetti e classi astratte, un buon punto di partenza per capire il codice da portare è la guida a interfacce e classi astratte, e per il lavoro in squadra sul codice la guida a Visual Studio e Team Foundation Server.

In cinque righe. Conta quanti dei sette segnali si applicano al tuo programma Delphi e dove vive l'ambiente di sviluppo. Estrai le regole dal codice e dai trigger prima di parlare con qualsiasi fornitore, perché sono il patrimonio che non si può perdere. Misura i minuti persi ogni giorno per utente: valgono 2.581 euro l'anno ciascuno con ventidue utenti. Dai un valore alla persona sola, perché è quello che sposta il pareggio da 10 anni e mezzo a 7. Aggiorna Delphi dove serve, e migra un modulo per volta dove il cambiamento o l'accesso da fuori lo giustificano.

Se il portale da modernizzare è scritto in ASP.NET WebForms, con ViewState pesante e nessuno che lo conosce più, il conto a cinque e a otto anni è in migrazione da ASP.NET WebForms a Core.

Se il programma da modernizzare è un gestionale scritto in Visual Basic 6, il conto a uno, tre, cinque e otto anni, con il ponte COM per sostituire un modulo per volta, è in migrazione da VB6 a .NET.

Domande frequenti

Per un gestionale con 22 utenti e 310.000 righe di codice, migrare a .NET un modulo per volta costa circa 191.100 euro (455 giornate), più 14.700 di doppio mantenimento. Riscrivere tutto costa 238.980 euro. Aggiornare Delphi a una versione corrente costa 25.200 euro (60 giornate).

A cinque anni aggiornare Delphi costa meno: 199.720 euro contro 294.013, e anche a otto anni 304.432 contro 346.941. La migrazione si giustifica con un orizzonte oltre 7-10 anni, componenti senza sorgenti, richieste di accesso web o il rischio di una persona sola, che vale 8.448 euro l'anno nel caso descritto.

No: esiste una versione corrente, aggiornata ogni anno. Il rischio non riguarda il linguaggio ma il singolo programma: la versione vecchia, l'accesso ai dati senza futuro (come il BDE), i componenti senza sorgenti e una persona sola che conosce il codice.

Con lo strangler fig: un guscio .NET si affianca a Delphi, il database resta condiviso e un modulo per volta sostituisce il corrispondente di Delphi. Ogni modulo va in produzione da solo, con una settimana di parallelo su due utenti pilota. Nel caso descritto servono 14 mesi.

Tre: le date sono numeri (TDateTime conta i giorni dal 30 dicembre 1899), gli importi sono spesso in virgola mobile e l'arrotondamento cambia, il testo dipende dal set di caratteri del database. Si risolve con uno strato che converte tutto in un punto solo.

Si sostituiscono prima che si rompano: con un successore dello stesso produttore, con una libreria standard o, se parlano con una macchina, riscrivendo il protocollo in poche centinaia di righe. Nel caso descritto erano 14 componenti, 3 senza sorgenti, per 14 giornate.

Lascia i tuoi dati nel form qui sotto

Matteo Migliore

Matteo Migliore è un imprenditore e architetto software con oltre 27 anni di esperienza nello sviluppo di soluzioni basate su .NET e nell'evoluzione di architetture applicative per imprese e organizzazioni di alto profilo.

Nel corso della sua carriera ha collaborato con realtà come Cotonella, Il Sole 24 Ore, FIAT e NATO, guidando team nello sviluppo di piattaforme scalabili e modernizzando ecosistemi legacy complessi.

Ha formato centinaia di sviluppatori e affiancato aziende di ogni dimensione nel trasformare il software in un vantaggio competitivo, riducendo il debito tecnico e portando risultati concreti in tempi misurabili.

Stai leggendo perché vuoi smettere di rattoppare software fragile.Scopri il metodo per progettare sistemi che reggono nel tempo.