A few years back, a fintech startup I was advising finished a major rebuild of their payments infrastructure. The CTO told the board it cost roughly $2.1 million to build. The CFO’s number was $3.4 million. The lead engineer, when I asked her privately, said closer to $4.8 million. Same project. Same company. Three numbers that couldn’t all be right.

Nobody was lying. That’s the uncomfortable part.

The Setup

The company, which I’ll call Meridian (not their real name, and they’d prefer it that way), had spent 18 months migrating off a legacy payment processing system onto a modern microservices architecture. On paper, it was a success. Latency dropped, reliability improved, and the engineering team could finally ship features without tiptoeing around a codebase that had been accumulating technical debt since 2014.

When the board asked the obvious question, “what did that cost us,” it set off a quiet, slow-motion argument that lasted weeks and was never fully resolved.

The CTO counted direct engineering salaries for the eight engineers who worked primarily on the migration, prorated by the percentage of their time devoted to the project. That math got him to $2.1 million. Clean, defensible, easy to put in a slide.

The CFO added infrastructure costs, vendor contracts, and the opportunity cost of three product features that got delayed because senior engineers were absorbed by the migration. That got her to $3.4 million. Also defensible.

The lead engineer counted something different: the actual hours her team spent on the project, including the nights and weekends that didn’t show up in any HR system, plus the time spent by engineers outside the core team who got pulled in for two-week stints to help with specific subsystems. She also included the six weeks of post-launch firefighting that nobody called “migration work” even though it clearly was. Her number was $4.8 million.

All three methods were reasonable. None of them was complete.

Timeline diagram showing a precise start point dissolving into multiple ambiguous endpoints
The boundary problem: software projects have clear beginnings and contested endings.

What Actually Happened

Meridian’s situation is not unusual. It’s close to universal.

Software cost accounting has a few persistent structural problems that make honest measurement genuinely hard, not just politically inconvenient.

The first is the shared-resource problem. Most engineers don’t work on one thing. They get pulled into code reviews, Slack threads, interviews, on-call rotations, and architectural discussions that don’t map cleanly to any project. Time-tracking systems, where they exist at all, are almost always filled out retroactively and optimistically. Nobody logs the 40 minutes they spent helping a colleague debug a problem tangentially related to the project you’re trying to cost. Multiply that across 12 engineers over 18 months and you’ve lost a significant number.

The second problem is the boundary problem. When does a project begin and end? Meridian’s CTO started his clock when the migration was formally kicked off. But the six months of architectural planning that preceded it, including two engineers who did almost nothing else during that period, didn’t make his count. The lead engineer included them. Neither was wrong to draw the line where they did.

The third problem is opportunity cost, which is the hardest to measure and the easiest to ignore. Meridian’s CFO tried to capture it. Most people don’t bother, because estimating the value of features you didn’t build requires a chain of assumptions that quickly becomes uncomfortable. But the cost is real. Three features got delayed. Some of those features would have generated revenue. Some of that revenue was real money left on the table. Underpricing your startup is harder to fix than overpricing, but undercosting your infrastructure work creates the same kind of distorted thinking.

The fourth problem is maintenance debt. The migration solved a lot of problems and introduced some new ones. The new architecture required a different kind of operational knowledge, and onboarding engineers to it took longer than the old system. That cost showed up as slower hiring ramp-up and higher incident rates in the first six months. It belonged in the project cost. Nobody put it there.

Why It Matters

You might think this is an accounting problem, interesting only to CFOs and auditors. It’s not. It’s a decision-making problem.

When companies systematically undercount what software costs to build, they make predictable mistakes. They greenlight rewrites that aren’t worth doing. They understaff projects that need more people. They set prices for products based on cost structures they don’t actually understand. They make build-versus-buy decisions using only part of the math.

Meridian made one of these mistakes. Because the “official” cost was $2.1 million (the CTO’s number won the political argument, as engineering numbers tend to), the board concluded the migration was a bargain. They approved a second major infrastructure project on similar assumptions. That one ran 70% over its anticipated budget, partly because nobody had built accurate priors from the first project.

The real cost of bad cost accounting is bad future decisions. It compounds.

What We Can Learn

Meridian eventually developed a cost accounting framework that came closer to capturing reality. It wasn’t elegant, but it worked well enough to improve decisions.

They did four things worth borrowing.

First, they adopted a two-number discipline. Every project got a direct cost estimate and a fully-loaded cost estimate, and both numbers were required to appear together in any planning document. Nobody was allowed to quote just one. The gap between the two numbers became a useful conversation in itself.

Second, they started tracking engineer time at a coarser granularity. Not the fantasy of 15-minute time logs, but a weekly “what did you mostly work on” check-in that made it harder for project costs to hide in the margins. It wasn’t perfect, but it was better than nothing, and better than the retroactive guesses they’d been relying on.

Third, they built a post-launch window into every project’s official lifecycle. Six weeks after go-live, stabilization work still counted against the project. This forced more honest estimates upfront because engineers knew the firefighting would be on their ledger.

Fourth, and most importantly, they made the CFO and lead engineer part of the cost conversation from the beginning, not just the CTO. Different perspectives aren’t noise. They’re signal. When the person managing the budget, the person writing the code, and the person responsible for the roadmap all give different numbers, the right response is to understand why, not to pick the most comfortable one.

The deeper lesson from Meridian is that software cost disagreement isn’t a communication failure or a personality conflict. It’s what happens when you ask a genuinely ambiguous question and expect a clean answer. The CTO, CFO, and lead engineer were each measuring something real. The mistake was assuming there was a single correct number waiting to be found, rather than a range of perspectives that together told a more complete story. Context switching steals your best thinking, and so does the false certainty of a single cost figure that obscures more than it reveals.

The most useful thing a team can do is get explicit, upfront, about which cost they’re measuring and why. That conversation, uncomfortable as it is, is worth more than any single number that comes out of it.