The Good the Bad and the Ugly of
Dealing with Smelly Code
Dr. Radu Marinescu
radum@intooitus.com
IT.A.K.E - May 30, 2013
I, me and myself...
my two hats...
the academic one
Full Professor. PhD Advisor
software engineering
since 2013
software maintenance. quality assurance
Co-founder. Head
since 2003
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005 ECOOP 1998 WCRE 2005WCRE 2004 SYNASC 2005
500+
citations
in mainstream
publications
Michele Lanza
Radu Marinescu
Object-Oriented
Metrics
in Practice
Using Software Metrics to
Characterize, Evaluate, and Improve
the Design of Object-Oriented Systems
Foreword by Stéphane Ducasse
Lanza·Marinescu
Object-Oriented
MetricsinPractice
tant Professor at the University of Lugano, Switzer-
rests lie in software (re)engineering and software evo-
n software visualization and metrics. He is the creator
ailable language-independent software visualization
e Ernst Denert Software Engineering Award in 2003.
istant Professor at the Politehnica University of
earch focus is on object-oriented design, reenginee-
He is the author of a suite of novel object-oriented
or of iPlasma, an integrated and freely available tool-
. Several of his published research ideas have already
own “Borland Together Control Center” CASE tool.
ented Metrics in
very engineering discipline. However, due to its lack
mplexity, software engineering is not considered a
y. Moreover, defining, understanding and applying
s like an overly complex activity, recommended only
general, if a software system is delivering the
few people – if any – care about measuring the qua-
Consequently, software metrics are still regarded
st software developers.
stify the design metrics used to assess the size,
bject-oriented software systems. Based on a novel
ally accepted semantics for metrics and by statistical
ustrial projects, they deduce a suite of metrics-based
esign of object-oriented software systems. They
fy design disharmonies in code, and how to devise
cally sound results and practically tested procedu-
es this book an ideal companion for professional
pers and quality engineers. The pattern-oriented des-
ers easy access to detecting shortcomings and
oblems.
ect-oriented
*many reengineering strategies
for poorly structured code
*brief introduction to software
visualization
‘’This well-written book is an impor-
tant piece of work that takes the
seemingly forgotten art of object-
oriented metrics to the next level in
terms of relevance and usefulness.’
Richard C. Gronback,
Chief Scientist, Borland Software
Corporation
1 3
1
Michele Lanza
Radu Marinescu
Object-Oriented
Metrics
in Practice
Using Software Metrics to
Characterize, Evaluate, and Improve
the Design of Object-Oriented Systems
Foreword by Stéphane Ducasse
Lanza·Marinescu
Object-Oriented
MetricsinPractice
tant Professor at the University of Lugano, Switzer-
rests lie in software (re)engineering and software evo-
n software visualization and metrics. He is the creator
ailable language-independent software visualization
e Ernst Denert Software Engineering Award in 2003.
istant Professor at the Politehnica University of
earch focus is on object-oriented design, reenginee-
He is the author of a suite of novel object-oriented
or of iPlasma, an integrated and freely available tool-
. Several of his published research ideas have already
own “Borland Together Control Center” CASE tool.
ented Metrics in
very engineering discipline. However, due to its lack
mplexity, software engineering is not considered a
y. Moreover, defining, understanding and applying
s like an overly complex activity, recommended only
general, if a software system is delivering the
few people – if any – care about measuring the qua-
Consequently, software metrics are still regarded
st software developers.
stify the design metrics used to assess the size,
bject-oriented software systems. Based on a novel
ally accepted semantics for metrics and by statistical
ustrial projects, they deduce a suite of metrics-based
esign of object-oriented software systems. They
fy design disharmonies in code, and how to devise
cally sound results and practically tested procedu-
es this book an ideal companion for professional
pers and quality engineers. The pattern-oriented des-
ers easy access to detecting shortcomings and
oblems.
ect-oriented
*many reengineering strategies
for poorly structured code
*brief introduction to software
visualization
‘’This well-written book is an impor-
tant piece of work that takes the
seemingly forgotten art of object-
oriented metrics to the next level in
terms of relevance and usefulness.’
Richard C. Gronback,
Chief Scientist, Borland Software
Corporation
1 3
1
1000+reprinted2010
Innovation Award 2006
2006
Continuous detection of design problems
“...have done the most to improve programmer productivity ...”
IBM
2009
“...have done the most to improve programmer productivity ...”
IBM
jury included
Grady Booch, Erich Gamma,
Fred Brooks, Frances Allen
2009
WorkingConferenceon
Reverse Engineering
InternationalConferenceon
Program Comprehension
ConferenceonSoftware
Maintenance & Re-Engineering
International Conference on Software Maintenance
2010
General Chair
T.J. Watson Research
Invited Talks
Consultancy & Trainings
my entrepreneurial hat
Co-Founder
www.intooitus.com
Dr. Radu MarinescuDr. Adrian Trifu Dr. Mircea Trifu George Ganea Ioana Verebi
Dr. Radu MarinescuDr. Adrian Trifu Dr. Mircea Trifu George Ganea Ioana Verebi
...uniquely innovative tools, and project-specific consultancy
to support complex quality assessment tasks
in large-scale software systems
inFusion
control the architecture and design quality of your system!
http://www.intooitus.com/products/infusion
inFusion
inFusion
1+ Billion LOC total
inFusion
1+ Billion LOC total
10.000+ users
inFusion
1+ Billion LOC total
10.000+ users
your daily companion for code and design quality
http://www.intooitus.com/products/incode
inCode
your daily companion for code and design quality
http://www.intooitus.com/products/incode
inCode
New version
launched yesterday!
Setting the stage ...
1946
1951
1951
1951
1951 2013
1951 2013
?1951 2013
Software is complex
Software is complex.
The Standish Group, 2004
53% Challenged
18% Failed
29% Succeeded
}
{
}
{
}
{
}
{
}
{
How complexis your project?
1’000’000 lines of code
1’000’000 lines of code
* 3 = 3’000’000 seconds
1’000’000 lines of code
* 3 = 3’000’000 seconds
/ 3600 = 833 hours
1’000’000 lines of code
* 3 = 3’000’000 seconds
/ 3600 = 833 hours
/ 8 = 104 days
1’000’000 lines of code
* 3 = 3’000’000 seconds
/ 3600 = 833 hours
/ 8 = 104 days
/ 22 = 4.5 months
But, code is for the computer.
Why would we ever read it?
forward
engineering
}
{
}
{
}
{
}
{
forward
engineering
actual development }
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
forward
engineering
actual development }
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
forward
engineering
actual development }
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
The only real documentation:
the code!
Ward Cunningham, 1992
technical debt.
When, due to constraints,
I design quickly and dirty,
my project gets loaded with
Ward Cunningham, 1992
technical debt.
?How can I controlthis...
You cannot control
what you cannot measure.
Tom de Marco
1Measure
design
2Assess
design
3Improve
design
1Measure design
Software metrics are measurements which
relate to software systems, processes or
related documents.
Metrics compress system traits into numbers.
Let’s see some examples...
Lorenz, Kidd, 1994
Chidamber, Kemerer, 1994
Lorenz, Kidd, 1994
Chidamber, Kemerer, 1994
LOC - number of lines of code
CYCLO - cyclomatic complexity of a function
NOF - number of functions
FANOUT - outgoing coupling
NOA - number of attributes
DIT - depth of inheritance tree
TCC - tight class cohesion
Lorenz, Kidd, 1994
Chidamber, Kemerer, 1994
LOC - number of lines of code
CYCLO - cyclomatic complexity of a function
NOF - number of functions
FANOUT - outgoing coupling
...
Examples of metric tools
Trouble in paradise...
Thresholds
What about software metrics?
Metric Value
LOC (lines of code) 8.000
Would you maintain this system ?
Metric Value
LOC (lines of code) 8.000
Would you maintain this system ?
NOF (functions) 2
Metric Value
LOC (lines of code) 8.000
Would you maintain this system ?
NOF (functions) 2
Changed your mind, right? ;-)
Metric Value
LOC 35175
NOM 3618
NOC 384
CYCLO 5579
NOP 19
FANOUT 8590
Metric Value
LOC 35175
NOM 3618
NOC 384
CYCLO 5579
NOP 19
FANOUT 8590
?
Are these numbers “normal” ?
We need means to compare.
We need comparable metrics.
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Size
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Size Communication
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Size Communication
Inheritance
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Size
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
More numbers?!?
...
HIGH
0.30
16
15
10
9
0.25
AVG
C++
4
5
0.20
LOW
Java
AVGLOW HIGH
0.24
10
13
7
0.20
10
0.16
7
4NOM/NOC
LOC/NOM
CYCLO/LOC
...
HIGH
0.30
16
15
10
9
0.25
AVG
C++
4
5
0.20
LOW
Java
AVGLOW HIGH
0.24
10
13
7
0.20
10
0.16
7
4NOM/NOC
LOC/NOM
CYCLO/LOC
4.000+OSS projects
500.000.000+LOC
...
HIGH
0.30
16
15
10
9
0.25
AVG
C++
4
5
0.20
LOW
Java
AVGLOW HIGH
0.24
10
13
7
0.20
10
0.16
7
4NOM/NOC
LOC/NOM
CYCLO/LOC
4.000+OSS projects
500.000.000+LOC
...and counting...
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Overview Pyramid provides a system’s overview.
Marinescu, Lanza
0.31ANDC
NOM
20.21 19
0.12
35175
NOP
NOC
418
0.15
8590
LOC
3618
9.42
5579
NOM
CALLS15128
384
FANOUT
9.72
0.56
AHH
CYCLO
Overview Pyramid provides a system’s overview.
close to high close to average close to low
Marinescu, Lanza
Overview Pyramid provides a system’s overview.
close to high close to average close to low
Marinescu, Lanza
But why do we measure?
We measure to control quality!
We measure to detect abnormalities!
1Measure
design
2Assess
design
3Improve
design
2Assess design
Imagine changing just a small design fragment
33%of all the classes
would require changes
Imagine changing just a small design fragment
Breaking design principles, rules and best practices
deteriorates the code;
it leads to design problems.
Are these bugs?
NO!
but...
Foutse et. al. - An exploratory study of the impact of anti-patterns on class change- and fault-proneness, 2012
Foutse et. al. - An exploratory study of the impact of anti-patterns on class change- and fault-proneness, 2012
Classes participating in design problems are
significantly more likely to be subject to changes and
to be involved in fault-fixing changes (bugs)
“
”
God
Class
Brain
Class
Feature
Envy
Data
Class
Brain
Method
Significant
Duplication
Intensive
Coupling
Dispersed
Coupling
Shotgun
Surgery
Tradition
Breaker
Refused
Parent
Bequest
uses
has
is
has
has
has (partial)
is partially
has
is
is
has
Futile
Hierarchy
uses
has
has
is
has (subclass)
Riel, 1996
Brown, 1998
Fowler, 1999
Marinescu, 2004
Design Problems (anti-patterns)
How to detect design problems?
Use metrics!
Granularity of metrics
Metrics must be aggregated
Treat design problems as first-class entities
Let’s see an example...
God Classes tend to centralize the intelligence of the
system, to do everything and to use data from small
data-classes.
A.Riel, 1996
God Classes tend
to centralize the intelligence of the system,
to do everything and
to use data from small data-classes.
God Classes
centralize the intelligence of the system,
do everything and
use data from small data-classes.
God Classes
are complex,
are not cohesive,
access external data.
God Classes
are complex,
are not cohesive,
access external data.
Compose metrics into queries using
logical operators
Detection Strategies are metric-based queries to
detect design flaws.
METRIC 1 > Threshold 1
Rule 1
METRIC 2 < Threshold 2
Rule 2
AND Quality problem
Marinescu
A God Class centralizes too much intelligence in
the system.
ATFD > FEW
Class uses directly more than a
few attributes of other classes
WMC ≥ VERY HIGH
Functional complexity of the
class is very high
TCC < ONE THIRD
Class cohesion is low
AND GodClass
Marinescu
Envious Methods are more interested in data from
a handful of classes.
ATFD > FEW
Method uses directly more than
a few attributes of other classes
LAA < ONE THIRD
Method uses far more attributes
of other classes than its own
FDP ≤ FEW
The used "foreign" attributes
belong to very few other classes
AND Feature Envy
Marinescu, Lanza
Data Classes are dumb data holders.
WOC < ONE THIRD
Interface of class reveals data
rather than offering services
AND Data Class
Class reveals many attributes and is
not complex
Lanza, Marinescu 2006
Data Classes are dumb data holders.
AND
OR
Class reveals many
attributes and is not
complex
NOAP + NOAM > FEW
More than a few public
data
WMC < HIGH
Complexity of class is not
high
NOAP + NOAM > MANY
Class has many public
data
WMC < VERY HIGH
Complexity of class is not
very high
AND
Lanza, Marinescu 2006
20+ Detection strategies
for design flaws on class, method and subsystem level
!Demo time
inCode
?Does anyone care design flaws
Time can tell
63releases of Eclipse JDT and EMF
2
previous
release
9
current
release
7 3
3
6
5
Decaying
Class
Refactored
Class
NewFlawed
Class
2
previous
release
9
current
release
7 3
3
6
5
Decaying
Class
Refactored
Class
NewFlawed
Class
2
previous
release
9
current
release
7 3
3
6
5
Decaying
Class
Refactored
Class
NewFlawed
Class
2
previous
release
9
current
release
7 3
3
6
5
Decaying
Class
Refactored
Class
NewFlawed
Class
2
previous
release
9
current
release
7 3
3
6
5
Decaying
Class
Refactored
Class
NewFlawed
Class
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
JDT EMF
God
Class
Schizophrenic
Class
Refused
Parent
Bequest
Code
Duplication
Blob
Operation
Data
Clumps
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
JDT EMF
God
Class
Schizophrenic
Class
Refused
Parent
Bequest
Code
Duplication
Blob
Operation
Data
Clumps different
patterns
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
JDT EMF
God
Class
Schizophrenic
Class
Refused
Parent
Bequest
Code
Duplication
Blob
Operation
Data
Clumps
only
flawed
by birth
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
JDT EMF
God
Class
Schizophrenic
Class
Refused
Parent
Bequest
Code
Duplication
Blob
Operation
Data
Clumps
strong
reaction
to debt
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
1.1 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
0
2
4
6
8
10
2 2.1 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7
JDT EMF
God
Class
Schizophrenic
Class
Refused
Parent
Bequest
Code
Duplication
Blob
Operation
Data
Clumps
only
pay-back
1Measure
design
2Assess
design
3Improve
design
3Improve design
Let’s start with a simple example...
public class TarHeader{
/**
	 * The entry's name.
	 */
	 public StringBuffer name;
	 /**
	 * The entry's permission mode.
	 */
	 public int	mode;
	 /**
	 * The entry's user id.
	 */
	 public int	userId;
	 /**
	 * The entry's group id.
	 */
	 public int	groupId;
}
public class TarHeader{
/**
	 * The entry's name.
	 */
	 	 	 	 StringBuffer name;
	 /**
	 * The entry's permission mode.
	 */
	 	 	 	 int	 mode;
	 /**
	 * The entry's user id.
	 */
	 	 	 	 int	 userId;
	 /**
	 * The entry's group id.
	 */
	 	 	 	 int	 groupId;
}
public
public
public
public
public class TarHeader{
/**
	 * The entry's name.
	 */
	 	 	 	 StringBuffer name;
	 /**
	 * The entry's permission mode.
	 */
	 	 	 	 int	 mode;
	 /**
	 * The entry's user id.
	 */
	 	 	 	 int	 userId;
	 /**
	 * The entry's group id.
	 */
	 	 	 	 int	 groupId;
}
public
public
public
public
DATA
CLASS
public class TarHeader{
/**
	 * The entry's name.
	 */
	 	 	 	 StringBuffer name;
	 /**
	 * The entry's permission mode.
	 */
	 	 	 	 int	 mode;
	 /**
	 * The entry's user id.
	 */
	 	 	 	 int	 userId;
	 /**
	 * The entry's group id.
	 */
	 	 	 	 int	 groupId;
}
public class TarHeader{
/**
	 * The entry's name.
	 */
	 	 	 	 StringBuffer name;
	 /**
	 * The entry's permission mode.
	 */
	 	 	 	 int	 mode;
	 /**
	 * The entry's user id.
	 */
	 	 	 	 int	 userId;
	 /**
	 * The entry's group id.
	 */
	 	 	 	 int	 groupId;
}
private
private
private
private
public class TarHeader{
/**
	 * The entry's name.
	 */
	 	 	 	 StringBuffer name;
	 /**
	 * The entry's permission mode.
	 */
	 	 	 	 int	 mode;
	 /**
	 * The entry's user id.
	 */
	 	 	 	 int	 userId;
	 /**
	 * The entry's group id.
	 */
	 	 	 	 int	 groupId;
}
private
private
private
private
Encapsulate public data
(in TarHeader)1
but ...
Suddenly we have compile errors!
public class {
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 	 int offset = 0;
	 	 hdr.name = TarHeader.parseName( header, offset,
TarHeader.NAMELEN );
	 	 offset += TarHeader.NAMELEN;
	 	 hdr.mode = (int)TarHeader.parseOctal( header, offset,
TarHeader.MODELEN );
	 	 offset += TarHeader.MODELEN;
	 	 hdr.userId = (int)TarHeader.parseOctal( header, offset,
TarHeader.UIDLEN );
	 	 offset += TarHeader.UIDLEN;
	 	 hdr.groupId = (int)TarHeader.parseOctal( header, offset,
TarHeader.GIDLEN );
}
TarEntry
public class {
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 	 int offset = 0;
	 	 hdr.name = TarHeader.parseName( header, offset,
TarHeader.NAMELEN );
	 	 offset += TarHeader.NAMELEN;
	 	 hdr.mode = (int)TarHeader.parseOctal( header, offset,
TarHeader.MODELEN );
	 	 offset += TarHeader.MODELEN;
	 	 hdr.userId = (int)TarHeader.parseOctal( header, offset,
TarHeader.UIDLEN );
	 	 offset += TarHeader.UIDLEN;
	 	 hdr.groupId = (int)TarHeader.parseOctal( header, offset,
TarHeader.GIDLEN );
}
TarEntry
TarHeader hdr
hdr.name
hdr.mode
hdr.userId
hdr.groupId
parseTarHeader
public class {
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 	 int offset = 0;
	 	 hdr.name = TarHeader.parseName( header, offset,
TarHeader.NAMELEN );
	 	 offset += TarHeader.NAMELEN;
	 	 hdr.mode = (int)TarHeader.parseOctal( header, offset,
TarHeader.MODELEN );
	 	 offset += TarHeader.MODELEN;
	 	 hdr.userId = (int)TarHeader.parseOctal( header, offset,
TarHeader.UIDLEN );
	 	 offset += TarHeader.UIDLEN;
	 	 hdr.groupId = (int)TarHeader.parseOctal( header, offset,
TarHeader.GIDLEN );
}
TarEntry
TarHeader hdr
hdr.name
hdr.mode
hdr.userId
hdr.groupId
parseTarHeader
Move the method
(TarEntry > TarHeader)1
public class {
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 	 int offset = 0;
	 	 hdr.name = TarHeader.parseName( header, offset,
TarHeader.NAMELEN );
	 	 offset += TarHeader.NAMELEN;
	 	 hdr.mode = (int)TarHeader.parseOctal( header, offset,
TarHeader.MODELEN );
	 	 offset += TarHeader.MODELEN;
	 	 hdr.userId = (int)TarHeader.parseOctal( header, offset,
TarHeader.UIDLEN );
	 	 offset += TarHeader.UIDLEN;
	 	 hdr.groupId = (int)TarHeader.parseOctal( header, offset,
TarHeader.GIDLEN );
}
TarEntry
TarHeader hdr
hdr.name
hdr.mode
hdr.userId
hdr.groupId
parseTarHeader
Encapsulate public data
(in TarHeader)2
Move the method
(TarEntry > TarHeader)1
but ...
public class TarEntry{
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 int offset = 0;
	 hdr.name = TarHeader.parseName(
	 	 	 	 	 header, offset, TarHeader.NAMELEN );
	
