The Problem
The old system had two main layers: a VB6 front end that operators used to interact with the system, and a C++ back end that handled data collection and talked to the hardware. Over the years, different teams had maintained each layer separately.
At the heart of the C++ layer was a driver that communicated with a physical card plugged into an ISA expansion slot — a type of hardware connection that the industry stopped using years ago. Because the system needed that ISA slot to function, it couldn’t run on any modern machine.
On top of the hardware problem, the software itself had become fragile. The two layers weren’t formally connected, but they depended on each other in hidden ways — shared assumptions about the order things ran in, how data was formatted, and what the hardware would do. Changing one part could cause unexpected breakdowns in seemingly unrelated parts of the system.
Over time, small additions that each made sense on their own had built up into a web of undocumented rules baked into the code. Salem Automation’s engineers found cases where calling what looked like a simple function would actually set off a chain reaction across multiple parts of the system, all the way down to the hardware driver. None of this was written down. The only way to uncover it was to watch the system run, trace its behavior, and piece together the logic buried in the code.
The Solution
Discovery
Before changing anything, Salem Automation’s team studied how the entire system actually behaved. They treated the old codebase not as a list of parts to swap out one by one, but as a living system that had to be understood as a whole first. This focus on how the parts interacted — not just what each part did on its own — shaped the project’s timeline and approach from start to finish.
Choosing the New Technology
The team chose C# as the main programming language because it’s modern, well-supported, and has a large community of developers — making the system much easier to maintain long-term. They used WPF for the user interface, which cleanly separates what the screen looks like from what the application does behind the scenes, something the old system never had. And they used the Prism framework to give the new system a clear, organized structure with built-in tools for managing how different parts of the application connect and communicate.
Isolating the Hardware Dependency
The old system’s connection to the ISA hardware was scattered throughout the code with no clear boundaries. In the new system, Salem Automation wrapped that hardware connection behind a single, clearly defined interface. This did two things: it made the hardware dependency visible for the first time, and it created a clean boundary so the hardware can eventually be replaced without having to rework the rest of the system.
The system still needs an ISA-equipped machine to run until the hardware is physically replaced. But now that dependency is clearly identified and contained in one place, rather than hidden throughout the code.
Building in the Right Order
Because so many parts of the system depended on each other, the team couldn’t just rebuild pieces at random. They worked from the bottom up — starting with the foundational components that other parts relied on, then moving to the layers above them. At every step, they checked that the new version behaved exactly the same way the old one did. The old system’s behavior was the spec.