Definition: KISS (Keep It Simple, Stupid) is a design principle stating that most systems work best when kept simple. Simplicity should be a key design goal, and unnecessary complexity should be avoided.
— Source: NERVICO, Software Development Consultancy
What is KISS
KISS originated in the US Navy in the 1960s, credited to engineer Kelly Johnson of Lockheed. The idea was that fighter jets should be repairable by an average mechanic in field conditions with basic tools.
Applied to software: the simplest solution that solves the problem is almost always the best. Not because it's easier to write, but because it's easier to understand, maintain, debug and evolve.
Why Complexity is the Enemy
- More bugs: Complex code has more places for errors to hide.
- Costly maintenance: Understanding complex code takes time. A lot of time.
- Slow onboarding: New developers take longer to become productive.
- Risky changes: Modifying something you don't understand well is dangerous.
- Difficult testing: More execution paths = more cases to test.
Sources of Unnecessary Complexity
Over-engineering
Building for requirements that don't exist. "Just in case we need..." Most of the time, you won't need it. And when you do, what you built probably won't fit anyway.
Premature Abstraction
Creating frameworks, libraries and patterns before understanding the real problem. Generic code is harder to write, understand and use than specific code.
Blindly Following "Best Practices"
Applying microservices to an application with one user. Using React for a static page. Best practices depend on context.
Developer Ego
Wanting to show how clever you are with ingenious code. The smartest code is the one that seems obvious. If other developers say "of course, makes sense", you've done your job well.
How to Apply KISS
Solve the Current Problem
Not the problem two years from now. Not the generic problem. The specific problem you're facing right now.
Use Domain Language
Name things as the business calls them. If the client says "order", don't call it "TransactionRequest". Reduce the mental translation needed.
Prefer Obvious Code Over Clever Code
An explicit for loop may be better than a chain of map/filter/reduce if it makes the code clearer. Don't use a language feature just because it exists.
Eliminate Dead Code
Commented code, functions nobody calls, half-implemented features. Every line of code has a maintenance cost. If it's not used, delete it.
Divide and Conquer
Complex problems are solved by dividing them into simple problems. Small functions that do one thing. Modules with clear responsibilities.
KISS vs Excessive Simplicity
KISS doesn't mean doing everything the most basic way possible. Sometimes the "simple" initial solution creates complexity later:
- Spaghetti code because "it was faster that way"
- Raw SQL everywhere instead of an abstraction layer
- One giant file because "creating more files complicates things"
KISS simplicity is long-term simplicity. Sometimes it requires more initial effort to achieve code that's simple to maintain.
Examples in Practice
Bad: Framework for Everything
Creating a plugin system, dependency injection and hexagonal architecture for a 5-endpoint API. The complexity exceeds the benefit.
Good: Start Simple, Evolve
Start with a well-structured monolith. When (and if) you need microservices, extract the modules you already have separated.
Bad: Premature Optimisation
Implementing caching, sharding and CDN before you have users. Optimise when you have data demonstrating the problem.
Good: The Obvious Solution First
Need to persist data? Start with a normal relational database. Not with MongoDB "in case it scales" or an event-sourcing architecture.
Related Phrases
- YAGNI: "You Aren't Gonna Need It"
- "Make it work, make it right, make it fast": In that order.
- "Perfection is achieved when there is nothing left to take away": Antoine de Saint-Exupéry.
