The First Software Bug Is Written Before the First Line of Code. Why Testing Should Start Before Development
Share this post

Introduction

The first software defect rarely appears in source code.

It usually appears in a conversation.

It appears in a Slack message that says "let's just make it configurable" without anyone asking configurable by whom, for what, and until when. It appears in a roadmap slide that says "self-service onboarding" without anyone defining what happens when a customer's data doesn't match the happy path. It appears in a hallway conversation where a product manager says "I think finance already approved this," and an engineer nods, and nobody writes anything down, and eight months later a compliance officer asks why nobody asked.

None of that shows up in a stack trace. None of it triggers a linter. None of it fails a unit test, because there is no code yet to test. And yet every one of those moments is a defect — a defect in understanding, in agreement, in shared reality — that will eventually be reborn as a defect in software. By the time it reaches a tester's screen, it has already been rewritten twice: once as a misunderstood requirement, and once as working code that faithfully implements the misunderstanding.

This is the uncomfortable truth that most engineering organizations avoid: testing does not create quality. Testing reveals the absence of it. By the time a QA engineer opens a bug ticket, quality was already decided — usually weeks earlier, usually by people who never wrote a line of code, usually in a room (or a Zoom call) where nobody thought they were doing "quality work" at all.

Shift Left Testing tried to solve this by moving testing earlier into the development pipeline — testing during coding instead of after it. That was progress. But it quietly preserved the old assumption: that quality is something you do to software, a checkpoint bolted onto a process that starts with a developer opening an IDE. It never asked the harder question: what if the pipeline itself starts in the wrong place? What if, by the time a developer opens that IDE, the most expensive bugs have already been written — not in Java or Python or TypeScript, but in ambiguity?

This article is not about testing earlier. It's about recognizing that testing was never the beginning of the story. Quality begins during:

  • conversations, where meaning is created or lost
  • assumptions, where risk hides in plain sight
  • architecture, where structural decisions outlive the people who made them
  • prioritization, where "not now" quietly becomes "never validated"
  • product discovery, where the actual problem is defined — or misdefined

If you are a CTO, a founder, a VP Engineering, a product manager, or a tech lead, this article will ask you to relocate your mental model of "quality" from the end of the pipeline to its very beginning — to the campfire where the first idea is spoken aloud, long before anyone reaches for a keyboard.


Software Doesn't Build Itself. People Do.

Software is often discussed as if it were a natural, almost geological process — requirements "flow down," architecture "emerges," features "roll out." This language is comforting because it removes people from the equation. But nothing about software is geological. Every function, every schema, every button is the fossilized record of a decision made by a human being who was tired, or rushed, or confident, or unsure, or simply didn't know what they didn't know.

Software is not built by requirements documents. It is built by people who interpret those documents through the lens of their own assumptions, biases, incentives, and incomplete knowledge. This is not a flaw to be engineered away — it is the fundamental material engineering leaders are working with. Steel has a known tensile strength. Human understanding does not.

Consider the ordinary forces that shape a single decision before it becomes a single line of code:

Assumption. A product manager assumes engineers know that "active users" means users who logged in during the last 30 days, because that's the internal convention everyone used at their last company. The engineers, new to the company, assume "active" means "not deleted." Nobody asks. Both build with confidence. Both are wrong for six months.

Bias. A senior engineer, having been burned by over-engineering in the past, pushes for the simplest possible implementation of a permissions system. The simplification quietly drops an edge case — shared team ownership — because the engineer's last three projects never needed it. Confidence, born from real experience, becomes a blind spot.

Communication gaps. A distributed team spans four time zones. A critical clarification about how refunds should be prorated is asked in a Slack thread at 6 p.m. in one office and answered at 9 a.m. the next day in another. In the 15 hours between question and answer, two developers have already written code based on their best guess.

Knowledge gaps. A backend engineer does not know that the finance team reconciles invoices monthly and assumes daily reconciliation is close enough. Nobody told them otherwise, because nobody thought to ask whether they knew.

Organizational complexity. A feature touches three teams — growth, platform, and billing — each with a different roadmap, different incentives, and different definitions of "done." The feature ships when two of the three teams believe it's ready. The third team finds out in production.

None of these are technical failures. All of them become technical failures. This is the core reframe this article asks you to make: software is a crystallized record of human understanding at a moment in time. When that understanding is incomplete, contradictory, or silently assumed, the software will be incomplete, contradictory, and silently broken — no matter how skilled the engineers who write it.

The Campfire

Picture a campfire at dusk. No laptops. No code. Just people, seated in a loose circle, talking. One person describes a problem a customer had. Another suggests a solution. A third nods, only half-listening, thinking about something else the customer said last week. The fire crackles. Ideas pass from mouth to mouth like sparks jumping between logs.

This is where software actually begins — not at a keyboard, but around a campfire of shared understanding that is far less "shared" than anyone in the circle believes. Some ideas around that fire are true. Some are almost true. Some are confidently wrong. And every misunderstanding that leaves the campfire uncorrected will, months later, arrive on a tester's desk wearing the disguise of a "bug," when it was actually a story that got retold slightly wrong at every step of its journey.

Engineering leaders who understand this stop asking "how do we test better?" and start asking "how do we listen better, at the campfire, before the story leaves the fire?"


Every Feature Starts As A Story

Every feature that has ever shipped — every checkout flow, every dashboard, every dark-mode toggle — began its life not as code but as a story. Someone told it. In a meeting. On a whiteboard. In a rushed voice memo recorded in a parking lot after a customer call. In an email with the subject line "quick idea." In a moment of frustration: "why can't the app just do this already?"

