Delphi to .NET migration: when it pays and what it costs
Matteo Migliore

Matteo Migliore is an entrepreneur and software architect with over 27 years of experience developing .NET-based solutions and evolving enterprise-grade application architectures.

He has led enterprise projects, trained hundreds of developers, and helped companies of all sizes simplify complexity by turning software into profit for their business.

A plastic injection moulding company near Brescia, 41 employees and 14 million in revenue, runs orders, warehouse, bills of materials, production and shipping on a program written in Delphi 7 in 2003. Twenty-two people use it every day. The program was written, and is still maintained, by a consultant who is now 61, works 30 days a year for the company and has said, quite honestly, that in five years he would like to stop. The owner has one question: is a Delphi to .NET migration worth it, or can we carry on as we are?

The answer usually sits between two extremes, both wrong. The first is "Delphi is dead, let's rewrite everything", said by those who sell rewrite projects. The second is "it has worked for twenty years, don't touch it", said by those who do not want to spend or to change. Delphi is not dead: a current version exists, updated every year, and programs of that kind can be kept alive for a long time. But the fact that a language is alive says nothing about that program, written in that version, with those components and one person who knows it.

The decision rests on three numbers that no quote writes down: how many minutes each user loses every day working around the program's limits, how many years it still has to serve, and what the risk of a single person is worth. With the Brescia case, composite and not a real client, you will see how to measure them in a week and what they say: at five years the cheapest road is updating Delphi, at eight years it still is, and migration is justified by reasons that are not the price.

You will find the seven signs that a Delphi program is at risk, an inventory of what it really contains, the four roads with their costs, the one, three, five and eight year bill, how to migrate one module at a time without stopping the company, a C# program that reads the old data without being fooled by Delphi's dates and amounts, the rules hidden in the code, and the mistakes I have seen repeated in twenty-six years of migrations.

An honest preface. I have written software since 1999 and built a multi-tenant legal management system, so I know which side my interest is on. The Brescia case is composite, the assumptions are written one by one and the result includes the case in which migrating does not pay, from me or from anyone else. Advice that does not tell you when not to spend is worth little.

When do you need a Delphi to .NET migration?

A Delphi program in good shape is not a problem. The problem is the set of conditions around it, and there are seven signs. With three or more we are in the zone where the risk starts to cost more than the change.

1. The development environment lives on a single machine

Delphi 7 dates from 2002. It is installed on an old computer or a virtual machine nobody dares to switch off, with an installer on a CD and a licence nobody can find. If that computer breaks, the company has the compiled program but can no longer change it. In Brescia the environment lives in a virtual machine on a 2017 server.

2. Data access uses a technology with no future

Many Delphi programs of those years talk to the database through the BDE, the Borland Database Engine, which does not exist in a 64-bit version and which Embarcadero has declared obsolete for many years. It works as long as 32-bit Windows works, and Windows 11 still runs it. The risk is not that it stops tomorrow, it is that every system update is a small bet and nobody can fix it if it breaks.

3. One person knows the program

It is the most serious sign and the least discussed. Three hundred thousand lines of code with no documentation and no tests, written over twenty years by one person, are knowledge that lives in one head. If that person falls ill, changes job or retires, the company loses the ability to change its own business, not just its software.

4. There are third-party components without source code

Grids, report generators, libraries for label printers and scales were often commercial components. Some vendors have closed or been absorbed, and the component exists only as a compiled file. In Brescia it is three out of fourteen. As long as the program stays 32-bit on the same Windows it works, but it can no longer be taken anywhere.

5. The database is old and fragile

Firebird 1.5, Interbase, Paradox or a DBF file do their job, but without security updates and with manual backups. In Brescia the database weighs 6.4 GB and the backup is a file copied at night to a USB disk by a clerk.

6. Integrations are all makeshifts

Electronic invoicing, customer portal, order exchange with an automotive customer, logistics labels: each was added with a text file, a script or a small separate program. Every new request from an important customer is another crutch. When a customer asks for a real-time link, the program cannot do it.

7. Nobody can use it outside the office

The program opens on a computer on the local network. To work from home, from a remote warehouse or from a phone, people use remote desktop or a VPN with all their flaws. It is not a defect of the language but of the way the program was born.

