Skip to content
intermediatePhase 49 · Low-Level Design

YAGNI

You Aren't Gonna Need It: build only what's required now.

30m
0 problems
Topic Progress0%

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

  1. Optimizing before measuring: Adding complexity without profiling
  2. Optimizing hot paths that aren't hot: Caching rarely-accessed data
  3. Over-engineering for scale: Building for 1M users when you have 100
  4. Adding layers: Cache, queue, CDN before you need them
  5. 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

  1. Prove you need it: Show actual usage or measurement
  2. Delay decisions: The last responsible moment
  3. Simple first: Easy to change later
  4. Measure: Don't guess, profile
  5. Refactor: When the need is proven, refactor cleanly

Practice Problems

0/3solved
Design YAGNI System

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 & reliability
YAGNI Scaling

How 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 decomposition
YAGNI Failure Modes

Analyze 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 degradation

Quiz

1. What does YAGNI stand for?

Question 1 options

2. Why is premature optimization harmful?

Question 2 options

3. When should you add a caching layer?

Question 3 options

4. Which is a YAGNI violation?

Question 4 options

5. What is the right approach to performance?

Question 5 options

Flashcards

Question

What is YAGNI?

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?

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?

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?

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?

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:

  1. Prove you need it
  2. Delay decisions
  3. Simple first
  4. Measure, don't guess
  5. 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