KISS — Keep It Simple
Most systems work best when kept as simple as possible — choose the straightforward solution over the clever one, and add complexity only when the problem demands it.
★★★★★5/5Inside a codebase — classes, modules, files
How it works
KISS ('Keep It Simple, Stupid') originated in the US Navy in the early 1960s as a design principle for systems that field engineers could repair under pressure with minimal tools. Kelly Johnson, the Lockheed Skunk Works engineer, made this a guiding philosophy: design for the real constraints of the people who use it, not for the ideal conditions of the designer.
In software, KISS is a counter to the natural tendency of developers to over-engineer. The clever recursive solution, the generic framework with twelve extension points, the beautifully abstract system designed for hypothetical future requirements — these are KISS violations when a simpler solution would work.
Simplicity has a cost up front (resisting the urge to abstract, suppressing the 'what if' instinct) and a compounding payoff: simple code is easier to read, debug, test, and modify. Complex code is harder to do all of those, and that cost compounds every time someone touches it.
KISS doesn't mean write naive code — it means choose the simplest design that correctly solves the actual problem.
Implementation
TypeScript · Go · Rust// ❌ Over-engineered — solving a hypothetical problem with a generic framework
abstract class SortStrategy<T> {
abstract sort(data: T[]): T[];
}
class SortStrategyFactory<T> {
create(algo: "bubble" | "quick" | "merge"): SortStrategy<T> { /* ... */ }
}
class SortingPipeline<T> {
constructor(private factory: SortStrategyFactory<T>) {}
sort(data: T[]): T[] {
const strategy = this.factory.create("quick");
return strategy.sort(data);
}
}
// 30 lines to sort an array
// ✓ Simple — solve the actual problem
function sortByPrice(items: Item[]): Item[] {
return [...items].sort((a, b) => a.price - b.price);
}
// 1 line. Add complexity only when the problem actually demands it.Why it matters
Complexity is the enemy of reliability and maintainability. Every additional abstraction, indirection, and moving part is a place where bugs can hide and a place that must be understood before the code can be changed. Simpler code has fewer of both.
✓ When to use
- →Always start with the simplest solution that works
- →When you notice you're designing for hypothetical future requirements
- →When a code review reveals that understanding the code requires extensive context
- →When debugging a system — if the fix requires adding more complexity, reconsider the design
✗ When NOT to use
- →Don't conflate 'simple' with 'naive' — a correct distributed consensus algorithm is necessarily complex
- →Some domains (cryptography, networking protocols) have inherent complexity that can't be wished away
Trade-offs
Simple code is fast to read, understand, modify, and debug
Resisting abstraction requires experience and discipline — it's psychologically hard
Fewer moving parts means fewer bugs and easier testing
Oversimplification can mean revisiting the design when real complexity arrives
New developers onboard faster into simple codebases
Simple today might not handle scale tomorrow — evaluate the actual growth trajectory
In production
Single file, no server, no configuration — the simplest possible relational database, used in billions of devices
Go deliberately omits generics (originally), inheritance, and many OOP features — simplicity over expressiveness
cat, grep, sort — each does one simple thing; complexity comes from composing them, not from each tool
Industry adoption
Related principles
YAGNI — You Aren't Gonna Need It
Don't implement something until you actually need it — speculative features add complexity today and may never deliver value.
DRY — Don't Repeat Yourself
Every piece of knowledge should have a single, authoritative representation — duplication forces you to keep multiple copies in sync, and they inevitably drift.
Single Responsibility Principle
A class should have only one reason to change — keep each unit focused on a single job so unrelated concerns don't accidentally break each other.
Separation of Concerns
Divide a program into distinct sections where each section addresses one concern — so changes to one area don't ripple unexpectedly into unrelated areas.