skip to content

What do DRY, KISS, YAGNI, and separation of concerns mean, and how do you apply them when writing Java?

level: juniorimportance: should knowfreq 62%

answer

  1. DRY = one authoritative place per piece of knowledge
  2. KISS = simplest thing that works
  3. YAGNI = build for today, not speculation
  4. SoC = one concern per module/layer
  5. DRY is about knowledge, not identical text

basics

~10 s

DRY: 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 s

These 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

for a junior

Can define each acronym and extract an obvious duplicated method or constant to satisfy DRY.

for a middle

Applies all four during refactoring and recognizes layered separation of concerns in a typical Spring app.

for a senior

Articulates the tensions (DRY vs wrong abstraction, YAGNI vs OCP) and makes deliberate trade-off calls.

for a principal

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.

context