Post on 12-Nov-2014
description
Application ArchitectureApril 2014
Lars-Erik KindbladSenior Consultant
& Head Of Microsoft Community Of Practice
Feature Delivery For Most Software Projects
Project Progress• Complex and messy code• Code and logic is duplicated• No common coding standard• No strict architecture• ++
Ideal Feature Delivery
Project Progress
Agenda
Testable code Inversion of Control
Maintainable code with less duplication Single Responsibility Principle Extract Method Principle Execute Around Method Pattern
Well structured code N-Layered Architecture & Onion Architecture Ways to group and structure code
Reduce bugs Event Sourcing & replaying events
Inversion Of Control
Make code loosely coupledMake unit testing possible
Traditional Code
Inversion Of Control
Traditional code
Main class UserCreator
CreateUserDbCommand
1. Creates
2. Creates
Inversion of control code
Main classCreateUser
DbCommand
1. Creates
UserCreator
Dependency2. Creates withobject from 1.
Dependency
Dependency Injection - Constructor Injection
Dependency Injection - Interface Injection
Dependency Injection - Setter Injection
Static Service Locator
Injected Service Locator
Which Patterns To Use
Traditional Code
Dependency Injection - Constructor Injection
Dependency Injection - Interface Injection
Dependency Injection - Setter Injection
Static Service Locator
Injected Service Locator
When To Use Which Patterns
Always Use Dependency Injection – Constructor Injection
...except
Facade Classes
Dependency Injection
Service Locator
Loops
Dependency Injection
Service Locator
Base Classes
Dependency Injection
Service Locator
Unknown Types At Compile Time
Service Locator
Summary
Constructor Injection Injected Service Locator
Facade classes(WCF Services,MVC Controllers)
X
Loops X X
Base classes X
Unknown types at compile time
X
All other scenarios X
Inversion Of Control (IOC) Container
A framework that can automatically create an instance of a given type with all the required dependencies
Popular frameworks Unity, Castle Windsor, Ninject, StructureMap etc.
Manual approach
Using an IOC container
Configuration
Must register what types the container can resolveTypes are registered with a life time manager
PerContainer – Container.Resolve<UserCreator> returns the same UserCreator instance every time (Singleton)
Transient – Container.Resolve<UserCreator> returns a new UserCreator instance every time
PerRequest – Container.Resolve<UserCreator> returns the same UserCreator instance within a web request
Configuration can be done through XML – Read from the .config file. Bad practice, too limiting Code – Register all types through code
• Auto registration – Automatically register types based on conventions e.g. all types in assembly x
Where To Plugin
An IOC container should be created and initialized in the presentation layer or or above (DependencyResolution layer)
Any other layer should NOT have a reference to the IOC container
Presentation
Domain
Database, Web Service,Queue, SMTP server etc.
Infrastructure
Don’t reference container here
Don’t reference container here
Should reference and use container
Unity Example 1/3
Unity Example 2/3
Unity Example 3/3
Summary
Use an IOC Container to create type instances when using inversion of control
Only the presentation layer should know about the IOC ContainerConfiguration: Prefer code over xmlUse auto registration to reduce configuration code
Single Responsibility Principle
Single Responsibility Principle = SRP1 of the 5 SOLID principles ”A class or module should have one, and only one, reason to change”
A class should do one thing A class should have only one responsibility
Max 100-200 lines of code per class?The benefits
Easier to give the class a good name Easier to read Easier to maintain & extend Easier to test
The God Object
A God object is an object that knows too much or does too muchThe opposite of the SRP
Current responsibilities:• Facade class• Input validation• Talks to a database• Sends e-mail
Refactored To SRP
UserManager
CreateUser
GetUser
DeleteUser
Refactored UserManager
Responsibility• Facade class
Refactor GetUser & DeleteUser
Responsibility• Return the user from the
database
Responsibility• Delete the user from the
database
Refactored to CreateUser
Responsibility• Input validation• Create the user in the
database• Send confirmation e-mail
Future Refactoring
Split into multiple classes when the code increases in size
CreateUser
CreateUserDbCommand
SendEmailConfirmation
Summary
A class following the single responsibility principle is a class that does only one thing and has only one reason to change
The opposite of SRP is a God-objectBenefits
Easy to give the class a good name Less code per class means
• Reduced complexity = less errors
• Easier to maintain & extend
• Easier to test
Can use the Facade pattern if a special API is required
Code Duplication – Example #1
Duplicated code
Extract Method Principle - Refactored
Code Duplication – Example #2
Duplicated code
Execute Around Method Pattern - Refactored
Execute Around Method - Example #2
1-Layered Architecture
Presentation
Database, Web Service,Queue, SMTP server etc.
2-Layered Architecture
Presentation
Database, Web Service,Queue, SMTP server etc.
Infrastructure
3-Layered Architecture
Presentation
Domain Services
Database, Web Service,Queue, SMTP server etc.
Domain Model
Infrastructure
4-Layered Architecture
Presentation
Application Services
Domain Services
Database, Web Service,Queue, SMTP server etc.
Domain Model
Infrastructure
4-Layered Architecture – Dependency Inversion
Presentation
Application Services
Domain Services
Database, Web Service,Queue, SMTP server etc.
Domain Model
Infrastructure
Domain Model
Domain Services
Presentation
Application Services
Infrastructure
Frameworks and external endpoint integrations
Onion Architecture
A layer can only depend on inner layers
Frameworks and infrastructure concerns are pushed to the outer layer
A change of framework will not affect the application core
Application business rules= use cases
Enterprise business rules
Database, Web Service,Queue, SMTP server etc.
Application Core
Dep
ende
ncy
Res
olut
ion
The Use Case – Open New Account
Create new account in database and return account number
Is personal number empty?
Is the customer credit worthy?
Return error
No
Yes
Yes
No
Dependency Resolution
Domain Model
Domain Services
Presentation
Application Services
Infrastructure
AccountController
Database
Onion Architecture – Open New Account Use Case
• OpenNewAccountUseCase• ICreateAccountCommand
CreateAccount-DbCommand
• CreditCheckService• IGetTotalDebtForCustomerQuery
Web service
GetTotalDebtForCustomer-ServiceAgent
ExecuteUseCase
Process Flow
AccountController
OpenNewAccountUseCase
CreateAccountDbCommand
CreditCheckServiceGetTotalDebtForCustomer-
ServiceAgent
ExecuteUseCase
DependencyResolver Unity IOC Container
Database
Web service
• Transaction management• Exception handling• Logging
Insert/Update/Delete = *CommandRead = *Query
The Use Cases
Open new account
View accounts
Latest transactions
Single payment
Multiple payments
International payment
View Executed payments
View policies
Change address
Change payment limit
Group Into Components
Account•Open new account•View accounts•Latest transactions
Payments•Single payment•Multiple payments•International payment•View Executed payments
Insurance
•View policies
Settings•Change address•Change payment limit
Package By Layer
Application Services
• Account• Open new account
• OpenNewAccountUseCase• ICreateAccountCommand
Domain Services
• Account• Open new account
• CreditCheckService• IGetTotalDebtForCustomerQuery
...
Package By Component
Account
• Application Services• Open new account
• OpenNewAccountUseCase• ICreateAccountCommand
• Domain Services• Open new account
• CreditCheckService• IGetTotalDebtForCustomerQuery
• ...
Payments
• Application Services• ...
Package By Feature
Account
• Open new account• OpenNewAccountUseCase• ICreateAccountDbCommand• CreditCheckService• IGetTotalDebtForCustomerQuery
• ...
Payments
• ...
Change Request Comparison
Package by layer Must change code in multiple projects
Package by component Must change code in 1 project but multiple folders
Package by feature Must change code in 1 project, one folder
Event Sourcing
ExecuteUseCase: _log.UseCase(useCaseInput) generates a stream of executed use cases/events
A use case should either be a command or a query
Serialized data Execution date Status
OpenNewAccountInput 3. march Successful
ChangeAddressInput 4. march Successful
OpenNewAccountInput 7. march Successful
ChangePaymentLimitInput 10. march Failed
ChangePaymentLimitInput 11. march Successful
Replay Use Cases/Events
Stream of use cases/events can be replayed Test the system for errors Restore from failure
How to replay? Make an application that1. Delete all the data in the database
2. Read first event in log
3. Resolve use case class from use case input
4. Execute use case
5. Read next event and goto 23.
Summary
Use Inversion of Control to write testable and loosely coupled codeUse Single Responsibility Principle to write small, easy to maintain classesUse Extract Method Principle & Execute Around Method pattern to reduce
code duplicationUse the Onion Architecture or N-Layer to get a fixed architecturePackage by Layer-, Component- or Feature to get well organized codeLog executed use cases and replay them before a new release to check
for bugs
The information contained in this presentation is proprietary.© 2014 Capgemini. All rights reserved.
www.capgemini.com