What do DRY, KISS, YAGNI, and separation of concerns mean, and how do you apply them when writing Java?
answer
- DRY = one authoritative place per piece of knowledge
- KISS = simplest thing that works
- YAGNI = build for today, not speculation
- SoC = one concern per module/layer
- DRY is about knowledge, not identical text
basics
~10 sDRY: don't repeat the same logic — extract it into one method. KISS: keep it simple. YAGNI: don't build features you don't need yet. Separation of concerns: each class/method does one kind of job.
solid answer
~50 sThese are clean-code heuristics that keep Java code maintainable. DRY — 'Don't Repeat Yourself' — means every piece of knowledge lives in one place; you extract duplicated logic into a shared method, helper class, or constant so a change is made once. KISS — 'Keep It Simple, Stupid' — favour the straightforward solution over a clever one. YAGNI — 'You Aren't Gonna Need It' — don't add abstraction or features on speculation; build for today's requirement. Separation of Concerns means each module handles one aspect (parsing, persistence, presentation) so they evolve independently — in Java this shows up as layered packages and single-purpose classes. They interact and sometimes pull against each other: over-applying DRY can couple unrelated code, and over-abstracting violates KISS/YAGNI. Good Java design balances them — extract real duplication, but don't invent indirection for hypothetical needs.
go deeper
Can define each acronym and extract an obvious duplicated method or constant to satisfy DRY.
Applies all four during refactoring and recognizes layered separation of concerns in a typical Spring app.
Articulates the tensions (DRY vs wrong abstraction, YAGNI vs OCP) and makes deliberate trade-off calls.
Sets team conventions and architectural boundaries that operationalize SoC, and coaches when a little duplication or deferred abstraction is the right long-term choice.
## What these principles are These four are **clean-code principles**: language-neutral heuristics for writing code that humans can read, change, and trust. They sit *below* SOLID and design patterns — they're everyday rules of thumb, not structural blueprints. **DRY — Don't Repeat Yourself.** Coined in *The Pragmatic Programmer*. 'Every piece of knowledge must have a single, unambiguous, authoritative representation in a system.' If the same business rule, calculation, or string appears in three places, a change must be made in three places — and you'll miss one. In Java you remove duplication by extracting a `private` method, a shared utility class, a `static final` constant, a base class, or by introducing a parameter. *Caveat:* DRY is about duplicated **knowledge**, not duplicated **text**. Two methods that look identical today but represent unrelated rules (e.g. 'tax rate' and 'discount rate' that happen both to be 0.1) should stay separate — merging them couples concepts that will diverge. **KISS — Keep It Simple, Stupid.** Prefer the simplest design that solves the problem. A plain `if`/loop often beats a reflection-driven, generics-heavy framework. Simplicity aids readability, debugging, and onboarding. In Java this means: don't reach for `Stream`/reflection/inheritance when a method call does; choose clear names; keep methods short and single-purpose. **YAGNI — You Aren't Gonna Need It.** From Extreme Programming. Don't implement something until you actually need it. Speculative generality — adding a configuration knob, a plugin interface, or a layer 'in case we need it later' — usually costs maintenance now and the predicted need never arrives (or arrives differently). In Java this is the antidote to premature interfaces and over-deep class hierarchies. **Separation of Concerns (SoC).** A 'concern' is a distinct aspect of the program: input parsing, business logic, persistence, presentation, logging. SoC says keep these in distinct modules so each can be understood and changed in isolation. In Java this manifests as **layered architecture** (controller → service → repository), single-responsibility classes (the class-level form of SRP), and package boundaries. Frameworks like Spring encourage it (controllers vs services vs repositories). ## How they interact (and tug against each other) These principles overlap and sometimes **conflict**, which is why design is judgement, not rule-following: - **DRY vs KISS/coupling:** aggressively de-duplicating can introduce a shared abstraction that couples two modules that should evolve independently. Sometimes a little duplication is cheaper than the wrong abstraction ('duplication is far cheaper than the wrong abstraction' — Sandi Metz). - **YAGNI vs OCP:** OCP encourages extension points, but YAGNI warns against building them speculatively. The resolution: refactor *toward* an abstraction when a second concrete case actually appears, not before. - **KISS vs patterns:** a design pattern adds structure; if the problem doesn't need it, the pattern is complexity, not clarity. ## Worked example If three controller methods each format a currency the same way, extract a `MoneyFormatter` (DRY + SoC). But if you find yourself adding a `MoneyFormatterFactory` with a `Strategy` interface 'in case we support other formats later', stop — that's a YAGNI/KISS violation until a second format is real. ## Why it matters These principles keep code **changeable**. Most software cost is maintenance, and these heuristics reduce the surface you must touch and reason about per change. But they're heuristics, not laws — apply them with judgement, and let the conflicts between them push you toward the *simplest design that isn't repetitive and matches today's needs*.
- When is duplicating code actually the right call despite DRY?When the two snippets only *look* alike but represent different concepts that will diverge (e.g. two unrelated rates both currently 0.1). Merging them creates a false abstraction that couples unrelated change reasons. 'Duplication is cheaper than the wrong abstraction' — wait until you see the real shared knowledge before extracting.
- How do YAGNI and the Open/Closed Principle coexist without contradicting each other?OCP wants extension points; YAGNI warns against speculative ones. Reconcile by adding the abstraction *reactively*: write the simple concrete code now, and when a genuine second variant appears, refactor to introduce the interface/extension seam. You get OCP's benefit exactly when it's justified, without YAGNI's speculative cost.
saying these in an interview costs you the question
- Treating DRY as 'never have two identical lines' rather than 'no duplicated knowledge'.
- Using KISS to justify skipping needed structure, or YAGNI to skip required functionality.
- Building speculative interfaces/config 'for the future' (YAGNI violation) and calling it good design.
- Claiming these principles never conflict — DRY vs KISS and YAGNI vs OCP routinely trade off.
- Confusing Separation of Concerns (aspect-level) with Single Responsibility (class-level) as if identical.