Yehuda Katz is a member of the Ember.js, Ruby on Rails and jQuery Core Teams; his 9-to-5 home is at the startup he founded, Tilde Inc.. There he works on Skylight, the smart profiler for Rails, and does Ember.js consulting. He is best known for his open source work, which also includes Thor and Handlebars. He travels the world doing open source evangelism and web standards work.

MythBusting — Rails is not a monolith

Continuing his interesting train of thought, DHH posted on his blog yesterday that Rails is, in fact, not monolithic. In reality, he says, it is quite modular. In the post, he finally fully articulated the rationale behind the excessive use of alias_method_chain in Rails, which he says is to keep the code even more “modular”.

Let’s take a look at some of the claims:

Rails is not actually that large

They count all lines including comments and whitespace in Ruby files, thus punishing well-documented and formatted code

As I said yesterday, I did not actually include comments and whitespace. I specifically provided the command that I used, which removed whitespace-only lines and comment-only lines. In fact, the comment by bitsweat (a member of the Rails Core team) which started this back-and-forth erroneously included comments in Merb’s count, when merb-core has about 1 line of comment per line of code. This is why Jeremy incorrectly thought that merb-core was over 15,000 lines of code.

They count tests, thus punishing well-tested code

Neither Jeremy nor I counted tests. I’m not sure which LOC-count he’s referring to.

They count bundled dependencies, thus punishing dependency-free code

I did in fact make this mistake, but I disagree with the assertion that bundling dependencies makes code more “modular”. For example, bundling xml-simple in Rails causes a conflict with gems that require a newer version of xml-simple than the one bundled with Rails. Conversely, merb-haml has a haml dependency, which means that users can use newer versions of Haml that are released between Merb releases.

This statement by David actually teases out a fundamental difference of opinion between Rails and Merb. In effect, Rails prefers to bundle everything to reduce dependencies, while Merb prefers to use the existing Rubygems system so that applications can use different versions of the “bundled” dependencies.

Additionally, we don’t want to be maintaining bitrotted versions of things like tmail. We’d prefer to rely on gems created by experts in their niche who can maintain, and more importantly, fix bugs in, their code. We fully admit that our approach pushes the limits of Rubygems, but that has forced us to work with rubygems to improve a core piece of Ruby infrastructure.

Rails is actually pretty modular

The arguments made here almost defy reason, but let’s go through some of them.

First, Rails can include almost as much or as little of the six major pieces as you prefer.

Absolutely. I’ve referred to this in the past as the Lego vs. Duplo philosophy. Rails has added in a feature to allow you to remove entire blocks of functionality, but isn’t built on an architecture that lets you granularly opt-out. Granular opt-out allows you to reuse foundational code without buying into the full set of opinionated defaults.

One example of this is our auth system, which allows you to reuse the base auth code, which simply allows you to define strategies inside of a framework, even if you don’t want to use our built-in strategies or login views.

Granular opt-out builds a community around chunks of code that can be swapped in; having an auth core makes it easy to share small, simple authentication strategies between users of Merb.

The next part is the part that makes me incredulous. According to David, because Rails is spread across many files, it is “modular”. He describes how you would go about granularly removing certain features:

All these optional parts can actually very easily be turned off as well, if you so please. If you look at actionpack/lib/action_controller.rb, you’ll see something like the following:

ActionController::Base.class_eval do

  include ActionController::Flash
  include ActionController::Benchmarking
  include ActionController::Caching
  ...

This is where all the optional bits are being mixed into Action Pack. But they didn’t need to be. If you really wanted to, you could just edit this 1 file and remove the optional bits you didn’t need and you’d have some 3,500 lines of optional goodies to pick from.

Read that carefully. If you want to opt out of certain parts of Rails, you need to:

  1. Read the source, and figure out which files contain the features you want
  2. Figure out where the modules in question have been mixed in
  3. Fork Rails
  4. Modify your own personal version of Rails to remove modules that have been mixed in
  5. Never upgrade Rails again (or upgrade Rails and hope they haven’t made any changes to the part of the file you’ve modified)

Fundamentally, Rails’ “modular” architecture is fine for core committers, but it’s not particularly useful for consumers of the framework. Which makes sense, since 37 Signals sees Rails primarily as a library that they use to write their apps. So thinking about modularity in terms of the code of the framework itself makes perfect sense from that perspective.

On the other hand, Merb looks at modularity from the perspective of the developer using the framework.

