A nice addition to Rails that came with version 3.1 was the mountable engines which are basically full Rails apps that you can mount in another Rails app. They have fully isolated namespace, which is great! That will let you add, say, an e-commerce solution like Spree, a forum like Forem or a CMS like Refinery or Locomotive in your own Rails application.
Sounds good, right?
You can add functionality to your project without having to code anything and there isn't any namespace collision. This is amazing! Yes, but watch your back: here comes a possible dependency nightmare. Let me tell you why: they all have their own dependencies. Figure a hypothetical project that needs e-commerce and CMS.
You think of Spree as your e-commerce platform and Refinery or Locomotive as your CMS. Let's take a look at their dependencies: Spree needs Devise, as Refinery and Locomotive does. Now, what version of Devise do they need? '~> 2.0' for Spree (1.1.0 beta, which is master as the time of writing), '~> 2.0.0' for Refinery 2.0 (actual edge version too) and '~> 1.5.3' for Locomotive 2.0.0.rc branch. You won't be able to use Spree and Locomotive together, at least, not out of the box as they need different Devise versions. But still, Refinery and Spree will work together. "This is great" you might say? You will hit a few problems using both, but nothing major. I did it and Philip Arndt, a Refinery maintainer, did it too. You will have to use a little fix to use both Kaminari and will_paginate in the same project and maybe a few other basic fix. Nothing beyond any Rails developer's scope. You can take a look at Philip Arndt's Github repo for a "Spreefinery" proof of concept for hints. Spree and Refinery both have a bunch of other dependencies. But what will happen if one of those project bump any dependencies while the other mountable engines you use don't? It'll break your project! Simple as that. You'll have to fix all the dependency problems: doh!
My two cents
I think there might be a problem in the future. You now have multiple projects which all have dependencies, all in the same Rails app. What if you want to get to a hypothetical new version of Refinery that uses a new version of Devise that doesn't work with any version of Spree? Now, get to work and fix it. Next step: pull request...but hey, maybe there is a reason for such a dependency? Maybe Refinery, Spree or whatever engine's team won't be ready for a dependency version bump? Welcome in a dependency nightmare. Now you fork, fix it for yourself...hum, sounds bad!
Is this a problem? If yes, what's the solution? Being aware that problems could occur eventually is the first step. Choose wisely the engines you work with and do not use too many of them at once. You're a mountable engine maintainer? Reduce dependencies to it's bare minimum. Please.
Do not misunderstand me, I do love mountable engines. They are almost the 8th world wonder for Rails developers. That said, I think we should use them with care and be aware that you might hit a few problems in the future.
And you, do you use them? Which ones? What's your opinion about that subject?
More on the subject
Want to read more on mountable engines?
Want to read more on mountable engines?
- Ryan Bigg wrote an official guide about them
- Official API documentation (once was the only documentation): http://api.rubyonrails.org/classes/Rails/Engine.html
- Rails 3 in action has a full chapter about it.
- Ryan Bates did a Railscast about it http://railscasts.com/episodes/277-mountable-engines
A few mountable engines...
- https://github.com/spree/spree (from 1.0)
- https://github.com/resolve/refinerycms (from 2.0 which should be out in the next few days)
- https://github.com/locomotivecms/engine/tree/2.0.0.rc (from 2.0, which should come out...well...I don't know! Guys from Locomotive are pretty silent.)
- probably much more...
I am myself working on a mountable blog engine with almost no dependencies. This blog runs on a really basic version of Monologue. It might not be out before a few more weeks/months as I'll work on that on spare time between work and other projects.