Does Ruby have a distribution problem?
Luke Kanies wrote an article, in which he says that Ruby has a distribution problem. It criticizes Rails applications for vendoring a lot of stuff, and criticizes RubyGems for not being able to handle native package dependencies, among other things.
I beg to disagree. The described problem is not a pure Ruby problem: it’s a general software distribution problem. I’m concerned that people would use this as another “reason” to oppose Ruby, even though it’s not specific to Ruby.
My response
I posted a reply to Luke’s article, and it was as follows:
Luke, I don’t really understand what you’re expecting from the Ruby/Rails community. You’re dealing with cross-platform distribution issues. That’s hard by its very nature. I was a developer in the Autopackage project (www.autopackage.org), a software packaging system that works across multiple Linux distributions. I’m currently a developer of Passenger (www.modrails.com). We’ve run into many of the issues that you mention here.
If I understand it correctly, you’re claiming that vendoring stuff is bad because:
- You cannot vendor everything (glibc, web browser, etc).
- As someone else has mentioned, vendoring stuff creates potential security issues. This is not unlike static linking in C/C++ projects.
On the other hand, vendoring stuff does have benefits:
- Guaranteed compatibility. Suppose you rely on GTK 2.2. On a faithful day, GTK 2.2.5 was released, but accidentally introduced a regression, and now your application fails left and right. Uh oh. If you vendored GTK then that wouldn’t have happened. This is not a theoretical possibility: GTK 2.2.15 or something actually broke AbiWord. (I’m not saying that vendoring GTK is a good idea, as GTK is quite large. I’m just pointing out a benefit of vendoring.)
- Less installation hassle. Not all platforms have good packaging systems. As far as I know, Debian-based distros are the only ones. RedHat-based YUM repositories tend to be quite small compared to Debian’s APT repositories. MacOS X and Windows don’t have native package management systems at all. If your app is cross-platform, then vendoring stuff is a lot easier for both the developer and the end user.
Vendoring stuff is not only common in the Java world, but also in the Windows and MacOS X world. Windows apps tend to bundle all their dependencies (with the exception of obvious stuff, such as Internet Explorer). How many games have you seen that bundle DirectX? Actually I’d say that not vendoring stuff is only common in Linux, and languages that have strong ties to Linux, such as Perl. Here’s where Debian’s package management system and huge package repositories really shine.
There’s almost no common ground in the world of package management. We at Autopackage had to invent our own dependency resolution mechanism (similar to APT) because there’s no lowest common denominator, even amongst Linux distros. RubyGems is probably created for the same reason: not all Ruby-supported platforms have (decent) package management, so they just wrote their own. Autopackage experimented with native package management integration (i.e. being able to use the system’s native package manager to resolve dependencies) but that proved to be much, much harder than initially expected, and up until today that feature still isn’t finished. So I don’t think you can reasonably expect the Ruby community to do something about this. It’s not a pure Ruby problem: it’s a general software distribution problem.
As for being FHS-compliant: I can only say “don’t bother” if your application is cross-platform. It seems that only hardcore Linux users care about that. Outside the Linux world, FHS is being criticized by pretty much everyone. Windows and OS X users complain that application files in Linux are scattered everywhere, instead of being self-contained. Scattering files isn’t a problem in Linux because of package management, but it is a problem in all other platforms that don’t have decent package management. I’ve found that being FHS-compliant is more trouble than it’s worth.
So how do you solve this problem? I don’t think it’s possible to come up with a general silver bullet solution. So that leaves the following choices to you, the developer:
- Create a native package for every platform that you support, i.e. .deb for Ubuntu/Debian, .rpm for RedHat, another .rpm for Mandriva and SuSE because their package names are different, a .exe for Windows, .dmg for MacOS X, .tgz for Slackware, .??? for Solaris, etc.
- Write a cross-platform installer. Passenger/mod_rails chose this option because it’s a lot easier than the first one. Passenger depends on Ruby packages (Rails, fastthread, Rake, etc.) as well as native packages (GCC, Apache, APR). It checks whether all dependencies are available, and if not, it tells the user how to install those dependencies. We’ve put platform autodetection and Linux distro autodetection code in the installer. So on Debian/Ubuntu it would tell you to run “apt-get install apache2-prefork-dev” while on Fedora/RHEL/CentOS it would tell you to run “yum install apache-devel”. We’ve found that this approach works extremely well.
Finally, we at Autopackage fully recognized the pros and cons and vendoring/static linking. Autopackage recommends the following: dynamically depend on stuff that are common, but vendor/static link stuff that are uncommon. We believe that this is a good trade off between the pros and cons. Passenger follows this recommendation as well: we vendor the Boost C++ library. Few people have Boost installed, and when they have it installed it often isn’t the version that Passenger requires. Installing Boost is a huge, huge pain on MacOS X. In this case, the benefits that vendoring Boost gives us outweight the cons by far.
On the other hand, Apache is fairly common, and easy to install on most platforms. Rake, fastthread, etc. are also easy to install because of RubyGems. That’s why we dynamically depend on those things instead of vendoring them.
So it all boils down to making the right choices and correctly balancing the pros and cons of vendoring. There’s no silver bullet.
Gunnar Wolf’s follow-up
Luke’s article was quickly followed by a blog post by Debian developer Gunnar Wolf:
By using Ruby Gems, you dramatically increase entropy and harm your systems’ security.
To this, I say nonsense. It’s pretty well-known that Debian, and Linux distros in general, dislike foreign packaging systems, regardless of their merits. I see quite a lot of conversations on #rubyonrails @ irc.freenode.net that are somewhat like this:
Person A: hi, I’m using Debian/Ubuntu/some-other-Debian-derived-distro. I typed “gem install rails”. But when I type “rails foo”, it says “command not found”. what’s going on?
Person B: type “gem update –system && gem install rails”
Person A: wow, it worked! thank you!
It is painfully obvious that Debian did something to RubyGems. I was bitten by this very issue as well. Debian’s RubyGems package places binaries in /var/gems (or something like that, I don’t remember the exact location) instead of /usr/bin. Fine, I understand that they don’t want foreign packages to pollute /usr/bin, which is a managed directly. But the least they can do is adding /var/gems to $PATH by default, something which they didn’t. As a result, many people who installed Rails via Debian thought that Rails is broken, when it’s actually Debian who crippled RubyGems.
“Increase entropy”? I don’t even know what this is supposed to mean in the context of Ruby software distribution.
“Harm your systems’ security”? As I’ve already stated, vendoring has both pros and cons. If one dynamically depends on a library, then it means that the system administrator and library author are responsible for security updates, but it also means that a security update can potentially break the application. By vendoring stuff, the responsibility of security updates is mostly shifted to the application developer. This is a trade-off: there’s nothing wrong with it, and whether it’s the best thing to do depends on the situation. Gunnar however has an extremely purist view, along the lines of “if you don’t agree with us then you’re an idiot, regardless of the circumstances”.
It seems more like that Gunnar’s words are carefully picked, with the goal of creating knee-jerk reactions. Debian said pretty much the same thing about Autopackage in the past, and now they’re doing it again with RubyGems.
Luke, Gunnar, will you realize that all you’re doing is ranting about a problem, without offering any solutions? And no, creating native Debian packages is not a solution, the world isn’t comprised of just Debian.

