Complexity

Essential complexity

All systems are complex because all systems have essential complexity. Essential complexity is the complexity that is inherent in the [problem] that the system is trying to solve, or the [domain] of the software.

For example, a system that is trying to solve the problem of routing packets across a network will have to deal with the inherent complexity of routing algorithms, network topologies, and so on.

You can’t eliminate essential complexity in a system, but you can reduce it by reducing the scope of the problem you’re trying to solve.

Accidental complexity

Accidental complexity is the type of complexity in software systems that developers have more control over. This is the complexity that comes from the decisions the developers choose to make in the [system design].

Different architectural styles, design patterns, programming paradigms, application frameworks, and runtime environments – all of these things make trade-offs between competing [qualities], and therefore bring different types of accidental complexity into a solution.

For example, [distributed software] is inherently more complex than [monolithic software]. A distributed program has to deal with the complexities of network communication, data consistency, and fault tolerance. Add [asynchronous] [inter-process communication] to the mix, and you have even more complexity that requires specialist tools and techniques – like [observability] and especially [distributed tracing] – to deal with.