What is YAGNI
YAGNI stands for You Aren't Gonna Need It. Don't build functionality until it's actually required.
The Principle
YAGNI: You Aren't Gonna Need It
Always implement things when you actually need them,
never when you just forecast that you will need them.
— Kent Beck, Extreme Programming
Why YAGNI Matters
Without YAGNI:
- Build features "just in case"
- Waste time on unused code
- Increase maintenance burden
- Add complexity for nothing
- Slow down development
With YAGNI:
- Build only what's needed now
- Save time for actual requirements
- Keep codebase lean
- Reduce complexity
- Ship faster
The Cost of YAGNI Violations
Feature built preemptively:
- Development time: 2 days
- Testing time: 1 day
- Documentation: 0.5 days
- Maintenance per year: 0.5 days
- Total if never used: 3.5 days wasted + ongoing maintenance
Same feature built when needed:
- Development time: 2 days
- Testing time: 1 day
- Documentation: 0.5 days
- Total: 3.5 days (same, but no waste)
Common YAGNI Excuses
| Excuse | Reality |
|---|---|
| "We'll need it later" | You probably won't |
| "It's easy to add now" | It's easier to add when needed |
| "Other systems have it" | You're not other systems |
| "The architect said so" | Architects can be wrong |
| "It's a best practice" | Context matters |
When YAGNI Applies
- Building a new feature "just in case"
- Adding configuration options for hypothetical use cases
- Creating abstraction layers for potential future needs
- Implementing caching before measuring performance
- Adding notification channels before users request them
Premature Optimization
Premature optimization is adding performance improvements before you've proven they're needed.
The Quote
"Premature optimization is the root of all evil."
— Donald Knuth
Actually, he said:
"We should forget about small efficiencies, say about 97% of the time:
premature optimization is the root of all evil.
Yet we should not pass up our opportunities in that critical 3%."
Premature Optimization Examples
// BAD: Premature caching
public class UserService {
private final Cache<String, User> cache = new LRUCache<>(1000);
public User getUser(String id) {
return cache.get(id, () -> database.findById(id));
}
}
// Problem: Database is fast enough, caching adds complexity for no benefit
// GOOD: Simple first, optimize later
public class UserService {
public User getUser(String id) {
return database.findById(id);
}
}
// Add caching when you measure slow queries
// BAD: Premature connection pooling
public class OrderService {
private final ConnectionPool pool = new ConnectionPool(50);
public void processOrder(Order order) {
Connection conn = pool.getConnection();
// ...
}
}
// Problem: Application handles 10 requests/second, pool is unnecessary
// GOOD: Simple connection
public class OrderService {
public void processOrder(Order order) {
Connection conn = database.getConnection();
// ...
}
}
Signs of Premature Optimization
- Optimizing before measuring: Adding complexity without profiling
- Optimizing hot paths that aren't hot: Caching rarely-accessed data
- Over-engineering for scale: Building for 1M users when you have 100
- Adding layers: Cache, queue, CDN before you need them
- Complex algorithms: Using advanced data structures for small datasets
The Right Approach
1. Write simple, correct code
2. Measure performance
3. Find actual bottlenecks
4. Optimize the bottlenecks
5. Measure again
NOT:
1. Guess where bottlenecks might be
2. Add complex optimizations
3. Hope it helps
Performance Rules
| Situation | Approach |
|---|---|
| DB query takes 10ms | Leave it, it's fast enough |
| DB query takes 100ms | Maybe optimize |
| DB query takes 1s | Definitely optimize |
| 100 users | Simple architecture |
| 1M users | Consider scaling |
| 100M users | Optimize aggressively |
When Optimization IS Needed
- After measuring and finding actual bottlenecks
- When SLAs require specific performance
- When user experience degrades
- When costs are too high
- When scaling to new scale levels
Practical Examples
Real-world examples of applying YAGNI in system design.
Example 1: Notification System
// BAD: Building all channels upfront
public class NotificationService {
private EmailSender email;
private SmsSender sms;
private PushSender push;
private SlackSender slack;
private WebhookSender webhook;
private DiscordSender discord;
private TelegramSender telegram;
// All channels built, only email is used
}
// GOOD: Build what you need, add when requested
public class NotificationService {
private final Map<Channel, NotificationSender> senders;
public NotificationService() {
// Only email for now
this.senders = Map.of(Channel.EMAIL, new EmailSender());
}
// Add SMS when users request it
// Add Push when mobile app launches
}
Example 2: Plugin System
// BAD: Plugin system for fixed features
public class PluginManager {
private Map<String, Plugin> plugins = new HashMap<>();
public void loadPlugins() {
// Complex plugin loading, registry, lifecycle management
// For 3 fixed features that never change
}
}
// GOOD: Simple service classes
public class FeatureService {
private final FeatureA featureA;
private final FeatureB featureB;
private final FeatureC featureC;
// When you actually need plugins, refactor then
}
Example 3: Internationalization
// BAD: i18n framework before any non-English users
public class MessageService {
private ResourceBundle messages;
private LocaleResolver resolver;
private MessageFormatter formatter;
public String getMessage(String key, Locale locale) {
return formatter.format(messages.getString(key), locale);
}
}
// Problem: All users are English-speaking, this adds complexity for nothing
// GOOD: Simple string constants
public class Messages {
public static final String WELCOME = "Welcome!";
public static final String GOODBYE = "Goodbye!";
}
// Add i18n when you have international users
Example 4: Audit Logging
// BAD: Audit logging before compliance requires it
public class OrderService {
private AuditLogger audit;
public void createOrder(Order order) {
audit.log("Creating order: " + order);
// ... create order
audit.log("Order created: " + order.getId());
}
}
// GOOD: Simple logging when needed
public class OrderService {
private Logger log = LoggerFactory.getLogger(OrderService.class);
public void createOrder(Order order) {
log.info("Creating order");
// ... create order
}
}
// Add audit logging when compliance requires it
YAGNI in System Design
| Premature | YAGNI Approach |
|---|---|
| Multi-region deployment | Single region, add when global users exist |
| Auto-scaling | Fixed instances, add when load varies |
| Event sourcing | Simple CRUD, add when audit trail needed |
| CQRS | Simple reads/writes, add when read/write patterns differ |
| Service mesh | Direct communication, add when services grow |
The YAGNI Mindset
- Prove you need it: Show actual usage or measurement
- Delay decisions: The last responsible moment
- Simple first: Easy to change later
- Measure: Don't guess, profile
- Refactor: When the need is proven, refactor cleanly
Practice Problems
Design a scalable YAGNI system. Cover high-level architecture, data model, and API design.
Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliabilityHow would you scale YAGNI to handle 10x the current load? Identify bottlenecks and solutions.
Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decompositionAnalyze potential failure modes for YAGNI and design mitigation strategies.
Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradationQuiz
1. What does YAGNI stand for?
2. Why is premature optimization harmful?
3. When should you add a caching layer?
4. Which is a YAGNI violation?
5. What is the right approach to performance?
Flashcards
Question
What is YAGNI?
Click to reveal answer
Answer
You Aren't Gonna Need It. Don't build functionality until it's actually required. Avoid building features "just in case."
Question
What is premature optimization?
Click to reveal answer
Answer
Adding performance improvements before measuring and proving they're needed. Adds complexity for potential benefits that may never be realized.
Question
When is premature optimization harmful?
Click to reveal answer
Answer
When you add caching, pooling, or complex algorithms before measuring actual performance problems. The complexity is wasted if the optimization isn't needed.
Question
What is the YAGNI mindset?
Click to reveal answer
Answer
1) Prove you need it. 2) Delay decisions. 3) Simple first. 4) Measure, don't guess. 5) Refactor when need is proven.
Question
YAGNI + KISS + DRY?
Click to reveal answer
Answer
YAGNI: don't build what you don't need. KISS: build it simply. DRY: don't repeat yourself. Together: build only needed things, simply, without duplication.
Revision Notes
Key Takeaways
- 1.YAGNI means don't build functionality until it's actually required
- 2.Premature optimization adds complexity for benefits that may never be realized
- 3.Build only what you need, when you need it, in the simplest way possible
- 4.Measure performance before optimizing — don't guess at bottlenecks
- 5.YAGNI, KISS, and DRY work together to reduce unnecessary complexity
Interview Tips
- •Explain YAGNI when discussing why you chose simpler solutions
- •Show you understand the cost of premature optimization
- •Discuss when you WOULD add complexity (measured need, proven bottleneck)
- •Mention YAGNI when explaining design decisions that avoid over-engineering
Cheat Sheet
YAGNI - Cheat Sheet
Definition:
You Aren't Gonna Need It. Don't build until actually required.
Premature Optimization:
- Adding caching before measuring
- Connection pooling for small apps
- Complex algorithms for small data
- Building for scale you don't have
YAGNI Approach:
- Prove you need it
- Delay decisions
- Simple first
- Measure, don't guess
- Refactor when proven
Common Violations:
- Plugin system for fixed features
- i18n before international users
- Audit logging before compliance
- Multi-region before global users
- Auto-scaling for predictable load
YAGNI + KISS + DRY:
- YAGNI: Don't build it
- KISS: Build it simply
- DRY: Don't repeat it