Donavan said,
May 7, 2008 @ 1:21 am
I’ve dealt with a lot of software management problems, and have been a software packaging advocate for a long time. I agree that package management is a hard problem, and not just one that Ruby has. Here are some of my opinions on the subject:
Vendoring stuff is a double-edge sword, and one that a lot of people don’t understand well. You’re point about security updates shifting to application developers by vendoring is totally spot on. However, the problem is that application developers tend to do it too much, and don’t realize that they’ve taken on the responsibility of fixing bugs and vulnerabilities in those libraries! I think that purists adopt these views because they’ve been burned in one way or the other in the past, and so drift to the extremes.
I think that the open-source world has a harder time of managing software than the closed-source world in many respects. In a purely commercial setting, just about everything is vendored. However, commercial companies have support agreements in place with the people they vendor stuff from, and security updates are delivered to the application developer, regardless of version, and the app provider integrates that into their software. If the company sources software from an open-source project, they completely vendor it and keep tabs to make sure that they are current with bug fixes and security updates. In the open-source world I think the perception is that the upstream maintainer will fix the software, and everyone will just upgrade. This mentality discourages vendoring and it also discourages having multiple versions installed.
RubyGems is the best overall cross-platform package management system out there. However, it still has some warts, and I’m actively working to refine it. What I don’t want to happen to Ruby and RubyGems is what happened to Java, which is an absolute total NIGHTMARE. In java, everyone vendors libraries, and they also vendor the VM itself! I don’t know how many different versions of Java I need to have installed on a box to run applications. It seems that every app developer (especially the closed-source folks) has to have a specific version of the VM for their app. Noone has a good solution that I’ve ever seen for this. Interpreted languages fall prey to this more than any other (byte-code or source-based). The only well-known interpreted language that doesn’t have this versioning nightmare on their hands is Perl, and it’s interesting because they’ve dodged the issue by not having a major release is ages. (I don’t know if PHP has this problem, but then again PHP is 100% vendored in all aspects that I’ve ever seen). The Ruby community needs to break through and come up with at least a somewhat sane solution to this problem.
I also think that the reason that Ruby is catching more flak than, let’s say Java, is because Ruby is a wonderful, let me repeat, WONDERFUL system scripting language. It’s the first language I’ve ever picked up and said “wow, I actually enjoy programming in this”. However, for Ruby to be more than just another Web application environment, the community needs to embrace concepts that system builders and distribution maintainers deal with all the time.
Finally, on the FHS front, I just want to say: FHS is designed to help system administrators and builders, not developers. I like the idea of being able to perform nightly backups of /var instead of the entire machine; I like to be able to make /tmp a ramdisk instead of a hard drive; I like configuring Tripwire to lock down /etc on machines that have high security requirements. I like being able to NFS mount /usr (which is still done in a lot of scenarios!). So in a lot of ways, FHS is a good thing, and developers should help thier local sysadmin out if they can. What I dislike about the FHS zealots are in areas like arch-specific libraries. So what if a 32-bit library sits in /usr/lib64, if the system knows what’s going on? RubyGems understands how to select the right library at runtime, so there’s just no need to break up the software at such a fundamental level.
At the end of the day, I think that RubyGems, with some tweaks, will do an excellent job at maintaining Ruby libraries. I also think that it will integrate well with native package management. I’m spending what spare-spare time I have accomplishing just that with openSUSE.
Kaj said,
May 7, 2008 @ 11:41 pm
While it is easy for a person to use gems to install everything he needs to get rails (or whatever) working with minimal fuss the guys maintaining several hundreds of servers want systems that are reproducible every time and packages that you know a. compiles from scratch, b. installs cleanly, c. do not download funky stuff from the internet on a whim. A is very nifty if you suddenly find yourself using something that breaks and you need to patch and redeploy, B is kind of obvious for the automation part, C means whatever got packaged gets installed no matter what.
My problem with RubyGems is that it is a competiting packaging system to the one provided by the Operating System - it competes both on a file level (as the Packaging System provided by the Operating System tracks files) and package level. Rule number one says there has to be one packaging system responsible for everything and no libraries, applications, whatnot get installed without being packaged first.
For Java there is JPackage which does a great job considering the resources they have.
For Perl it’s relatively simple to package perl modules off CPAN.
For PHP (yay!) it’s relatively simple to package PEARs.
FWIW, it would be nice if RubyGems supported installing gems into a buildroot kind of like Perl’s MakeMaker. The guys at SuSE had a patch for it at some point (0.9.4 days) but it does not seem to have been accepted upstream.
Kaj said,
May 7, 2008 @ 11:43 pm
Also, the same actually applies for Passenger. mod_rails seems very nice but deploying it without packaging it properly (to depend on Apache ABI, etc.) is just a major no-no.
Hongli said,
May 8, 2008 @ 12:05 am
Kaj, what do you expect us to do? To make a native package for Debian Sarge, Debian Etch, Ubuntu 6.10, Ubuntu 7.10, Ubuntu 8.04, RHEL 4, RHEL 5, CentOS 4, CentOS 5, SuSE x.x, SuSE y.y, Solaris, MacOS X, etc. etc.? Sorry but I have to disappoint you, we simply don’t have the man power to do that, and neither do most developers.
Donavan said,
May 8, 2008 @ 1:30 am
@kaj
RubyGems support build-root style installations. gem install –install-dir and –bindir will do the equivalent of Markus’s old buildroot patch, and fits a little better with the Gems way of doing things.
@Hongli
Actually, that might not be as hard as you think. The openSUSE build service let’s you use a single spec and control file to build native packages for tons of different distributions. I built a passenger RPM on lots of the SUSE variants this exact way, and it’s almost brain dead simple to do. If you want, I can expand the distros I build for and become a default package maintainer for this.
Thanks!
Kaj said,
May 8, 2008 @ 11:34 am
@Donavan
Thanks for the -install-dir, -bindir tip, wasn’t aware of those at all.
@Hongli
It would be nice if there was a way of doing everything manually instead of the packager (me) attempting to reverse engineer the install script and check for any changes in install logic on version upgrades.
Donavan said,
May 8, 2008 @ 1:43 pm
@kaj
What kind of package are you trying to make? I was able to build an RPM for openSUSE with a simple gem install using –install-dir and –bindir, then running rake to generate the Apache module. I simply bypassed the script because it was unnecessary, and used the same system the script uses, sans all the autodetection routines.
Nome do Jogo » Artigo » Rails Podcast Brasil - Episódio 16 said,
May 9, 2008 @ 5:17 pm
[…] Does Ruby have a distribution problem? […]