@radekmie
By Radosław Miernik · Published on · Comment on Reddit
The vast majority of software requires maintenance. That’s normal and nothing to be scared of! Most of this maintenance comes from updating the dependencies – both on the source and the API level. The former are easy, as long as there are no breaking changes1 – usually, it’s just a version change. However, the latter pose a great challenge.
By “API-level dependencies”, I mean not only the API of a library or runtime you’re using but also the outgoing dependencies. Whether we’re talking about a library or an app, the users will – sooner or later – rely on every single part of the observable behavior; that’s a law.
As people are updating their runtimes (systems, drivers, browsers, etc.), the unmaintained software slowly becomes unusable. Usually, it starts with a beta user asking whether the change was intended or not2. The community often “reacts” with a workaround. But at some point, there’s nothing they can do.
And that’s everyone’s problem.
Plugin systems1 tend to increase the “survivability” of software, as it allows the community to adjust or extend it if needed. As a web developer myself, I really like the fact that GNOME’s extensions are written in JavaScript, as it’s easy for me to read their sources and tweak them when I need to. (Actually, the entire GNOME Shell is written in JavaScript and styled in CSS, which makes it extremely easy to work with, even interactively.)
As in most plugin systems (every single one I know), the plugin itself defines the runtime versions it supports; here it’s the GNOME Shell version. As time goes by, new and new versions are released (again, that’s normal). But the authors of some extensions are no longer interested in maintaining them.
Luckily, GNOME developers are not introducing that many breaking changes with each release! That means the maintainer has to add a new version to the list of supported ones, release it, and call it a day. Sounds easy, right? Well, it is easy, but not everyone is willing to do so.
Don’t get me wrong – I’m not saying they have or are obliged to – definitely not. Some are no longer using the extension themselves, some are too busy, and others are completely unreachable (everybody dies). However, it leads to a surprisingly large number of stale, single-line PRs (example a, b, c, d, e). Or…
I once read that open source never actually dies; it gets forked and carried over as long as it’s wanted. There are tens of examples supporting this claim, for sure. But whenever a relatively popular piece of software gets abandoned, everyone wants to be the one “owning” the new version. It’s all about the stars.
Even if you’re not knee-deep in the JavaScript world, you’ve probably heard about faker.js earlier this year. I won’t want to get into details here – long story short, an author of an extremely popular package (2.5m weekly downloads) pulled off the plug abruptly (and most likely definitely).
It took people less than a couple of hours to release packages with the same functionality (sometimes even forks) and promote them on Reddit. I won’t list them here, but believe me, my Feedly was full of them. Actually, so were my Slack and mail2. In the meantime, the package still works (previous version of it) up to this day. I know that cause we’re still using it.
I don’t think it’s necessarily wrong to release an alternative, but tens of them at once simply made me annoyed. Some were actually developed long before everything happened, but most looked like a long shot for popularity. Seriously, I can’t imagine a different reason for a horse name generator. I have to admit that it worked, though – 2.3k stars on GitHub is something.
Of course, it’s not always easy to come up with an alternative. Especially when the package heavily relies on many internals that are no longer there. It’s exactly what happened with Enzyme, a set of testing utilities for React. The package is still also very popular (2.2m weekly downloads), even though it’s effectively abandoned for two years (last release was in December 2019).
React team is known for preserving backward compatibility, but even they have to change a thing or two once in a while. However, in v17, they actually changed a lot. Luckily for the community, someone did the job and released a package that gave everyone an additional year to migrate off. Thank you!
The time has passed, and the React team worked on v18, which changed even more. That means releasing a package to make Enzyme compatible with it is no longer possible at all. Check out the package author’s writeup about the entire situation and some more details.
Lesson learned: do not rely on a package that touches the deep internals of other packages. Even if it’s backed by a huge company like Airbnb3.
In the last couple of years, monorepos got really popular. Because of that, there’s a lot of tooling software to ease the management of one: scripting, versioning, handling dependencies, etc. You could do all of that by yourself (as always), but this is not something most people want to put a lot of time into.
In the JavaScript world, the most popular tools were4 Yarn workspaces and my personal favorite: Lerna. I’ve used it in a few projects and never spent too much time on it – it does the job and doesn’t get in the way. The uniforms repo is using it since the first public release. And that was nearly six years ago.
Today, more than a year from the last release and nearly two from the one before, it’s still very popular (1.2m weekly downloads). It already had problems with maintainers back in 2017, but everything kind of worked out, and the time passed by. Finally, someone said it out loud: Lerna is largely unmaintained.
Is this a problem, though? Well, yes, because issues are piling up; even if most of them are not really issues but questions, more than 700 is a lot. On the other hand, it works. I know, I know – it doesn’t for some people. And I know it will break at some point. (Probably rather sooner than later.)
Obviously, adding an already orphaned dependency to a project is not the best idea in the long run, but may help achieve short-term goals; sometimes even deciding on its future. Similarly, when one of the existing dependencies loses traction, it doesn’t force you to get rid of it now. It can wait, really.
Managing technical debt is important, especially for bigger teams. It takes all kinds of resources to battle it, so it’d be wise to prevent it if possible. There’s no one good approach here, and you have to see what works and what does not.
Maybe I’m getting too old for hype trains. Maybe.
A breaking change doesn’t always imply a lot of work. Sometimes it’s just about changing the internals that most users shouldn’t even be concerned about. Sometimes it’s a change on the API surface, but in that case, the maintainers often provide an alternative or a migration guide. Of course, it’s not always as easy – a removal of a feature without a viable alternative can happen. That’s the cost of relying on an external dependency.
Not all breaking changes are something the maintainers are aware of. I’m not talking about a bug that slipped through, but something that they never promised. A non-code example would be a change of a logo or even name; most people won’t mind, but it may ruin a business. (Or at least the SEO of one.)
There are also mods, but I’ve never heard about one for something else than a game. Also, mods often can not only extend the existing functionalities but also modify the ones that are already there (i.e., changing the UI).
Yep, even a client mailed me about this incident. That’s crazy what happens when a programming event hits the news. It actually happened a few times in the past months, unfortunately (Log4Shell, Spring4Shell).
Of course, Airbnb is not the only company “killing” their own projects or even products. For a bit of nostalgia or a good laugh, check the Killed by * website.
I say were, as in the last year, new alternatives like Nx, Rush, or Turborepo are in the lead now. Check out monorepo.tools for a not-so-biased summary.