Monday, May 24, 2010

Rails has no place at the office

This is a milestone post for me! My first ever purposefully incendiary title!

I should probably run with it and try to get everybody super offended, to the point where you have no idea what my point is because all you can see is red. I guess I'll have to leave that for a future milestone...

Because, yeah, I'm not really serious. Rails has a place at the office. And no, this isn't going to be one of those "Is Rails ready for the Enterprise?" posts. Rails is perfectly ready for use in the Enterprise, but that's the wrong question.  As usual, the right question is much more complicated.

To start with, let me point out that this conversation has nothing to do with Ruby vs. C#. It doesn't really have anything to do with Rails vs ASP.NET MVC either. Instead I'm going to be talking about Active Record vs. Data Mapper, and View-Models vs. no View-Models, and this general concept of "the straight and narrow" vs. explicit abstraction and control. These are design patterns which apply to any language and appear in many different frameworks.

Rob Conery recently wrote a blog post in which he said,
For a lot of .NET/Java devs this will look "messy" - you shouldn't elevate "data concerns" into your model. This argument makes good sense for a large, complex site - that you're building in C# or Java. Typically Ruby focuses on the straight, narrow path and with that comes a dramatic turn towards "doing what you need to do... and no more". This resonates with me...
The part about Ruby/Rails focusing on "the straight and narrow path" really struck a chord for me.  Ruby, being a dynamic language, is very much on the "straight and narrow."  It dispenses with all kinds of things found in strongly typed languages like private, internal, protected, interfaces, etc.  These are things that are usually considered very important in a strongly typed language, and practices like DDD, but Ruby doesn't really bother with them.  Ruby favors documentation and convention over strict control.

Rails has a similar story.  It uses the Active Record pattern for its data access, which requires a 1-1 correspondence with your database.  Further, the models don't even really exist!  They're built dynamically from the schema of the database tables.

If you compare ASP.NET MVC to Rails one of the differences you'll quickly discover is this concept of a "View-Model". ASP.NET peeps seem to like these, whereas I haven't found a Rails sample anywhere that uses these.  Both Active Record and this lack of a View-Model are accomplishing the same thing: removing abstraction in favor of directness and simplicity.

Now lets step back from this for a second and ask a question.  Who in there right mind would want to have to deal with things like class and method visibility and extra layers of abstraction, which more often than not appear to be just duplication?  No one!  No one would want to deal with these things!  It's extra work!  I _hate_ extra work!

So why do we do it?  Why does DDD make a big deal out of private constructors and Factories?  Why does Fowler recommend the Data Mapper pattern over Active Record?  Why do we create View-Models to separate our Views from our Models?  Why do we do all these things that seem to just make life more complicated?  Why don't we all take the straight and narrow path on all of our projects all of the time?

Certainly it's not as simple as the language we're using.  Just because you're writing in C# and Java doesn't mean you can't use Active Record.  And it doesn't mean you can't pass your Model straight to your View.  There is also nothing about C# or Java that forces you to use interfaces, or follow the Dependency Inversion Principle.  That said, there's also no reason why you couldn't use the Data Mapper pattern in Ruby, or create View-Models.  The language certainly HELPS with some of these issues, but it's not the real difference.  These are just patterns, and they apply equally well to any language.

The reason why we introduce this complexity and divert from the straight and narrow path in our technical approach is actually due primarily to non-technical reasons.  Here are some of the reasons I think lead us to adopt these "enterprise" patterns:

  • There are more than two or three developers on the project
  • You have more than 6 entities in the domain
  • The project has a timeline longer than 3 months
  • The developers aren't intimately familiar with the domain
  • The project is likely to grow in fits and starts
  • The team members are more likely to come and go

These are not technical issues but they have technical IMPLICATIONS!

The practices prescribed by DDD are a big deal if you're working with a large complicated domain with lots of potential for change.  If you're not, then you don't need DDD.  Fowler's enterprise patterns are a big deal for the same reasons.  If you know things are complicated, likely to change, and not possible for everyone on the team to grok completely, then you need to build abstraction into your code.  And you need to try to be as explicit as you possibly can about what the code does and how it works.  And you need to look for opportunities to prevent error and misunderstanding before it happens.  These things will allow you to keep things clean, organized, and ultimately make your project successful when you're faced with "enterprise" challenges.

This is obvious.  I'm sure you're sitting there (or standing) thinking, "duh!" or "when is this dude going to get to the point?" or "does this moron really think this is revolutionary?!"

My point is as simple as this.  Rails is awesome.  Simplicity is awesome.  But as I sit here in my ivory tower looking out over the landscape I see lots of quiet subtle backlash from people against the "enterprise-y" patterns in favor of the simplicity of Rails.  This makes a lot of sense to me because, as we pointed out, who would WANT to deal with the complexity of enterprise problems and patterns?  But it is easy to be tempted by the appeal of simple solutions to simple projects.  And certainly we should always strive to find the simplest solution that could possibly work.  But we can not close our eyes to the complexities of the problem or the environment in which we are solving the problem.  And we cannot allow ourselves to be boiled alive either.

So by all means, choose the right tool for the right job, but make sure you understand the job as well as you understand the tool.