Stories are wonderful. They carry intent, emotion, and context that a Jira ticket never can. But stories are also unstable. Every time a story is retold — by a founder to a product manager, by a product manager to a tech lead, by a tech lead to a developer, by a developer to a code reviewer — some part of it is compressed, some part is embellished, and some part is quietly dropped because the person retelling it didn't think it mattered.

This is not a moral failing. It is how human communication works. Ask any journalist, any historian, any translator: meaning degrades with every retelling unless someone actively works to preserve it. Software teams rarely do that work, because they don't recognize it as engineering work. It looks like "just talking."

Story River

Imagine a river, and floating on its surface, paper notes — not neatly stacked, but drifting, some face-up, some face-down, some already soaked through and illegible. The river carries them downstream through five distinct bends:

VisionConversationRequirementDesignDevelopmentRelease

At the Vision bend, the note reads something ambitious and slightly vague: "Help customers self-serve so support tickets go down." By the time that note reaches the Conversation bend, someone has interpreted "self-serve" as "add a help center." By the Requirement bend, someone else has interpreted "help center" as "an FAQ page with search." By the Design bend, "search" has quietly become "a text box that filters a hardcoded list of 12 articles." By Development, the engineer builds exactly that — competently, cleanly, on time. By Release, the original vision — reducing support tickets — is nowhere to be found in the finished feature, because at some bend in the river, the note that carried the why fell into the water and dissolved.

This is not a hypothetical. This is the ordinary lifecycle of most product ideas in most companies. The river doesn't lose information because people are careless. It loses information because nobody is assigned to watch the notes as they float, to fish out the ones that are sinking, to ask "wait — does this still say what it originally said?"

Engineering leaders who take quality seriously assign that job to someone, explicitly, at every bend. Not as a formality. As a discipline. The question is never "did we build what was in the ticket?" The question is "does what we built still answer the original story?"


The Cost Of Invisible Assumptions

If stories are the water, assumptions are the fog that settles over the river at night — present everywhere, visible nowhere, until something collides with what nobody could see.

An assumption is a belief nobody stated because everybody assumed everybody else already knew it. This is precisely what makes assumptions more dangerous than mistakes. A mistake gets corrected the moment someone notices it. An assumption doesn't get corrected because nobody knows it needs correcting — including the person who holds it.

Common invisible assumptions that quietly script future bugs:

  • "Obviously the export feature needs to handle files over 1GB" — obvious to the data engineer who has seen enterprise customers, invisible to the frontend developer who tested with a 40KB CSV.
  • "Of course we'll need audit logs for this — it's touching payment data" — obvious to the compliance-minded architect, invisible to the product manager optimizing for speed to market.
  • "We'll handle time zones the same way we always do" — except "always" was undocumented tribal knowledge that left the company when the last two backend engineers did.
  • "The client said 'real-time' but they probably mean 'fast,' not literally real-time" — a translation performed silently, in someone's head, and never verified with the client.

Each of these assumptions feels, in the moment, like common sense. That is exactly the danger. Common sense is not common — it is deeply personal, shaped by each person's specific experience, and it varies wildly across roles, teams, and companies. What is "obvious" to a senior backend engineer who has been burned by timezone bugs before is invisible to a junior frontend developer who has never touched that part of the system.

Foggy Bridge

Picture a long stone bridge disappearing into thick fog. You can see the first ten meters clearly. Beyond that: nothing. Teams that move fast without clarifying questions are like travelers sprinting across that bridge in the fog — confident, because the ten visible meters look solid, unaware that the bridge may be missing a section forty meters ahead, or may not lead to the destination they think it does.

The farther a team moves without stopping to clarify, the greater the risk compounds — not linearly, but exponentially, because each unclarified assumption becomes the foundation for the next decision. An assumption about "what counts as an active subscription" becomes the foundation for a billing rule, which becomes the foundation for a dunning email sequence, which becomes the foundation for a churn dashboard the board reviews quarterly. By the time someone notices the original assumption was wrong, it has three stories built on top of it, and correcting it requires demolishing all four.

The discipline that prevents this is not "more testing." It is the deliberate, uncomfortable practice of asking questions early, even when — especially when — everyone in the room seems to already agree. Agreement without articulation is not alignment. It's just silence that hasn't been tested yet.


Software Quality Is Built With Questions

If tests are how you verify code, questions are how you verify understanding — and understanding is the actual product being built during discovery. A test can only check whether code does what someone decided it should do. A question checks whether that decision was the right one in the first place.

Here are forty questions that, asked before a single line of code is written, prevent far more defects than any test suite written after the fact.

Clarifying intent

  1. What problem are we actually solving — not the feature, the problem?
  2. Who specifically has this problem, and how do we know?
  3. What does success look like in numbers, not adjectives?
  4. What happens if we do nothing?
  5. Is this the smallest version of the idea that still solves the problem?

Surfacing assumptions 6. What are we assuming about the user that we haven't verified? 7. What are we assuming about the data that we haven't verified? 8. What are we assuming another team will handle? 9. What did we agree on without saying it out loud? 10. If this assumption is wrong, what breaks?

Finding the edges 11. What happens if this input is empty? 12. What happens if this input is enormous? 13. What happens if the user does this twice, quickly? 14. What happens if two people do this at the same time? 15. What happens if the network fails halfway through? 16. What is the very first thing a new user sees, and does it make sense with zero data? 17. What happens on the last day of a billing cycle, a leap year, or a time-zone change?

