Three types of complexity

Big Idea

Not all hard problems are hard for the same reason. Before you write a single line of code, you need to understand what kind of complexity you are facing — because the tools for handling algorithmic complexity are completely different from the tools for handling social complexity. Misidentifying the problem is one of the most expensive mistakes a programmer can make.

This article is organised in layers. Each section starts with the basic idea — what every programmer working on complex problems needs to understand. Then it goes deeper.

LayerWhat it meansWhen to read it
Basic ideaWhat every programmer needs. Read this first, always.Right now.
At a deeper levelThe mechanism behind the basic idea. Helps you reason about where things go wrong.Once you have worked through the opening examples.
At the deepest levelHow professionals actually navigate this type of complexity. Not required — but explains things that will otherwise seem mysterious.When you are curious, or when a project breaks down and you cannot figure out which type of complexity is responsible.

1   What Do We Mean by "Complexity"?

Basic Idea

When programmers say a problem is complex, they usually mean one of three very different things. A sorting algorithm can be complex because the mathematics of its runtime is subtle. A hospital booking system can be complex because dozens of components interact in unpredictable ways. A content moderation tool can be complex because humans disagree about what counts as harmful speech.

These are not the same problem wearing different clothes. They require different skills, different teams, and different definitions of "done." This article introduces a framework for telling them apart.

At a Deeper Level

A codebase that solves the wrong problem perfectly is still a failure. Understanding complexity before you design a solution is not an academic exercise — it is how professional engineers decide what to build, who to talk to, and what questions to ask. The best programmers are also the best problem readers.

The three types below are not mutually exclusive. Real systems almost always contain all three simultaneously. The skill is not memorising the categories — it is learning to ask: which type of complexity am I fighting right now?

At the Deepest Level

This three-part framework maps loosely onto how engineering failures are classified in the professional literature. Algorithmic failures are studied in computer science theory. Systemic failures are the subject of resilience engineering and the field called complex systems. Social failures are studied under the umbrella of value-sensitive design, ethics of computing, and sociotechnical systems research. Each field has its own vocabulary and its own methods — which is itself evidence that the three types of complexity are genuinely distinct.

2   Type 1 — Algorithmic Complexity

Basic Idea

The core question: How much does this cost to compute — and how does that cost grow as the input gets larger?

Algorithmic complexity is precise and mathematical. Given the same inputs, the same algorithm always takes the same number of steps. There is a right answer, and we can prove it. The challenge is finding an approach whose cost is acceptable at real-world scale.

Real Case — Google's PageRank (1998)

When Google launched, it needed to rank billions of web pages by importance. A naïve approach — comparing every page to every other page — would require quadrillions of operations and take years. The founders designed PageRank, an iterative algorithm that models a "random surfer" clicking links. The insight was not about building faster hardware; it was about finding an algorithm whose cost grew slowly enough to be tractable. The complexity class of the problem was the engineering problem.

At a Deeper Level

Algorithmic complexity is usually described using Big O notation, which captures how runtime or memory grows as input size n increases. An O(n²) algorithm applied to a list of 10 items takes 100 steps; applied to 1,000 items, it takes 1,000,000 steps. That growth rate is the problem — not the raw speed of the machine.

This is why the canteen scenario later in this article involves algorithmic complexity: scheduling lunch slots for 800 students across three periods while respecting dietary constraints and minimising wait times is a variant of a timetabling problem — a class of problems that are provably expensive to solve optimally. No amount of faster hardware makes this easy.

At the Deepest Level

Many important real-world problems belong to a class called NP-hard — problems for which no known algorithm can find the optimal solution in polynomial time. Timetabling, route optimisation, and protein folding all fall here. In practice, engineers respond with one of three strategies: approximate algorithms (find a good-enough answer quickly), heuristics (rules of thumb that work well in practice), or problem reformulation (reframe the problem so it becomes tractable). The choice between these strategies is itself a design decision that requires understanding the complexity class of the original problem.

3   Type 2 — Systemic Complexity

Basic Idea

The core question: What happens when all the parts talk to each other at once?

Systemic complexity arises when many independently correct components interact in ways that produce unpredictable emergent behaviour. Individual pieces can each work perfectly in isolation, yet the system as a whole behaves in ways no one designed or anticipated. You cannot reason about systemic complexity by reading the code for any one module — you have to think about interactions, timing, and feedback loops.

Real Case — The 2010 Flash Crash

