+ All Categories
Home > Education > Accu2010 archrefactoring

Accu2010 archrefactoring

Date post: 09-May-2015
Category:
Upload: michael-stal
View: 1,251 times
Download: 0 times
Share this document with a friend
64
Dr. Michael Stal: Architecture Refactoring 1 © Dr. Michael Stal, 2010 Architecture Refactoring – Motivation, Approach and Patterns Motivation, Approach and Patterns accu 2010 Dr. Michael Stal Panta rhei There is nothing permanent except change [Heraclitus, 535–475 BC] Page 2
Transcript
Page 1: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

1

© Dr. Michael Stal, 2010

Architecture Refactoring –Motivation, Approach and PatternsMotivation, Approach and Patterns

accu 2010

Dr. Michael Stal

Panta rhei

There is nothing permanent except change

[Heraclitus, 535–475 BC]

Page 2

Page 2: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

2

© Dr. Michael Stal, 2010

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

Motivation and foundation

Agenda

Refactoring

Refactoring

Reengineering

Rewriting

Page 4

Comparison

Summary

Page 3: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

3

© Dr. Michael Stal, 2010

Design erosion is the root of all evil

A BackpackBackpack

ABackpack

Detached Extensions In the lifecycle of a software system changesare the rule and not the exception

AComponent

SomeoneElse's Comp

AnotherComponent

The FifthElement

AnotherBackpack

p

New requirements or increments imply modifications or extensions

Engineers must adopt their solutions tonew technologies

Changes in business force changes in IT

Bug fixes require patches or local corrections

Unsystematic approaches ("workarounds")

Page 5

DBAccess Layer

Yet AnotherComponent

Component42

Spaghettidesign

DB accessshortcut

Unsystematic approaches ( workarounds ) cure the symptom but not the problem

After applying several workarounds, software systems often suffer from design erosion

Such systems are doomed to fail as work-arounds have a negative impact on opera-tional and developmental properties

Refactoring is part of the architecture design process

Refactoring is integrated into the iterative-incremental architecture design process:

It improves the structure

It t i k

Refine & AssessArchitecture

Refactor Architecture

Feedback Loop

Page 6

It supports a risk-, requirements- and test-driven approach

Complete?

yesnoExecutable Increment

Page 4: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

4

© Dr. Michael Stal, 2010

Yes, but was is it?

Note: external interfaces i h d!

"Code refactoring is the processof changing a software system

remain unchanged!g g y

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: Refactoringis the process of changing asoftware system or process in

Page 7

software system or process insuch a way that it does not alterthe external behavior, yetimproves its internal structure

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

Page 8

Spacing

Symmetry

Emergence

Consequently, the goal of architecture refactoring is to achieve or improve such qualities

Page 5: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

5

© Dr. Michael Stal, 2010

Motivation and foundation

Agenda

Refactoring

Refactoring

Reengineering

Rewriting

Page 9

Comparison

Summary

Code refactoring

According to Martin Fowler, code refactoring is

Reasons to use refactoring Design improvement and

… 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

… a disciplined way to clean up code that minimizes the chances of introducing bugs

maintenance Better readability Bugs It is the third step in TDD

The Rules of Three Refactor before adding new

functionality, e.g., when t t t i l

Page 10

structure prevents simple additions

Refactor when fixing bugs Refactor after code reviews

toapply improvements

Page 6: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

6

© Dr. Michael Stal, 2010

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

Page 11

Subclasses introducing the same method

Usage of temporary variables

Usage of switch statements

Introduction of a "middleman"

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) {

i tH d ()

Page 12

printHeader();

printRest(text);

}

printHeader() {

System.out.println("Copyright (c) 2008, Siemens AG");

System.out.println("Author: Michael Stal");

}

Page 7: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

7

© Dr. Michael Stal, 2010

Refactoring to patterns

Refactoring to patterns was introduced by Joshua Kerievsky

Kerievsky's book focuseson design patterns

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

Page 13

on design patterns

However, we could alsoapply the same principleto architecture patterns

In the latter case, we'll obtainarchitecture refactorings

Introduce symmetry by making sure the same problem is always solved using the same pattern / solution

This represents a precursor of software architecture refactoring

Replace hard-coded notifications with Observer [Joshua Kerievsky]

Do it yourself Observer Pattern

Observer

update

ConcreteObserver

updatedoSomething

Subject

attachdetachnotifysetDatagetData

stateobserverList

*EventSink

updatedoSomething

Subject

notifysetDatagetData

stateobserverList

*

Dynamic Wiring

Page 14

s->getData()

state = X;

notify();

for all observersin observerList do

update();

