Modeling components of a code base with namespaces is a much better idea than modeling them with assemblies. I wrote about the namespaces vs. assemblies debate in the past (Control components dependencies to gain clear architecture). The fact is that namespace is a logical artifact while assembly is a physical artifact. Of course, creating assemblies to partition parts of the code that at runtime physically don’t live within the same AppDomain is a good thing. I explained that in Advices on partitioning code through .NET assemblies. Unfortunately, the vast majority of .NET teams use assemblies instead of namespaces to partition logically their code. They end up with hundreds of Visual Studio projects:
- Hundreds of VS projects organized through dozens of VS solutions is something hard to manage.
- These hundreds of projects takes a lot of extra time to be compiled (because of the repetitive tier assemblies parsing). By extra time I mean that the compilation takes minutes instead of seconds!
- And finally, loading all these assemblies at runtime slow down consequently the startup time of applications. Indeed, doing so multiply the unit overhead that the CLR needs to load an assembly. The overhead is mainly due to CAS security checks, cryptographic signing check, and IO file read.
In order to model logical components, the logical nature of namespace is a preemptive advantage over the physical nature of assembly. However namespace have a second awesome characteristic: they can be declared hierarchically. So namespaces can be use to modelize a hierarchy of components. Today I would like to ramble on some consequences and caveat of organizing hierarchically components.
Theory: Tree vs. Flat view
This hierarchical way of componentizing code is something that we took account early in the NDepend development. At any time, the user can choose to display namespaces through tree (i.e through a hierarchy)…

…or to display flat namespaces:

Personally I prefer the tree option. After all, why do developers naturally partition the code? Because of the need to organize code and API through some smaller chunks. Smaller chunks are naturally easier to develop, understand, maintain, test and debug. This is the famous divide and conquer tenet.
But when the code base is consequently growing developers are facing a dilemma:
- Smaller components are easier to be managed one by one. But this implies to deal with hundreds of components. As a consequence the big picture becomes messy.
- Keeping a small number of components force to have large components. While the big picture remain understandable, larger components are harder to manage.
This is why developers apply recursively the divide and conquer idea. As a result, they obtain a hierarchical organization of code.
Practice: Tree vs. Flat view
These 2 dependency graphs illustrate well the point. The first one is made of the 52 namespaces declared in the mscorlib (this is the flat view).

The second one is made of the 16 root namespaces of the DLL mscorlib (this is the root tree view). The root tree view present less information than the flat view, but at least it is readable.

Moreover the root tree view is a good start to dig into the code and browse nested namespaces inter-dependency:

The same phenomenon appears with the Dependency Matrix. The root tree view (first matrix) is a better way to browse the code than the flat view (second matrix).


Component Hierarchy and Dependency Cycle
Avoiding cycles between components is an essential point to care for, in order to keep a code base maintainable. I detailed that in the post: Maintainability, Learnability, Component, Layering. When components are hierarchically organized, some non-trivial cycles can appear. Let's look at a small example.
If we look at the dependency between the 3 following namespaces we won’t find any cycles:
namespace ParentA.Child1 {
public class ClassA1 { private ParentB.ClassB m_Field; }
}
namespace ParentA.Child2 {
public class ClassA2 { }
}
namespace ParentB {
public class ClassB { private ParentA.Child2.ClassA2 m_Field; }
}
There is no cycle, this is clear from the flat dependency view,

This is what I called a non-trivial cycle because a cycle exists while there are no cycles between namespaces. The fact is that RootA.* is not considered as a namespace because it doesn’t contain directly any class. In our internal NDepend terminology we named RootA.* a namespace container. Technically your code is entangled and contain a cycle even if physically there is no cycle between namespaces!

Hierarchical components constitute a powerful way to partition code but be aware that some non-trivial entangling cases might appear. In a next post, I’ll expose a cool way to use hierarchical componentization effectively in the real world.
Posted
Mon, Oct 26 2009 4:49 PM
by
Patrick Smacchia