In Brescia five signs out of seven are real: the environment on a single machine, the single person, the components without source code, the crutch integrations and office-only access. With a result like that the question is not whether to think about it, but what to do and when. For the general picture of the cost of an old program, the guide to the cost of legacy software shows how to do the bill for the generic case.

What is really inside your Delphi program?

Before choosing a road you need an inventory, because the price of any solution depends on what is inside, and the owner usually describes only what he sees. A Delphi application contains five kinds of things, and each is replaced differently.

  • Units and forms: the Pascal code and the screens. Screens are redesigned, the code is read to understand what it decides.
  • Data access: queries scattered in the forms, data components and, at times, logic in the database triggers and procedures.
  • Reports: the printouts, meaning order confirmations, delivery notes, labels. They are what the final customer sees.
  • Third-party components: grids, report generators, drivers. Some have a modern equivalent, others do not.
  • Rules: discounts, blocks, rounding, lead time and batch calculations. They are the real asset, and they are written only in the code.

In the Brescia case the inventory, done by reading the project in four days, gives these numbers.

ItemQuantityWhat it means for the cost
Pascal units842 (310,000 lines)To be read in full to find the rules, at least by searching for decisions
Forms18752 used every day, 71 once a month, 64 never: the last ones are not migrated
Reports6419 are documents for customers and suppliers, to be redone with the same care
Firebird tables21234 with no writes for three years; 58 triggers and procedures with logic
Third-party components143 without source code, 2 from a closed vendor: to be replaced
Business rules in the code235 differ from today's practice

The number that weighs most is not the one that looks biggest. The 842 units are impressive, but the real work lies in the 52 forms used every day, the 23 rules and the 58 triggers that hide logic inside the database, where nobody looks. The 64 forms never opened are a saving: in almost every migration I have seen, 30-40% of the program has been useless for years and is carried along out of fear.

The third number to look at is third-party components. A grid that has a modern equivalent costs a few days of adaptation. A scale driver whose source code nobody has any more can mean rebuilding the link from scratch, sometimes by reading the protocol with a serial port analyser. Those three Brescia components alone are worth 14 days in the estimate, which you see below.

What are the four roads, and what do they buy?

The options are not "Delphi yes" or "Delphi no". There are four, and the first, which almost no quote writes down, is to do nothing.

Road 0: do nothing

The program stays as it is and keeps costing. In Brescia that is 30 days a year of consultant maintenance, 12,600 euros, plus the cost that appears in no budget: the users' lost minutes and the stoppages. I estimate it below, with a table. It is not a "free" road: it is the cheapest in the first year and the riskiest in the fifth.

Road A: update Delphi and stay on Delphi

The program is taken to a current version of Delphi, the BDE is replaced with modern data access, the code is converted to Unicode and the components without source code are changed. You get a program that compiles today, 64-bit if needed, with an environment that can be rebuilt. The way of working does not change, and there are no users to retrain.

The work costs 60 days: 14 for the move to Unicode and the new compiler, 20 to replace the BDE, 14 for the components without source code and 12 for tests. At 420 euros a day that is 25,200 euros. The fixed annual cost rises to 16,600 euros, that is 12,600 of maintenance plus 4,000 of licences for the environment and components.

The limit is that the dependence on one person remains, and that Delphi on Windows remains an office program: it does not become web or mobile. It is the road that buys time and order, not a new future.

Road B: migrate to .NET one module at a time (strangler fig)

A new .NET shell is placed next to the Delphi program, which keeps working. One module at a time is rewritten in .NET and replaces the corresponding Delphi one, until nothing of the old remains. The name, strangler fig, comes from the climbing plant that wraps a tree and slowly replaces it, and it is the way I use when the system cannot stop: I explain it in detail in the guide to the strangler fig pattern.

For Brescia the estimate is 455 days, that is 191,100 euros: 40 for inventory and rules, 45 for the data, 280 for the modules, 45 for tests and the parallel run, 25 for project management and 20 for training and launch. During the 14 months the old program still has to be maintained: 35 days, 14,700 euros. When it is done, the annual cost is 12,480 euros, that is 24 days of maintenance (10,080 euros) plus 2,400 euros of hosting.

Road C: rewrite everything from scratch

