Friday, January 6, 2012

Web Client Software Factory vs. Code Metrics


I’ve been building a web application with the Microsoft Web Client Software Factory (WCSF), and it has an interesting default option.  The option is to put interface definitions in an assembly separate from the implementation when creating a new module.  This will generate 2 projects for each module, which means at least 2 namespaces, if you don’t change anything.  This post will investigate whether the code metrics generated by this approach, specifically abstractness and instability as defined by NDepend, are worth the increased maintenance compile time.

The option can be seen here when creating a foundational module in WCSF:


WCSF also presents this option when creating a business module, although it still places the interface for the module controller in the “concrete” project, not the interface project.

The effect is that you’ll end up with 2 new projects, as seen in the picture above; Blah, and Blah.Interface.  The thinking is that the projects that use the services of the module need reference only the interface project.  Dependency injection will take care of locating the actual implementations.  A rather high-minded architectural choice, especially considering that for foundational modules WCSF doesn’t even add a reference to the interface project to the web project.

Let’s say you follow the intention, though, and add some interfaces to Blah.Interface, some services that implement them to the Blah project, and some views in the web app that use the interfaces.  WCSF’s behaviour aside, what’s of real interest to me is how NDepend scores these 2 projects on the abstract/instability graph:


Blah is right near the WebClient5 assembly.  It’s perfectly instable, meaning no types depends on its types directly, and perfectly concrete, or non-abstract, because it has no abstract types.  It just implements abstract types.

Blah.Interface is perfectly abstract because it has only abstract types, and is very “stable” because while lots of types depend on its type, its types (interfaces) do not depend on anything else.  (NDepend claims Blah.Interface has 1 external type dependency, but I don’t know what.  If I eliminated this dependency then Blah.Interface would be perfectly stable.)

Now, compare the graph of the same project refactored to merge Blah and Blah.Interface:


Blah’s abstractness has increased and it’s “stability” has decreased.  These in themselves don’t mean much, but their relative values are still well within the area closest to the ideal dotted line. 

Given that NDepend suggests that this approach won’t result in pain or uselessness in this simple case, I conclude that the 2-project approach is not worth the extra maintenance.  This approach should be used only when it solves an actual problem, not by default for every module.

No comments:

Post a Comment