In my previous post Keep your code structure clean I explained how to build Code Query Language (CQL) constraints that can help avoiding design erosion by preventing mistakes. This is the preventive approach, but what if you have to improve an already existing design? I believe that any code base contains many design mistake that would make architects blush. The reason is that there is a lack of tool to help human deals with tangle code. This is why I take a chance here to explain how to deconstruct the design of your code base with NDepend.
Getting a particular transitive closure
Let’s show which code of the NUnit framework can potentially use the class System.AppDomain. We need to know about the methods that are using AppDomain objects. But also we need to list the methods that are using these methods, and then the methods that are using these methods etc… Basically we want the transitive closure of AppDomain users. Transitive closure is a powerful mean to deconstruct software because it shows how the code is really layered (not how it should be layered). Getting a transitive closure from the source code is practically impossible and there is a need for tooling. As far as I know NDepend is the only tool that deals with transitive closure (even if considering tools in the Java sphere).
The following screenshot shows how to get the transitive closure of NUnit namespaces that are using the class System.AppDomain.
Actually we could have chosen the transitive closure made of methods or types or assemblies. We choosed namespaces for clarity since there are 198 methods involved in the transitive closure made of methods.
A CQL query had been generated for us and here is the result. There is a metric DepthOfIsUsing “System.AppDomain”. The namespace with the value 1 are the ones that are using directly the class AppDomain. Those with the value 2 are the ones that are using the namespaces with a value 1 etc… The namespace System has a value 0 because it contains the class AppDomain.
A good news is that thanks to NDepend addins, you can get such a transitive closure directly from VisualStudio or even Reflector:
Visualizing a particular transitive closure
NDepend comes with many original facilities to help users have an intuitive understanding of the code design. The best way to visualize a transitive closure is the good old Boxes and Arrows diagram.To get such a diagram, just right click the parent node in the Query Result panel, and export it the Graph panel.
Browsing transitive closure
Below, here is the internal design of the VisualNDepend assemblies with the Dependency Matrix panel. A blue cell means that the corresponding namespace in the horizontal header is directly using the corresponding namespace in the vertical header. This diagram immediately tells us which namespace is low-level and which one is high-level. It also tells that the design is well layered and that there is no dependency cycles (more on dependency cycles below).
With the matrix, we can see transitive closures by switching to the indirect dependencies mode, as shown below. Now a blue cell with a weight of X tells that the namespace user is using the namespace used with a depth of X. Rows that contain a lot of blue cells indicate low level namespaces that are used directly or indirectly by almost all other namespaces.
For example the namespace TreeCodePanel is using the namespace Helpers with a depth of 6. 6 represents here the length of a shortest path from TreeCodePanel to Helpers. The picture below shows how you can visualize one of the shortest paths…
…and here is the shortest path:
Transitive closures and dependencies cycles
When the design contains some dependencies cycles, the matrix contains some black cells. For example, the matrix below tells that almost all namespaces of mscorlib are involved in a dependency cycle with almost all other namespaces of mscorlib.
Here also, to give more sense to data, you might prefer visualizing the cycle with a boxes and arrows diagram. You can generate such a diagram as shown in the following screenshot:
…and here is the resulting diagram. Notice that the value of a black cell indicates the shortest length of a cycle that contains both involved code element. Here the length of a shortest cycle that contains both System.Runtime.Remoting.Data and System.IO.isolatedStorage is 6.
My personal opinion is that dependencies cycles are the worth kind of mistake a design can contain. When there are some cycles, you cannot anymore develop your software with the divide and conquer way. In other words, cycles break componentization. I wrote an article about this topic that explains my positions and also how you can use NDepend to remove cycles.
Actually NDepend and especially the CQL language has some others features that helps dealing with dependencies and closure that I will explain in some other posts.
I would like to notice that we worked hard to optimize the NDepend code that deals with transitive closures of large and complex code base. For example, to browse dependencies closures of all classes of System and all classes of System.Threading (282 x 70 classes with thousands of long dependencies cycles), NDepend won’t take more than 2 seconds to compute the matrix.