mark pollack principal software engineer springsource arc305
Post on 26-Dec-2015
241 Views
Preview:
TRANSCRIPT
Architecture Refactoring: Improving the Design of Existing Application Architectures
Mark PollackPrincipal Software EngineerSpringSourceARC305
Session Objectives and Agenda
Architectural Decay
Refactoring Overview
Architectural Refactoring
The Problem: Architectural Decay
System works but…Difficult to meet new requirements
Lacks in quality attributes
MaintainabilityExtensibilityPerformance
"Brownfield" development
Component 1
Data Access Layer
Presentation Layer
Component 2
Component 3
Component 5 Component 6
Component 4
How did This Happen?
As software evolves, architecture decaysThe original design
Gets lost in sea of changesCompromised by shortcutsWas never meant to address current requirements
New development is done 'fearfully'Design flaws are not addressed directlyNew features are added by cut-n-paste of old onesThose with the original system knowledge haveManagement fearful of cost/time to make changes
What can be done about it?
Apply refactoring principals to the architectureCode refactorings are more well known
Classify recurrent problems and apply 'recipes' to implement best practices
Refactoring is part of an iterative development processes
Aims for incremental improvements in each cycleInclude the architecture during each cycle
This talk will introduce architectural refactoringsShow by example how to apply
Code Refactoring
"…the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure"
- Martin Fowler
Refactoring as a process
Provides a well defined, generally applicable transformational processCatalogs common problemsSpecifies 'recipes' so that best practices can be incrementally appliedBorn out of experienceProcess can be applied to other artifacts
UML Diagrams, databases, test plansCollectively … the architecture
Refactoring Categories
Code Level – M. FowlerDatabases – S. AmblerDesign Patterns - J. KerievskyArchitecture – M. Stal
Apply changes to structure but not functionalityDistinct process from ReengineeringTypically encompass several other refactoring categories
How a Refactoring is 'Born'
They are discovered, not inventedCome from 'smells'Smells that violate common principals
Separation of Concerns Don't Repeat YourselfYou Ain't Gonna Need It
Architecture Smells
Shortcuts across application layersApplication feels like a 'big ball of mud'An existing layer should be split into two or more logical layersDependency cycles Business logic is tightly coupled to
non-functional requirements
Architecural Refactoring Catalog (I)Courtesy: Michael Stal
Rename EntitiesRemove DuplicatesIntroduce Abstraction HierarchiesRemove Unnecessary AbstractionsSubstitute Mediation with AdaptationBreak Dependency CyclesInject DependenciesInsert Transparency LayerReduce Dependencies with Facades
Merge SubsystemsSplit SubsystemsEnforce Strict LayeringMove EntitiesAdd StrategiesEnforce SymmetryExtract InterfaceEnforce ContractProvide Extension InterfacesSubstitute Inheritance with DelegationProvide Interoperability Layers
Architecural Refactoring Catalog (II)Courtesy: Michael Stal
Introduce AspectsIntegrate DSLsAdd Uniform Support to Runtime AspectsAdd Configuration SubsystemIntroduce the Open/Close PrincipleOptimize with CachingReplace SingletonSeparate Synchronous and Asynchronous ProcessingReplace Remote Methods with Messages
Add Object ManagerChange Unidirectional Association to Bidirectional
Architectural Refactorings in action
Apply as part of a controlled iterative development processGoal is to improve or introduce a set of quality attributesArchitect's role to
Determine the order of refactoringsApply the refactoringsEnsure quality
Example Application
Microsoft's StockTrader example application
Enforce Strict LayeringInject DependenciesIntroduce Aspects
Trade Service Façade (ASMX)
Data Access Layer
WPF
Trade Service Façade (WCF)
Trade Service
ASP.NET
A
A
A A
Prequisite: Create Integration Tests
One must take steps to ensure qualityHow do we know the refactorings are correct?
Does new architecture still meet the specificationNeed integration tests to run as a regressionAutomation is essentialSeveral tools and techniques can helpActs as a safety net
Automated Testing Toolbox
Code focused testing frameworksMSTest, NUnit, mbUnit, etc…
UI focused testing productsWinRunner, LoadTest, Ranorex, Selenium, …
Continuous IntegrationVSTS, CruiseControl, Hudson
Code coverageVSTS, NCover
Build toolsMSBuild, NAnt.
Integration TestsMark PollackPrincipal Software EngineerSpringSource
demo
ProblemLack of strict layering leads to tight coupling
Refactoring : Enforce Strict Layering
ContextNot clear where to place new functionality
Application
Component 3.1 Component 3.1 Component 3.1
Component 2.1 Component 2.2
Component 1.1 Component 1.1 Component 1.1
Layer 2
Layer 3
Layer 1
BrokenLayering
ProblemImpediment to more fine grained testing
SolutionRedesign - new layers, moving of functionality, break data format dependencies
Layering Toolbox
Visualization and enforcement toolsVSTS 2010SotoArcDependency Structure Matrix (DSM)
NDependLattix
Testing Frameworks
Refactoring: Inject Dependencies
ContextObject needs to create and use collaborating objects
Component 1private Component2 c2;public Init() {
S1 s1 = new S1(...); S2 s2 = new S2(...); c2 = new C2(s1,s2); }
Component2
S1
S2
DIContainer
ProblemThe object should not be dependent on knowledge of how to create its collaborators
ProblemHand coded factories are impractical
SolutionSeparate the responsibility of creating collaborating objects to a Dependency Injection (DI) container
private Component2 c2;
public Component2 C2 { set { . . . }}
private Component2 c2;
public Component1 (Component2 c2){
this.c2 = c2;}
The Quick Guide to DI
DI containers act as generalized object factoriesHow to configure a DI container with object creation and configuration rules?Provide metadata
XMLAttributes Fluent API
Autofac Configuration (XML)
<autofac defaultAssembly="Trade.DALSQLServer"> <components> <component type="Trade.BSI.TradeService, " service="Trade.BSC.ITradeServices, Trade.BSC"/>
<component type="Trade.DALSQLServer.Order" service="Trade.IDAL.IOrder, Trade.IDAL" />
<component type="Trade.DALSQLServer.Customer" service="Trade.IDAL.ICustomer, Trade.IDAL"/>
<component type="Trade.DALSQLServer.MarketSummary" service="Trade.IDAL.IMarketSummary, Trade.IDAL"/>
</components>
</autofac>
Autofac Configuration (Fluent API)
var builder = new ContainerBuilder();
builder.Register<TradeService>() .As<ITradeServices>() .ContainerScoped();
builder.Register<Order>() .As<IOrder>() .ContainerScoped();
builder.Register<Customer>() .As<ICustomer>() .ContainerScoped();
builder.Register<IMarketSummary>() .As<MarketSummary>() .ContainerScoped();
NInject (Attributes) public class TradeService : ITradeServices {
[Inject] public TradeService(IOrder dalOrder, ICustomer dalCustomer, IMarketSummary dalMarketSummary) { this.dalOrder = dalOrder; this.dalCustomer = dalCustomer; this.dalMarketSummary = dalMarketSummary; } }
IKernel kernel = new StandardKernel( new InlineModule( x => x.Bind<ITradeServices>().To<TradeService>(), x => x.Bind<IOrder>().To<Order>(), x => x.Bind<ICustomer>().To<Customer>(), x => x.Bind<IMarketSummary>().To<MarketSummary>()));
Unity Configuration (XML)
<type type="Trade.BSC.ITradeServices, Trade.BSC" mapTo="Trade.BSI.TradeService, Trade.BSI "> <lifetime type="singleton" /> <typeConfig extensionType="TypeInjectionElement, Unity.Configuration"> <constructor> <param name="orderDal" parameterType="Trade.IDAL.IOrder, Trade.IDAL"/> </constructor> </typeConfig> </type>
<type type="Trade.IDAL.IOrder" mapTo="Trade.DALSQLServer.Order, Trade.DALSQLServer "> <lifetime type="singleton" /> </type>
Spring Configuration
<object id="tradeService" type="Trade.BSI.TradeService, Trade.BSI"> <constructor-arg ref="orderDal"/> <constructor-arg ref="customerDal"/> <constructor-arg ref="marketSummaryDal"/></object>
<object id="orderDal" type="Trade.DALSQLServer.Order, Trade.DALSQLServer"> <property name="ConnString" value="${orderDalConnStr}"/></object>
<object id="customerDal" type="Trade.DALSQLServer.Customer"> <property name="ConnString" value="${customerDalConnStr}"/></object>
<object id="marketSummaryDal" type="Trade.DALSQLServer.MarketSummary"> <property name="ConnString" value="${marketDalConnStr}"/> </object>
DI and the Runtime Environment
DI containers provide integration support to many common runtime environments
WCFCustom ServiceHost
ASP.NETCustom HttpModule/PageHandlerFactory
ASP.NET MVCTest frameworks
Custom base class or attribute extensions
Example: DI for ASP.NET
<object type="StockTrade.aspx"> <property name="TradeService" ref="tradeService"/></object>
Register custom HttpModule and HttpHandler
Example: DI for ASP.NET MVC
Register custom Controller Factory
<object name="controller.StockTrade" type="StockTrader.StockController, StockTrader" singleton="false">
<property name="TradeService" ref="tradeService"/>
</object>
Example: DI for WCF
Register custom Service Host
<object name="wcfTradeService" type="Trade.StockTraderWebApplication.BusinessServiceClient
singleton="false"> <property name="TradeService" ref="tradeService"/> </object>
Inject DependenciesMark PollackPrincipal Software EngineerSpringSource
demo
Benefits
Application is more easily testableComponents not responsible for self configurationNo custom factories to maintain
Application becomes collection of loosely coupled componentsDivide and conquer implementation approach
Test layers individually, then assembleCan incrementally adopt dependency injectionImproved design automatically 'creeps' in
Refactoring: Introduce Aspects
ContextDecouple components from the surrounding technical infrastructure
ProblemBusiness logic is tied to a technology decreasing its portability and 'life expectancy'Excessive cut-n-paste reuse
SolutionImplement concerns separatelyBring concerns together using Aspect Oriented Programming (AOP)
Non Functional Requirements
Often expressed in terms such asthe service layer should be transactionalA business service that fails with a particular exception failure can be retried Secure every business method invocation
The 1:1 principal"There should be a clear, simple, 1:1 correspondence between design-level requirements and the implementation"
The AOP Value Proposition
Achieve separation of concernsCross cutting concerns in one componentBusiness functionality in another component
But still recombine business and technical requirements into a complete application
System Evolution Without AOP
BankService
Codescattering
Codetangling
TransactionsSecurity
Logging
CustomerService ReportingService
System Evolution With AOP
TransactionAspect
SecurityAspect
LoggingAspect
BankService CustomerService
ReportingService
AOP Terminology
All the possible places one could 'insert' functionality
Join pointWhat is the functionality?
AdviceWhere to insert?
PointcutWhat + Where =
Aspect
AOP Implementation Approaches
Dynamic ProxyBehavior added at run time'Auto generation' of wrapper classes
IL WeavingBehavior added at compile timeAssembly rewriting
AOP + DI in combination is natural and powerful
Example: Transation Management
How to best satisfy the requirement that the service layer should be transactionalAdding transactional boilerplate code in the service layer is prone to errorsSolution: Declarative Transaction Management
Use meta data to specify transactional boundarySelect among several transaction APIs
Transaction Management Proxy
AOP ProxyAOP Proxy
TradeService(target)
TradeService(target)
TransactionAdviceTransactionAdvice
ITradeServicesITradeServicesBuy
ADO.NET Transaction Manager
ADO.NET Transaction Manager
begin commit
System.TransactionsTransaction ManagerSystem.TransactionsTransaction Manager
NHibernate Transaction Manager
NHibernate Transaction Manager
Introduce AspectsMark PollackPrincipal Software EngineerSpringSource
demo
Introduce Aspects: Benefits
Clean simple business codeImplementation looks more like requirementsSystem now has 'conventions' in it
"this namespace is transactional"Ensures we meet requirement
No errors of omissionProvides a contract with developers
they know what to expect.
Just the beginning…Add caching to DAO layer, monitoring etc.
Conclusion
Refactoring is not constrained to code but is applicable to architectureYou can change for the better incrementallyRegression tests are essentialStrict layering is the first things to tackleUse DI and AOP to aid in many architectural refactorings
Refactoring: Improving the Designof Existing Code, Addison-Wesley, 1999
Refactoring Databases: EvolutionaryDatabase Design, Addison-Wesley, 2006
http://stal.blogspot.comOOPSLA Conference Tutorials/Podcasts
Kerievsky, Joshua: Refactoring to Patterns,Addison-Wesley, 2004
Resources
Brownfield Application Development in .NET, Manning 2009
Resources
Related Content
ARC201 - A Lap aroudn Team System 2010 Architecture Edition
ARC303 – Architectural Strategies for Increased Discovery, Integration, and Modularity
Track Resources
Michael Stahl's Blog - http://stal.blogspot.com
Wikipedia entries for Depenency Injection and Aspect Oriented Programming
Spring for .NET Framework - http://www.springframework.net
www.microsoft.com/teched
Sessions On-Demand & Community
http://microsoft.com/technet
Resources for IT Professionals
http://microsoft.com/msdn
Resources for Developers
www.microsoft.com/learningMicrosoft Certification and Training Resources
www.microsoft.com/learning
Microsoft Certification & Training Resources
Resources
question & answer
Complete an evaluation on CommNet and enter to win!
© 2009 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS,
IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
top related