A while ago, I wrote about different kinds of dependencies we encounter when building software products.
And of those, structural dependencies are by far the worst. They are detrimental to team productivity and take real effort to fix. A team has a structural dependency when they must wait for others to complete work before being able to start.
The typical example is a frontend team that's blocked until the backend team delivers their part of the solution. This creates a chained workflow, much like an assembly line. Workstation two can't start until workstation one ships.
As long as the first team doesn't release its code, the second one can't start tackling the problem. They can do all kinds of other unrelated work, but they can't focus on the problem they want to solve before the API is available. This kind of serial collaboration isn't very productive and leads to long delivery times.
But there's more. Structural dependencies create rigid plans. For every problem we try to solve, two teams need to be involved. If the backenders need to prioritize another problem for some reason, the frontend team's plan is also impacted. This kind of ripple effect makes our plans brittle.
Finally, if the frontend team discovers limitations or wrong assumptions in the delivered API, the problem ends back on the first team's desk. It's naive to believe in first-time-right. As a result, we're used to seeing a lot of wasteful ping pong between two teams in such a relationship.
It's clear to see why this kind of structural dependency is bad for business. They must be broken whenever they are found.
But that's easier said than done. How do you break structural dependencies?
While there is no simple one-size-fits-all solution, I want to discuss a few typical examples and ways to mitigate those.
Backend and frontend team
It's a classic, so let's start with this one. Grouping developers by skillset creates a structural dependency. The work typically gets serialized. Not only does this lead to longer delivery times, brittle plans, and rework, but it often results in an inferior product, too. Conway's Law states that the team organization influences product design. "If you have four groups working on a compiler, you'll get a 4-pass compiler". If you have a frontend and a backend team, you'll get two apps that kinda work together.
The way to fix this is to build your teams around products, not tech skills. Such a cross-functional team can collaborate on the same problem without the need for handovers. It's important to note that this doesn't mean everyone should be a full-stack developer. Front-end developers can pair program on problems with their backend teammates. This kind of collaboration is much more efficient than ping pong. It increases knowledge sharing in a team, leading to less compartmentalization.
Creating teams around products is the best way to break structural dependencies among developers.
Designer handover
Another typical example is the relationship between designer and developer. If you have a scenario where designs need to be finished before the devs can start, you have a structural dependency. It's similar to the frontend/backend division. Teams are grouped by skill set, not product.
So, one solution would be to add the designer to the cross-functional team. But this isn't always possible. Often, designers are shared among multiple teams.
In such cases, design systems and component libraries are the way forward. Instead of designing every page in Figma and then coding pixel-perfect implementations, it's much more productive to create or buy a set of reusable components. That way, mockups are trivial to implement, and feedback-driven change is easy to incorporate. Developers can build interfaces without having to wait for the designs.
Productive dev teams solve problems rather than implementing solutions. That doesn't mean they can just start coding whatever they want. But, organizations need to avoid the mistake of spelling out what developers must code. That's a structural dependency. Instead, opt for systems that involve developers in the solution design. This applies to all the work that typically fell into the design or analysis phases.
Platform teams or operators
There was a time when developers handed their packaged deliverables to the operations guys, who installed them on a server. The handover to ops might be the mother of all structural dependencies. Operators had to wait for the developers to ship their increment before being able to do their work. When things invariably went wrong, the feedback loop was dreadful.
With the rise of the DevOps movement, we've seen the industry evolve towards developers pushing to production. This is a boon for productivity.
But the operations landscape is complex, with its Kubernetes and its Terraforms and those serverless servers. It's unreasonable to expect developers to be up-to-date with all those technologies. Let's not even mention cybersecurity and compliance.
So, these days, we often see "Platform Teams" abstracting this complexity away.
Platform teams are great if they really build a platform. That means building tools that empower the developers to ship. But more often than not, these teams are just operators with fancy business cards. If a product increment can't be shipped without passing through the hands of the platform team, you got yourself a structural dependency.
Any handover between "done" and "released" is a scenario that requires scrutiny. Make sure the platform team builds internal tools for dev productivity rather than installing increments on servers.
With these common scenarios in mind, it becomes easier to detect structural dependencies. When a team's day-to-day work depends on the skills of another team, you've spotted a live one.
These kinds of dependencies often look a lot like handovers. The PM who needs to write tickets before the devs can code. The "to test" column that collects User Stories.
Structural dependencies work fine in a phased project approach. It's okay to involve the developers only after the requirements and designs are finished. That's a valid approach for certain scenarios. But it's Iron-Triangle-style project work, and we all know the limitations of that model. If you choose the tools of agile software development, structural dependencies are the enemy. They create brittle plans, inter-team ping pong, and wasteful delivery.
Agile software development with structural dependencies is the worst of both worlds.
Spot them and break them as fast as you can.
Here’s a true story: a program taking 75 teams to be delivered. Quite often limitations where identified at very end, which could mean ping-ponging across 10 different teams, for instance!
Thank you! Really enjoyed the read!