Clean Architecture: A Craftsman's Guide to Software Structure and Design receives mixed reviews. Many praise its focus on SOLID principles and decoupling, while others find it repetitive and lacking practical examples. Some readers appreciate the historical context and anecdotes, while others feel they detract from the core content. The book is generally seen as helpful for understanding high-level architectural concepts, but opinions vary on its usefulness for beginners versus experienced developers. Several reviewers note that the book's content could have been conveyed more concisely.
Software architecture is about minimizing human resources and maximizing productivity
Clean architecture separates business rules from external details
SOLID principles guide the creation of flexible, maintainable systems
Components are the building blocks of a clean architecture
Boundaries define and protect the core business logic
Clean architecture facilitates test-driven development and independent deployability
Frameworks and databases are implementation details, not architectural elements
The web is just another delivery mechanism in clean architecture
Clean embedded architecture separates hardware concerns from business logic
Microservices and service-oriented architectures can benefit from clean architecture principles
The goal of software architecture is to minimize the human resources required to build and maintain the required system.
Architectural decisions matter. Good architecture reduces the effort required to develop, deploy, and maintain software systems. It allows teams to work independently, minimizes the impact of changes, and enables the system to evolve over time.
Key aspects of good architecture:
Separation of concerns
Dependency management
Abstraction of implementation details
Flexibility to accommodate future changes
By focusing on these aspects, architects can create systems that are easier to understand, modify, and extend, ultimately leading to increased productivity and reduced costs over the system's lifetime.
The center of your application is not the database. Nor is it one or more of the frameworks you may be using. The center of your application is the use cases of your application.
Business rules are the core. Clean architecture organizes code into concentric circles, with business rules at the center and implementation details at the outer layers. This separation allows the core business logic to remain unaffected by changes in external factors such as databases, user interfaces, or frameworks.
Key layers in clean architecture:
Entities: Enterprise-wide business rules
Use Cases: Application-specific business rules
Interface Adapters: Convert data between use cases and external agencies
Frameworks and Drivers: External tools and technologies
By adhering to this structure, developers can create systems that are:
More flexible and adaptable to change
Easier to test and maintain
Less dependent on specific technologies or frameworks
The SOLID principles tell us how to arrange our functions and data structures into classes, and how those classes should be interconnected.
SOLID enhances modularity. These five principles provide guidelines for creating software systems that are more understandable, flexible, and maintainable. They help developers design code that is resistant to changes and easy to extend.
The SOLID principles are:
Single Responsibility Principle: A class should have only one reason to change
Open-Closed Principle: Software entities should be open for extension but closed for modification
Liskov Substitution Principle: Objects of a superclass should be replaceable with objects of its subclasses without affecting the program's correctness
Interface Segregation Principle: Many client-specific interfaces are better than one general-purpose interface
Dependency Inversion Principle: High-level modules should not depend on low-level modules; both should depend on abstractions
By applying these principles, developers can create more robust and scalable software architectures that can adapt to changing requirements over time.
Components are the units of deployment. They are the smallest entities that can be deployed as part of a system.
Modular design enables flexibility. Components in clean architecture are independently deployable and developable parts of the system. They encapsulate related functionality and have well-defined interfaces, allowing for easier maintenance and modification of the system.
Key characteristics of well-designed components:
High cohesion: Related functionality grouped together
Low coupling: Minimal dependencies between components
Clear interfaces: Well-defined methods of interaction
Independent deployability: Can be updated or replaced without affecting other parts of the system
By organizing systems into components, architects can:
Facilitate parallel development by different teams
Enable easier testing and debugging
Allow for incremental updates and improvements to the system
Improve overall system scalability and maintainability
At each architectural boundary, we are likely to find the Humble Object pattern lurking somewhere nearby.
Boundaries protect the core. Architectural boundaries in clean architecture separate different areas of concern, particularly between business logic and implementation details. These boundaries help maintain the independence of the core business rules from external changes.
Key aspects of architectural boundaries:
Use of interfaces to define interactions between layers
Dependency inversion to ensure that dependencies point inward
Data transfer objects to pass information across boundaries
Humble objects to separate testable behavior from hard-to-test components
By establishing clear boundaries, architects can:
Minimize the impact of changes in external systems or technologies
Facilitate easier testing of core business logic
Enable the replacement of implementation details without affecting the core system
Improve overall system flexibility and adaptability
A good architecture makes the system easy to change, in all the ways that it must change, by leaving options open.
Testability and flexibility are key. Clean architecture promotes practices that make systems easier to test and deploy independently. By separating concerns and managing dependencies, it becomes simpler to write unit tests for core business logic and to deploy different components of the system separately.
Benefits of clean architecture for testing and deployment:
Core business rules can be tested without UI, database, or external dependencies
Different components can be deployed independently, allowing for easier updates
Changes in one area of the system have minimal impact on others
New features can be added with less risk of breaking existing functionality
These characteristics lead to:
Faster development cycles
Reduced risk in deployments
Improved system reliability
Greater flexibility in adopting new technologies or changing existing ones
Frameworks are tools to be used, not architectures to be conformed to.
Core logic should be framework-agnostic. Clean architecture treats frameworks and databases as external details that should not influence the core business logic. This approach allows for greater flexibility in changing or updating these external elements without affecting the system's core functionality.
Key principles for handling frameworks and databases:
Treat them as plugins to the core business logic
Use dependency inversion to keep core logic independent
Create abstractions for database operations
Delay framework and database decisions as long as possible
Benefits of this approach:
Easier to change or upgrade frameworks and databases
Core business logic remains stable despite external changes
Reduced vendor lock-in
Improved testability of core system components
The web is a delivery mechanism, and your application architecture should treat it as such.
Business logic is delivery-agnostic. In clean architecture, the web is treated as an external detail, similar to databases or frameworks. This perspective allows the core business logic to remain independent of the specific delivery mechanism, whether it's a web application, desktop app, or API.
Key considerations for web applications in clean architecture:
Separate web-specific code from core business logic
Use interface adapters to convert between web formats and internal data structures
Treat web frameworks as plugins to the core system
Design use cases to be independent of web-specific concerns
Benefits of this approach:
Easier to adapt the system to different delivery mechanisms
Core business logic can be reused across multiple platforms
Simplified testing of business rules without web dependencies
Greater flexibility in changing or updating web technologies
Although software does not wear out, it can be destroyed from within by unmanaged dependencies on hardware.
Hardware independence is crucial. Clean embedded architecture applies the principles of clean architecture to embedded systems, separating hardware-specific concerns from core business logic. This separation allows for easier updates to hardware components and improved portability of the software.
Key elements of clean embedded architecture:
Hardware Abstraction Layer (HAL) to isolate hardware-specific code
Device-independent business logic
Clear interfaces between hardware and software components
Use of dependency inversion to manage hardware dependencies
Benefits of this approach in embedded systems:
Easier to port software to new hardware platforms
Simplified testing of core logic without hardware dependencies
Reduced impact of hardware changes on overall system
Improved maintainability and longevity of embedded software
The architecture of a system is defined by boundaries that separate software elements from one another, and restrict those on one side from knowing about those on the other.
Clean principles apply at all scales. While clean architecture is often discussed in the context of monolithic applications, its principles can be effectively applied to microservices and service-oriented architectures. These principles help maintain the independence and testability of individual services while managing the complexity of distributed systems.
Applying clean architecture to microservices:
Treat each microservice as a bounded context with its own clean architecture
Use well-defined interfaces for inter-service communication
Apply dependency inversion between services
Maintain independent deployability of services
Benefits of clean architecture in microservices:
Improved modularity and scalability of the overall system
Easier to understand and maintain individual services
Greater flexibility in evolving and replacing services
Reduced coupling between services, leading to more robust systems