• Home
  • About
  • Notes
  • Projects
<- Back to notes
notessystem_architecture9/23/2025

Clean Architecture Notes

Practical notes on Clean Architecture based on implementing it in a Go blog project.

Project Reference

This analysis is based on: [https://github.com/kangko05/blog-go]

Core Concepts

Layer Structure

  • Entities (innermost): Core business logic and rules
  • Use Cases/Application: Application-specific business rules
  • Interface Adapters: Controllers, presenters, gateways
  • Frameworks & Drivers (outermost): Database, web framework, external services

Dependency Rule

  • Dependencies point inward only (outer layers depend on inner layers)
  • Inner layers know nothing about outer layers
  • Source code dependencies must point toward higher-level policies

Dependency Inversion

  • High-level modules shouldn't depend on low-level modules
  • Both should depend on abstractions (interfaces)
  • Abstractions shouldn't depend on details; details depend on abstractions

Implementation in Go Blog Project

Repository Pattern

// Domain layer - interface definition
type Repository interface {
    SavePost(post *Post) error
    GetPost(id int) (*Post, error)
    // ...
}

// Infrastructure layer - implementation
type PostRepository struct {
    db *Database
}

func (pr *PostRepository) SavePost(post *Post) error {
    // Database-specific implementation
}

Service Layer

// Application layer
type Service struct {
    repo Repository  // Depends on interface, not implementation
}

func NewService(repo Repository) *Service {
    if repo == nil {
        // Fallback to in-memory implementation
        repo = newMemoryRepository()
    }
    return &Service{repo: repo}
}

Practical Benefits

Testability

  • Can swap real database with in-memory implementation for tests
  • No external dependencies needed for unit testing business logic
  • Each layer can be tested independently

Flexibility

  • Easy to change database (SQLite → PostgreSQL)
  • Can add new interfaces (CLI, web, gRPC) without changing business logic
  • Infrastructure changes don't affect core functionality

Maintainability

  • Clear separation of concerns
  • Business logic isolated from external dependencies
  • Changes in one layer don't cascade to others

Limitations & Trade-offs

Structural Rigidity

  • Changes in core entities often cascade upward through all layers
  • Common utilities and shared modules don't fit neatly into layer boundaries
  • Perfect entity design is nearly impossible in practice

Entity Layer Challenges

  • Requires near-perfect initial design to avoid widespread changes
  • Real-world business logic is messier than theoretical examples
  • Shared concerns (logging, validation, etc.) create dependency dilemmas

When Clean Architecture May Not Be Worth It

  • Small projects with frequent structural changes
  • Prototypes or proof-of-concepts
  • Teams unfamiliar with the patterns (learning curve overhead)
  • Projects with unclear or evolving business requirements

Key Takeaways

When It Works Best

  • Business rules are well-understood and stable
  • Team is experienced with the patterns
  • Long-term maintainability is prioritized over short-term velocity
  • Even small projects benefit from clear structure

Practical Reality

  • Repository pattern is extremely valuable for testability
  • Dependency injection doesn't have to be complex
  • Interface segregation helps keep things focused
  • Start simple, refactor toward clean architecture as requirements stabilize

Bottom Line

Clean Architecture isn't about rigid rules, but about managing dependencies to make code more testable and maintainable. For evolving projects, a pragmatic approach might be starting with simpler patterns and refactoring toward clean architecture as requirements stabilize.