The Work is in the Fog of War
In some teams I've worked in, there was a moment in a project that always made my stomach tighten.
The designs are "done". We've had the walk-throughs. Stakeholders have nodded along through a few rounds of feedback. The UI mocks look convincing enough that everyone can imagine the feature existing already. The mood in the room shifts to: "right, time to get serious and write the tickets".
On paper, you break the mock-ups down into tasks, put estimates on them, slice the work across the team, and press go. In reality, this is where everything starts to wobble. As soon as you try to write actionable tickets - slicing work to build the code paths, data flows, and tackle edge cases - you discover how much you don't yet understand.
Someone points out a pile of forgotten tech debt that has to be moved before anything else can fit. Someone else realises that the new flow contradicts another flow once you see them side by side. A stakeholder changes their mind the moment they imagine clicking through the screens for real. The illusion that the problem is "solved on paper" falls apart the moment you slice that paper into implementation pieces.
I've come to think of these moments, in cycle planning meetings, as the point where the fog becomes visible. Not because the meeting is the problem, but because it's the first moment where the team has to turn a convincing story into executable slices. That translation is still design work. Even with the best intentions in earlier review phases, you don't surface the unknown-unknowns until you try to actually do the thing.
The work is not what happens once that fog has been burned away. The work is moving through it.
The cabinet maker fantasy
Part of why this moment feels so uncomfortable is that it fails to match up with a storyline development teams find reassuring.
If you ask a cabinet maker to build you a piece they've made a hundred times before, they can usually tell you exactly what it will cost and how long it will take. They'll measure the space, pick the timber, do the cut list, and come back with a price. They have patterns, jigs, and muscle memory. They're not discovering a new object; they're repeating a known shape with small variations.
Many organisations instinctively treat software work like this. They want to know what they're going to get and when they're going to get it. They want to be comforted by the idea that someone, somewhere, is in control - that the hard thinking has already been done, the unknowns have been ironed out in discovery, and what remains is the cabinet-making part: skilled, but predictable.
You can see this in many forms:
- Roadmaps that read like delivery schedules.
- Requests for precise estimates before anyone has opened the codebase.
- Contracts that promise exactly which features will ship by which date.
- Agencies charging a premium for fixed scope work, because taking on that level of risk is expensive.
It's an appealing fantasy, and not entirely unreasonable. There are parts of software that do behave more like cabinetry: well-trodden integrations, familiar CRUD, boring but necessary plumbing. But most interesting product work doesn't feel like building the same cabinet over and over. It feels much closer to tackling a novel problem. Hidden complexity is the norm, not the exception.
And the painful bit is that we ask for a cabinet-maker level of certainty in a medium where the plan itself is a large chunk of the work. The line from "the idea" to "the plan" is often wiggly. If you invest huge amounts of energy up front to produce a perfect plan, you pay twice: once in the cost of doing the thinking far away from the code, and again when reality changes and the plan goes stale.
Treating software as repeatable craft is how you end up with everyone being surprised – and potentially annoyed – when the fog rolls back in at ticket‑writing time.
What the fog feels like
The fog of war isn't just the absence of a plan. It's what it feels like to do the plan-shaping work while everyone is pretending the shaping is already finished.
On the surface, things look tidy. The UI mocks tell a coherent story. Stakeholders are confident enough in the direction that they want to talk about timelines. The work is framed as: "how long will it take to build this?"
As soon as you start getting specific, the cracks show:
- New constraints appear the moment you try to map a design to actual data and APIs.
- Edge cases and awkward paths pop up that weren't obvious in a linear Figma prototype.
- Performance, accessibility, and interaction details start to matter once you imagine a real user actually clicking around.
If you're working on something strictly technical the pattern is the same. On a whiteboard, the refactor or new module looks straightforward: extract this, rename that, shuffle a couple of responsibilities. Once you take one webpage or one package and actually try the change, you realise how entangled things are, or that a concept you thought was cleanly defined isn't clean at all.
None of this means the design work was bad or that people weren't paying attention. It's just that you learn about the problem by working on it. Implementation is one of the main ways a team deepens its understanding. If you somehow knew, up front, every change that would be required in the codebase to make a solution real, you've already done most of the work in your head.
In a healthy team, you're not really assigning people to "build this solution". You're assigning them to a problem and a goal, with permission - implicit or explicit - to reshape the solution as they learn. The work naturally swings between discovery, refinement, and execution: talking to users, adjusting the concept or scope, changing the software itself, often in the same week.
The fog is simply what it feels like to be inside that loop.
Treating unknowns as first‑class work
One of the most useful shifts I've seen in culture and process is to stop treating unknowns as a sign of failure and start treating them as work.
Instead of asking "why didn't we catch this earlier?", you name the unknowns explicitly:
- What problem are we actually solving for this user?
- What happens if they try to do X that isn't in the happy path?
- What hidden technical constraints might shape what "good enough" looks like?
You put those questions on the table as things to be tackled, not as embarrassments to be swept away. In practice, that can look like:
- Framing work as "here's the problem space and direction; go explore and shape a solution", rather than "this design is final; estimate and implement it".
- Picking a time appetite first, then shaping scope to fit it (instead of treating scope as sacred because it was written down early).
- Time‑boxing learning on the riskiest unknowns, and only then committing to the long tail of implementation.
- Keeping tickets honest: some are for shipping, some are for finding clarity.
I'm working on a companion piece for this article with more actionable details. If you want to catch it when it lands, subscribe to my RSS feed.
If you don't accept the fog, you often end up pouring huge amounts of energy into ever more elaborate planning phases, just so you can feel confident about perfectly executing the implementation. You have planning meetings, then end up with pre-planning meetings, then pre-pre-planning meetings. Developers spend more time scratching their heads to find convincing answers than building things to learn from.
Embracing the fog feels risky
None of this lands easily in organisations that are used to certainty.
Stakeholders and leaders quite reasonably want to reduce risk. They want to be able to tell customers and partners when something will ship and what they'll get. They want to believe that someone has already walked the battlefield and marked out all the traps. It's not surprising that classic waterfall and big‑up‑front design were attractive for so long: they promise that, with enough analysis, the fog can be banished before anyone writes a line of code.
Agile, at its best, is an honest admission that this isn't how development work behaves. You can only really see the next handful of moves clearly. You need to ship, learn, and adjust.
It's uncomfortable to say "we don't know yet" in cultures that idolise decisiveness. Senior people are used to being the ones with answers. Admitting that you're working in a fog can feel like losing authority. It's also hard to put on a dashboard. Velocity and throughput are easy to count; clarity gained and bad ideas discarded are not.
From the developer's side, there's a different kind of discomfort. Being honest about uncertainty can make you feel like you're letting people down. If you treat every estimate as a promise, then every burst of hidden complexity becomes a kind of personal failure. You start to dread the wiggly path.
The alternative is not to shrug and stop caring about dates. It's to be more precise about what you can and can't promise.
You can promise that you'll use the time well. That you'll surface unknowns early, rather than hiding them. That you'll keep something working and demo-able so people can feel the thing, not just look at pictures of it. That you'll make good-faith trade-offs between scope, quality, and time, instead of pretending all three are fixed.
You cannot honestly promise that you'll build exactly the picture in the design file, on exactly the date in the roadmap, without learning anything that might change your mind.
Naming the fog, doing the work
The more I work, the more I think the healthiest teams are the ones that are willing to say, out loud, "we're in the fog right now".
They don't treat that as a shameful confession. They treat it as a status update. They write down the questions they need to answer. They use tickets and spikes and prototypes as tools for learning, not just delivery. They measure success not only by features shipped, but by how much clearer the landscape looks than it did a week ago.
The work is in the fog of war, not in typing out a foregone conclusion. The sooner you name that, the less time you'll spend pretending to be a cabinet maker when you're really trying to chart a path through unfamiliar ground.