Application Architecture April 2014

Preview:

DESCRIPTION

Slides from my talk on application architecture at Capgemini in Fredrikstad

Citation preview

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

Recommended