Skip to main content

Benjamin
Charity

Published: January 1, 2099

Building While Defining the Problem

Reading time: 14min

Product teams experiment. Most engineering teams still wait for the answer.

Over the past decade, product and UX teams have internalized a discovery mindset. They run experiments. They test assumptions before committing. They expect to be wrong early and treat changing direction as evidence that the process is working.

Engineering teams have adopted iterative delivery. CI/CD, feature flags, sprint-based releases, A/B testing infrastructure. The mechanics of shipping frequently are well understood. Most modern engineering orgs are iterative in their delivery process.

But there is a gap that the delivery improvements did not close. Most engineering teams are iterative in how they ship, but not in their relationship to uncertainty about what to ship. They deploy frequently. They just expect someone else to decide what gets deployed. The engineering side is optimized for execution speed, not for experimentation.

That distinction matters more now than it ever has. The cost of producing working code has dropped so far that engineering teams can now test ideas with real, functioning software faster than traditional UX research and design sprint cycles. The team that recognizes this shift and uses code as an experimentation tool gets a structural advantage. The team that keeps waiting for the validated spec before writing a line of code is leaving that advantage on the table.

A laptop on a cluttered workbench surrounded by sketches, sticky notes, and prototype parts, a visual for using code as a live experiment rather than a deliverable

The cost of the gap

When product operates in discovery mode and engineering operates in execution mode, the friction shows up in predictable ways.

Product validates a concept through customer conversations, prototypes, or competitive analysis. They hand it to engineering as a spec. Engineering builds it. Then product learns something new from real user behavior that changes the direction. But the code was built to be permanent, not to be refined. Adapting it requires rearchitecting, not reconfiguring. The refinement loop stalls at the engineering boundary.

Engineers feel whiplash. They built what they were asked to build. Now it is changing. The natural response is to build even more defensively next time: more abstraction, more flexibility, more "just in case" architecture. That defensive posture makes the system even harder to change, which makes the next iteration even more expensive.

Product responds by limiting how much they share with engineering. They stop surfacing early ideas because the last time they did, engineering spent three weeks building something that changed significantly. So they wait until they are more certain before handing off a spec. Which means engineering gets less context, builds with less understanding, and the gap widens.

Both sides are being rational. And the system is getting worse.

Engineering experimentation is not product discovery

The fix is not to turn engineers into product managers or to run design sprints in the codebase. Engineering experimentation is its own discipline.

Product discovery asks: "What should we build? What problem are we solving? Who is it for?"

Engineering experimentation asks: "Now that we have a validated direction, what is the fastest way to get a working version in front of users so we can refine how it actually needs to work?"

The hierarchy matters, but not the way it used to. Cheap discovery comes first. Talk to customers. Run a survey. Simulate the workflow in a spreadsheet. These tools answer the "should we build this at all" question faster than anything else.

But the traditional next step, building a polished Figma prototype before writing any code, is worth questioning. If your codebase has a well-defined design system and component library, spinning up a rough, clickable code prototype may actually be faster than designing one from scratch in Figma and pushing it through a prototyping tool. The user can click through real interactions, navigate real flows, and feel the weight of the product in a way that static frames never capture.

This does not mean the code prototype needs real data or production-quality edge case handling. It can be as rough as a design mockup. Fake data, contrived scenarios, happy-path only. The point is that users are interacting with something that behaves like software rather than looking at pictures of software. The feedback is different in kind, not just degree.

Conversation validates the idea. Code validates the interaction. And sometimes code sends you back to the conversation. A user interacting with a working prototype may reveal that the idea itself needs to change, not just the implementation. The loop is circular, not linear. But the starting point matters: understand the problem before you build, then get something interactive in front of users as fast as the tooling allows.

Engineering teams that understand this loop participate in it instead of waiting at the end of it.

What engineering experimentation looks like in practice

This is not theory. It is a set of specific decisions that change how code gets written and how teams operate.

Optimize early code for learning speed, not durability

Every assumption baked into the architecture is a bet. At the earliest stage of a new product or feature, most of those bets are wrong. The question is how expensive it is to update them.

