Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

KISS

Pattern

A reusable solution you can apply to your work.

“Simplicity is the ultimate sophistication.” — Leonardo da Vinci

Also known as: Keep It Simple, Stupid; Keep It Short and Simple

Understand This First

Context

At the heuristic level, KISS is one of the oldest and most broadly applicable design principles. It applies whenever you’re making decisions about how to structure code, design an interface, or organize a system. It’s especially relevant after patterns like Separation of Concerns and Abstraction have been introduced, because those patterns can be misapplied in ways that add complexity without adding clarity.

In agentic coding, KISS matters doubly. AI agents are fluent in complex patterns. They’ll happily generate an abstract factory wrapping a strategy pattern behind a dependency injection container when a simple function would do. The human’s job is to recognize when the agent has over-engineered the response and steer it back toward simplicity.

Problem

How do you keep a system understandable and maintainable when there are always more patterns, abstractions, and frameworks available than necessary?

Complexity is seductive. Each individual abstraction feels justified (“what if we need to swap databases later?”) but the cumulative weight of speculative design makes the system harder to understand, harder to change, and harder to debug. The irony is that complexity introduced to make future changes easier often makes present changes harder.

Forces

  • Anticipated future needs tempt you to build generality you may never use.
  • Pattern knowledge creates pressure to apply patterns whether they fit or not.
  • Team expectations can equate complexity with thoroughness or professionalism.
  • Agent fluency means AI assistants produce sophisticated code effortlessly, removing the natural friction that once discouraged over-engineering.

Solution

Prefer the simplest approach that solves the current problem. “Simple” doesn’t mean “easy” or “naive.” It means free of unnecessary parts. A well-factored function with a clear name is simpler than a class hierarchy, even if the class hierarchy is technically correct.

Apply the test: can you remove any part of this design without losing functionality you actually need today? If yes, remove it. If a junior developer would struggle to follow the code, ask whether the complexity is earning its keep or just showing off.

When reviewing agent-generated code, watch for gratuitous layers. An agent asked to “build a REST endpoint” might produce a controller, a service, a repository, a DTO, and a mapper — five layers for what could be one function and a database query. Push back. Ask the agent: “Can you simplify this to the minimum that works?”

Tip

When prompting an agent, add constraints like “use the fewest files possible” or “avoid unnecessary abstractions.” Agents default to patterns they’ve seen most often in training data, which tends to be enterprise-scale code. Explicit simplicity constraints produce better results for most projects.

How It Plays Out

A developer asks an agent to build a configuration system. The agent produces a YAML parser, a schema validator, an environment-variable overlay, and a hot-reload watcher. The developer actually needs to read three settings from a file at startup. She asks the agent to simplify. The result: a single function that reads a JSON file and returns a dictionary. It takes ten seconds to understand and covers every real need.

A team inherits a codebase with nineteen microservices, each with its own database, message queue, and deployment pipeline. The original authors anticipated Netflix-scale traffic. The system serves two hundred users. The team spends six months consolidating into a monolith, not because monoliths are always better, but because the complexity wasn’t earned by actual requirements.

Example Prompt

“I need to read three settings from a config file at startup. Don’t build a schema validator or hot-reload watcher — just read the JSON file and return a dictionary.”

Consequences

Simple systems are easier to read, test, debug, and modify. They have fewer failure modes and smaller attack surfaces. New team members (human or agent) can become productive faster.

The risk is under-design. Some problems genuinely require sophisticated solutions, and forced simplicity can produce brittle code that breaks under real-world pressure. KISS isn’t an argument against all abstraction. It’s an argument against premature and unearned abstraction. When you discover a genuine need for complexity, add it then, with the benefit of concrete requirements.

  • Contrasts with: YAGNI — YAGNI focuses on features you don’t need yet; KISS focuses on complexity you don’t need at all.
  • Uses: Local Reasoning — simple code is easier to reason about locally.
  • Refined by: Smell (Code Smell) — unnecessary complexity often shows up as code smells.
  • Depends on: Separation of Concerns — simplicity requires putting things in the right place, not just reducing volume.
  • Related: Big Ball of Mud – ignoring simplicity accelerates structural collapse.
  • Violated by: Premature Optimization – optimization replaces simple code with clever code.
  • Related: Technical Debt – unnecessary complexity is a leading source of debt.