Skip to the content.

Use with judgement

Everything in this repo – the patterns, SOLID, DRY – is a tool for a specific problem, not a rule to comply with. That framing matters, because every one of these tools has a cost, and paying the cost without having the problem makes code worse. Design maturity isn’t knowing the patterns; it’s knowing when not to use them.

Every tool has a price

The benefit column in this repo’s tables is real, but so is the invoice:

Tool Solves Costs when the problem isn’t there
Builder Many optional fields Fifty lines of ceremony for a two-field class – a constructor was clearer
Simple Factory Callers coupled to concrete types An indirection layer over a single new that never varies
Strategy Multiple interchangeable algorithms An interface, a context, and one lonely implementation – an if was clearer
Interfaces everywhere Multiple implementations / substitution in tests BookService + BookServiceImpl pairs that only ever have one member
SRP Unrelated reasons-to-change tangled together Logic shattered into confetti – ten two-line classes nobody can follow
DRY One piece of knowledge in several places Coincidentally-similar code welded together, coupling rules that change separately
Observer Many independent reactions to an event Control flow nobody can trace – “what happens when I restock?” has no findable answer

Signals you’re overdoing it

Signals you’re underdoing it

How to calibrate

  1. Start with the simplest thing that works. A constructor, a plain method, one class.
  2. Let the problem show up before the solution. The second or third time a change hurts, the real shape of the abstraction is visible – extract it then (the “rule of three”). Patterns applied speculatively usually guess the wrong axis of change.
  3. Refactor toward patterns, don’t start from them. Their biggest everyday value is vocabulary: “this wants to be a Strategy” is a one-sentence design review.
  4. Match the effort to the mattering. The order-money path deserves DIP and careful seams; a one-off report script does not.

The tests in this repo model this deliberately: each one demonstrates a pattern earning its keep against a concrete problem – telescoping constructors, drifting VAT copies, an untestable payment call. If your code doesn’t have the problem, it shouldn’t have the pattern.