Ownership and rules 18. Who owns this business rule, and can we ask them directly? 19. Is this rule written down anywhere, or does it live in someone's memory? 20. What happens when this rule conflicts with a different team's rule? 21. Who is allowed to change this rule after we launch? 22. What happens if this rule is wrong for one customer but right for a thousand others?

Security and trust 23. What is the worst thing a malicious user could do with this feature? 24. What data does this feature expose that it doesn't need to? 25. Who can see this data, and who explicitly should not? 26. What happens if someone tries this feature without permission? 27. What happens if credentials, tokens, or sessions expire mid-action?

Performance and scale 28. What does this feature look like with 10 users? With 10 million? 29. What is the slowest acceptable response time, and who decided that? 30. What happens when this feature succeeds too well and gets ten times the expected traffic?

Accessibility and inclusion 31. Can someone using only a keyboard complete this flow? 32. Does this work for someone who doesn't speak the primary language? 33. Does this depend on an assumption about a "typical" user that excludes real users?

Compliance and risk 34. Does this touch regulated data — health, financial, personal? 35. Who needs to approve this before it ships, and have we asked them? 36. What is the cost if this is wrong for a single customer versus every customer?

Reliability and operations 37. How will we know if this breaks in production before a customer tells us? 38. Can this be turned off quickly if something goes wrong? 39. Who is on call for this, and do they know it exists?

The one question that catches everything else 40. What are we most afraid someone will ask us about this feature — and have we answered it yet?

None of these questions require a QA certification to ask. They require curiosity, humility, and a culture that rewards the person who says "wait, what happens if—" instead of quietly filing that thought away as a distraction from velocity.

Question Lantern

Imagine a lantern held up in a dark room, its light splitting into distinct beams as it passes through a faceted glass shade — one beam falling on a stack of documents labeled Security, another on a ledger labeled Business, another on a gauge labeled Performance, another on a ramp labeled Accessibility, another on a switchboard labeled Reliability, another on a sealed folder labeled Compliance. The lantern doesn't create these risks. It simply reveals what was already sitting in the dark, waiting to be discovered by a customer instead of by a question.

The best engineering organizations don't have more testers. They have more people, across more roles, who feel safe holding up the lantern before the room goes quiet and everyone agrees to just start building.


The Architecture Of Trust

Quality is often discussed as a technical property: does the code do what it's supposed to do? But underneath every technical definition of quality is a social one: do the people building this system trust that the decisions behind it are sound?

Trust is not a soft, secondary concern bolted onto engineering culture. It is structural. When a developer trusts that a requirement has been thought through, they build with confidence and speed. When they don't — when they suspect the requirement is shaky, the priority is arbitrary, or the deadline is political rather than technical — they either slow down defensively (guessing at edge cases nobody confirmed) or, worse, they stop caring about edge cases entirely, because why invest effort in a decision that might be reversed next sprint anyway?

This is why quality engineering is inseparable from:

  • Ownership — a rule, a decision, or a piece of data has a name attached to it, someone who can be asked and who is expected to answer.
  • Documentation — not exhaustive documentation for its own sake, but the specific record of why a decision was made, so the next person doesn't have to reverse-engineer intent from code six months later.
  • Shared understanding — the difference between a team that read the same document and a team that discussed the same document until everyone could explain it in their own words.
  • Systems thinking — recognizing that a decision in the billing system has consequences in the support system, the analytics system, and the sales team's commission calculations, even though nobody explicitly connected those dots.
  • Decision-making — a visible, traceable process for how a choice was made, so that when it turns out to be wrong, the team can learn from how the decision was reached, not just that it was wrong.

Stone Cathedral

Software is often described with construction metaphors — "building" a feature, laying a "foundation." But most teams treat this metaphor too casually, as if software were poured concrete: fast, uniform, forgiving of small errors because the whole mass sets together.

A better image is a stone cathedral, built one stone at a time, over years, by many hands who never all worked together at once. Each stone is a decision: an architecture choice, a data model, a conversation that resolved an ambiguity, a code review that caught a flawed assumption. No single stone holds up the cathedral. But a poorly placed stone in the foundation — one set without proper thought, in a rush, because the mason had a deadline — doesn't just weaken itself. It transfers stress to every stone placed on top of it for years afterward, in ways nobody can see until, decades later, a crack appears in a ceiling nowhere near the original flaw.

This is why "we'll fix it later" is one of the most expensive sentences in software. It is not a promise. It is a stone being placed carelessly, on the assumption that future masons will notice and correct it — when in reality, future masons build confidently on top of what's already there, trusting that the stones beneath them were placed with care. Structural integrity in software, as in cathedrals, is not the presence of strong stones. It's the absence of weak ones nobody flagged.


When Teams Start Coding Too Early

There is a particular kind of energy in engineering organizations that feels like productivity but is actually its opposite: the rush to start coding before a decision has been made. It feels like momentum. It looks like progress in a status update. And it is one of the most reliable predictors of expensive rework six months later.

Teams start coding too early for understandable, even sympathetic reasons:

  • Deadline pressure makes "we're already building it" feel safer than "we're still clarifying it," even when the clarifying work would take two days and save two months.
  • Feature rush, driven by competitive anxiety or a leadership mandate to "ship something," rewards visible activity over invisible thinking.
  • False productivity — the comforting illusion that a growing codebase equals progress, even when it's built on a shaky, unvalidated premise.
  • Technical debt normalization — a culture where "we'll refactor later" has been said so often that it has stopped meaning anything, including to the people saying it.
  • Late discovery — the moment, usually during a demo or a customer pilot, when someone finally asks the question that should have been asked in week one, and the answer forces a redesign of something already built.

