Plugems, Welcome!
Revolution on Rails have finally released their solution to shared dependencies between Rails applications, which they have called Plugems (see what they’ve done there?). In their announcement they discuss some of the differences between plugins, “engines” (ahem!) and Plugems, and I think they’ve raised some interesting points.
What seems to be the main thrust of the Plugems effort is the addition of dependencies to whatever things we’re extending Rails with. And it’s not surprising; in any sufficiently complex software environment, you end up with subsystems that depend on other subsystems, and often require specific versions of those other subsystems too. There has been talk of adding dependency-esque behaviour to Rails plugins for almost as long as Rails has had plugins.
Even the engines plugin has had a patch submission to enable declaration of dependencies, but I ultimately decided against the idea. In the ticket, you’ll see my reason was related to how people perceived the engines plugin at the time, but in actuality is was more than that. The engines plugin exists (as does the Plugems system, I’m sure) to serve a very concrete development need that we have where I work, and so everything that it does springs from some need that we have. And none of those needs are a dependency mechanism.
Do we really need a dependency mechanism?
Here’s the gist, as I see it. If we have a dependency with a Rails application, best practice tells us to insure that when our application is deployed, it always deployed with that specific set of code that we’ve been developing against. While declaring those versions in code, a-la RubyGems, is certainly possible, for the most part it’s entirely unnecessary.
SVN Externals
If you’re diligent, SVN externals might be all that you require. This is because they can be locked to a particular revision:
(svn:externals for /vendor/plugins)
engines -r123 http://svn.rails-engines.org/plugins/engines
someotherplugin -r456 svn://an.other-repository.internal/var/svn/my_plugin
The drawbacks to using externals are two-fold: firstly, it makes deployment a bit slower, because we’re referencing several, possibly remote repositories. Secondly, and more importantly, we’re depending on the existence (and availability) of other repositories, particularly at deploy time. However, in our case we control almost all of the repositories that we’re using, so that’s not such a huge issue, but for the Rails community at large it should certainly be a major concern.
I must control everything!
If you’re not happy with externals, you can actually export your dependency and include it directly in the application itself. With this solution, we’re in total control of the versions of code that our application loads; heck, we can even change that code, and store the changes with the rest of our application too.
Paranoia begone!
Piston; like Prozac
The compromise is Francois Beausoleil’s Piston, which exports external code into your application, but stores information about where that code came from, and particular which revision that code was, in piston-specific SVN properties.
When you deploy an application with piston’d externals, the code comes from your repository, and yours alone. If you ever want to get an updated version of the external code, piston can handle that too, and you’re free to use any new features, test them in your particular app and then redeploy when you’re happy. Perfect.
And that is why I don’t think we need dependencies.
I’ve left a fairly lengthy comment on the Plugems blog entry, considering some of the issues that piggy-backing on RubyGems and enabling dependencies might bring; you might want to skim it if you’re into this type of thing. Regardless, it will be interesting to see how this is all going to work.