Skip to content

Understanding legacy code with NDepend

One of the facts of life for a freelance/contract software developer is that you often have to deal with working on legacy code bases a.k.a Brown-field projects.

Brownfield project is used in many industries, including software development, to mean to start a project based on prior work or to rebuild a product from an existing one.

Brownfield projects can be a lot of fun and rewarding to work on. They also require focus on enhancing and developing skill sets.

Over the years I have learned there is a myth perpetuated in the software development industry that, you always need to focus learning the latest new framework or tool that is hyped on twitter or discussed on Slack.

The truth is today's hyped framework or tool will be tomorrow's support issue and all Greenfield projects eventually evolve into Brownfield projects over time.

Software projects are primarily developed to target a specific needs and desires of it's users, and these needs can and will evolve and change overtime. In my experience even the users of applications will change, i.e. the system may have initially been designed to target human users but it has now needs to cater for mostly machine users.

The platforms your users will use to access your system will change, as technology constantly evolves.

Irrespective of how well or even how much effort expended in design and architecture of your systems, there will always be a need to replace huge chunks of your application logic.

In my opinion this is what makes Brownfield software development projects far more challenging, in respect you have to deal with decisions that were probably right at the time of implementation, but overtime have evolved into balls of mud.

Talk to any developer about another developers code, and they will always say they would've done better irrespective of whether they have seen the code

Many of the frustrations of working with legacy code mainly revolve around a few key areas.

Inconsistent Documentation

Most software project documentation is not worth the time reading, let alone writing in most cases. I'm not saying skip over this the step, because the most probable result in this is that it will result in a number of people losing their jobs 🙂

The reality is that there are often huge chasms between what is contained in the documentation as to what you'll find in the reality of code. Let alone the adventures a developer normally has to face to actually find the relevant documentation.

There may be some form of Document detailing what users may have originally expected from software, however what actually happens is that over time code usually starts to drift from it original intention, as further enhancements, improvements , bug fixes and support issues are raised.

Vital information regarding a specific code change may be locked away in a support ticket, or some other Issue tracking system that the company once had.

Code bases themselves tend to go on journeys and may change departments, vendors and even countries over time. The result of these migrations is that they will often change Source Control providers, issue tracking systems or even in some instances I have worked on never actually ever had an original source control system and things were just managed via access to shared folders.

Some of the worst people ever to ask to write documentation for software are the actual developers. For a few reasons:

  • Developers hate writing documentation
  • Most developers believe the code itself is documentation
  • Duplication of effort

People change

Despite the best of companies, it is an unassailable fact that the hardest thing to keep consistent on a project is people. People come and people go and at worst people die. What most of these people have in common is that they will inevitability take with them some knowledge of whichever system they are working on.

Over time changes in staff has an impact on the code base. Paradoxically, even if you projects to manage to retain the same staff on them, this also has a negative impact on the code quality.

How to understand legacy code bases

In my experience, one of the best ways to learn and understand a legacy code base, is to look for either week or vulnerable points within it and start to make minor repairs as you go.

This is where a Tool like nDepend NDepend - a static analysis tool for .NET managed code

Technical Debt

Gaining an understanding of the levels of technical debt within a project provides a view of difficulty and risks of implementing new features and enhancements.

Using NDepend, code rules can be written through C# LINQ queries. Applied on a code base a rule yields issues. A dedicated debt API is proposed to estimate both the technical-debt and the annual-interest of the issue through formulas written in C#. Both the technical-debt and annual-interest of an issue are measured in man-time.

Taking the opportunity to review and understand the areas of technical debt then removing the lower risk items and gradually building up as you go helps to add value to the code base.

NDepend Technical Debt
Sample Technical Debt Report

Dependency Graph

Having the ability to quickly generate dependency graphs. A dependency graph is a directed graph representing dependencies of several objects towards each other.

The Dependency Structure Matrix (DSM) is a compact way to represent and navigate across dependencies and coupling between components. A DSM is an alternative to viewing a dependency graph.

A Dependency graph is great way to review dependencies small subsection sof code and intuitive, However they can get unmanageable when analyzing a large code base The DSM lets you observe dependencies of a larger project at a glance all in on view but is not as intuitive. Once you know what you are looking for you can spot structural patterns at a glance.

NDepend offers context sensitive help to guide you options helping to break down information presented.

NDepend’s DSM relies on a simple 3 colour scheme for DSM cells: Blue, Green and Black. When hovering over a row or a column with the mouse, the Context-Sensitive Help explains the meaning of this colouring scheme.

Dependency Graph

The trick with working with the Dependency Graph is not run it on the entire solution, because you will end up with a dependency graph that looks lile this :

The key here is rather focus on reducing the scope of analyses and rather focus on project by project dependencies. Another trick I use is to create smaller Visual Studio solutions and include only the projects I am interested in.

The objective of this exercise is to find any cyclical dependencies or namespaces that are just too big.  This could be the first areas you can attack in the code base by maybe splitting code up in to smaller classes or namespaces.

I have found by doing this, I get to find areas in need of repair and also start to get the feel of how the application was developed over time.

Call Graph

A call graph is a control flow graph, which represents calling relationships between subroutines.

Using this information you can analyse the areas of high call relationships. This may present opportunities to review application pinch points or identify opportunities for library upgrades etc.

Using this in conjuction with the Dependency Graph slowly but surely helps to understand the code base.  Usually uncovering areas you can clean up.

Visualising code metric

The NDepend Metric View offers many capabilities to visualize an application code metrics. This way, code flaws and code patterns become more apparent. Such perspectives aim to enhance your understanding of the code base, to let you take better decision to increase code quality and code maintainability.

Summary

nDepend is a rich powerful tool to have in your arsenal and helps play a crucial role in understanding legacy code bases. Using it to help guide you through the phases of refactoring legacy code bases by removing areas of technical debt helps to start adding value to code bases while you gain a deeper understanding.

Latest posts by Gary Woodfine (see all)