A new project that replaces the old one in a single day. For Brescia it is 569 days, 238,980 euros, with 18 months in which the old program lives in parallel (18,900 euros). It is the road rewrite suppliers love, because it is a big project. And it is the riskiest: for eighteen months no value is delivered, and on the day of the switch everything is discovered at once. The comparison of these two logics, and why the second loses more often, is in the guide to rewriting or refactoring.

A summary comparison, with the same assumptions.

A. Update DelphiB. Strangler to .NETC. Rewrite
Start-up cost25,200 euros191,100 euros238,980 euros
Double maintenance costnone14,700 euros18,900 euros
Fixed annual cost16,600 euros12,480 euros12,480 euros
Time to be in use2-3 months14 months, by modules18 months, all at once
Dependence on one personRemainsShrinks module after moduleShrinks, with the risk of switch day
Web and mobile accessNoYes, for the new modulesYes
When it makes senseYou need order and time, short horizonLong horizon, system that cannot stopAlmost never

If the path you need is the overall one, with decisions on the database, the code and the risks, you will find it on the page about legacy software modernisation, which includes the cases in which the answer is to touch nothing.

What does a Delphi to .NET migration cost against not doing it: the five and eight year bill

The start-up price tells you little. After five or eight years what weighs is the running cost, and an item no quote writes down: the minutes each user loses every day because the program does not do what is needed.

To turn them into euros three numbers are enough: 22 users, 220 working days and a company hourly cost of 32 euros. Each minute lost every day by each user is worth 22 x 220 / 60 x 32 = 2,581 euros a year. A half-day stoppage, with everyone stopped, is worth 4 hours x 22 users x 32 euros = 2,816 euros. How many are there in the Brescia case?

  • Do nothing: 10 minutes a day per user, between waiting, double entry and reports made in Excel because the program does not produce them. That makes 25,813 euros a year. Plus two stoppages a year, 5,632 euros, and maintenance, 12,600. In all 44,045 euros a year.
  • Update Delphi: 6 minutes, because most interface defects remain, and one stoppage a year. With 16,600 euros fixed it is 34,904 euros a year.
  • Migrate to .NET: 2 minutes, no stoppages, 12,480 euros fixed. That is 17,643 euros a year, once the migration is done.
  • Rewrite: the same as B at steady state, 17,643 euros a year.

The minutes are estimates and must be replaced with real measures, as I explain in the last part. But the structure of the bill holds: start-up cost, double maintenance cost, fixed annual cost and cost of lost minutes, added up over a chosen horizon.

HorizonDo nothingA. Update DelphiB. Strangler to .NETC. Rewrite
1 year44,045 euros60,104 euros223,443 euros275,523 euros
3 years132,136 euros129,912 euros258,728 euros310,808 euros
5 years220,227 euros199,720 euros294,013 euros346,093 euros
8 years352,363 euros304,432 euros346,941 euros399,021 euros
Cumulative cost over eight years of four ways to handle a Delphi management system with twenty-two users: do nothing, update Delphi, migrate to .NET one module at a time and rewrite everything

The result is less obvious than a salesperson would like, and should be read honestly. Updating Delphi costs less than migrating at 1, 3, 5 and even 8 years: 199,720 euros against 294,013 at five years, 304,432 against 346,941 at eight. The break-even between updating and migrating arrives only after about 10.5 years, because the starting gap is 180,600 euros and the annual saving of the migration is 17,261 euros. Updating Delphi, instead, pays back against doing nothing in under three years.

Whoever tells you migration "pays for itself" in three years is leaving something out, or has a much lower starting cost than yours, or a much worse system. A program whose lost minutes are hard to estimate is migrated for another reason too, which is not yet in the bill.

The risk of a single person, put into euros

The bill above treats the single person as an ordinary cost. It is not: it is a risk, and it can be given a value. Suppose the consultant stops, falls ill or cannot be reached, with a probability of 10% a year. In that case the company is left without maintenance for about three weeks, 15 working days, before finding someone who understands the program. With 22 users at reduced pace, the damage is 22 x 15 x 8 x 32 = 84,480 euros. The expected value is 8,448 euros a year.

That risk weighs on "do nothing" and on "update Delphi" (the person remains), and shrinks with the migration, where the code is documented, tested and written in a technology with millions of developers. Adding it, updating Delphi goes from 34,904 to 43,352 euros a year, and the break-even with migration drops from 10.5 to 7 years. With this assumption, over a ten-year horizon migration costs less than updating alone.

