And why most custom software isn't.

There's a pattern that plays out constantly in businesses that run on operational complexity, and it almost always ends the same way.

A company hires a developer to build something custom — an internal tool, a management portal, an ops system. The developer asks what they want. The company describes it. The developer builds it. It works. At launch, everyone is pleased.

Six months later, the gaps appear.

Not critical failures — the software doesn't crash. It just doesn't quite fit. The workflow has an edge case the software doesn't handle, so someone made a spreadsheet for it. The reporting doesn't match how the team actually looks at the data, so they export to Excel. There's a multi-step process that the software treats as a single step, so people have developed a workaround. Over time, the workarounds compound. The spreadsheets multiply. The software works in the technical sense, but the operation has grown around it rather than through it.

This is the default outcome of custom software, and it's not because the developer was bad. It's because of something more fundamental: the developer understood code better than they understood the operation.

The code-first problem

Most software development starts with technology.

A client describes what they want. The developer asks questions about features and data — what should the system store, what should it display, what should users be able to do. This is the natural language of software development. Entities, relationships, actions.

What it misses is the operational layer: the way work actually flows through the business, the rules that govern decisions, the exceptions that happen regularly but don't fit the happy path, the informal processes people have developed because the formal process doesn't quite cover everything.

A developer who starts with code will build exactly what was described. The gap between "what was described" and "how the operation actually works" is where the workarounds live.

This is a harder problem than it sounds, because the operational layer is often invisible to the people inside it. If you've been running a warehouse for ten years, you don't think consciously about every rule and exception — you just know them. They're in your head, in the heads of your staff, in the informal protocols that developed over time. When a developer asks "what do you need the system to do," you describe the happy path. The exceptions surface later, in production, as gaps.

What operation-first looks like

I recently started work on a complete rebuild of a legacy operations platform for a warehouse and inventory business. The existing system had been running for over a decade. It was built on a technology stack that hasn't been actively developed in years — a ColdFusion application backed by a database the client didn't own and couldn't export from directly. There was no documentation. One developer held all the context. The client was effectively dependent on a person they were trying to move away from.

The technology problems were solvable. The more interesting challenge was this: nobody had formally documented how the operation actually worked.

The existing system captured some of it. But a decade of operational evolution had produced processes that existed around the system, not in it. Inventory decisions that got made in a particular order because of supplier relationships the original system didn't model. Grading criteria that had been refined over years but lived only in the heads of the people doing the grading. A check-in process that had three different workflows depending on where goods came from, none of which were explicitly documented anywhere.

Before writing a line of code, I spent time learning the operation. Not just the features — the workflow. What happens at each stage. Who makes which decisions and based on what criteria. What triggers movement from one stage to the next. What the exceptions are and how they're currently handled. What rules are firm and what rules are guidelines.

That understanding became the specification. The specification became the software.

The difference, in practice: when the software ships, it handles the exceptions. The grading workflows are modeled correctly because we designed them from observed operational reality, not from a surface description. The multi-stage check-in process works the way it actually works, not a simplified version of it. Edge cases that would have appeared as gaps six months after launch were designed in before the first line was written.

Why this is more important now

The rise of AI-assisted development has changed the cost structure of building software. A developer with the right tools can build significantly faster than was possible a few years ago. Features that used to take a week take a day. Systems that used to require a team can be built by one person.

This is genuinely good. It makes custom software accessible to businesses that couldn't afford it before.

It also amplifies the code-first problem.

AI coding tools execute instructions. They're very good at this. Given a clear specification, they can produce reliable code quickly. But they can't interrogate whether the specification actually captures the full complexity of an operational workflow. They don't know what to ask. They build what they're told to build, and they build it fast.

The result is software that works at a surface level and misses the operational depth — but built faster than ever. The gap between "what was described" and "how the operation actually works" appears sooner and compounds faster, because more features get built before anyone notices the misfit.

Starting with the operation isn't just good practice in an AI-assisted world. It's the difference between using AI tools to accelerate a build that fits and using them to accelerate a build that doesn't.

The documentation consequence

There's a second problem with code-first development that surfaces more slowly: the knowledge doesn't get captured.

When a developer builds from their own understanding of the system — understanding they developed through the build process — that knowledge lives in their head. The code implements it. The code is not the same as the documentation of why things work the way they do.

When that developer leaves, the knowledge leaves with them. The next developer looks at the codebase and sees what the system does. They don't see why specific decisions were made, what the exceptions were that drove certain designs, what the rules are that govern edge cases. They figure it out slowly, by reading code and making inferences. Or they make changes that break things they didn't know were load-bearing.

The company I mentioned earlier — the one with the decade-old legacy system — had exactly this problem. There was one developer who knew how everything worked. Not because he was withholding anything, but because nobody had ever built the practice of capturing that knowledge alongside the code. When the client wanted to replace the system, they couldn't safely migrate away without his involvement, because he was the only person who knew what the system was doing in places that weren't obvious.

Every project I build runs on a documentation system called Groundwork: seven structured documents maintained throughout the build that capture the architecture, the data model, the business logic, the build history, and the operational rules. Not written after the project ships — built as the project is built, updated after every session.

When the project is done, the documentation travels with the codebase. A new developer can get oriented in hours, not weeks. The knowledge isn't locked in my head. The client owns not just the software but the understanding of how and why it works.

This is connected to the operation-first process, not separate from it. Building operation-first produces software that's worth capturing in writing. Building code-first produces software that's hard to document because the operational logic is scattered and implicit.

What to look for before you build

If you're evaluating a developer for a custom project, the most important questions aren't about technology. They're about how they start.

"How do you learn the operation before you start building?" A developer who asks primarily about features and data is building code-first. A developer who asks primarily about workflow, rules, exceptions, and how things actually run today is building operation-first.

"What happens if you're not available six months after launch?" The answer should describe documentation — something that makes the system legible to another developer without you. Staying available is a business arrangement. Documentation is independence.

"Can you show me the specification process?" A developer who can show you a structured spec process — how operational understanding becomes a formal build plan — has built this practice into how they work. A developer who figures it out as they go builds faster at the start and surprises more often later.

The best custom software doesn't feel like software. It feels like the operation, formalized — the way your workflow actually runs, captured in a system that handles the cases that matter, including the ones nobody thought to mention explicitly.

That only happens if you start with the operation.