0/0
Design Principles

Pragmatic Principles

The famous one-liners every programmer quotes โ€” DRY, KISS, YAGNI, Composition over Inheritance, Law of Demeter. Each is a smell-and-fix you can spot in 30 seconds. Together they cash out as the same goal SOLID and GRASP encode formally: low coupling, high cohesion, and code you can read aloud.

Explore Topics

๐Ÿ”
DRY
Don't Repeat Yourself โ€” but only when it's the SAME rule.
Smell Clinic ยท Patient #1: DRY
Symptom
boolean validateUsername(String s) {
    if (s == null) return false;
    if (s.isEmpty()) return false;
    if (s.trim().length() == 0) return false;
    return true;
}
boolean validateEmail(String s) {
    if (s == null) return false;
    if (s.isEmpty()) return false;
    if (s.trim().length() == 0) return false;
    return s.contains("@");
}
boolean validateCity(String s) {
    if (s == null) return false;
    if (s.isEmpty()) return false;
    if (s.trim().length() == 0) return false;
    return true;
}
The same non-blank check is inlined three times. Three places to fix when the rule changes.
Which principle is violated?
๐Ÿ”
DRY
Don't Repeat Yourself โ€” but only when it's the SAME rule.

Hunt and Thomas, in The Pragmatic Programmer (1999), wrote: "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." DRY is about knowledge, not characters. Two methods that LOOK the same but encode different business rules should stay separate; their resemblance is coincidence. Two encodings of the SAME rule โ€” in code and in a database trigger, or copied across three validators โ€” are duplication. Find the rule, name it once, call it from everywhere. The trap: premature DRY creates the wrong abstraction, which is much harder to fix than honest duplication.

Key Ideas
  • Hunt & Thomas โ€” The Pragmatic Programmer (1999), the canonical source
  • DRY of KNOWLEDGE, not characters โ€” two same-looking methods can both be correct
  • Sandi Metz: "duplication is far cheaper than the wrong abstraction"
  • Rule of three โ€” wait for the third occurrence before extracting
  • Cousin principle: SRP (a class has one reason to change โ†’ one place to change)
Strengths
  • โœฆSingle source of truth โ€” change in one place propagates to all callers
  • โœฆReveals intent: extracted name documents the rule
  • โœฆCuts maintenance cost when the rule genuinely evolves
  • โœฆAligns with SRP and Information Expert from GRASP
Weaknesses
  • โ–ณPremature DRY creates the wrong abstraction โ€” much harder to unwind than duplication
  • โ–ณCan couple callers that should evolve independently
  • โ–ณEasy to over-apply by spotting syntactic similarity instead of semantic identity
  • โ–ณOften fights YAGNI ("don't generalize speculatively")
Used in:Spring's @Validated and Jakarta Bean Validation collapse three hand-written validators into one @NotBlank annotation per field. The annotation IS the DRY refactor โ€” the rule (a non-blank String) lives in one place and is referenced declaratively from every model.
Code Snippets

Quiz

DRY Quiz
QUIZ 1/6
Two service classes contain methods that look almost identical. Both compute a discount as `price * 0.10`. One is the holiday discount; the other is the loyalty discount. The two are governed by separate marketing teams. Should you DRY them into a shared helper?

Diagrams

Law of Demeter โ€” who is a friend?
Loading diagram...
Pragmatic principles map to their named cousins
Loading diagram...

Practice

Classify each smell into the principle it violates. Drag each card to the right bucket.
EXERCISE 1/4
Identical null + isEmpty check copy-pasted across three validators
The same business rule lives in code AND in a database trigger
Five nested ternaries in one expression returning a letter grade
Map<String,Object> "options bag" passed everywhere; all callers send empty
class MyStack extends ArrayList โ€” to "reuse the storage"
order.getCustomer().getAddress().getCity().startsWith("606")
user.getAccount().getBalance().compareTo(BigDecimal.ZERO) > 0
DRY violation
KISS violation
YAGNI violation
Composition-over-Inheritance violation
Law of Demeter violation
Find the Law-of-Demeter train wreck
EXERCISE 2/4
Click on the line you think contains the bug, then press Confirm.
1 1 class ShippingCalculator {
2 2 double surcharge(Order order) {
3 3 // Reach into the customer's address to read the ZIP code
4 4 String zip = order.getCustomer().getAddress().getZip();
5 5
6 6 if (order.isPremium()) return 0.0;
7 7 if (zip.startsWith("9")) return 5.50;
8 8 if (zip.startsWith("6")) return 3.00;
9 9 return 2.50;
1010 }
1111 }
Pragmatic principle myths โ€” which are TRUE?
EXERCISE 3/4
DRY means: you should never have two methods with similar-looking code.
KISS forbids using design patterns since patterns add complexity.
YAGNI exempts security, error handling, and basic observability.
Composition over Inheritance means: never use the extends keyword.
Stream chains like list.stream().filter(...).map(...) violate the Law of Demeter.
When DRY and YAGNI disagree, you should always pick DRY.
Refactor the train wreck
EXERCISE 4/4
// BEFORE โ€” three types accessed in one line: // String area = customer.getAddress().getCity().substring(0, 3); class Customer { private Address address; String shippingAreaCode() { return ; // ask your DIRECT friend } } class Address { private String city; String () { // owns the answer return city.substring(0, 3); } }

References

๐Ÿ“š

Hunt & Thomas โ€” The Pragmatic Programmer, 20th Anniversary Edition

pragprog.com

book
๐Ÿ“š

Martin Fowler โ€” Refactoring (Speculative Generality, Duplicated Code, Message Chains, Long Method smells)

martinfowler.com

book
๐Ÿ“š

Joshua Bloch โ€” Effective Java, Item 18: Favor composition over inheritance

oreilly.com

book
๐Ÿ“„

Martin Fowler โ€” "Yagni"

martinfowler.com

article
๐ŸŽฌ

Sandi Metz โ€” "All The Little Things" (RailsConf 2014, on premature abstraction)

youtube.com

video
๐Ÿ“‹

Wikipedia โ€” Law of Demeter

en.wikipedia.org

docs