UniVerse and Pick BASIC systems still run a surprising amount of the world’s inventory, distribution, healthcare, and financial operations. They tend to share a pattern: they were built decades ago, they work, and they have quietly become difficult to staff, integrate, and extend. The business does not want to gamble the system that generates its revenue on a full rewrite, but it also cannot keep hiring for a shrinking pool of MultiValue developers forever.
I have worked on both sides of that seam — inside UniVerse and Pick BASIC applications, and building the C#/.NET APIs, services, and cloud infrastructure that eventually need to talk to them. The approach that actually works looks nothing like a rewrite. It looks like a series of deliberate, reversible moves.
The data model is the business logic
The instinct coming from a relational or .NET background is to treat UniVerse as “a weird database” and normalize it as fast as possible. That instinct causes real damage.
Multi-valued fields, associated attributes, and dynamic arrays in a Pick BASIC file are rarely arbitrary. They usually encode a relationship the business cares about — line items on an order, addresses for an account, history for a case — compacted into a single record because that was the efficient way to model it thirty years ago. Decades of BASIC subroutines depend on that exact shape. Before I touch schema, I want to know which programs read a given file, which reports depend on its attribute order, and which “obviously dead” fields are actually read once a quarter by a job nobody remembers writing.
That discovery phase is not wasted time. It becomes the specification for the .NET system, because the legacy application is usually the only complete, accurate description of what the business actually does.
Wrap before you replace
The first code I write in a modernization project is rarely new business logic. It is a boundary.
A thin .NET API — or in some cases a UniObjects/.NET or ODBC-based data access layer — sits in front of the UniVerse account and exposes the data and operations the rest of the organization needs, without changing how Pick BASIC programs write to those files. This does two things: it lets new work (a web portal, a reporting dashboard, an integration with a modern SaaS product) start immediately in C#, and it gives me a controlled place to observe real read and write patterns before committing to a target schema in SQL Server.
This is the same strangler-pattern thinking I’ve used modernizing legacy PHP systems: change the seams first, prove the new boundary under real traffic, and only then start moving logic across it.
Migrate logic in slices, not in one cutover
Once the boundary exists, individual workflows move one at a time — order entry, a scheduled follow-up job, a reporting screen — each rebuilt as a tested C# service that reads and writes through the same boundary. I favor slices with a clear business owner and a measurable “done”: the new .NET workflow produces the same output as the BASIC subroutine it replaces, for the same inputs, across a real sample of production data.
Parity testing carries more weight than new feature work in this phase. I run the old and new paths side by side — same input, both outputs compared — until the differences are understood and intentional rather than accidental. A modernization effort loses the business’s trust the moment a total, a due date, or a record count quietly stops matching, so I would rather find that mismatch in a diff report than in a customer complaint.
Plan for what the terminal screens don’t tell you
MultiValue shops often have integration points that never show up in the file dictionary: EDI feeds, label printers, third-party warehouse systems, nightly batch jobs kicked off by cron or a scheduler most of the team has forgotten exists. I treat mapping those integrations as seriously as mapping the data model, because a .NET rebuild that is functionally perfect but silently breaks an EDI trading partner is not a successful migration.
The same applies to the people who operate the system. Pick BASIC developers understand exactly why a screen behaves the way it does, even when the reasoning was never written down. Pairing them with the .NET team — not sidelining them — is usually the fastest way to avoid rebuilding a workflow that is subtly, expensively wrong.
What a good outcome actually looks like
A successful UniVerse-to-.NET modernization does not end with an empty MultiValue account and a champagne toast. It usually ends with a period — sometimes a long one — where a C#/.NET system and a shrinking UniVerse footprint run side by side, each handling the workflows it is currently responsible for, with a clear boundary and a clear plan for what moves next.
That is a less dramatic story than “we rewrote it,” but it is the version that keeps the business operating every day of the migration instead of betting it on a single cutover weekend. For a system that has been quietly correct for twenty years, boring and reversible is the feature, not the compromise.