Badly designed code is one of the highest price we pay as an industry. In many cases the cost of adding or changing features increases with the time we advance into the project. The bigger the project gets, the more complex it gets and the more costly it is to work on it, if it lacks structure. If you need to migrate it, you need to rewrite it all.
In this session I will show from real world projects experience how to keep your team efficient changing the code when you need to move into the Cloud, with what I call the Application Software Infrastructure. It assures code quality through structure rather than relying on discipline only. It documents the architecture into code and bridges this way the architectural diagrams and the code structures.
Architecture decision records - How not to get lost in the past
‘Cloud Ready’ Design through Application Software Infrastructure
1. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
‘Cloud Ready’ Design through
Application Software Infrastructure
Florin Coroș
onCodeDesign.com | www.infiniswiss.com | www.iquarc.com
florin.coros@iquarc.com
@florincoros .com
2. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Many thanks to our sponsors & partners!
GOLD
SILVER
PARTNERS
PLATINUM
POWERED BY
3. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
About me
@florincoros
Co-Founder & Partner
Partner
.com
Co-Founder & Partner
4. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Enterprise
Software
Old Technologies
Costly to
maintain and to
update
Outdated Enterprise Software
4
5. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Legacy System
• High costs to update
• Shitty UX
• Outdated functionalities
• Not scalable, not reliable
Modern System
• Accessible everywhere
• Actual technologies
• Good maintainability
Re-Implement on a Modern Architecture
5
7. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Build and operate for On-Premises, Deployable in Azure
7
Enable a gradual migration into the Cloud
Cloud migration does not require a
rewrite or reengineering
First phase use IaaS
Second phase use PaaS
Quality
Isolation
Separation
Build, Test and
Deploy for
On-Premises
only
Large and
Complex
System
Deployable on
Azure
Use PaaS
8. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Separate the application from the frameworks
8
Source code dependencies can
only point inwards
• Nothing in an inner circle can know anything
at all about something in an outer circle
• Abstractions and application concepts are
independent of frameworks
– frameworks are used as tools, not to cram
the system into their limiting constraintshttp://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
9. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Design Envision
solutions
Setup rules
and practices
Managing
Complexity
Quality
Change
Separations
Abstraction &
Encapsulation
Explain &
Validate
Diagrams Prototypes
What did we already do?
9
10. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Importance of Managing Complexity
10
when projects do fail for reasons that are primarily
technical, the reason is often
uncontrolled complexity
11. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
The gap between the architecture and the code
11
Deployment
Scalability
Availability
Multitenancy
Security
16. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
App Infrastructure: primary TOOL to control complexity and size
16
17. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Invest in Design and Application Infrastructure
Enforce Consistency
Enforce Separation of
Concerns
Focus on Modularity, Abstraction, Encapsulation
Loosely Coupled
Modules
Hide the frameworks
Manage Dependencies
Dependency Injection
Discoverability
How to do it?
17
18. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Abstract and hide external libraries / frameworks
18
Exception Wrappers Decorators
<<Interface>>
API Interfaces
<<static class>>
Log
+LogError()
+LogWarining()
19. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Enforce separation of logging concern
19
public interface ILog
{
void Info(string message, params object[] args);
void Warn(string message, params object[] args);
void Error(string message, Exception ex);
}
This interface only changes if my application logging
needs changes
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
20. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Implementing a clean architecture
20
Usecases
Adapters
Exception Wrappers Decorators
<<Interface>>
API Interfaces
21. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Encapsulate Data Access Concerns
21
<<Interface>>
TDataModel
IRepository
+GetEntities<TDataModel>()
<<Interface>>
TDataModel
IUnitOfWork
+GetEntities<TDataModel>()
+SaveChanges()
Database
Repository UnitOfWork
<<Stereotype>>
<<DTO>>
Order
<<DTO>>
Person
iQuarcDataAccess
[Service(typeof(IRepository))]
internal class EfRepository : IRepository, IDisposable
{
public EfRepository(IDbContextFactory contextFactory,
IInterceptorsResolver resolver)
{
...
}
...
}
internal class EfUnitOfWork : IUnitOfWorjk
{
public EfUnitOfWork(IDbContextFactory contextFactory,
IInterceptorsResolver resolver)
{
...
}
...
}
22. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Patterns on how DataAccess is used in all the application code
22
<<Interface>>
TDataModel
IRepository
+GetEntities<TDataModel>()
<<Interface>>
TDataModel
IUnitOfWork
+GetEntities<TDataModel>()
+SaveChanges()
Database
Repository UnitOfWork
<<Stereotype>>
<<DTO>>
Order
<<DTO>>
Person
public class OrdersController : Controller
{
private readonly IRepository repository;
public OrdersController(IRepository repository)
{
this.repository = repository;
}
[HttpGet]
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,
});
return View(orders);
}
...
}
[HttpPost]
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. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Enforce Separation of Data Access Concerns
23
<<Interface>>
TDataModel
IRepository
+GetEntities<TDataModel>()
<<Interface>>
TDataModel
IUnitOfWork
+GetEntities<TDataModel>()
+SaveChanges()
Database
Repository UnitOfWork
<<Stereotype>>
<<DTO>>
Order<<DTO>>
Person
24. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Lightweight library that handles the startup of an application
Implements Separation of
Construction and
Configuration from Use
Modularity
Defines and abstracts a
modular application
Makes the application
independent of the host
process
Dependencies Management
Dependency Injection
Enforces consistency in
declaring dependencies
Encourages good practices
Encourages separation
between data and behavior
AppBoot Library
24
iQuarcAppBoot
25. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
AppBoot gives abstractions to declare dependencies
25
<<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
26. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Patters for creating services that depend only on interfaces
26
[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)
{
bool isApproved = orderApproval.Approve(request);
}
}
27. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
AppBoot defines an abstraction for a modular application
27
• Modular Application Support
• Application modules do not depend on
Frameworks
• Application can be hosted in any .NET
process
<<Interface>>
IModule
+ Initialize()
Application
+ Initialize()
*
+ Modules[]
AppModule1
+ Initialize()
AppModule2
+ Initialize()iQuarcAppBoot
28. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
Application Hosted in Any .NET Process
28
• The application is not aware of the process it is hosted in
– The application is isolated from framework specifics
• The host process is not aware of what modules it hosts
– The host process is isolated from application logic
• Benefits:
– Flexible deployments
• same host can load different modules depending on
configuration
• Flexibility in development and testing
– Framework setup is separated from application setup
<<Attribute>>
ServiceAttribute
+ ServiceAttribute()
+ServiceAttribute(Type contract)
+ ServiceAttribute(Type t, Lifetime lifetime)
Bootstrapper
+Bootstrapper(Assembly[] assemblies)
+Run()
Application
+ Initialize()
iQuarcAppBoot
29. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
.NET Framework
WF
WCF
WEB API
ASP.NET
Entity
Framework
. . . Unity
NServiceBus Log4Net
. . .
Application Infrastructure
Application Functionalities
Application Infrastructure – Shaping to Context
29
30. @ITCAMPRO #ITCAMP18Community Conference for IT Professionals
https://onCodeDesign.com/ITCamp2018
iQuarc iQuarc
Dependencies
Management
Design Patterns in
Service Composition
Enforce Consistency
through Structure
Enforce
Separation of Concerns
Patterns for
Reading and Writing Data
Application Infrastructure to Control Complexity and Size
30
iQuarcCode-Design-Training
onCodeDesign.comtraining
Clean Architecture
My name is Florin Coros
I live in Cluj-Napoca
I like to go to ROCK concerts
I like to travel with my girl-friend
I like to play GO. GO is a game that thought me to look a few steps ahead, which turned to be very useful for me…
I tweet quite a lot
I am a big fan of Uncle Bob
I am a Software Architect at ISDC
I am one of the cofounders of RABS
I am part of iQuarc
Old enterprise software which works:
- Investment companies,
- Banks
- Insurance companies
- healthcare software (companies that have software products they install and operate in large hospitals)
Old Technologies, which do not scale and do not have a modern UI
- Progress, or other 4GL languages
- Delphi
Difficult to maintain and to update with new regulations
- hard to find developers in old technologies
- no one knows, dears to change some parts of the system
They want to rewrite it again!
If you come from Delphi or Progress, and you are in the enterprise, usually you are going to choose Microsoft Application Platform
6’
On-Premise:
An enterprise already has a large datacenter
The datacenter needs to be managed anyhow for a long time for many other systems
The migration in the cloud of every app, cannot be done overnight
Keeping data in the could can be problematic for some organizations
SaaS are not interesting for an large organization
Cloud:
The enterprise:
They know that this is the future, so they want to facilitate the migration there, not to make it more difficult
Software vendor
Sell for big organizations stand-alone solution in their datacenters and offer SaaS for small businesses -> multitenancy
Target for OnPremises, and
Deployable in Cloud is an important requirement
Take advantage of Azure Services
The target is that when needs to be migrated into the Cloud we do not rewrite, we can make a plan.
- we cannot say we did not know and this is a change for which we need to rewrite / reengineer
14’
15’
18’
Application Software Infrastructure is composed by:
Application Framework elements: the framework implements and is in control of certain aspects. The framework calls the code I am writing
Application Toolkit elements: a set of utilities specific for my application which my code calls
Abstracts and hides external libraries and frameworks providing my application with a framework independence, and also assuring a consistent way in using those libraries
Conventions and Rules on how to implement things
Same Solutions to identical problems
Most important, the Application Infrastructure provides a clear structure in my application code, which gives consistency and which translates into efficiency and quality
You can thing of it as the foundation on top of which I develop the application
It also dictates the structure and how the entire building is going to be build
Like in construction, after the Architect defines the architecture which lays out all the designs and the calculation of the building clearly defines if it is an:
Office building
House
Block of apartments
Hotel
Theater
And takes into account all sort of concerns like: electricity, water, evacuation, heat, parking places etc.
The same happens in software development: after the architect defines and documents the architecture, we want a common structure to build on and to follow:
We should have one SOLUTION to same problem CONSISTENCY
Data Access, Logging, Error Handling, Localization,
How would be a house build without an foundation or infrastructure?
One electricity solution for the kitchen, one for the bathroom other for the bedroom?
One type of bricks for one wall, other for another wall. How does the paint stick on each? higher complexity
How about the roof?
23’
The rooms are built differently. With different bricks and materials. The roof is the other way around
Not only that the house is differently build, but the COMPLEXITY is higher:
- how will I paint it? NOW I need paint that sticks on wood and on bricks
24’
We want our code to look like the one on the right!
We want to be able to identify patterns on how our code is written
I don’t necessary mean the known Design Patterns, but patterns specific to our project, Patterns that clearly say how we do things in this project, how this concern is addressed or implemented
A system with patterns is going to have a manageable complexity.
It is maintainable even if it is very complex and large is size
Patterns make it simple
A system in which everything is unique is going to be difficult to change and maintain.
Even if it is small and simple, the uniqness, the chaos makes it complex
25’
- Enforces Separation of Concern!
31’
Encapsulates ALL data access concerns
Assures a consistent way to do data access
any component that has to access data has to use a IRepository or an IUnitOfWork
Constraints SoC: DA from BLL
Encapsulates ALL data access concerns
Assures a consistent way to do data access
any component that has to access data has to use a IRepository or an IUnitOfWork
Constraints SoC: DA from BLL
37’
Lightweight library which defines and abstracts a modular application
Configures and initializes the application
Two main parts:
- Modularity
Dependency Injection
Enforces Dependency Injection through Constructor only
- By hiding the underlying DI Container it makes that the configuration of it can ONLY be done at app startup through annotations or conventions
39’
Dependencies are visible in the constructor
Can see classes that have too many dependencies –> poor cohesion refactor to loose coupling
Dependencies are on interfaces ONLY Loose Coupled code
Testable code
Emphasis on the fact that it can be hosted in any .NET process
Abstracts the app
Separates it from the frameworks
Link w/ Clean Architecture picture
Outline that there are no dependencies among the process dlls and the application dlls
WindowsService for On-Premises - Worker Role in Azure
41’
42’
A question I always get
- Technical / strategic debt can be done bellow the line
No Design, no trade-off:
no matter how less attention I will pay to the design I will still go slow. I am impeded by the mess.
Less quality -> less options -> more unexpected things -> slower you are
Design: I can make the trade-off
- Red team productivity NEVER decreases. See above chart with productivity going to 0.
- It is important to know where you are. As long as you are under the line you may take technical debt but you must be aware! To be able to keep it under control
- When not pay attention to design:
- Prj finishes before the intersection point: prototype, throw away, PoC
- CHALLENGE: unaware of having bad code or taking too big technical debt.
It takes us by surprise
- By being on the blue line with our prj most of the times we have done a great job in making our customers/managers not to trust us!
51’
All projects have a slower start and then the efficiency increases. The project reaches an healthy productivity rate after the design payoff line
Begin 55’
All projects have a slower start and then the efficiency increases. The project reaches an healthy productivity rate after the design payoff line
51’
28’30”
skip or go fast on SalesEntities
skip
We could even take out from the VS Solution the DbContextProvider project if the Context.tt generate is triggered by the SalesEntities.tt and a post build event of the DataModel assembly also builds the DbContextProvider.csproj