Dependencies and Concerns

Jim Bolla, a contributor to the NHibernate project, had a surprising remark while describing what NDepend has to say about the NHibernate code on its blog: 

(with NDepend) as an example, you can do stuff like this..

WARN IF Count > 0 IN SELECT METHODS WHERE IsDirectlyUsing “System.Web” AND IsDirectlyUsing “System.Data.SqlClient”

And you will get a result set of any methods in your project that are doing web stuff and SQL stuff in the same method! COOL! Now you know which n00b programmers you need to go slap mentor. In other words, you can define NDepend CQL queries to find methods that violate the Separation of Concerns principle.

 

The cool part is that using CQL constraints to enforce Separation of Concerns principle is something that we (the NDepend team) didn’t think about. Basically, tell me what you use and I can tell you what you are concerned about. This is a great idea! CQL comes with the direct dependencies conditions: IsDirectlyUsing / IsDirectlyUsedBy. For example:

// Which methods are directly calling a particular method
SELECT METHODS WHERE IsDirectlyUsing “MyNamespace.MyType.MyMethod()”


 


These conditions works on Assemblies/Namespaces/Types/Methods/Fields (ANTMF) and you can mix domains for example:


// Which assemblies are directly using a particular method?
SELECT
ASSEMBLIES WHERE IsDirectlyUsing “MyNamespace.MyType.MyMethod()” 


 


// Which types are directly used by a particular assembly?
SELECT TYPES WHERE IsDirectlyUsedBy “MyAssembly”




// Which namespaces are directly using a particular field?
SELECT NAMESPACES WHERE IsDirectlyUsing “MyNamespace.MyType.m_Field”


 

You can mix these conditions with all CQL facilities for example:

SELECT TYPES FROM ASSEMBLIES “MyAssemblyA” WHERE IsDirectlyUsing “MyAssemblyB”


 


Or:

SELECT METHODS OUT OF NAMESPACES “MyNamespace” WHERE IsDirectlyUsing “MyType”

 

As pointed Jim, you can enforce some separation of concerns by mixing several direct dependencies conditions in the same constraint. Alternatively you can also make sure that an API is used as it should be. Often there are situations where doing something implies doing another things. For example this constraint warns if a method tries to delete a file but is not using the class IOException:

WARN IF Count > 0 IN SELECT METHODS WHERE
IsDirectlyUsing
“System.IO.File.Delete(String)” AND !IsDirectlyUsing “System.IO.IOException”


 


You can also readily write any kind of constraint to force the use of interfaces instead of classes:


WARN IF Count > 0 IN SELECT METHODS WHERE
IsDirectlyUsing
“MyNamespace.MyType” AND !IsDirectlyUsing “MyNamespace.IMyInterface”


 


The following constraints warns when a method obtains a Graphics from an image and doesn’t call the Dispose() method:


WARN IF Count > 0 IN SELECT METHODS WHERE
IsDirectlyUsing
“System.Drawing.Graphics.FromImage(Image)” AND !IsDirectlyUsing “System.IDisposable.Dispose()”


 


 


If you are developing a framework, you can build a set of such constraints that your clients should applies to make sure that they are using your framework correctly.


 


Another use of mutiple IsDirectlyUsing conditions is to guess where an API should be used. For example, this query matches methods that are changing some states and that are not using any synchronization API:

SELECT METHODS WHERE !(
   IsDirectlyUsing
“System.Threading.Mutex” OR
   IsDirectlyUsing
“System.Threading.Interlocked” OR
   IsDirectlyUsing
“System.Threading.Monitor” OR
   IsDirectlyUsing
“System.Threading.ReaderWriterLock”) AND
(
ChangesObjectState OR ChangesTypeState) AND
!(
IsConstructor OR IsClassConstructor)

 


Another idea is to make sure that the layer represented by the code in the namespace MyNamespace  is not entangled with any other namespaces (i.e has no bi-directional dependency with any other namespace):

WARN IF Count > 0 IN SELECT NAMESPACES WHERE
IsDirectlyUsing
“MyNamespace” AND IsDirectlyUsedBy “MyNamespace”

 


I will certainly post more on these. Thanks to its flexibility CQL offers a wide range of possibilities to explore!

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://icelava.net Aaron Seet

    How to check which methods/types of from an assembly is using a set of low-level framework assemblies?

    We have many framework assemblies “company.system.framework.*” and don’t want to manually type out each and every assembly.

    Also would like to see which framework types/methods those top-level methods are using.