alias_method_chain makes Rails modular

As I’ve said many times before, I don’t like alias_method_chain. But Rails’ philosophy around it is a perfect example of its problems. Superficially, it seems like it divides up responsibilities neatly into their own modules. And again, this is perfectly true from the perspective of developers working on the framework itself.

For consumers of the framework, it is simply maddening. Here’s a code snippet David provided in his post:

module Benchmarking
  def self.included(base)
    base.extend(ClassMethods)

    base.class_eval do
      alias_method_chain :perform_action, :benchmark
      alias_method_chain :render, :benchmark
    end
  end

This is an extremely common idiom in Rails. Unfortunately, it makes Rails methods extremely opaque. It is nearly impossible, without reading through a dozen files and putting together the puzzle, to figure out what the perform_action method actually does. This is evident in a Rails stack trace, which includes close to 10 frames for different parts of perform_action.

And this alias_method_chain isn’t even greppable. Effectively, it’s up to the user to divine that including a module modifies methods in the class, since it’s done via metaprogramming in an included hook. Again, this all makes perfect sense for developers on the Rails framework. But for consumers of the framework, it leads to many frustrating days trying to track down all the pieces of a particular method.

But why bother?

Again, this question makes perfect sense coming from the perspective of using Rails as an internal library. Don’t need something, like pagination? Simply move it out of the core framework. From the perspective of trying to develop something that can be used for many different purposes, in many different situations, we have different priorities.

Merb has already been used as the base for SproutCore, which generates static HTML out of a Merb base. It has been used for sinatra-like web services. And it’s being used by several large companies who don’t want to use DataMapper (and are using Sequel instead).

As people use Merb for more kinds of things, decisions like hardcoding features of Merb to a particular ORM (like Rails has done), requiring a certain directory structure, or bundling in dependencies become much harder to justify. People using Merb actually do use other gems that conflict with Rails bundled dependencies. People using Merb want to be able to upgrade their versions of Haml, ParseTree, or MailFactory without expensive surgery to the framework itself.

For the moment, these differences are the reason that Rails will continue to dominate amongst developers seeking to build apps similar in scope to apps built by 37Signals. I suspect that Merb will pick up steam amongst developers looking to build innovative apps leveraging the latest and greatest Ruby techniques and libraries.

I, for one, spent several years building large Rails applications, and am happy to leave the “just keep your own frozen, patched copy of Rails” philosophy behind.

UPDATE: Just to be clear, I know that Rails tries to use more recent versions of gems if they’re available on the system. However, that is a very naïve dependency approach, that in our experience, produced issues. It’s much better to be warned that you have dependency conflicts up front than to have them manifest in running production code.

22 Responses to “MythBusting — Rails is not a monolith”

What’s with this pissing contest? Why don’t you focus on real issues, like the fact that Merb has little to no docs? Until Merb gets some decent documentation, it’s always going to be a toy framework, 1/2 the lines of code or not.

It’s nice that you guys are having a little “truth shootout” here, but don’t lose track of the fact that Merb was inspired by Rails and that both frameworks are awesome.

How about an up to date guide on porting apps from Rails to Merb, btw?

@evan eh. it’s all in good fun. I don’t consider this so much a pissing contest as an opportunity for both frameworks to get their philosophy out in the open and subject to scrutiny :)

good fun?

That’s not how the rest of the world reads it.

Sure making noise is great for publicity, but it depends how you want to sleep with trying to split communities rather than joining them.

Philosophy is to help people write successful web apps, surely? Oh, snap, both do that.

@raggi sigh. I just had a very productive conversation with Rails folks about this stuff. It’s perfectly reasonable to discuss philosophical differences out in the open.

I think it’s pretty clear that there is one RUBY community, and a Merb and Rails community. Instead of trying to figure out ways to magically merge the Merb and Rails communities, let’s all work together as part of the Ruby community. So far, it’s been working grand.

I develop daily in rails and I think this type of dialog is important for the future of rails, merb, sinatra, etc.

If we can’t discuss things openly and weigh whether they hold water or not, the overarching ruby community has a serious problem.

Thank you.

I love both Merb and Rails for different reasons (and for the same reason; they’re Ruby), and I think talking about the differences constructively is very useful. Proponents on both sides just need to focus on what makes their framework great — instead of burning valuable time pointing out flaws in the other. Defining yourself by what you’re _not_ is pretty lame.

People will ultimately use what they like, anyhow, regardless of facts (real or perceived).