This means thin abstractions, minimal coupling between modules, and a bias toward configuration over hardcoded logic. Multi-tenant systems, for example, force early decisions about data isolation, permissioning, and workflow configuration. If those decisions are buried in application logic, changing them requires surgery. If they are externalized into configuration, changing them requires a conversation.

Build for the conversation, not the surgery.

This does not mean zero quality. There is a minimum bar below which a prototype stops being useful as a discovery tool. If users are fighting crashes and data loss, they are evaluating your quality, not your concept. The bar is: reliable enough that users can interact with the core workflow without the implementation getting in the way of the feedback.

Make production behavior observable from day one

You cannot learn from code that users interact with if you cannot see how they interact with it. Logging, analytics, and error reporting are not polish for later. They are the mechanism by which early code teaches you anything at all.

From day one, you should be able to answer: Where do users get stuck? Which features do they ignore? What workflows take three times longer than expected? Where does the system fail silently?

If you ship an MVP without observability, you shipped a guess and removed your ability to verify it.

Accept that early code will survive longer than you planned

The most common and most honest criticism of "build disposable code" is that disposable code almost never gets disposed of. The MVP becomes the foundation. The temporary workaround lives for years. The prototype is running in production eighteen months later because there was always something more urgent than replacing it.

Plan for this. Not by over-engineering from the start, but by building with enough modularity that the parts that need to harden can harden without requiring a full rewrite.

A rolling approach works well in practice: as specific parts of the product stabilize, those parts graduate from "exploratory" to "foundational." They get tests, documentation, and proper abstractions. The parts that are still in flux stay light and cheap to change.

This is not a one-time migration. It is a continuous judgment about which bets have been validated and which are still open.

Know when to stop discovering and start committing

There is a moment in every early-stage build where the fog starts to lift. You have shipped enough iterations, watched enough user behavior, and absorbed enough domain knowledge that the real problem starts to separate from the noise.

This moment usually sounds like someone on the team saying, "Oh, the thing they actually need is..." followed by a restatement of the problem that is simpler, more specific, and more actionable than anything in the original brief.

That is the moment to start hardening. Not before.

The skill is knowing when you have crossed from "learning what to build" to "building what you learned." It is a judgment call, not a milestone on a Gantt chart. And it is a judgment call that requires fluency in both product thinking and engineering execution.

How to close the gap at the leadership level

The tactical engineering practices above are necessary but not sufficient. The gap is organizational. Closing it requires changes to how product and engineering relate to each other, how time is structured, and how decisions about exploration vs commitment get made.

Bring engineering into the discovery conversation earlier

In most orgs, engineering gets involved when the spec is written. By that point, the key decisions have been made without technical input. Engineering's only role is execution.

The shift: involve a senior engineer or tech lead in the discovery phase. Not to build anything. To hear the customer conversations, see the research, understand the hypotheses. When engineers have the same context that product has, they make better architectural choices. They know which parts of the system are likely to change and which are stable. They can design for the right kind of flexibility instead of guessing.

This is not about adding engineers to every meeting. It is about making sure the people who will design the system understand why it is being built, not just what.

Create space for experimentation in the sprint cadence

If every sprint is fully committed to delivery, there is no room for experimentation. Engineering will default to execution mode because the schedule demands it.

Reserve a portion of engineering capacity for experimentation work. This is different from tech debt allocation. Tech debt is about the health of existing systems. Experimentation capacity is about learning whether new concepts work before committing to full builds.

How much capacity depends on how much uncertainty the business is actually facing. A company entering a brand new vertical, launching its first product, or testing a fundamentally different approach to a known problem needs significant experimentation capacity. The product is not yet defined. The assumptions behind it have not been validated. Code is one of the fastest ways to close that gap.

A company building a CRM in a well-understood market with established user expectations and competitive benchmarks needs far less. The problem space is known. The workflows are documented. Experimentation capacity might be minimal or focused narrowly on the few areas where the product diverges from established patterns.

Most teams fall somewhere between those extremes. The honest assessment is: how much of what we are building right now rests on assumptions we have not yet tested? The higher that number, the more experimentation capacity you need. As the product matures and the assumptions get validated, that capacity naturally shifts toward delivery. This is not a fixed allocation. It is a dial that moves with the business.

Make the explore/commit decision explicit

