Have you ever had to work with a legacy codebase? Designing new functionality on existing applications can be daunting. There are always differences between the original design and the current implementation. The new Architecture tools within Visual Studio 2010 help you to understand the application you have, design new functionality you need, and validate that your design and your implementation do not deviate. In this post, we’ll look at how to understand the application that you have.
Software can grow complex very quickly. Whether you’re handed a legacy codebase that was created by someone else or you just want to get a better high-level view of the code that your team has produced, Visual Studio 2010 has some tools to help you better understand your code.
First of all, one of the biggest contributors to complexity is dependencies within your codebase. To better manage your dependencies, you can create dependency graphs of your existing code. Under the Architecture menu item, there is a option called “Generate Dependency Graph”.
When generating dependency graphs, there are three options. Collectively, these three options are called the “standard graphs”:
- By Assembly
- By Namespace
- By Class
Let’s walk through an example, using the .NET Pet Shop 4.0 codebase. Under the Architecture menu item, I’m going to click on Generate Dependency Graph, By Assembly. This will pop up a screen like this:
Under the covers, Visual Studio is making sure that everything builds, cracking open the assemblies, and building the graphs. Once it’s complete, this will generate a DGML file. DGML stands for “Directed Graph Markup Language”.
This diagram shows the dependencies between your assemblies. The thickness of the link line indicates the number of dependencies between the nodes; thicker lines indicate a stronger dependency.
You can navigate through the diagram using Ctrl + mouse wheel to zoom in and out, or right-click and drag a boxed selection to zoom in on that. When we drill in, it will show the namespaces that the assembly is dependent on (not all namespaces in the assembly), and we can drill down further to see the classes that your assembly is using too. This is an easy way to visualize and explore your dependency impact.
Notice the two pink-ish boxes near the bottom of the diagram. The orange-pink box is labeled “Externals” and the purple-pink box is labeled “Generics”. The Externals group contains all external dependencies that you have on code outside of your solution. The Generics group contains all generics in your solution; the generics were grouped together to avoid cluttering the diagram.
Let’s take a look at the PetShopWeb.dll node.
The “2” in the upper left-hand corner indicates that there are 2 sub-items. In the case of this diagram, it means that there are 2 namespaces within PetShopWeb.dll. You can expand the node and see them by clicking the chevron icon in the upper right-hand corner of the node.
Clicking on the PetShop.Web namespace to select it will also show you the dependency links (in purple) within that particular namespace.
You can also expand the PetShop.Web namespace to view the classes used by your assembly. Click the chevron icon in the upper right-hand corner of the PetShop.Web namespace node.
Finally, let’s walk through the right-click menu…there is some cool functionality in there. If you right-click on a node on the design surface, you will get this menu:
There are a couple of things in here worth calling out:
- You have the ability to export/save your diagrams in other formats.
- “Save As XPS…” gives you the ability to export your diagram into XPS format.
- You can use “Copy Image” to copy and paste your diagram into Word. (Note that just selecting the diagram and hitting Ctrl+C won’t copy the diagram into Word properly; you must use “Copy Image”. Ctrl+C will copy just the DGML markup as XML.)
- “Categorize” – you can tag and annotate your nodes. For example, if you find a node with a crazy number of dependencies, you could create a category called “Refactor” and then apply that category to various links or nodes. It also color-codes based on categories.
- “Analyzers” – these tools allow you to find circular dependencies, hubs, and unreferenced nodes.
Now, I’m going to clean up my diagram a little by deleting the “Externals” node. This shows just the code in my system. (Since I’ve expanded a bunch of nodes, I also right-clicked and selected “Group” then “Collapse All”.)
Now I can click “Quick Clusters” to see the assemblies that are at the heart of my system. The “Quick Clusters” icon looks like three little bubbles.
Clicking on it produces a view like this:
Now, just from looking at this clustering, I can tell that PetShop.Model.dll has a lot of code depending on it, so I can make smarter decisions. For example, if I’m triaging whether to make a change to that code and we’re fairly close to the ship date, I can make an informed decision that changing that code would be high risk to introduce bugs into the system, since there is so much other code depending on it.
You can also drill all the way into code from these diagrams. I’m going to expand the PetShop.BLL.dll, the PetShop.BLL namespace, and the Order class (using the chevron icons in the upper right-hand corner of each node). Now I can see the individual methods within the class:
Now I can double-click on a method (for example, the Insert method), and it will take me directly to the corresponding code. So you can navigate all the way to the code level.
A few final fun facts on dependency graphs:
- Out of the box, there is support for managed code only. However, there is a feature pack coming with additional support for web (dependencies between pages) and native code.
- They can crack any .NET 1.1 assembly or up. Yes, that is right. This functionality is *not* limited to just your new .NET 4.0 code!
- These graphs can only be created in Visual Studio Ultimate edition, but they can be viewed and navigated with read-only access in Visual Studio Premium.
- You can create dependency graphs on obfuscated assemblies, but the names will be funny since it’s parsing the IL.
- You don’t need the source code; you can pull third-party assemblies into dependency graphs. (Again, it’s using the IL to generate the graphs.)
- The DGML design surface is not available to rehost in your own applications. However, you can utilize DGML if you write a Visual Studio plugin.
- The diagrams aren’t added to your solution by default. One easy way to do this is to drag and drop the diagrams into the solution from the Miscellaneous Files in the Solution Explorer. To check if Miscellaneous Files is enabled, go to the “Tools” menu item in Visual Studio and select “Options…”. In the Options dialog on the left-hand side, expand “Environment” and select “Documents”. Check the box for “Show Miscellaneous files in Solution Explorer” (see below). Now the DGML file should be visible in the Solution Explorer, and you can add it to source control or whatever you like.
I’ve navigated all the way down to the code level, and now I want to get a better understanding of what this code does. One way that I can do that is to create a sequence diagram.
Right-click in your code and select “Generate Sequence Diagram…”. A dialog box will appear with some options, such as how many method calls deep to include in the diagram:
This generates a UML 2.1 sequence diagram.
It’s a visualization of your code flow. You can also add proposed changes to your design. For example, I might consider adding a method called ModifyPriceForRewardsCustomer. I can do that by right-clicking on the box from which my new method would be called, and selecting “Add” then “Synchronous Message” (or “Asynchronous Message” if you prefer). That will create a new message, which I can rename to reflect the method call. This is a good way to brainstorm, visualize ideas, and share them with others. Note also how when I add a new method, it appears in a different color (mustard yellow) to indicate that it is not implemented in the code (see below). This clarifies what does exist in the codebase and what does not. You can’t currently generate code from the sequence diagram.
The if statements are represented as combined fragments (in the little boxes). In UML terminology, a combined fragment specifies a group of lifelines/actors to show conditional flow in a sequence diagram.
Finally, the analysis to determine dependencies and call information when generating the Sequence Diagram from code is all done statically. That means we are not going to pick up types that were loaded dynamically at runtime.
There is full reference material on sequence diagrams at http://msdn.microsoft.com/en-us/library/dd409377(v=VS.100).aspx. Cameron also has done a few blog posts on sequence diagrams based on questions from the tour. Check out:
One last tool to help you understand your code is the Architecture Explorer. The Architecture Explorer lets you go spelunking through your code, and when you find what you want, then you can visualize it using one of the diagrams.
You can access the Architecture Explorer in Visual Studio by selecting the “View” menu item and then “Architecture Explorer”. In the Architecture Explorer (see below), the first window on the left-hand side gives me different views to choose from. I selected the Class View, which brought up the second window of namespaces. I selected the PetShop.BLL namespace, which brought up the third window of types/classes. I selected the Order class, which brought up the fourth window of members within the class. I selected the Insert method, which brought up its calls to other methods. In this manner, I can explore my code.
You can select the items that you are interested in, and then use the icons on the far left-hand side to create graphs based on the selected nodes or add the selected nodes into existing graphs. You can also build a query and save it into a DGQL (Directed Graph Query Language) file.
In summary, there are some amazing features in Visual Studio 2010 to help you understand, explore, and visualize your code. Stay tuned for tomorrow’s post where I will discuss how to maintain control of your software system.