Same stack, same server, full access. We built it separately anyway.

Sep 9, 2026 | Architecture Under Constraint

Reading Time: 6 minutes
Same stack, same server, full access. We built it separately anyway.

A client gave us full access to their system, showed us how it worked, and asked us to extend it.

Same language. Same database. Same kind of server. Nothing about the work was technically difficult and nothing about their platform was in the way.

We built a separate system instead. I want to walk through why, because the reason had nothing to do with the code, and because I got it wrong myself the first time I tried to explain it.

What was actually in front of us

The client runs a staffing business. Several hundred people, and here is the part that matters more than it looks: almost every one of them is working on a customer’s systems, not on their own. That is what a staffing company is. The engineering capacity is pointed outward, by design, and that is the correct way to run that business.

Their internal system, the one that runs the staffing operation itself, was built in .NET on SQL Server, hosted on a Windows server, by a team that has since moved on to client work. That is also normal. When an internal build is finished, the people who built it are the most billable people in the company, and they get billed. What stays behind is one or two people on maintenance and enhancement, and the knowledge concentrates in whoever led the work.

What the client wanted from us would have been .NET, on SQL Server, on a Windows server. The proposal was an extension: part of the same system, sharing its data, deployed the same way.

And they were open about all of it. We had access. They walked us through the details. There was no black box and nobody being cagey, which is worth saying because that is what people usually assume when they hear this story.

Every technical precondition for extending the system was met.

The thing that changed the decision

The person who still carried the whole system in his head was preparing to leave.

Not a junior. The one who had led the build and then stayed on as the person who understood how all of it fit together. In most internal systems there is exactly one of those by the time the system is a few years old, and every company knows who theirs is.

That is an ordinary situation and I want to be careful not to make it sound like anything else. People move on. What it meant here was specific. At the moment we would be making changes inside a system that runs the whole operation, the person best placed to look at a change and say “that will break the payroll export” was on his way out.

The client saw that and re-examined the plan. They also did the obvious thing and worked to keep him, which is what any well-run company does when it identifies its single point of knowledge. But they were not going to bet the operation on the retention working out, and they were not going to invite an outside team to make changes inside that system in the same quarter.

What I got wrong when I first told this story

For a while I described this as an institutional memory problem. Nobody left could vouch for the system, so the risk could not be sized, so we built alongside.

That sounds reasonable and it is not what happened. It is also unfair to the client, because it implies they had lost control of their own software.

They had not. The system was understood, access was open, and a competent developer could learn it. The fear was never that we would fail to understand it.

The fear was that a new person, any new person, working inside a system the business depends on, might make one small mistake. The ordinary kind everyone makes in their first months on unfamiliar code. And that if that small mistake landed in the wrong place, at a moment when the person who would normally catch it was distracted by his own departure, the operation stops.

Those are two completely different concerns and they look identical from outside. One is about capability. The other is about blast radius, measured against who is available to catch a mistake before it reaches production.

Only the second one was in play. And the client was right about it.

Why they were right

Work out what a small mistake costs, in that system, in that particular quarter.

It carries the records behind hundreds of placements. If it stops, the business stops, and recovery does not just depend on the fix. It depends on someone being available who knows the surrounding code well enough to be confident the fix is complete.

That person’s attention was, understandably, elsewhere.

So the honest sizing was never “how likely is a mistake”. Mistakes are certain. It was: when one happens, who is in the building to catch it before it ships, and how long is the business down if they miss it. Both answers were worse than usual for a few months, and no amount of care on our side changed either one.

This is where I think a lot of vendors go wrong, and I did for years. We answer the question we are good at, which is whether we can do the work. The client is asking a different question, which is what happens to them on the worst day.

I would rather work with a client who asks the second question. It is the one that predicts whether a project goes well.

What we built instead

The new capability runs as its own system.

It owns only the new work. It does not replicate what the existing system does, it does not migrate its data, and it does not require it to change. The original keeps running, untouched, which means the risk nobody could improve was simply never taken.

The failure mode is now contained by construction. If something we built is wrong, it is wrong in a place that did not exist a few months ago, and switching it off returns the business exactly to where it was. You cannot say that about a change inside a system everything else depends on.

The cost is real and I would rather state it than let a prospect discover it. There are two systems now where there was one. Somebody has to hold both. Over time they will need to talk to each other more than they do today, and that integration is a bill that arrives later.

We did not eliminate the problem. We drew a line around it, and accepted a smaller, slower cost in exchange for removing a sudden one.

The question I ask now

I used to ask whether a system could take the change. That is a question about the code, and it is the one I am best at answering, which is probably why I liked it.

The question that actually decides these is: if somebody makes a small mistake in here, what stops, and who is around to catch it first?

If the answer is that a feature degrades and three people notice within an hour, extend the system. That is almost always the better trade and it is most of what we do.

If the answer is that the business stops, and the person who would have caught it is halfway out the door, then the honest recommendation is to build alongside and leave the original alone. Not because it is badly built. Not because you would not understand it. Because the cost of being wrong, this quarter, in this system, is out of proportion to what is being gained.

That is not a technical judgement and I have stopped pretending it is one. It is a question about the business, and the only people who can answer it are the ones who would be in the room when it broke.