Every project has a moment where it transitions from "we are still learning" to "we are committing to this direction." In most orgs, that transition is implicit. Nobody announces it. The team just gradually starts treating exploratory code as the production system.

Make the transition explicit. Name the phase. "We are in exploration mode on this feature. The code we write this sprint is designed to be refined or replaced. We will evaluate at the end of the sprint whether to commit or pivot." When the team commits, the expectations change: tests, documentation, proper abstractions.

This gives engineers permission to write lighter-weight code during exploration without feeling like they are cutting corners. And it gives product a clear signal for when the engineering team needs stability to do their best work.

Redefine what engineering success looks like

If engineering is measured purely on delivery velocity, the incentive is to build fast and not look back. Experimentation feels like waste because it does not produce shippable features every sprint.

Add a structured practice for surfacing what experimentation produces. This is not a dashboard metric. It is a recurring question in sprint reviews or retrospectives: "What did we learn from the last experiment that changed what we are building next?"

If the answers are substantive and specific, the experimentation capacity is producing value. If the answers are vague or nonexistent, either the experiments are poorly designed, nobody is observing the results, or the team is not actually running them.

You can also track lightweight signals over time: how many experiments led to a change in direction, how often experimentation work influenced what got committed to the next cycle, how long it takes from experiment to decision. These are not KPIs to optimize. They are indicators that the practice is alive and producing learning rather than just consuming capacity.

When this does not apply

This is not an argument against spec-driven engineering. For stable products with well-understood users, clear requirements, and proven workflows, the spec-first model works. An engineering team executing against a well-defined plan is not broken. It is efficient.

A new CRM, an invoicing tool, a standard e-commerce checkout flow: these do not require you to build your way to understanding. The user workflows are documented. The competitive landscape tells you what is expected. The right move is to execute against a known pattern, not to run experiments.

But even in mature products, some capacity for experimentation is worth preserving. New features enter uncertain territory. Market shifts create ambiguity. User behavior changes in ways that past specs did not anticipate. The team that has no experimentation muscle at all will struggle to respond when the ground shifts under a stable product.

The waste is not in building fast. It is in treating a known problem like an unknown one, or treating every problem like a known one when some of them are not. The judgment call is which category you are in.

Why this gap is about to widen

AI tooling has collapsed the cost of spinning up code. Generating a prototype, scaffolding an MVP, wiring up a basic interface takes a fraction of the time it did even two years ago.

This changes the math for teams that have closed the gap. When a validated idea can go from concept to working software in days instead of weeks, the refinement loop tightens dramatically. The team can put real software in front of users, observe how they interact with it, and adjust the implementation based on what they learn. Faster cycles, more data, better outcomes.

The team that has not closed the gap does not get this leverage. They use AI to produce more code, but the code is still built downstream of a spec that was finalized before engineering got involved. The output increases. The learning does not. More gets shipped. The quality of the decisions behind what gets shipped stays the same.

The bottleneck was never typing speed. It was judgment about what to build next. AI makes production cheaper. It does not make judgment better. And judgment improves when engineering teams are part of the experimentation loop, observing user behavior, and feeding what they learn back into what gets built.

Cheap code production also creates a new trap. It tempts teams to build more without observing more. If you spin up ten prototypes but never watch how users interact with any of them, you have not increased your learning rate. You have increased your output. The observability and feedback loop work matters more now, not less.

The takeaway

The product-engineering experimentation gap is one of the most expensive misalignments in modern software companies. Product teams experiment. Engineering teams execute. And the boundary between them is where refinement goes to die.

The teams that will move fastest are the ones where engineering participates in the experimentation loop, not just the delivery pipeline. Where code is understood as a refinement tool for validated ideas, not just an execution artifact. Where engineers understand why they are building, not just what.

One question for your next kickoff

The next time you start a new product or feature in unfamiliar territory, ask the team: "What are we trying to learn from this build, and how will we know if we learned it?"

If the answer is clear, your engineering team is part of the discovery loop.

If the answer is "we are building what the spec says," the gap is still open.

Build, Scale, Succeed

Join others receiving expert advice on
engineering and product development.

Newsletter Subscription

No data sharing. Unsubscribe at any time.