There are two fundamental approaches to building software systems: the Kokeshi doll model and the Lego model.

Understanding which you’re using — and when to use each — determines whether your system becomes more flexible or more brittle over time. This choice often reflects deeper philosophical differences about engineering — whether we prioritize elegance or practicality.

The Kokeshi Doll Model

Kokeshi dolls (also known as Russian nesting dolls) stack abstractions on top of each other. Each layer adds features and complexity, with different capabilities at each level.

In software, this looks like:

  • Frameworks built on frameworks built on frameworks
  • Each layer adding its own abstractions and conventions
  • Features distributed across multiple levels
  • Deep inheritance hierarchies
  • Middleware stacks with different concerns at each level

Common Kokeshi Examples

Web Framework Stacks

1
2
3
4
5
6
7
8
9
Your Application
  ↓ (uses)
Web Framework (Rails, Django)
  ↓ (uses)  
HTTP Server (Puma, Gunicorn)
  ↓ (uses)
Language Runtime (Ruby, Python)
  ↓ (uses)
Operating System

Each layer has different abstractions:

  • Application layer: Models, controllers, business logic
  • Framework layer: Routing, middleware, ORM
  • Server layer: Request handling, connection pooling
  • Runtime layer: Memory management, garbage collection
  • OS layer: Process management, networking

Enterprise Software Architectures

1
2
3
4
5
6
7
8
9
Business Logic Layer
Service Layer  
Data Access Layer
Database Abstraction Layer
Database Engine

The Lego Model

Lego pieces are composable units that can be combined in countless ways. Each piece has clear interfaces (the connecting studs) and can be used independently or as part of larger structures.

In software, this looks like:

  • Small, focused modules with clear interfaces
  • Composition over inheritance
  • Microservices with well-defined APIs
  • Functional programming with pure functions
  • Plugin architectures

Common Lego Examples

Unix Philosophy

1
cat file.txt | grep "error" | sort | uniq -c | head -10

Each command:

  • Does one thing well
  • Has clear input/output interfaces
  • Can be combined arbitrarily
  • Doesn’t depend on what comes before or after

Microservices Architecture

1
2
3
4
5
User Service ←→ Auth Service
     ↓              ↓
Order Service ←→ Payment Service
     ↓              ↓  
Inventory Service ←→ Notification Service

Each service:

  • Has a single responsibility
  • Communicates through well-defined APIs
  • Can be developed and deployed independently
  • Can be composed into larger workflows

Trade-offs: When to Use Each

Kokeshi Advantages

  • Powerful abstractions: Each layer can provide sophisticated capabilities
  • Incremental learning: You can use surface-level features without understanding deep internals
  • Integrated experience: Everything works together smoothly
  • Rich ecosystems: Frameworks can provide extensive functionality out of the box

Kokeshi Disadvantages

  • Hard to repurpose: Each layer assumes the layers below it
  • Difficult to debug: Problems can exist at any level of the stack
  • Vendor lock-in: Hard to replace individual layers
  • Complexity accumulation: Each layer adds cognitive overhead

Lego Advantages

  • Flexible composition: Pieces can be combined in unexpected ways
  • Easy to replace: Swap out individual components without affecting others
  • Clear boundaries: Well-defined interfaces make reasoning easier
  • Testable in isolation: Each piece can be verified independently

Lego Disadvantages

  • Integration overhead: You have to wire everything together yourself
  • Inconsistent experience: Different pieces may have different patterns
  • More boilerplate: Less magic means more explicit configuration
  • Coordination complexity: Managing many small pieces can be challenging

Recognizing Each Pattern

You’re in Kokeshi territory when:

  • You can’t easily extract one layer without breaking others
  • Adding features requires changes at multiple levels
  • Testing requires setting up the entire stack
  • Documentation focuses on framework conventions rather than interfaces
  • Customization happens through inheritance or configuration

You’re in Lego territory when:

  • Components can be tested in isolation
  • You can easily swap implementations
  • Integration happens through explicit APIs
  • Documentation focuses on inputs, outputs, and contracts
  • Customization happens through composition

Hybrid Approaches

Most successful systems use both patterns strategically:

Kokeshi for integrated experiences:

  • Web frameworks for rapid application development
  • Game engines for graphics and physics
  • Database systems for data management

Lego for customization and flexibility:

  • Plugin systems for extending functionality
  • API gateways for service composition
  • Configuration management for deployment options

The Evolution Pattern

Systems often start as Lego but evolve toward Kokeshi:

  1. Phase 1: Small, composable pieces
  2. Phase 2: Common patterns emerge
  3. Phase 3: Patterns get abstracted into frameworks
  4. Phase 4: Frameworks accumulate features and complexity
  5. Phase 5: New generation of developers builds simpler alternatives (back to Phase 1)

Choosing Your Architecture

Choose Kokeshi when:

  • You need rapid development with consistent patterns
  • The problem domain is well-understood and stable
  • Integration and convention are more important than flexibility
  • You have a team that can learn and maintain the full stack

Choose Lego when:

  • Requirements are likely to change significantly
  • You need to integrate with many external systems
  • Different parts of the system have different scaling needs
  • You want to minimize vendor lock-in and maintain flexibility

The Key Insight

Neither approach is inherently better. The question is: what kind of flexibility do you need?

  • Kokeshi gives you flexibility within the framework’s assumptions
  • Lego gives you flexibility to question and change those assumptions

Understanding this difference helps you choose the right tool for the right job, rather than trying to force every problem into the same architectural pattern.

Sometimes you need the power of nested abstractions. Sometimes you need the freedom of composable pieces.

The best architects know when to use each.