LESSON 2.6
DRY, KISS, YAGNI and the Law of Demeter
Four lightweight heuristics that prevent unnecessary complexity before a class grows large enough to need a refactor.
6 min read
These four heuristics are not patterns — they are questions you ask while writing a class. Together they prevent the most common sources of unnecessary complexity before a design gets large enough to require a structural refactor.
DRY: don't repeat yourself
DRY is about knowledge, not about text. If two places compute VAT in the same way, a change to the VAT rate must be applied in two places. That duplication is a bug waiting to happen.
// Before: VAT duplicated in two services.
class CartService {
total(items) { return items.reduce((s, i) => s + i.price, 0) * 1.2; }
}
class InvoiceService {
amount(lines) { return lines.reduce((s, l) => s + l.net, 0) * 1.2; }
}
// Changing VAT from 20% to 21% requires finding and fixing both.DRY says extract the knowledge: create a TaxCalculator that both services call. The rate lives in one place.
The anti-pattern is incidental duplication: two functions that look the same today but will diverge tomorrow. Merging them prematurely creates an awkward shared function that serves neither caller well. Only merge what represents the same piece of knowledge.
KISS: keep it simple
Every abstraction you add must be learned by the next engineer. If the problem can be solved with a function and a Map, a class hierarchy with a factory and a flyweight is not simpler — it is harder.
KISS says solve the problem at hand, not the imagined harder problem. The simplest solution that correctly handles the actual requirements is the right one.
YAGNI: you ain't gonna need it
Adding a plugin registry to a single-user tool "just in case" is not good engineering — it is speculative generality. The plugin system will never be used, but it must be maintained, documented and tested. Every YAGNI violation steals time from features users actually need.
YAGNI does not forbid extensibility. It says: wait until the second use case before abstracting. When two real callers need the same thing, extract it. Not before.
Law of Demeter: talk to your friends, not to strangers
The Law of Demeter says a method should call only:
- its own methods
- methods of its direct parameters
- methods of objects it creates locally
- methods of its own fields
In practice: avoid chains of more than one dot.
In code
Using the heuristics together
Ask these four questions at the end of every design review:
- DRY: is this piece of knowledge expressed in more than one place?
- KISS: is there a simpler way to solve this specific problem?
- YAGNI: am I solving a problem that doesn't exist yet?
- LoD: does this method reach through more than one layer to get a value?
Each question takes ten seconds. Together they catch the most common sources of accidental complexity before the design hardens.
Try it
Coupon Rule Engine LLD
Apply DRY by extracting the discount calculation into a single Coupon.apply() method before adding stacking rules.