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.

Enforce Consistency through Application Infrastructure - Florin Coros

1,325 views

Published on

When projects do fail for reasons that are primary technical, the reason is often uncontrolled complexity. The complexity goes out of hand when the code lacks structure. In large software projects where many developers work on the same code base one of the biggest challenge is to get consistency in code, to create development patterns for common problems, so you can control the complexity and size of the system.
In this session I will show how we can achieve consistency through structure, rather then 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.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Enforce Consistency through Application Infrastructure - Florin Coros

  1. 1. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals Enforce Consistency through Application Infrastructure Florin Coros www.rabs.ro | www.iquarc.com | onCodeDesign.com florin.coros@rabs.ro @florincoros
  2. 2. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals Many thanks to our sponsors & partners! GOLD SILVER PARTNERS PLATINUM POWERED BY
  3. 3. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals About me @florincoros Founder & Partner Partner Partner .com
  4. 4. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals Many thanks to our sponsors & partners! GOLD SILVER PARTNERS PLATINUM POWERED BY
  5. 5. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 5 Why Consistency is Key?
  6. 6. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 6 Impeded by Others Code?
  7. 7. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 7 Different Solutions to the Same Problem
  8. 8. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 8 Which one is the ONE?
  9. 9. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 9 Cost of Change Wrong approach consistently repeated in all of the application screens vs Uniquely new approach in all of the application screens
  10. 10. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 10 Managing Complexity when projects do fail for reasons that are primarily technical, the reason is often uncontrolled complexity
  11. 11. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 11 Controlling the Complexity uniqueness consistency
  12. 12. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 12 Rules Are Easy to Ignore Quick and Dirty vs The only way to go fast, is to go well!
  13. 13. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 13 Quality through Discipline
  14. 14. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 14 Seniors May Be Overwhelmed with Review
  15. 15. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 15 Quality through Structure • You enforce consistency with structure • Create a structure that makes difficult to write bad code rather then code that follows the design • You use assemblies and references among them to enforce rules • Hide external frameworks to enforce the way they are used • Enforce Constructor Dependency Injection and encourage Programming Against Interfaces
  16. 16. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 16 Assure Consistency in Using External Library by Hiding It <<static class>> Log +LogError() +LogWarining() Exception Wrappers Decorators <<Interface>> API Interfaces
  17. 17. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 17 public interface ILog { void Info(string message, params object[] args); void Warn(string message, params object[] args); void Error(string message, Exception ex); } Enforces Separation of Concerns • The application code only knows about ILog • Once I is defined we can develop screens and call this interface to log traces or errors – The real implementation can be done later • If logging needs changes, we can modify the interfaces at once in all places it is used – The implementation is in only one place, so one place to change only
  18. 18. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 18 Encapsulate Data Access Concerns <<Interface>> TDataModel IRepository +GetEntities<TDataModel>() <<Interface>> TDataModel IUnitOfWork +GetEntities<TDataModel>() +SaveChanges() Database Repository UnitOfWork <<Stereotype>> <<DTO>> Order <<DTO>> Person [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(); } ... } iQuarcDataAccess
  19. 19. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 19 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
  20. 20. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 20 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); } ... }
  21. 21. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 21 Enforce Construction of Unit of Work 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; } }
  22. 22. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 22 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(); } ... } }
  23. 23. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 23 Create Development Patters in how Data is Accessed
  24. 24. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 24 Enforce Separation of Data Access Concerns <<Interface>> TDataModel IRepository +GetEntities<TDataModel>() <<Interface>> TDataModel IUnitOfWork +GetEntities<TDataModel>() +SaveChanges() Database Repository UnitOfWork <<Stereotype>> <<DTO>> Order<<DTO>> Person
  25. 25. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 25 DIP to Enforce Separation of Data Access Concern <<Interface>> TDataModel IEntityInterceptor +OnLoad() +OnSaving() <<Interface>> TDataModel IDbContextFactory +CreateContext() Database <<DTO>> Customer<<DTO>> Order <<DTO>> Person DbContextFactoryUnitOfWork Repository
  26. 26. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 26 DIP to Enforce OnSave/OnLoad Logic out of Data Access <<Interface>> TDataModel IEntityInterceptor +OnLoad() +OnSaving() <<Interface>> TDataModel IDbContextFactory +CreateContext() DbContextFactoryUnitOfWork Repository
  27. 27. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 27 AppBoot as Support <<Attribute>> ServiceAttribute IModule <<Interface>> TDataModel IEntityInterceptor +OnLoad() +OnSaving() <<Interface>> TDataModel IRepository Database <<DTO>> Customer<<DTO>> Order<<DTO>> Person DbContextFactoryUnitOfWork Repository <<Interface>> TDataModel IUnitOfWork
  28. 28. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 28 AppBoot to Enforce Constructor Dependency Injection <<Attribute>> ServiceAttribute + ServiceAttribute() +ServiceAttribute(Type contract) + ServiceAttribute(Type t, Lifetime lifetime) Bootstrapper +Bootstrapper(Assembly[] assemblies) +Run() 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 } } iQuarcAppBoot
  29. 29. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 29 Software systems should separate the startup process, when the application objects are constructed and the dependencies are “wired” together, from the runtime logic that takes over after startup <<Interface>> IModule + Initialize() Application + Initialize() * + Modules[] AppModule1 + Initialize() AppModule2 + Initialize() Enforce Separation of Construction from Use public static void Main(string[] args) { var assemblies = GetApplicationAssemblies().ToArray(); Bootstrapper bootstrapper = new Bootstrapper(assemblies); bootstrapper.ConfigureWithUnity(); bootstrapper.AddRegistrationBehavior(new ServiceRegistrationBehavior()); bootstrapper.Run(); }
  30. 30. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 30 Patters for Creating Services that Depend Only on Interfaces [Service(typeof (IOrderingService))] public 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) { ... } }
  31. 31. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 31 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; } ... }
  32. 32. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 32 Design Patterns like Composition or Chain of Responsibility
  33. 33. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 33 Development Patters in How Dependencies are Created
  34. 34. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 34 No References Between Modules -> Enforce Constraints <<Attribute>> ServiceAttribute + ServiceAttribute() +ServiceAttribute(Type contract) + ServiceAttribute(Type t, Lifetime lifetime)
  35. 35. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals 35 iQuarc iQuarc Dependencies Management Design Patterns in Service Composition Enforce Consistency through Structure Enforce Separation of Concerns Patterns for Queries & Commands Interceptors for Queries & Commands Enforce Consistency through Application Infrastructure iQuarcCode-Design-Training
  36. 36. @ITCAMPRO #ITCAMP16Community Conference for IT Professionals Florin Coros Co-founder & Partner, iQuarc www.iquarc.com Partner, Infiniswiss www.infiniswiss.com .com email: florin.coros@iquarc.com blog: onCodeDesign.com tweet: @florincoros

×