Train Leaving The Station

Picture a train platform. The train is scheduled to leave at a specific time, and it will — the schedule is the deadline, and deadlines in most organizations are treated as fixed, sacred, non-negotiable. On the platform stand several passengers, each representing a perspective that should board before departure: Requirements. Architecture. QA. Security. Product. Operations.

The whistle blows. Some of the passengers have boarded. Others are still walking across the platform, still mid-conversation, still waiting for an answer to a question they asked an hour ago. The train doors close anyway. The train leaves — because the schedule, not the readiness of the passengers, is what everyone agreed to protect.

The passengers left on the platform don't disappear. They catch a later train — usually much later, usually at a much higher cost, usually disguised as a "hotfix," an "incident," or an "unplanned sprint." Security review that didn't board before launch reappears three months later as a penetration test finding that requires an emergency patch. QA that didn't board reappears as a customer-reported outage. Product clarity that didn't board reappears as a support escalation about a feature that "doesn't do what customers expected," which is really just the original ambiguity, finally surfacing where it's most expensive to fix: in front of a paying customer.

Every leader who has said "we don't have time to wait for that answer, let's just start building" has, in effect, let the train leave the station without a passenger who was trying to prevent exactly the fire the team will be fighting later. The train always looks like it left on time. It rarely looks like it left incomplete — until the incomplete part becomes unavoidable.


The Meetings That Prevent Thousands Of Bugs

If the previous sections have made the case that quality is decided in conversation, this section makes the practical case: which conversations, specifically, and how should they be structured so they actually work?

Not all meetings are quality activities. A status update is not a quality activity. A meeting that exists only to report progress everyone could have read in a ticket is a meeting that consumes calendar time without reducing risk. But certain meeting formats — when run with discipline, not as a checkbox — are among the highest-leverage quality activities an organization can invest in, precisely because they happen before code exists, when changing a decision costs a sentence instead of a sprint.

Example Mapping. A structured conversation, typically 30–60 minutes, where a team takes a single rule or story and explores it through concrete examples: "Give me an example of a customer this rule applies to. Now give me an example where it doesn't." Example Mapping is powerful because it makes ambiguity impossible to hide — vague language survives in prose, but it collapses immediately when someone has to produce a specific example.

Three Amigos. A conversation, ideally before a story enters a sprint, between three perspectives: someone who represents the business/product view, someone who represents the technical/engineering view, and someone who represents the testing/quality view. The magic of Three Amigos isn't the number three — it's the deliberate presence of a perspective whose entire job is to ask "what could go wrong here?" before anyone has invested effort in an answer.

BDD (Behavior-Driven Development) conversations — not the automation frameworks that often get bolted onto BDD later, but the conversation at its core: describing behavior in terms of concrete scenarios ("given this situation, when this happens, then this should be true") before any code is written. Done well, this conversation is where ambiguous requirements get forced into unambiguous, testable language — not by a tester writing test cases, but by the whole team agreeing on what "correct" actually means.

Architecture workshops. A room (physical or virtual) where the people who will build a system, and the people who will depend on it, sketch out the structure together — not to produce a perfect diagram, but to surface disagreements about how components should interact before those disagreements get encoded, silently, into incompatible implementations built by teams who never had this conversation.

Design reviews. Not rubber-stamp approvals, but genuine scrutiny of a proposed approach by people who didn't design it — because the person who designed a solution is structurally the worst-positioned person to spot its blind spots. They already believe it works. That's why they designed it that way.

Risk reviews. A deliberate, scheduled conversation whose only purpose is to ask "what's the worst thing that could happen here, and how likely is it?" — treated as seriously as a budget review, because the cost of an unmitigated risk is frequently larger than the cost of the budget it was traded against.

Event Storming. A collaborative technique where a team maps out a business process as a sequence of events, commands, and decisions — often revealing, in the first ten minutes, that different people in the room have fundamentally different mental models of how the business actually works. This disagreement, surfaced on a wall of sticky notes, is infinitely cheaper to resolve than the same disagreement discovered after two systems have been built to reflect two different, incompatible models.

Chess Board

Picture a chessboard where the pieces are not knights and bishops but disciplines: Business. Engineering. QA. UX. Security. Operations. Each occupies its own square, and each has its own way of moving — Business moves in bold, sweeping lines driven by market timing; Engineering moves carefully, constrained by what the board's structure allows; Security moves diagonally, always watching for an attack nobody else is looking for; Operations moves one square at a time, deliberate, because it's the piece that has to live with every consequence of every other piece's move.

The mistake most organizations make is playing this game as if only one piece is on the board — usually Engineering, or Business — and being genuinely surprised, months later, when a move that looked perfectly safe from one piece's perspective turns out to have left another piece exposed. A design decision that looked elegant to Engineering left Operations with no way to monitor it. A pricing decision that looked smart to Business left Security holding a compliance gap nobody flagged.

Good discovery meetings are not decoration. They are the moments when all six pieces are actually on the board, actually visible to each other, before a single irreversible move is made.


Quality Before Coding

