Two approaches to dependencies in projects

As I mulled over some of our recent packaging issues with UME's X components, it struck me that in Open Source there's (at least) two drastically different approaches for handling dependencies.

It's really common when developing some bit of code to learn that a fix for some issue you've run into is already available in a newer version of the library, kernel module, xserver, or whatever that you're developing against. What do you do?

The first philosophy is to immediately upgrade to that version of the dependency, and shift your program's requirements to require it. From your point of view, this makes the most sense - you solve the problem you're having with a minimal amount of time investment on your part.

However, the trade off is that it shifts the time investment to your code's users. If they wish to use your code, they find they must upgrade to whatever versions of dependencies you're using.

Sometimes that's not a huge deal, sometimes it is. Often the net result is that your userbase will be limited to those that like installing bleeding edge stuff; others will wait until their distro's packaging system catches up.

So, this philosophy essentially has an underpinning assumption that most users should wait to use my code for several months to a year, until the distro provides the versions of libraries I'm using. Users that really want it, will need to invest the time to build and/or install the development versions of things.

A second philosophy takes a more disciplined approach to dependency versions. With this philosophy you consider if it will be available to your target audience in the time frame you plan to release. If not, then you look for a solution which does not involve a dependency version increment.

There's a lot of ways to do this. Sometimes you can extract the fixed code and simply carry it temporarily in your tree to build against. Or you can select a different design for your feature which doesn't trigger the issue to begin with. You also might be to conditionalize your build system to use the "correct" solution when the newer dependency is present, and a "workaround" solution when it isn't. Other times, especially when you can work closely with packagers, you can simply flag the patches you need from the newer dependency, and the packagers can handle the porting work.

Inkscape uses this second philosophy; we value enabling people to get involved in contributing, and so the easier it is to build and install Inkscape on the widest variety of platforms, the better. This has served us well, and has enabled new releases of Inkscape to be packaged and built for a huge number of operating systems, often even including older (e.g. enterprise) distros.

Of course, this philosophy also has its downsides. For one thing, it requires more discipline by the original developer to think about how the fix can get delivered to the end user; I'd argue that unless your project is extremely obscure, you'll probably end up expending an equal or greater amount of effort down the road when users try installing your code. Another downside is that it can result in code bloat, as you accumulate #ifdef's and pulled-in code blobs; vigilance and planning can address this.

So which philosophy is better? Actually, both are good approaches in some situations, and poor approaches in others. If you value getting the development done efficiently, the first philosophy will be the more appealing. If you value making life easy for your users to install your code, and don't mind putting a bit more work in to achieve that, the second philosophy may be your preference.

Posted in | | Submitted by bryce on Thu, 2008-01-10 20:18.
bryce's blog

Perhaps with BZR or git or something else, the second approach can be used to branch stable releases. Rather than pretend that those #ifdefs are getting adaquate testing, pursue the proper library fix in the dev branch, and publish the version safe fixes in a stable branch. With bzr or git, it's probably easier to share the burden. Each distro publishes patches for the library versions it needs to retain; first the ones with only a one or two version problems write a quick patch. Then those distros slightly worse off discover that they only need to write a few more. Maybe the oldest can continue to snowball, or maybe they're simply left in the lurch. But formalizing the process may aid in spreading the good ;)

jldugger | Sat, 2008-01-12 06:39

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
More information about formatting options