Implementing Clean Architecture - Conference Talk

FlorinCoros 42 views 21 slides Sep 25, 2024
Slide 1
Slide 1 of 21
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21

About This Presentation

Has implementing Clean Architecture become more of an ideal than a reality in your projects? Despite its clear rules and intended separations, the complexity of growing codebases and the crunch of time often render these principles invisible in practice. When projects technically fail, the culprit i...


Slide Content

Florin Coro ș [email protected] linkedin.com/in/ florincoros I mplementing Clean Architecture

oncodedesign.com/ DevTalks -Cluj Software Architect Consultant Technical Trainer Founder of Code Design e njoing playing GO e njoing traveling Florin Coro ș

Florin Coro ș [email protected] linkedin.com/in/ florincoros I mplementing 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 4

Decompose - Separation of Concerns 5

Manage the Complexity and Size when projects do fail for reasons that are primarily technical, the reason is often uncontrolled complexity 6

The Architecture is Separation of Concerns and a Set of Rules 7                                                    

Implementing the Architecture 8                                                    

Structure that Supports the Architecture 9

Clean Architecture 10 http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html Dependencies should be in one direction only Source code dependencies can only point inwards

Implementing Clean Architecture through Structure 11 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

Creating a Structure for Clean Architecture 12

Hide External Libraries from App Code 13

Enforce Separation of Data Access Concerns \iQuarc\ DataAccess 14 14

DIP to Enforce Separation of Data Access Concern 15 15

\iQuarc\ AppBoot AppBoot Hides the DI Framework under Abstractions 16 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 } }

AppBoot : DI Abstractions & Type Discovery 17

Patterns on how most of the code is written [ 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) { ... } } 18

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 ; } ... } 19 19

Encapsulate Data Access Concerns \iQuarc\ DataAccess [ 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 (); } ... } 20 20

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 21 21