When Simple Code Beats Design Patterns
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
Simple code wins when the problem doesn't justify the abstraction.
If you have only one way of doing something and no concrete plan to add more, a straightforward method beats creating interfaces and multiple classes. The pattern gives you flexibility you'll never use, but you pay the cost immediately in complexity. Let's say you're building a cart service and you have one discount calculation for standard customers.
Writing a calculateDiscount method is better than introducing Strategy pattern with DiscountStrategy interface, StandardDiscountStrategy class, and DiscountContext. You're adding three new classes to solve a problem that doesn't exist. The threshold I use is: if this logic is unlikely to change in the next six months and I have no second variant, simple code wins.
Another case is stable requirements. If the shipping cost calculation hasn't changed in a year and there's no roadmap item to add variations, the 10 lines of direct code are clearer than a Strategy setup. Patterns optimize for change, but if change isn't happening, you're optimizing for nothing.
Small codebases are another case. In a 300-line utility or a proof-of-concept, patterns add more overhead than structure. You'd spend more time explaining the abstraction than you would just reading the direct implementation.
The key is cost-benefit thinking. Every pattern has a cost — extra classes, more cognitive load, harder debugging. The benefit is flexibility.
If you're not getting the benefit, you shouldn't pay the cost. In an interview, I'd say something like: 'For this scenario, a 5-line method beats creating three new classes for Strategy pattern. If we add a second discount type later, that's when I'd refactor' — that shows pragmatism and judgment, which is what separates good developers from pattern enthusiasts.
When Simple Code Beats Design Patterns
Direct Answer
Simple code wins when you have only one variation of behavior, when the problem is unlikely to change, when the codebase is small, or when introducing a pattern would add more complexity than the flexibility it provides.
Code Example
import java.math.BigDecimal;
// One discount rule, no second variant planned -> a plain method beats Strategy.
class CartService {
BigDecimal totalAfterDiscount(BigDecimal subtotal) {
// 10% off for everyone today; add Strategy only when a 2nd rule appears.
return subtotal.multiply(new BigDecimal("0.90"));
}
}
// Over-engineered alternative for the SAME single rule:
// interface DiscountStrategy { BigDecimal apply(BigDecimal s); }
// class StandardDiscount implements DiscountStrategy { ... }
// class DiscountContext { ... } // 3 files + indirection for zero flexibility gained
If you are adding classes to avoid duplicating three lines, the simple version wins.
Common Mistakes & Pitfalls
- Pattern as Default Choice: Freshers often think 'design patterns are best practices, so more patterns = better code.' They create Factory and Strategy reflexively without asking if the problem justifies the abstraction.
- Ignoring Team Size: In a solo project or two-person team, the communication overhead of patterns often exceeds benefits. Patterns shine in large teams where they provide shared vocabulary, but in small teams, simple code with comments is clearer.
- Future-Proofing Fallacy: Believing that adding patterns now prevents work later — but refactoring simple code to patterns when needed is easier than maintaining unused abstraction. The problem must exist today to justify the solution.
Check your understanding
Answer these without looking back at the article.
- How do you know when a codebase has outgrown a simple approach?
- What is the rule of three in refactoring?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.