The 10% and the three weeks are assumptions, to be replaced with yours. The point is that the risk of a single person is countable, and putting it in the bill is better than leaving it in a sentence like "we depend on him".

Mind the limits: under ten users the lost minutes weigh less than half and migration almost never pays. Above forty, and with a process that is truly a competitive advantage, the bill changes in favour of B. For the logic of the costs of custom management software, with the thresholds, there is the guide to how much custom management software costs.

How to decide: three questions and a rule

The bill gives an order of magnitude. The decision is made with three questions, in the order in which they reduce risk.

Question 1: how many years does it have to serve?

If the answer is "I don't know", that is already information. Write three numbers: minimum, likely and maximum. A company that expects to move or be sold in three years has no reason to build anything. A company that will still be here in ten years with the same way of working has reason to consider a new system, because it is on the long horizon that migration recovers.

Question 2: is the single person a risk you can accept?

A simple test: if tomorrow that person stops answering the phone, how long does it take to get another person up to speed? If the answer is "months", the risk has a price, and it is the 84,480 euros from before. If the program is documented and another Delphi programmer would understand it in a few weeks, the risk is lower and road A stays defensible for longer.

Question 3: where do the rules live today?

If they are written in a document or in the managers' heads, they can be carried into any system. If they are in the Pascal code and the triggers and only there, the first expense is not the new system but the extraction of the rules, and that is done in any case. There is no road without this step, and it is better done before talking to suppliers.

The rule

SituationRoad
Horizon under 3 years, or company for saleDo nothing, or only what is needed for a rebuildable environment
Horizon between 3 and 7 years, single person but documentableUpdate Delphi (A) and write the rules down
Horizon beyond 7-10 years, components without source code, web access requestsStrangler to .NET (B), by modules
More than 40 users and a process that is the company's advantageStrangler to .NET, prioritising the modules of the advantage
Any case, with a project that cannot stop for 18 monthsNever the full rewrite (C)

For Brescia the advice is in two steps: update the broken points straight away, meaning extract the 23 rules, put the environment on a rebuildable machine and replace the three components without source code, and start the first .NET module in parallel on the point with the most requests for change, orders. The rest is decided after the first module, with a real number of recovered minutes.

If the choice falls on building, how you choose who writes it weighs as much as the choice itself: you will find the questions in the guide to how to choose a software house.

How the strangler fig works applied to Delphi

Migrating one module at a time is not an abstract idea. With Delphi it has three specific features, and it is worth knowing them before signing.

The database is shared, at least at the start

The old program and the new modules read and write the same Firebird database. Data is not copied back and forth: that would be the source of all problems. The .NET shell connects to the same database with an ADO.NET provider (the official one for Firebird exists) and goes through a single point, called an anti-corruption layer, which you see in the program below. Only at the end, when the last Delphi module is switched off, is the database migrated to a modern one, with the automatic reconciliation you know from the Access migration.

The new program launches the old one

The .NET shell has the login, the menu and the main window. For modules not yet migrated, it opens the corresponding Delphi form, as a separate executable to which it passes the user and the context, for example the selected customer. For the user there is one program. For you there is a migration index: each menu entry points to the old or the new, and is moved with one line of configuration.

The order of the modules is chosen with three criteria

You do not start from the simplest or the biggest. You start from where change is most frequent and risk is lowest, in this order.

  1. What changes most: in Brescia it is orders and quotes, where sales asks for a change every month. The benefit arrives straight away there.
  2. What is needed outside the office: web access for travelling salespeople and the customer portal. It is where Delphi cannot reach.
  3. What risks most: the module with the components without source code, for example the link with the scales. The piece that can break is removed first.

The rest, meaning master data, warehouse and bills of materials, follows the order of dependencies. Invoicing and accounting closings go last, because a mistake there has the highest cost and because they have more rules.

Order of migrating modules from Delphi to .NET over fourteen months: data and rules, shell and master data, orders and quotes, warehouse and bills of materials, production and shipping, invoicing and shutdown

The Brescia plan is 14 months with two developers and a part-time coordinator. In months 1-2 you do inventory, rules and data cleaning. In months 3-4 you build the shell and the master data. Months 5-7 are for orders and quotes, the first module with visible value. Months 8-10 for warehouse and bills of materials. Months 11-12 for production and shipping. Months 13-14 for invoicing, the final database migration and switching off Delphi.

