Divide and Conquer: Assessing different dependency types separately
The user can also assess the design space formed by one or more selected types of dependencies. In particular, the inheritance relation among files often captures important aspects of the system’s design decisions. We have observed that each type of dependency can form its own design space.
Next we illustrate how to use DV8 to explore the design space formed by different types of dependencies using the small calculator.
To examine the design space formed by inheritance relations, the user can click Matrix->Cell Options, and the following window will be displayed, from which the user can check the "Extend" and "Implement" so that DV8 only displays these two types of relations. The user can also customize how each type of dependency is to be displayed. For example, we use "Ext" and "Imp" to denote "Extend" and "Implement" respectively, as illustrated below:
Once selected, DV8 will only display these two selected dependencies in the DSM. The user can click Matrix-> Toggle Cell Details to display dependency types in the cells, and click Tree -> Cluster as DRH to cluster the DSM into a DRH using the selected dependencies only. The resulting DSM is as follows:
This DSM shows that the inheritance relations of the system form a clear design rule space. The design rules are the files at the top of the DSM, including Filter.java, Pipe.java, astNode.java, and bnfNode.java. The rest of the files form 6 modules with distinctive functions, as shown above.
The user can also use DV8's Design Anti-patterns detection function to identify "Improper Inheritance" instances—groups of files that violate the Liskov Substitution Principle . This anti-pattern includes two cases: (1) the parent class depends on one or more of its subclasses; (2) the client of the hierarchy depends on both the parent class and one or more of its subclasses.
The following DSM is an Improper Inheritance anti-pattern instance detected in the small calculator example. The DSM shows that Parser.java and Convert.java–clients of the bnf classes—depend on all the bnf classes—the parent class mij.bnf.Node.java and all of its subclasses. If additional expressions are added, the Parser.java will need to change and accommodate more complicated switch cases. It would be better to apply the State Pattern to address this problem.