Getting started with NDepend (part 2 of n) – Digging up Roots
A while back I posted the first in a series of post on NDepend – a static code analysis tool for .NET code. Today it is time to add a second post to the series. If you’re new to NDepend take a quick look at my previous post which should provide a decent understanding of what it can do…
I have an ASP.NET 3.5 ecommerce website running in production on the internet for a third party who will remain nameless. The site itself is based on the open source nopCommerce ecommerce application which originally allowed me to avoid the plumbing work and focus my energy on the implementation of features valuable to the customer. Since it’s launch it has done quite well and has required little-to-no maintenance on my part – a happy fact!
What I have noticed unfortunately is that I’ve (sub-consciously I think) avoided adding new features or performing any major refactoring since the site’s inception – based, I think, on the fact that the vast majority of source code is not mine and there is a relatively larger cognitive effort required when making changes. A weak excuse, I know, but an excuse nonetheless.
My goal is to refactor the code in increments, starting with a very high level refactoring – this post – in which unused assemblies/types will be removed permanently in order to make my codebase leaner. To help me on my way I will use the newly released NDepend 3.x to identify and remove dependencies.
Please note that I really like nopCommerce. However, when using an open source ecommerce platform is that what you gain in speed-to-market you lose in simplicity. Simply put, such solutions are one-size-fits-all and by proxy do more than is needed. I guess this is an example of KISS and YAGNI after the face as there is a TON of code that I am not using and will never use - and I’m going to remove it all. I’m not looking for performance gains (actually I’ve heard anecdotal evidence that suggests build times are impacted by the number of projects in one’s solution (and not just the total amount of code)…so maybe future builds will be a little quicker. YAY!) and know that the disk space savings are negligible. My goal is to reduce the size of the codebase to facilitate easier refactoring in the future.
While writing my previous post on the subject I was using version 2.x of NDepend – the most up-to-date version available at the time. Since then version 3.x has hit the shelves and it is a massive improvement to an already great tool. Right at the top of my wish list when writing that post was tighter integration of NDepend within Visual Studio. See the below excerpt:
While I definitely see NDepend as a standalone product rather than a VS add-in, I would love to have access to a number of its features within my regular workflow without having to switch between tools.
I’m happy to say that the NDepend team was way ahead of me. In version 3.x one can now access all of the NDepend functionality from Visual Studio – including writing and executing CQL queries and viewing dependency matrices and graphs. While I’m using Visual Studio 2010 the same functionality is available in VS2005 and VS2008 and is awesome!
For this post I have identified two project within my solution that I do not need. The fact of the matter is that due to the nature of the ecommerce store shipping via UPS and/or USPS is impossible. I will never use this code. Ever!
On a side note, even if there was a chance that I would use this code in the future I would still remove it – it is redundant, plain and simple. I can always go to source control later in the unlikely case I do need it…
Right-clicking on either project in visual studio presents me with a plethora of options and I’m most interested in seeing which types are directly using these assemblies.
Choosing Select Types->…that are using me (directly or indirectly) the CQL Query Editor pops up, pre-populated with the relevant query. The query is executed and interestingly it tells me that Nop.Shipping.USPS is not currently used by any assemblies. See below…
There are no dependencies on Nop.Shipping.USPS. Therefore the project can be permanently removed from my solution. The project itself is tiny with only 138 lines of code and 3 types, but it is a little less than I need to maintain.
It seems a little strange to have an assembly that isn’t used, but looking at the metrics for this assembly in the NDepend Info view we can see that Afferent coupling is zero (Afferent coupling expresses the number of namespaces that depend on the namespace in question whereas Efferent coupling expresses the number of namespaces the namespace in question depends on), lending credence to our original finding that this assembly is unused.
Taking a quick look at the dependency matrix (which I’ll come back to in a bit) I can see that the Nop.Shipping.USPS assembly depends on 6 namespaces within the Nop.DataAccess assembly – but there are no dependencies on Nop.Shipping.USPS itself.
At this point I’m comfortable that I can safely remove Nop.Shipping.USPS from my solution and I’m 138 lines and one whole project lighter.
[Aside: The version of NopCommerce I originally used did not bundle any unit tests, therefore I’m flying a little blind. I can confirm that the solution builds but runtime errors are still possible. Right about now I would LOVE some unit tests for my solution]
I’m done with USPS but now it is time to move onto it’s sibling UPS. We’ll take the same approach as before, but this time there should be a bit more meat (I got a sneak peak and know that this assembly is used!).
As usual I use the Select Types->…that are using me (directly or indirectly) shortcut to get a high level overview of what is going on. This is about the quickest step to getting up and running and makes it easy to get a high level idea of what I’m getting myself in for (i.e. should I wait until after lunch?)
This time my results are a little bit different and I can see that one assembly depends on Nop.Shipping.UPS (i.e. afferent coupling is 1). Changing the CQL query a little bit I can query the same dependency on a type and method basis and see that a single type and 4 methods depend on Nop.Shipping.UPS.
Looking at the methods that use this assembly directly, we see that the depth of using is 1 for BindData and Save, but 2 for Page_Load. This means that Page_Load has an indirect dependency on this assembly, and BindData and Save have a direct dependency. Based on the method naming (specifically Page_Load) we know that this type is in fact the code behind for an ASPX page.
The next couple of steps are technically unnecessary but I like to be well informed – especially before removing code – and look at a couple more views. Copying the assembly to the Horizontal header of the data matrix i am able to drill down very deeply and see that it is indeed being used by two methods in the ConfigureShipping type in the NopCommerceStore assembly.
Looking at the above screenshot it is clear that the ConfigureShipping type is specific to UPS shipping (look at the namespace) and specifically is a function visible only from the administration section of the site (again, look at the namespace).
At this point I jump to the source code by right-clicking on the ConfigureShipping type and choose “Open one of my 2 declarations ins source code (double click)”.
At this point I see exactly what I suspected – this is indeed the code behind for an ASPX page and the page itself is specific to UPS shipping configuration (rather than being a more generic and encompassing shipping page).
At this point I know the following:
- Only one assembly uses the Nop.Shipping.UPS assembly
- Within that assembly only one type uses type uses the Nop.Shipping.UPS assembly
- The type is the code behind of a very specific ASPX page
Before removing this assembly there is one thing I need to know:
- Is this ASPX page ever used?
The answer to this question is: no, the ASPX page is never used. I know this because I originally removed all ties to shipping configuration from the administration section of the code. I could confirm this in two ways 1) Using NDepend, use the matrix view to look at dependencies on ConfigureShipping. This follows the exact same approach as we used above so I won’t repeat myself 2) use another tools (I use Resharper right now…Find Usages Advanced specifically) to find usages of the page itself.
At this point I am ready to remove the ConfigureShipping page itself as well as the Nop.Shipping.UPS assembly.
This was very much a 101 level introduction to removing un-needed code with NDepend. While writing this post took some time, removing the code was extremely fast – between 5 and 10 minutes. Everything I did was inside Visual Studio and I never had to switch context – for me this is a massive improvement over the previous version of NDepend which I really liked. For the save of 10 minutes I removed about 500/600 lines of code – including an ASPX file (basically an entire namespace) and two assemblies.
My plan for the next x number of posts in the series is to ratchet up the difficulty level incrementally and start refactoring code with more wide-spread dependencies. Stay tuned!