The rule I have always kept: each module goes live on its own, with the old one available to go back by the evening. If a module is not ready, it does not block the others. And each module closes with a week of parallel run on two pilot users, because it is the only way to discover the rules nobody remembered. If the company also has a desktop interface to carry over, the comparison between keeping it, porting it or rewriting it is in the guide to Windows Forms in 2026.

How to read Delphi data without being fooled

The data of a Delphi program hides three oddities that produce silent errors, the kind discovered three months later, and it is worth knowing them before writing a line.

  • Dates are numbers: Delphi's TDateTime type is a decimal number counting days from 30 December 1899, with the hours as the fractional part. In .NET the same value is read with DateTime.FromOADate, but if someone treats it as an integer the time is lost, and if it is compared without conversion the dates are wrong by a century.
  • Amounts are floating point: many programs of those years save amounts as double numbers. A total of 10.005 euros becomes 10.0049999 and the rounding to the cent changes. Delphi's rounds the way the accountant expected, the .NET default is different: it must be specified on purpose.
  • Text depends on the character set: a database created without specifying it contains Windows-1252 bytes, and if the new program does not know it shows "perché" as "perché". The connection string states the column's character set, and a sample with accents is checked.

The solution is to put all this in one place: a layer that talks to the old database and hands the new code clean objects, with real dates and amounts in decimal. The program below is a reduced example. It works with any ADO.NET provider (you pass a DbConnection), compiles with .NET 10 and needs no packages beyond the provider's.

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)));
        }
    }
}

The code assumes that, in this database, order dates are saved as numbers, as happens in many programs of that period; if they are date-type columns, the conversion is not needed. The rest holds in any case: the new modules do not know Delphi, they only know Ordine. When the database is migrated, this class is rewritten and the rest of the program does not notice.

On the old database the first trial run in Brescia found 1,340 orders with a zero date, which Delphi showed as "30/12/1899" and which nobody had ever noticed because the program hid them with a filter. They are real data, and each must be decided with the customer: ignore, correct or keep as history.

The rules hidden in the Pascal code: how to extract them

This is the part that decides whether the migration succeeds. A Delphi application is not a set of forms: it is a set of forms and behaviours, and the behaviours live in the code and the triggers. Carrying the forms without the rules produces a system that seems to work and gives wrong numbers.

The method I use has four steps, and in Brescia it took eight days of work.

1. Search for decisions, do not read everything

Reading 310,000 lines is not possible. You search for the words that indicate a decision: if, case, messages to the user (ShowMessage, MessageDlg) and early exits (Abort, Exit). The Brescia project gave about 4,100 decision points, most of which are interface. To these you add the 58 triggers and database procedures, which are all read.

2. Classify every decision

Each condition falls into one of three categories: business rule (the discount, the block, the calculation), interface rule (the field that hides, the colour) and remedy for a limit (the check that avoids a component error). The first are carried over, the second are decided for the new system, the third usually disappear.

3. Write each rule as a sentence and an example

An example from Brescia. In the Pascal code there is this.

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 plain language it becomes: "Customers with at least three years of relationship and 80,000 euros of revenue in the last twelve months get a 4% discount, except on moulds. If they do not qualify for that, an order of at least five minimum batches gets 2%. Example: order of 12,000 euros from a customer with four years and 95,000 euros, discount 480 euros". A sentence and a case with numbers are what then lets you write a test and have the rule read by those who truly know it.

4. Have it confirmed by the people who work

The 23 rules were read aloud to sales, the warehouse and administration. Five differed from practice: the code did one thing, but the practice had changed years ago and nobody had touched the code. In one case, a block on customers with overdue payments, the program ignored it through a shortcut added in 2011 and nobody knew. It is the most valuable result of the inventory: the rules in the code are often different from the ones the company thinks it has.

The bonus of the operation is the test. Each rule written with its example becomes an automatic test, which from then on protects the new system from every change. The same method applies to any old desktop application: you will find it applied in the guide to migrating from VB6 to .NET, where the form-based architecture is very similar, and in the one on migrating from .NET Framework to .NET 10, for those starting from a program already written in .NET but old.

Third-party components without source code: what to do

