• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Accu2010 archrefactoring
 

Accu2010 archrefactoring

on

  • 1,867 views

 

Statistics

Views

Total Views
1,867
Views on SlideShare
1,849
Embed Views
18

Actions

Likes
1
Downloads
30
Comments
0

3 Embeds 18

http://www.scoop.it 9
http://www.linkedin.com 7
http://www.lmodules.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Accu2010 archrefactoring Accu2010 archrefactoring Document Transcript

    • Dr. Michael Stal: Architecture Refactoring Architecture Refactoring – Motivation, Approach and Patterns accu 2010 Dr. Michael Stal Panta rhei There is nothing permanent except change [Heraclitus, 535–475 BC] Page 2 © Dr. Michael Stal, 2010 1
    • Dr. Michael Stal: Architecture Refactoring Refactoring Learning objectives  Understand about design erosion and how to avoid it  Learn about the principles of refactoring  Know about activities and best practices necessary for refactoring  Understand how reengineering and rewriting differ from refactoring Page 3 Refactoring Agenda  Motivation and foundation  Refactoring  Reengineering  Rewriting  Comparison  Summary Page 4 © Dr. Michael Stal, 2010 2
    • Dr. Michael Stal: Architecture Refactoring Design erosion is the root of all evil  In the lifecycle of a software system Detached Extensions changes A A Backpack Backpack Backpack are the rule and not the exception p Another  New requirements or increments imply Backpack modifications or extensions  Engineers must adopt their solutions to A Someone Component Else's Comp new technologies  Changes in business force changes in IT Another The Fifth  Bug fixes require patches or local Component Element corrections  Unsystematic approaches ( workarounds ) ("workarounds") Yet Another Component cure the symptom but not the problem Component 42  After applying several workarounds, software systems often suffer from design DB Spaghetti erosion Access Layer design  Such systems are doomed to fail as work- DB access arounds have a negative impact on opera- shortcut tional and developmental properties Page 5 Refactoring is part of the architecture design process Feedback Loop Refine & Assess Refactor Refactoring is integrated into Architecture Architecture the iterative-incremental architecture design process:  It improves the structure  It supports a risk-, t i k Executable no Complete yes requirements- and test- Increment ? driven approach Page 6 © Dr. Michael Stal, 2010 3
    • Dr. Michael Stal: Architecture Refactoring Yes, but was is it?  "Code refactoring is the process of changing a software system g g y Note: external interfaces remain unchanged! i h d! in such a way that it does not alter the external behavior of the code yet improves its internal structure" [Martin Fowler]  Put more generally: Refactoring is the process of changing a software system or process in such a way that it does not alter the external behavior, yet improves its internal structure Page 7 Why should we refactor?  Architecture refactoring needs to achieve quality improvement in terms of  structural as well as  non-functional qualities  Structural quality indicators include:  Economy  Visibility  Spacing  Symmetry  Emergence  Consequently, the goal of architecture refactoring is to achieve or improve such qualities Page 8 © Dr. Michael Stal, 2010 4
    • Dr. Michael Stal: Architecture Refactoring Refactoring Agenda  Motivation and foundation  Refactoring  Reengineering  Rewriting  Comparison  Summary Page 9 Code refactoring  According to Martin Fowler, code  Reasons to use refactoring refactoring is  Design improvement and  … the process of changing a maintenance software system in such a way  Better readability that it does not alter the external  Bugs behavior of the code yet  It is the third step in TDD improves its internal structure  … a disciplined way to clean up code that minimizes the  The Rules of Three chances of introducing bugs  Refactor before adding new functionality, e.g., when structure prevents simple t t t i l additions  Refactor when fixing bugs  Refactor after code reviews to apply improvements Page 10 © Dr. Michael Stal, 2010 5
    • Dr. Michael Stal: Architecture Refactoring Code smells  Kent Beck's grandmother's saying: y g "If it stinks, change it"  Thus, identify bad smells such as  Code that is duplicated  Methods that span several dozen lines  Subclasses introducing the same method  Usage of temporary variables  Usage of switch statements  Introduction of a "middleman" Page 11 Code Refactoring Example: Extract Method  Make code fragment a method of its own void printFormatted(string text) { System.out.println("Copyright (c) 2008, Siemens AG"); System.out.println("Author: Michael Stal"); printRest(text); } void printFormatted(string text) { printHeader(); i tH d () printRest(text); } printHeader() { System.out.println("Copyright (c) 2008, Siemens AG"); System.out.println("Author: Michael Stal"); } Page 12 © Dr. Michael Stal, 2010 6
    • Dr. Michael Stal: Architecture Refactoring Refactoring to patterns  Refactoring to patterns was introduced by Joshua Kerievsky y y  General idea: Patterns might give guidance how to refactor on the architectural level  Replace your proprietary solution with a pattern that solves the same problem  Kerievsky's book focuses on design patterns  Introduce symmetry by making  However, we could also sure the same problem is apply the same principle always solved using the same to architecture patterns pattern / solution  In the latter case, we'll obtain  This represents a precursor of architecture refactorings software architecture refactoring Page 13 Replace hard-coded notifications with Observer [Joshua Kerievsky] Do it yourself Observer Pattern Subject EventSink Subject * Observer * update state update state observerList doSomething observerList attach Dynamic notify detach Wiring ConcreteObserver setData notify getData setData update getData doSomething state = X; Subject notify(); contains hardwired list s->getData() of interested for all observers in observerList do components update(); Page 14 © Dr. Michael Stal, 2010 7
    • Dr. Michael Stal: Architecture Refactoring Architecture refactoring  Architecture refactoring is about Architecture smells the semantic-preserving  Duplicate design artifacts transformation of a software t f ti f ft  Unclear roles of entities design  Inexpressive or complex  It changes structure but not architecture behavior  Everything centralized  It applies to architecture-relevant  Home-grown solutions instead of design artifacts such as UML best practices diagrams, models, DSL  Over-generic design expressions, aspects  Asymmetric structure or behavior  Its goal is to improve quality. You  Dependency cycles got a "smell"? Use an architecture  Design violations (such as relaxed refactoring instead of strict layering) pattern to solve it!  Inadequate partitioning of functionality  Unnecessary dependencies  Missing orthogonality Page 15 Remove unnecessary abstractions (1) Transport * Abstract Abstract A true story: In Way y Storage g Strategy gy * this example * architects Equip- Composite Concrete Dump Door Bin introduced ment Storage Strategy * Transport Way as an additional abstraction. But Cart Belt can't we consider transport ways as just as another kind of storage? As a consequence Abstract Abstract the unnecessary Storage Strategy abstraction was * * removed, leading Composite Concrete to a simpler and Equipment Dump Door Bin Storage Strategy cleaner design. Page 16 © Dr. Michael Stal, 2010 8
    • Dr. Michael Stal: Architecture Refactoring Remove unnecessary abstractions (2)  Context  Eliminating unnecessary design abstractions g y g  Problem  Minimalism is an important goal of software architecture, because minimalism increases simplicity and expressiveness  If the software architecture comprises abstractions that could also be considered abstractions derived from other abstractions, then it is better to remove these abstractions  General solution idea  Determine whether abstractions / design artifacts exist that could also be derived from other abstractions  If this is the case, remove superfluous abstractions and derive dependent from other existing abstractions  Caveat  Don't generalize too much (such as introducing one single hierarchy level: "All classes are directly derived from Object") Page 17 Break dependency cycles (1) GetState() GetState() In this example, SetState { SetState { the monitor ... ... M.GetDate() D.GetDate() invokes the state } } getter / setter methods but also Sensor Sensor GetDate() provides GetDate() to the sensor, lea- ding to a simple X Break Cycle Date dependency cycle. Providing this me- thod to monitors Monitor Monitor was a bad design decision, anyway. Draw() { Introducing a GetDate() Draw() { ... separate date S.GetState(); ... object solves the S.GetState(); } problem. } Page 18 © Dr. Michael Stal, 2010 9
    • Dr. Michael Stal: Architecture Refactoring Break dependency cycles (2)  Context  Dependencies between subsystems  Problem  Your system reveals at least one dependency cycle between subsystems  Subsystem A may either depend directly or indirectly on subsystem B (e.g., A depends on C which depends on B) which is why we always need to consider the transitive hull  Dependency cycles make systems less maintainable, changeable, reusable, testable, understandable  Thus, dependency hierarchies should form DAGs (directed acyclic graphs)  General solution idea  Get rid of the dependency cycle by removing one of the dependencies Page 19 Merge Subsystems (1) Example: While tight coupling between subsystems is bad, high cohesion within subsystems is good. Thus, merge tightly coupled subsystems to form a highly cohesive subsystem . Sensor Sensor + Utilities Utilities Special variant: Merge a layer in a layered system Page 20 © Dr. Michael Stal, 2010 10
    • Dr. Michael Stal: Architecture Refactoring Merge Subsystems (2)  Context  Coupling between subsystems  Problem  Between two subsystems in a software architecture the degree of coupling should be rather loose  Within a subsystem the number of interdependencies (cohesion) should be high  If the coupling is too tight, then the many interdependencies between these two subsystems decrease qualities such as  Changeability  Performance (maybe)  Reusability of one of the subsystems  General solution idea  Tight coupling between subsystems implies that the two subsystems in fact implement one subsystem  Either merge both subsystems to form one, or  Move functionality from one subsystem to the other Page 21 Split Subsystems (1) Example: When analyzing interdependencies between entities in a subsystem, two (or more) sets can be determined. Within these sets there is high cohesion; between these sets there is only low cohesion. Thus, split the subsystem into two (or more) parts. Component Container High Cohesion Lifecycle Persistence Event Handling Management Component Container Communication Communi- cation Special variant: Split layer in a layered system Page 22 © Dr. Michael Stal, 2010 11
    • Dr. Michael Stal: Architecture Refactoring Split Subsystems (2)  Context  Cohesion within a subsystem  Problem  Within a subsystem the interdependencies (cohesion) should be high  Between two subsystems in a software architecture, the degree of coupling should be rather loose  If the cohesion between some parts is loose, then some design decisions seem to be questionable  It is recommendable to change this to obtain better modularization and understandability  Another potential problem are subsystems/components with too many responsibilities  General solution idea  Loose cohesion within a subsystem implies that the functionality can be split into multiple subsystems  Thus, determine areas with high cohesion in a subsystem. All those areas with low cohesion are candidates for becoming subsystems of their own Page 23 Move Entities (1) Example y z y z x x Game Game getPlayerHistory(p) getPlayerHistory() Player Player Page 24 © Dr. Michael Stal, 2010 12
    • Dr. Michael Stal: Architecture Refactoring Move Entities (2)  Context  Moving entities between subsystems  Problem  This can be considered a generalization of the Split Subsystem refactoring  In a subsystem an entity is defined that fits better semantically in another subsystem to which it has high coupling  General solution idea  Again, we should consider cohesion and coupling  If entity e reveals low or zero cohesion to the rest of its subsystem A, but tight coupling to subsystem B, then move e from A to B  Note: This may also help with breaking dependency cycles between subsystems Page 25 Move Entities (3) Some additional issues  In many cases we can t apply the refactoring to single atomic entities cases, can't such as a class, method, constant, interface  It is more likely that there will be clusters of atomic entities that together build a complex entity  In the example, it is very likely that there will be classes and interfaces related to the method to be moved  Thus, always consider semantically related entities with high internal y y g cohesion but less cohesion to the rest of their subsystem. If some of them show tight coupling to another subsystem, move the whole group  Moving may not always be a simple operation, but imply several smaller grained transformations (see example) Page 26 © Dr. Michael Stal, 2010 13
    • Dr. Michael Stal: Architecture Refactoring Reduce Dependencies with Facades (1) Example 1.3 Rental Car Bookingg 1.2 Hotel Client Booking Flight 1.1 Booking 2.3 Rental Car Booking B ki Facade 1 2.2 Hotel Client Travel Booking Booking Flight 2.1 Booking Page 27 Reduce Dependencies with Facades (2)  Context  Client implements workflows that mostly access other components  Problem  If a client needs to access different external components for each workflow, it becomes dependent on details such as the set of available components  As soon as the configuration and / or interfaces of these components change, there will be a direct impact on the client  General solution idea  Introduce a Facade component that acts as the client's gateway into the set of required components  Implement workflow methods within the facade that represent the different p p workflows  The facade methods take over the responsibility for accessing the set of required components on behalf of the client, thus decoupling the client from the components  If components are remote, performance is also improved (Session Facade) Page 28 © Dr. Michael Stal, 2010 14
    • Dr. Michael Stal: Architecture Refactoring Substitute Mediation with Adaptation (1) Example I_have no_clue_sub_1 no clue sub 1 I_have I_have A B C no_clue_sub2 no_clue_sub_3 Adapter Adapter Adapter Do_Everything_ Class Integration Layer a.k.a. Mediator Adapter Adapter Adapter I_have I_have no_clue_sub_4 no_clue_sub_5 D E F I_have no_clue_sub_6 Page 29 Substitute Mediation with Adaptation (2)  Context  Centralized system using a mediation level between peers  Problem  When interaction between different peers is complex, a mediator may be the right solution  However, extensive use of mediator may reduce scalability  If mediation was just applied to build an extremely generic solution, design erosion is often the price  How can we improve this situation?  General solution idea  Introduce adapters to uniformly plug in peers  But make interaction explicit, i.e. subsystems themselves are in charge to interact with the appropriate peers using an integration layer  Known use: Enterprise Application Integration (Hub and Spoke) => Enterprise Service Bus Page 30 © Dr. Michael Stal, 2010 15
    • Dr. Michael Stal: Architecture Refactoring Add Uniform Support for Runtime Aspects (1) Subsys UI Subsys UI IUIAdmin IAdmin Subsys DB Subsys DB IDBAdmin IAdmin Subsys ATM Subsys ATM IATMAdmin IAdmin Management Console Page 31 Add Uniform Support for Runtime Aspects (2)  Context  Software architecture that must support runtime aspects such as lifecycle management, management, configuration f f  Problem  Each non-trivial software architecture consists of multiple components, each of which supports common aspects  If every component implements its own interfaces for runtime aspects, the overall system will lack simplicity and expressiveness  Is there a way to provide a uniform approach to support those kinds of runtime aspects?  General solution idea  For each aspect, define a common interface (e.g., an interface for runtime configuration)  In each component supporting the aspect, provide this common interface (maybe using Extension Interfaces to prevent bloating)  To achieve orthogonality, provide one runtime component that is in charge of accessing these common interfaces (e.g., a management console) Page 32 © Dr. Michael Stal, 2010 16
    • Dr. Michael Stal: Architecture Refactoring Add Configuration Subsystem (1) Example Actor Subsystem UI Subsystem UI IConfig1 IConfig Configuration Subsystem DB Configuration Subsystem DB Actor IConfig2 Subsystem IConfig Subsystem ATM Subsystem ATM IConfig3 IConfig  Use patterns such as Component Configurator for this purpose Page 33 Add Configuration Subsystem (2)  Context  A system with many configurable variabilities  Problem  If a system contains a lot of configuration options, then configuration itself is often tedious and error-prone  This holds in particular when the configuration options are (partially) related to each other  How can we refactor the software system so that configuration is simplified and (partially) automated?  General solution idea  Instead of providing dozens of configuration options to external actors, we introduce a configuration subsystem that takes a declarative configuration (from a file or a wizard)  The configuration subsystem reacts to configuration change events, reads the passed configuration, and then accesses the configuration interfaces of configurable subsystems  Ideally, all subsystems provide the same generic configuration interface Page 34 © Dr. Michael Stal, 2010 17
    • Dr. Michael Stal: Architecture Refactoring Where to obtain architecture refactorings? A whole catalog of architecture refactorings is provided as a starting point i t 1. Rename Entities 17. Enforce Contract 18. Provide Extension Interfaces 2. Remove Duplicates 19. Substitute Inheritance with Delegation 3. Introduce Abstraction Hierarchies 20. Provide Interoperability Layers 4. Remove Unncessary Abstractions 21. Aspectify 5. Substitute Mediation with Adaptation 22. Integrate DSLs 6. Break Dependency Cycles 23. Add Uniform Support to Runtime Aspects 24. Add Configuration Subsystem 7. Inject Dependencies 25. Introduce the Open/Close Principle 8. Insert Transparency Layer 26. Optimize with Caching 9. Reduce Dependencies with Facades p 27. Replace Singleton 10. Merge Subsystems 28. Separate Synchronous and Asynchronous Processing 11. Split Subsystems 29. Replace Remote Methods with Messages 12. Enforce Strict Layering 30. Add Object Manager 13. Move Entities 31. Change Unidirectional Association to Bidirectional 14. Add Strategies 15. Enforce Symmetry 16. Extract Interface Page 35 Checking correctness  To check the correctness of refactorings, we use the test-driven approach that we introduced.  Available options:  Formal approach: Prove semantics and correctness of program transformation  Implementation approach: Leverage unit and regression tests to verify that the resulting implementation still meets the specification  Architect re analysis: Check the resulting Architecture anal sis res lting software architecture for its equivalence with the initial architecture (consider requirements) – see also CQM methods and tools  Use at least the latter two methods to ensure quality Page 36 © Dr. Michael Stal, 2010 18
    • Dr. Michael Stal: Architecture Refactoring Refactoring – responsibilities and communication The process of refactoring requires communication with testers and developers Product Lifecycle Manager SW Project Manager  Control product development  Define detailed project plans across lifecycles  Assign resources Requirements Engineer  Review system architecture Detailed project documents planning Head of R&D SW Design  Control SW Testability y process  Act as escalation Software Architect point  Analyze architecture smells Software Developer  Identify appropriate software  Identify code Test Manager architecture refactorings e.g., using smells  Review product architecture refactoring catalogs  Apply code  Refine master test plan  Apply software architecture refactorings  Set up test strategy for integration and refactorings system test  Verify correctness of refactorings  Define test environment  Be involved in design reviews  Define verification and validation  Leverage CQM tools procedure Page 37 Application of architecture refactorings  The usage of a concrete application refactoring should never happen in an ad-hoc, unsystematic way. I t d dh t ti Instead, the architect's role is to  Check the applicability of refactorings  Would the refactoring affect parts that need to remain unchanged, such as integration of third-party APIs?  Could the refactoring impact require- ments in a negative way?  Define the order of refactoring  Strategic before tactical aspects  Requirement priorities drive order!  Apply the refactorings  Ensure the quality of the software architecture after the refactoring (in conjunction with the test manager) Page 38 © Dr. Michael Stal, 2010 19
    • Dr. Michael Stal: Architecture Refactoring Obstacles to refactoring (1)  Organization / management  Considering improvement by refactoring as less important than providing new p p g features  Ignorance of refactoring necessity typically causes design erosion  “Organization drives architecture” problem  Process support  No steps / activities defined in process for architecture refactoring: Refactoring should be addressed explicitly in the h ld b dd d li itl i th process; responsibilities must be assigned to different roles  Refactorings are not checked for correctness, test manager not involved: Architects should work hand in hand with test manager and leverage means such as tests, architecture reviews Page 39 Obstacles to refactoring (2)  Technologies and tools  Unavailability of tools: Refactoring must be done manually, which can be tedious y, and error-prone  Unavailability of refactoring catalog: It is important to collect refactorings and document them  Applicability  Refactoring used instead of reengineering, and vice versa  Wrong order of refactorings: Should be determined by requirements priority and d t i db i t i it d relevance Page 40 © Dr. Michael Stal, 2010 20
    • Dr. Michael Stal: Architecture Refactoring Refactoring Agenda  Motivation and foundation  Refactoring  Reengineering  Rewriting  Comparison  Summary Page 41 Reengineering – how it differs from refactoring  Scope: Reengineering always affects the entire system; refactoring has typically f t i h t i ll (many) local effects  Process: Reengineering follows a disassembly / reassembly approach; refactoring is a behavior- preserving, structure transforming process  Result: Reengineering can create a whole new system – with different structure, behavior, and functionality; refactoring improves the structure of an existing system – leaving its behavior and functionality unchanged Page 42 © Dr. Michael Stal, 2010 21
    • Dr. Michael Stal: Architecture Refactoring Reengineering – when and how to use it  Use reengineering when  Process  Phase I: Reverse engineering g g  The system s documentation system's  Analysis / recovery: determine is missing or obsolete existing architecture (consider  The team has only limited using CQM) understanding of the  SWOT analysis system, its architecture, and  Decisions: what to keep, what implementation to change or throw away  Phase II: Forward engineering  A bug fix in one place causes bugs in other places Reverse Forward engineering engineering  New system-level require- Requirements ments and functions cannot Conference Organizer uses Conference Manager * uses manages Scheduler Telegram Forwarder Telegram Receiver The network organizes be addressed or integrated Media passes telegrams to participates Conference uses Manager passes telegrams to Telegram Design Converter Conference Participant * has applies passes Conference * Command Logging Documents Logger commands to Session Processor Strategy executes Log Command Alarms creates Pick SetPoint W orkpiece Calculation appropriately Code Page 43 Refactoring Agenda  Motivation and foundation  Refactoring  Reengineering  Rewriting  Comparison  Summary Page 44 © Dr. Michael Stal, 2010 22
    • Dr. Michael Stal: Architecture Refactoring Rewriting in a Nutshell Rewriting is a radical and fresh restart: existing design and code is trashed and replaced by a whole new design and implementation. Depending on focus:  Improves structure regarding:  Simplicity, visibility, spacing, symmetry, emergence  Maintainability, readability, extensibility  Bug fixing  Provides new functionality  Improves its operational qualities p p q  Improves design and code stability As a consequence, rewriting addresses all types of software quality: functional, operational, and the various developmental qualities. Page 45 Learning from failure Failure and understanding failure is a key factor for successful design! [Henry Petroski] Before you’re going to rewrite, check what went wrong in the project that developed the previous application Page 46 © Dr. Michael Stal, 2010 23
    • Dr. Michael Stal: Architecture Refactoring Refactoring Agenda  Motivation and foundation  Refactoring  Reengineering  Rewriting  Comparison  Summary Page 47 Refactoring, reengineering, and rewriting comparison (1) Refactoring, reengineering, and rewriting are complementary approaches to sustain architecture and code quality  Start with refactoring – it is cheap and (mostly) under the radar  Consider reengineering when refactoring does not help – but it is expensive  Consider rewriting when reengineering does not help – but it is expensive and often risky Command Processor Strategy Reverse Forward Command Logging Client engineering engineering Processor Strategy Concrete Requirements q Logging Strategy Command & Composite uses uses Conference Scheduler The network Manager Telegram Telegram Conference Organizer * organizes participates manages Conference uses Media Forwarder Receiver passes telegrams to passes telegrams to Command Memento Design * Manager Telegram Conference Converter Participant * has applies passes Conference * Command Logging Documents Logger commands to Session Processor Strategy executes Log Command Alarms creates Pick SetPoint Workpiece Calculation Memento Concrete Composite Command Command Code Application Page 48 © Dr. Michael Stal, 2010 24
    • Dr. Michael Stal: Architecture Refactoring Refactoring, reengineering, and rewriting comparison (2) Refactoring Reengineering Rewriting Scope  Many local effects  Systemic effect  Systemic or local effect Process  Structure transforming  Disassembly / reassambly  Replacement  Behavior / semantics preserving Results  Improved structure  New system  New system or new  Identical behavior component Improved  Developmental  Functional  Functional qualities  Operational  Operational  Developmental  Developmental Drivers  Complicated design / code  Refactoring is insufficient  Refactoring and evolution  Bug fixes cause rippling effect reengineering are insufficient  Wh fi i b When fixing bugs  New functional and or inappropriate  When design and code smell operational requirements  Unstable code and design bad  Changed business case  New functional and operational requirements  Changed business case  Part of daily work  Requires a dedicated project  Requires dedicated effort or a  At the end of each iteration dedicated project, depending When  Dedicated refactoring on scope iterations in response to reviews Page 49  It is the 3rd step of TDD Refactoring Agenda  Motivation and foundation  Refactoring  Reengineering  Rewriting  Comparison  Summary Page 50 © Dr. Michael Stal, 2010 25
    • Dr. Michael Stal: Architecture Refactoring What we learned  Refactoring changes artifacts without changing external behavior. It helps with quality improvement and necessary changes d h  In contrast, reengineering is a complete redesign of a complete architecture and typically changes external behavior  If reengineering is not appropriate, it is often the best alternative to rewrite a system or its parts  All methods are essential. Use the right one for the right purpose  Testing and architecture introspections are important when refactoring, reengineering, i t t h f t i i i rewriting  You as a software architect are responsible to  Detect architecture smells  Find and apply appropriate refactorings  Perform QA of refactoring activities Page 51 A departing thought Each problem that I solved became a rule which served afterwards to solve other problems. [René Descartes, 1596–1650, in "Discours de la Methode"] Page 52 © Dr. Michael Stal, 2010 26
    • Dr. Michael Stal: Architecture Refactoring Backup Backup Page 53 Rename Entities (1) Example Comp ShareTicker AnotherComp ShareObserver Page 54 © Dr. Michael Stal, 2010 27
    • Dr. Michael Stal: Architecture Refactoring Rename Entities (2)  Context  Using non intuitive names non-intuitive  Problem  Your software architecture contains entities named in such a way that the whole architecture lacks expressiveness  General solution idea  Introduce intuitive names so that stakeholders can easily understand the role of each subsystem  Change the names of the entities and also consider references to these entities  Change only one entity name at a time  Use one predefined naming scheme / strategy throughout the project Page 55 Remove Duplicates (1) Example Extract: call locateBean(X) Client A Extract: Client A' main() {  Connect JNDI main() { ... ... }  Get Home }  Locate bean X Bean 1. Connect JNDI Location 2. Get Home Component 3. Locate bean Client B Extract: Client B' main() {  Connect JNDI main() { ... ... }  Get Home }  Locate bean Y Extract: call locateBean(Y) Page 56 © Dr. Michael Stal, 2010 28
    • Dr. Michael Stal: Architecture Refactoring Remove Duplicates (2)  Context  Equivalent design artifacts are replicated throughout the q g p g architecture  Problem  DRY (Don't Repeat Yourself) is an essential means to increase simplicity, expressiveness, orthogonality and reuse  On the other hand, if the same design artifacts are repeatedly implemented and used in a software architecture, then manageability and productivity will suffer  How can we prevent the introduction of equivalent design artifacts?  General solution idea  Identify common (sequences of) tasks or sequences of tasks repeatedly used throughout your software system  Analyze whether these common (sequences of tasks) can be provided as a generic component  If that's the case, remove duplicates and introduce one common design artifact instead Page 57 Introduce Abstraction Hierarchies (1) Example: Class hierarchy Window Wi d Window Wi d display() display() Panel Panel display() drawPixel() drawPixel() Button Button display() onClick() drawPixel() onClick() Separate Related abstractions abstractions "is-a" relation Page 58 © Dr. Michael Stal, 2010 29
    • Dr. Michael Stal: Architecture Refactoring Introduce Abstraction Hierarchies (2)  Context  Entities representing related concepts p g p  Problem  In the architecture design entities appear that implement almost the same functionality  This leads to design and code replication, as well as to less expressiveness and simplicity  General solution idea  Leverage the Liskov Substitution Principle  Introduce general abstractions containing the common parts of these entities  Define hierarchy of abstractions  Derive entities from the most specific abstraction  Different possibilities  Adding superclass  Adding common interfaces Page 59 Remove Unnecessary Abstractions (1) Example Transport * Abstract Abstract Way Storage Strategy * * Equip- Composite Concrete Dump Door Bin ment Storage Strategy * Cart Belt Abstract Abstract Storage Strategy * * Composite Concrete Equipment Dump Door Bin Storage Strategy Page 60 © Dr. Michael Stal, 2010 30
    • Dr. Michael Stal: Architecture Refactoring Remove Unnecessary Abstractions (2)  Context  Eliminating unnecessary design abstractions  Problem  Minimalism is an important goal of software architecture, because minimalism increases simplicity and expressiveness  If the software architecture comprises abstractions that could also be considered abstractions derived from other abstractions, then it is better to remove these abstractions  General solution idea  Determine whether abstractions / design artifacts exist that could also be derived from other abstractions  If this is the case,  remove superfluous abstractions;  derive entities that depend from removed abstractions to derive from abstractions being left  Challenge: Don't generalize too much (such as introducing one single hierarchy level: "All classes are directly derived from Object") Page 61 Substitute Mediation with Adaptation (1) Example I_have no_clue_sub_1 no clue sub 1 I_have I_have A B C no_clue_sub2 no_clue_sub_3 Adapter Adapter Adapter Do_Everything_ Class Integration Layer a.k.a. Mediator Adapter Adapter Adapter I_have I_have no_clue_sub_4 no_clue_sub_5 D E F I_have no_clue_sub_6 Page 62 © Dr. Michael Stal, 2010 31
    • Dr. Michael Stal: Architecture Refactoring Substitute Mediation with Adaptation (2)  Context  Centralized system using a mediation level between peers  Problem  When interaction between different peers is complex, a mediator may be the right solution  However, extensive use of mediator may reduce scalability  If mediation was just applied to build an extremely generic solution, design erosion is often the price  How can we improve this situation?  General solution idea  Introduce adapters to uniformly plug in peers  But make interaction explicit, i.e. subsystems themselves are in charge to interact with the appropriate peers using an integration layer  Known use: Enterprise Application Integration (Hub and Spoke) => Enterprise Service Bus Page 63 Break dependency cycles (1) GetState() GetState() In this example, SetState { SetState { the monitor ... ... M.GetDate() D.GetDate() invokes the state } } getter / setter methods but also Sensor Sensor GetDate() provides GetDate() to the sensor, lea- ding to a simple X Break Cycle Date dependency cycle. Providing this me- thod to monitors Monitor Monitor was a bad design decision, anyway. Draw() { Introducing a GetDate() Draw() { ... sepa-rate date S.GetState(); ... object solves the S.GetState(); } problem. } Page 64 © Dr. Michael Stal, 2010 32
    • Dr. Michael Stal: Architecture Refactoring Break dependency cycles (2)  Context  Dependencies between subsystems  Problem  Your system reveals at least one dependency cycle between subsystems  Subsystem A may either depend directly or indirectly on subsystem B (e.g., A depends on C which depends on B) which is why we always need to consider the transitive hull  Dependency cycles make systems less maintainable, changeable, reusable, testable, understandable  Thus, dependency hierarchies should form DAGs (directed acyclic graphs)  General solution idea  Get rid of the dependency cycle by removing one of the dependencies Page 65 Break dependency cycles – Dependency Inversion interface IObserver { Handle() } Attach(Observer) Attach(IObserver) Notify( Notify( Dependency inver- observer.Handle(); iObserver.Handle(); sion constitutes ) ) another variant Subject' Subject Observer' Observer Handle() class Obs implements IObserver { StartUp() { Handle() { ...} } subj.Attach(obs); StartUp( ) subj.Attach(obs); ) Page 66 © Dr. Michael Stal, 2010 33
    • Dr. Michael Stal: Architecture Refactoring Inject Dependencies (1) Example Component c { Component c { S s = new S(.....); inject(S p){ s=p;} s.m(); s.m(); } } Component c Component c Component s Container m Component s C c = new C(); S.S = new S(.....); c.inject(s); Page 67 Inject Dependencies (2)  Context  Components that need to create and use other components  Problem  If a component c needs access to other components, it most somehow create these components or locate them  However, this makes c too dependent on the knowledge about specific component location or factory mechanisms  How can we avoid these additional dependencies?  General solution idea  Move functionality for discovery and creation of components to separate component m  Introduce configuration to let component c specify its requirements and let m be responsible for creating, discovering and then injecting required component references to c Page 68 © Dr. Michael Stal, 2010 34
    • Dr. Michael Stal: Architecture Refactoring Insert Transparency Layer (1) Example Subsystem B Subsystem B TRANSPARENCY Client Client LAYER Page 69 Insert Transparency Layer (2)  Context  Decoupling clients or from subsystems and vice-versa  P bl Problem  When a client accesses subsystems directly, some dependencies are introduced, e.g.,  On the exact physical location of the subsystems, or  On specific data or document formats the subsystem expects  The client must have knowledge about how to locate and access the subsystems  Finally, the client also becomes dependent on subsystem implementation aspects  General solution idea  To avoid such dependencies, we introduce transparency layers to decouple these dependencies from clients  Transparency layers also open additional optimization possibilities  This is basically a whole class of architecture refactorings, because for the implementation of transparency layers we rely on patterns such as Proxy, Facade, Wrapper-Facade, Business Delegate, Service Locator, Proxy Page 70 © Dr. Michael Stal, 2010 35
    • Dr. Michael Stal: Architecture Refactoring Example: Introducing Protection Layers  Typically, an architectural entity depends directly on other architectural entities Client  This becomes a problem when the target of the p g dependency is subject to change (volatility)  In this case add a layer to protect your entity from directly depending on a volatile entity  Note: this decreases inter-component coupling Protection Layer Server Page 71 Reduce Dependencies with Facades (1) Example 1.3 Rental Car Bookingg 1.2 Hotel Client Booking Flight 1.1 Booking 2.3 Rental Car Booking B ki Facade 1 2.2 Hotel Client Travel Booking Booking Flight 2.1 Booking Page 72 © Dr. Michael Stal, 2010 36
    • Dr. Michael Stal: Architecture Refactoring Reduce Dependencies with Facades (2)  Context  Client implements workflows that mostly access other components p y p  Problem  If a client needs to access different external components for each workflow, it becomes dependent on details such as the set of available components  As soon as the configuration and / or interfaces of these components change, there will be a direct impact on the client  General solution idea  Introduce a Facade component that acts as the client s gateway into client's the set of required components  Implement workflow methods within the facade that represent the different workflows  The facade methods take over the responsibility for accessing the set of required components on behalf of the client, thus decoupling the client from the components  If components are remote, performance is also improved (Session Page 73 Facade) Merge Subsystems (1) Example: While tight coupling between subsystems is bad, high cohesion within subsystems is good. Thus, merge tightly coupled subsystems to form a highly cohesive subsystem . Sensor Sensor + Utilities Utilities Special variant: Merge a layer in a layered system Page 74 © Dr. Michael Stal, 2010 37
    • Dr. Michael Stal: Architecture Refactoring Merge Subsystems (2)  Context  Coupling between subsystems  Problem  Between two subsystems in a software architecture the degree of coupling should be rather loose  Within a subsystem the number of interdependencies (cohesion) should be high  If the coupling is too tight, then the many interdependencies between these two subsystems decrease qualities such as  Changeability  Performance (maybe)  Reusability of one of the subsystems  General solution idea  Tight coupling between subsystems implies that the two subsystems in fact implement one subsystem  Either merge both subsystems to form one, or  Move functionality from one subsystem to the other Page 75 Split Subsystems (1) Example: When analyzing interdependencies between entities in a subsystem, two (or more) sets can be determined. Within these sets there is high cohesion; between these sets there is only low cohesion. Thus, split the subsystem into two (or more) parts. Component Container High Cohesion Lifecycle Persistence Event Handling Management Component Container Communication Communi- cation Special variant: Split layer in a layered system Page 76 © Dr. Michael Stal, 2010 38
    • Dr. Michael Stal: Architecture Refactoring Split Subsystems (2)  Context  Cohesion within a subsystem  Problem  Within a subsystem the interdependencies (cohesion) should be high  Between two subsystems in a software architecture, the degree of coupling should be rather loose  If the cohesion between some parts is loose, then some design decisions seem to be questionable  It is recommendable to change this to obtain better modularization and understandability  Another potential problem are subsystems/components with too many responsibilities  General solution idea  Loose cohesion within a subsystem implies that the functionality can be split into multiple subsystems  Thus, determine areas with high cohesion in a subsystem. All those areas with low cohesion are candidates for becoming subsystems of their own Page 77 Enforce Strict layering (1) Example Application pp Application Layer 3 Layer 3 Component Component Component Component Component Component 3.1 3.2 3.3 3.1 3.2 3.3 Layer 2 Layer 2 Broken Component Component Component Component layering 2.1 2.2 2.1 2.2 Layer 1 Layer 1 Component Component Component Component Component Component 1.1 1.2 1.3 1.1 1.2 1.3 Page 78 © Dr. Michael Stal, 2010 39
    • Dr. Michael Stal: Architecture Refactoring Enforce Strict Layering (2)  Context  An architecture with broken layering  Problem  Layers are introduced to reduce dependencies, increase adaptability and reusability, as well as maintainability  Sometimes relaxed layering is used intentionally to solve problems such as performance issues  At other times relaxed layering is used accidentally without any y g y y justification and value  In the latter case, how can we cure the broker layering?  General solution idea  Redesign so that the broken layering is substituted with strict layering Page 79 Enforce Strict Layering (3)  Unfortunately, broken layering is often hard to cure  To resolve the broken layering between component 3.1 and component 1.1, we must differentiate the following cases:  Case 1: All the types of functionality of component 1.1 that component 3.1 uses are also available in layer 2  In component 3.1, substitute all usages of component 1.1 by equivalent functionality of layer 2  Case 2: Not all the types of functionality of component 1.1 that component 3.1 uses are available in layer 2  Substitute all those component 1.1 invocations with equivalent invocations of layer 2 For the rest of the invocations move 2. invocations, functionality from layer 3 to layer 2  In case 2 it is sometimes not advisable to move functionality from layer 3 to layer 2. Consider reengineering activities instead!  Note: This is one of the refactorings that can also be applied in the opposite direction. If strict layering is not feasible (e.g., due to performance), relax the strict layering! Page 80 © Dr. Michael Stal, 2010 40
    • Dr. Michael Stal: Architecture Refactoring Move Entities (1) Example y z y z x x Game Game getPlayerHistory(p) getPlayerHistory() Player Player Page 81 Move Entities (2)  Context  Moving entities between subsystems  Problem  This can be considered a generalization of the Split Subsystem refactoring  In a subsystem an entity is defined that fits better semantically in another subsystem to which it has high coupling  General solution idea  Again, we should consider cohesion and coupling  If entity e reveals low or zero cohesion to the rest of its subsystem A, but tight coupling to subsystem B, then move e from A to B  Note: This may also help with breaking dependency cycles between subsystems Page 82 © Dr. Michael Stal, 2010 41
    • Dr. Michael Stal: Architecture Refactoring Move Entities (3) Some additional issues  In many cases we can t apply the refactoring to single atomic entities cases, can't such as a class, method, constant, interface  It is more likely that there will be clusters of atomic entities that together build a complex entity  In the example, it is very likely that there will be classes and interfaces related to the method to be moved  Thus, always consider semantically related entities with high internal y y g cohesion but less cohesion to the rest of their subsystem. If some of them show tight coupling to another subsystem, move the whole group  Moving may not always be a simple operation, but imply several smaller grained transformations (see example) Page 83 Add Strategies (1) Example Warning Client Client  Never introduce strategies in an uncontrolled way  A strategy basically Middleware means "I have no idea Middleware which option to use at DispatcherStrategy runtime" Request Dispatcher  St t Strategy S d Syndrome isi ConcreteDispatcher a serious disease that leads to an over- generic architecture which is doomed to Protocol Protocol design erosion Page 84 © Dr. Michael Stal, 2010 42
    • Dr. Michael Stal: Architecture Refactoring Add Strategies (2)  Context  Enable selection and exchange of implementations  Problem  Services and algorithms in a component can be implemented in various ways. Their implementation often also depend on client requirements  The client should not depend on the concrete implementations used  Hard-coding a service or algorithm and then exchanging it at source code level is a possible solution  Unfortunately, this does not hold for runtime configurability  How can we refactor a component to support this kind of runtime configuration?  General solution idea  Use the Strategy pattern Page 85 Enforce Symmetry (1) Examples for structural symmetry  Some places in Subsystem UI Subsystem UI the architecture Based on MVC Based on MVC throw exceptions, and Observer and Observer while other return error codes  One subsystem leverages the Subsystem Accounts y Observer pattern, pattern Uses hardwired Subsystem Accounts configuration of Uses Observer another one a event handlers hardwired event notification strategy Page 86 © Dr. Michael Stal, 2010 43
    • Dr. Michael Stal: Architecture Refactoring Enforce Symmetry (2)  Context  Refactor an asymmetric solution  Problem  Asymmetry reduces conceptual integrity and simplicity  Structural asymmetry deals with the usage of the same solution concepts throughout an architecture  Functional asymmetry is relevant on the method level ("When there is an open, there should be a close operation")  General solution idea  Prioritize strategy over tactics  For identical problem contexts in your architecture, apply the same solutions (e.g., the same patterns)  Use refactoring-to-patterns where applicable  All unmotivated asymmetries should be removed step-by-step Page 87 Enforce Symmetry (3) Example for functional symmetry: Abstract Factory with missing dispose method AbstractFactory AbstractProductA create_productA create productA ProductA ConcreteFactory ConcreteProductA create_productA ProductA AbstractFactory AbstractProductA create_productA ProductA dispose_productA ConcreteFactory ConcreteProductA create_productA ProductA dispose_productA Page 88 © Dr. Michael Stal, 2010 44
    • Dr. Michael Stal: Architecture Refactoring Extract Interface (1) Example << interface >> ISensor getTemperature(UNIT) Sensor Adapter if (UNIT == CELSIUS) temperature() Sensor useCelsius() useCelsius(); useFahrenheit() temperature() else initialize() useCelsius() reset() useFahrenheit() useFarhrenheit(); getAverage(from,to) initialize() return temperature(); storeRecord() reset() getRecord(DateTime) getAverage(from,to) getDateTime() storeRecord() getRecord(DateTime) getDateTime() Page 89 Extract Interface (2)  Context  (Sub)system needs to export functionality  Problem  An existing (sub)system needs to export some of its internal functionality to external users  How can the (sub)system developer make internal functionality available externally?  General solution idea  Define abstract interface and contract  Provide wiring of interface methods to internal functionality  Apply patterns such as Bridge, Decorator, or Adapter to separate interface from implementation  Optionally, use the Extension Interface pattern to manage multiple interfaces Page 90 © Dr. Michael Stal, 2010 45
    • Dr. Michael Stal: Architecture Refactoring Enforce Contract (1) Example << interface >> << interface >> IFile IFile Handle open(File) Handle open(File) Write(Handle, buf) Write(buf) close(Handle) close() Write/ notEmpty(buf) Open/ Contract IsValid(File) Implementation Close Open/ not IsValid(File) ( ) File System File System Page 91 Enforce Contract (2)  Context  Enforcing contract of an interface  Problem  A contract defines what the user of an interface must provide and what the user can expect in turn, e.g., preconditions, postconditions, required order of method execution  Often, interface implementations do not enforce the contract  A contract that is never enforced is of limited value  How can we enforce the interface contract?  General solution idea  Define contract explicitly: For example, use a state machine to define method execution order. Specify interface invariants. For each method, determine preconditions and postconditions  Enrich interface implementation to enforce contract Page 92 © Dr. Michael Stal, 2010 46
    • Dr. Michael Stal: Architecture Refactoring Provide Extension Interfaces (1) Client Factory create() Interface1 find() service_1.1(); service_1.2(); service_1.3(); service_1.4(); RootInterface . get_extension() . . . . . Extension Extension . Interface1 Interface2 service_1.n(); service_1() service_2() Component Component svc_1_impl() svc_2_impl() Page 93 Provide Extension Interfaces (2)  Context  Managing interfaces of a component  Problem  If a component evolves over time, often new functionality is added to the component's interfaces  This may lead to severe interface bloating, which has a negative impact on quality attributes such as usability and manageability (Swiss Army Knife anti-pattern)  Unsystematic interface evolution may also break client code  How can we add an interface management for systematically evolving and providing interfaces?  General solution idea  Apply Extension Interface Patterns [POSA2]  Introduce a common protocol for all provided interfaces (including interface navigation)  Integrate additional functionality so that clients can discover existing component interfaces and navigate between them Page 94 © Dr. Michael Stal, 2010 47
    • Dr. Michael Stal: Architecture Refactoring Provide Extension Interfaces (3) Client Factory Notes Interface ID1 Root Ext Ext  This refactoring alters Comp. Inter- Inter- create Interface face1 face2 components and Interface clients. Thus, handle ID1 with care! Interface Interface  Interface navigation 1 1 service1 should be reflexive, symmetric, transitive  But you may also Interface ID2 get_extension Interface introduce a dedicated 2 service2 interface that includes the navigation functionality Page 95 Substitute Inheritance with Delegation (1) Example Player IPlayer play() play() Player Ninja lookupExperience() Ninja play(IPlayer) play() lookupExperience() play() Player p delegate play(IPlayer ip) { // pre-processing this.play(); // post-processing } Page 96 © Dr. Michael Stal, 2010 48
    • Dr. Michael Stal: Architecture Refactoring Substitute Inheritance with Delegation (2)  Context  Using delegation when inheritance is not available or not suitable  Problem  Assume an entity D should logically inherit from entity B, but inheritance is not available on component or subsystem level, or inheritance cannot be used due to other restrictions  In these cases, using inheritance is not the right approach  How can we get rid of (the necessity to use) inheritance but get the same possibilities?  General solution idea  Keep B as it is  Within entity D add reference to B  Provide public interface of B also in D but forward all invocations to referred B (optionally passing a reference to D for back calls)  Additional note  This is another one of the reversible patterns that may also be applicable in the opposite direction! Page 97 Provide Interoperability Layers (1) Example Application layer Adapter layer  Provide bidirectional interoperability between two subsystems using Web Services  Extract subsystem interfaces and use adapters (e.g., session facades, business delegates) to integrate them with their subsystems Page 98 © Dr. Michael Stal, 2010 49
    • Dr. Michael Stal: Architecture Refactoring Provide Interoperability Layers (2)  Context  Enable interoperability between two subsystems  Problem  Sometimes formerly collocated subsystems need to be distributed, or  An application needs to interoperate with other legacy applications  Unfortunately, both of them were not designed to interoperate  General solution idea  Insert adapter layers to provide interoperability  Adapt subsystem A to B or subsystem B to A or use a bidirectional A, adaptation  Adaptation is a holistic approach. You may adapt communication, data, policies  Use patterns such as Adapter or Wrapper Facade. In other words, apply the Insert Transparency Layer refactoring Page 99 Provide Interoperability (3)  Aspects for interoperability in object-oriented, distributed systems  Interoperability is not restricted to data transformation and communication  For example, we also need to adapt error management  Likewise, object models must be mapped onto each other  Policies (e.g., security, memory management) must be mapped onto each other  The simpler the adaptation layers provided, the more work developers p p y p , p must spend to close the semantic gap  Integration products such as EAI solutions just provide a set of proprietary interoperability solutions Page 100 © Dr. Michael Stal, 2010 50
    • Dr. Michael Stal: Architecture Refactoring Aspectify (1) Example + Logging Logging functionality functionality Page 101 Aspectify (2)  Context  Dealing with cross-cutting concerns g g  Problem  Cross-cutting concerns such as security mechanisms, distribution mechanisms and other invasive functionalities lead to extensive replication of design and code  OO mechanisms such as inheritance can't solve the problem, due to infeasible centralization of these concerns  Nonetheless, separation of concerns should be supported  General solution idea  Express concern as a centralized package  Introduce injection mechanism to integrate wrapped concern in all required places of software architecture  If cross-cutting concerns are interdependent, allow injection mechanism to take care of interdependencies, for example by using prioritization or a generative approach Page 102 © Dr. Michael Stal, 2010 51
    • Dr. Michael Stal: Architecture Refactoring Integrate DSLs (1) Example Interface Root Monitor Interface Root Monitor Factory Interface Factory Interface StorageMgr Capacity ServiceX Abstract StorageMgr Capacity ServiceX Abstract Interface Interface Interface Interceptor Interface Interface Interface Interceptor * * Storage Leafs LoadIn Storage Leafs LoadIn Capacity Only Layers Capacity Only Layers Storage Abstract Abstract Abstract Storage Abstract Abstract Abstract Hook Hook Manager Visitor Iterator Strategy Manager Visitor Iterator Strategy * * Abstract * * * * Abstract Storage Successor Successor Storage * * SOC Atomic Composite SOC Atomic Composite Factory Storage Storage Factory Storage Storage * Hazardous Ware- * Bin Aisle Hazardous SOC house Bin Warehouse Aisle SOC Hazardous Real Thread Hazardous Real Thread Socket Socket Value Bin Mutex Value Bin Mutex  Microsoft's XAML (eXtensible Application Markup Language) is used for specifying workflows declaratively within and between applications  In the past, developers had to hardcode these workflows in the architecture using implementation languages such as C# Page 103 Integrate DSLs (2)  Context  A system that covers many different domains  Problem  Mastering complexity in a software system is an important challenge. Complexity is often cause by the usage of multiple domains (based on different concepts and paradigms)  If many domains are involved, such as the business logic itself, accessing databases, specifying workflows, UI design, then impedance mismatch becomes an essential issue  In addition, the work of different domain experts is more difficult, because all domain experts must understand the full software system  General solution idea  Instead of hard-coding domain-specific functionality manually, define a metamodel / DSL that allows domain experts to define their logic  Implement generators that transform models / DSLs to implementation artifacts  Define an integration subsystem for each of these domains that integrates the generated artifacts with the rest of the system Page 104 © Dr. Michael Stal, 2010 52
    • Dr. Michael Stal: Architecture Refactoring Add Uniform Support for Runtime Aspects (1) Subsys UI Subsys UI IUIAdmin IAdmin Subsys DB Subsys DB IDBAdmin IAdmin Subsys ATM Subsys ATM IATMAdmin IAdmin Management Console Page 105 Add Uniform Support for Runtime Aspects (2)  Context  Software architecture that must support runtime aspects such as lifecycle management, management, configuration f f  Problem  Each non-trivial software architecture consists of multiple components, each of which supports common aspects  If every component implements its own interfaces for runtime aspects, the overall system will lack simplicity and expressiveness  Is there a way to provide a uniform approach to support those kinds of runtime aspects?  General solution idea  For each aspect, define a common interface (e.g., an interface for runtime configuration)  In each component supporting the aspect, provide this common interface (maybe using Extension Interfaces to prevent bloating)  To achieve orthogonality, provide one runtime component that is in charge of accessing these common interfaces (e.g., a management console) Page 106 © Dr. Michael Stal, 2010 53
    • Dr. Michael Stal: Architecture Refactoring Add Configuration Subsystem (1) Example Actor Subsystem UI Subsystem UI IConfig1 IConfig Configuration Subsystem DB Configuration Subsystem DB Actor IConfig2 Subsystem IConfig Subsystem ATM Subsystem ATM IConfig3 IConfig  Use patterns such as Component Configurator for this purpose Page 107 Add Configuration Subsystem (2)  Context  A system with many configurable variabilities  Problem  If a system contains a lot of configuration options, then configuration itself is often tedious and error-prone  This holds in particular when the configuration options are (partially) related to each other  How can we refactor the software system so that configuration is simplified and (partially) automated?  General solution idea  Instead of providing dozens of configuration options to external actors, we introduce a configuration subsystem that takes a declarative configuration (from a file or a wizard)  The configuration subsystem reacts to configuration change events, reads the passed configuration, and then accesses the configuration interfaces of configurable subsystems  Ideally, all subsystems provide the same generic configuration interface Page 108 © Dr. Michael Stal, 2010 54
    • Dr. Michael Stal: Architecture Refactoring Introduce the Open/Close Principle (1) Example Sensor Sensor ObserverInterface SensorMonitor Page 109 Introduce the Open / Close Principle (2)  Context  Opening a subsystem for external monitoring or modification (e.g., eventing or interception) )  Problem  An existing subsystem needs to be opened to let other subsystems observe this subsystem or intercept specific behavior  So far, the subsystem has been a black box  How can we introduce mechanisms for opening our architecture in a controlled way?  General solution idea  Apply the Open / Close Principle  Design the states and state transitions of the subsystem and decide which transitions should be observable or interceptable  For all these observation and interception points, introduce appropriate hooks with which other subsystems can register for observation or interception  If interception is required, design the required context object and subsystem internal functionality required for interception Page 110 © Dr. Michael Stal, 2010 55
    • Dr. Michael Stal: Architecture Refactoring Optimize with Caching (1) Example Client Subsystem Client Subsystem getResource() getResource() allocates and creates * Resource Cache acquire() release() maintains * Resource Page 111 Optimize with Caching (2)  Context  Optimize access to reusable resources using caching  Problem  When a subsystem provides resources to other parties, resource access becomes a potential bottleneck  If high usage frequency of the same resources leads to performance bottlenecks due to costs for resource creation, allocation, initialization, additional means of accelerating resource access are necessary  How can we optimize resource access?  General solution idea  Introduce a fast cache where reusable resources are maintained  Define an appropriate resource allocation (activation) and a de- allocation (eviction) strategy  Provide a transparency layer to resource users Page 112 © Dr. Michael Stal, 2010 56
    • Dr. Michael Stal: Architecture Refactoring Optimize with Caching (3)  The choice of allocation / de-allocation strategy is important  Example  A web site that returns weather maps based on zip codes  Suppose zip-based maps and weather data are stored in databases. When a new request arrives  A servlet reads the map  reads the weather data  then uses image processing to calculate the map with weather information  which it finally returns to the client  When we introduce a cache, how do we decide which maps to store? Should we always remove the least frequently used maps? Or could we just store the "empty" map in the cache?  How should we deal with updates (weather changes)? For example, can we introduce timeout values (leasing)? Page 113 Replace Singleton (first variant) (1) Example Singleton MethodClass +m1(); +m1(); +m2(); +m2(); +m3(); +m3(); state state t t  State is now a singleton, while behavior isn't  In the end it's all about identity  Known use: EJB Entity Beans Page 114 © Dr. Michael Stal, 2010 57
    • Dr. Michael Stal: Architecture Refactoring Replace Singleton (first variant) (2)  Context  Resources / objects with state that should be available at most once  Problem  Assume that a resource type (objects within a class, threads in a thread pool, …) that represents a particular state should only contain one single instance  For this purpose, the Singleton Pattern is often applied  Unfortunately, the Singleton pattern acts like a global declaration  Are there any alternatives for our problem context?  General solution idea  In a singleton, state and behavior are integrated. The non-transient parts of the state represent the identity of the singleton object  Thus, the singleton mustn't be replicated, as this would duplicate its identity  Replace the singleton class with a class that provides the same public interface (value class), but store all the non-transient state in a central place (database, TSS, hash table, …) with the key known to the new class. The behavior and transient state, however, may be replicated Page 115 Replace Singleton (first variant) (3) Virtual Objects HalfObject1 HalfObject2  The same concept is applicable to se ce () service1() se ce () service1() introduce operational qualities such service2() service3() as availability or fault-tolerance protocol() protocol() through replication  In this case a number of objects provide the same services but store Half Objects their state in a central place Here There  For clients all objects appear as one single (virtual) object local  For state synchronization between physical objects (that represent the same virtual object), a protocol is required remote  Patterns to be applied:  Half-Sync-Plus-Protocol Protoco  Object Group l Page 116 © Dr. Michael Stal, 2010 58
    • Dr. Michael Stal: Architecture Refactoring Replace Singleton (second variant)  Another possible way to remove singletons is to introduce a wrapper, such as an object manager or factory  The wrapper is in control of lifecycle management and thus able to f f ensure that a specific type has only one instance Singleton User +m1(); +m2(); +m3(); state The wrapper ensures that at most one instance of the singleton is created. Note that a singleton Wrapper might be removed and then reactivated, e.g., due to leasing. Page 117 Separate Synchronous and Asynchronous Processing (1) Example sy_svc_1 sy_svc_2 sy_svc_3 as_svc_1 as_svc_2 as_svc_3 Synchronous Service Layer Async Sync Queue sy_svc_1 sy_svc_2 sy_svc_3 Service Service interrupt msg enqueue notify Queuing Layer de-queue as_svc_1 as_svc_2 as_svc_3 msg work interrupt Asynchronous Service Layer Page 118 © Dr. Michael Stal, 2010 59
    • Dr. Michael Stal: Architecture Refactoring Separate Synchronous and Asynchronous Processing (2)  Context  Distributed systems that include a mixture of synchronous and y y asynchronous processing  Problem  Both asynchronous and synchronous services should be decoupled, so that neither suffers from the deficiencies of the other  Both asynchronous and synchronous services should be able to communicate with one another efficiently using their own communication paradigm  How can we refactor an architecture where synchronous and asynchronous services are tightly coupled?  Solution  Separate synchronous and asynchronous services from one another by dedicated layers and add a queuing layer between them to mediate communication between services (Half Sync / Half Async Pattern) Page 119 Replace Remote Methods with Messages (1) Example Client C_Side_Proxy C Side Proxy C_Side_Proxy C Side Pro service_c() service_s() service_s() snd_request() snd_request() rcv_response() rcv_response() * Broker Queue Bridge Direct est_connection() connection listen() est_connection() find_server() enqueue() find_server() register_svt() dequeue() unregister_svt() * Servant S_Side_Proxy S_Side_Proxy service_s() rcv_request() rcv_request() snd_response() snd_response() Page 120 © Dr. Michael Stal, 2010 60
    • Dr. Michael Stal: Architecture Refactoring Replace Remote Methods with Messages (2)  Context  Asynchronous problem using synchronous remote methods  Problem  In many distributed systems remote method invocation is the primary choice of communication. Asynchronicity is often introduced in the application layer, but implemented on top of remote methods  However, message-oriented middleware is often the better choice for dealing with event-based or asynchronous communication  Is there a migration path to move from synchronous to asynchronous communication without huge impact?  General solution idea  Keep the Broker-based architecture unchanged but integrate an additional asynchronous layer that relies on messaging middleware  For synchronous communication, still use the synchronous layer  For asynchronous communication, use the asynchronous layer instead (message queues, asynchronous completion tokens, …)  Future functionality may then directly rely on asynchronous messaging Page 121 Add Object Manager (1) Example Client Factory Object Manager Client create() createObject() delete() deleteObject() find() insertObject() removeObject() findObject() objectIterator() Object * service() ManagedObject service() Page 122 © Dr. Michael Stal, 2010 61
    • Dr. Michael Stal: Architecture Refactoring Add Object Manager (2)  Context  Management support for objects  Problem  Objects (and resources) for client usage often need to implement management functionality in addition to business logic, e.g., lifecycle management, persistence management  This burden leads to memory usage and responsibility overload  Clients shouldn't be responsible for object management either  Different applications may require different management policies  How can we provide such additional management?  General solution idea  Separate object usage from object management  Introduce an manager component that manages objects throughout their lifetime Page 123 Change Unidirectional Association to Bidirectional (1) (Fowler) Example Order Order * * 1 1 Customer Customer class Order... class Customer... Customer getCustomer() { private Set _orders = new HashSet; return _customer; void addOrder(Order arg) { } arg.SetCustomer(this); void setCustomer(Customer arg) { } _customer = arg; Set friendOrders() { } return _orders; Customer customer; } class Order... void setCustomer(Customer arg) { _if (_customer != NULL) customer.friendOrders().add(this); } Page 124 © Dr. Michael Stal, 2010 62
    • Dr. Michael Stal: Architecture Refactoring Change Unidirectional Association to Bidirectional (2) (Fowler)  Context  Two classes referring to each other  Problem  Class A refers to a class B, but there is no backward navigation from B to A  However, after some development activities, you recognize that B also requires a reference to all A objects referring to it  How can we transform the unidirectional to a bidirectional navigation?  General solution idea  Add a back link in class B that allows navigation from B to the referring A object(s)  Decide which class is in charge of controlling the association, e.g.  The composite controls its constituents  In one-to-many relationships, make the one-side (i.e., side with multiplicity of one) the controller  Introduce helper method in the non-controlling side  If the existing modifier is on the controlling side, modify it to update back references, otherwise create a controlling method on the controlling side and call it from the existing modifier Page 125 Refactoring References Page 126 © Dr. Michael Stal, 2010 63
    • Dr. Michael Stal: Architecture Refactoring Refactoring References  Fowler Martin et al. 1999. Refactoring: Improving Fowler, al 1999 the Design of Existing Code. Addison-Wesley  Demeyer, S; Ducasse, S; Nierstrasz, O. 2002. Object-Oriented Reengineering Patterns. Morgan Kaufmann  Kerievsky, Joshua. 2004. Refactoring to Patterns. Addison-Wesley  Ambler, Scott W.; Sadalage, Pramodkumar J, 2006. Refactoring Databases: Evolutionary Database Design. Addison-Wesley  Thanks to Dr. Michael Stal for his permission to use his material in this presentation Page 127 © Dr. Michael Stal, 2010 64