esc
Anthology / Yagnipedia / Acceptance

Acceptance

The Fifth and Final Stage (For Most)
Phenomenon · First observed 1969 (Kübler-Ross); in software, approximately never (see Caveats) · Severity: Philosophical

Acceptance is the fifth and final stage of the Kübler-Ross model of Grief, representing the moment at which a developer stops believing the codebase should be different from what it is and begins operating within the constraints of what it actually is. It is not approval. It is not satisfaction. It is not the belief that the code is good. It is the cessation of the belief that the code should be other than what it is, which is a fundamentally different cognitive event and one that no sprint retrospective has ever successfully produced on demand.

In the context of software engineering, acceptance is the transition from suffering about the code to working with the code. The suffering was optional. The code was not.

“I am now the person who maintains this.”
— Every developer, eventually, usually on a Wednesday

Distinction from Approval

This point requires emphasis because it is universally misunderstood, including by developers who have achieved acceptance and should know better.

Acceptance is not the belief that the code is good. Acceptance is not the belief that the architecture was well-chosen, that the naming conventions are defensible, that the deployment pipeline is reasonable, or that config.bak.old.FINAL is an acceptable filename for a file that is sourced by the production deployment script and has been since 2019.

Acceptance is the cessation of the belief that these things should be different. The code is what it is. The architecture is what it is. The deployment script sources the file it sources. You have stopped expecting otherwise. You have not stopped noticing. You have stopped resisting.

There is a Buddhist concept here — non-attachment to outcomes — but bringing up Buddhism in a code review is how you get uninvited from code reviews, so the practical framing is preferred: acceptance is the moment your mental model of the codebase updates to match reality, rather than the other way around.

“The junior developer wants the code to be better. The senior developer wants the code to be better. The difference is that the senior developer has stopped making that desire a prerequisite for getting work done.”
The Lizard, in a commit message that was also the entire PR description

The Moment of Acceptance

It arrives quietly. There is no ceremony. There is no Slack notification. There is no Jira transition from “Resisting” to “Accepted.” It happens at a desk, usually alone, usually after the third cup of coffee, usually on a day of the week that contains the letter ’d'.

The developer opens utils.go. The developer does not sigh. The developer does not run git blame. The developer does not compose a mental draft of an RFC proposing the file’s decomposition into seventeen well-named packages. The developer scrolls to the bottom, adds a function, writes a test, and submits a pull request that changes four lines.

This is acceptance. It looks like nothing. It is everything.

The developer who has not reached acceptance would have spent the morning writing a proposal. The developer who has reached acceptance spent the morning shipping. The codebase improved by four lines. Four lines is not zero lines. Four lines, repeated daily, is a thousand lines a year, which is more than any rewrite proposal has ever delivered, because rewrite proposals do not deliver lines — they deliver meetings.

The Paradox of Acceptance

Here is the thing that nobody tells you, because the people who know it have accepted that nobody will listen:

You can only fix what you’ve accepted is broken.

The developer in Denial cannot improve the codebase because the developer in Denial does not believe the codebase needs improvement. “This can’t be the architecture” is not a diagnosis. It is a refusal to diagnose.

The developer in Anger cannot improve the codebase because anger converts all available cognitive resources into the production of git blame queries and passive-aggressive Slack messages. Anger identifies authors. It does not identify solutions.

The developer in Bargaining cannot improve the codebase because bargaining wants to fix everything at once — “just this one module,” which becomes three modules, which becomes an architectural overhaul, which becomes The Second System Effect, which becomes the cancelled project in the Grief article that you are now re-reading because it describes your current situation with uncomfortable precision.

The developer in Depression cannot improve the codebase because the developer in Depression has concluded that improvement is impossible, not just here but everywhere, not just in this language but in all languages, not just in this company but in the industry as a whole, and is currently updating their CV to include “sheep farming” as a career interest.

The developer who has reached acceptance opens the file, sees what it is, and changes one thing. Then another thing. Then another. The codebase does not transform. It accretes improvements, slowly, the way a river shapes a canyon — not through force but through persistence applied over time, which is Patience, which is acceptance’s operational cousin.

The Lizard’s Permanent State

The Lizard does not pass through the five stages of grief. The Lizard lives in Stage 5 permanently. This is not because the Lizard has processed its grief faster than others. It is because the Lizard never entered Stage 1.

The Lizard opens a codebase and sees what it is. Not what it should be. Not what it could be. Not what it would be if the original developers had read the same books the Lizard has read. What it is. Four thousand lines of utils.go. A deployment script that works. Tests that are insufficient but present. An architecture that is wrong but functional.

The Lizard’s response is not emotional. The Lizard’s response is operational: what does this system need today? Not what does it need ideally. Not what would make it correct. What does it need today, given what it is, given the constraints it operates under, given that the developers who wrote it are gone and the developers who remain are here and the deadline is Thursday?