It is the most annoying technical part, because it is not solved by reading code: the code is not there. There are four cases, and each has its solution.

The component has a successor. The grids and report generators of those years almost always have a modern equivalent, sometimes from the same vendor. You replace it, adapt the forms and the cost is a few days per component. In Brescia this is the case for 7 components out of 14.

The component can be replaced with a standard library. For example a component for generating PDF files or reading Excel files, today covered by widespread, maintained libraries. You write a small adapter and replace it. That is 4 components.

The component talks to a machine. A scale, a code reader, a label printer. There you do not look for a successor: you read the protocol, often a simple exchange of bytes over a serial or network port, and rewrite it in a few hundred lines. You keep the machine and throw away the component. That is 2 components, and the 14 days estimated are almost all for them, because you need the real machine in front of you to test.

The component does something nobody remembers the purpose of. It is more common than you would think. Before replacing it, you disable it in a copy and see what stops working. In Brescia an unknown component turned out to be the licence check of another program, and it was switched off.

The general rule: a component without source code is a debt with an unknown due date. It must be replaced before it breaks, when you work on the module that uses it, not on the day it stops working.

Which mistakes have I seen most often?

Delphi migrations go wrong in a few ways, always the same. I write them down because avoiding them is worth more than any technical choice.

Converting the Pascal code to C# with an automatic tool. Tools exist that translate line by line, and the result is a program that compiles and carries all of Delphi's habits: global variables, data access inside forms, no tests. The language has changed, the architecture has not. The debt remains, written in another syntax.

Trusting "the supplier will handle it". A migration supplier does not know your 23 rules. If you do not write them first, the forgotten ones emerge in the first three months as errors. The document of rules is yours, not the supplier's.

Migrating everything, including what is not needed. The 64 forms never opened do not go into the new system. Every element carried along costs days of testing and increases the surface of problems. Ask the users what they really use.

Forgetting the reports. Users say "management system" but think of documents: the order confirmation with its look, the label the customer scans. If the new system does not produce an equal or better document, it will look like a step back even if everything else works.

Migrating the data only once, at the end. It is the temptation of waterfall projects. If the data is tried only in the last month, the problems (the 1,340 zero dates from before) emerge when there is no time left. Data is migrated as a trial every two weeks, from the first month.

Skipping the parallel run out of haste. It costs a week of double entry for two people, about 2,560 euros. The errors it finds cost a multiple of that, and arrive when customers see them.

Keeping the single person as the only reference. The consultant who wrote the program must take part in the inventory, where his knowledge is valuable, and must do so with fair pay and the certainty of not being left out. A consultant who feels replaced delays, does not cooperate. But responsibility for the new system must sit somewhere that does not depend on one person, and the first thing written is the documentation.

Not planning training. Twenty-two people used to an interface for twenty years do not move to another in an afternoon. In Brescia the 20 days of training and launch are 4% of the cost and determine adoption: a beautiful system that is not used is a fixed cost.

How to decide in a week?

The choice does not require a project. It requires five days of work by an internal person and a conversation with someone who can advise you.

  • Day 1: horizon and signs. Write how many years the program has to serve and count how many of the seven signs apply. Note the Delphi version, the data access technology and where the development environment lives.
  • Day 2: the inventory. List units, forms, reports, components and tables. For each form, write who uses it and how often. Set aside those never used.
  • Day 3: the rules. Search for decisions in the code and triggers, and write the first ten rules with an example each. If the consultant cooperates, do this day with him.
  • Day 4: lost minutes and risk. For each user, three observations on different days: how much time is lost waiting, double entry, copying. Multiply by 220 days and the hourly cost. Then write how long it would take to get the program back on its feet if the single person disappeared.
  • Day 5: the comparison. With these numbers, ask for one quote for the update and one for the module-by-module migration, on the same list of modules. Enter the values in the model and read the four scenarios.

The first step is always small and reversible. If the signs are on the environment side (signs 1, 2 and 4), it is putting the program on a rebuildable machine and replacing the BDE and the components without source code. If the strongest sign is the single person, it is writing the rules and having a second programmer read them. If the strongest sign is requests the program cannot meet, it is a first .NET module on that point alone, in three months.

At the end of the week you have four things you did not have before: a horizon in years, a list of rules, a figure for lost minutes and a value for the risk. With these, the discussion is no longer "Delphi yes or no", but "which one reduces cost and risk in the coming years".

