Chapter 3

Bird By Bird

Architecting systems that scale and endure

With the fundamentals in place, we can now explore how to design systems that work in the real world.

The Architecture Stack

Modern technology is built in layers, each depending on the one below:

LayerPurposeExample
ApplicationUser-facing functionalityWeb browsers, mobile apps
FrameworkReusable patternsReact, Django, Rails
LanguageExpression of logicJavaScript, Python, Rust
RuntimeExecution environmentNode.js, JVM, WASM
Operating SystemResource managementLinux, macOS, Windows
HardwarePhysical computationCPUs, GPUs, memory

Design Trade-offs

Every technical decision involves trade-offs. Consider this example:

// Option A: Simple but slower
func processItems(items []Item) []Result {
    var results []Result
    for _, item := range items {
        results = append(results, process(item))
    }
    return results
}

// Option B: Complex but faster (parallel processing)
func processItemsConcurrent(items []Item) []Result {
    results := make([]Result, len(items))
    var wg sync.WaitGroup
    
    for i, item := range items {
        wg.Add(1)
        go func(idx int, it Item) {
            defer wg.Done()
            results[idx] = process(it)
        }(i, item)
    }
    
    wg.Wait()
    return results
}

The second approach is faster but introduces complexity around concurrency. Which is better depends entirely on context.

Scalability Patterns

As systems grow, they face new challenges. Here are common patterns for handling scale:

Horizontal Scaling

Instead of making one machine bigger, add more machines:

  • Load balancers distribute traffic
  • Stateless services can run anywhere
  • Data is replicated across nodes

Caching

Store frequently accessed data closer to where it’s needed:

class CachedUserService:
    def __init__(self, cache, database):
        self.cache = cache
        self.database = database
    
    def get_user(self, user_id: str) -> User:
        # Try cache first
        cached = self.cache.get(f"user:{user_id}")
        if cached:
            return cached
        
        # Fall back to database
        user = self.database.find_user(user_id)
        self.cache.set(f"user:{user_id}", user, ttl=3600)
        return user

Summary

Good system design balances competing concerns: simplicity vs. flexibility, performance vs. maintainability, cost vs. capability.


Next: We’ll explore how these systems fail and how to build resilience.