# When Patterns Help and When They Hurt — Design Patterns

Source: https://www.skillbyai.com/en/design-patterns/f-when

> Patterns solve problems; they are not goals.

## Pull patterns in, do not push them

Patterns help when you actually have the problem they solve: several interchangeable algorithms (Strategy), an incompatible third-party API (Adapter), a complex object with many optional parts (Builder). They hurt when added speculatively: an interface with one implementation, a factory that only ever creates one class, or five layers of indirection for a CRUD screen. This is **premature abstraction**; it makes code harder to read and change. A good habit is to write the simple version first, and refactor *towards* a pattern when duplication or change requests show you where the flexibility is needed. Also note that many GoF patterns compensate for missing language features; in languages with first-class functions, closures and modules, some patterns shrink to a few lines.

## Over-engineered versus enough

The same tax calculation.

```typescript
// Over-engineered: one rule, three abstractions
interface TaxStrategy { calculate(amount: number): number; }
class StandardTax implements TaxStrategy {
  calculate(amount: number) { return amount * 0.2; }
}
class TaxStrategyFactory {
  create(): TaxStrategy { return new StandardTax(); }
}
const tax = new TaxStrategyFactory().create().calculate(100);

// Enough, until a second tax rule actually appears
const TAX_RATE = 0.2;
const calculateTax = (amount: number) => amount * TAX_RATE;
```

## The rule of three

A common heuristic: tolerate duplication the first two times, and extract an abstraction when the third similar case appears and you can see what really varies.

**Quiz:** Which situation is most likely premature abstraction?

- [ ] A Builder for an object with many optional settings
- [ ] An Adapter wrapping an incompatible payment SDK
- [ ] A Strategy for three real shipping-cost rules
- [x] An interface and factory for a class that has only one implementation and no planned variants

*Answer:* An interface and factory for a class that has only one implementation and no planned variants. Abstractions should follow real variation.