What would the Brescia company do today?

Back to the moulding company. The owner had one question and a consultant who talks about retirement. With the bill in hand he would have seen that "do nothing" costs 44,045 euros a year in maintenance, lost minutes and stoppages, that updating Delphi costs less than migrating at eight years, and that the migration's break-even arrives at 7 years only by giving a value to the risk of the single person.

He would therefore have decided in two steps. Straight away, about 60 days: extract the 23 rules into a document, put the environment on a rebuildable machine, replace the BDE and the three components without source code. It costs 25,200 euros, pays back in under three years and removes the most urgent risk. In parallel, the first .NET module on orders and quotes, because it is the point where the company asks for the most change and where a new system returns visible value in a few months. With that module live, the decision on the rest is made with measured minutes recovered, not estimated ones.

The full migration to .NET, 191,100 euros, becomes the right choice if the company expects to keep the same system for ten years or more, if customers ask for web access and real-time links, or if the consultant stops earlier than planned. It is not the right choice if the reason is "Delphi is old": that reason, alone, is not a number.

In any case he would have decided with a number and not with a salesperson's charm, and he would still have the right road open in two years. That is the difference, and it is worth more than the outcome.

If you have a Delphi program and want to know which zone your company falls into, the path starts from the page on legacy software modernisation, which also includes the cases in which the answer is to touch nothing. If your starting point is an Access file and not Delphi, the guide to replacing Access with a management system does the same bill. And if you need someone to look at the numbers with you, there is software consulting. For those who also have applications written with object interfaces and abstract classes, a good starting point to understand the code to carry over is the guide to interfaces and abstract classes, and for team work on the code the guide to Visual Studio and Team Foundation Server.

In five lines. Count how many of the seven signs apply to your Delphi program and where the development environment lives. Extract the rules from the code and the triggers before talking to any supplier, because they are the asset that cannot be lost. Measure the minutes lost every day per user: they are worth 2,581 euros a year each with twenty-two users. Give a value to the single person, because it is what moves the break-even from 10.5 years to 7. Update Delphi where needed, and migrate one module at a time where change or outside access justifies it.

If the portal to modernize is written in ASP.NET WebForms, with heavy ViewState and nobody who knows it any more, the bill at five and eight years is in ASP.NET WebForms to Core migration.

If the program to modernise is a business application written in Visual Basic 6, the cost at one, three, five and eight years, with the COM bridge to replace one module at a time, is in VB6 to .NET migration.

Frequently asked questions

For a management system with 22 users and 310,000 lines of code, migrating to .NET one module at a time costs about 191,100 euros (455 days), plus 14,700 of double maintenance. Rewriting everything costs 238,980 euros. Updating Delphi to a current version costs 25,200 euros (60 days).

At five years updating Delphi costs less: 199,720 euros against 294,013, and even at eight years 304,432 against 346,941. Migration pays with a horizon beyond 7-10 years, components without source code, web access requests or the risk of a single person, worth 8,448 euros a year in the case described.

No: a current version exists and is updated every year. The risk is not the language but the single program: the old version, data access with no future (such as the BDE), components without source code and one person who knows the code.

With the strangler fig: a .NET shell sits next to Delphi, the database stays shared and one module at a time replaces its Delphi counterpart. Each module goes live on its own, with a week of parallel run on two pilot users. In the case described it takes 14 months.

Three: dates are numbers (TDateTime counts days from 30 December 1899), amounts are often floating point and rounding changes, text depends on the database character set. A layer that converts everything in one place solves it.

You replace them before they break: with a successor from the same vendor, with a standard library or, if they talk to a machine, by rewriting the protocol in a few hundred lines. In the case described there were 14 components, 3 without source code, for 14 days.

Leave your details in the form below

Matteo Migliore

Matteo Migliore is an entrepreneur and software architect with over 27 years of experience developing .NET-based solutions and evolving enterprise-grade application architectures.

Throughout his career, he has worked with organizations such as Cotonella, Il Sole 24 Ore, FIAT and NATO, leading teams in developing scalable platforms and modernizing complex legacy ecosystems.

He has trained hundreds of developers and supported companies of all sizes in turning software into a competitive advantage, reducing technical debt and achieving measurable business results.

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