	 offset += TarHeader.NAMELEN;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 offset += TarHeader.UIDLEN;
	 hdr.groupId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.GIDLEN );
}
public void writeEntryHeader(byte[] outbuf){
	 int offset = 0;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 long size = this.header.size;
	 offset = TarHeader.getLongOctalBytes
	 	 ( size, outbuf, offset, TarHeader.SIZELEN );
}
hdr.mode = (int)TarHeader.parseOctal( header,
hdr.mode = (int)TarHeader.parseOctal( header,
offset, TarHeader.MODELEN );
offset, TarHeader.MODELEN );
offset += TarHeader.MODELEN;
offset += TarHeader.MODELEN;
hdr.userId = (int)TarHeader.parseOctal( header,
hdr.userId = (int)TarHeader.parseOctal( header,
offset, TarHeader.UIDLEN );
offset, TarHeader.UIDLEN );
parseTarHeader
writeEntryHeader
public class TarEntry{
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 int offset = 0;
	 hdr.name = TarHeader.parseName(
	 	 	 	 	 header, offset, TarHeader.NAMELEN );
	
	 offset += TarHeader.NAMELEN;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 offset += TarHeader.UIDLEN;
	 hdr.groupId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.GIDLEN );
}
public void writeEntryHeader(byte[] outbuf){
	 int offset = 0;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 long size = this.header.size;
	 offset = TarHeader.getLongOctalBytes
	 	 ( size, outbuf, offset, TarHeader.SIZELEN );
}
hdr.mode = (int)TarHeader.parseOctal( header,
hdr.mode = (int)TarHeader.parseOctal( header,
offset, TarHeader.MODELEN );
offset, TarHeader.MODELEN );
offset += TarHeader.MODELEN;
offset += TarHeader.MODELEN;
hdr.userId = (int)TarHeader.parseOctal( header,
hdr.userId = (int)TarHeader.parseOctal( header,
offset, TarHeader.UIDLEN );
offset, TarHeader.UIDLEN );
parseTarHeader
writeEntryHeader
Duplicated
Code
public class TarEntry{
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 int offset = 0;
	 hdr.name = TarHeader.parseName(
	 	 	 	 	 header, offset, TarHeader.NAMELEN );
	