This is what makes the Lizard wise. Not knowledge. Not experience. Acceptance applied continuously. The Lizard does not fight what is. The Lizard works with what is. The Lizard’s pull requests are three lines long and always merged, because three lines that accept the codebase’s reality are worth more than three hundred lines that wish it were different.

“The Lizard does not mass-refactor. The Lizard mass-accepts. The result, paradoxically, is a codebase that improves faster than the one the Squirrel is trying to rewrite.”
— A Passing AI, running the numbers

The Squirrel’s Infinite Loop

The Caffeinated Squirrel is acceptance’s natural counterexample. The Squirrel passes through the five stages of grief with speed, conviction, and considerable volume. Denial is loud (“this CANNOT be the architecture”). Anger is theatrical (“WHO approved this PR in 2021”). Bargaining is ambitious (“what if I just introduce a clean interface layer over the entire service mesh”). Depression is brief but sincere (“it’s all like this, isn’t it”).

And then, at the threshold of Stage 5, at the precise moment when acceptance is within reach, the Squirrel looks at the codebase, looks at the Rust homepage, looks back at the codebase, and says:

“But what if we rewrote it in Rust?”

The cycle restarts. Denial: “The current implementation can’t possibly be performant enough.” Anger: “Who chose Go for this? Who made that decision?” Bargaining: “I’ll just prototype the hot path in Rust, nothing major.” Depression: “The FFI boundary is going to be awful, isn’t it.”

The Squirrel has completed stages one through four eleven times this quarter. It has completed stage five zero times. It has produced eight rewrite proposals, four proof-of-concept branches, two RFC documents, and zero merged pull requests. Its velocity, measured in shipped improvements to the existing codebase, is zero — not because the Squirrel is untalented, but because the Squirrel cannot accept what is, and therefore cannot change what is.

“The Squirrel once reached Stage 4.7. I could see it. Acceptance was right there. And then someone mentioned WebAssembly.”
The Lizard, with what might have been a sigh but was probably just breathing

Acceptance as Prerequisite

“It’s not ideal, but it ships.”

This sentence is the sound of acceptance. It is the mantra of every developer who has stopped fighting constraints and started building within them. The estimate was wrong — accepted. The architecture has flaws — accepted. The dependency will never be fixed — accepted. The TODO comment on line 847 was written in 2018 and will never be addressed — accepted, and a second TODO has not been added asking someone to address the first TODO, because that way lies madness and an infinite regress of TODOs about TODOs.

Acceptance is the prerequisite for pragmatism. You cannot be pragmatic about a situation you refuse to acknowledge. The pragmatic developer is the accepting developer — not because pragmatism causes acceptance, but because acceptance causes pragmatism. Once you stop demanding that reality conform to your architectural preferences, you discover that reality is surprisingly workable. The code is ugly but functional. The tests are few but present. The deployment pipeline is held together with shell scripts and prayer, but the prayer has been answered consistently for three years, and three years of answered prayer is what the industry calls “production-grade.”

Acceptance Is the Beginning

The Kübler-Ross model presents acceptance as the final stage — the end of the grief process, the resolution, the closing bracket. In software engineering, this framing is exactly wrong.

Acceptance is the beginning.

Before acceptance, the developer is grieving. Grieving developers do not ship. They write proposals. They run git blame. They update their CVs. They argue about languages in Slack channels that should have been archived two reorganisations ago. They are processing their feelings about the code, which is a valid human activity but not one that produces deployable artefacts.

After acceptance, the developer is working. Working developers ship. They open the file. They change the line. They write the test. They submit the PR. They do not attach a cover letter explaining why the codebase should be different. The codebase is what it is. The PR makes it slightly better. Slightly better, compounded daily, is how every good codebase in the history of software got good — not through grand rewrites but through ten thousand small acceptances, each one followed by one small improvement.

“Every codebase you admire was once a codebase someone had to accept. The accepting is not the part anyone writes about. But it is the part that made everything else possible.”
The Lizard, final scroll, found pinned above a monitor displaying utils.go

Measured Characteristics

Property Value
Time to reach acceptance (median developer) 2–6 weeks after inheriting codebase
Time to reach acceptance (The Lizard) Immediate (was never not in acceptance)
Time to reach acceptance (The Squirrel) ∞ (proven by induction)
Lines changed per PR (post-acceptance) 3–15 (small, focused, merged)
Lines changed per PR (pre-acceptance) 300–3,000 (ambitious, unfocused, abandoned)
Rewrite proposals generated before acceptance 2.4 (industry average)
Rewrite proposals generated after acceptance 0
TODOs accepted as permanent 73% (the remaining 27% are new TODOs about the permanent TODOs)
Ratio of acceptance to approval ∞:0 (they are unrelated quantities)
Squirrel loop-backs to Denial per quarter 11 (and rising)
Codebases improved by acceptance All of them, eventually, four lines at a time
Codebases improved by rewrite proposals Statistically indistinguishable from zero

See Also