Long before a developer writes a function, a well-run discovery process produces a set of artifacts that most organizations mistakenly categorize as "product" or "design" work — separate from, and lower-status than, "engineering" work. This categorization is a mistake. These artifacts are quality artifacts. They are, in a very real sense, the first test suite a feature ever has — except instead of testing code, they test understanding.

Wireframes test whether a proposed interface actually matches how a real user would try to accomplish their goal — before a single pixel of production CSS is written. A wireframe that confuses a stakeholder in a five-minute review has just saved weeks of frontend work built on a confusing flow.

Data models test whether the team's mental model of the business actually holds together. Trying to model "a customer can belong to multiple organizations, but only one can be the billing owner, unless it's an enterprise account" as an actual schema — with actual foreign keys and constraints — exposes contradictions that survive comfortably in a sentence but collapse the moment someone tries to draw them as a table.

API contracts test whether two teams that will never sit in the same meeting still agree on what data means. An API contract that specifies status: "active" | "cancelled" | "paused" forces a conversation that a shared verbal understanding of "active" never would have forced: what happens to a paused subscription's data — is it still counted as revenue? The contract cannot be written without answering that question. That's the point.

Acceptance criteria test whether "done" has actually been defined, or whether it's a feeling everyone privately hopes they share. Acceptance criteria written as concrete, falsifiable statements — "a user with an expired card sees this specific error message, not a generic failure" — remove the ambiguity that would otherwise be resolved, inconsistently, by whichever engineer happens to write that part of the code.

Threat models test whether anyone has thought about this feature from an adversary's perspective before an actual adversary does. A lightweight threat-modeling exercise — "how would I abuse this if I were trying to?" — run for thirty minutes before development, routinely surfaces vulnerabilities that would otherwise be discovered during a penetration test, a compliance audit, or, worst of all, a breach.

User journeys test whether the feature makes sense in the context of everything around it, not in isolation. A feature that looks perfect on its own slide often falls apart the moment someone maps the five steps a real user takes before and after using it.

The Workshop Wall

Picture a large wall covered in sticky notes, sketches, printed screenshots of a competitor's product, a hand-drawn customer journey with arrows and question marks, a few index cards labeled with risks, a wireframe taped up crookedly, someone's handwritten list of "things we're not sure about yet." No code. No IDE. No terminal window in sight.

This wall is not a mess to be cleaned up before "real work" begins. This wall is the real work. Every element on it is a quality artifact — evidence that a team stopped to think, to sketch, to disagree, to write down what it didn't yet know, before it committed that uncertainty permanently into a codebase where uncertainty is far more expensive to correct.

Two additional images belong in this same family of "quality before code" artifacts. The first is the Blueprint Scroll — an architect's rolled parchment, unfurled to reveal not a finished building but a set of annotated, still-negotiable structural decisions, with margin notes and crossed-out revisions visible, showing that even blueprints are drafts, meant to be argued with before they're finalized. The second is the Origami Blueprint — a single sheet of paper, folded and refolded into a complex shape, representing how a simple idea (a flat sheet) becomes something structurally complex (a folded form) through a precise sequence of decisions — and how, if any single fold is made incorrectly early in the sequence, every subsequent fold inherits and compounds that error, producing a final shape that looks deliberate but is actually the visible record of one small early mistake.


Thinking Like A Tester Before Development

There is a mindset associated with skilled testers that is far more valuable, and far more portable, than any specific testing technique: a particular way of looking at a system and asking "what haven't we considered?" This mindset — critical thinking, systems thinking, curiosity, risk awareness, business empathy, and a sense of ownership over outcomes rather than just outputs — is not exclusive to people with "QA" in their title. It is a discipline that every role in a discovery process should practice, because every role has blind spots that only this mindset reliably catches.

Critical thinking means treating every stated requirement as a hypothesis, not a fact, until it's been examined. Not out of distrust of the person who stated it, but out of respect for how easily good people state incomplete things with full confidence.

Systems thinking means recognizing that no feature exists in isolation — that a change to how discounts are calculated will eventually touch reporting, tax calculations, refund logic, and the sales team's commission structure, whether or not anyone explicitly traced those connections in advance.

Curiosity means being the person in the room who asks "but what if—" even when the room's energy is pushing toward "let's just move on," because momentum is not the same thing as correctness, and a team that never slows down to ask "what if" is a team that will eventually be slowed down by production, at a much higher cost.

Risk awareness means holding two questions simultaneously — "how likely is this to go wrong?" and "how bad would it be if it did?" — and recognizing that a low-probability, high-severity risk (a rare but catastrophic data-loss bug) often deserves more attention than a high-probability, low-severity one (a slightly misaligned button).

Business empathy means understanding that a decision that looks like the "right" engineering choice can be the wrong business choice, and that a good discovery process must hold both truths without letting either one silently override the other.

Ownership means treating "this isn't my part of the system" as an unacceptable answer to the question "did anyone check this?" — because the customer experiencing a bug has no concept of which team owned which microservice.

The Observatory

Picture an observatory, but instead of a telescope pointed at the night sky, the instrument is pointed at the system being built, and instead of stars, the observer studies seven distinct fields of light: Users. Business. Technology. Operations. Compliance. Support. Quality. Each field, when observed carefully, reveals patterns invisible from the others — a risk visible from the Compliance field that is completely invisible from the Technology field; a user-behavior pattern visible from the Users field that contradicts an assumption baked into the Business field's projections.

The discipline of "thinking like a tester before development" is really the discipline of rotating this telescope deliberately through all seven fields before committing to a plan — rather than pointing it once, at whichever field is most comfortable or most familiar, and calling the observation complete.


Real Case Study: Two SaaS Companies, One Fork In The Road

Consider two fictional companies — call them Ferrix and Lantern Cloud — both B2B SaaS companies building similar products: workflow automation tools for mid-market operations teams. Both start the same quarter with the same ambition: launch a new "conditional approval routing" feature that lets customers set up multi-step approval chains for internal requests.

Ferrix operates with a feature-first culture. The roadmap is driven by competitive pressure — a rival just launched something similar, and leadership wants parity within six weeks. The product manager writes a concise one-page spec: "Allow admins to set up approval chains with multiple steps." Engineering, eager to move fast, begins building immediately. Questions that arise mid-development — "what happens if an approver is deactivated mid-chain?" "what happens if two steps are set to run in parallel and one rejects while the other approves?" — get answered ad hoc, by whichever engineer is writing that part of the code, based on their best guess, because stopping to ask feels like it would blow the six-week deadline.

The feature ships on time. It demos beautifully. Then real customers start using it. Within three weeks: a customer's approval chain silently breaks when a manager goes on leave and their account is deactivated, and nobody is notified — the request simply stalls forever. Another customer discovers that parallel approval steps produce inconsistent results depending on which approval arrives first, a race condition nobody thought to test because nobody thought to discuss it. Support tickets spike. Two engineers are pulled off the next roadmap item to firefight. The fix takes five weeks — almost as long as the original build — because correcting the underlying data model (which didn't account for reassigned approvers) requires a migration, not a patch.

Lantern Cloud, tackling the identical feature in the same timeframe, runs a two-day discovery process before writing code: an Example Mapping session that surfaces eleven concrete scenarios (including "an approver is deactivated mid-chain" and "two parallel steps resolve in conflicting order"), a data-model review that forces the team to decide, explicitly, how reassignment should work, and a thirty-minute risk review that flags the parallel-approval race condition as a "must resolve before launch" item. The discovery process takes two days and delays the start of coding by two days. Development takes four weeks — slightly longer than Ferrix's rushed six, because the more complete data model requires a bit more upfront engineering — but ships with zero critical incidents in the following two months. No firefighting sprint. No emergency migration.

Measured business impact, 90 days post-launch:

  • Ferrix: 2 critical incidents, 5 engineer-weeks of unplanned firefighting, a customer churn event directly attributed to the deactivated-approver bug, and a support team absorbing an ongoing trickle of confused tickets about approval chain behavior.
  • Lantern Cloud: 0 critical incidents, 0 unplanned firefighting weeks, and — because the discovery process forced clarity on edge cases — a support team that could answer customer questions from documentation instead of escalating them to engineering.

Ferrix's team was not less skilled than Lantern Cloud's. They wrote comparable code, with comparable competence, in a comparable language. The difference was not talent. It was where the team invested its thinking — during a rushed six weeks of coding, versus two days of discovery followed by four weeks of coding built on decisions that had already survived scrutiny.

This is the pattern engineering leaders should internalize: the choice is never "spend time on discovery" versus "save time by skipping it." It is "spend a small amount of time on discovery now" versus "spend a much larger amount of time on discovery later, disguised as debugging, after a customer has already been affected."


25 Decisions That Create Bugs Before Coding

Not coding mistakes — decision mistakes. Each of these is a choice made during planning, prioritization, or discovery that reliably produces defects later, along with the future consequence it tends to cause and the practice that prevents it.

  1. Approving a feature based on a one-line description. Consequence: engineers fill the gaps with private assumptions that never get reconciled. Prevention: require a concrete example before approval, not just a description.
  2. Skipping the "who owns this rule" question. Consequence: a business rule gets implemented based on guesswork and contradicts the actual policy discovered later. Prevention: name an owner for every non-trivial rule before development starts.
  3. Treating a deadline as more fixed than the scope. Consequence: scope quietly balloons to match ambition while the deadline stays fixed, guaranteeing a rushed final stretch. Prevention: treat scope as the flexible variable, not the last thing cut.
  4. Assuming "the client will tell us if something's wrong." Consequence: clients discover ambiguity by using the product incorrectly, not by raising a question. Prevention: proactively surface ambiguity through examples before build, not after feedback.
  5. Letting one team define a shared concept unilaterally. Consequence: two systems encode two different definitions of the same word (e.g., "active"), producing subtly wrong reports later. Prevention: define shared terms in a single glossary, reviewed by every team that touches the concept.
  6. Skipping a risk review because the feature "feels simple." Consequence: the simplest-looking features often hide the most business logic (see: date handling, currency rounding). Prevention: apply the risk-review discipline uniformly, not based on how the feature "feels."
  7. Deferring the "what happens when this fails" question. Consequence: failure paths get built as an afterthought, often producing confusing or silent failures. Prevention: design the failure path with the same rigor as the success path, before coding begins.
  8. Not asking who will maintain this after the original team moves on. Consequence: undocumented tribal knowledge disappears with the people who leave, and the next team rediscovers the same bugs. Prevention: document intent, not just implementation, as a release requirement.
  9. Assuming a competitor's approach is automatically the right approach. Consequence: copying a visible feature without understanding the invisible business logic behind it produces a shallow, broken imitation. Prevention: validate the underlying problem independently, rather than reverse-engineering a competitor's UI.
  10. Letting the loudest voice in the room define the requirement. Consequence: quieter but more informed perspectives (often support or ops) get overridden, and their concerns resurface later as incidents. Prevention: structure discovery meetings to explicitly solicit dissent, not just agreement.
  11. Treating "we'll fix it in v2" as a plan rather than a risk. Consequence: v2 rarely arrives before the gap becomes a customer-facing problem. Prevention: if a gap is significant enough to defer, document it as an active risk with an owner and a trigger for revisiting it.
  12. Not defining what data must be true for the feature to make sense. Consequence: the feature works in a demo with clean sample data and breaks on real, messy production data. Prevention: test the data model against real (or realistically messy) data before, not after, development.
  13. Assuming internal tools don't need the same rigor as customer-facing ones. Consequence: an internal tool becomes business-critical over time, and its lack of rigor becomes an operational risk nobody planned for. Prevention: apply proportional, not zero, rigor to internal tools based on their actual blast radius.
  14. Skipping alignment between engineering and legal/compliance early. Consequence: a feature ships and is later found to violate a regulation, requiring a retroactive and expensive redesign. Prevention: involve compliance in discovery for any feature touching regulated data, not just before launch.
  15. Assuming "most users" behavior applies to all users. Consequence: edge-case users (a small percentage, but often the most vocal or most valuable) hit unhandled scenarios. Prevention: explicitly discuss the boundaries of "most," and decide, consciously, what happens outside them.
  16. Confusing "technically possible" with "operationally sustainable." Consequence: a feature that works at launch becomes unmaintainable at scale because operational cost was never discussed. Prevention: include an operations perspective in discovery, not just an engineering one.
  17. Not validating a growth assumption before building for it. Consequence: infrastructure and logic are built for a scale that never materializes, wasting effort, or built for a scale that's exceeded immediately, causing outages. Prevention: validate growth assumptions against real data before architecting around them.
  18. Letting a feature's name shape its scope. Consequence: a feature called "notifications" quietly expands to include everything anyone associates with the word, without anyone deciding that expansion deliberately. Prevention: define scope by explicit inclusion and exclusion, not by the connotations of a name.
  19. Assuming a previous decision is still valid without re-checking it. Consequence: a rule made a year ago, under different circumstances, gets built upon as if it were still true. Prevention: re-validate load-bearing assumptions periodically, especially before major new features depend on them.
  20. Not distinguishing between "nice to have" and "silently expected." Consequence: something users consider a baseline expectation (e.g., data export) gets deprioritized as optional, and its absence is experienced as a broken product, not a missing feature. Prevention: explicitly ask what users would consider a failure, not just what they've requested.
  21. Trusting a stakeholder's summary of a customer conversation instead of the raw conversation. Consequence: nuance and caveats get lost in translation, and the team builds toward a flattened version of what the customer actually said. Prevention: whenever feasible, review the original source (call recording, transcript) rather than a secondhand summary for load-bearing decisions.
  22. Approving a design without asking how it fails gracefully. Consequence: the feature works perfectly until something unexpected happens, at which point it fails in a way that confuses or alarms the user. Prevention: require a documented graceful-failure behavior as part of design approval.
  23. Assuming security is someone else's job at the discovery stage. Consequence: security is bolted on late, often incompletely, because the architecture wasn't designed with it in mind. Prevention: include a lightweight threat-modeling pass in every discovery process touching sensitive data or access control.
  24. Treating a prototype's success as proof the real feature will succeed. Consequence: a prototype tested with friendly internal users or a curated demo dataset hides problems that appear with real, adversarial, or careless users. Prevention: validate with realistic conditions, not just favorable ones.
  25. Not asking "what would make us regret shipping this?" before shipping it. Consequence: teams discover regret only after a customer, a journalist, or an auditor points it out. Prevention: make this question a standing, explicit part of every pre-launch review — not a rhetorical one, but one someone is required to answer in writing.

Decision Seeds Growing Into Trees

Picture a single seed being planted, and beside it, a time-lapse sequence showing it grow into a tree — except the tree's final shape (crooked, leaning, or split at the trunk) was entirely determined by a small, invisible flaw in the seed itself, or by the angle at which it was first planted. By the time the tree is fully grown, the flaw is enormous and impossible to hide. But it was always there, in miniature, from the very first day — visible only to someone who thought to examine the seed closely before planting it.

Every one of the twenty-five decisions above is a seed. The tree it grows into — whether a stable, load-bearing structure or a slow-motion structural failure — is determined long before anyone sees leaves.


The CTO Checklist: 50 Questions Before Approving Development

This checklist is designed to be used by engineering leaders — CTOs, VPs of Engineering, or engineering managers — as a gate before a feature moves from discovery into active development. It is not a bureaucratic form to be filled out mechanically. It is a discipline: if a leader cannot answer most of these questions confidently, that is information, not an inconvenience.

Problem and intent

  1. What specific problem does this solve, in one sentence a customer would recognize?
  2. How do we know this problem is real, and not assumed?
  3. What does success look like, quantitatively, 90 days after launch?
  4. What is the smallest version of this that still solves the problem?
  5. What happens if we don't build this at all?

Assumptions and ownership 6. What are the three riskiest assumptions this plan depends on? 7. Who owns each business rule this feature depends on? 8. Have those owners actually reviewed and confirmed the rule, or are we assuming it? 9. What have we agreed on verbally that hasn't been written down anywhere? 10. Which team's roadmap does this quietly depend on, and do they know that?

Edge cases and failure 11. What happens with zero data, one record, and an extreme volume of data? 12. What happens if two users perform this action simultaneously? 13. What happens if a required external service is unavailable? 14. What is the graceful failure behavior, and has anyone actually reviewed it? 15. What happens at time-based boundaries — midnight, month-end, year-end, leap years?

Security and access 16. What is the worst thing a malicious actor could do with this feature? 17. What sensitive data does this feature touch, and who can access it? 18. Has this been reviewed by someone with a security mindset, not just a feature mindset? 19. What happens if authentication or authorization fails mid-action? 20. Are there audit or logging requirements we haven't yet defined?

Compliance and legal 21. Does this touch regulated data (financial, health, personal, biometric)? 22. Has legal or compliance reviewed this, if relevant? 23. What jurisdictions does this need to work correctly in, and do their rules differ? 24. What is our data retention and deletion policy for anything new this feature creates?

Architecture and systems impact 25. What other systems does this feature touch, directly or indirectly? 26. What breaks in adjacent systems if this feature behaves unexpectedly? 27. Does this introduce a new source of truth, and if so, is that intentional? 28. What is the migration or rollback plan if this needs to be reversed? 29. Have we sketched the architecture with someone who didn't design it, to get a second perspective?

Performance and scale 30. What load do we expect at launch, and at 10x that volume? 31. What is the acceptable response time, and who decided that number? 32. What happens to this feature's performance as the underlying dataset grows?

Operational readiness 33. How will we know this is broken before a customer tells us? 34. Can this feature be disabled quickly if something goes wrong? 35. Who is on call for this, and have they been briefed? 36. What dashboards or alerts need to exist before, not after, launch?

Team and process 37. Has this gone through an Example Mapping, Three Amigos, or equivalent conversation? 38. Have we asked the "what are we most afraid someone will ask about this?" question, out loud? 39. Does everyone in the room agree on what "done" means for this feature, in writing? 40. Has anyone outside the immediate team reviewed this with fresh eyes?

Customer and business impact 41. What would make a customer feel this feature broke a promise, even if it "technically works"? 42. What would make us regret shipping this? 43. Who benefits most from this feature, and who might be disadvantaged by it? 44. Have we validated this with real, messy data — not just a clean demo dataset? 45. What is the support team's plan for handling questions about this feature?

Documentation and knowledge transfer 46. Is the reasoning behind key decisions documented, not just the decisions themselves? 47. Would a new engineer joining next month understand why this was built this way? 48. Is there a single source of truth for the definitions this feature depends on?

Final gate 49. If this feature fails in production, will we be surprised, or will we recognize the failure as something we already discussed and accepted the risk of? 50. Are we approving this because it's ready, or because the deadline arrived?

A leader who runs a feature through this checklist honestly, even briefly, will frequently find three or four questions with no good answer. That is not a failure of the checklist. That is the checklist doing exactly its job: finding the bug before it's written into code.

Additional Visual Concepts For This Section

Broken Compass — a compass whose needle spins freely, never settling, because the magnetic field around it (representing organizational priorities) is being pulled in three directions at once by three unmarked magnets labeled only with question marks. This represents a team trying to navigate a decision without a fixed, agreed-upon "north" — without agreement on what success actually means.

Spider Web of Dependencies — a web strung between several fixed points (representing teams, systems, and stakeholders), with a single strand, once cut near the center, causing the entire structure to sag and distort far from the point of the cut. This represents how a single unclarified dependency, invisible in a discovery meeting, radiates consequences across a system in ways that are only obvious after the fact.

Handwritten Feature Map — a hand-drawn, imperfect map of a feature's territory, complete with crossed-out paths, question marks in the margins, and a small "here be dragons" label over an unexplored corner representing an untested assumption. This represents the honest, unfinished nature of real discovery work, in contrast to the polished, false-confidence of a finished roadmap slide.


Conclusion

Somewhere in every engineering organization, there is a moment that never makes it into a retrospective, a postmortem, or a sprint review: the moment, weeks or months before a bug is discovered, when someone almost asked a clarifying question — and didn't. Not out of negligence. Out of momentum, politeness, deadline pressure, or the simple, human assumption that everyone else in the room already understood what they understood.

That moment is where quality is actually decided. Not in the pull request. Not in the QA environment. Not in the automated test suite that runs on every commit. Those are the places where the consequences of that moment eventually surface — sometimes months later, dressed up as a "bug," when it was really always a decision.

This is not an argument against testing. Automated tests, exploratory testing, QA expertise — these remain essential, irreplaceable disciplines. But they are the last line of defense, not the first. They catch what discovery missed. They cannot manufacture understanding that was never built in the first place. No test suite, however comprehensive, can verify a requirement that was never actually agreed upon — it can only confirm that the code faithfully implements whatever ambiguity survived the planning process.

The best software teams don't write fewer bugs because they test more.

They write fewer bugs because they make better decisions — earlier, together, out loud, before those decisions are compiled into something far more expensive to change: working code that everyone has already started to trust.

The campfire is still burning. The story is still being told. The question is whether anyone in the circle is listening closely enough to catch the misunderstanding before it leaves — before it becomes a requirement, a design, a deployed feature, and finally, months later, a ticket in someone's bug tracker with a severity label that should really just read: this was always going to happen.

Recent posts

July 21, 2026
AI Doesn't Hallucinate. Companies Do.
July 21, 2026
The Most Expensive Engineer On Your Team Isn't The Highest Paid One
July 21, 2026
Stop Measuring Velocity. Start Measuring Confidence.