Sie sind auf Seite 1von 48

ITARC Singapore 2008

Hotel Grand Hyatt Singapore


10 & 11 November 2008

Combating software entropy with Design Patterns and Principals


By Hammad Rajjoub and Zac Walker

Introduction

Why is it hard to change existing software?

Introduction

Statement: The ability to change, is linked to a systems stability in the face of change.

Stability and Change


Stability in the face of change is a requirement of all systems.
As we layer up behaviour for a release As we add new requirements As user feedback is acted on As we fix bugs

In an Agile World
In and agile world we already manage change. We have many practices:
Unit tests Refactoring Continuous Integration Iterations On-sight customer

Design for Change

As Architects how do we judge a designs ability to change technically?

Bad design indicators

Rigidity: Hard to change Fragility: Changes break other parts Immobility: Reuse is not possible

Combating software entropy

What we need is a set of principals to evaluate a designs ability to change and remain stable.

Principals we can use

The Open Closed Principal Single Responsibility Principal Dependency Inversion Principal Liskov Substitution Principal

The Open-Closed Principal "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"

What a blessing it would be if we could open and shut our ears as easily as we open and shut our eyes!
Georg Christoph Lichtenberg (1742 1799)

The Open-Closed Principal "To understand the Open-Closed Principal, we need to understand stability in the face of change."

What is an object?
Objects encapsulate state with behaviour. Classes are more stable because state is encapsulated. Behaviour

State

Interaction and Stability


There is a dynamic between object/module interaction and stability. Changing an object de-stabilises its dependants.

Less Stable

Stable

The single responsibility principal "A responsibility is a reason to change, a class or module should have one, and only one, reason to change."

None but Buddha himself must take the responsibility of giving out occult secrets...
E. Cobham Brewer 18101897. Dictionary of Phrase and Fable. 1898.

The Single Responsibility Principal

Responsibility is a Reason for change Each responsibility is an axis of change There should never be more than one reason for a class to change Dijkstras SoC: Separation of Concerns This helps us evaluate a classes exposure to change

Counterparty Validator

Counterparty Validator

Trade DB

What is wrong here: Changes if DB changes or Business Logic Changes

