Write Your Own Code Rules

The use case Query Code with C# LINQ explains that with NDepend, your code can be queried with C# LINQ the same way your relational data can be queried with with SQL. This feature is named CQLinq.

An NDepend code rule is a special CQLinq code query with a non-standard-C# warnif prefix. Many such Default-Rules are proposed. They are all open-source C# LINQ queries that can be customized.

What kind of custom rule can be written?

With CQLinq it is easy to write your own rule to validate any particular point in your code. CQLinq is feature rich and many sorts of code properties can be constrained and validated:

  • Object Model: A base class should not used its derivatives (each point is followed by an example of rule)
  • Dependencies: The UI code shouldn't invoke directly the DB code
  • Design: Classes that are candidate to be turned into structures
  • Code Quality: Avoid too complex methods
  • Code Coverage: New Methods should be tested
  • Changes since a Baseline: Avoid making complex methods even more complex
  • API Breaking Changes: Avoid removing a public type
  • State Mutability: Structures should be immutable
  • Naming Conventions: Avoid having different types with same name
  • Encapsulation: Methods that could have a lower visibility
  • Framework Usages: Collection properties should be read only
  • ...

A complement to Roslyn Analyzers, not a replacement

It is important to note that CQLinq is not a replacement for Roslyn Analyzers but a complement:

  • Most of CQLinq code properties listed above would require significant effort to be implemented through Roslyn Analyzers.
  • On the other hand CQLinq is not meant to validate details in code flow and refactor the code automatically like Roslyn excels at.

Moreover a CQLinq code rule is just a textual LINQ query compiled and executed instantly on the fly. There is no need to deal with compiled and versioned assemblies.

An example of custom rule

Let's write a simple code quality rule with CQLinq based on the Cyclomatic Complexity code metric:

// <Name>Avoid complex methods</Name>
warnif count > 0 
from m in JustMyCode.Methods
where m.CyclomaticComplexity > 20
select new { m, m.CyclomaticComplexity, m.NbLinesOfCode }

This simple rule works fine. However a few other steps than the warnif prefix are needed to properly transform a code query into a full-fledged code rule

Finally the initial query to obtain complex methods transformed into a rule looks like:

// <Name>Avoid complex methods</Name>
// <Id>ND9001:AvoidComplexMethods</Id>
warnif count > 0 
from m in JustMyCode.Methods
where m.CyclomaticComplexity > 20
select new { 
  
m, 
  
m.CyclomaticComplexity, 
  
m.NbLinesOfCode,
  
Debt = 
    
((m.CyclomaticComplexity -19)*4).ToMinutes().ToDebt(),
  
AnnualInterest = 
    
((m.CyclomaticComplexity -19)*2).ToMinutes().ToAnnualInterest()
}

//<Description>
// Avoid methods with cyclomatic complexity higher than 20.
// https://www.ndepend.com/docs/code-metrics#CC
//</Description>
//<HowToFix>
// Split matched methods into smaller and less complex methods.
//</HowToFix>

One key characteristic of CQLinq is how fast it is: it just takes a few milliseconds to compile and execute a query or a rule against your largest code base. This means that it is easy to write a code rule and refine it until the matched code elements are exactly the set you want as result. This also means that after each NDepend analysis, it just takes 2 or 3 seconds to pass hundreds of default and custom rules in Visual Studio without slowing down the IDE.

For example in the screenshot above our Avoid complex methods rule is compiled and executed in 1 millisecond against the large NopCommerce OSS code base (2.600+ types).

Execution of a Code Rule to Match Most Complex Methods

A 4 minutes video on NDepend rules

Watch this 4 minutes video about NDepend Code Rules: