SOLID, DRY, KISS & YAGNI

Principles that keep code easy to change as a system grows.

Beginner9 min read3 interview questions

Good system design starts inside each service. Principles like SOLID give teams a shared way to reason about responsibilities, dependencies and change.

They are guidelines, not laws. Applied blindly they produce layers of abstractions nobody needs; applied with judgement they keep a codebase cheap to change.

Diagram

Code that iseasy to changeSingle responsibilityone reason to changeOpen / closedextend, don’t editLiskov substitutionsubtypes keep promisesInterface segregationsmall, focused contractsDependency inversiondepend on abstractionsDRY · KISS · YAGNI
Five SOLID principles plus three simplicity rules, all serving one goal.

Key concepts

S — Single responsibility
A class or module should have one reason to change. Split billing rules from email formatting.
O — Open/closed
Add behaviour by adding code (a new strategy class), not by editing a growing switch.
L — Liskov substitution
Any subtype must work wherever its base type is expected, without surprises.
I — Interface segregation
Prefer several small interfaces over one large one that forces empty implementations.
D — Dependency inversion
High-level policy depends on interfaces; infrastructure implements them. This is what makes testing easy.
DRY
Don’t repeat yourself — one source of truth for each piece of knowledge, not just each line of code.
KISS & YAGNI
Keep it simple, and don’t build for requirements you don’t have yet.

Trade-offs

Benefits

  • Smaller, focused units are easier to test
  • Changes stay local instead of rippling across the code
  • Teams share a vocabulary for design reviews

Costs

  • Over-applied, they create needless interfaces and indirection
  • Premature DRY can couple things that only look similar

Use it when

  • Designing service internals and domain models
  • Reviewing code that is hard to test or change

Common mistakes

  • An interface for every class “just in case” (violates YAGNI)
  • Merging two similar functions that later need to diverge
  • God classes such as UtilityManager that everything depends on

Interview questions

Q1Give an example of the open/closed principle.
A payment service with an IPaymentProvider interface. Adding a new provider means adding a new class and registering it, without editing the existing checkout code.
Q2How does dependency inversion help testing?
Business logic depends on an interface such as IOrderRepository. In tests you supply a fake implementation, so no real database is needed.
Q3When is it right to duplicate code?
When two pieces look alike but change for different reasons. Duplication is cheaper than the wrong abstraction; merge later if they truly stay the same.