Subject contains hardwired list of interested components

Page 8: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

8

© Dr. Michael Stal, 2010

Architecture refactoring

Architecture smells Duplicate design artifacts

Architecture refactoring is about the semantic-preserving t f ti f ft

Duplicate design artifacts Unclear roles of entities Inexpressive or complex

architecture Everything centralized Home-grown solutions instead of

best practices Over-generic design Asymmetric structure or behavior Dependency cycles

transformation of a software design

It changes structure but not behavior

It applies to architecture-relevant design artifacts such as UML diagrams, models, DSL expressions, aspects

Its goal is to improve quality. You

Page 15

Dependency cycles Design violations (such as relaxed

instead of strict layering) Inadequate partitioning of

functionality Unnecessary dependencies Missing orthogonality

got a "smell"? Use an architecture refactoringpattern to solve it!

Remove unnecessary abstractions (1)

*

AbstractStorage

TransportWay

* AbstractStrategyA true story: In

*g

CompositeStorage

BinDoorDumpEquip-ment

y

*ConcreteStrategy

gy

*

Cart Belt

A true story: In this example architects introduced Transport Way as an additional abstraction. But can't we consider transport ways as just as another

Page 16

ConcreteStrategy

*

AbstractStorage

CompositeStorage

BinDoorDump

AbstractStrategy

Equipment

*

kind of storage? As a consequence the unnecessary abstraction was removed, leading to a simpler and cleaner design.

Page 9: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

9

© Dr. Michael Stal, 2010

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

Page 17

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")

Break dependency cycles (1)

GetState()

