Grief and loss are very human experiences. Although we most commonly associate grief with the death of a loved one, people grieve many kinds of loss: jobs, marriages, careers, and even seemingly trivial things like beloved products being discontinued or childhood homes being sold.

Traditional grief has been studied and categorized into five stages: Denial, Anger, Bargaining, Depression, and Acceptance.

Unsurprisingly, grief also exists in software engineering.

There are probably more types of grief in software engineering, but this post is about a category I’ll call Architecture Grief.

Architecture Grief is something I’ve experienced firsthand and observed in others throughout my career, at every single job I’ve had (sometimes multiple times!). I only recently characterized these feelings as grief.

Architecture Grief is the process of an individual, team, or organization coming to terms with the reality that systems are shaped by constraints that cannot be engineered away.

Software engineers naturally over-index on the unpleasant parts of their systems. That’s where the outages live, where the tedious engineering work/toil lives. During the tedium, software engineers form idealized mental models of what their systems architecture should be.

The wider the gap between the architecture we wish we had and the architecture reality permits, the longer the grieving process tends to last.

The rest of this post is a mapping of Architecture Grief to each stage of grief.

Denial

In traditional grief, people naturally have trouble even acknowledging a loss although they are factually aware of it. Denial doesn’t mean ignorance of facts, it’s a resistance to what the facts reveal.

In Architecture Grief, software engineers in the denial stage typically are factually aware of the unpleasant truths within their systems but they fail to acknowledge the constraints that created them.

Some signs of the denial stage of Architecture Grief:

  • “$CAPABILITY shouldn’t reside in $COMPONENT”
  • “This will go away in v2, if we can ever get to it”
  • “This is too complicated, we can simplify it”
  • Massive greenfield re-architecture proposals

The most helpful way to process denial in Architecture Grief is two simple words: Contributions Welcome. When someone in denial has ownership, they often get the needed context and clarity on why a given domain might be so complex.

Amazon even has a Principal Engineer tenet that rhymes with this:

Respect what came before. Principal engineers are grateful to our predecessors. We appreciate the value of working systems and the lessons they embody. We understand that many problems are not essentially new.

Anger

Anger is tricky. Anger in both traditional grief and Architecture Grief is factually justified. The loss of a loved one can leave you angry at a world where bad things happen to good people. Objectively bad software architectures exist. For me personally, in both traditional grief and Architecture Grief, anger tends to show up when I feel a loss of agency. I’m angry because I’m helpless to change a challenging situation.

Anger starts when engineers understand why their systems/constraints exist, but they oppose the decisions or circumstances that shaped them.

Some signs of the Anger stage of Architecture Grief:

  • “Why would customers ever use this deprecated API?”
  • “Why can’t we force a migration?”
  • “Why are there duplicative systems?”
  • “Why do we have to deal with all of these ridiculous edge cases?”
  • Why can’t we fund The Big Rewrite?

It’s hard to move forward from anger. The most useful thing I’ve done to process the anger stage (which I’ll expand on later) is thoughtfully separating causes of anger as decisions made or circumstances.

Bargaining

In traditional grief, the bargaining stage isn’t actually a negotiation. It’s more of an internal conversation about what could/can/should be done to tamper the pain of loss.

Architecture Grief is no different. Bargaining begins when engineers accept the constraints shaping their systems, but search for increasingly creative ways to preserve their ideal architecture anyway.

Some signs of the Bargaining stage of Architecture Grief:

  • “We’ll make a cross functional architecture team”
  • “Eventually we’ll shift to…”
  • “We’ll make a new API and a compatibility layer.”

Bargaining is often where ambitious initiatives, migration plans, and architecture diagrams are born. Some succeed. Most fail.

The defining characteristic of bargaining is the belief that we can somehow have both: preserve the existing constraints while still achieving the architecture we originally imagined.

Depression

Depression is a gut punch in both traditional grief and Architecture Grief. It’s the realization that loss is real, permanent, and unavoidable.

In Architecture Grief, it’s when software engineers realize the ideal architecture is not going to happen.

The migration will never fully complete. The temporary compatibility layer is no longer temporary. The Big Rewrite is not getting funded. The architecture we imagined is simply not going to happen.

Some signs of the Depression stage of Architecture Grief:

  • A decline in architectural ambition
  • Cynicism about modernization efforts
  • “Sure. We’ll deliver that in Q7 2029.”
  • “The temporary workaround is a friend for life.”
  • Silence where there was once passionate discussion
  • Refusal to take part in speculative forward looking discussions

Depression often leads to cynicism. Personally, I fall into this stage fairly often.

In order to get through the Depression stage, you have to stop measuring success against a desired architecture that was never realistically attainable. Failing to change to a desired architecture isn’t an individual/team/organizational shortcoming, it simply wasn’t a tractable problem given the operating constraints that weren’t apparent and given proper weight.

Acceptance

Acceptance in Architecture Grief does not mean believing every architectural decision was correct. Acceptance is not surrender. Acceptance is understanding the problem space well enough to make meaningful improvements despite the constraints.

It means recognizing that systems are the accumulated result of decisions, constraints, timing, luck, and changing realities.

Mature engineers eventually realize that systems are rarely collections of purely good or bad decisions. They are the accumulated result of decisions, constraints, timing, luck, and changing realities.

Architecture Grief is challenging to see in yourself and in others. I recommend these books to someone in Architecture Grief that helped me:

Sports and poker are both unique mixes of decision making and circumstances, but unlike software engineering you get immediate feedback! These books helped me more clearly see differences between decision making and circumstances in new ways. In particular, they helped me name some painful truths:

  • Some percentage of decisions will be bad. Perfection does not exist.
  • The outsized role of timing and luck in life, both good and bad.
  • You can make an the best possible decision at the time and circumstances change, which make it seem like a bad decision.
  • You can make a poor decision and good luck can make it seem like a good decision.
  • Mutual trust is essential. Decision makers often have context that they cannot completely share due to confidentiality. A bad decision might not be a bad one everyone has a shared context- you ultimately have to trust the decision maker.

Wrapping up

A table of Architecture Grief stages vs. reality:

StageReality
Denial“These constraints shouldn’t exist.”
Anger“These constraints exist, and I hate them.”
Bargaining“Maybe I can work around these constraints.”
Depression“These constraints aren’t going away.”
Acceptance“These constraints define the problem space.”

The cost of change is understated, constraints are under appreciated, and the benefit of change is overstated.

There is no free lunch.

There is no magic.

Hard things are hard. You’ll get through it.