In this issue, we will discuss Clean Architecture. What is it, when should you use it, and when should you not? We will find out why vertical slice architecture is necessary, and we will also see some essential learning resources (more than 40) on clean architecture and domain-driven design.
So, let’s dive in.
The Clean Architecture philosophy emphasizes the importance of separating concerns in software design and creating modular, testable, and maintainable code. It was developed by a software engineer and consultant, Robert C. Martin, and introduced in 2012. in this blog post.
At its core, Clean Architecture promotes the idea that software systems should be designed to be understood and maintained by developers over the long term. To achieve this goal, Clean Architecture proposes a layered architecture with clear boundaries between different system components to achieve independence of frameworks, UI, databases, and delivery mechanisms and the possibility to test in isolation. Clean Architecture borrows ideas from Hexagonal Architecture, also known as Ports and Adapters, which emphasizes separating business logic from external dependencies. This architectural pattern facilitates easier testing and promotes flexibility by decoupling the core application from external frameworks and libraries.
The Clean Architecture philosophy defines a set of layers, starting with the most general and abstract layers and moving toward the most concrete and specific layers. These layers include:
Entities. The system's fundamental objects represent the core business logic and data. They encapsulate the most general and high-level rules.
Use cases involve high-level interactions between the system and its users or other external systems containing application-specific business rules. This layer is not expected to affect the entities or external systems.
Interfaces. The mechanisms by which the system communicates with external systems or users. Here, we can have an MVC architecture of a GUI.
Controllers. The components manage the data flow between the other system layers.
Presenters. The components are responsible for presenting data to users or other systems.
Infrastructure. The components are responsible for interacting with external systems or services, such as databases or APIs.
An application structure with Clean Architecture could look like this:
Compared to Onion Architecture, Clean Architecture offers a more precise separation of concerns and a better comprehension of boundaries. They support similar ideals but with various levels and are close relatives.
When should you use Clean Architecture?
We should use Clean Architecture when:
Building complex or long-lived applications where maintainability, testability, and scalability are crucial.
It's suitable for projects where the domain model is central to the application's functionality and needs to be well-defined and encapsulated.
Clean Architecture benefits teams that prioritize clean code practices, separation of concerns, and a domain-driven design approach.
When should we not use Clean Architecture?
Clean Architecture might introduce unnecessary complexity and overhead for small or simple projects with straightforward requirements. It introduces increased complexity, with more layers and abstractions, which can make the codebase more complex.
Projects with tight deadlines or limited resources may not benefit from the upfront investment required to implement Clean Architecture.
If the project's requirements are likely to change frequently or the domain model is not well-understood, a more flexible and agile approach might be more appropriate.
Teams unfamiliar with the architecture: If the development team is not familiar with the principles of Clean Architecture, the learning curve could lead to implementation mistakes and slow development.
Clean architecture makes it crystal clear why each layer is necessary and what their roles are, which is why it is often referred to as Screaming architecture (along with Onion and Hexagonal architectures).
The term "Screaming Architecture" suggests that the architecture should "scream out" its intent and purpose, making it evident to developers, stakeholders, and anyone involved in the project. Here we want to keep domain related code separate from technical details.
For example, if you’re building an e-commerce platform, someone looking at your codebase should immediately see elements like "ShoppingCart," "ProductCatalog," and "CustomerProfile" instead of just "Controllers," "Services," and "DTOs."
This is achieved by following principles such as:
Domain-Centric Design: The architecture should reflect the domain and business logic of the system, making it easy to understand how the software solves real-world problems.
Clear Separation of Concerns: Different parts of the system should have clear and distinct responsibilities with well-defined boundaries. This separation makes it easier to reason about and maintain the codebase.
Dependency Inversion: Dependencies should be abstracted from the core business logic, allowing flexibility and easier testing. This principle promotes loose coupling and high cohesion within the system.
Use of Patterns and Practices: Applying design patterns and best practices helps to standardize the architecture and make it more predictable and understandable.
How to scale your system with Vertical Slice Architecture
When using standard architectural patterns, such as the Layered or Clean architecture approach, where we have N-layers, such architecture doesn't scale well when the application grows. We usually violate the Single Responsibility Principle (SRP), as one functionality is split across many layers. We need to know about all dependencies between layers to implement a feature or fix a bug.
With Vertical Slice Architecture, we build our architecture over different requests, grouping all concerns from the front end to the back end. Here, we couple vertically along the slice, minimizing coupling between slices and maximizing coupling in a slice (things that change together belong together).
This means we don't need many abstractions, such as repositories, services, etc. With this approach, every slice decides how to approach a request. In addition, this approach enables us to test our application better, as the boundaries of the test become a lot cleaner. This allows us to write integration tests with little mocking that are unrelated to the feature we are testing.
The code structure of such architecture would look like this:
How to Learn Clean Architecture and Domain-Driven Design?
While conceptually straightforward, applying clean architecture effectively can have a learning curve. It requires an understanding of dependency injection and good software design practices. If you want to learn more about it, with real-life examples, here are some learning resources:
📚 Books
"Clean Architecture: A Craftsman's Guide to Software Structure and Design," Robert C. Martin https://amzn.to/40XN8yt
"Get Your Hands Dirty on Clean Architecture," Tom Hombergs https://amzn.to/3SZrJ65
📝 Articles
"The Clean Architecture,” Robert C. Martin blog.
"Clean Architecture: Standing on the shoulders of giants,” Herberto Graca.
"DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together", Herberto Graca.
"A Brief Intro to Clean Architecture, Clean DDD, and CQRS,” John Jacobs
"A Template for Clean Domain-Driven Design Architecture," John Jacobs
"CQRS Translated to Clean Architecture,” Filipe Lima.
"Multiple ways of defining Clean Architecture layers," Igor Wojda.
"Rules to Better Clean Architecture," SSW Rules.
"Clean Architecture for .NET Applications," Ivan Paulovich.
"Clean Architecture Essentials," Ivan Paulovich.
"Implementing Clean Architecture in ASP.NET Application," Harsh Matharu.
"Implementing Clean Architecture - Make it scream," Plainionist.
"Adoption of Clean Architecture layers with modules," Anil Gudigar.
“Vertical slice Architecture,” Jimmy Bogard.
⏩ Videos
"Clean Architecture,” Robert C. Martin.
"Clean Architecture: Patterns, Practices, and Principles," Matthew Renze.
"Clean Testing - Clean Architecture with .NET Core," Jason Taylor, NDC Oslo 2020.
"Clean Architecture Example & Breakdown - Do I use it?", CodeOpinion.
"Clean Architecture with ASP.NET Core,” Steve "Ardalis" Smith.
"Clean Architecture & DDD Series," Milan Jovanović.
🗔 Samples
"Learn Domain-Driven Design, software architecture, design patterns, best practices." by Sairyss.
"Clean Architecture Solution Template for ASP.NET Core," by Jason Taylor.
"Clean Architecture Solution Template: A starting point for Clean Architecture with ASP.NET Core," by Steve Smith.
"Go (Golang) Clean Architecture," Iman Tumorang.
"SwiftUI sample app using Clean Architecture," Alexey Naumov.
"Android - Clean Architecture - Kotlin," Fernando Cejas.
"DDD/Clean Architecture inspired boilerplate for Node web APIs," Talysson de Oliveira Cassiano.
🎨 Domain-Driven Design
"Domain-Driven Design: Tackling Complexity in the Heart of Software," book by Eric Evans.
"Domain-Driven Design Distilled," book by Vaughn Vernon.
"An Introduction to Domain-Driven Design (DDD)," Khalil Stemmler.
"Design a DDD-oriented microservice," Microsoft.
"Domain-Driven Design — Designing Software in a Complex Domain," Bibek Shah.
"Domain-Driven Design Starter Modelling Process," DDD Crew.
"Practical DDD," Hila Fox.
"Visualising Socio-Technical Architecture with DDD and Team Topologies," Nick Tune.
"The Bounded Context Canvas," Nick Tune.
"Domain-Driven Design example with problem space strategic analysis and various tactical patterns."
"DDD Beyond the Basics: Mastering Aggregate Design," Mario Bittencourt.
"Domain-driven design practice — Modelling the payments system," Chaojie Xiao.
"Event Storming: a technique to understand complex projects," Danilo Vilhena
More ways I can help you
Patreon Community: Join my community of engineers, managers, and software architects. You will get exclusive benefits, including all of my books and templates (worth 100$), early access to my content, insider news, helpful resources and tools, priority support, and the possibility to influence my work.
Sponsoring this newsletter will promote you to 33,000+ subscribers. It puts you in front of an audience of many engineering leaders and senior engineers who influence tech decisions and purchases.
1:1 Coaching: Book a working session with me. 1:1 coaching is available for personal and organizational/team growth topics. I help you become a high-performing leader 🚀.
It seems you are contradicting yourself here. In the first chapter you say Clean Architecture is good for long-lived software where scalability is crucial and in the next chapter you say Clean Architecture doesn't scale well and you should use Vertical Slices? Doesn't make much sense to me. Why do you introduce Vertical Slices Architecture in between 2 chapters about Clean Architecture? 🤔 What am I missing?