Dependency Graphs

The Modularity Principle states that programs should be built from cohesive, loosely coupled modules.

Module A is coupled to module B if A depends on B.

A depends on B

A depends on B if changes to B might require changes to A.

Intuitively, A and B are loosely coupled if the probability that changes to B will require changes to A is low. This happens, for example, if only a small part of A depends on a small part of B.

Note that this is a transitive relationship:

A depends on A.

If A depends on B and B depends on C, then A depends on C.

A references B

Module A references module B, if B appears in the implementation of A.

For example, if A and B are classes, then B might appear as the type of a field, parameter, local, or super class:

class A extends B {
   B someField;
   B someMethod(B someParameter) {
      B someLocal;
      // etc.
   }
}

A references B implies that A depends on B, but not the reverse. For example, A may not reference B, but it may reference C, which references B, and so A depends on C, which depends on B, hence by transitivity, A depends on B.

Dependency in UML

The UML dependency arrow is meant to represent the idea of dependency between classes, packages, components, and other UML elements:

Note that realization, generalization, and association arrows are all special cases of the dependency arrow.

However, if we take into account the transitivity of dependence, then showing all of the dependencies between UML elements could become cumbersome:

Therefore, in these notes we will use the UML dependency arrow to denote the references relationship.

Dependency Graphs

Let p be a program or a package. In the dependency graph of p—DG(p)—the nodes are the classes and interfaces in p. A (dashed) arrow connects node A to node B if A references B.

A class diagram for p is a special case of DG(p).

Example

Assume package p contains the classes A, B, C, D, and E:

package p;

class A extends C {
  
 B field1;
  
 ...
}

class B { 
  
 C field2;
  
 ... 
}

class C extends D {
  
 E field2;
  
 ...
}

class D { ... }

class E extends B {
  
 ...
}

Here's DG(p):

Main

Providers and Clients

providers(A) = the number of classes that A references

clients(A) = the number of classes that reference A

providers*(A) = encumbrance(A) = the number of classes that A depends on.

clients*(A) = the number of classes that depend on A

Responsibility, Stability, and Deviance