2.2.2 · D5Design Principles

Question bank — KISS — Keep It Simple

1,408 words6 min readBack to topic

True or false — justify

The simplest code is always the code with the fewest lines.
False — line-count measures characters, not understanding-time. A branch-free one-liner like (a>b)*a+(a<=b)*b is fewer lines yet harder to reason about, so it violates KISS.
KISS means you should never use design patterns.
False — KISS bans premature abstraction, not abstraction itself. A pattern that removes real, proven duplication is simplifying; a pattern added for an imagined future is the thing KISS warns against.
"Keep It Simple, Stupid" is calling the programmer stupid.
False — "Stupid" describes the target audience of the code: it must stay understandable to someone tired, new, or under pressure (future-you at 2 a.m.), not to an insulted author.
A system that handles every conceivable edge case is a KISS system.
False — handling edge cases you don't actually have is over-engineering; each imagined case adds moving parts and interactions with zero present benefit.
Removing a necessary edge-case check makes code simpler and therefore more KISS.
False — that is over-simplification, a bug. Einstein's razor is "as simple as possible, but no simpler"; dropping needed behaviour breaks correctness, not complexity.
Doubling the number of interacting pieces in a function roughly doubles the mental effort to read it.
False — cognitive load scales like pairs , which is quadratic, so doubling roughly quadruples the effort (e.g. vs , a 5× jump).
Clever code is a good default because you have full context when you write it.
False — you write code once but read it many times; clever code optimizes for the single writing moment and pays a tax across every later reading, debugging, and onboarding moment.
KISS and YAGNI contradict each other.
False — YAGNI ("You Aren't Gonna Need It") is a tool for achieving KISS: by refusing speculative features you keep small and the design simple.
Applying Single Responsibility to split a big function into small ones increases total complexity because now there are more units.
False — each small unit has tiny , and grows super-linearly, so several small functions have far fewer total interactions than one giant one.

Spot the error

"This class is more flexible, so it's the simpler design." — what's wrong with the reasoning?
Flexibility and simplicity are different axes. Flexibility you don't currently use is speculative generality — it adds moving parts and reading cost now for a benefit that may never arrive.
"I compressed six lines into one, so I applied KISS." — what's the flaw?
Compression raised cognitive density (more reasoning per character) even though it lowered line-count. KISS optimizes understanding-time, so this often makes the code less simple.
"We built the plugin architecture upfront so future greeting types are easy." — where does this break KISS?
There is exactly one greeting type today. Abstraction with a single implementation adds with no benefit; the pattern should arrive when a real second case does, not before.
"The three nested if blocks are fine because each condition is short." — what's overlooked?
Short conditions don't reduce the load of holding three open branches simultaneously. Guard clauses / early returns let the reader dispose of each condition and exit, cutting the interactions tracked at once.
"Deleting this unused parameter does nothing useful — it's not a feature." — why is this attitude a trap?
Deletion is an engineering win under KISS: an unused param is a moving piece a reader must consider and rule out. Removing it shrinks and removes questions.
"We should abstract now to avoid duplicating this once." — what principle is being misused?
DRY targets proven duplication, not a single occurrence. Abstracting on the first instance is prediction, and premature abstraction is exactly what KISS forbids.

Why questions

Why does adding code feel more productive than deleting it?
Adding produces visible artifacts (new lines, new features) that look like output, while deletion looks like "nothing" — KISS retrains you to count restraint and removal as real progress.
Why is cognitive load modeled by pairs of pieces rather than the count of pieces?
Because understanding requires tracking how pieces interact, and each of pieces can pair with the other ; the unordered pairs are , so interactions — not raw count — drive difficulty.
Why does the "Stupid" audience assumption make code better for everyone, not just beginners?
Designing for a tired/new reader forces clarity that also helps experts under pressure. Since 90% of a program's life is reading and maintaining, clarity compounds for all readers.
Why does KISS pay off super-linearly rather than just linearly?
Because is quadratic in : shaving even a few pieces removes a disproportionately large number of interactions, so small simplifications yield large mental savings.
Why prefer a plain loop over a clever recursion, all else equal?
The boring solution matches most readers' mental model and control flow, minimizing understanding-time; cleverness only pays if it removes real complexity, not if it merely looks impressive.
Why is naming for clarity considered a KISS move?
A clear name removes the need for an explanatory comment and lets the reader grasp intent without tracing the code — it lowers reasoning cost, which is what "simple" measures.

Edge cases

Is the empty / do-nothing solution ever the KISS answer?
Yes, when the problem genuinely doesn't require action (e.g. a no-op default), but only if it still actually solves the problem — "simplest that solves it, and no simpler."
A function is already one line and perfectly readable. Should you still split it for Single Responsibility?
No — splitting a trivial, clear unit adds indirection (extra across call boundaries) without lowering load. KISS applies to the split too: don't decompose past the point of clarity.
Two implementations of a behaviour now genuinely exist. Is abstracting them a KISS violation?
No — that's proven duplication, so abstracting via DRY removes real complexity. KISS only forbade the premature version; the second real case is the trigger. :::
The clever one-liner and the simple version produce identical output for all valid inputs. Does KISS still prefer the simple one?
Yes — identical behaviour makes reading cost the tiebreaker, and the readable version wins on understanding-time even though it may have more lines.
A codebase is measured with high cyclomatic complexity but reads clearly. Has KISS failed?
Not necessarily — metrics are proxies. High branching that maps cleanly to real, irreducible cases can be simple; KISS targets unnecessary complexity, so judge by understanding-time, not the number alone.
Is chasing performance a valid reason to abandon a simple design?
Only with measured evidence — otherwise it's premature optimization, which adds complexity for a speed gain you haven't proven you need. KISS defaults to the simple version until profiling justifies otherwise.
The requirement really does have five distinct legal cases. Is five branches a KISS violation?
No — that complexity is essential, driven by the problem, not invented by the coder. KISS removes accidental complexity; it never asks you to under-handle genuinely distinct cases.
You inherit clear but verbose code and a compressed "smart" version. For long-term maintenance, which is more KISS?
The clear verbose one, because readability and understanding-time dominate a program's life; the compressed version trades one-time writing satisfaction for repeated reading pain.

Recall One-line litmus for every trap above

"Could a tired teammate fix this at 2 a.m.?" — if a design choice makes that harder while claiming to be "simpler," it's a trap.