@wycats ok…

Size – first of all, size is irrelevant without discussing features, meaning or complexity. As we all know, accurate and provable mathematics fail in this regard. The best tool ruby has is flog. Flog however still can’t tell you about features, only complexity.

Bundled dependencies – In ruby this makes no difference at all. The truth of the matter at the fundamental level is that ruby has crap version management for object and class structures – i.e. none. To attack a framework for not addressing this is pointless really. A recent common occurrence of this was in hoe.rb, iirc specifically 0.4.5. In this case, one has to patch, somewhere. No choice, the language makes it so. Using more gems / more vendor dirs / more of anything won’t make the blindest bit of difference.

Modularity – yes, rails has mainly 6 big chunks. Yes that means you have to read more source to split it up. Yes that’s a difference in philosophy. In fact, this is one of the reasons why many consider it faster to develop in rails. Remember “convention over configuration”, same deal here. Having said that, modularity has it’s disadvantages. Interface glue for dealing with plugins will have it’s performance hits. One such issue comes from having so many gems – gemspec loading is messy in the heap, and our GC current sucks for that.

How about this approach:

class MyBaseController
include ActionController::Whatever

end

Now, forgive me if I’m wrong, but merb doesn’t make that much simpler. I mean plugin APIs might slightly change the ‘include’ to some other method call, but honestly, there’s little difference there.

Versions always break APIs somewhere, that’s part of what maintenance is about. If you didn’t need to change something, you wouldn’t need a new version. Merb can’t claim to escape that fact either.

On alias method chain I agree, there are certainly better ways for building up a chain set that might read better. No matter what, though, defining dynamic dependency sets in a method chain is always going to have some kind of api which doesn’t instantly reveal where the definition is. This same problem exists in rake task dependencies, but they are easier to read and grep (for the most part). I’d be interested to see an article covering in detail merbs idiomatic approach to this problem.

I don’t see the problem upgrading the gems you mentioned in a rails app… As for dependency management, a few decent gem management scripts can help out a lot.

Of course, I wonder why a web framework is responsible for gem management in the first place…

My main point was, there’s much much much more important stuff to discuss, and I see less real talk about actual philosophy. You seem to be spending a lot of time raising issues, rather than explaining the philosophy that lead to them (such as the previously mentioned “convention over configuration”, and so on). It’s also worth noting that you can do a lot of this stuff in rails:
“As people use Merb for more kinds of things, decisions like hardcoding features of Merb to a particular ORM (like Rails has done), requiring a certain directory structure, or bundling in dependencies become much harder to justify. People using Merb actually do use other gems that conflict with Rails bundled dependencies. People using Merb want to be able to upgrade their versions of Haml, ParseTree, or MailFactory without expensive surgery to the framework itself.”

I find “without expensive surgery” an interesting way of putting it. That is as much dependent on the libraries tendency to encourage bad coupling and also “what changed” as much as anything else. Hell such problems aren’t even strictly ‘in the framework’, and any dependency merb has could suffer the same issues in the future. Any time you start to couple with a dependency you’re going to struggle there, coupling with parsetree in merb is just one such example. As pointed out earlier, ruby sucks for this, and no one is immune, no matter what a blog says.

There are several other major issues to which no one is immune which have been raised here. With such important work that needs doing, I really see these discussions as a gross strange detractor to the real underlying issues.

You could do well to do a full and proper analysis of any one of the raised problems, break it down to base principles and you’ll often find there are some important areas of development that can be explained.

If your target is education of the community then properly addressing an issue like “how to manage version conflicts gracefully”, covering wrapping to avoid coupling, how to couple lightly, how to monkey-version, etc. could be invaluable to members of the community who are less familiar with these issues. Hell, it’ll affect the core language, rather than just this web domain.

I hope this post makes you sigh a little less, similarly I hope your next will do the same for me.

Wow, people really see drama everywhere.
No offense raggi, but a blog post would be more appropriate than this huge comment ;)

Here are my 2 cents worth: http://merbist.com/2008/11/15/rails-vs-merb-drama/

@james we have an entry in the wiki: http://wiki.merbivore.com/faq_converting_a_rails_app_to_merb it could certainly better.

Documentation is our main focus now that 1.0 is out the door. We are expected 3 books to be released soon. Yehuda’s book is already in beta: http://www.manning.com/ivey/ Foy Savas, Merb way should be out soon and we have a third one I don’t have in mind right now.

