In my first post of this series, I broke down the VSTS 2010 Architecture product into "functional" areas, and I've been slowly describing the pieces. The areas highlighted ( Modeling Project here and here, Model Explorer, and Work Item Integration ) I've already discussed at some length. Today, I want to drill into the Layer Diagram a bit more. Specifically, I want to walk you through the steps of creating a simple Layer diagram, map your code onto it, and validate that code against the constraints authored in the diagram via a manual validation gesture. ( In a future post I'll show you how to automate validation in your build process. )
For this post, I'll be using the VSTS 2010 CTP.
In this example, I'm going to be using some very simplistic code, as it is not the details of the code that I'm trying to emphasize, but more the concept the code represents. Let's get started...
So what does this program do at this point? Well, actually nothing except instantiate a type, call a property on that type, throw a "NotImplementedException", then exit. Not that interesting, but also not the point. This is just setting the stage for a very common problem found in systems of all types.
This code is pretty typical of code that is early in its evolutionary path. We've got a client program accessing the specific implementation of an interface directly. This is fine for now, as all the program needs is the data that "DataRetriever" was designed to retrieve ( imagine DataRetriever pulling from a SQL database for instance ). But what about tomorrow when a requirement hits your desk, demanding data to be pulled from a different data source without changing the behavior of the rest of the application?
What we need is to *not* make any assumptions on *how* an interface is implemented, and depend *only* on the contract of the interface(s) itself. Again, a fairly common design pattern, but one that is pretty easy to violate in today's world, as it takes but one line of code to break this pattern and create dependencies that were not intended. This is what various IoC containers are out to help mitigate.
So how do we enforce this design in our code, protecting the intent of that design, and ensure our code is resilient to this type of breakage? Enter the Layer Diagram and Layer Validation.
Let's create a Layer Diagram where we will visually describe the constraints on our architecture that we want to maintain.
Back in Program.cs, we need to make sure that we are only using types out of the "Interfaces" project, or more importantly, *not* use types out of the "Implementation" project. That's all well and good, but we need a way to get an instance of an object that implements IDataRetriever without taking a direct dependency on that type. Enter the Factory pattern.
I've shown you, through an admittedly trivial example, how to validate your solution through a simple Layer diagram. I've shown you how to map source onto the layers and how to tell the system what dependencies are valid and which are not via a manual gesture and that diagram.
There is much more to show on this diagram and how you can interact with it. A very important next step is to show you how to make the Validation action an automatic step in your build process. I'll do that in a future post.
Stay tuned! :)