Search code examples
ooparchitectureumlmetrics

Calculate the Martin-Metrics for packages


See for calculation: https://101.jqassistant.org/calculate-metrics/index.html

  • Ca (afferent couplings): The number of classes outside this component that depend on classes within this component. In short: the number of incoming dependencies.
  • Ce (efferent couplings) The number of classes inside this component that depends on classes outside this component. In short: the number of outgoing dependencies.

Given is the UML-Diagram of the car-simulation application. Every layer represents its own package.

UML-Diagram

Calculate the Martin-Metrics for the four packages.

Result

Apart from the initialization this is a correct example of a layered architecture. Therefore calculate the afferent and efferent coupling again, this time without the initialization package.

Result Which number(s) give a hint, that these three packages may form a correctly layered architecture?

I wanted to know if my solution is correct and if I have calculated it correctly.


Solution

  • How to find dependencies in an UML diagram?

    Direct dependencies are documented with dashed arrows.

    Dependencies can also be deducted from associations (and aggregations and compositions):

    • We cannot say anything when there is unspecified navigability and no association-end ownership: the association could own the ends and manage the links.
    • We can assume a dependency for navigable associations and owned association end (dot notation) : the association needs to know at least about the class at the arrow or dot end.
    • We cannot say for sure anything for the reverse dependency in case of unspecified navigability in the opposite direction; it could be navigable or not. We could assume absence of dependency, since nothing formally identifies a dependency here.

    We assume that the diagram is comprehensive and does show all the relevant classes.

    Inventory of dependencies in your diagram and metrics

    The inventory:

    • SensorBus directly depends on Dashboard. Note that the label of the dependency notifies() is very strange. Is it a usage dependency (i.e. an operation notifies() uses Dashboard as parameter, but from where does it get this parameter)?
    • Startup in initialization depends on Dashboard, SensorBus and Car
    • Dashboard in UI depends on Locale
    • SensorBus in functional layer depends on Sensor, Car, as well as Weather and Locale which are in the same package
    • Car in HW-layer depends on Sensor which is in the same package
    • Sensor in HW-layer depends on SensorType which is in the same package

    According to your definition, this leads us to:

                          Ca    Ce
    ----------------------------------
    Initialization         0     3
    UI                     2     1
    Functional layer       2     3 !!
    HW layer               2 !!  0
    

    Yes: 2 classes outside the HW package depend on HW classes.
    Yes: the functional layer, SensorBus depends on 3 external classes: Car, Sensor and Dashboard.

    Issues in your background material

    The wording used in your linked document is ambiguous about Ce:

    • "The number of classes inside this component that depends on classes outside this component" contradicts the second part of the definition, since it does not correspond to the "outgoing flows".
    • The correct definition is more like "The number of classes in other packages that the classes in a package depend upon" (source: wikipedia and this blog)

    Moreover, there is an issue about the package level of the calculation:

    • Ca and Ce are well defined for classes are easy to apply since you just count unique classes on one side or the other of dependencies.
    • For components and packages should we still keep counting classes ? Or should we work at an homogeneous level of packages, i.e. counting dependencies with other packages? Martin and most authors opts for classes. But this seems inconsistent: if I have a package with one class exposing nested clases, dependencies would count the top-level class (since the nested class is just a detail of the enclosing class) whereas the same design with a package providing directly the same classes instead of nesting them would count more classes and higher Ca or Ce.