Chris Umbel

Understanding Source Code with NDepend and CQL

The longer I work in this industry the more I realize the pain involved when source code gets out of control. The larger the project the harder it is to refactor and the longer it can take to see the need to do so. Then once you've made the decision to refactor the task can become so overwhelming and complex that you do so ineffectively or simply give up.

There have long been tools to combat refactoring complexities but one of the more interesting modern ones I've found is NDepend. What specifically intrigues me about this tool is its Code Query Language (CQL), which is NDepend's flagship feature. CQL is a language patterned after SQL that can be used to determine what source code elements meet specified criterion. This allows the developer to effectively understand and navigate the codebase which is critical in developing and refactoring.

To demonstrate I'll need a nicely-sized Visual Studio solution, let's say the Enterprise Library 4.1 application block's source code. According to the report generated after adding the solution to an NDepend project we'll be querying a solution of 1,542 classes spread over 28,281 lines of code which compiles down to 196,966 IL instructions.

Now let's take a look at some actual CQL. Consider the following line:

SELECT TYPES 
WHERE DeriveFrom "System.Drawing.Design.UITypeEditor"

Notice the similarity to SQL. There's a familiar SELECT and WHERE clause. Although this particular statement is lacking a FROM clause they are supported and will be demonstrated later. The TYPES expression indicates that my query will return .Net types such as classes and structs. The DeriveFrom "System.Drawing.Design.UITypeEditor" expression simply stipulates that all types returned will subclass System.Drawing.Design.UITypeEditor.

The result is a list of types that you can select in NDepend and perform a number of actions such as navigating directly to that class in Visual Studio or Reflector as well as viewing dependancy graphs and matrices.

Let's consider another query, this time slightly more complex.

SELECT TYPES 
FROM ASSEMBLIES "Microsoft.Practices.EnterpriseLibrary.Data.Configuration.Design"
WHERE NameLike "Oracle.*Builder"
AND IsSealed 

This query employs a FROM clause which limits the results to the assembly "Microsoft.Practices.EnterpriseLibrary. Data.Configuration.Design". Also the NameLike expression accepts a regular expression which filters the results to types named accordingly. As you may guess the IsSealed expression causes the query to return only sealed classes.

CQL queries need not always be written manually as much of the core NDepend functionality simply writes it for you. Interestingly the software is forthright about this and includes CQL queries directly into its menu system as is shown below.

CQL is certainly one of the most flexible tools a developer can employ to understand a large codebase, especially one they're not entirely familiar with. It's also very intuitive because its set-based query approach is something most developers are already accustomed to. Despite it's simplicity it's very feature-rich and I suggest taking a look at The CQL 1.8 Specification for a more detailed view.

I also suggest taking a look at CQL Constraints which are a more in-depth topic that facilitate proactive management of source code.

Mon Jun 22 2009 16:06:48 GMT+0000 (UTC)

Follow Chris
RSS Feed
Twitter
Facebook
CodePlex
github
LinkedIn
Google