Files
codeql/java/ql/src/Metrics/Files/FEfferentCoupling.qhelp
2018-08-30 10:48:05 +01:00

86 lines
2.7 KiB
XML

<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
This metric measures the number of outgoing dependencies for each compilation
unit, i.e. the number of other units on which this compilation unit depends.
</p>
<p>
Compilation units that depend on many other units are typically subject to
more frequent recompilation, because they have to be recompiled every time one
of the many units on which they depend changes. It is particularly problematic
if such a compilation unit is also heavily depended on by other units, because
any minor change to one of its dependencies will trigger a ripple effect of
recompilation throughout the code: such units are known as hubs, and can be
responsible for greatly increasing the time needed for incremental
recompilation.
</p>
</overview>
<recommendation>
<p>
Unit-level efferent coupling can be reduced by splitting the unit into pieces
along its dependency fault lines, as illustrated by the following diagrams.
Initially, the compilation unit has many incoming and outgoing dependencies,
but it is not the case that the entire unit depends on every dependency. For
example, sub-unit <code>Y</code> only depends on <code>O2</code> and
<code>O4</code> (note that <code>Y</code> is not necessarily a class, just
a part of the compilation unit):
</p>
<table>
<tbody><tr>
<td><img src="./FEfferentCoupling_SplitBefore.png" alt="Split Before" /></td>
</tr>
<tr>
<td>Before</td>
</tr>
</tbody></table>
<p>
This suggests the following refactoring, where the unit containing
<code>X</code>, <code>Y</code> and <code>Z</code> is split into three new
units, each with fewer dependencies. Notice how the efferent coupling of each
of the new units is significantly lower than that of the original unit:
</p>
<table>
<tbody><tr>
<td><img src="./FEfferentCoupling_SplitAfter.png" alt="Split After" /></td>
</tr>
<tr>
<td>After</td>
</tr>
</tbody></table>
<p>
Performing this refactoring clearly relies on an ability to determine suitable
places at which to partition the compilation unit. This can often be done by
simple inspection of the code, but for more complicated units there are
scientific approaches as well. As a simple example of this, consider a
compilation unit that contains multiple classes. This could be partitioned by
visualizing the dependencies of the various classes and grouping those with
the same dependencies. Each group would then be turned into a new compilation
unit. (Of course, for classes it is often best to just have a compilation unit
for each class; this example is merely intended to illustrate how one might go
about partitioning a unit in a mechanical way.)
</p>
</recommendation>
<references>
<li>
M. Fowler. <em>Refactoring</em>. Addison-Wesley, 1999.
</li>
</references>
</qhelp>