The Essential Guide to Dependency Graphs

Eylam Milner
Aug 29 · 7 min read

When building legacy or cloud-native applications, codebases can quickly become entangled. This complexity becomes an issue when your teams add additional features, change existing parts of the application, or refactor it. These issues promptly reveal themselves when you deploy the application and are immediately followed by a mad scramble to diagnose what went wrong, fix errors, and roll back releases. This process is much simpler when you use a dependency graph for your application. This graph gives you a clear overview of each part of the codebase and how the different parts work with each other. 

To use dependency graphs, follow the steps in this complete guide. Soon you’ll gain more control over your codebase and see your deployments speed up.

What are dependency graphs?

According to Pablo Azero of Jalasoft, “A dependency graph is a graph that represents dependencies between objects of some application domain.” That is, it’s a tool that maps out relationships between the different components of an application. It shows both the connections and directions of the dependencies to help you visualize which components depend on each other. The following figure shows an example of a dependency graph.

Figure 1. Dependency graph for a tgmath.h header file in the C Programming Language; source: Wikimedia

Dependency graphs can also help map out specific components. For example, you can create a data dependency graph to map out data relationships. Or you might create a GitHub dependency graph to keep track of repositories on the GitHub platform. 

Why are dependency graphs important?

Dependency graphs help you manage code and applications better. How so? In any large application, the codebase becomes gnarled and difficult to manage. To achieve a high-level view of the components, you need to abstract the codebase. By doing so, you gain improvements in the following areas:

  1. Regression testing: By using dependency graphs, you achieve more predictable and successful deployments when you check for backward compatibility as application changes occur.
  2. Re-architecting applications: Viewing components and their dependencies gives you a vantage point to understand the components that require changes, are redundant, and are missing and must be added.
  3. Troubleshooting: You can easily trace across various components to find the root cause of an issue in a software system.
  4. Team collaboration: Sharing your dependency graph with your team helps everyone understand how your components relate to each other and gives them a common language to communicate with daily.
  5. Strategic application planning: You gain a broader perspective on each part or component when planning for the future of your application.
  6. Security posture of a system: You can see which dependencies make the system vulnerable. Without a dependency graph, these gaps otherwise become lost in code clutter.

7 steps to working with dependency graphs

Now that you understand what dependency graphs are and why you should use them, follow these practical considerations for working with a dependency graph.

1. Draw out your dependencies

Start your dependency graph on paper or another drawing surface. Nothing beats the simplicity of hand drawing to get your ideas from thought to reality. This approach is good for a brain dump of your initial thoughts and is also the fastest way to get started.

Eventually, you’ll need to move to a digital tool to handle the complex nature of your application. Although you can choose from many digital options, opt for an interactive and intuitive tool that shows multiple views for a dependency graph, such as a matrix view. This type of view is especially useful when you need to look at a complex graph from different perspectives to better understand it.

2. Visualize your dependency graph

A key aspect of a dependency graph is the ability to visualize it. If you can view the same graph in different layouts, you can greatly improve your understanding of your system’s architecture. The following example illustrates a visualization of a dependency graph.

Figure 2. Visualization of a dependency graph for refToolbar source files; source: Wikimedia

The tool you choose matters in its ability to render the same dependency graph in more than one way. It must automate visualization of dependencies and not do it manually. Netlify and nDepend are two tools that visualize dependency graphs well. Irrespective of the tool you choose, you must be able to view the same dependency graph in more than one way. 

3. Discover patterns and dependencies

After you visualize your dependency graph, identify and discover the different dependency patterns across the components. By exploring the various patterns and dependencies, you understand how your application functions and how to secure every part of the system.

GitHub generates its own dependency graph for any repository hosted on their platform. They gather data from the manifest and lockfiles and then map this information as a dependency graph. A GitHub dependency graph enables better security for those repositories. 

4. View and debug dependencies

A dependency graph maps out which parts of a system depend on which binaries. Larger and more complex applications have many dependencies. As a result, it can be difficult to identify why certain dependencies exist. 

Digital graphing tools help because they provide a reason for a dependency. Depending on the reason, you can then decide, when prompted, whether to continue to allow that dependency or remove it. This way, you can resolve dependency confusion, such as version conflicts, selection errors, and unsafe dependencies

5. Break up dependency cycles

At some point, you might need to change the structure of your system’s dependencies. For example, you might find redundant dependencies that you must delete. Or you might need to enhance dependencies to improve application performance. Regardless, you might need to change your codebase and can specify them to your overall architecture somewhere in the future. The process is much easier to manage with a dependency graph and results in a better performing application.

As you refactor your legacy application into a cloud-native application, break up dependencies into smaller, more modular parts. You do this step after decomposing an application from a monolith to a collection of microservices in the application layer. Similarly, you must break down dependencies, simplify them, and decouple them from each other

6. Secure and protect your CI/CD pipeline

A key reason to use a dependency graph is to better secure and protect your application. In particular, focus on your continuous integration and delivery (CI/CD) pipeline where your application is born and released to the world. 

By using a purpose-built CI/CD security solution, you gain end-to-end visibility into the CI/CD pipeline for powerful security of your software system. The CI/CD security solution must have the following capabilities:

  1. Provide a view of the different components of a CI/CD pipeline, such as GitHub repositories, a Jenkins server, or secret information like passwords and tokens.
  2. Surface any vulnerabilities in the components.
  3. Secure your components end to end. 

When used in combination with a dependency graph, this type of CI/CD tool gives you impressive control over how you build and ship software with the following capabilities: 

  1. Helps you enforce the principle of least privilege so that no component escalates its privileges and leaves the entire system vulnerable. 
  2. Scans plugins in a CI/CD pipeline and identify threats from open source and third-part plugins that are essential for the functioning of a CI/CD pipeline
  3. Secures your systems from dependency confusion attacks that originate from outside and leave your system vulnerable. 

7. Reduce the dependency attack surface

When you have a clear view of all dependencies, remove any unnecessary and risky dependencies. The goal is to have as few dependencies as possible, so you have a smaller attack surface—a foundational principle for security. Dependency graphs help you see all dependencies, but it’s up to you to make changes to improve and reduce the number of dependencies in your software system.

Secure your applications from version to version

Dependency graphs are essential for understanding how the components of your application relate to each other. By creating a dependency graph, you gain different perspectives and deeper insights into how your application’s components work with each other. Once you have your dependency graph, you can use it to improve your application’s testing, manage dependencies, and improve the security posture of your system. Finally, as you adopt dependency graphs to help manage your application codebases, secure and protect the integrity of your application throughout the DevOps CI/CD pipeline.

Eylam Milner
Aug 29 · 7 min read

Related Articles

Dependency Confusion: An open door to your on-prem

Modern software development and delivery is not done in a silo, on a single-developer machine. It is written in collaboration…

Eilon Elhadad
Sep 09 · 4 min read

The Essential Guide to Dependency Graphs

When building legacy or cloud-native applications, codebases can quickly become entangled. This complexity becomes an issue when your teams add…

Eylam Milner
Aug 29 · 7 min read

The importance of least privilege access in your CI/CD pipeline

There are many aspects to securing a software supply chain, and these keep changing and growing as technology advances. One…

Eylam Milner
Aug 23 · 5 min read

End-to-End CI/CD Security Platform

open source vulnerability scanner
Join our CTO in a thought-provoking discussion on software supply chain attacks with Cyberint
Join our CTO in a thought-provoking discussion on supply chain attacks