On May 6, 2010, the US stock market dropped nearly 1,000 points in minutes, then recovered — almost entirely because of automated trading algorithms interacting with each other. Each individual algorithm was doing exactly what it was designed to do. No single line of code had a bug. The crash emerged from the interaction of thousands of correct programs responding to each other's outputs in a feedback spiral no one had modelled. The complexity was systemic, not algorithmic.

At a Deeper Level

Systemic complexity tends to surface under conditions that were not tested: high load, simultaneous edge cases, a component that responds faster than expected, or two modules that each assume the other will yield first. The bugs are often impossible to reproduce in isolation — they only appear when the system runs at scale with real traffic.

This is why professional teams invest heavily in monitoring, circuit breakers, graceful degradation, and chaos engineering (deliberately breaking parts of a live system to find systemic weaknesses before they find you). The goal is not to prevent all failures — it is to ensure failures stay local rather than cascading.

At the Deepest Level

The theoretical foundation for systemic complexity comes from the study of complex adaptive systems — systems where components adapt in response to each other, producing behaviour that cannot be predicted from any individual component's rules. Financial markets, ecosystems, the immune system, and large software architectures all exhibit this property. The field of resilience engineering (associated with researchers like Sidney Dekker and David Woods) argues that the goal of system design should not be preventing failure but building systems that can absorb and recover from it — because in complex systems, failure is normal.

4   Type 3 — Social Complexity

Basic Idea

The core question: What should this system actually do — and who gets to decide?

Social complexity cannot be resolved by a better algorithm. The requirements themselves are in dispute. Different stakeholders have legitimate but incompatible needs. What counts as "correct" output depends on whose perspective you adopt — and that perspective can change over time, or vary by culture, context, or law.

Real Case — YouTube's recommendation engine (2016–present)

YouTube built a recommendation system that was algorithmically sophisticated and systemically well-engineered. It was enormously effective at maximising watch time — which turned out to mean promoting increasingly extreme content, because outrage and anxiety are engaging. The algorithm was doing exactly what engineers told it to do. The problem was social: engineers had encoded "engagement" as a proxy for "value," but real human communities had a different, contested, and hard-to-define idea of what a valuable recommendation looks like. No amount of algorithmic tuning could fix a problem that was fundamentally about human values.

At a Deeper Level

Social complexity shows up at requirements time — before a line of code is written. The tell is that stakeholders give you contradictory requirements and are both right. A school canteen app must be fast (the headmaster), accessible to students without smartphones (equity concern), privacy-compliant for allergy data (the law), and still profitable enough to justify the canteen's operation (the finance team). These are not negotiation positions. They are legitimate constraints that cannot all be maximised simultaneously.

Common Confusion — "We just need a better algorithm"

When a software system causes harm — a biased hiring tool, a recommendation engine that radicalises users, a facial recognition system that misidentifies people of colour — it is tempting to frame this as an algorithmic problem with a technical fix. It rarely is. The algorithm is usually working correctly against the objective it was given. The problem is social: the objective itself was wrong, incomplete, or only represented some users' interests. Trying to solve social complexity with algorithmic tools produces better versions of the wrong thing.

At the Deepest Level

Social complexity is the reason software projects fail more often for organisational and requirements reasons than for technical ones. The classic study is the Chaos Report (Standish Group, 1994 and updated regularly), which has consistently found that the top causes of project failure are incomplete requirements, lack of stakeholder involvement, and changing requirements — not bugs or insufficient computing power.

The field of value-sensitive design (Batya Friedman, University of Washington) offers one systematic approach: explicitly identify all affected stakeholders, including indirect ones, and map their values before designing any system. This does not eliminate social complexity, but it surfaces the value conflicts early — when they are cheap to resolve — rather than after deployment, when they are expensive and public.

5   Comparing the Three Types

 AlgorithmicSystemicSocial
Core questionHow much does this cost to compute?What happens when parts interact?What should this system do at all?
SourceMathematics of the problemEmergent behaviour from interactionsCompeting human values
Can you prove "correct"?Yes — formally or empiricallyPartially — through testing at scaleNo — values are contested
Solved bySmarter algorithms, better data structuresArchitecture, monitoring, resilience engineeringStakeholder engagement, ethics, iteration
Gets worse withLarger inputsMore components and integrationsMore diverse users and higher stakes
Key skillMathematical reasoningSystems thinkingListening, ethics, humility
They coexist — and the hardest problems have all three

