Design Rule Theory. Baldwin and Clark's Design Rule Theory [1]  states that design rules create independent modules, that is, stable design decisions that decouple the rest of the system into modules, and that the value of a module is in the form of options. The more independent and active a module is, the higher the value it has; the more such independent modules in the system, the higher the system value. Sullivan et al. [11]  first introduced this theory into software design. 


Their theory also proposed several module operators to describe the evolution of modular systems, including 

  1. Splitting: decouple proto-modular designs into true modules
  2. Substitution: replace a module with a different version
  3. Augmentation: adds a module to a system
  4. Exclusion: removes a module
  5. Inversion: supplies a common design element
  6. Porting: which transports a module for use in another system.


Splitting is the most important operator. The essence is the creation of design rules so that the rest of the system only depends on design rules but not on each other. The following diagram illustrates this process: 

Before splitting (the DSM on the left): 

  • B Depends on A: If the designer changes A, B may change, but not the other way around. Hence A should usually be decided (implement) first
  • B and C cyclically depend on each other and form a proto-module
  • C and A are independent of each other. 
  • There are two prototype modules (proto-module) in this design, A and B-C. Because B depends on A, these two modules are not independent (True module)

Splitting Operation: Adding a design rule I


After splitting (the DSM on the right): 

  • Both B and A depend on I and no longer depend on each other
  • I decouples A and B as interfaces between A and B


In a software system, a design rule is typically manifested as an interface or abstract class. For example, if an Observer Pattern [3]  is used in a codebase, then there must exist an observer interface that decouples the subject and concrete observers into independent modules. As long as the interface is stable, addition, removal, or changes to concrete observers should not influence the subject. In this case, the observer interface is considered a design rule, decoupling the subject and concrete observers into two independent modules. Consider another example: if a Strategy Pattern [3] is implemented, then the strategy interface is considered the design rule that decouples the context and concrete strategies into independent modules.


Design Rule Hierarchy (DRH). To automatically identify the design rules and the files that they influenced, we proposed a clustering algorithm—Design Rule Hierarchy (DRH) [2] [4] [12] which clusters the files of a system into a hierarchical structure. Within such a hierarchy, files in layer Li should only depend on files in the higher layers, Li-1 to L1, and files in the top layer, L1, should not depend on files in the lower layers, Li+1 to Ln. Hence files in the top layer, L1, should contain the most influential interfaces or abstract classes, which do not depend on files in other layers. Also, files in the same layer should be decoupled into a set of mutually independent modules from each other. Thus the changes, addition, even replacement to a module will not influence other modules within the same layer. Therefore, the independent modules in the bottom layer of a design rule hierarchy are the most valuable, from an evolutionary perspective, because changes to these modules will not affect the rest of the system. 


The DSM in Fig. 1 presents a design rule hierarchy (DRH) with 2 layers: L0:(rc1 – rc6), L1:(rc7 - rc13). The first layer,  L1, contains the most influential design rules that should remain stable. Within each layer, files are grouped into mutually independent modules. Taking L1 as an example: it is grouped into 2 mutually independent modules: M1:(rc7 -rc9), M2:(rc10 - rc13). Modules in L1 only depend on files in L0, but not on each other. From the absence of annotations in the cells shared by these modules, we can observe no dependencies between them. The text in a cell is used to indicate the number of dependencies between the files. 



This DSM illustrates how the key interface classes in the Abstract Factory pattern, such as "MazeFactory.java", split the rest of the system into two independent modules, each capturing classes involved in a concrete factory. 


Following is the DRH within a small compiler design, formed by inheritance relationships (Extend and Implement) only. It is clear that the top two layers L0:(rc1 – rc4), L1:(rc5 – rc6) contain the key design rules, such as Filer.java, Pipe.java, Node.java.  These design rules decouple the rest into 6 independent modules. 



We use DSMs as a major design modeling approach because they can express DRH, and manifest decoupling design rules and stand-alone modules, which other models, such as graphs in UML or Understand,  cannot express. Moreover, a DSM is independent of programming paradigm and programming languages and can express dependencies among requirements, design, implementation, and tests in a unified way. It is also computable and can be used for quantitative assessments.  The DRH can be used to assess design quality both quantitatively and qualitatively and forms the foundation of the Decoupling Level metrics.