Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Implementing Clean Architecture

Clean Architecture as a term is around for a while. However, the path to implement it is not always clear nor easy to follow. When projects fail for reasons that are primary technical, the reason is often uncontrolled complexity. The complexity goes out of hand when the code lacks structure, when it lacks Clean Architecture.

In this presentation, I will show how to achieve consistency by
implementing Clean Architecture through structure, rather than relying on discipline only. We will look at some basic building blocks of an application infrastructure which will enforce the way dependencies are created, how dependency injection is used or how separation of the data access concerns is enforced.

  • Login to see the comments

  • Be the first to like this

Implementing Clean Architecture

  1. 1. Florin Coroș florin@onCodeDesign.comwww.onCodeDesign.com/training Implementing Clean Architecture
  2. 2. https://onCodeDesign.com/implementing-clean-architecture Co-Founder & Partner About me @florincoros Partner https://onCodeDesign.com/training Founder & Partner
  3. 3. Florin Coroș florin@onCodeDesign.comwww.onCodeDesign.com/training Implementing Clean Architecture
  4. 4. https://onCodeDesign.com/implementing-clean-architecture Why is Architecture Important -- Robert C. Martin, Clean Architecture The goal of software architecture is to minimize the human resources required to build and maintain the required system
  5. 5. https://onCodeDesign.com/implementing-clean-architecture Decompose - Separation of Concerns Title Title Title Title Title Title Title
  6. 6. https://onCodeDesign.com/implementing-clean-architecture Manage the Complexity and Size when projects do fail for reasons that are primarily technical, the reason is often uncontrolled complexity
  7. 7. https://onCodeDesign.com/implementing-clean-architecture The Architecture is Separation of Concerns and a Set of Rules External Interfaces UI Frameworks Devices Controllers EntitiesEntities Use Cases
  8. 8. https://onCodeDesign.com/implementing-clean-architecture Implementing the Architecture External Interfaces UI Frameworks Devices Controllers EntitiesEntities Use Cases
  9. 9. https://onCodeDesign.com/implementing-clean-architecture Structure that Supports the Architecture External Interfaces UI Frameworks Devices Controllers EntitiesEntities Use Cases
  10. 10. https://onCodeDesign.com/implementing-clean-architecture Clean Architecture External Interfaces UI Frameworks Devices Controllers EntitiesEntities Use Cases http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html Presenter Controller UseCase Implementation Presenter Controller UseCase Implementation UseCase InputAbstraction UseCase OutputAbstraction Dependencies should be in one direction only Source code dependencies can only point inwards
  11. 11. https://onCodeDesign.com/implementing-clean-architecture Implementing Clean Architecture through Structure • Hide external frameworks to enforce the way they are used • Use assemblies and references among them to enforce rules • Enforce Constructor Dependency Injection that encourages Programming Against Interfaces Create a structure that makes it difficult to write bad code and it makes it easy to write good code, code that follows the architecture and the design
  12. 12. https://onCodeDesign.com/implementing-clean-architecture Creating a Structure for Clean Architecture <<interface>><<interface>> ILogger +LogError() Logger +LogError() <<public interface>><<public interface>> ILogger +LogError() <<Internal class>><<Internal class>> Logger +LogError() External Interfaces UI Frameworks Devices Controllers EntitiesEntities Use Cases
  13. 13. https://onCodeDesign.com/implementing-clean-architecture Hide External Libraries from App Code <<Internal class>><<Internal class>> Exception Wrappers <<public Interface>> <<public Interface>> API Interfaces <<Internal class>><<Internal class>> Decorators
  14. 14. https://onCodeDesign.com/implementing-clean-architecture <<Interface>> TDataModel IRepository +GetEntities<TDataModel>() <<Interface>> TDataModel IUnitOfWork +GetEntities<TDataModel>() +SaveChanges() Database EfRepository EfUnitOfWork <<Stereotype>> <<DTO>> Order <<DTO>> Person Enforce Separation of Data Access Concerns iQuarcDataAccess
  15. 15. https://onCodeDesign.com/implementing-clean-architecture DIP to Enforce Separation of Data Access Concern <<Interface>> IDbContextFactory +CreateContext() Database <<DTO>> Customer<<DTO>> Order<<DTO>> Person UnitOfWork Repository DbContextFactory <<Interface>> TDataModel IRepository, IUnitOfWork +GetEntities() +SaveEntities()
  16. 16. https://onCodeDesign.com/implementing-clean-architecture AppBoot: DI Abstractions & Type Discovery <<Interface>> TDataModel <<Interface>> TDataModel IEntityInterceptor +OnLoad() +OnSaving() <<Interface>> TDataModel <<Interface>> TDataModel IDbContextFactory +CreateContext() Database <<DTO>><<DTO>> Customer<<DTO>><<DTO>> Order<<DTO>><<DTO>> Person <<DTO>> Customer<<DTO>> Order<<DTO>> Person UnitOfWork Repository UnitOfWork Repository DbContextFactory <<Attribute>><<Attribute>> ServiceAttribute
  17. 17. https://onCodeDesign.com/implementing-clean-architecture <<Attribute>> ServiceAttribute +ServiceAttribute(interface : Type ) Bootstrapper +Run() <<Internal>> DependencyContainerAdapter iQuarcAppBoot AppBoot Hides the DI Framework under Abstractions public interface IPriceCalculator { int CalculateTaxes(Order o, Customer c); int CalculateDiscount(Order o, Customer c); } [Service(typeof(IPriceCalculator), Lifetime.Instance)] interal class PriceCalculator : IPriceCalculator { public int CalculateTaxes(Order o, Customer c) { return 10; // do actual calculation } public int CalculateDiscount(Order o, Customer c) { return 20; // do actual calculation } }
  18. 18. https://onCodeDesign.com/implementing-clean-architecture Patters forCreating Services thatDepend Only onInterfaces [Service(typeof (IOrderingService))] private class OrderingService : IOrderingService { private readonly IRepository repository; private readonly IPriceCalculator calculator; private readonly IApprovalService orderApproval; public OrderingService(IRepository repository, IPriceCalculator calculator, IApprovalService orderApproval) { this.repository = repository; this.calculator = calculator; this.orderApproval = orderApproval; } public SalesOrderInfo[] GetOrdersInfo(string customerName) { var orders = repository.GetEntities<SalesOrderHeader>() ... return orders.ToArray(); } public SalesOrderResult PlaceOrder(string customerName, OrderRequest request) { ... } }
  19. 19. https://onCodeDesign.com/implementing-clean-architecture Enforce Constructor DI to Prevent Circular Dependencies [Service(typeof(IApprovalService))] class ApprovalService : IApprovalService { private readonly IPriceCalculator priceCalculator; public ApprovalService(IPriceCalculator priceCalculator) { this.priceCalculator = priceCalculator; } ... } [Service(typeof (IPriceCalculator), Lifetime.Instance)] public class PriceCalculator : IPriceCalculator { private readonly IApprovalService approvalService; public PriceCalculator(IApprovalService approvalService) { this.approvalService = approvalService; } ... }
  20. 20. https://onCodeDesign.com/implementing-clean-architecture <<Interface>> TDataModel IRepository +GetEntities<TDataModel>() <<Interface>> TDataModel IUnitOfWork +GetEntities<TDataModel>() +SaveChanges() Database EfRepository EfUnitOfWork <<Stereotype>> <<DTO>> Order <<DTO>> Person Encapsulate Data Access Concerns iQuarcDataAccess [Service(typeof (IRepository))] internal class EfRepository : IRepository, IDisposable { private readonly IDbContextFactory contextFactory; private readonly IInterceptorsResolver interceptorsResolver; private DbContext context; private readonly IEnumerable<IEntityInterceptor> interceptors; public EfRepository(IDbContextFactory contextFactory, IInterceptorsResolver resolver) { this.contextFactory = contextFactory; this.interceptorsResolver = interceptorsResolver; this.interceptors = resolver.GetGlobalInterceptors(); } ...
  21. 21. https://onCodeDesign.com/implementing-clean-architecture public interface IRepository { IQueryable<TDbEntity> GetEntities<TDbEntity>() where TDbEntity : class; IUnitOfWork CreateUnitOfWork(); } public interface IUnitOfWork : IRepository, IDisposable { void SaveChanges(); void Add<T>(T entity) where T : class; void Delete<T>(T entity) where T : class; void BeginTransactionScope(SimplifiedIsolationLevel isolation); } Create Separated Patterns for Read-Only and Read-Write
  22. 22. https://onCodeDesign.com/implementing-clean-architecture Patterns for Read-Only data public class OrdersController : Controller { private readonly IRepository repository; public OrdersController(IRepository repository) { this.repository = repository; } public IActionResult Index(string customer) { var orders = repository.GetEntities<SalesOrderHeader>() .Where(soh => soh.Customer.Person.LastName == customer) .Select(soh => new OrdersListViewModel { CustomerName = customer, Number = soh.SalesOrderNumber, SalesPersonName = soh.SalesPerson, DueDate = soh.DueDate, }); return View(orders); } ...
  23. 23. https://onCodeDesign.com/implementing-clean-architecture Patterns for Read-Write data public class OrdersController : Controller { ... [HttpPost] [ValidateAntiForgeryToken] public IActionResult PlaceOrder(OrderRequestViewModel model) { ... using (IUnitOfWork uof = repository.CreateUnitOfWork()) { SalesOrderHeader order = uof.GetEntities<SalesOrderHeader>() .FirstOrDefault(o => o.CustomerID == c.ID && o.OrderDate.Month == DateTime.Now.Month); if (order == null) { order = new SalesOrderHeader {Customer = c}; uof.Add(order); } AddRequestToOrder(model, order); uof.SaveChanges(); } ... } }
  24. 24. https://onCodeDesign.com/implementing-clean-architecture Consistency Creates Optimizations Opportunities internal class EfRepository : IRepository, IDisposable { public IQueryable<T> GetEntities<T>() where T : class { return Context.Set<T>().AsNoTracking(); } public IUnitOfWork CreateUnitOfWork() { return new EfUnitOfWork(contextFactory, interceptorsResolver); } private sealed class EfUnitOfWork : IUnitOfWork { private DbContext context; private TransactionScope transactionScope; private readonly IDbContextFactory contextFactory; public EfUnitOfWork(IDbContextFactory contextFactory, IInterceptorsResolver resolver) { this.contextFactory = contextFactory; this.interceptorsResolver = interceptorsResolver; } }
  25. 25. https://onCodeDesign.com/implementing-clean-architecture Create Development Patterns in Code
  26. 26. https://onCodeDesign.com/implementing-clean-architecture Implementing Clean Architecture through Structure External Interfaces UI Frameworks Devices Controllers EntitiesEntities Use Cases <<Attribute>><<Attribute>> ServiceAttribute RepositoryImpl + GetEntities<T>() : IQueriable() + SaveChanges() Hide external frameworks to enforce the way they are used Use assemblies and references among them to enforce rules Enforce Constructor Dependency Injection that encourages Programming Against Interfaces /iQuarc iQuarc onCodeDesign.com/training
  27. 27. https://onCodeDesign.com/implementing-clean-architecture Florin Coroș Author & Trainer, onCodeDesign onCodeDesign.com Co-founder & Partner, InfiniSwiss www.infiniswiss.com Co-founder & Partner, iQuarc www.iquarc.com email: florin@onCodeDesign.com blog: onCodeDesign.com tweet: @florincoros https://onCodeDesign.com/training

×