Free sample lesson ยท A Philosophy of Software Design

Complexity Fundamentals

Why do software projects that start simple become nightmares to maintain?

Lesson 1 of the Wondering course A Philosophy of Software Design

Why Simple Projects Turn Painful

Most software starts small and easy to follow. A few files, a clear purpose, quick changes.

Then it grows. Each new feature adds more to understand, and changes start taking longer.

A software project growing from tidy to tangled

Notice that the developer is the same on both sides; only the amount of structure to understand has grown.

The greatest limitation in writing software is our ability to understand the systems we are creating.

That limit is why complexity decides whether a project succeeds or fails over the long term.

What Complexity Actually Is

Complexity is anything related to the structure of a software system that makes it hard to understand and modify.

The two tests inside the definition
  • Complexity: Anything in a system's structure that makes work harder.
  • Hard to understand: You struggle to follow what the code does.
  • Hard to modify: You struggle to change it safely.

Notice the two tests. Can you understand the code? Can you change it safely?

If any part of the structure makes either one harder, that is complexity.

Size alone is not the test. The question is whether the way code is organized gets in the way of understanding and change.

Complexity Creeps In

Complexity rarely arrives all at once. It accumulates incrementally.

One quick workaround. One extra special case. One shortcut to hit a deadline. Each seems harmless alone.

How a clean system becomes unmanageable
  • Clean start: The system is small and easy to follow.
  • Small decision: A workaround or shortcut seems harmless alone.
  • More decisions: Special cases and shortcuts keep piling up.
  • Compounding: Together they make the system hard to understand and modify.

But small decisions compound over time. Together they turn a clean system into an unmanageable one.

No single bad change explains the mess. That is why every small choice deserves attention.

The Real Goal of Good Design

If complexity is the problem, what does success look like?

The ultimate goal is to minimize the amount of code a developer needs to understand to make changes.

Picture fixing a bug. In a healthy system, you read one small area and make the change with confidence.

In a complex one, you must trace through many files before you dare touch anything.

How much did your last change require?

Two Ways to Fight Complexity

There are two general approaches to fighting complexity.

Make code simpler and more obvious. Remove what is not needed so readers grasp it quickly.

Encapsulate complexity through modular design. Hide the hard parts inside modules, so others can use them without studying their insides.

Two strategies, one goal
  • Simpler code
  • Modular design

Strong designs use both. Simplify what you can, then contain what remains.

How Encapsulation Helps

Some complexity cannot be removed. A system may truly need tricky logic.

Modular design puts that logic inside a module, a self-contained part of the system.

A module hiding tricky logic from other developers

The tangled logic stays sealed inside the box, so the developer outside only needs to understand the simple surface.

Other developers work with the module from the outside. They do not need to understand its inner details.

The complexity still exists, but fewer people must think about it at once. That shrinks the code each developer needs to understand.

Spotting Complexity in Your Work

You can now spot complexity in everyday code.

Ask two questions about each change: Is this easy to understand? Is it easy to modify?

If not, first try to make it simpler and more obvious. If the hard part must stay, wrap it in a module.

Warning signs and responses

Small decisions compound, so treat each one as part of the long-term design.

Check yourself

In software design, complexity is anything related to a system's structure that makes it hard to _____

  • understand and modify
  • compile and execute quickly

Answer: understand and modify

Complexity is about structure that makes a system hard to understand and modify. Slow execution is a performance concern, not the definition of complexity.

One way to fight complexity is to make code _____ and more obvious. The other is to hide complexity behind clean boundaries, called _____ design.

Answer: One way to fight complexity is to make code simpler and more obvious. The other is to hide complexity behind clean boundaries, called modular design.

The two strategies are eliminating complexity by making code simpler and more obvious, and encapsulating complexity through modular design so developers don't need to deal with it all at once.

Which situation best illustrates software complexity?

  • A small feature change requires reading and editing many tangled files
  • The program runs slowly on an older laptop
  • Users dislike the color scheme of the app
  • A developer mistyped a variable name once

Answer: A small feature change requires reading and editing many tangled files

Complexity is structural: anything that makes a system hard to understand and modify. A small change needing edits across many confusing files fits exactly. Slow hardware, bugs from typos, or user preferences are not about structure hindering understanding.

Keep going

This is lesson 1 of 25 in A Philosophy of Software Design. Next up:

  1. Complexity Symptoms
  2. Strategic Programming
  3. Deep Modules
  4. General-Purpose Modules
  5. Different Abstractions

Start this course free

Wondering turns any topic into short lessons you can read, watch, or listen to, with practice questions and an AI tutor.