The Four Quadrants of Complexity

Essential complexity is where software engineers are uniquely able to deliver business value, whereas accidental complexity is what some engineers think looks good on their resumes.

Another dimension, shown in the diagram below, is frequency. This ranges from frequently repeated complexities to once-off complexity.

Repeated complexities can be an area of the system that suffers a high rate of change, or it can be a cross-cutting concern that re-appears frequently throughout the codebase.

These two dimensions give rise to four quadrants:

  • Repeated accidental complexity: a time sink where engineering productivity goes to die.
  • Once-off accidental complexity: a necessary evil. You get through it and hope you never need to touch it again.
  • Repeated essential complexity: leaves people feeling good about wasting time. The hardest thing about repeated essential complexity is detecting it, but boredom or attrition of talented engineers might be a sign.
  • Once-off essential complexity: the holy grail of software engineering — it delivers business value with minimal cost and great ROI.

What are the fixes?

For repeated accidental complexity, you either need to eliminate the complexity entirely (do you really need Kubernetes? No, really, do you?) or create an abstraction, API, or framework that transforms repeated tasks into once-off tasks. But be warned, this only shifts the complexity left. Natural entropic forces push complexity to the right. One day, it could blow up into a time-sink again.

For once-off accidental complexity, the fix is to leave it alone. Take engineers off it, prioritise and champion other work. Sometimes, the source of the entropic force pushing complexity to the right is your team’s desire to improve things! But if it ain’t broke, don’t fix it.

Repeated essential complexity first needs to be detected, then, like its accidental cousin, the correct abstraction, API, or framework needs to be created to shift left. But note that you’re paying for this with what you hope is once-off accidental complexity. There are several traps here, such as excessive code reuse leading to inappropriate coupling that makes changes harder.

For once-off essential complexity, the fix is to focus on solving the problem in front of you. Don’t overcomplicate it. Don’t reach for new tools. Don’t try to prematurely optimise.

In general, good tooling helps shift all complexity a little left. Whether that’s paying for a proper IDE rather than VSCode, setting up linters, debuggers, or static analysis tools.

Platform teams are also another solution, but one that many companies reach for too soon. You need many engineers for accidental complexity to cost enough to give platform teams a positive ROI. Buy one too early, and they might start trying to fix stuff that ain’t broke.

Of course, non-functional requirements introduce a lot of complexity that looks accidental but turns out to be essential or vice versa. Much of technical leadership is helping teams distinguish the two.