Clean Architecture কী?
Robert C. Martin (Uncle Bob)-এর architecture — dependency inward, business logic framework-independent।
4 Layer Structure
MyApp.sln
├── src/
│ ├── MyApp.Domain/ # Entities, value objects (no deps)
│ ├── MyApp.Application/ # Use cases, interfaces (depends Domain)
│ ├── MyApp.Infrastructure/ # EF Core, external APIs (depends App)
│ └── MyApp.Api/ # Controllers (depends App + Infra)
└── tests/
└── MyApp.UnitTests/
Dependency Rule
Inner layer outer-কে জানে না। Domain → কারো উপর depend করে না। API → Infrastructure → Application → Domain।
Domain Layer
// MyApp.Domain/Entities/Product.cs
public class Product {
public int Id { get; private set; }
public string Name { get; private set; }
public decimal Price { get; private set; }
private Product() {} // EF
public Product(string name, decimal price) {
if (price < 0) throw new DomainException("Price negative");
Name = name; Price = price;
}
public void UpdatePrice(decimal newPrice) {
if (newPrice < 0) throw new DomainException("Invalid");
Price = newPrice;
}
}
Application Layer
// MyApp.Application/Interfaces/IProductRepository.cs
public interface IProductRepository {
Task<Product?> GetByIdAsync(int id);
Task AddAsync(Product p);
Task SaveChangesAsync();
}
// Use case (CQRS handler)
public class CreateProductHandler {
private readonly IProductRepository _repo;
public CreateProductHandler(IProductRepository r) => _repo = r;
public async Task<int> Handle(CreateProductCommand c) {
var p = new Product(c.Name, c.Price);
await _repo.AddAsync(p);
await _repo.SaveChangesAsync();
return p.Id;
}
}
Infrastructure Layer
// MyApp.Infrastructure/Persistence/ProductRepository.cs
public class ProductRepository : IProductRepository {
private readonly AppDbContext _ctx;
public ProductRepository(AppDbContext c) => _ctx = c;
public Task<Product?> GetByIdAsync(int id) => _ctx.Products.FindAsync(id).AsTask();
public async Task AddAsync(Product p) => await _ctx.Products.AddAsync(p);
public Task SaveChangesAsync() => _ctx.SaveChangesAsync();
}
API Layer (Composition Root)
// Program.cs (MyApp.Api) builder.Services.AddDbContext<AppDbContext>(...); builder.Services.AddScoped<IProductRepository, ProductRepository>(); builder.Services.AddMediatR(...);
Benefits
- Domain framework-free → ব্যবসার rule শুধু Domain-এ
- Easy unit test — Mock repository
- EF Core → Dapper swap → শুধু Infrastructure বদলান