Attributes as a mean to partition code

 

On top of
things Code Query Language users where asking for, was the condition HasAttribute. I am glad to announce
that NDepend 2.7 supports CQL 1.6 that supports this condition for assemblies, types, methods and fields. This single condition opens the door to a wide range of interesting
scenarios.

 

 

 

Attributes and
generated code

 

You can use
HasAttribute to segregate code. For
example suppose that your generated methods are tagged by the attribute YourNamespace.YourGeneratedAttribute.
You can now write very easily a CQL constraints to care about code quality of
code non-generated such as:

 

WARN IF Count > 0 IN SELECT METHODS  WHERE

// Quality conditions

( NbLinesOfCode > 30 OR CyclomaticComplexity > 10 OR ILNestingDepth > 6 )

AND !HasAttribute “YourNamespace.YourGeneratedAttribute”

 

 

We could
have define a
NDepend.CQL.GeneratedAttribute
attribute in the assembly NDepend.CQL.dll for example but we want
to make NDepend non-intrusive to your code. In other words, we want to make
sure that your code doesn’t mention anything about NDepend. This way, the
attribute class YourNamespace.YourGeneratedAttribute
is totally yours and you can reuse it in any way you want.

 

 

 

Tests attributes

 

You can
also use the HasAttribute condition
to identify test methods: 

 

SELECT METHODS WHERE HasAttribute “NUnit.Framework.TestAttribute”

 

More
interestingly, you can write an astute query to get an estimation of which test
methods is testing a particular method YourClass.YourMethod():

 

SELECT METHODS WHERE

HasAttribute “NUnit.Framework.TestAttribute”
AND

IsUsing “YourClass.YourMethod()”

 

Notice that
because the IsUsing condition
returns the transitive closure of callees, this query will also
match test methods that are using a method that is using YourClass.YourMethod().

 

 

 

Attribute to
check for Immutability

 

The
condition HasAttribute can also be
used to make sure that some methods or some classes have some properties that
can be statically verified by NDepend. This is like if NDepend was an extension
of the C# compiler in charge to verify that some contracts are respected.

 

For
example, I observed recently a great buzz about immutability in the .NET
community. For more information on immutability in .NET and the various
facilities offered by NDepend to handle it, please have a glance at this blog
post: Immutable types: understand their benefits and use them.
With the HasAttribute condition, it
is easy to check for the immutability of your types with an ImmutableAttribute and the rule:

 

WARN IF Count > 0 IN SELECT TYPES WHERE

!IsImmutable AND HasAttribute “YourNamespace.ImmutableAttribute”

 

And as Greg
Young
noticed here, this is an idea that Microsoft is
already harnessing because of the attribute ImmutableAttribute in the namespace Microsoft.Contracts in the assembly System.Core. The bad news is that Microsoft keeps all this internal. The good news is that with
NDepend you can have it all and more [:)].

 

Interestingly
enough, we check that the .NET Fx (including WPF, WCF…) doesn’t rely yet on the
immutability attributes. Only the internal class System.Numeric.BigInteger is actually using it.

 

In the same
spirit, you can check for method purity. I mean, you can make sure that a
method won’t modify any state thanks to the CQL conditions ChangesObjectState and ChangesTypeState
(a la const keyword in C++) :

 

WARN IF Count > 0 IN SELECT TYPES WHERE

(ChangesObjectState OR ChangesTypeState) AND

HasAttribute “YourNamespace.PureAttribute”

 

 

 

Attribute to
check for tricky encapsulation scenario

 

The
condition HasAttribute can also be a
great help in the optimal encapsulation scenario. If you are using NDepend to
make sure that your method and types are optimally encapsulated (i.e not
declared as public when it could be declared as internal, protected or private for
example) you certainly found out some cases where it is not applicable. For
example, the Windows Form designer requires your control classes to be public
in order to use them (actually there are plenty of cases where a type should be
declared as public to be used by a tool or a framework). Imagine that your
control is only used inside your assemblies, then NDepend will tell you that it
should be declared as internal with the following rule:

 

WARN IF Count > 0 IN SELECT TYPES WHERE CouldBeInternal

 

A good
solution to this problem is to tag your public control class with a CantBeInternalBecauseOfWindowsFormDesignerAttribute
and to rewrite your constraint:

 

WARN IF Count > 0 IN SELECT TYPES WHERE

CouldBeInternal AND

!HasAttribute “YourNamespace.CanBeInternalBecauseOfWindowsFormDesignerAttribute”

 

This might sound awkward but think about it: Thanks to this attribute you’ve added a very useful active comment for future
developers of your code: Beware! Make sure to not declare this type as
internal!

 

 You
could also add the condition…

!CouldBeInternal AND

HasAttribute “YourNamespace.CanBeInternalBecauseOfWindowsFormDesignerAttribute”

…to make sure that the attribute is only used
where it should be.

 

 

And more…

 

Let’s use the HasAttribute condition
in any scenario you can imagine like:

 

  • Restricted
    use on a class:

WARN IF Count > 0 IN SELECT TYPES WHERE

IsDirectlyUsing “YourNamespace.Foo” AND

!HasAttribute “YourNamespace.AllowedToUseFooAttribute”

 

  • Restricted
    possibility on instantiating a class:

WARN IF Count > 0 IN SELECT TYPES WHERE

DepthOfCreateA “YourNamespace.Foo” == 1 AND

!HasAttribute “YourNamespace.AllowedToInstantiateFooAttribute”

 

  • Restricted
    use on assigning a field:

WARN IF Count > 0 IN SELECT TYPES WHERE

IsDirectlyWriting “YourNamespace.Foo.m_Field” == 1 AND

!HasAttribute “YourNamespace.AllowedToWriteFieldAttribute”

 

 

  • I don’t
    want that this code change (because it will be refactored for example):

WARN IF Count > 0 IN SELECT TYPES WHERE

CodeWasChanged AND

HasAttribute “YourNamespace.MustNotBeChangedAttribute”

 

 

  • Some assemblies should only contain interfaces
    (i.e, not a single lines of code):

WARN IF Count > 0 IN SELECT ASSEMBLIES WHERE

NbLinesOfCode > 0 AND 

HasAttribute “YourNamespace.OnlyInterfaceAssemblyAttribute”

 

 

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.bluespire.com/blogs Christopher Bennage

    I’m really finding these posts useful as I am trying to learn NDepend.Thanks!