Working With Developers, Not Against Them
The previous page was about a single artifact — a bug report crafted so a developer can reproduce, diagnose, and fix without a second conversation. This page zooms out from the artifact to the relationship that produces it. A perfectly written bug report handed across a hostile wall still lands badly. The report is a message; the relationship is the channel it travels through.
There is a story software teams tell themselves so often it feels like the natural order of things: developers build, testers break, and the two are natural adversaries locked in a game of catch-me-if-you-can. It is a bad story, and it produces bad software. The goal was never to catch a developer out. The goal is a working product. Everything on this page follows from taking that sentence literally.
Hold that goal fixed and the adversarial posture stops making sense. A tester and a developer both want the same thing — software that works — so they are on the same side by construction; the bug is the only thing in the room that neither of them wants. The rest of this page is what it looks like to organize a team around that fact instead of against it.
The frame decides the outcome
Section titled “The frame decides the outcome”Testing has two possible framings, and the whole team’s behavior downstream is decided by which one you pick.
POLICING FRAME PARTNERSHIP FRAME──────────────── ─────────────────tester = gatekeeper tester = quality partnerbug = a developer's failure bug = the shared enemyfinding a bug = "gotcha" finding a bug = a gift, found earlygoal = catch people out goal = a working productdev's incentive: hide/dispute bugs dev's incentive: surface bugs earlyresult: bugs go underground result: bugs come to the surfaceThe two columns describe the same activity — a person running software and reporting what they find — differing only in the meaning the team attaches to it. That meaning is not cosmetic; it changes what everyone does next.
The policing frame feels intuitive and even righteous — someone must guard the gate — but it is quietly self-defeating. If a reported bug is heard as an accusation, the rational response for anyone being accused is to minimize the surface they expose: report less, dispute more, route around the tester, ship the risky thing quietly. The frame that treats every bug as a failing drives bugs underground, which is the exact opposite of what a tester wants. You cannot find what people are motivated to hide.
The partnership frame inverts the incentive. If a bug is the shared enemy — a defect in the product both people are trying to make good — then finding one early is a win for both, and the developer’s rational move is to help you find more, sooner. Same people, same defects, opposite dynamics, entirely because of the frame. Choosing the partnership frame is not being nice; it is the strategy that surfaces the most bugs at the lowest cost.
The economic argument: the cost-of-a-bug curve
Section titled “The economic argument: the cost-of-a-bug curve”If the partnership frame were merely pleasant, you could take it or leave it. It is not merely pleasant — it is the cheaper way to build software, and there is a curve that proves it.
A defect costs more to fix the later it is found, and the growth is closer to exponential than linear. A wrong assumption caught in a design conversation is a sentence changed on a whiteboard. The same wrong assumption caught after code is written is a rewrite plus its tests. Caught in a shared environment, it is a rewrite plus a redeploy plus everyone who built on top of it. Caught in production, it is all of that plus an incident, affected users, and a fix under time pressure.
COST TO FIX ONE DEFECT (relative, illustrative — the shape is the point)
requirements/design █ ~1× coding ███ ~3–5× integration/test ██████████ ~10× production ████████████████████ ~30–100×+ └──────────────────────────────► later it's found → costlierThe exact multipliers vary by study, team, and domain, and you should treat any single number with suspicion — but the shape is one of the most robust findings in software engineering. That shape is the entire economic case for collaboration. Every activity on this page — pulling testers into design, sharing the suite, framing findings well — exists to move defect discovery left on this curve, to the cheap end. Adversarial relationships push discovery right, to the expensive end, because they suppress early signal.
Shift left: test the design, not just the code
Section titled “Shift left: test the design, not just the code”The cheapest bug to fix is the one that is never written, and the way you prevent a bug from being written is to catch the ambiguity or untestable requirement that would have caused it — before code exists.
That is what “shift left” means concretely: involve testers early, in the places where decisions are still cheap to change.
- In requirements and design. A tester’s core skill is adversarial imagination — asking “what about empty? what about a million? what about two users at once? what happens at midnight on a leap day?” Aimed at a requirement instead of a finished feature, that skill exposes gaps while they are still sentences. “The report shows recent orders” — what is recent? which timezone? are cancelled orders included? Each question closes a hole that would otherwise become a defect.
- On testability. A tester reading a design can ask the question no one else thinks to ask: how would I know this works? A requirement with no observable outcome is an oracle problem waiting to happen. Surfacing “I can’t tell if this is correct” during design forces the team to define success before building, which is a gift to everyone.
- In review. A tester reviewing a pull request is not re-checking the developer’s logic; they are asking which cases the tests don’t cover and which failure modes the change introduces. That is the adversarial mindset applied at the moment a fix is still one keystroke away.
design ──► code ──► review ──► test ──► prod ▲ ▲ ▲ │ │ │ tester here tester here tester here ◄── shift left: (ambiguity, (pairing, (missing cases, move the tester's testability) TDD) new failure modes) attention earlierNone of this replaces testing the finished thing. It adds a cheap, early pass where the tester’s judgment prevents defects instead of merely detecting them. A tester who only appears at the end is a tester used at the most expensive point on the cost curve.
Shared ownership of the suite
Section titled “Shared ownership of the suite”The second habit that separates partnership from policing is who owns the tests. In an adversarial shop, “the tests” belong to QA: developers throw code over the wall, testers write everything, and the suite becomes a thing done to the code rather than by the team.
That arrangement fails for a structural reason. The person who wrote a unit of code understands its internals, its edge cases, and its failure modes better than anyone — at the moment they wrote it. That knowledge is perishable. A developer writing a test for their own change captures it while it is fresh and cheap; a separate tester reconstructing it weeks later pays far more to learn less.
So the healthy division of labor is not “developers build, testers test.” It is by altitude:
WHO WRITES WHAT (a healthy split, not a hard wall)
developers ──► unit + integration tests for their own code (fast, close to the code, run on every change)
testers ──► the hard cases devs won't think of; exploratory testing; end-to-end and system scenarios; the test strategy; making the whole team better at testing
everyone ──► owns keeping the suite greenThe tester’s highest-value contribution is not writing every assertion. It is the adversarial imagination the rest of the team lacks, the exploratory testing no automated suite can do, and raising the whole team’s testing skill. QA is not a dumping ground for all testing work. A team that offloads all testing onto its testers has both overloaded a specialist and robbed developers of the fast, cheap feedback that comes from testing their own work while it is fresh.
There is a second, quieter benefit to developers owning their own tests: it makes tests a design tool, not just a verification one. A developer who has to write a test for a function first must answer “how would I even call this, and how would I know it worked?” — which surfaces awkward interfaces and hidden dependencies while the code is still soft. Code that is hard to test is usually hard to use; feeling that pain early, as the author, is a design signal the developer would never get from a tester writing the tests weeks later. The suite is not merely a net under the code — for the person who wrote both, it is a mirror held up to the code’s design.
Communicate findings without blame
Section titled “Communicate findings without blame”Even inside a partnership, most communication a tester does is delivering unwelcome news: this is broken. How you deliver it decides whether the news is heard as information or as an attack — and an attack triggers defense, not fixes.
The rule is simple and mechanical: describe behavior and impact, not fault. State what the software does, what you expected, and who it affects. Do not narrate who caused it or imply carelessness. The bug is the enemy; the developer is your ally against it.
BLAME FRAME BEHAVIOR-AND-IMPACT FRAME─────────── ─────────────────────────"You broke checkout." "Checkout returns a 500 when the cart is empty; users can't buy."
"Your code doesn't handle nulls — "A null customer name reaches the how did this pass review?" invoice step and crashes it. Repro: create an order via the guest flow."
"QA found another one of your bugs." "Found an edge case worth a look: two concurrent updates to the same row lose one write. Details attached."The left column contains subjects like you and your code and verbs of blame like broke and doesn’t handle. The right column contains subjects like checkout and a null name — the behavior, not the person. Same defect, same urgency, but the right column makes the developer a collaborator on a shared problem instead of a defendant. Assume good intent. Almost no defect is the product of carelessness; it is the product of a reasonable person meeting a case no one anticipated. Writing as if that is true is not naïveté — it is usually the literal truth, and it keeps the channel open.
Feedback loops developers actually value
Section titled “Feedback loops developers actually value”The final piece is the machinery, not the manners. Good intentions do not survive contact with a suite that wastes people’s time; the relationship is only as strong as the tooling that carries it. A partnership is sustained by a test suite developers trust, and trust — the willingness to act on what the suite tells you without second-guessing it — is earned by three properties.
- Fast. A suite that takes forty minutes is a suite developers stop waiting for; they push and move on, and the feedback arrives too late to be cheap. Fast feedback (seconds to a few minutes for the inner loop) is what keeps discovery on the left of the cost curve.
- Reliable. A flaky test — one that fails without a real defect — is worse than no test. The first flaky failure is investigated; the tenth is ignored; and once a red result means “probably nothing,” the suite has stopped protecting anyone. A suite people trust is a suite people keep green; a suite people distrust is one they route around.
- Low-noise. Every failure should point at a real, actionable problem. If half the failures are environment hiccups, stale data, or assertions on things that don’t matter, developers learn to squint past red — and the one failure that mattered goes with the rest.
A SUITE PEOPLE TRUST A SUITE PEOPLE ROUTE AROUND──────────────────── ───────────────────────────fast → results before you context- slow → push and forget; feedback switch away arrives too late to be cheapreliable→ red means a real defect flaky → red means "probably nothing"; real failures hide in the noiselow-noise→ every failure is actionable noisy → devs learn to ignore red
green is a meaningful signal green is meaningless; the suite the team defends is a formality nobody trustsNotice the through-line: every property is about signal quality. The suite is a feedback loop between the developer and the truth about their code, and its whole value is how much a developer can trust what it tells them. A trustworthy loop gets kept green because green means something; an untrustworthy one gets ignored, decays, and takes the partnership down with it. Building loops developers value is therefore not a nicety on top of the relationship — it is the relationship, expressed in tooling. (This connects to test maintenance and test debt: an untrusted suite is the most expensive debt of all.)
Under the hood — make the good behavior structural, not heroic
Section titled “Under the hood — make the good behavior structural, not heroic”Culture is fragile when it depends on individuals choosing to be gracious every day. The durable version of this partnership is built into the machinery, so that the collaborative behavior is the path of least resistance rather than a daily act of will. A few structural moves do most of the work:
- Run the fast suite where the developer already is. Pre-commit hooks and a fast CI job on every push mean a developer gets the tester’s signal in seconds, from their own keyboard, before anyone else sees the change. The tester’s judgment reaches the developer at the exact moment fixing is cheapest — no meeting, no ticket, no wall.
- Blameless post-incident review as a standing practice. When an escaped defect is examined, the question is “how did our process let this through, and what changes so the next one can’t?” — never “who wrote it?” A process that structurally refuses to assign blame makes it safe to surface the next bug, which is the whole detection mechanism from the Challenger lesson made routine.
- A definition of done that includes tests and review. If “done” means tests written and a reviewer’s eyes on it, then testing and review are not something imposed on a developer at the end by an adversary — they are part of what it means for the developer’s own work to be finished. Ownership moves upstream by definition.
- Quarantine flaky tests fast. The moment a test is known-flaky, it should be quarantined or fixed, not left to erode trust in every other green. Protecting the signal is protecting the relationship.
HEROIC (fragile) STRUCTURAL (durable)──────────────── ────────────────────"remember to be blameless" → blameless review is a standing ritual"please write tests" → "done" is defined to include tests"try to give feedback early" → fast CI runs on every push, automatically"don't trust flaky reds… mostly" → flaky tests are quarantined on sight
depends on everyone choosing well the good path is the default path every single day the machinery does the rememberingThe lesson is the same one that runs through this whole part: don’t rely on people being heroes. Encode the collaborative behavior into the tools and rituals so that working with each other is simply how the system is shaped.
The architect’s lens
Section titled “The architect’s lens”- Why does it exist? Because software quality is produced by a team, not extracted by an inspector at the end — and the relationship between the people who build and the people who test is itself a determinant of how many defects reach users.
- What problem does it solve? It kills the adversarial “developers build, testers break” dynamic that drives bugs underground, and replaces it with one that surfaces defects early — on the cheap, left end of the cost-of-a-bug curve.
- What are the trade-offs? Partnership is diffuse: it asks developers to own tests, testers to enter design conversations, and everyone to keep the suite green — harder to point at on an org chart than a single “QA gate,” and it demands cultural investment (blameless communication, trusted tooling) that pays back over time, not this sprint.
- When should I avoid it? Never avoid the partnership frame — but don’t over-read it into abolishing the tester’s independence. The tester’s adversarial imagination is most valuable precisely because it is not the builder’s; collaboration must not soften into a rubber stamp where no one plays the skeptic.
- What breaks if I remove it? Remove the partnership and you rebuild the wall: bugs disputed instead of fixed, testers routed around, a suite no one trusts, and defect discovery shoved right into production — the most expensive place on the curve — where the team pays for the relationship it never invested in.
Check your understanding
Section titled “Check your understanding”- Contrast the “policing” and “partnership” frames of testing. Why does the policing frame tend to reduce the number of bugs a tester actually finds?
- What is the cost-of-a-bug curve, and how is it the economic argument for pulling testers into design and review rather than only end-of-line testing?
- “Shift left” for a tester is not just testing earlier code. Give two concrete things a tester can catch in a design or requirements review that prevent a defect from ever being written.
- Why should developers write and maintain tests for their own code, and what does “QA is not a dumping ground” mean in practice? What is then the tester’s highest-value contribution?
- Rewrite this blame-framed report into a behavior-and-impact one, and say why the rewrite gets fixed faster: “You broke the export again — your code never handles empty results.”
Show answers
- Policing casts the tester as a gatekeeper and each bug as a developer’s failure, so a report is heard as an accusation; the rational response to accusation is to hide, dispute, or route around, driving bugs underground. Partnership casts the tester as a quality partner and the bug as the shared enemy, so finding one early is a win for both and developers help surface more. The policing frame reduces found bugs because you cannot find what people are motivated to hide.
- It is the robust finding that a defect costs (roughly exponentially) more to fix the later it is found — ~1× in design, ~10× in test, ~30–100×+ in production. It is the economic argument because collaboration moves defect discovery leftward to the cheap end (a design question instead of a production incident), while adversarial relationships suppress early signal and shove discovery rightward to the expensive end. The exact multipliers vary; the shape is what matters.
- Any two of: an ambiguous requirement (“recent orders” — recent by what definition? which timezone? cancelled included?); an untestable requirement (“how would I even know this works?” — forcing an observable success criterion before code exists); a missing edge case in the design (empty, one, many, concurrent, boundary-of-time). All are caught while they are still sentences, at ~1× cost.
- Because the author understands a change’s internals and edge cases best at the moment they write it, and that knowledge is perishable — so testing it then is cheapest and captures the most. “QA is not a dumping ground” means testing isn’t all offloaded onto testers; developers own their unit/integration tests and everyone keeps the suite green. The tester’s highest-value work is then the adversarial imagination the team lacks, exploratory and end-to-end testing, the test strategy, and raising the whole team’s testing skill.
- E.g.: “The export produces an empty/corrupt file when the query returns zero rows — users get a broken download. Repro: run the export with a filter that matches nothing. Details attached.” It gets fixed faster because the subject is the behavior (the export, an empty result) not the person, it states the user impact and a repro, and it assumes good intent — so the developer engages the defect as an ally instead of defending against an accusation.