Quanto costa la migrazione da VB6 a .NET?
La scelta si fa su tre numeri: i minuti persi ogni giorno (3.168 euro l'anno ciascuno con 27 utenti), gli anni di vita richiesti e il costo di un fermo.

Un produttore di serramenti in provincia di Treviso, 64 dipendenti e 22 milioni di fatturato, gestisce preventivi, ordini, distinte base, magazzino e produzione con un programma scritto in Visual Basic 6 nel 2003. Lo usano 27 persone: ufficio tecnico, commerciale, magazzino e due capireparto. Gira su sei PC e su un server Terminal, con un database SQL Server 2008 R2 che Microsoft non aggiorna più da anni. Chi lo ha scritto è il socio fondatore di una piccola software house, oggi ha 68 anni e risponde al telefono quando ha voglia. Il titolare ha una sola domanda: conviene fare la migrazione da VB6 a .NET, oppure continuiamo così finché regge?
Le risposte che girano sono due, entrambe scomode. La prima dice che VB6 è morto e va riscritto tutto: la dice chi vende riscritture. La seconda dice che funziona da vent'anni e quindi non si tocca: la dice chi non vuole spendere o chi non vuole decidere. La verità sta in mezzo e si calcola. Il runtime di VB6 continua a funzionare su Windows 11, quindi il programma non smette da solo. Quello che smette è tutto il resto: lo strumento per modificarlo, i componenti di terzi, il database sotto, le persone che lo conoscono. Il problema non è la data di scadenza di un linguaggio. È quanto costa ogni anno restare fermi e quanto costa muoversi.
Con il caso del Veneto, che è composto e non di un cliente reale, vedrai come si misura il conto in una settimana. Il risultato sorprende chi si aspetta che io venda una migrazione: per un orizzonte sotto gli otto anni la strada più economica è mettere in sicurezza il VB6 con 18.900 euro di lavoro, che si ripagano in dieci mesi. La migrazione a moduli in C# diventa la scelta più economica dal quasi ottavo anno, e prima solo se gli utenti sono molti o se un fermo costa tanto. Il punto di pareggio sta a 7,8 anni e cambia con quattro numeri che ti mostro uno per uno.
Trovi i sette segnali che dicono che il programma è a rischio, l'inventario di che cosa contiene davvero, la risposta onesta alla domanda sulla conversione automatica, le cinque strade con i loro costi, il conto a uno, tre, cinque e otto anni, il modo di sostituire un modulo per volta con un ponte COM fra il vecchio e il nuovo, i problemi di valuta, arrotondamenti e valori nulli che fanno sbagliare i conti, i guai che fanno saltare le stime e gli errori che ho visto ripetersi in ventisei anni di progetti.
Una premessa onesta. Scrivo software dal 1999, ho costruito e venduto un gestionale legale multi-tenant e faccio anche questo tipo di lavoro, quindi so da che parte sta il mio interesse. Il caso è composto, le ipotesi sono scritte una per una e il risultato include l'ipotesi in cui non conviene migrare né da me né da nessun altro. Un consiglio che non dice quando non spendere vale poco.
Quando serve una migrazione da VB6 a .NET?
Un programma VB6 che funziona non è un problema da risolvere domani. 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. Nessuno può più modificarlo con strumenti supportati
L'ambiente di sviluppo di VB6 è fuori supporto dal 2008. Il runtime, cioè quello che serve a eseguire il programma, è invece garantito da Microsoft insieme a Windows 11. È una differenza che si dimentica: il programma gira, ma ogni modifica si fa con un installatore del 1998 su un PC che nessuno osa reinstallare. Nel caso del Veneto l'unico PC con l'ambiente funzionante è un portatile del 2014 nel cassetto del titolare.
2. Il programma lo conosce una persona sola, o nessuna
È il segnale più serio e il meno discusso. Trecentodieci maschere, scritte in vent'anni da quattro persone, con la logica nel codice delle maschere e nelle stored procedure, sono conoscenza che vive in una testa. Se quella testa smette di rispondere, l'azienda non perde un programma: perde la possibilità di cambiare il proprio modo di vendere.
3. Il database sotto è fuori supporto
SQL Server 2008 R2 non riceve aggiornamenti di sicurezza da molti anni. Se il programma ci sta attaccato con una vecchia libreria di accesso ai dati, aggiornare il database significa verificare ogni query. Questo vincolo è nascosto: nessuno lo vede finché un audit o un assicuratore non lo chiede.
4. I componenti di terzi sono introvabili
Un programma VB6 di vent'anni contiene componenti OCX comprati nel 2003: griglie, calendari, grafici, lettori di codici a barre. Molti produttori non esistono più, e le versioni a 32 bit non si installano più con facilità su macchine nuove. Se un componente si rompe, non c'è nessuno a cui chiedere.
5. Il programma non parla con niente di nuovo
Il collegamento con la contabilità, con il corriere, con la banca, con il cliente della grande distribuzione che chiede i dati in formato EDI: ciascuno è un file di testo copiato a mano o un lavoro notturno. Quando un cliente chiede i dati in tempo reale, il programma non sa darli. È qui che il costo del "non fare niente" si trasforma in una commessa persa.
6. Le macchine nuove non lo vogliono
VB6 è a 32 bit, e produce programmi a 32 bit. Su un PC nuovo con Windows 11 il programma parte, ma le stampanti, i lettori di codici e i driver nuovi non sempre collaborano, e ogni sostituzione di un PC diventa un piccolo progetto.
7. Il lavoro quotidiano costa troppi minuti
Quattordici minuti persi ogni giorno a persona fra attese, ricopiature, telefonate al collega che sa dove sta un dato e fogli di calcolo paralleli. È il segnale che si misura meno e che pesa di più, e lo vedremo con la cifra.
Nel caso del Veneto i segnali veri sono sei su sette: l'ambiente di sviluppo, la persona sola, il database, i componenti introvabili, le integrazioni a stampella e i minuti persi. 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 gestionale VB6?
Prima di scegliere una strada serve un inventario, perché il prezzo di qualunque soluzione dipende da quello che c'è dentro, e di solito chi decide descrive solo quello che vede. Un programma VB6 contiene sei tipi di cose, e ciascuna si sostituisce in modo diverso.
- Maschere: i file
.frmcon il loro codice. Le maschere si ridisegnano, il codice si legge per capire che cosa decide. - Moduli e classi: i file
.base.clsdove di solito stanno i calcoli, ma anche variabili globali che le maschere si passano a vicenda. - Componenti di terzi: i controlli
.ocxe le librerie.dllregistrate nel sistema. - Accesso ai dati: ADO o DAO, query scritte dentro il codice, a volte logica dentro le stored procedure.
- Stampe: Crystal Reports di una versione vecchia, o report del Data Report Designer di VB6.
- Regole: sconti per cliente, minimi d'ordine, arrotondamenti, scorte riservate. Sono il vero patrimonio e sono scritte solo nel codice.
Nel caso del Veneto l'inventario, fatto leggendo il progetto in tre giorni, dà questi numeri.
| Elemento | Quantità | Che cosa significa per il costo |
|---|---|---|
| Maschere .frm | 310 | 74 usate ogni giorno, 96 una volta al mese, 140 mai: queste ultime non si migrano |
| Moduli e classi | 88 | Dentro ci sono 41 variabili globali che le maschere usano per parlarsi |
| Componenti OCX e DLL | 14 | 5 di terzi, di cui 2 con produttore sparito |
| Report Crystal | 96 | 31 usati davvero, 14 sono documenti per i clienti e vanno rifatti con cura |
| Procedure e viste nel database | 142 | In 27 c'è logica che il codice dà per scontata |
| Integrazioni | 7 | Contabilità, EDI di un cliente, macchina di taglio, corriere, banca, fatture elettroniche, posta |
| Test automatici | 0 | Il comportamento va catturato prima di toccarlo |
La riga più importante è quella delle maschere mai usate: 140 su 310. Quasi metà del programma non esiste nel conto, perché nessuno la apre da anni. Questo da solo abbassa il preventivo di una riscrittura più di qualsiasi negoziazione, e si scopre solo con i registri di accesso, non chiedendo agli utenti.
Un'altra riga da non saltare è quella delle variabili globali. Quarantuno variabili che le maschere si passano a vicenda sono lo stato nascosto del programma. Chi lo ricostruisce deve decidere dove vive ciascuna, e ognuna è un punto in cui il nuovo può comportarsi in modo diverso dal vecchio senza che nessuno se ne accorga.
Si può convertire automaticamente VB6 in VB.NET o C#?
Si può, con un risultato che non è quello che si spera. Esistono strumenti commerciali di conversione che leggono il progetto VB6 e producono un progetto VB.NET che compila. Il vecchio assistente di Microsoft, quello integrato in Visual Studio fino alla versione 2008, non esiste più nelle versioni recenti. Gli strumenti di terzi fanno meglio, ma restano due problemi che nessun programma risolve.
Il primo è che il codice prodotto è VB6 scritto in sintassi .NET. Porta con sé una libreria di compatibilità, le stesse variabili globali, la stessa struttura a maschere con il codice dentro. Compila, gira, e ha tutti i difetti di prima. Chi lo deve mantenere trova un programma che nessun sviluppatore .NET riconosce come proprio.
Il secondo è più sottile: dove il comportamento di VB6 e quello di .NET differiscono, il convertitore non sempre lo sa. Il tipo Currency di VB6 non è il decimal di .NET, il Variant con un valore nullo non si comporta come un tipo nullo, Format(2,5; "0") arrotonda in un modo e CInt(2,5) in un altro. Il programma converte e il calcolo cambia di un centesimo su un caso ogni mille. Lo scopri a fine mese, con l'ufficio amministrativo.
| Che cosa fa la conversione automatica | Che cosa non fa |
|---|---|
| Porta il progetto fuori da VB6 e dal suo ambiente di sviluppo | Non toglie le variabili globali e la logica dentro le maschere |
| Produce un programma a 64 bit possibile, con componenti sostituiti | Non sostituisce da sola gli OCX di terzi senza futuro |
| Costa meno di una riscrittura, anche se non poco | Non riduce i minuti persi: l'interfaccia è la stessa |
| Dà un punto di partenza per i test | Non scrive i test e non scopre le differenze di calcolo |
La conversione ha un posto, ed è un posto preciso: quando il programma deve vivere pochi anni, deve uscire dall'ambiente VB6 e l'interfaccia va bene così com'è. Nel conto che segue la chiameremo strada C, e vedrai che nessun orizzonte la rende la più economica. Resta il modo in cui la sceglie chi vuole togliersi un problema di mantenibilità senza toccare l'uso quotidiano.
Quanto costa la migrazione da VB6 a .NET rispetto a non farla?
Per rispondere servono cinque strade a confronto, con le stesse ipotesi. Il modello è in euro e si può rifare con i tuoi numeri. Le ipotesi del caso sono queste.
- Costo medio di una giornata di sviluppo: 420 euro. 220 giornate lavorative l'anno e 32 euro l'ora per il costo di un utente interno.
- Utenti: 27. Ogni minuto perso al giorno per ognuno vale 27 × 220 ÷ 60 × 32 = 3.168 euro l'anno.
- Un fermo del programma di una settimana costa 180.000 euro fra produzione bloccata, ritardi sulle consegne e penali. È la stima più incerta, e la discutiamo fra poco.
- Ogni strada ha un costo annuo di gestione: minuti persi, probabilità di fermo e giornate di assistenza.
A. Non fare niente
Quattordici minuti persi per utente al giorno valgono 44.352 euro l'anno. La probabilità di un fermo grave l'anno, con un ambiente di sviluppo che nessuno riesce a rimettere in piedi, è del 15%: 27.000 euro. Le giornate di assistenza di un consulente che ogni volta deve ricostruire il contesto sono 18, cioè 7.560 euro. Totale: 78.912 euro l'anno, senza spendere un euro di progetto.
B. Mettere in sicurezza il VB6
Quarantacinque giornate, 18.900 euro. Si fa un ambiente di sviluppo ricostruibile in una macchina virtuale documentata, si mettono i sorgenti nel controllo di versione (per chi parte da una cartella condivisa, la guida al controllo del codice sorgente con Visual Studio e Team Foundation Server spiega i concetti), si sostituiscono i due OCX di produttori spariti, si porta il database su una versione supportata di SQL Server verificando le query, si scrivono i test sulle 30 regole che muovono i soldi e si fa un backup che si ripristina davvero. Dopo, i minuti persi scendono da 14 a 12 e la probabilità di fermo da 15% a 6%. Il costo annuo diventa 54.696 euro.
C. Conversione automatica a VB.NET
Centosessanta giornate più 6.000 euro di strumento: 73.200 euro. Si ottiene un programma VB.NET che gira in 64 bit, senza ambiente VB6. L'interfaccia è la stessa, quindi i minuti persi restano 12. La probabilità di fermo scende al 3%. Costo annuo: 48.456 euro.
D. Migrazione a moduli in C#
Cinquecentoventi giornate, 218.400 euro, più 12.600 di doppio mantenimento: 231.000 euro in ventidue mesi. Un modulo per volta passa in C# con un ponte COM e lo stesso database, e ogni modulo esce da solo. Nei primi due anni il costo di gestione è quello della strada B, perché la messa in sicurezza fa parte del lavoro. Dopo, i minuti persi scendono a 4, il fermo al 2% e le giornate di assistenza a 4: 17.952 euro l'anno.
E. Riscrittura completa
Seicentoquaranta giornate, 268.800 euro. Il vecchio resta in mano finché il nuovo non è pronto, e il rischio è che non arrivi mai a coprire tutto. A regime costa quanto la D, ma ci arriva con più spesa e con un solo grande rilascio.
| Strada | Spesa iniziale | Costo annuo a regime | Che cosa cambia per l'utente |
|---|---|---|---|
| A. Non fare niente | 0 | 78.912 | Niente |
| B. Mettere in sicurezza | 18.900 | 54.696 | Poco: meno fermi e 2 minuti recuperati |
| C. Conversione automatica | 73.200 | 48.456 | Niente di visibile |
| D. Migrazione a moduli | 231.000 | 17.952 | Maschere nuove un modulo per volta, 10 minuti recuperati |
| E. Riscrittura completa | 268.800 | 17.952 | Tutto nuovo in una volta, dopo due anni |
Il modello è semplice di proposito: la forma conta più della precisione al centesimo. Per chi pensa di partire da zero con un software su misura, il conto con le voci del preventivo è in quanto costa un software gestionale su misura.
Dopo quanti anni conviene migrare VB6 a .NET?
Il costo di una strada non è la sua spesa iniziale: è quello che hai pagato dopo un certo numero di anni. Mettendo insieme spesa iniziale e costo annuo, il costo cumulato nelle cinque strade è questo.
| Orizzonte | A. Niente | B. Sicurezza | C. Conversione | D. Moduli in C# | E. Riscrittura |
|---|---|---|---|---|---|
| 1 anno | 78.912 | 73.596 | 121.656 | 285.696 | 323.496 |
| 3 anni | 236.736 | 182.988 | 218.568 | 358.344 | 396.144 |
| 5 anni | 394.560 | 292.380 | 315.480 | 394.248 | 432.048 |
| 8 anni | 631.296 | 456.468 | 460.848 | 448.104 | 485.904 |
I pareggi sono quattro numeri.
- Mettere in sicurezza contro non fare niente: si ripaga in 0,8 anni, circa dieci mesi. È l'unico intervento la cui convenienza non dipende da niente.
- Migrare contro non fare niente: si ripaga in 5,0 anni.
- Migrare contro mettere in sicurezza: si ripaga in 7,8 anni. Se il programma deve servire meno di otto anni, si mette in sicurezza e basta. Se deve servirne dieci, si migra.
- Riscrivere contro migrare a moduli: non si pareggia mai. La riscrittura costa 37.800 euro in più e porta allo stesso costo a regime.
Il grafico mostra le cinque linee: le curve di D ed E partono molto più in alto ma crescono più piano.

La conversione automatica non vince mai: a due anni e mezzo supera "non fare niente", ma resta sopra la messa in sicurezza fino a quasi nove anni, e a quel punto la migrazione a moduli costa già meno. È la strada che spende molto e cambia poco, e questo è il motivo per cui la consiglio di rado.
Che cosa sposta il pareggio
Il numero 7,8 non è una legge, è il risultato di quelle ipotesi. Cambiandone una alla volta, ecco che cosa succede al pareggio fra mettere in sicurezza e migrare.
| Se cambia... | Il pareggio fra sicurezza e migrazione diventa |
|---|---|
| Gli utenti scendono da 27 a 12 | 11,4 anni |
| Gli utenti salgono da 27 a 50 | 5,6 anni |
| Un fermo costa 400.000 euro invece di 180.000 | 6,7 anni |
| Un fermo non costa niente | 9,2 anni |
| La migrazione costa 400 giornate invece di 520 | 6,4 anni |
| La migrazione costa 680 giornate | 9,6 anni |
| Dopo la migrazione restano 8 minuti persi invece di 4 | 10,8 anni |
| Anche dopo la messa in sicurezza il rischio di fermo resta al 12% | 6,5 anni |
L'osservazione che conta è che due numeri pesano più di tutto il resto: i minuti che si recuperano davvero e il costo di un fermo. Un programma usato da dodici persone non si migra per convenienza, si mette in sicurezza. Un programma usato da cinquanta persone, in un'azienda dove un fermo ferma la produzione, si migra anche a un orizzonte breve. E se i minuti persi dopo la migrazione non scendono davvero, tutto il conto cade: il numero da difendere in progetto è questo, non la data di consegna.
Se vuoi un confronto più largo fra sostituire e ripulire il codice, la guida su riscrivere o rifattorizzare il software legacy mette le due scelte sullo stesso piano. E se il tuo caso richiede un intervento sul sistema nel suo insieme, il percorso sta nella pagina sulla modernizzazione del software legacy.
Come si migra VB6 a .NET senza fermare l'azienda?
Il metodo si chiama strangler fig: si costruisce il nuovo intorno al vecchio, un modulo alla volta, finché il vecchio non serve più e si spegne. La guida al pattern strangler fig spiega perché e quando funziona. Per un programma desktop VB6 l'ostacolo non è un proxy in rete, come nei portali web, ma il fatto che la maschera vecchia e quella nuova devono convivere sullo stesso computer e condividere calcoli e dati.
La soluzione tecnica è COM, la stessa tecnologia con cui VB6 parla con i suoi componenti. Il nuovo codice in C# si compila come una libreria che il VB6 vede come un componente qualsiasi. Il VB6 lo chiama con CreateObject, senza sapere che sotto c'è .NET 10. L'architettura è questa.

1. La libreria COM nuova, a 32 bit
Il VB6 è a 32 bit, quindi la libreria nuova va compilata a 32 bit anche se il resto del mondo è a 64. È un dettaglio che fa perdere una giornata a chi non lo sa. Il progetto si dichiara così.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0-windows</TargetFramework>
<PlatformTarget>x86</PlatformTarget>
<EnableComHosting>true</EnableComHosting>
<EnableRegFreeCom>true</EnableRegFreeCom>
</PropertyGroup>
</Project>Il file prodotto ha un'estensione .comhost.dll e si registra una volta sola con regsvr32, oppure si usa il manifesto senza registrazione per non toccare il registro del PC. Dentro la libreria stanno le regole di calcolo, scritte una volta e usate da tutti.
using System.Runtime.InteropServices;
namespace Serramenti.Servizi;
[ComVisible(true)]
[Guid("5B1B7C3E-2D44-4C0A-9A66-0B7F2E5E8A11")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IPrezzi
{
// Currency di VB6 arriva come decimal: nessuna perdita di precisione.
decimal PrezzoRiga(string codiceArticolo, decimal quantita, string codiceCliente);
}
[ComVisible(true)]
[Guid("A7D0F6C2-91B3-4E8D-B2C4-6F4E3D1A9C07")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Serramenti.Prezzi")]
public sealed class Prezzi : IPrezzi
{
public decimal PrezzoRiga(string codiceArticolo, decimal quantita, string codiceCliente)
{
var listino = Listini.Corrente(codiceArticolo);
var sconto = ScontiCliente.Percentuale(codiceCliente, codiceArticolo);
var riga = listino * quantita * (1 - sconto);
// Il VB6 arrotondava con la regola del banchiere: lo stato di fatto si conserva.
return Math.Round(riga, 2, MidpointRounding.ToEven);
}
}Dal lato VB6 la modifica è di una riga. Dove prima c'era il calcolo scritto nella maschera, adesso c'è la chiamata.
' Prima: il calcolo stava nella maschera, in 140 righe.
' Dopo: la maschera chiede il prezzo al servizio condiviso.
Dim prezzi As Object
Set prezzi = CreateObject("Serramenti.Prezzi")
txtImporto.Text = Format(prezzi.PrezzoRiga(txtArticolo.Text, CDec(txtQta.Text), cboCliente.Value), "#,##0.00")Il passo ha due effetti. Il calcolo esce dal VB6, quindi lo scrive e lo testa una persona che lavora con strumenti moderni. E la nuova maschera in C# che arriverà fra qualche mese userà la stessa identica funzione, per cui il vecchio e il nuovo non possono più divergere sui prezzi.
2. Il database resta uno
Non si copia il database e non si fa una sincronizzazione. Vecchio e nuovo leggono e scrivono le stesse tabelle, che è la ragione per cui il passaggio si può fare un modulo alla volta. Il prezzo è una regola rigida: per ogni tabella c'è un solo scrittore, o il vecchio o il nuovo. Quando un modulo passa, passa con le sue tabelle, e il vecchio da quel momento le legge soltanto.
3. Il primo modulo è una consultazione
Si comincia da un modulo che mostra dati e non ne scrive, per esempio la ricerca articoli o la scheda cliente. Prova il ponte con poco rischio e dà agli utenti un risultato visibile. Se sbaglia, si torna indietro cambiando una riga di menu.
4. L'interfaccia nuova
Le maschere nuove si scrivono in WinForms o in WPF. Per un gestionale con molte griglie e molti campi, WinForms su .NET 10 è una scelta sensata e veloce da imparare per chi viene da VB6. Se l'azienda vuole un'interfaccia più curata, i trigger in WPF mostrano come si rende un'interfaccia reattiva senza riempirla di codice. Per la decisione fra tenere, portare e riscrivere un programma Windows Forms, ho scritto un confronto a parte in Windows Forms nel 2026.
5. L'ordine dei moduli
Si comincia dai moduli a basso rischio che mostrano un valore visibile, non da quelli più importanti. Un buon ordine, nel caso del Veneto, è questo.
| Mese | Modulo | Che cosa si ottiene |
|---|---|---|
| 1-3 | Messa in sicurezza, libreria COM, test sulle 30 regole critiche | Il programma è invariato, ma ora si può spostare un modulo |
| 4-6 | Anagrafiche e ricerca articoli | Le ricerche passano da 6 secondi a meno di uno |
| 7-10 | Preventivi e prezzi | Un solo calcolo del prezzo, scritto una volta e provato |
| 11-14 | Ordini e distinte base | L'area più complessa, in parallelo di due settimane con due utenti pilota |
| 15-18 | Magazzino e produzione | Il collegamento in tempo reale con la macchina di taglio |
| 19-21 | Stampe, integrazioni residue, contabilità | Si toglie l'ultimo motivo per tenere il vecchio |
| 22 | Spegnimento del VB6 | Si rimuove il rischio che si portava dietro |
Per un programma di queste dimensioni servono ventidue mesi, e ogni trimestre qualcosa cambia per gli utenti. La differenza con la riscrittura non è la durata, è il fatto che dal quarto mese ogni modulo rende da solo, e che se il progetto si ferma al ventesimo mese l'azienda ha comunque venti mesi di valore.
Come si portano calcoli e dati senza cambiare un centesimo?
Il pericolo più concreto di una migrazione da VB6 non è che il programma non parta. È che parta e che un totale sia diverso di un centesimo. L'ufficio amministrativo lo scopre a fine mese e da quel momento non si fida più del nuovo. Ci sono quattro differenze che ho visto fare danni, e vanno scritte in un test prima di toccare qualunque cosa.
Currency non è decimal, ma ci si avvicina
Il tipo Currency di VB6 è un intero a 64 bit diviso per diecimila: quattro decimali esatti, senza errori di virgola mobile. Il Double invece sbaglia, e un programma che somma importi in Double accumula errori che il vecchio nascondeva con un arrotondamento finale. In C# la scelta giusta è sempre decimal. Il rischio è doppio: dove il vecchio usava Double e arrotondava, il nuovo deve fare la stessa cosa, anche se è "sbagliato".
L'arrotondamento non è uno solo
In VB6 Round e CInt arrotondano al pari più vicino, la regola del banchiere: 2,5 diventa 2 e 3,5 diventa 4. Format invece arrotonda mezzo in su: Format(2,5; "0") dà 3. Un programma scritto in vent'anni usa le due cose in punti diversi, e il totale di una fattura dipende da quale delle due è stata usata. In C# Math.Round usa per impostazione predefinita la regola del banchiere, e per avere il mezzo in su si passa MidpointRounding.AwayFromZero. La scelta si fa riga per riga, guardando che cosa faceva il vecchio.
Null non è vuoto
Una colonna del database che vale NULL arriva in un Variant VB6 come valore nullo, che propagato in un calcolo dà nullo, mentre in molti punti il programma lo trattava come zero con IIf(IsNull(x), 0, x). In C# una colonna nullable non diventa zero da sola. Ogni punto in cui il vecchio faceva questa conversione implicita è una regola che qualcuno deve aver deciso e nessuno ha scritto.
Date, stringhe e il fuso che non c'era
Il tipo Date di VB6 non ha fuso orario e non distingue data da ora. Le stringhe a lunghezza fissa del vecchio formato di file riempiono di spazi. Il carattere di conversione dei file di testo è ANSI, non Unicode. Sono differenze minime e ciascuna è un file di integrazione che smette di essere letto dalla macchina di taglio.
La cura è sempre la stessa: si scrive un test sul comportamento del vecchio e si riesegue sul nuovo. Un test sul prezzo di una riga, con i tre arrotondamenti messi in fila, è questo.
using Xunit;
public class PrezziTest
{
// I valori attesi sono quelli che il programma VB6 ha prodotto in fattura,
// non quelli che sembrano giusti a una persona.
[Theory]
[InlineData("A-1042", 2.5, "C-0007", 187.50)]
[InlineData("A-1042", 3.5, "C-0007", 262.50)]
[InlineData("P-0310", 12, "C-0112", 1043.28)]
[InlineData("P-0310", 0.5, "C-0112", 43.47)]
public void IlNuovoPrezzoCoincideConQuelloDelVecchio(
string articolo, decimal quantita, string cliente, decimal atteso)
{
var prezzi = new Serramenti.Servizi.Prezzi();
Assert.Equal(atteso, prezzi.PrezzoRiga(articolo, quantita, cliente));
}
}I valori attesi si prendono dall'archivio: duecento righe di fatture reali degli ultimi dodici mesi, con articolo, quantità, cliente e importo. Si scelgono i casi di confine, quelli con sconti a cascata, quantità frazionarie e clienti con un listino speciale. Il test sul prezzo del caso del Veneto aveva 214 righe, e alla prima esecuzione ne ha fallite sei. Erano le sei regole che nessuno aveva mai scritto.
Quali sono i problemi che fanno saltare le stime?
Ogni stima di migrazione ha un margine di errore, e quasi tutto cade su sei problemi che si possono vedere in anticipo. Nel caso del Veneto valgono circa 90 giornate su 520.
1. I componenti OCX senza produttore
Due dei cinque componenti di terzi hanno un produttore sparito: la griglia con le colonne bloccate e il calendario di pianificazione. Non si portano, si sostituiscono, e la griglia è dentro 60 maschere. Una griglia di sostituzione non si comporta uguale e ogni differenza è un po' di formazione. Costo: 20 giornate.
2. Le stampe e i documenti dei clienti
Novantasei report, di cui 31 usati. Quattordici sono documenti che il cliente riceve, con il suo layout, il suo logo e le sue diciture di legge. Si rifanno con la cura di un'interfaccia, e vanno confrontati a video con l'originale. Costo: 22 giornate.
3. La logica nascosta nelle stored procedure
In 27 procedure su 142 c'è una regola che il codice dà per scontata: un blocco di credito, uno sconto, un'assegnazione di lotto. Nessuno la cita, e il giorno in cui il vecchio sparisce, la regola sparisce con lui. Costo: 18 giornate di lettura e di test.
4. Le integrazioni con file
Sette collegamenti, di cui tre con un file di testo a formato fisso che una macchina di taglio legge ogni quindici secondi. Il formato non si cambia, ogni carattere conta, e il nuovo deve produrlo identico. Costo: 15 giornate.
5. L'hardware e i driver
Il lettore di codici a barre in magazzino, le etichettatrici e un lettore di badge si collegano con driver a 32 bit scritti per VB6. Il nuovo li usa in un processo a 32 bit oppure li sostituisce. Costo: 8 giornate, o un acquisto.
6. Le variabili globali
Quarantuno variabili che le maschere si passano. Ognuna va letta, assegnata a un modulo e trasformata in un parametro esplicito. È un lavoro noioso e pieno di sorprese, perché la stessa variabile viene scritta in dieci punti. Costo: 7 giornate.
La somma è 90 giornate, il 17% del totale. È il motivo per cui nessun preventivo serio dà un prezzo a corpo prima dell'inventario, e per cui un preventivo che arriva in due ore dopo una telefonata è una cifra messa lì per vincere la gara.
Come si decide in una settimana?
Il percorso che uso con un cliente è sempre lo stesso, e si fa in cinque giorni di lavoro.
Giorno 1: l'orizzonte in anni
Una domanda sola al titolare: per quanti anni pensi di usare questo programma? Non "fino a quando funziona", ma un numero. Dieci anni e tre anni sono due progetti diversi. Se la risposta è tre, tutto il resto si semplifica: si mette in sicurezza e basta.
Giorno 2: il conteggio dei minuti
Si siede un'ora accanto a sei utenti e si annota ogni volta che aspettano, aggirano, ricopiano o telefonano per un dato che il programma non dà. Si cronometra. Il numero che esce, in minuti per utente al giorno, vale 3.168 euro l'anno per ogni minuto con 27 utenti. È il numero più sottovalutato del progetto, e di solito è il più alto.
Giorno 3: l'inventario
Lo scopo è la tabella vista sopra. Si contano maschere, moduli, componenti, report e procedure, si guarda quali maschere sono usate dai registri di accesso (non da quello che dice la gente) e si elencano integrazioni e variabili globali. Costa tre giorni se si parte da zero e uno se i registri ci sono già.
Giorno 4: le regole e il fermo
Si estraggono le regole di business dal codice e dalle procedure, si scrivono in italiano con un esempio numerico per ciascuna e le si fa leggere a chi lavora. Poi si fa una domanda scomoda: che cosa succede se il programma si ferma per una settimana? Si scrive la risposta in euro, con il direttore di produzione, non con l'informatico.
Giorno 5: il conto e la decisione
Con orizzonte, minuti, inventario, regole e costo del fermo si compila il confronto delle cinque strade. Se il pareggio fra mettere in sicurezza e migrare cade dopo l'orizzonte, si mette in sicurezza. Se cade prima, si migra, e si sceglie il primo modulo.
Alla fine hai cinque cose che prima non avevi: un orizzonte, una cifra di minuti persi, un elenco di regole, un valore del fermo e un inventario con i numeri. Con queste la discussione non è più "VB6 sì o no", ma "quale strada riduce il costo e il rischio nei prossimi anni".
Quali errori si ripetono nella migrazione da VB6?
In ventisei anni di progetti gli stessi errori tornano. Ne elenco otto, con il modo di evitarli.
- Cominciare dal modulo più importante. Si comincia da una consultazione, che prova il ponte con poco rischio.
- Scrivere il nuovo senza test sul vecchio. Se non sai che cosa fa il vecchio, non sai se il nuovo lo fa. I valori attesi si prendono dalle fatture vere.
- Copiare il database "per sicurezza". Due copie dello stesso dato divergono nel giro di una settimana. Uno scrittore per tabella, sempre.
- Migrare le maschere che nessuno usa. Sono il 45% delle maschere e zero del valore.
- Affidarsi solo alla conversione automatica. Dà un programma che compila e che nessuno sa mantenere, e lascia intatti i minuti persi.
- Cambiare l'interfaccia e i calcoli insieme. Se qualcosa non torna non sai se è colpa della maschera o della regola. Prima si sposta il calcolo, poi si ridisegna la maschera.
- Dimenticare l'hardware. I lettori di codici, le etichettatrici e le bilance sono il primo posto dove il nuovo si blocca.
- Non misurare il guadagno. Se non misuri i minuti persi prima e dopo, non puoi dimostrare che il progetto ha funzionato, né a te stesso né a chi paga.
Un altro errore, meno tecnico: decidere dal titolo di un articolo. Anche questo, compreso, mostra un caso composto. Il tuo programma ha un'altra curva, e l'unico modo per saperlo è mettere i tuoi numeri nella tabella.
Che cosa farebbe oggi l'azienda del Veneto?
Torno al produttore di serramenti. Il titolare aveva una domanda e un programmatore che risponde al telefono quando ha voglia. Con il conto in mano avrebbe visto che il "non fare niente" costa 78.912 euro l'anno, che mettere in sicurezza si ripaga in dieci mesi, e che la migrazione a moduli si ripaga rispetto alla messa in sicurezza in 7,8 anni.
Avrebbe deciso in due tempi. Subito, 45 giornate: ambiente di sviluppo ricostruibile, sorgenti nel controllo di versione, sostituzione dei due OCX senza produttore, database portato a una versione supportata, test sulle 30 regole che muovono i soldi, backup ripristinato davvero. Costa 18.900 euro, si ripaga in un anno e toglie il rischio più urgente. In parallelo, il ponte COM e il primo modulo, la ricerca articoli e le anagrafiche, perché sono le maschere più lente e quelle che i commerciali aprono di più. Con quel modulo in produzione, la decisione sul resto si prende con minuti recuperati misurati e non stimati.
La migrazione completa, 231.000 euro in ventidue mesi, diventa la scelta giusta se l'azienda pensa di tenere il programma per dieci anni, se gli utenti salgono verso cinquanta, se un fermo costa più di 400.000 euro o se il programmatore smette prima del previsto. Non è la scelta giusta se il motivo è "VB6 è 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 gestionale VB6 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. Per chi parte da altri linguaggi, il conto è in migrazione da Delphi a .NET e in migrazione da ASP.NET WebForms a Core, e se il punto di partenza è un database Access la guida è sostituire Access con un gestionale. Per i dettagli tecnici dell'accesso ai dati c'è anche la guida alla migrazione dei database da VB6 a .NET. E se ti serve una persona che guardi i numeri con te, c'è la consulenza software.
In cinque righe. Conta quanti dei sette segnali si applicano al tuo programma e da quanti anni nessuno lo conosce. Misura i minuti persi ogni giorno per utente: valgono 3.168 euro l'anno ciascuno con ventisette utenti. Metti in sicurezza prima di qualsiasi altra cosa: ambiente ricostruibile, sorgenti nel controllo di versione, backup che si ripristina. Estrai le regole dal codice e dalle procedure e scrivi i test sul vecchio prima di parlare con qualsiasi fornitore. Migra un modulo per volta con un ponte COM dove il numero di utenti, il costo di un fermo e l'orizzonte lo giustificano.
Domande frequenti
Per un gestionale con 27 utenti e 310 maschere, migrare a moduli in C# costa circa 231.000 euro (520 giornate, ventidue mesi). La riscrittura completa costa 268.800 euro, la conversione automatica 73.200 e mettere in sicurezza il VB6 18.900.
Si può con strumenti di terzi, ma il risultato è VB6 scritto in sintassi .NET: stesse variabili globali, stessa logica nelle maschere, stesse differenze di calcolo su Currency, arrotondamenti e valori nulli. Costa 73.200 euro nel caso descritto e non vince mai sugli altri orizzonti.
Sotto gli otto anni conviene metterlo in sicurezza: 18.900 euro che si ripagano in dieci mesi. Il pareggio fra mettere in sicurezza e migrare sta a 7,8 anni nel caso descritto e scende a 5,6 anni con cinquanta utenti.
Con un ponte COM: una libreria C# a 32 bit che il VB6 chiama con CreateObject, un solo database condiviso con un solo scrittore per tabella e un modulo alla volta, partendo da una consultazione. Nel caso descritto servono ventidue mesi.
Quattro: Currency contro decimal, l'arrotondamento (Round e CInt usano la regola del banchiere, Format arrotonda mezzo in su), i valori Null trattati come zero e le date senza fuso. Si scrivono test sul comportamento del vecchio e si rieseguono sul nuovo.
Sei: componenti OCX senza produttore, report e documenti dei clienti, logica nascosta nelle stored procedure, integrazioni con file a formato fisso, driver hardware a 32 bit e variabili globali. Nel caso descritto valgono circa 90 giornate su 520.
