Post

#19: Mind Your Dependencies

Managing dependencies can be one of the most difficult tasks when working on a project at scale. It’s crucial to understand your dependency graph and how it affects other parts of the firmware.

An Example

To best illustrate how dependency management can quickly get away from you I’ll share a recent story about trying to help a Deploy the Fleet customer.

The DTF library for ESP32 projects using Arduino Core utilizes the WiFiClientSecure class to connect to the DTF service. Since the connection is done with TLS a certificate is needed to validate the server. As I learned through recent painful experience, it’s best to have a bundle of certificates to validate the server.

I began to refactor the library to improve the code to use a certificate bundle. It turns out the WiFiClientSecure class has a method called setCACertBundle. Perfect! This is just what I need. Except, it didn’t work. There was a bug in the implementation.

The good news was how fast the team responded to my bug submission. They fixed it in less than 24 hours. The bad news…they fixed it in version 3.0.4 of the library.

The customer, in this case, integrated my library code into a PlatformIO project. As of this writing, PlatformIO uses the 2.0.17 version of the ESP32 Arduino Core library. So the customer wouldn’t get the fix in the core library my library depends on.

“Ok, just have them pull in version 3.0.4 of that library” you may say. Now we’ve just created more dependency hell because version 2.0.17 of the Arduino library is based on IDF version 4.4.7. The 3.0.4 version of the Arduino library is compiled against IDF version 5.1.4 which is a massive, breaking API change from 4.x.

So if I update my library to depend on 3.0.4 of Arduino Core I’m forcing my consumers to migrate IDF major versions which, while recommended, isn’t my decision to make. The tail can’t wag the dog.

Ultimately I implemented a working, but sub-optimal approach that supports both the old and new versions of the Arduino Core library which means, by association, it also works both 4.x and 5.x versions of the IDF.

Production Pointers

  • Track all of your library dependencies and understand how they interact with each other
  • Be intentional about version updates
  • Always try to be on library versions within the active or maintenance window defined by the provider
  • In cases where others consume your code as a library, do your best to ensure backward compatibility

Summary

As you write your firmware be mindful of your dependencies, both upstream and downstream. Managing them can get very complex. And whatever you do, make sure you explicitly understand which version of every major library you use and the implication of migrating to different versions.

Dependency management ties into the Maintainable Pillar of Production.

Join the community and get the weekly Production ESP32 newsletter. Concise, actionable content right in your inbox.

© Kevin Sidwar

Comments powered by Disqus.