Getting Started with Clean Architecture: A Practical Guide for Beginners
Introduction
Hey there, devs! Let’s talk about one of the coolest and most useful concepts to improve your code: Clean Architecture.
Have you ever found yourself trying to understand messy code or found it hard to add new features without breaking anything?
Clean Architecture is here to save the day!
In this post, I’ll show you the basics of this approach and how it can transform your software projects, making everything more organized and easier to maintain.
Let’s go?
What is Clean Architecture?
So, after all, what is this thing called Clean Architecture?
The Clean Architecture is a software design principle introduced by Robert C. Martin, often referred to as “Uncle Bob.”. Basically, it’s a way to organize your code into well-defined layers, each with its own responsability. To maximize the benefits, it is essential to also follow the principles of Clean Code.
This helps keep things separate and independent, which is great for making maintenance and evolution of the software easier.
Basic Independence Principles
- Framework Independence: The system should not depend on frameworks. They are tools, not solutions;
- Testability: Business logic can be tested independently of implementation details;
- UI Independence: The user interface can change without affecting business logic;
- Database Indendence: The system can work with any database or even without one;
- External Agent Independence: Business rules are isolated from external agents like APIs.
Benefits of Clean Architecture
Adopting Clean Arch brings several benefits to software projects:
- Maintainability: Code is easier to understand and modify;
- Testability: Facilitates the creation of automated tests;
- Flexibility: Changes in one part of the system do not affect other parts;
- Scalability: Facilitates the addiotion of new features;
- Reusability: Well-defined components can be reused in other projects.
Layers of Clean Architecture
Clean Architecture is divided into several layers, each with its own responsabilities. Let’s expore each one:
- Domain Layer (Entities): Domain represents the most general and high-level business rules. The entities in it are independent of any specific technology or framework;
- Application Layer (Use Cases): Use cases contain the specific application logic, orchestrating the interactions between entities and external systems;
- Presentation Layer: The presentation layer is the responsible to be the interface between the business logic and the user interface;
- Infrastructure Layer: This is where the external systems, such as the database, are interacted with.
Implementing Clean Architecture in C#
Let’s look at a simple, but practical, example of how to implement Clean Architecture in a C# project.
- Entities:
public class Customer
{
public Customer(Guid id, string name, string email)
{
Id = id;
Name = name ?? throw new ArgumentNullException(nameof(Name));
Email = email ?? throw new ArgumentNullException(nameof(Email));
}
public Guid Id { get; init; }
public string Name { get; init; }
public string Email { get; init; }
}
public class CreateCustomer
{
public string Name { get; set; }
public string Email { get; set; }
}
- Use Cases:
public interface ICustomerService
{
Guid Add(Customer customer);
Customer GetById(Guid id);
}
public class CustomerService : ICustomerService
{
private readonly ICustomerRepository _customerRepository;
public CustomerService(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
public Guid Add(CreateCustomer request)
{
var id = Guid.NewGuid();
var customer = new Customer(id, request.Name, request.Email);
_customerRepository.Add(customer);
return id;
}
public Customer GetById(Guid id)
{
return _customerRepository.GetById(id);
}
}
- Presentation:
[ApiController]
[Route("customers")]
public class CustomerController : ControllerBase
{
private readonly ICustomerService _customerService;
public CustomerController(ICustomerService customerService)
{
_customerService = customerService;
}
[HttpPost]
public IActionResult Add([FromBody] CreateCustomer request)
{
var id = _customerService.Add(request);
return Ok(id);
}
[HttpGet("{id}")]
public IActionResult Get(Guid id)
{
var customer = _customerService.GetById(id);
if (customer is null)
return NotFound();
return Ok(customer);
}
}
- Infrastructure:
public class CustomerRepository : ICustomerRepository
{
private readonly AppDbContext _context;
public CustomerRepository(AppDbContext context)
{
_context = context;
}
public void Add(Customer customer)
{
_context.Customers.Add(customer);
_context.SaveChanges();
}
public Customer? GetById(Guid id)
{
return _context.Customers.FirstOrDefault(c => c.Id == id);
}
}
Best Practices and Tips
To keep your architecture clean and efficient, follow these best practices:
- Isolate Dependencies: Ensure that your inner layers do not depend on implementation details of the other layers;
- Follow the Single Responsibility Principle (SRP): Each class should have a single and well-defined responsability;
- Facilitate Testing: Use dependency injection to make automated testing easier;
Conclusion
Adopting Clean Architecture can transform the way you develop software, bringing clarity, flexibility, and maintainability to your code. Complementing this approach with the principles of Clean Code can further enhance these benefits.
While it may seem complex at first, constant practice and gradual adoption of its principles and patterns will make this model second nature in your daily work. Try applying these concepts to your projects and see how they can improve the quality and robustness of your software.
Now, you know a lit bit more about Clean Architecture, let me know your thoughts about it. Did you like it?
See ya!