SetState {

GetState()

SetState {In this example,

Sensor

SetState {

...

M.GetDate()

}

X BreakCycle

Sensor

SetState {

...

D.GetDate()

}

Date

GetDate()

In this example, the monitor invokes the state getter / setter methods but also provides GetDate()to the sensor, lea-ding to a simple dependency cycle. Providing this me-

Page 18

Monitor

GetDate()

Draw() {

... S.GetState();

}

Monitor

Draw() {

... S.GetState();

}

thod to monitors was a bad design decision, anyway. Introducing a separate date object solves theproblem.

Page 10: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

10

© Dr. Michael Stal, 2010

Break dependency cycles (2)

Context

Dependencies between subsystems 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 needto consider the transitive hull

Page 19

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

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

Page 20

Utilities

Special variant: Merge a layer in a layered system

Page 11: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

11

© Dr. Michael Stal, 2010

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)

Page 21

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

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; betweenthese sets there is only low cohesion. Thus, split the subsystem into two (or more) parts.

Component Container

LifecycleManagement

Persistence Event Handling

High Cohesion

ComponentContainer

parts.

Page 22

Communication

Communi-cation

Special variant: Split layer in a layered system

Page 12: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

12

© Dr. Michael Stal, 2010

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

Page 23

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

Move Entities (1)

Example

Game

getPlayerHistory(p)

x y z

Game

getPlayerHistory()

x y z

Page 24

Player Player

getPlayerHistory()

Page 13: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

13

© Dr. Michael Stal, 2010

Move Entities (2)

Context

Moving entities between subsystems 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

Page 25

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

Move Entities (3)

Some additional issues

In many cases we can't apply the refactoring to single atomic entities In many cases, we can t apply the refactoring to single atomic entities 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

Page 26

y y gcohesion 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 14: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

14

© Dr. Michael Stal, 2010

Reduce Dependencies with Facades (1)

Rental CarBooking

1.3

Example

ClientHotel

Booking

g

FlightBooking1.1

1.2

Rental CarB ki

2.3

Page 27

FacadeTravel

Booking

HotelBooking

Booking

FlightBooking2.1

2.2Client

1

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

Page 28

p pworkflows

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 15: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

15

© Dr. Michael Stal, 2010

Substitute Mediation with Adaptation (1)

Example

I_haveno clue sub 1

Adapter Adapter Adapter

Adapter Adapter Adapter

Integration Layer

A B C

no_clue_sub_1

I_haveno_clue_sub2

I_haveno_clue_sub_3

Do_Everything_Class

a.k.a. Mediator

Page 29

D E FI_have

no_clue_sub_4I_have

no_clue_sub_5

I_haveno_clue_sub_6

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

Page 30

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 16: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

16

© Dr. Michael Stal, 2010

Add Uniform Support for Runtime Aspects (1)

Subsys UI Subsys UI

Subsys DB

Subsys ATM

IUIAdmin

IDBAdmin

Subsys DB

Subsys ATM

IAdmin

IAdmin

Page 31

IATMAdmin IAdmin

ManagementConsole

Add Uniform Support for Runtime Aspects (2)

Context Software architecture that must support runtime aspects such as

f flifecycle management, management, configuration 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

Page 32

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 17: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

17

© Dr. Michael Stal, 2010

Add Configuration Subsystem (1)

Example

Subsystem UI

Subsystem DB

IConfig2

IConfig1

Actor

Subsystem UI

Subsystem DB

IConfig

IConfig

ConfigurationSubsystem

Actor

Configuration

Page 33

Subsystem ATM

IConfig3

Subsystem ATM

IConfig

Use patterns such as Component Configurator for this purpose

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,

Page 34

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 18: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

18

© Dr. Michael Stal, 2010

Where to obtain architecture refactorings?

A whole catalog of architecture refactorings is provided as a starting

i t

1. Rename Entities

2. Remove Duplicates

3. Introduce Abstraction Hierarchies

4. Remove Unncessary Abstractions

5. Substitute Mediation with Adaptation

6. Break Dependency Cycles

7. Inject Dependencies

8. Insert Transparency Layer

9. Reduce Dependencies with Facades

17. Enforce Contract18. Provide Extension Interfaces19. Substitute Inheritance with Delegation20. Provide Interoperability Layers21. Aspectify22. Integrate DSLs23. Add Uniform Support to Runtime Aspects24. Add Configuration Subsystem25. Introduce the Open/Close Principle26. Optimize with Caching27. Replace Singleton

point

Page 35

p

10. Merge Subsystems

11. Split Subsystems

12. Enforce Strict Layering

13. Move Entities

14. Add Strategies

15. Enforce Symmetry

16. Extract Interface

27. Replace Singleton28. Separate Synchronous and Asynchronous

Processing29. Replace Remote Methods with Messages30. Add Object Manager31. Change Unidirectional Association to Bidirectional

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 anal sis Check the res lting

Page 36

Architecture analysis: Check the resulting 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 19: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

19

© Dr. Michael Stal, 2010

Refactoring – responsibilities and communication

The process of refactoring requires communication with testers and developers

Detailed project planning

Testability

SW Design

Requirements Engineer Review system

architecture documents

Product Lifecycle Manager

Control product development across lifecycles

SW Project Manager

Define detailed project plans

Assign resources

Head of R&D Control SW

Page 37

y

Software Developer Identify code

smells Apply code

refactorings

Software Architect Analyze architecture smells Identify appropriate software

architecture refactorings e.g., using refactoring catalogs

Apply software architecture refactorings

Verify correctness of refactorings Be involved in design reviews Leverage CQM tools

Control SW process

Act as escalation point

Test Manager Review product architecture Refine master test plan Set up test strategy for integration and

system test Define test environment Define verification and validation

procedure

Application of architecture refactorings

The usage of a concrete application refactoring should never happen in and h t ti I t dad-hoc, unsystematic way. 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

Page 38

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 20: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

20

© Dr. Michael Stal, 2010

Obstacles to refactoring (1)

Organization / management Considering improvement by refactoring

as less important than providing new p p gfeatures

Ignorance of refactoring necessity typically causes design erosion

“Organization drives architecture” problem

Process support No steps / activities defined in process

for architecture refactoring: Refactoring h ld b dd d li itl i th

Page 39

should be addressed explicitly in the 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

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

d t i d b i t i it d

Page 40

determined by requirements priority and relevance

Page 21: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

21

© Dr. Michael Stal, 2010

Motivation and foundation

Agenda

Refactoring

Refactoring

Reengineering

Rewriting

Page 41

Comparison

Summary

Reengineering – how it differs from refactoring

Scope: Reengineering always affects the entire system;

f t i h t i llrefactoring has typically (many) local effects

Process: Reengineering follows a disassembly / reassembly approach; refactoring is a behavior-preserving, structure transforming process

Result: Reengineering can

Page 42

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 22: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

22

© Dr. Michael Stal, 2010

Reengineering – when and how to use it

Use reengineering when

The system's documentation

Process Phase I: Reverse engineering

Reverse Forward

The system s documentationis missing or obsolete

The team has only limited understanding of the system, its architecture, and implementation

A bug fix in one place causes bugs in other places

g g Analysis / recovery: determine

existing architecture (consider using CQM) SWOT analysis Decisions: what to keep, what

to change or throw away Phase II: Forward engineering

Page 43

Reverseengineering

Forwardengineering

Code

DesignPick

W orkpiece

LogAlarms

TelegramForwarder

TelegramReceiver

TelegramConverter

SetPointCalculation

Command

LoggingStrategy

CommandProcessor

Logger

The network

creates

executes

applies passescommands to

passes telegrams topasses telegrams to

ConferenceOrganizer

usesConference

Manager

ConferenceParticipant

Conference

ConferenceSession

organizes

manages

Scheduler

uses

has*

*

Documents

usesMedia

Manager

*

participates

Requirements

causes bugs in other places

New system-level require-ments and functions cannot be addressed or integrated appropriately

Motivation and foundation

Agenda

Refactoring

Refactoring

Reengineering

Rewriting

Page 44

Comparison

Summary

Page 23: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

23

© Dr. Michael Stal, 2010

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:Depending on focus: Improves structure regarding:

Simplicity, visibility, spacing, symmetry, emergence

Maintainability, readability, extensibility

Bug fixing

Provides new functionality

Improves its operational qualities

Page 45Page 45

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.

Learning from failure

Failure and understanding failure is a keyfactor for successful design!

[Henry Petroski]

Page 46

Before you’re going to rewrite, check what went wrong in the project that developed the previous application

Page 24: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

24

© Dr. Michael Stal, 2010

Motivation and foundation

Agenda

Refactoring

Refactoring

Reengineering

Rewriting

Page 47

Comparison

Summary

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

Reverseengineering

Forwardengineering

Requirements

LoggingStrategy

ConcreteLoggingStrategy

ClientCommandProcessor

StrategyCommandProcessor

Page 48Page 48

Code

DesignPick

Workpiece

LogAlarms

TelegramForwarder

TelegramReceiver

TelegramConverter

SetPointCalculation

Command

LoggingStrategy

CommandProcessor

Logger

The network

creates

executes

applies passescommands to

passes telegrams topasses telegrams to

ConferenceOrganizer

usesConference

Manager

ConferenceParticipant

Conference

ConferenceSession

organizesmanages

Scheduleruses

has*

*

Documents

usesMediaManager

*

participates

q

*

Strategy

ConcreteCommand

Command

CompositeCommand

Memento

Application

Memento

Command &Composite

Page 25: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

25

© Dr. Michael Stal, 2010

Refactoring, reengineering, and rewriting comparison (2)

Refactoring Reengineering Rewriting

Scope Many local effects Systemic effect Systemic or local effect

Process Structure transforming Disassembly / reassambly ReplacementProcess Structure transforming

Behavior / semantics preserving

Disassembly / reassambly Replacement

Results Improved structure

Identical behavior

New system New system or new component

Improved qualities

Developmental Functional

Operational

Developmental

Functional

Operational

Developmental

Drivers Complicated design / code evolution

Wh fi i b

Refactoring is insufficient

Bug fixes cause rippling effect

Refactoring and reengineering are insufficient or inappropriate

Page 49Page 49

When fixing bugs

When design and code smell bad

New functional and operational requirements

Changed business case

or inappropriate

Unstable code and design

New functional and operational requirements

Changed business case

When

Part of daily work

At the end of each iteration

Dedicated refactoring iterations in response to reviews

It is the 3rd step of TDD

Requires a dedicated project Requires dedicated effort or a dedicated project, depending on scope

Motivation and foundation

Agenda

Refactoring

Refactoring

Reengineering

Rewriting

Page 50

Comparison

Summary

Page 26: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

26

© Dr. Michael Stal, 2010

What we learned

Refactoring changes artifacts without changing external behavior. It helps with quality improvement

d hand necessary changes 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 i t t h f t i i i

Page 51

important when refactoring, reengineering, rewriting

You as a software architect are responsible to Detect architecture smells Find and apply appropriate refactorings Perform QA of refactoring activities

A departing thought

Each problem that I solved became a rule which served afterwards to solve other problems.

[René Descartes, 1596–1650, in "Discours

Page 52

de la Methode"]

Page 27: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

27

© Dr. Michael Stal, 2010

Backup

Backup

Page 53

Rename Entities (1)

Example

Comp ShareTicker

Page 54

AnotherComp ShareObserver

Page 28: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

28

© Dr. Michael Stal, 2010

Rename Entities (2)

Context

Using non-intuitive namesUsing non intuitive names

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

Page 55

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

Remove Duplicates (1)

Extract:

Example

Client Amain() {...}

Extract:

Connect JNDI

Get Home

Locate bean X

Client A'main() {...}

Bean LocationComponent

1. Connect JNDI

2. Get Home

3. Locate bean

call locateBean(X)

Page 56

Client Bmain() {...}

Extract:

Connect JNDI

Get Home

Locate bean Y

Client B'main() {...}

Extract:

call locateBean(Y)

Page 29: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

29

© Dr. Michael Stal, 2010

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?

Page 57

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

Introduce Abstraction Hierarchies (1)

Wi d Wi d

Example: Class hierarchy

Windowdisplay()

Paneldisplay()drawPixel()

Buttondisplay()drawPixel()

Windowdisplay()

PaneldrawPixel()

ButtononClick()

Page 58

drawPixel()onClick()

Separate abstractions

Related abstractions

"is-a" relation

Page 30: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

30

© Dr. Michael Stal, 2010

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

Page 59

these entities Define hierarchy of abstractions Derive entities from the most specific abstraction

Different possibilities Adding superclass Adding common interfaces

Remove Unnecessary Abstractions (1)

Example

*

AbstractStorage

TransportWay

* AbstractStrategy

CompositeStorage

BinDoorDumpEquip-ment

*

ConcreteStrategy

*

Cart Belt

Page 60

ConcreteStrategy

*

AbstractStorage

CompositeStorage

BinDoorDump

AbstractStrategy

Equipment

*

Page 31: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

31

© Dr. Michael Stal, 2010

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

Page 61

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")

Substitute Mediation with Adaptation (1)

Example

I_haveno clue sub 1

Adapter Adapter Adapter

Adapter Adapter Adapter

Integration Layer

A B C

no_clue_sub_1

I_haveno_clue_sub2

I_haveno_clue_sub_3

Do_Everything_Class

a.k.a. Mediator

Page 62

D E FI_have

no_clue_sub_4I_have

no_clue_sub_5

I_haveno_clue_sub_6

Page 32: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

32

© Dr. Michael Stal, 2010

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

Page 63

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

Break dependency cycles (1)

GetState()

SetState {

GetState()

SetState {In this example,

Sensor

SetState {

...

M.GetDate()

}

X BreakCycle

Sensor

SetState {

...

D.GetDate()

}

Date

GetDate()

In this example, the monitor invokes the state getter / setter methods but also provides GetDate()to the sensor, lea-ding to a simple dependency cycle. Providing this me-

Page 64

Monitor

GetDate()

Draw() {

... S.GetState();

}

Monitor

Draw() {

... S.GetState();

}

thod to monitors was a bad design decision, anyway. Introducing a sepa-rate date object solves theproblem.

Page 33: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

33

© Dr. Michael Stal, 2010

Break dependency cycles (2)

Context

Dependencies between subsystems 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 needto consider the transitive hull

Page 65

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

Break dependency cycles – Dependency Inversion

Attach(Observer)

Notify(

interface IObserver { Handle() }

Attach(IObserver)

Notify(

Subject'

Notify(

observer.Handle();

)

Subject

Notify(

iObserver.Handle();

)

Dependency inver-sion constitutesanother variant

Page 66

Observer'

Handle()

StartUp() {

subj.Attach(obs);

)

Observer

class Obs implements IObserver {

Handle() { ...} }

StartUp(

subj.Attach(obs);

)

Page 34: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

34

© Dr. Michael Stal, 2010

Inject Dependencies (1)

Component c {

S s = new S(.....);

Component c {

inject(S p){ s=p;}

Example

Component c

s.m();

}

Component c

s.m();

}

Page 67

Component s Container m Component s

C c = new C();

S.S = new S(.....);

c.inject(s);

Inject Dependencies (2)

Context

Components that need to create and use other componentsComponents 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

Page 68

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 35: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

35

© Dr. Michael Stal, 2010

Insert Transparency Layer (1)

Example

ClientSubsystem B

Client

Subsystem BTRANSPARENCY

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

Page 70

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 36: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

36

© Dr. Michael Stal, 2010

Example: Introducing Protection Layers

Typically, an architectural entity depends directly on other architectural entities

This becomes a problem when the target of the Client

p gdependency 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

Server

Protection Layer

Page 71

Server

Reduce Dependencies with Facades (1)

Rental CarBooking

1.3

Example

ClientHotel

Booking

g

FlightBooking1.1

1.2

Rental CarB ki

2.3

Page 72

FacadeTravel

Booking

HotelBooking

Booking

FlightBooking2.1

2.2Client

1

Page 37: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

37

© Dr. Michael Stal, 2010

Reduce Dependencies with Facades (2)

Context Client implements workflows that mostly access other componentsp 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

Page 73

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 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)

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

Page 74

Utilities

Special variant: Merge a layer in a layered system

Page 38: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

38

© Dr. Michael Stal, 2010

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)

Page 75

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

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; betweenthese sets there is only low cohesion. Thus, split the subsystem into two (or more) parts.

Component Container

LifecycleManagement

Persistence Event Handling

High Cohesion

ComponentContainer

parts.

Page 76

Communication

Communi-cation

Special variant: Split layer in a layered system

Page 39: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

39

© Dr. Michael Stal, 2010

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

Page 77

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

Enforce Strict layering (1)

Example

Application Application

Component 3.1

Component 3.2

Component 3.3

Layer 3

Component 2.1

Component 2.2

Layer 2

pp

Component 3.1

Component 3.2

Component 3.3

Layer 3

Component 2.1

Component 2.2

Layer 2

Application

Brokenlayering

Page 78

Component 1.1

Component 1.2

Component 1.3

Layer 1

Component 1.1

Component 1.2

Component 1.3

Layer 1

Page 40: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

40

© Dr. Michael Stal, 2010

Enforce Strict Layering (2)

Context

An architecture with broken layering 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

Page 79

y g y yjustification 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

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

Page 80

invocations of layer 2. For the rest of the invocations, move 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 41: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

41

© Dr. Michael Stal, 2010

Move Entities (1)

Example

Game

getPlayerHistory(p)

x y z

Game

getPlayerHistory()

x y z

Page 81

Player Player

getPlayerHistory()

Move Entities (2)

Context

Moving entities between subsystems 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

Page 82

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 42: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

42

© Dr. Michael Stal, 2010

Move Entities (3)

Some additional issues

In many cases we can't apply the refactoring to single atomic entities In many cases, we can t apply the refactoring to single atomic entities 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

Page 83

y y gcohesion 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)

Add Strategies (1)

Warning

Example

Client

Request Dispatcher

Client

Middleware

DispatcherStrategy

Middleware

Warning

Never introduce strategies in an uncontrolled way

A strategy basically means "I have no idea which option to use at runtime"

St t S d i

Page 84

Protocol Protocol

ConcreteDispatcher Strategy Syndrome is

a serious disease that leads to an over-generic architecture which is doomed to design erosion

Page 43: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

43

© Dr. Michael Stal, 2010

Add Strategies (2)

Context

Enable selection and exchange of implementationsEnable 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

Page 85

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

Enforce Symmetry (1)

Examples for structural symmetry

Subsystem UIBased on MVCand Observer

Subsystem Accounts

Subsystem UIBased on MVCand Observer

Some places in the architecture throw exceptions, while other return error codes

One subsystem leverages the Observer pattern

Page 86

yUses hardwiredconfiguration ofevent handlers

Subsystem AccountsUses Observer

Observer pattern, another one a hardwired event notification strategy

Page 44: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

44

© Dr. Michael Stal, 2010

Enforce Symmetry (2)

Context

Refactor an asymmetric solutionRefactor 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

Page 87

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

Enforce Symmetry (3)

AbstractProductA

ProductA

AbstractFactory

create productA

Example for functional symmetry: Abstract Factory with missing dispose method

ProductA

ConcreteProductA

ProductA

create_productA

ConcreteFactory

create_productA

Page 88

AbstractFactory

create_productAdispose_productA

ConcreteFactory

create_productAdispose_productA

AbstractProductA

ProductA

ConcreteProductA

ProductA

Page 45: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

45

© Dr. Michael Stal, 2010

Extract Interface (1)

<< interface >>

ISensor

Example

Sensor

temperature()useCelsius()useFahrenheit()initialize()reset()

ISensorgetTemperature(UNIT)

Sensor

temperature()useCelsius()useFahrenheit()

if (UNIT == CELSIUS)

useCelsius();

else

useFarhrenheit();

Adapter

Page 89

getAverage(from,to)storeRecord()getRecord(DateTime)getDateTime()

initialize()reset()getAverage(from,to)storeRecord()getRecord(DateTime)getDateTime()

return temperature();

Extract Interface (2)

Context

(Sub)system needs to export functionality(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

Page 90

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 46: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

46

© Dr. Michael Stal, 2010

Enforce Contract (1)

<< interface >> << interface >>

Example

<< interface >>

IFileHandle open(File)Write(Handle, buf)

close(Handle)

<< interface >>

IFileHandle open(File)

Write(buf)close()

Contract Implementation

Open/IsValid(File)

Open/not IsValid(File)

Write/notEmpty(buf)

Close

Page 91

File System File System( )

Enforce Contract (2)

Context

Enforcing contract of an interfaceEnforcing 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?

Page 92

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 47: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

47

© Dr. Michael Stal, 2010

Provide Extension Interfaces (1)

Factory Client

create()find()

RootInterface

get_extension()

Extension Extension

Interface1

service_1.1();service_1.2();service_1.3();service_1.4();......

Page 93

Interface1

service_1()

Interface2

service_2()

Component

svc_1_impl()svc_2_impl()

Component

.service_1.n();

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?

Page 94

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 48: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

48

© Dr. Michael Stal, 2010

Provide Extension Interfaces (3)

Client Factory

Notes

create Comp.Root

Interface

ExtInter-face1

ExtInter-face2

service1

InterfaceID1

InterfaceID1

Interface1Interface

1

InterfaceID2 get_extension

This refactoring alters components and clients. Thus, handle with care!

Interface navigation should be reflexive, symmetric, transitive

But you may also

Page 95

ID2

Interface2

service2

But you may also introduce a dedicated interface that includes the navigation functionality

Substitute Inheritance with Delegation (1)

Example

Playerplay()

NinjalookupExperience()

IPlayerplay()

Player

play(IPlayer)play()

NinjalookupExperience()play()Player pdelegate

Page 96

play(IPlayer ip) {// pre-processingthis.play();// post-processing}

Page 49: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

49

© Dr. Michael Stal, 2010

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

Page 97

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!

Provide Interoperability Layers (1)

Example

Application layer

Adapter layer

Page 98

Provide bidirectional interoperability between two subsystems usingWeb Services

Extract subsystem interfaces and use adapters (e.g., session facades, business delegates) to integrate them with their subsystems

Page 50: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

50

© Dr. Michael Stal, 2010

Provide Interoperability Layers (2)

Context

Enable interoperability between two subsystemsEnable 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

Page 99

Adapt subsystem A to B or subsystem B to A, or use a bidirectional 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

Provide Interoperability (3)

Aspects for interoperability in object-oriented, distributed systems

Interoperability is not restricted to data transformation and 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

Page 100

p p y p , pmust spend to close the semantic gap

Integration products such as EAI solutions just provide a set of proprietary interoperability solutions

Page 51: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

51

© Dr. Michael Stal, 2010

Aspectify (1)

Example

+

Page 101

Logging functionality

Logging functionality

Aspectify (2)

Context Dealing with cross-cutting concernsg 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

Page 102

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 52: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

52

© Dr. Michael Stal, 2010

Integrate DSLs (1)

Example

Abstract

Monitor

StorageMgr Capacity ServiceX

RootInterface

InterfaceFactory

Abstract

Monitor

StorageMgr Capacity ServiceX

RootInterface

InterfaceFactory

Hook

AbstractInterceptor

*

*

StorageMgrInterface

CapacityInterface

ServiceXInterface

StorageCapacity

*

AbstractVisitor

LeafsOnly

AbstractStrategy

LoadInLayers

AbstractIterator

*

StorageManager

HazardousSOC

SOCFactory

*Bin

*AbstractStorage

Warehouse

Successor

AtomicStorage

CompositeStorage

Aisle

Hook

AbstractInterceptor

*

*

StorageMgrInterface

CapacityInterface

ServiceXInterface

StorageCapacity

*

AbstractVisitor

LeafsOnly

AbstractStrategy

LoadInLayers

AbstractIterator

*

StorageManager

HazardousSOC

SOCFactory

*Bin

*AbstractStorage

Ware-house

Successor

AtomicStorage

CompositeStorage

Aisle

Page 103

Microsoft's XAML (eXtensible Application Markup Language) is usedfor specifying workflows declaratively within and between applications

In the past, developers had to hardcode these workflows in thearchitecture using implementation languages such as C#

RealBin

HazardousValue

ThreadMutex Socket

RealBin

HazardousValue

ThreadMutex Socket

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

Page 104

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 53: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

53

© Dr. Michael Stal, 2010

Add Uniform Support for Runtime Aspects (1)

Subsys UI Subsys UI

Subsys DB

Subsys ATM

IUIAdmin

IDBAdmin

Subsys DB

Subsys ATM

IAdmin

IAdmin

Page 105

IATMAdmin IAdmin

ManagementConsole

Add Uniform Support for Runtime Aspects (2)

Context Software architecture that must support runtime aspects such as

f flifecycle management, management, configuration 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

Page 106

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 chargeof accessing these common interfaces (e.g., a management console)

Page 54: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

54

© Dr. Michael Stal, 2010

Add Configuration Subsystem (1)

Example

Subsystem UI

Subsystem DB

IConfig2

IConfig1

Actor

Subsystem UI

Subsystem DB

IConfig

IConfig

ConfigurationSubsystem

Actor

Configuration

Page 107

Subsystem ATM

IConfig3

Subsystem ATM

IConfig

Use patterns such as Component Configurator for this purpose

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,

Page 108

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 55: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

55

© Dr. Michael Stal, 2010

Introduce the Open/Close Principle (1)

Example

Sensor Sensor

ObserverInterface

Page 109

SensorMonitor

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

Page 110

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 56: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

56

© Dr. Michael Stal, 2010

Optimize with Caching (1)

Example

Cache

acquire()release()

ClientSubsystem

getResource()

Resource

Client

*

allocates andcreates

Subsystem

getResource()

Page 111

release()

Resource*

maintains

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

Page 112

Define an appropriate resource allocation (activation) and a de-allocation (eviction) strategy

Provide a transparency layer to resource users

Page 57: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

57

© Dr. Michael Stal, 2010

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?

Page 113

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)?

Replace Singleton (first variant) (1)

Singleton MethodClass

Example

+m1();+m2();+m3();

state

+m1();+m2();+m3();

t t

Page 114

state

State is now a singleton, while behavior isn't In the end it's all about identity Known use: EJB Entity Beans

Page 58: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

58

© Dr. Michael Stal, 2010

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

Page 115

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

Replace Singleton (first variant) (3)

HalfObject1

service1()

Virtual Objects The same concept is applicable to

HalfObject2

service1()se ce ()service2()

protocol()

Here There

local

introduce operational qualities such as availability or fault-tolerance through replication

In this case a number of objects provide the same services but store their state in a central place

For clients all objects appear as one single (virtual) object

For state synchronization between

Half Objects

se ce ()service3()

protocol()

Page 116

remote

Protocol

For state synchronization between physical objects (that represent the same virtual object), a protocol is required

Patterns to be applied: Half-Sync-Plus-Protocol Object Group

Page 59: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

59

© Dr. Michael Stal, 2010

Replace Singleton (second variant)

Another possible way to remove singletons is to introduce a wrapper, such as an object manager or factory

f f

Singleton

+m1();+m2();+m3();

state

User

The wrapper is in control of lifecycle management and thus able to ensure that a specific type has only one instance

Page 117

Wrapper

The wrapper ensures that at most one instance of the singleton is created. Note that a singleton might be removed and then reactivated, e.g., due to leasing.

Separate Synchronous and Asynchronous Processing (1)

Example

sy_svc_1 sy_svc_2 sy_svc_3

sy_svc_1 sy_svc_2 sy_svc_3

Synchronous Service Layer

as_svc_1 as_svc_2 as_svc_3

AsyncService

QueueSync

Service

interrupt

msg

Page 118

as_svc_1 as_svc_2 as_svc_3

Asynchronous Service Layer

Queuing Layer

interrupt

notifyenqueue

work

msg

de-queue

msg

Page 60: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

60

© Dr. Michael Stal, 2010

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

Page 119

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)

Replace Remote Methods with Messages (1)

Client C Side Proxy C Side Pro

Example

Client

service_c()

C_Side_Proxy

service_s()

snd_request()rcv_response()

Broker

est_connection()find_server()register_svt()

Bridge

est_connection()find_server()

*

C_Side_Proxy

service_s()

snd_request()rcv_response()

Queue

listen()enqueue()dequeue()

Direct connection

Page 120

Servant

service_s()

S_Side_Proxy

rcv_request()snd_response()

unregister_svt()

*S_Side_Proxy

rcv_request()snd_response()

dequeue()

Page 61: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

61

© Dr. Michael Stal, 2010

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

Page 121

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

Add Object Manager (1)

Example

Client Factory

create()delete()find()

Object

ClientObject Manager

createObject()deleteObject()insertObject()removeObject()findObject()objectIterator()

Page 122

service() ManagedObject

service()

*

Page 62: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

62

© Dr. Michael Stal, 2010

Add Object Manager (2)

Context

Management support for objectsManagement 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

Page 123

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

Change Unidirectional Association to Bidirectional (1) (Fowler)

Order Order

Example

Customer

*

1

Customer

*

1

class Order...Customer getCustomer() {return _customer;}

class Customer...private Set _orders = new HashSet;void addOrder(Order arg) {arg.SetCustomer(this);

Page 124

}void setCustomer(Customer arg) {_customer = arg;}Customer customer;

arg.SetCustomer(this);}Set friendOrders() {return _orders;}

class Order...void setCustomer(Customer arg) {_if (_customer != NULL)customer.friendOrders().add(this);

}

Page 63: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

63

© Dr. Michael Stal, 2010

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)

Page 125

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

Refactoring

References

Page 126

Page 64: Accu2010 archrefactoring

Dr. Michael Stal: Architecture Refactoring

64

© Dr. Michael Stal, 2010

Refactoring

Fowler Martin et al 1999 Refactoring: Improving

References

Fowler, Martin et al. 1999. Refactoring: Improving 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

Page 127

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