Real systems rarely have just one type of complexity. A hospital scheduling system has algorithmic complexity (timetabling is NP-hard), systemic complexity (what happens when a doctor calls in sick and three automated systems try to reroute simultaneously?), and social complexity (whose preferences take priority — the patient's, the doctor's, the hospital's, the insurer's?). Learning to identify which type of complexity you are currently fighting is a professional skill that takes years to develop.

6   Discussion  ⏱ 25 min

Work through these questions with your group. There are no single correct answers — the goal is to sharpen your thinking before you face a real problem.

Discussion Questions
  1. What is fundamentally different about each type of complexity? Try to state it in one sentence per type, without using the examples from the article.
  2. Which type can be "finished"? Is there a point at which you can declare algorithmic complexity solved? Systemic complexity? Social complexity? Why or why not?
  3. Personal experience: Think of a problem — from a programming project, a school system, a game, an app you use — where you hit unexpected complexity. Which type was it? How did you know? What did you do about it?
  4. Danger of misidentification: A school builds an AI tool to flag students who are "at risk of failing." A teacher says the results seem biased against certain student groups. A developer responds: "We just need more training data." What type of complexity is the teacher pointing at? Is more data a sufficient fix? Why or why not?
Check Your Understanding
  1. In your own words: what is the single most important difference between systemic and social complexity?
  2. A self-driving car must decide whether to brake hard (risking a rear-end collision) or swerve (potentially hitting a pedestrian) when an obstacle appears suddenly. Identify at least one algorithmic, one systemic, and one social source of complexity in this scenario.
  3. A student argues: "Social complexity is just an excuse for not solving the problem properly." Write a two-sentence response that steelmans their concern and then pushes back on it.

7   Challenge Problem  ⏱ 25 min

Work on paper. Do not write code. The goal is to read the problem carefully enough to know what you do not yet know.

Challenge Scenario

The School Canteen Queue

Your school's canteen serves 800 students across three lunch periods. The current system is a physical queue: students line up, staff take orders, payment is made by card or cash. The headmaster wants to "modernise and improve the system" before September. You have been brought in as the student developer.

The headmaster says: "It takes too long, students are late back to class, there's always a big rush at the start of the period, and some students with dietary restrictions or allergies have to ask staff questions which slows everything down. Oh, and we'd like to reduce food waste. Can you build an app for this?"

Your task — on paper only:
  1. Identify the complexities. List at least one algorithmic, one systemic, and one social source of complexity you can already see in this scenario. Explain why each is that type.
  2. Map the stakeholders. Who has an interest in this system? For each stakeholder, write one sentence describing what they most want the system to do — and whether that might conflict with what another stakeholder wants.
  3. Write your questions. You cannot write a single line of code yet. List the ten most important questions you would need answered before you could even design the solution. For each question, say which type of complexity it relates to.
  4. Report back. When the class reconvenes, share: (a) the most surprising complexity you found, and (b) the question you most wish you could ask the headmaster.
What makes this scenario genuinely hard

Notice that the headmaster has described symptoms ("it takes too long"), not requirements. The request to "build an app" is a proposed solution, not a problem statement. One of the most important skills in software development is resisting the pull toward implementation before the problem is understood. A canteen app that is algorithmically efficient, systemically robust, and technically impressive — but that students refuse to use, or that disadvantages students without smartphones, or that fails to account for dietary data privacy — is a failed project.

8   The Big Picture

Big Idea

Complexity is not one thing. Algorithmic complexity is about the mathematics of computation — how cost scales with input size. Systemic complexity is about emergent behaviour from interacting parts — what happens when everything runs at once. Social complexity is about contested human values — what the system should do, and who gets to decide. The hardest real-world problems have all three. Before you build anything, your job is to identify which types you face — because each one requires a fundamentally different response. Jumping to code before you can answer that question is one of the most expensive mistakes a programmer can make.

Final Check Your Understanding
  1. Name the three types of complexity introduced in this article. For each, give a one-sentence definition and a real-world example that is not from this article.
  2. A friend says: "All complexity is really just systemic complexity — if you model the human factors carefully enough, you can encode them as system rules." Do you agree? What does social complexity have that systemic complexity does not?
  3. Think about the canteen scenario from Section 7. Write one sentence explaining why a technically perfect app could still be a failure — and which type of complexity that failure would come from.
  4. Explain why "write more requirements" is not always a complete solution to social complexity.