NDepend analyzes .NET assemblies of an application and generates reports containing design quality metrics, warnings...
and diagrams. NDepend is a complement and not a competitor of FxCop, the main .NET static code analyzer provided by Microsoft. Very few needs are handled by both tools. Basically:
- FxCop rules are rigid and are mostly .NET issues-oriented while NDepend rules are customizable (thanks to a dedicated language named CQL) and are mostly design/architecture/code structure-oriented.
- NDepend handles code metric and FxCop doesn't.
Compared to other .NET code metric and static code analyzers, here are the main differences:
- NDepend 2.0 is shipped with an interactive UI (VisualNDepend.exe) which allows you to browse metrics in a unique way thanks to a treemap view.
- NDepend provides a very complete set of type metrics. The list of type metrics is available here and includes Lack of Cohesion Of Methods (LCOM), Cyclomatic Complexity (CC), Size of instance, Afferent Coupling (Ca), Efferent Coupling (Ce), Association Between Class (ABC), Number of Children (NOC), Depth of Inheritance Tree (DIT), Response For a Type (RFT). Trivial metrics such as #IL instructions, #local variables or #parameters are also handled.
- NDepend is the only .NET tool which yields components metrics as defined by Robert C. Martin in his book Agile Software Development: Principles, Patterns, and Practices (Prentice Hall, 2002).
- NDepend yields diagrams about assemblies dependencies, assemblies abstractness vs. instability and treemap view.
- NDepend analyzes assemblies and IL code. Clearly the main drawback is that code source comments are not taken into account; rather, this approach allows NDepend to analyze any .NET application independently from the language in which it is written -- C#, VB.NET, etc.
The support for CQL (Code Query Language) is indeed the main enhancement to the tool. While creating CQL, I wanted a means to express all sorts of design intentions such as the following:
- My business/domain classes shouldn't depend on anything.
- Instances of this particular class shouldn't be created out of this dedicated factory.
- This namespace shouldn't be used by any other namespace than N1, N2 and N3.
Often, after a couple of releases, primary designer intentions are lost and not respected anymore. As a means to avoid the rot of the design over time, CQL is a new weapon for agile programmers.
CQL is similar to SQL and supports the SELECT TOP FROM WHERE ORDER BY pattern. This resemblance is not by chance. NDepend considers your code and its underlying graph of dependencies as a database and CQL allows querying and checking some assertions on this database. Here are some CQL sample constraints:
WARN IF Count > 0 IN SELECT TYPES OUT OF NAMESPACES "System.Xml" WHERE DepthOfIsUsing "System.Xml.XmlChildNodes" == 1 // Restrict the possibility to create instances of "System.Xml.XmlLoader" only to certain namespaces.
WARN IF Count > 0 IN SELECT ASSEMBLIES WHERE !NameIs "System.Web" AND DepthOfIsUsing "System.Web.Services" == 1 // Assert that the assembly System.Web.Services will never be referenced by another assembly than System.Web.
WARN IF Count > 0 IN SELECT METHODS OUT OF TYPES "System.Xml.XmlNamedNodeMap", "System.Xml.XmlAttributeCollection" WHERE DepthOfIsCalling "System.Xml.XmlNamedNodeMap.InsertNodeAt(Int32,XmlNode)" == 1 // Restrict the possibility to call the method InsertNodeAt() only to certain types.
I figured out that this approach is also a good means to write metrics thresholds or naming rules such as the following:
WARN IF Count > 0 IN SELECT METHODS WHERE NbILinstructions > 200 ORDER BY NbILinstructions// Methods where NbILInstructions > 200 are extremely complex and should be split in smaller methods.
WARN IF Count > 0 IN SELECT FIELDS WHERE NameLike "^m_" AND IsStatic // A static field should be named 'm_XXX'.
The complete CQL 1.0 specification is available here.
The second enhancement of NDepend 2.0 is the VisualNDepend.exe UI which allows developers to have a global understanding of their code thanks to an interactive treemap view. VisualNDepend provides also a CQL editor which supports intellisense and verbose compile error description. While editing CQL queries, matched code elements are immediately highlighted on the view. For example here is a screenshot which gives an idea about the set of methods of the .NET framework 2.0 which overcome the limit of 200 IL instructions (highlighted in blue).
Numerous minor enhancements are also available. For example the NDepend.Project.exe tool allows editing NDepend projects instead of previous handcrafted XML configuration files. The report layout is now configurable. You can keep historics of NDepend reports.
In development, the main pitfall designers/developers should avoid is losing the control over the structure of their code. To do so, programmers must continuously wrestle to reduce the complexity of their code. This is one of the tenets of the agile programming manifesto (Continuous attention to technical excellence and good design enhances agility). Part of the complexity of a program is proportional to the sum of awkward potential dependencies which could be created in the code without yielding a warning or an error. In other words, encapsulation is a mean to reduce complexity. Encapsulation is traditionally achieved with OOP visibility levels such as public, internal/friend, protected, private. As we saw, CQL constraints constitute a complement to OOP visibility levels to express custom encapsulation needs. I consider them as some kind of regression tests on the design of an application.
Another pitfall is to avoid to regularly check the quality of the code with a tool. Numerous quality issues can be pinpointed by NDepend and most of them aren't handled by FxCop. CQL is a good way to provide your own metric thresholds for example to detect methods with too many IL instructions, too many parameters or too many local variables, types with low cohesion, high depth of inheritance or high footprint etc. However keep in mind that high metric values don't necessarily pinpoint a problem. For example it is legitimate that the System.String class has almost 200 methods and that the System.Windows.Forms.DataGridView has more than 1000 methods. They are necessary evils. Other code quality issues are also handled by NDepend such as warnings if the visibility of a type or a member is not optimal (i.e for example if in the context of the analyzed application a method could be declared protected instead of public) and warnings about type and members which are not statically used (i.e potential dead code).