Dependency management has always been hard. One of the best illustrations of the problem is Microsoft’s aptly named “DLL Hell.” Back in the 1990s and early 2000s, Microsoft products were built with the Component Object Model (COM). COM was a complex system. Still, one of its benefits was the ability to expose an application programming interface (API). Integrating API functionality in other applications was done via Dynamic Linked Libraries (DLLs).
For example, you could use the DLLs provided by Microsoft Office. You could then use Word and Excel to generate and format reports. As long as all the applications on a Windows PC ran the same version of any given DLL, it was a fantastic solution. The problems usually started when different applications required different DLL versions. This at best, would crash the application you were using. At worst, it would crash your entire system.
Following the launch of the .NET framework, the nightmare of DLL has almost completely disappeared. There are still many contemporary examples of similar issues. Current development practices emphasize breaking your project down into the smallest possible units. Here is the problem with this approach. Modules and their external dependencies function differently when tested in isolation. They function differently when integrated into their host system. At best, this causes minor delays that can be quickly fixed. At worst, it leads to system-wide failure, missed deadlines, major cost overruns and damaged reputations.
Dependencies: Definition & Types
Let’s start by defining what is a dependency.
A dependency is something you rely upon to achieve a goal but that is not under your control. Project dependencies come in many shapes and sizes. They include hardware, software, resources, and people. Your software project will rely on a large number of dependencies, regardless of the size of the your technology stack, or the available human and financial resources.
It is tempting to look at each dependency as a single independent unit. However, this type of isolated dependency is rare. In general, each dependency is part of a complex web of interconnected relationships that is hard to untangle. Let’s look at three common types of dependencies and how to resolve them.
A functional dependency entails the components, assets, or resources required for a project to function. Functional dependencies are the result of the tasks and activities required by a business to achieve a desired outcome. The best way to resolve issues caused by this type of dependency is to identify them. Next, build a list and organize the list in order of importance. Then, decide which dependencies are redundant or no longer needed. Remove these from the project.
If you need a dependency that is still in development or unavailable, you can use mocking techniques. For example, if your component depends on an external API, you can simulate the API calls and responses. Continue to develop and test your component, until the component is available. You can also rewrite your project requirements to remove the dependency and any related issues.
Developmental and Testing
These dependencies are components, assets, or resources required to build or test a project. Development and testing could be viewed as separate processes, but modern approaches of agile, shift left, and continuous testing view them as a single unit. Development and testing processes are subject to functional dependencies. They are also heavily reliant on the quality of available human resources.
Different team members have different levels of skills and experience. Teams often depend on the expertise of individual people. This works as long as each person remains a member of the team. Team members who are absent for an extended period or leave the organization, leave a void that can be hard to fill.
You can resolve these dependencies via training. Ensure all team members can handle the roles and responsibilities of other team members. Remove any risk of your teams becoming reliant on key individuals to handle critical tasks.
At the user-story level, complex scenarios will often have their own internal dependencies. For example, a user story that involves multiple actors who have individual dependencies. The story could also involve a number of steps that are performed in sequence but depend on the completion of previous steps to be implemented or tested. These dependencies can be resolved by carefully reviewing each story, identifying key actors, and deciding which are relevant and which can be removed. Breaking the story into steps, each step represents a single task. This will help you locate and remove unnecessary dependencies. Instead of creating unique tests for each user story, catalog your existing tests and, where possible, map them to new stories.
Operational and Non-functional
These are components, assets, or resources required to operate, deliver, or deploy a software-based project. This can entail any component that is required to perform operational tasks but is not an integral part of the product, such as applications, web services, and data stores. A common type of operational dependency relates to network infrastructure, management, and security policies. It also includes any deployment and operational-related performance and load testing, management, and monitoring.
Often, operational requirements are hidden within functional requirements and user stories. It is not uncommon for implicit operational dependencies to become apparent in the later stages of a project. These dependencies can be resolved by creating policies, writing detailed documentation, and deploying tools.
Resolution: Dependency Mapping
No matter the cause or type of dependency, they can all be managed through dependency mapping. Although each type of dependency requires a different type of mapping, the process of creating maps is similar and each type will have major long-term benefits.
Start the process by identifying the relevant dependencies. For functional dependencies, you need to identify stakeholder relationships, functional requirements, and technologies. Development and testing dependencies require identifying the team members, their roles, and their responsibilities. At the user-story level, you need to identify the actors, user stories, and available tests. You could also use it to create a combined map that shows user stories along with the team members assigned to code and test them. Operational mapping involves identifying operational resources, such as applications, networks, security domains, and the relevant hardware and software.
You should map dependencies using the method that best suits you, your organization, resources available, and budget. Most dependency-mapping projects start by making physical maps with whiteboards, index cards, and sticky notes. More advanced mapping can be created by using the systems for managing requirements, documents, tasks, backlogs, and testing. These methods work well for all the dependency types described in this article. When it comes to non-functional/operational dependencies, there are a large number of monitoring and mapping tools that can help.
Conclusion: Manage Dependencies by Mapping
Each type of dependency applies to a given project’s components, assets, or resources required as well as to a different domain. It is important to identify and resolve requirements as well as understand the ideas, processes, and benefits of mapping—and managing—the different types of dependencies.
Panaya’s Release Dynamix [RDx] is a complete solution for managing and releasing software-based systems and applications. It lets you manage all your projects in a single location, track each one to show dependencies on the project, team, and organizational level, and have the power to manage each of them. This tool lets you manage policies and processes as well, including IT governance, requirements, testing, releases, and risk assessment.
Release Dynamix is simple to use and features powerful graphics along with the tools required to analyze projects across an enterprise as well as map entities and their connections to show you where dependencies exist. These insights will help you manage your software development and release processes and also control internal and external dependencies. Specifically, RDx maps out all internal and external dependencies, making them transparent and enabling you to successfully locate and resolve them.