Part III Metrics and Tool Support
10.5 Constructing a Dependency Graph
11.3.3 Metric NCDC
Metric NCDC measures the size of the dependency cycles within a system.
Definition
For a system s, metric NCDC(s) is the total number of classes of s involved in dependency cycles:
Motivation and Purpose This metric can be used:
1 To characterize the size of the dependency cycles within a system.
2 To predict the effort caused by testing all classes involved in the dependency cycles at once (if the cycles aren’t broken with help of stubs) during integration testing.
Assumptions
Basic assumptions of the metric NCDC are:
1 The size and complexity of the classes within the depen- dency cycles does not matter.
2 Concrete classes, abstract classes, and interfaces within the dependency cycles have the same effect on testing.
Discussion
To the best knowledge of the author, no metrics have been pub- lished so far to characterize dependency cycles within a system. Metric NCDC is (like metric ACD) based on a very abstract view of the system and provides only a rough view of potential test problems caused by dependency cycles.
Properties of metric NCDC
name number of classes within dependency cycles
entity system
attribute size of dependency cycles category direct metric
scale type absolute scale
context System::NCDC() : Integer
134 Chapter 11: Metrics
11.3.4
Metric NFD
Metric NFD measures the number of dependencies causing dependency cycles within the system.
Definition
For a system s, metric NFD(s) is defined as the cardinality of the feedback dependency set for s:
Motivation and Purpose This metric can be used:
1 to characterize the number of dependencies causing depen- dency cycles, and
2 to predict the effort necessary to remove all dependency cycles by removing selected dependencies.
Assumptions
Basic assumptions of the metric NFD are:
1 The size and complexity of the classes involved in the feed- back dependencies does not matter.
2 The difficulty to remove a dependency to a concrete class, an abstract class, or an interface is the same.
3 it is not intended to remove inheritance or implements rela- tionships.
4 The strength of the feedback dependencies does not matter. Assumption 3 is considered by the heuristic algorithm used to identify feedback dependency sets (see Section 10.3.7).
Discussion
Feedback dependencies are identified based on a heuristic algorithm and may not be identical with the dependencies which actually introduced the dependency cycles. However, the size of
Properties of metric NFD
name number of feedback dependencies entity system
attribute number of dependencies causing dependency cycles category direct metric
scale type absolute scale
context System::NFD() : Integer
Chapter 11: Metrics 135
the feedback dependency set is a good indicator of the effort to remove the dependency cycles.
Related Metrics
Metric NSBC (Number of Stubs to Break Cycles) in [Jung02b] is similar to metric NFD, but measures the number of classes which have to be removed in order to break all dependency cycles.
11.4
Dependency Metrics
Hard-wired dependencies may have been introduced by acci- dent. Metrics DSTM and DSTMh help to identify such depen- dencies.
11.4.1
Metric DSTM
Metric DSTM measures the strength of a given dependency.
Definition
For a dependency d, metric DSTM(d) is defined as the number of distinct statements causing d.
Properties of metric DSTM
name number of statements causing the dependency entity dependency
attribute strength of dependency category direct metric
scale type absolute scale
context ClassDependency def
let isInheritanceDependency() : Boolean =
self.client.allSupertypes()->contains(self.supplier) context ClassDependency::DSTM() : Integer
post: if self.isInheritanceDependency() result =
self.typeDeclaration->size() + self.memberAccess->size() + 1 else result = self.typeDeclaration->size() +
136 Chapter 11: Metrics
Purpose
The metric is used to characterize the strength of the depen- dency.
Assumptions
Basic assumptions of metric DSTM are:
1 Multiple access of the same category from one method of a given client class to the same class member of a supplier class is counted only once (see Section 10.5).
2 Each type of access contributes the same to the strength of the dependency.
Discussion
Ad assumption 2: Weighting different access types differently would be an alternative. However, further research is required to quantify e.g. the effect of different access types on the average ease to refactor a dependency as a basis for defining actual weights.
11.4.2
Metric DSTMh
Metric DSTMh measures the proportion of statements which cause a dependency to be semi-hard-wired.
Properties of metric DSTMh
name percentage of statements causing a dependency to be semi-hard-wired
entity dependency
attribute proportion of statements which cause a dependency to be semi-hard-wired
category indirect metric
unit [%]
Chapter 11: Metrics 137
Definition
Fora dependency d,m etric D STM h(d)is defined as the num berofdis- tinctstatem ents causing d to be sem i-hard-w ired.
Note: An inheritance relationship contributes 1 to the value of metric DSTMh like any other statement causing a class dependency to be semi-hard-wired.
Purpose
The metric can be used for different purposes:
1 To characterize the degree to which the dependency is semi-hard-wired.
2 To predict the difficulty of refactoring a semi-hard-wired dependency into a type dependency.
Metric DSTMh can be also be used to characterize hard-wired dependencies as well, but this is not the main intention (see Section 8.5.2).
Assumptions
The basic assumptions of metric DSTMh are the same as for metric DSTM.
Discussion
The percentage of statements causing a dependency to be semi-hard-wired is not always sufficient to get a complete pic- ture:
context ClassDependency def
let isInheritanceDependency() : Boolean = self.client.Ancestors()->contains(self.supplier)
let numberHwStatementsWithoutInheritance() : Integer = self.memberAccess->select(causesHardwiring())->size() context ClassDependency::DSTMh() : Integer
post: if self.DSTM() = 0 result = 0
else if self.isInheritanceDependency() result =
(numberHwStatementsWithoutInheritance() + 1) / self.DSTM() else result = numberHwStatementsWithoutInheritance() /
138 Chapter 11: Metrics
Example 20
Dependency A is caused by 20 dependencies, 5 of them making the dependency semi-hard-wired. Dependency B is caused by 4 dependencies, only one making it semi-hard-wired. In both cases the value of DSTMh equals 0.25 but dependency B may be easier to be refactored into a type dependency because only on statement needs to be tackled.
A combination of the absolute number and relative number of statements causing a dependency to be semi-hard-wired there- fore provides more information to characterize the degree to which it is semi-hard-wired. However, the smallest values of DSTMh can be found within dependencies with a large value of DSTM:
The value of metric DSTMh is small, if the number of state- ments causing the dependency to be semi-hard-wired (the fraction’s numerator within the formula) is small and DSTM (the denominator) is large.
Therefore, we prefer the definition of metric DSTM as a relative number.
11.5
Reduction Metrics
Reduction metrics for dependencies are a new type of metrics which solve one shortcoming of existing coupling metrics: cou- pling metrics are class based. If the coupling value is to high, the developer is left alone with the task to identify the set of depen- dencies with the most negative impact on system structure.
11.5.1
Introduction
A reduction metric rM(d) for dependencies describes the degree to which the value of a metric M is reduced if a dependency d is removed from the system.
Note: metric values decrease when a dependency is removed in general.
A high value of a reduction metric for a given dependency means that the software characteristic is sensitive to the exist- ence of this dependency.
Chapter 11: Metrics 139
Related Metric Types
Change metrics Demeyer, Ducasse, and Nierstrasz use metrics called change
metrics to find refactorings [Deme00]. These metrics are calcu-
lated as the difference between system metric values of two dif- ferent system versions and are not linked to specific classes or class dependencies.
11.5.2
Metric rACD
Metric rACD measures the sensitivity of the number of indirect1 dependencies to the existence of a given dependency.
Definition
For a dependency d, metric rACD(d) is defined as a reduction metric based on metric ACD.
Motivation and Purpose
Metric rACD helps to identify metrics with a strong impact on the dependency structure.
Assumptions
The assumptions of metric rACD are:
1 The size and complexity of the classes does not matter. 2 Indirect dependencies do matter.
1 When removing any of the dependencies within a system, the overall number of direct dependencies is always reduced to the same amount, i.e. by 1. Therefore, metric rACD does only measure sensitivity concern- ing indirect dependencies.
Properties of metric rACD
name reduction metric based on metric ACD entity dependency
attribute effect on indirect dependencies category indirect metric
scale type rational scale
context ClassDependency::rACD() : Real post: if self.system.ACD() = 0 then result = 0
else result = 1 - self.system.removeDependency(self).ACD() / self.system.ACD()
140 Chapter 11: Metrics
3 The effect of indirect dependencies on the investigated attribute does not depend on the level of indirection.
4 Dependencies on concrete classes, abstract classes, and interfaces have the same effect on the investigated attribute. 5 The category of the dependency does not matter.
6 The dependencies can be removed without substitution. Discussion
Metric rACD only provides a rough evaluation of a dependency because it is based on simplifying assumptions. A more thor- ough evaluation of the effect of a given dependency on test tasks would require e.g. to consider the size and complexity of all classes during the calculation of the ACD values.
Ability to realize improvements
Possible improvements of system metrics, as indicated by the reduction metrics, can only be fully realized if the dependency can be removed without substitution (assumption 6).
Interpreting values of rACD
A high value of metric rACD is not bad per se: a well-designed system will always contain outstanding dependencies which e.g. connect subsystems and which therefore have a high rACD value. A high value of rACD only means, that it is worth to inves- tigate the related dependency closer because of possible large improvements to the dependency structure and testability if the dependency can and should be refactored.
Absolute versus relative metric definition
Note: whether metric ACD is defined as an absolute number (as in this work) or relative to the number of classes within the sys- tem does not have an effect on the metric rACD because the number of classes can be cancelled down in the formula of the reduction metric:
While the size of the system does not matter for reduction met- rics, a possible reduction of metric ACD by a particular value (e.g. 5%) may be more relevant in a larger system than in a smaller system.
Comparison with coupling metrics
Coupling metrics which take into account indirect coupling aren’t sensitive to dependency cycles (see Section 3.3.1) or to classes that play a pivotal role like hubs (see example below).
rA C D d C D D n --- C D D \{d} n --- --- C D D C D D \{d} --- = =
Chapter 11: Metrics 141
Example 21
Within the dependency graph shown in Figure 26, class
D
andF
play the role of a hub, i.e. a class which, when removed from the system, breaks the dependency graph into independent sub- graphs.
We compare metric rACD with metric CBOi, which is derived from metric CBO (see Appendix C) by taking into account indi- rect dependencies: while metric rACD clearly indicates that the dependency between
D
andF
is critical, metric CBOi is not able to highlight the critical classes.Figure 26 Dependency graph
Table 5 Dependencies and values of rACD
C F A H B D E G I dependency d CBOi of client class rACD(d) [%] Ao B 8 3.5 Ao C 3.5 Bo D 6 17.2 Bo E 0.0 Co D 6 20.7 Do E 5 6.9 Do F 55.2 Fo G 3 17.2 Fo H 0.0 Fo I 17.2 Go H 1 3.5
142 Chapter 11: Metrics