Five kinds of dependencies

Dependencies are evil. They lead to domino effects and brittle plans. Instead of getting work done, they are the reason you can’t start just yet.

In project management, a dependency is defined as a relationship between two tasks. When Task A needs to be completed before Task B can start, we say B depends on A.

We try to avoid dependencies because they create rigid plans. If we’re blocked on task A for whatever reason, we also can’t start B. That severely limits our flexibility when it comes to planning. When Task A starts slipping, we create a domino effect on the entire chain.

The gold standard is User Stories that don’t depend on each other. These allow teams to prioritize backlogs with ease.

Dependencies might be evil, but they are also a business reality. You just can’t get rid of all of them. While we should aim to remove unnecessary ones, we should find ways to cope with the dependencies we do need.

Not all dependencies are equal. Some are easy to avoid. Others are inescapable. Here are 5 common types of dependencies and ways to make them work.

1. Functional dependencies

The example above is a classic case of a functional dependency. We need to build feature A before we can build feature B. These can always be avoided by splitting up or joining User Stories. Always. You can build that user overview screen without first building the user onboarding wizard.

There is never a good reason to keep functional dependencies in your plan.

2. Technical dependencies

Another common scenario is when feature B relies on some technical task A. Let’s say we want to send out nightly reports. Before building the first report, we must set up the infrastructure for running these nightly batches. But technical stories don’t deliver value to the user, and we run the risk of building that batch system without delivering a single report.

What we can do here is work with a pilot story: The first report we build will also include the technical set-up. While we can’t work on the first two reports in parallel, we can change which report to work on first. This guarantees that we deliver at least one valuable report and still allows us to be flexible.

Technical dependencies are unavoidable. The trick is to try and pack them with something that does offer value to the users.

3. Structural dependencies

Some dependencies don’t come from scope but from the organization. When a developer can only start working on a story after the wireframes are done, that’s a structural dependency. These kinds of organizations build a chained workflow, much like an assembly line. If one of the workstations lags behind, the entire machine grinds to a halt.

In these hand-off cultures, developers risk running “idle” because there aren’t enough User Stories “ready for development”.

A similar scenario can occur between two teams. The classic example is a front-end team waiting for back-end changes.

Structural dependencies have a debilitating effect on productivity and must be tackled whenever they arise.

Structural dependencies are hard to fix because they require a change in mindset and a reorganization of teams. Hand-off culture must be replaced with cross-functional teams, which takes time and experience.

Breaking these chains works magic for productivity, though.

4. Collaborative dependencies

Organizations with cross-functional teams aren’t completely free of dependencies either. While these teams can generally work independently, they sometimes need to collaborate.

Let’s say there’s a team for the shopping basket and a team for the payment engine. The company wants to offer payments via QR codes. While we could have the payment engine team build their API first, this creates a dependency. The shopping basket team can’t plan their work on the roadmap without guessing when that API will be delivered.

The best way to avoid these kinds of internal dependencies is by jointly designing the API interface. The teams build a mock API together before working on their own side of the fence. This interface will, of course, change during development, but that’s not a problem. Changes to the joint mock will impact the automated tests of both teams.

Tackling collaborative dependencies comes at the price of building that mock but kills a lot of the communication and coordination overhead. It also doesn’t start from a naive first-time-right contract but allows for new insights and evolution.

5. External dependencies

When integrating with external vendors, dependencies really rear their ugly heads. These plans are often driven by a deadline: the vendor will deliver their system by May 1st, so development can start on the 2nd.

If our plan relies on a delivery date by an external party, the entire timeline is in jeopardy! The best-case scenario is trying to turn this external dependency into a collaborative one. If the vendor builds a bespoke system, we might be able to negotiate a similar “mock API” approach as described above.

In most cases, this won’t be possible. We might be tempted to resort to buffers. “Let’s start development in July; surely, they’ll be ready by then.” This impacts the lead time and offers no guarantees. The only way to know if a buffer is large enough is to not burn through it.

The most pragmatic approach is often to build a one-sided mock based on the specifications and cover it with automated outside-in tests. We can run this test suite against our mock and the vendor’s staging environment to ensure both are in sync. This way, we catch changes and omissions early.

External dependencies are often tricky because many factors are out of our control. Relying solely on specifications and deadlines is too risky.

Avoiding or managing dependencies is key to reliable planning. Functional and Technical dependencies can be fixed by being creative with Jira tickets. They can be managed at the team level. Cutting dependencies truly becomes powerful at the organizational level.

That takes time and experience but is so worth the effort.