Advanced Principles of Component Design

Advanced Principles II
Principles of Object-Oriented
Component Design
www.objectmentor.com
Copyright  1998-2006 by Object Mentor, Inc
All Rights Reserved
www.junit.org
Portions of this material are Copyright © 1998, by
Addison Wesley Longman,Inc. and have been
reproduced here with permission.
Increasing Complexity
Software Complexity increases Geometrically with
Time
10000
10000
8000
Lines of Code
(thousands)
Windows 95: 14,500,000
Windows NT: 35,000,000
6000
4000
2000
0
1
1960s
2
10
1970s
100
1980s
1000
1990s
2000s
Complexity and Failure
(Software’s Chronic Crisis, Scientific American, September, 1994)
Project Failure vs Function Points
12000
10000
8000
Function
6000
Points
4000
2000
0
10
20
30
Percent Projects that Fail
3
40
50
Complexity dilutes Productivity
Because complexity of software can
grow geometrically with size...
4
Coupling
1
Coupling is the term used
to describe the
dependence of one
software module upon
another.
2
3
4
7
5
6
2
In a system with n
modules, the coupling can
be as high O(n2).
5.E+06
4.E+06
4.E+06
3.E+06
3.E+06
2.E+06
2.E+06
1.E+06
5.E+05
0.E+00
1
15
1
30
1
45
1
60
1
75
1
90
1
10
51
12
01
13
51
15
01
16
51
18
01
19
51
When coupling is high,
there are many
dependencies between
the modules.
Number of dependencies
Coupling as a function of O(n )
Number of Modules
5
Coupling – Impact of Change
The impact of making a
change to a module is a
function of its coupling.
(A system with a fully
coupled architecture)
Every module that depends
upon the changed module
must be inspected,
compiled, tested, and
redeployed.
Moreover, the transitive
closure of modules that
depend upon a changed
module must be recompiled,
re-tested, and redeployed.
1
2
3
4
7
5
6
That transitive closure can
be as high as O(n); And
since there are n such
closures in the system…
6
Dilution of Productivity
At the knee of the curve
more effort is applied to
coupling than adding
features.
The effort expended to
add new features drives
the complexity upwards
and drives the productivity
downwards.
7
Productivity vs Module Count
Effort applie d to ne w fe ature s
As the application size
grows, more and more
effort is applied to dealing
with coupled modules.
100
90
80
70
60
50
40
30
20
10
0
Number of Modules
Project effort increases
geometrically with project size. …
Project size increases
Exponentially with time.
8
Other costs of a highly coupled
architecture
Geometrically increasing compile
time.
Geometrically increasing unit test
time.
Componentization is infeasible.
Making footprint and load-time issues
unmanageable.
9
Barrier to Components
As footprint and load time grows, the desire to break the
software into individual components -- that can be
independently built, tested, and deployed -- increases.
However, componentization depends critically upon being
able to create subsystems that are independent. So long as
coupling is high, and dependency cycles are rampant,
componentization will be infeasible.
1
1
2
2
3
3
4
4
5
6
7
7
5
10
6
?
Faulty Architecture:
Dependency Cycles
A single cyclic dependency in an otherwise
acyclic structure can dramatically increase
coupling.
Note that the red dependency forces module six to depend
upon every other module in the system.
1
2
4
3
5
6
7
Such dependencies have a tendency to creep in over time
as the system is being maintained and enhanced.
Especially during schedule crunches.
11
The Solution
Create a software architecture with
well managed interdependencies.
12
Flattening the Geometric Curve
Coupling need not increase as O(n2).
Tree structures have no cycles and reduced
coupling to O(nlog n);
Productivity decreases with the log, not the
square, of the number of modules.
1
2
1
3
2
4
4
5
13
3
7
6
5
6
7
Productivity Recaptured
O(n**2)
Productivity vs Module Count
Percent Productivity
O(nlog n)
1
100
90
80
70
60
50
40
30
20
10
0
2
4
3
5
6
7
1
2
3
4
6
256
506
756
1006
1256
1506
1756
2006
7
5
6
Number of Modules
time
14
See: Large Scale C++
Software Design
by John Lakos.
Principles of Object Oriented
Component Design
What is a component?
Components on Class Diagrams
The Triad of Component Principles
REP: The Reuse/Release Equivalency
Principle
CCP: The Common Closure Principle
CRP: The Common Reuse Principle
15
Intro to Components
“…the class is a necessary but insufficient vehicle for decomposition.”
-- Grady Booch
Large systems of objects and classes
would be overwhelming
We have lots of small and simple
classes
A way must exist to deal with
groups of classes
Otherwise, it’s almost like
building a sand castle from
individual grains of sand
16
What is a component
The “Simple” Answer
A group of classes.
Some of the classes are
public.
Some of the classes are
private.
17
A C++ “Namespace”.
A Java “Package”.
A DLL.
Components on Class Diagrams
Drawn as rectangle with a smaller rectangle above it.
They can be drawn large with icons of classes and their
interrelationships within them.
Then the name should be in the “tab”.
Also drawn as rectangle with two small rectangles on
left.
Geometry
18
Looks like a file folder
Package Relationships
Packages do not stand alone and must interact with other packages
We will discuss two relationships
between components
Dependency
Realizes
19
Dependency Structure
Control
Panel
Dependency structure of a n
automated parking garage.
Transport
Conveyor
Elevator
Alarm
20
Revenue
Database
Realizes
Components may be composed of abstract classes.Other packages may
provide implementations for the abstract classes.
«interface»
Package
This is drawn as a dashed line (like
dependency) with an open, triangular
arrowhead (like inheritance).
The relationship is officially known as
“realizes”, but means that the concrete
package implements the abstract
package’s interface(s).
Concrete
Package
21
This is another kind of dependency.
Component Cohesion Principles
REP
CCP
CRP
22
Reuse-release Equivalency Principle
Common Closure Principle
Common Reuse Principle
(REP) The Reuse/Release
Equivalency Principle
The granule of reuse is the granule of release
What do you expect from a
supplier of reusable modules?
23
Expectations
Documentation.
Accuracy.
Maintenance.
You expect the supplier to maintain the
modules that you are reusing.
Predictability.
24
You expect that the module will not change
out from under you.
That you will be notified in advance of any
changes
That you will be given the option to use the
old version.
Reusers Expect Release
Control
Version numbers and release tracking.
In order to get users to agree to reuse a
module:
You must bind the reusable classes
together into components.
Each component need to be tracked in a
release system.
Each component needs release numbers.
Each release needs release notes.
Users must be able to continue to use the
older versions for a while.
25
Thus, the granule of reuse is the granule
of release.
The granule of reuse is the
granule of release.
This principle deals with a kind of cohesion.
Single classes are seldom reusable
They typically depend on other
classes.
They are not typically released alone.
There are ramifications for component
design
The classes in a component should
form both a releasable and a reusable
module.
26
REP Review
REP: Group for
reusers
What is the REP?
Are reuse groupings coincidental?
Is it primarily concerned with coupling or
cohesion?
How does this differ from more traditional
ways of grouping components?
27
(CCP) The Common Closure Principle
Minimize the impact of change
Given an application to which
changes need to be made:
Do we want to change many
components?
Or as few as possible?
28
Scaling up the OCP
The open closed principle states that a class
should be “open for extension but closed for
modification.”
This cannot be completely achieved.
Thus, we design our classes to be closed to the
most likely kinds of changes that we can foresee.
That important class design consideration is also
an important component design consideration.
29
Cohesion of Closure
Given a particular kind of change, either all of the classes
within a package are closed to it, or they are all open to it.
Classes within a component should be closed
together.
A component is cohesive if the classes within
it are all closed to the same kinds of
modifications.
When this principle can be achieved, changes
do not propagate through the system.
30
Non-Propagation of Changes
Changes focus upon one, or a very few
packages.
The rest of the packages remain
unaffected.
This greatly lessens the number of
packages that are affected by a change,
and reduces the frequency with which
components must be released.
31
CCP and REP
REP: Group for
reusers
CCP: Group for
maintenance
Sometimes these principles are in complete
harmony
The best of times
Other times the two groupings may conflict
somewhat.
You can choose one to lean toward
How much maintenance is expected?
32
CCP Review
What does the CCP tell us to do?
Why is this a good idea?
How is the CCP different from the REP?
Do the CCP and REP direct us more
toward broad horizontal (technical)
partitioning, or vertical (functional)
partitioning?
33
(CRP) The Common Reuse Principle
Classes within a component should be
reused together
Reuse creates a dependency upon the
whole reused component.
Reusable components are generally made
of many collaborating classes.
34
Reusers Depend on the Whole
Component
When a new release of that component is
created, the reuser must reintroduce it into
existing applications.
There is a cost for this
And a risk
Therefore, the user will want each component to
be as focused as possible.
If the component contains classes which the user
does not make use of, then the user may be
placed in the position of accepting the burden of a
new release which does not affect any of the
classes within the component that he is using.
35
Common Reuse Principle
Given simply, the user should depend on the whole package.
This is a scaled up version of Interface Segregation.
This is a principle that breaks up
components.
You will end up with some small, focused
components.
You’ll end up with some loose classes.
Loose classes may be grouped with REP and
CCP into more cohesive groups.
Volatility should be considered.
36
Reusable Components Have
Many Collaborating Classes
The relationships between those classes
bind them together
Placing them in separate components will
create dependencies between those
components.
37
Conflict in the Triad
Will receive unneeded releases.
Where in this space does
your package fall?
CRP: Split to avoid
unneeded releases
38
CRP Review
39
What does the CRP tell us to do in
component design?
How is it different from the REP?
How is it different from the CCP?
Could you draw the triad, and label the
corners?
Place a well-known library or component in
the triangular space, showing how the
tradeoffs were made.
Package Cohesion Principles
Summary
REP
CCP
CRP
40
Group for convenience of (re)users
Group for convenience of maintainers
Split to prevent dependencies on partial
packages
Principles of Component Coupling
The larger the project, the more critical it is to
manage the relationships between components
(ADP) The Acyclic Dependencies Principle.
(SDP) The Stable Dependencies Principle.
(SAP) The Stable Abstractions Principle.
Metrics: Management vs. random walks.
Packages and Directory Structures.
Source code configuration systems.
41
(ADP) The Acyclic Dependencies
Principle
The dependency structure for components must be a DAG.
Applications must be stabilized and
released in pieces.
Otherwise, the developers interfere with
each other: The “Morning After” Syndrome.
By carefully structuring components, the
problem is avoided.
42
The “Morning After” Syndrome
You work till 5PM getting something working.
But when you come back the next day…
Your stuff doesn't work.
Somebody stayed later than you did…
… or came in earlier
And this repeats, day after day after day…
The engineers on a project step all over each other.
Time to stabilize a release is unpredictable.
43
Dependency Structures
Changes are rippling through the system in several directions!
The problem may be
that the dependency
structure of the project
is poor, is not
understood or is not
respected.
44
You
Your
Coworker
Well structured packages prevent this
problem
Components can be released.
Users that aren’t ready for the release can
continue to use the old versions.
The developers can continue to modify
components without affecting the users.
Components are stabilized and then
released internally
Changes flow in one direction only
Dependency Cycles ruin this scheme.
45
Well Structured Packages
Prevents This Problem
Control
Panel
Revenue
Transport
Elevator
Conveyor
Database
Alarm
46
How do package structure
problems occur?
In the garage system (prev page), we have a
sane structure.
We can stabilize and plan in a rational way.
Now there is a change:
When there is a problem, we just rang an alarm
Now we realize we need to display a message
The ‘alarm’ programmers aren’t aware of the
DAG...
47
Dependency Cycles Ruin This Scheme
Control
Panel
Transport
The resulting structure is
no longer a DAG.
Revenue
Database
Conveyor
Alarm
48
Elevator
Breaking the Cycle
Control
Panel
Transport
Revenue
Database
Conveyor
Display
Elevator
Alarm
It’s once again a DAG. Structure and sanity
return to our little world.
49
Cycles can also be broken by adding
abstraction
Imposing an abstract class can invert a dependency
A
C
B
A
C
B
50
Abstract
B
Stable Dependencies Principle
A component should only depend upon
others that are more stable than itself
Stability is a measure of the difficulty in
changing a component
What makes a component hard to
change?
51
Stable Dependencies Principle
A Component with many dependents
is “Responsible”
Responsibility implies stability.
A
Not free to change
Irresponsibility implies instability.
Free to change
A Component that depends on
many others is “Dependent”.
Independence implies stability.
Dependence implies instability.
52
A
Stable Dependencies Principle
Depending in the direction of
INstability
This is a bad thing
Component A depends in a
direction of INstability. B is
free to change. When B
changes, changes can
ripple up to A.
Since A is not free to
change, this will create a
problem.
We wish to depend in the
direction of Stability
53
A
B
Stable Dependencies Principle
Here, A is irresponsible and very
dependent. B is responsible and
independent.
A
In this case, A is free to change on its
own, and nothing in the system is
impacted by the change.
B is stable, and so it’s undesirable to
change it.
This is a healthy structure.
54
B
Stable Dependencies Principle
Stability can be measured
Define I. Instability metric
I = Ce / ( Ca + Ce)
Ce = Efferent
couplings
Ca = Afferent couplings
I=1
I=1
I=0
55
I = 1 / ( 3 + 1 ) = 0.25
Stable Abstractions Principle
The abstraction of a package should be in
proportion to its stability
If all packages are maximally stable, the
system would be unchangable
Some packages should be stable
Those that encapsulate high-level policy
These packages should be abstract
Some packages should be instable
Those that encapsulate low-level
implementation details
56
Stable Abstractions Principle
• Abstractness of a package can be measured
A = Na / N
Na = number of abstract classes
N = total number of classes
57
Analyzing Metrics
(0,1)
A
Main Sequence
I
(1,0)
Packages have degrees of abstraction
versus stability
Packages along the line from (0,1) to (1,0)
have a good balance
58
Analyzing Metrics
Zone of uselessness
(0,1)
A
Main Sequence
Zone of pain
I
(1,0)
Abstractions without dependents are
useless.
Concretions with lots of dependents are
painful.
e.g. database schemae
59
Main Sequence
(cont.)
A
n
ai
M
ce
en
qu
Se
D
I
• Distance from Main Sequence (normalized)
D=|A+I -1|
• Design can be analyzed for conformance to
main sequence
60
Tools that Calculate the Metrics
Smallworlds
Headway
Jdepend www.clarkware.com
Depend.sh www.objectmentor.com
61
Component and Directory Structures
Our convention at Object Mentor, Inc.
Each component is represented by a directory.
All the .cc and.h files are placed in that directory.
A library file (.a) is generated for that directory.
Any documentation files should be included too
Make file.
The directory structure is generally flat.
Nested packages are not impossible, but are rare.
#include
Written as # include “package/file.h”
62