Why it feels like nothing ever gets done.
Five contractor teams across two codebases. Less output than ever.
I caught Cal Newport’s latest episode this week. His guest, David Epstein, started in on the Theory of Constraints. By the end, I was thinking about an old job, and a senior VP who had the same complaint every leadership meeting: why does it feel like we never get anything done?
Goldratt was a physicist who walked factory floors in the 1980s. The core idea is simple.
Every system has one bottleneck. Improving anywhere else doesn’t help. It just creates a bigger pile.
Newport’s blog post took it further. Productivity tools often speed up the wrong tasks, making us busier instead of better. That describes almost every product org I’ve worked in.
In product, this is harder to see than on a factory floor. We don’t have visible piles of unfinished work. We have backlogs, Jira tickets, and Slack threads, all looking about the same, whether they’re moving or not.
But the dynamic is the same. When leadership thinks the company is shipping too slowly, the reflex is to add capacity.
Hire more engineers. Or bring in a contracting firm. A second team gets stood up in parallel. More people, more output.
Goldratt would tell you the math is wrong. Adding capacity to a non-bottleneck doesn’t make you faster. It just adds pressure to the actual bottleneck, which, in most product orgs, is upstream of the code.
The time to decide what to build. How long does it take to lock specs that engineers can act on? Leadership’s reluctance to commit to a direction long enough for a team to finish anything.
Adding execution capacity to a system that can’t decide what to build is like installing a second oven in a kitchen out of recipes. You haven’t made it faster. You’ve made it more expensive.
This isn’t theoretical for me. I lived it at an auto refinance startup a few years back. (PS I know I’ve referenced this gig a few times, but there were SO many great lessons. If you really want an adventure, try a start-up)
By the time I left, we had five contracting firms working in our codebase. Three teams in one repository, two in another. The strategy, per leadership, was to unlock speed without bloating internal headcount.
Every leadership meeting ended the same way. A senior VP would lean back, look around the room, and say it: " Why does it feel like we never get anything done?
He wasn’t wrong. We weren’t getting much done. But the diagnosis was upside down.
The assumption was that more teams meant more output, so the shortfall had to be a coordination problem, a contractor quality issue, or maybe a project management issue. Something downstream.
It wasn’t any of those things. The constraint was upstream.
Every team needed work prepared for them:
Clear specs
Prioritized stories
Design assets
Success criteria
Five teams didn’t multiply our output. They multiplied our preparation burden.
We had stacked five times the demand on a single expensive bottleneck: the work required to make work ready.
Even that wasn’t the whole story. The work-prep bottleneck was visible enough. The deeper one was harder to see.
Priorities at the company shifted constantly. Whoever spoke loudest in a meeting set the direction for the next sprint.
A new feature will surface on Monday from a customer call. By Wednesday, it was the most important thing we were building. By Friday, someone else had a louder idea, and we were redirecting again.
This is its own bottleneck, a nasty one because it disguises itself as urgency. Leadership thought they were being responsive. They were preventing any team from finishing anything.
Five contractor teams plus a moving target equals motion without progress.
It’s not a person, a team, or a tool. It’s a way of making decisions.
Bottlenecks like that are the hardest to fix because nobody owns them. They’re nobody’s job to solve and everybody’s job to live with.
Toward the end, I took direct oversight of three of the contractor teams. The first thing that changed wasn’t the teams themselves. It was the work going into them.
We invested upstream. Specs got tighter before reaching the teams, with acceptance criteria written before estimates. Designs were locked, not aspirational.
We protected them from the loudest voice by making it harder for new priorities to displace committed work mid-sprint.
The teams didn’t get faster, exactly. They started finishing things. The output looked different almost immediately, not because we’d added capacity but because we’d finally cleaned up the work going in.
This is the part Goldratt insisted on most. You don’t break a constraint by adding to it. You break it by feeding it well and refusing to dump work on it that should have happened upstream.
Final Thoughts
The pattern outlives the story. The names change, the bottlenecks shift, but the failure mode stays. If you’re recognizing pieces of it in your own work, a few starting moves:
Identify the actual bottleneck before adding capacity. If your engineering team is idle while waiting for specs, decisions, or designs, capacity isn’t your problem.
Audit your work-preparation process. How long does a feature sit in “ready” status before someone realizes it isn’t actually ready? That delay is the constraint announcing itself.
Treat priority churn as a tax. Every mid-sprint pivot costs you. Track it.
Protect the bottleneck. Give it space, feed it good inputs, and stop asking it to do work that should happen elsewhere.
I think about that auto refinance company more than I should. The VP never figured out why nothing felt like it was getting done.
The answer sat in his calendar every week. The shifting priorities, the uncommitted directions, and five teams hired to solve a problem that wasn’t capacity.
The constraint was never engineering. It rarely is.
Mike Watson @ Product Party
P.S. Want to connect? Send me a message on LinkedIn, Bluesky, Threads, or Instagram.


