Visualize IoC Container and Domain Dependencies - Part 2
Let's talk about using Graph# project to visualize dependencies and relations in IoC containers and in enterprise solutions.
We'll start with exploring enterprise solutions; Autofac IoC users can scroll down right to the next part.
Explore Domain of Enterprise Solutions
Some time ago I wrote about using Microsoft Visio 2010 to visualize domain interactions that could be obtained via the reflection.
A few days after that post, my domain assembly got so big, that the visualized graph had turned into a rather complex picture.

Even the auto-layout algorithms of Visio 2010 were not able to make everything more understandable:

Fortunately, Google quickly helped to discover more specialized solution capable of solving the layout problem for the auto-reflected representation of your domain. If you use Graph# WPF control library from CodePlex, it will handle all the layout, overlapping and highlighting challenges, using one of the multiple algorithms it has.
That's how the dependency architecture of our DDDD/CQRS solution will look like after applying some auto-layout algorithms:

Implementing this is extremely easy. You just drop the control on your WPF form:
<graphsharp:GraphLayout
x:Name="_graphLayout"
Graph="{Binding ElementName=root,Path=GraphToVisualize}"
LayoutAlgorithmType="EfficientSugiyama"
OverlapRemovalAlgorithmType="FSA"
HighlightAlgorithmType="Simple"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
>
</graphsharp:GraphLayout>
and bind it to the graph of your domain interactions, using following methods to define it:
var g = new BidirectionalGraph<object, IEdge<object>>();
var dict = new Dictionary<string, Point>();
foreach (var message in messages)
{
var point = new Point(message.FullName, message.Name);
dict.Add(message.FullName, point);
g.AddVertex(point);
}
foreach (var consumer in consumers)
{
var point = new Point(consumer.FullName, consumer.Name);
dict.Add(consumer.FullName, point);
g.AddVertex(point);
}
Code snippets are based on the reflection data retrieved with Lokad.Quality assembly. For more details, see the previous article.
This will build the nodes using very simple visualization. Whenever you need to add a connection between the two nodes (edge), then the following code will do:
var sourceNode = dict[sourceType.FullName];
var targetNode = dict[targetType.FullName];
g.AddEdge(new Edge<object>(sourceNode, targetNode));
After repeating this for every connection, we just need to bind the resulting graph to some place, where the graphing control would find it:
GraphToVisualize = g;
The mentioned Point class is used merely for a simple render of nodes:
public class Point
{
public readonly string Name;
public readonly string FullName;
public Point(string fullName, string name)
{
Name = name;
FullName = fullName;
}
public override string ToString()
{
return Name;
}
}
We can also pick one of the layout, overlap and highlight algorithms to use, by binding their names to the appropriate properties of the graph. I've selected to use EfficientSugiyama for layout, FSA for overlap removal along with Simple highlighting.
Keep in mind, that this is just on of the many ways to represent relations between the elements of an enterprise solution. It is not the best, but how many other alternatives do you have; alternatives that could automatically and easily provide meaningful insight into the architecture?
Greg Young had suggested representing complex interactions as transitions of the state machine. This is a very useful approach to design and represent interactions in a reasonable way, indeed. Yet, this is a part of the design process and not something that is easily applicable to automatic reflection of the development codebase, after it had been delivered.
Explore IoC Container and Composite Applications
Yes, this approach could be used to visualize dependencies inside your IoC Container, too.
For example, let's consider Windows.Forms add-in to Microsoft Office Excel 2007, that is implemented as a composite application. This application will be composed of multiple components (some of which could be reused in the other applications as well) and employ Autofac Inversion of Control Container for dependency injection.
If we query the container for the dependencies, binding them to the graph, the following picture might show up:

After reflecting over the dependencies, we could focus on the individual relations. Highlighting algorithms will help us here, automatically coloring the adjacent nodes and relations.

As we can see, some ExcelTaskController depends on ExcelContextView, ExcelRepository and ExcelTask factory to do it's job. This controller, in its own turn, is used by ExcelContextController to handle some larger scope of work.
Ability to view dependencies makes the whole Inversion of Control thing a little bit easier, does not it?
It is surprising, how relations between IoC components (as in component-driven development) are similar to messaging interactions in the distributed enterprise solutions. This makes sense, since messaging is to the enterprise application as inversion of control is to the composite application.
More ways to represent the component dependencies meaningfully - the better. It provides additional insight into the domain and simplifies the design, refactoring and evolution
What do you think about all that? Do such representations simplify solution delivery for you?
Most likely there will be more posts on the topic. You can stay updated by subscribing to the RSS feed. You can also keep an eye on the xLim 4 research and development project, where this article belongs.
Related Posts:
Saturday, April 24, 2010 at 1:28