	 offset += TarHeader.NAMELEN;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 offset += TarHeader.UIDLEN;
	 hdr.groupId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.GIDLEN );
}
public void writeEntryHeader(byte[] outbuf){
	 int offset = 0;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 long size = this.header.size;
	 offset = TarHeader.getLongOctalBytes
	 	 ( size, outbuf, offset, TarHeader.SIZELEN );
}
hdr.mode = (int)TarHeader.parseOctal( header,
hdr.mode = (int)TarHeader.parseOctal( header,
offset, TarHeader.MODELEN );
offset, TarHeader.MODELEN );
offset += TarHeader.MODELEN;
offset += TarHeader.MODELEN;
hdr.userId = (int)TarHeader.parseOctal( header,
hdr.userId = (int)TarHeader.parseOctal( header,
offset, TarHeader.UIDLEN );
offset, TarHeader.UIDLEN );
parseTarHeader
writeEntryHeader
Extract method
(by factoring out the duplicated code)1
public class TarEntry{
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 int offset = 0;
	 hdr.name = TarHeader.parseName(
	 	 	 	 	 header, offset, TarHeader.NAMELEN );
	
	 offset += TarHeader.NAMELEN;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 offset += TarHeader.UIDLEN;
	 hdr.groupId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.GIDLEN );
}
public void writeEntryHeader(byte[] outbuf){
	 int offset = 0;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 long size = this.header.size;
	 offset = TarHeader.getLongOctalBytes
	 	 ( size, outbuf, offset, TarHeader.SIZELEN );
}
hdr.mode = (int)TarHeader.parseOctal( header,
hdr.mode = (int)TarHeader.parseOctal( header,
offset, TarHeader.MODELEN );
offset, TarHeader.MODELEN );
offset += TarHeader.MODELEN;
offset += TarHeader.MODELEN;
hdr.userId = (int)TarHeader.parseOctal( header,
hdr.userId = (int)TarHeader.parseOctal( header,
offset, TarHeader.UIDLEN );
offset, TarHeader.UIDLEN );
parseTarHeader
writeEntryHeader
Extract method
(by factoring out the duplicated code)1
Move the newly created method
(in TarHeader)2
public class TarEntry{
public void parseTarHeader( TarHeader hdr, byte[] header ){
	 int offset = 0;
	 hdr.name = TarHeader.parseName(
	 	 	 	 	 header, offset, TarHeader.NAMELEN );
	
	 offset += TarHeader.NAMELEN;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 offset += TarHeader.UIDLEN;
	 hdr.groupId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.GIDLEN );
}
public void writeEntryHeader(byte[] outbuf){
	 int offset = 0;
	 hdr.mode = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.MODELEN );
	 offset += TarHeader.MODELEN;
	 hdr.userId = (int)TarHeader.parseOctal( header,
	 	 	 	 	 offset, TarHeader.UIDLEN );
	 long size = this.header.size;
	 offset = TarHeader.getLongOctalBytes
	 	 ( size, outbuf, offset, TarHeader.SIZELEN );
}
hdr.mode = (int)TarHeader.parseOctal( header,
hdr.mode = (int)TarHeader.parseOctal( header,
offset, TarHeader.MODELEN );
offset, TarHeader.MODELEN );
offset += TarHeader.MODELEN;
offset += TarHeader.MODELEN;
hdr.userId = (int)TarHeader.parseOctal( header,
hdr.userId = (int)TarHeader.parseOctal( header,
offset, TarHeader.UIDLEN );
offset, TarHeader.UIDLEN );
parseTarHeader
writeEntryHeader
Extract method
(by factoring out the duplicated code)1
Move the newly created method
(in TarHeader)2
Encapsulate public data
(in TarHeader)3
there is also an alternative solution ...
Move data
(TarHeader > TarEntry)1
Move data
(TarHeader > TarEntry)1
Encapsulate public data
(in TarEntry)2
vs.
Extract method
(out of the duplicated code)1
Move the newly created method
(in TarHeader)2
Encapsulate public data
(in TarHeader)3
Move data
(TarHeader > TarEntry)1
Encapsulate public data
(in TarEntry)2
vs.
Which solution is best?
Extract method
(out of the duplicated code)1
Move the newly created method
(in TarHeader)2
Encapsulate public data
(in TarHeader)3
Move data
(TarHeader > TarEntry)1
Encapsulate public data
(in TarEntry)2
Only the engineer can
decide!
Three lessons...
Correction implies understanding the whole context
Contextual
1
Correction involves the decision of the engineer
Decisional
2
We need tools
Automated
3
We need multiple instruments
to explore...
!Demo time
inCode
There are many ways to explore...
...but the best way is....
to see
1854,
London,
cholera
epidemic
1854,
London,
cholera
epidemic
We are
visual
beings.
..and we’re good at
spotting patterns
Gestalt principles
proximity
enclosure connectivity
similarity
Preattentive
Processing
Let me demonstrate that!
In 7 seconds count numbers larger than 0.85!
0.103 0.176 0.387 0.300 0.829 0.276 0.179 0.321 0.192 0.250
0.333 0.384 0.864 0.587 0.857 0.698 0.640 0.621 0.984 0.316
0.421 0.309 0.654 0.729 0.228 0.529 0.832 0.435 0.699 0.426
1.266 0.750 0.056 0.936 0.711 0.749 0.723 0.201 0.542 0.819
0.225 0.926 0.643 0.337 0.721 0.337 0.682 0.987 0.232 0.449
0.187 0.586 0.529 0.340 0.276 0.835 0.473 0.445 1.103 0.720
1.153 0.485 0.560 0.428 0.628 0.335 0.456 0.879 0.699 0.424
What about now?
0.103 0.176 0.387 0.300 0.829 0.276 0.179 0.321 0.192 0.250
0.333 0.384 0.864 0.587 0.857 0.698 0.640 0.621 0.984 0.316
0.421 0.309 0.654 0.729 0.228 0.529 0.832 0.435 0.699 0.426
1.266 0.750 0.056 0.936 0.711 0.749 0.723 0.201 0.542 0.819
0.225 0.926 0.643 0.337 0.721 0.337 0.682 0.987 0.232 0.449
0.187 0.586 0.529 0.340 0.276 0.835 0.473 0.445 1.103 0.720
1.153 0.485 0.560 0.428 0.628 0.335 0.456 0.879 0.699 0.424
What about now?
0.103 0.176 0.387 0.300 0.829 0.276 0.179 0.321 0.192 0.250
0.333 0.384 0.864 0.587 0.857 0.698 0.640 0.621 0.984 0.316
0.421 0.309 0.654 0.729 0.228 0.529 0.832 0.435 0.699 0.426
1.266 0.750 0.056 0.936 0.711 0.749 0.723 0.201 0.542 0.819
0.225 0.926 0.643 0.337 0.721 0.337 0.682 0.987 0.232 0.449
0.187 0.586 0.529 0.340 0.276 0.835 0.473 0.445 1.103 0.720
1.153 0.485 0.560 0.428 0.628 0.335 0.456 0.879 0.699 0.424
Pre-attentive features!
Why use pictures in software?
Remember...
1’000’000 lines of code
* 3 = 3’000’000 seconds
/ 3600 = 833 hours
/ 8 = 104 days
/ 22 = 4.5 months
A picture is worth
a thousand words.
Proverb
Software visualization is more than UML!
PolymetricViews
PolymetricViews show up to 5 metrics.
Color
metric
Width metric
Height metric
Position metrics
Lanza, 2003
Example 1: System ComplexityView
System Complexity shows class hierarchies.
lines
attributes
methods
Lanza, Ducasse, 2003
Compresses 1.300 classes in one picture.
Compresses 1.300 classes in one picture.
Example 2: Code City
Code City shows where your code lives.
Wettel, Lanza, 2007
classes are buildings grouped in quarters of packages
Look carefully how the system evolves in time!
Look carefully how the system evolves in time!
Trouble in paradise...
Heterogeneity
They are simply too many...
Edges
They are simply too many...
Beyond polymetric views...
Polymetric Maps
Polymetric Maps
display various design concerns, but reuse the layout!
Polymetric Maps
display various design concerns, but reuse the layout!
...and no edges!
Example #1: Package Map
Remember this one?
Package Map: the layout
Eclipse-JDT, 2010
Package Map: design problems
Eclipse-JDT, 2010
severeno
affected by design problems
Package Map: coupling perspective
Eclipse-JDT, 2010
client (uses other classes)
provider (is used by other classes)
many
many
none
none
Eclipse-JDT, 2010
Package Map: coupling perspective
Eclipse-JDT, 2010
Interactive!
Package Map: coupling perspective
Example #2: Hierarchy Map
Multiple Inheritance ?
Multiple Inheritance ?
Interfaces?
Multiple Inheritance ?
Interfaces?
severeno
affected by design problems
client (uses other classes)
provider (is used by other classes)
many
many
none
none
11.000+ classes in one picture...
Java JDK 1.5, 2011
A picture is worth
a thousand words.
Proverb
A demo is worth
a thousand pictures.
Radu
!Demo time
inCode
inCode
intooitus.com/products/incode

The Good the Bad and the Ugly of Dealing with Smelly Code (ITAKE Unconference)