What is dependency analysis?
Dependencies are the relationships that exist between the constituent parts, or entities, of a complete system. A single dependency represents a directional relationship, and therefore a sequence, between a pair of system entities.
For example, if the system were a journey, there might be a walking dependency from a flight to a taxi. If this is applied to a software context, in a codebase, a function may depend on (invoke) another function. As you can infer, dependencies can have types, or behaviour, as well as a direction, indicating how the transition occurs and in what order. Dependency analysis is the process of extracting the set of entities, their dependencies and their types and direction, from the system so that the system structure can be analysed, understood and improved.
Why use dependency analysis?
A codebase may have been initially designed with a modular or layered architecture, but over time, that clean structure could have been eroded, introducing unexpected coupling between elements, which can damage or even destroy the architectural intent. This can lead to ongoing development or maintenance of the codebase becoming more complex and time consuming to do, which can result in additional errors and complications creeping into the code. The longer these problems go unchecked, the more the problems can be compounded into the codebase and therefore more expensive in time and money to address. Beyond dependency analysis tools providing a way for you to address such problems, they may also offer the ability to enforce structural rules dictating how the different modules/layers or external entities such as third party libraries may interact with and within the system respectively. Once in place these rules typically allow the codebase to be automatically checked for adherence and where violations are detected, notifications of said problems can be immediately brought to the attention of team members so the problems can be more quickly identified and addressed before the issues become too embedded.
Software architecture evaluation and refactoring should be a standard activity in any development process because it is a way to reduce risk. It is relatively inexpensive, and it pays for itself in the reduction of costly errors or schedule delays. As software teams grow and/or become more distributed, understanding software architecture becomes even more vital. Dependency analysis allows everyone on the team to have a clear understanding of the architecture (what components depend on other components, etc.).
Technical debt is a common concept in modern software development practices that happens when there is no core set of well-defined and enforceable design rules for a code base combined with a culture that does not value creating technical wealth. By establishing and iteratively improving design rules, using dependency analysis, technical debt is paid down and the code base is easier to understand and maintain. Development accelerates and this establishes technical wealth.
Automatic impact analysis, a feature of dependency analysis, will highlight which parts of the application will be affected by planned codebase changes, such as replacement of modules or third party libraries. Understanding the impact of changes enables teams to quickly and accurately respond to change requests. With impact analysis, teams can be responsive while maintaining control over scope and customer expectations. Impact analysis helps developers calculate the impact of change.
What to look for in a dependency analysis tool
Complex systems can make analysing and understanding the implementation challenging. It is therefore important to look for tools that support multiple languages and provide visualisations that are interactive and simplify the tasks at hand.
How does dependency analysis work?
From the perspective of software dependency analysis, there must be an initial parsing phase to gather all the data. There can be different qualities of parsing depending on the approach taken. Some approaches rely on a scan of directories containing the codebase in question whilst other mechanisms exist where the codebase is compiled, resulting in a more complete and precise picture. Once the “database” of information exists, it is loaded into some tool that provides a suitable way of visualising the structure of the codebase, and functionality to assist the user in understanding and improving the architecture.
Dependencies can be extracted using a variety of tools and techniques depending on the language or software that is being analysed. This can be as simple as scanning directories for languages such as C# or Java, to using static analysis tools for languages such as C and C++.
Most enterprise class dependency analysis tools have more than one import mechanism for dependencies. This will generally include a number of different supported languages, possibly with the ability for the definition of custom import processes.
Once you have the data imported dependency analysis tools allow you to interact with the dependencies to visualise the implementation against a ‘reference’ architecture. Features such as impact analysis and change logs can be used to help ensure there is no ‘architecture creep’ in the implementation.