2. Feature Delivery For Most Software Projects
Project Progress
• Complex and messy code
• Code and logic is duplicated
• No common coding standard
• No strict architecture
• ++
8. Traditional code
Main class UserCreator
CreateUser
DbCommand
1. Creates
2. Creates
Inversion of control code
Main class
CreateUser
DbCommand
1. Creates
UserCreator
Dependency
2. Creates with
object from 1.
Dependency
35. 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
36. 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
37. Configuration
Must register what types the container can resolve
Types 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
38. 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
42. Summary
Use an IOC Container to create type instances when using inversion of
control
Only the presentation layer should know about the IOC Container
Configuration: Prefer code over xml
Use auto registration to reduce configuration code
43. Single Responsibility Principle
Single Responsibility Principle = SRP
1 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
44. The God Object
A God object is an object that knows too much or does too much
The opposite of the SRP
51. Future Refactoring
Split into multiple classes when the code increases in size
CreateUser
CreateUserDbCommand
SendEmailConfirmation
52. 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-object
Benefits
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
62. 4-Layered Architecture – Dependency Inversion
Presentation
Application Services
Domain Services
Database, Web Service,
Queue, SMTP server etc.
Domain
Model
Infrastructure
63. 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
64. 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
65. 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
73. 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
74. 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
75. Package By Layer
Application Services
• Account
• Open new account
• OpenNewAccountUseCase
• ICreateAccountCommand
Domain Services
• Account
• Open new account
• CreditCheckService
• IGetTotalDebtForCustomerQuery
...
76. Package By Component
Account
• Application Services
• Open new account
• OpenNewAccountUseCase
• ICreateAccountCommand
• Domain Services
• Open new account
• CreditCheckService
• IGetTotalDebtForCustomerQuery
• ...
Payments
• Application Services
• ...
77. Package By Feature
Account
• Open new account
• OpenNewAccountUseCase
• ICreateAccountDbCommand
• CreditCheckService
• IGetTotalDebtForCustomerQuery
• ...
Payments
• ...
78. 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
79. 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
80. 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 that
1. 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.
81. Summary
Use Inversion of Control to write testable and loosely coupled code
Use Single Responsibility Principle to write small, easy to maintain classes
Use Extract Method Principle & Execute Around Method pattern to reduce
code duplication
Use the Onion Architecture or N-Layer to get a fixed architecture
Package by Layer-, Component- or Feature to get well organized code
Log executed use cases and replay them before a new release to check
for bugs