Previous: Complexity Metrics Control, Up: Specifying a set of metrics to compute


15.1.3.4 Coupling Metrics Control

Coupling metrics measure the dependencies between a given entity and other entities the program consists of. The goal of these metrics is to estimate the stability of the whole program considered as the collection of entities (modules, classes etc.).

Gnatmetric computes the following coupling metrics:

Two kinds of coupling metrics are computed:

fan-out coupling (efferent coupling)
the number of entities the given entity depends upon. It estimates in what extent the given entity depends on the changes in “external world”
fan-in coupling (afferent coupling)
the number of entities that depend on a given entity. It estimates in what extent the “external world” depends on the changes in a given entity

Object-oriented coupling metrics are metrics that measure the dependencies between a given class (or a group of classes) and the other classes in the program. In this subsection the term “class” is used in its traditional object-oriented programming sense (an instantiable module that contains data and/or method members). A category (of classes) is a group of closely related classes that are reused and/or modified together.

A class K's fan-out coupling is the number of classes that K depends upon. A category's fan-out coupling is the number of classes outside the category that the classes inside the category depend upon.

A class K's fan-in coupling is the number of classes that depend upon K. A category's fan-in coupling is the number of classes outside the category that depend on classes belonging to the category.

Ada's implementation of the object-oriented paradigm does not use the traditional class notion, so the definition of the coupling metrics for Ada maps the class and class category notions onto Ada constructs.

For the coupling metrics, several kinds of modules – a library package, a library generic package, and a library generic package instantiation – that define a tagged type or an interface type are considered to be a class. A category consists of a library package (or a library generic package) that defines a tagged or an interface type, together with all its descendant (generic) packages that define tagged or interface types. That is a category is an Ada hierarchy of library-level program units. So class coupling in case of Ada is called as tagged coupling, and category coupling - as hierarchy coupling.

For any package counted as a class, its body and subunits (if any) are considered together with its spec when counting the dependencies, and coupling metrics are reported for spec units only. For dependencies between classes, the Ada semantic dependencies are considered. For object-oriented coupling metrics, only dependencies on units that are considered as classes, are considered.

For unit and control coupling also not compilation units but program units are counted. That is, for a package, its spec, its body and its subunits (if any) are considered as making up one unit, and the dependencies that are counted are the dependencies of all these compilation units collected together as the dependencies as a (whole) unit. And metrics are reported for spec compilation units only (or for a subprogram body unit in case if there is no separate spec for the given subprogram).

For unit coupling, dependencies between all kinds of program units are considered. For control coupling, for each unit the dependencies of this unit upon units that define subprograms are counted, so control fan-out coupling is reported for all units, but control fan-in coupling - only for the units that define subprograms.

The following simple example illustrates the difference between unit coupling and control coupling metrics:

     package Lib_1 is
         function F_1 (I : Integer) return Integer;
     end Lib_1;
     
     package Lib_2 is
         type T_2 is new Integer;
     end Lib_2;
     
     package body Lib_1 is
         function F_1 (I : Integer) return Integer is
         begin
            return I + 1;
         end F_1;
     end Lib_1;
     
     with Lib_2; use Lib_2;
     package Pack is
         Var : T_2;
         function Fun (I : Integer) return Integer;
     end Pack;
     
     with Lib_1; use Lib_1;
     package body Pack is
         function Fun (I : Integer) return Integer is
         begin
            return F_1 (I);
         end Fun;
     end Pack;

if we apply gnatmetric with --coupling-all option to these units, the result will be:

     Coupling metrics:
     =================
         Unit Lib_1 (C:\customers\662\L406-007\lib_1.ads)
            control fan-out coupling  : 0
            control fan-in coupling   : 1
            unit fan-out coupling     : 0
            unit fan-in coupling      : 1
     
         Unit Pack (C:\customers\662\L406-007\pack.ads)
            control fan-out coupling  : 1
            control fan-in coupling   : 0
            unit fan-out coupling     : 2
            unit fan-in coupling      : 0
     
         Unit Lib_2 (C:\customers\662\L406-007\lib_2.ads)
            control fan-out coupling  : 0
            unit fan-out coupling     : 0
            unit fan-in coupling      : 1

The result does not contain values for object-oriented coupling because none of the argument unit contains a tagged type and therefore none of these units can be treated as a class.

Pack (considered as a program unit, that is spec+body) depends on two units - Lib_1 and Lib_2, therefore it has unit fan-out coupling equals to 2. And nothing depend on it, so its unit fan-in coupling is 0 as well as control fan-in coupling. Only one of the units Pack depends upon defines a subprogram, so its control fan-out coupling is 1.

Lib_2 depends on nothing, so fan-out metrics for it are 0. It does not define a subprogram, so control fan-in metric cannot be applied to it, and there is one unit that depends on it (Pack), so it has unit fan-in coupling equals to 1.

Lib_1 is similar to Lib_2, but it does define a subprogram. So it has control fan-in coupling equals to 1 (because there is a unit depending on it).

When computing coupling metrics, gnatmetric counts only dependencies between units that are arguments of the gnatmetric call. Coupling metrics are program-wide (or project-wide) metrics, so to get a valid result, you should call gnatmetric for the whole set of sources that make up your program. It can be done by calling gnatmetric from the GNAT driver with -U option (see The GNAT Driver and Project Files for details).

By default, all the coupling metrics are disabled. You can use the following switches to specify the coupling metrics to be computed and reported:

--coupling-all
Report all the coupling metrics
--tagged-coupling-out
Report tagged (class) fan-out coupling
--tagged-coupling-in
Report tagged (class) fan-in coupling
--hierarchy-coupling-out
Report hierarchy (category) fan-out coupling
--hierarchy-coupling-in
Report hierarchy (category) fan-in coupling
--unit-coupling-out
Report unit fan-out coupling
--unit-coupling-in
Report unit fan-in coupling
--control-coupling-out
Report control fan-out coupling
--control-coupling-in
Report control fan-in coupling