Counterparty Validator
internal class CounterpartyValidator { public void AssertValid(Trade t) { var sql = "SELECT COUNT(*) FROM counterparty WHERE name=@Name"; using (var conn = CreateOpenConnection()) { var cmd = new SqlCommand(sql, conn); cmd.Parameters.Add("@Name", SqlDbType.VarChar); cmd.Parameters["@name"].Value = t.CounterpartyName; var count = (Int32) cmd.ExecuteScalar(); if (count != 1) throw new InvalidCounterpartyException(t.CounterpartyName); } } ...

Where is the business logic? Hidden by database code.

Better Counterparty Validator


internal class CounterpartyValidator { private readonly CounterpartySource counterpartySource; public CounterpartyValidator(CounterpartySource counterpartySource) { this.counterpartySource = counterpartySource; } public void AssertValid(Trade t) { if (counterpartySource.FindByName(t.CounterpartyName) == null) throw new InvalidCounterpartyException(t.CounterpartyName); } }

CounterpartyValidator now has a single responsibility

Single responsibility

Counterparty Validator

Counterparty Source

Trade DB

What's its job? Classes must have an identifiable single responsibility.

Whats it job?
Classes should have a single responsibility or job Developers should have that job in mind when they work on a class A developer should easily be able to write a block comment at the top of a class identifying its job. That comment should not have the word AND in it.

Dependency Inversion Principal High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions."
It may be that the old astrologers had the truth exactly reversed, when they believed that the stars controlled the destinies of men. The time may come when men control the destinies of stars.
Arthur C. Clarke (1917 - ), First on the Moon, 1970

Counterparty Validator
High Level (Less Stable)

Counterparty Validator

Counterparty Source

Trade DB Low Level (More Stable) Introduce stability with abstraction

Better Counterparty Validator

<Interface> ICounterparty Source


Counterparty Validator DBCounterparty Source Trade

DB

Extensible Counterparty Source


Good Dependency Counterparty Validator <Interface> ICounterparty Source

Trade

DBCounterparty Source

Web Service Counterparty Source

DB

Cloud

Inversion of Control

Inversion of Control
IoC is key part of Frameworks Hollywood Principal (Dont call us, We will call you)

Frameworks have extensibility points Interfaces, Closures & Events

Dependency Injection

Specific means of IoC Closely tied to Plug-ins Lookup (service locator) specific plug-in like implementation Containers vs. Factories Suits TDD (Mocks) Number of injections indicate stability

Containers at your service


Available Containers Pico Spring Castle Object Map Unity Custom (home grown) Container Registering dependencies Resolving params Managing Lifetimes (Caching etc)

The Liskov substitution principal Functions that reference a base class must be able to use objects of derived classes without knowing it."

There is a theory which states that if ever anybody discovers exactly what the Universe is for and why it is here, it will instantly disappear and be replaced by something even more bizarre and inexplicable. There is another theory which states that this has already happened. Douglas Adams (1952 - 2001)

Rate Calculator

RateCalculator

Trade

Fee

Option

Rate Calculator Code

public decimal CalulateRate(Trade t) { if (t is Fee) { return 1.0m; } return t.BaseAmount/t.QuotedAmount; }

Issues: Exposed to change. We cannot add an adjustment fee type. A convention not a design, developers may not follow.

Better Rate Calculator


public abstract class Trade { ... public abstract decimal Rate { get; } } public class Fee : Trade { ... public override decimal Rate { get { return 1.0m; } } } Protecting against change: Forces developers to implement rate logic when they introduce a now instrument or trade type.

Example: Contract First Development


Contract First Component Development Problem with COM across C++ and VB Contracts in SOA Web Services scenario:

Understand the contract


As a stock broker I want to validate my quotes so that I know they have a valid counterparty Counterparty Validator

Trade

Fee

Option

First Attempt
Counterparty Validator <Interface> ITrade Quote

Trade

Linked to the stability of trade

Fee

Option

Role based interface


Counterparty Validator <Interface> ICounterpartyHost

Quote

Trade

OCP software entities should be open for extension, but closed for modification

Fee

Option

Stability in the face of Change

Measuring stability using metrics

Stable Dependencies Principal The dependencies between packages in a design should be in the direction of the stability of the packages. A package should only depend upon packages that are more stable than it is."

Module Dependencies

Validation Module

Products Module

Reference Data Module

Stability Metrics
Ca : Afferent Couplings : The number of classes outside this package that depend upon classes within this package. Ce : Efferent Couplings : The number of classes inside this package that depend upon classes outside this package. I : Instability : (Ce/(Ca+Ce)) : This metric has the range [0,1]. I=0 indicates a maximally stable package. I=1 indicates a maximally instable package.

Module Dependencies
Ca: 0 Ce: 1 I:1 Validation Module

Ca: 1 Ce: 0 I:0 Products Module

Ca: 1 Ce: 0 I:0 Reference Data Module

Low Ce (Efferent Couplings) but high Ca (Afferent Couplings )

Stable Abstractions Principle Packages that are maximally stable should be maximally abstract. Instable packages should be concrete. The abstraction of a package should be in proportion to its stability."

Measuring Abstraction

A = abstractClasses / totalClasses
Only as approximation as abstract classes have varying numbers of abstract methods, but it is a good guide.

Module Dependencies

Validation Module

Products Module

Reference Data Module

Should be maximally Abstract

Strategic Closure
No significant program can be 100% closed Closures cant be complete Closures must be Strategic Stability metrics can indicate hotpots Designer must choose the changes against which her design should be closed

Summary
Judge your design for exposure to change The Open Closed Principal Single Responsibility Principal Dependency Inversion Principal Liskov Substitution Principal Understand stability in the face of change Stable Dependencies Principal Stable Abstractions Principal

References
Open Closed Principal: http://www.objectmentor.com/resources/articles/ocp.pdf Single Responsibility Principal: http://msdn.microsoft.com/en-us/magazine/cc546578.aspx Contract First Development: http://msdn.microsoft.com/en-us/magazine/cc163800.aspx Robert C. Martin http://www.objectmentor.com/omTeam/martin_r.html Martin Fowlers Blog: http://martinfowler.com/bliki/

Q&A Thank You


Hammad.rajjoub@gmail.com zac@imagewalker.com

Das könnte Ihnen auch gefallen