KISS and YAGNI: When to Keep It Simple
Writing simple code and declining to build a possible future feature sound similar, but they are different decisions. KISS concerns the complexity of the solution to today’s requirement. YAGNI concerns whether to add a capability nobody needs yet.
Two different decisions
- KISS: Can I deliver the required behavior clearly and correctly with fewer moving parts?
- YAGNI: Am I adding an unused capability only because I expect someone might need it later?
Confusing these questions can leave a current requirement unfinished or turn every future idea into code.
A CSV export example
Users need to download an existing report from an API as CSV. The required fields and authorization rule are known. Nobody has requested PDF, Excel, or third-party export plugins.
Today’s work is to deliver the right data to an authorized user as valid CSV. That includes the filename, escaping rules, error cases, and necessary checks. A generic plugin engine for every possible format is not needed to complete this task.
KISS — Current solution
Applying KISS here suggests a clear report query, a small CSV writer, and an understandable endpoint flow. We would avoid extra layers, general-purpose factories, and configuration choices that do not help this feature.
The shortest code is not always the simplest solution. A compressed one-liner with unclear failure behavior can be harder to understand and change than a few explicit steps.
YAGNI — A hypothetical future
Applying YAGNI here means waiting to add PDF and Excel output or loadable format plugins until a real need appears. When that happens, we can review the CSV flow and extract shared behavior if there is actual duplication.
YAGNI does not prohibit refactoring that keeps code healthy or tests needed for today’s feature. Code that is easy to change makes it practical to add the capability when it becomes necessary.
What simplicity does not excuse
Neither idea justifies postponing authorization, data correctness, error handling, or accessibility when these are part of the current feature’s correct behavior.
Abstraction is not always wasteful, either. If several real uses share behavior, collecting it in one place may reduce complexity. Base the decision on present requirements and maintenance cost, rather than an imagined number of uses.
Decision questions
- Is there a real scenario using this capability today?
- Does the current solution meet the requirement correctly and clearly?
- Does this extra part help today’s work, or prepare for an assumed future?
- Could I change the code safely if the requirement changes?