Wednesday, October 1, 2025

Escaping dependency hell with the Tarjan Algorithm

Kenny
Kenny

Let’s suppose the following: you’ve been building an app for a while, hundreds of files, modules, classes, etc. Suddenly, you realize the project is getting into dangerous territory: the Users module needs the Auth module to work, but surprise, the Auth module also needs the Users module to work. It’s like two people trying to get through a revolving door at the same time, one going in and one going out... we’re in trouble my friend.

Dependencies were crashing our code

The Problem We Were Facing

Like in any dev team, at Volt we’re working on something pretty complex and keeping everything well organized, in well-defined modules, is key.

But reality is always different from expectations: depending on the whole WhatsApp core, dozens of race conditions kept popping up and made everything randomly break…

We went down the easy path:

  • Timeouts waiting for modules to load in less than 750ms
  • Infinite loops checking whether a WhatsApp internal module existed before running our code
  • Sketchy retry logic that magically made everything work

It was a disaster: unclear, unreliable and… between us, quite embarrassing. The guys and I spent way too much time fighting these dependency issues.

Mati’s Discovery

One day, things got interesting. Mati started digging for hours into WhatsApp’s minified code and discovered something that would have saved us countless hours and headaches.

WhatsApp had found a very fancy way to handle circular dependencies and interdependencies, treating them as interconnected groups: the wonderful Tarjan Algorithm, an algorithm that allowed identifying strongly connected components in a directed graph. Internally, using this algorithm, WhatsApp was able to load modules in the necessary order, even partially when needed, ensuring all related modules were loaded. A true work of engineering art.

GIF

Tarjan algorithm

It’s like analyzing a group of friends where everyone knows everyone (some more, some less). This algorithm took care of finding these groups and handling them in a special way as needed!!!

How We Worked With This

This is the coolest part of all: we didn’t build our own system for dependency management, nor did we keep using those sketchy techniques to make things work. Since we practically work inside WhatsApp’s code, we just had to use their solution: easy win.

Now, every module we build is a beauty, and WhatsApp takes care of the complicated part:

  • It detects when a module depends on another (even in circles)
  • It makes sure every module finds the others it needs
  • Everything is loaded in the correct order, no tricks

Really, it’s like having an assistant that takes care of all the headaches dependencies used to bring us, without timeouts, without loops.

Why This Changed Everything For The Team

Thanks to all this, building new modules is really effortless, we use the same dependency injection system WhatsApp’s own team uses for their features, and we stopped fighting with this architecture to start extending it and making the most of it.

Our code is now:

  • Cleaner and more logical
  • Way easier for the team to maintain
  • Even fun to work with

Thanks to Mati’s discovery, at Volt we’re literally using WhatsApp’s (battle-tested) solution to fight dependency hell.

The Biggest Lesson

Sometimes, the best solutions don’t come from reinventing the wheel in a fancier way, but from understanding what already works and building on top of it. WhatsApp had already solved the problem that tormented us for so long, using pure math. Consider this post a reminder that the most elegant engineering often comes from taking a few steps back, understanding what already exists, and figuring out how to take advantage of it.

And also, that sometimes the best discoveries come from a teammate brave enough to dive into minified code for days, only to finally conclude that… the thing that made us bleed was right in front of us all along.