Peepcode.com also has a great PDF with a draft screencast for Merb, highly recommended.

-Matt

Finally, Yehuda and I are offering a training course at the beginning of next year: http://ma-agile.com/training/

Nice writeup.

I think its important for both sides to clearly and concisely explain their side of the fence, and I think both you and DHH have done this.

I don’t think it’s a drama at all. Why are people afraid of apparent conflict?

Once upon a time, Rails had little to no documentation.

These two frameworks can exist side by side as far as I can see.

Someone wrote that merb has bad docus.

Let’s be honest now guys – Ruby projects in general have horrible documentation.

Now there ARE exceptions but as a user who feels that ruby as a language is by far the best language, I think the documentation IN GENERAL is still NOT GOOD ENOUGH.

I really dont care much how the code behind a project looks. I also dont care that much about the speed – the whole speed nazis got too much room anyway. But a bad documentation is something I always regret. That includes examples btw. Making examples that highlight what a project does is absolutely important. Most do this by now, but some dont. Horrible horrible horrible!

When I looked at rails the documentation was quite annoying by the way. That was years ago.

Documentation in the ruby world has improved but I still find it weird that projects compare their code instead of really TOTALLY making a GREAT documentation. PHP is such a horrible language but at least when I started with php many years ago (i abandoned php completely lateron) it had nice documentation in general, including user comments (which sometimes helped, sometimes didnt).

So please – focus on documentation instead.
Documentation helps other people invest less time, which makes documentation so precious. Documentation should evolve – the Unix world still relies on man pages, which is an outdated concept from 10000 years ago. I hope the agile scripting languages have learned from that ancient mistake and constantly make their documenation UP TO DATE and “AGILE” (feel free to interprete that last word how you will in regard to documentation).

It’s nice seeing some competition in the Ruby community. Ruby needs more disruptive frameworks to keep them all on their toes and the ideas fresh.

I’ll be def following Merb as a strong up and comer.

In the immortal words of Dr. Rev. Rodney King “Can’t we all just get along?”

I am trying to organize a boxing match between you and David at RailsConf. I think you two should headline while Matt and Jeremy are the opening match. What do you say?

We can do the whole thing for charity.

@steven haha I got a good laugh reading your comment. I’m not really into boxing, maybe we should organize a curling game instead. It’s less violent, more fun and a team game. (I considered darts, but it might turn out dangerous)

More seriously tho, while most people don’t really care about the LOC, what’s positive in all of this, is the fact that we finally start addressing the difference of philosophies between frameworks.

I have to agree with markus. Merb documentation is a bit lacking. For example I was searching for an example of a single file application and the wiki didnt conatin any information about that. So I googled and in some random blog post I found about the very-flat option.

Though I use neither rails or merb it’s good to see someone refuting DHH’s post a bit about how modular rails is. His ‘rails myths’ have been informative overall but that post was by far the worst. To me as a non-framework-biased person, his post basically argued for how non-modular rails was even though he was trying to claim otherwise.

Wow.. I go away for the weekend and miss all the excitement.

There’s a lot of good discussion happening here. We had some great discussions at Railscamp Australia also.

Speaking of differences of philosophy, one of the fundamental differences in philosophies that I see with Merb and Rails, is that of convention over configuration.

Rails == convention over configuration
Merb == sensible defaults for convention

This difference really is fundamental and has a large impact on the way merb is defined.

Sometimes I want to change things, and it’s always for a good reason. Merb makes it possible and does so without breaking.

No matter which way you swing, it’s a great idea to take a look at the source of both of these frameworks and understand how they both work. This can only help you write better code.

I agree with some of the previous posters, this post was slightly on the immature side. I don’t really know what you were trying to accomplish by writing up a huge article refuting DHH’s blog posts on rails. Publicity maybe? I love merb, and use it on a few projects, but the only thing this post is going to accomplish is pissing off people.

Lastly, I strongly disagree with your comments on alias_method_chain. It allows you to split up logic into modules and make the code MUCH easier to maintain. I think your comment on this exposes a fundamental flaw with merb. You say it adds confusion to the end user trying to figure out what a method actually does. Correct me if I’m wrong, but that is what documentation is for, something merb is *severely* lacking. Can you imagine what rails would be like if they decided not to do this, because it was a little confusing to someone reading the source code? It would be impossible to maintain. Write your code so it is maintainable, and then worry about clarifying with documentation.

Leave a Reply

Archives

Categories

Meta