It's about time to start fighting against the Rails “magic” myth
blog.plataformatec.com.br
blog.plataformatec.com.br
Some developers prefer Python, some prefer Ruby. An individual developer might be able to reel off a list of reasons why one is better than the other, but in the end it comes down to something intangible and subjective - "Ruby just feels better" or "Python fits my brain better".
The concept of "magic" is very similar. What feels magical and opaque to one developer might be plain and obvious to another. When you ask what "magic" means, you'll get different answers from different people.
From my point of view (as a Python/Django developer), even the basic commands that Rails uses feel strange. Compare the very first line of code that you run in a Django project vs a Rails project:
django-admin.py startproject mysite
with rails new blog
The former says: "run the Python script called django-admin.py" (which immediately tells me that this is just a Python script that I could read, if I were so inclined) and pass the arguments "startproject" (which is a clear description of what is about to happen) and "mysite" (which is, fairly obviously, the name of the project to start). This reads like a sentence of the form 'use <tool> to perform <action> with arguments <arguments>'.The latter says: "run the command rails" (what is this? A Ruby script? A bash script? A binary? Why is it called "rails" when the whole framework is called "Rails"?) and pass the arguments "new blog" (obviously this is creating something, but what? In most languages, "new" is a keyword that is usually used to create instances of classes - so is it creating an instance of something called "blog"? Does that mean that Rails knows what a "blog" is already?) To me - this is magic. Rails says "type this incantation and I'll do some stuff for you". Django says "here are some tools you can use to do stuff".
You might disagree with me entirely in this particular case - perhaps you find the Rails example clearer - which is fine. The point of this example is to say that framework and language preference is so intangible that the very first line of your documentation can sway someone's opinion either way. Instead of fighting against the "magic myth", you should just be trying to attract developers who like your particular brand of magic (or, alternatively, don't see your code as magic at all).
hg init project
to mercurial-admin.py startrepository project
Those Ruby developers and their magic. Or something.The rails command exhibits 2 qualities which I value greatly, good encapsulation and a high signal to noise ratio. When I create a new project that is exactly what I'm concerned with, I have no interest in _how_ this happens. The fact that the django command is twice as long to describe the same thing to me implies redundancy and from more of a philosophical than perhaps practical point of view, waste.
A blog, on the other hand, is an application that should be written on top of all this. It would make more sense to me include this as an example application.
It seems pretty obvious to me that the intent of creating the "ruby new blog" command was to make it extremely easy to install the example blog app. However, by doing this, they are marketing rails as a magical framework. The framework auto-generating you a whole blog isn't really a good hello world program; it didn't teach me anything about how rails works.
I remember back when ruby first came out (I'm sure a lot has changed since) I was watching videos that introduced it, and every time the presenter would say something like "Hey you want a blog? Just type magic make me a blog command, and now you have a fully functioning blog with a built in CMS." I remember thinking to myself, "but I'm not building a blog" and then I went back to my PHP. I'm not saying this was the correct reaction, perhaps I should have instead gone and investigated it further, but that's how it was marketed, and I found it off-putting.
> I remember back when ruby first came out
I think you meant Rails here (not sure if you can edit HN posts). Ruby's been around since the mid-90s.
> I remember thinking to myself, "but I'm not building a blog" and then I went back to my PHP
This makes me think that you're not using a MVC framework. PLEASE, please spend 30 minutes researching MVC and conceptualising the models behind your application talking to each other.
In plain PHP, you would run a SQL query to see if a user can reply to a blog post. In a MVC framework (such as Rails), you would ask the user itself in a higher-level manner:
if @user.can_reply_to? @post
This helps keep your views clean and all your business logic separated out. Views should contain no logic, controllers should contain as little code as possible to grab model data and anything else needed to show in the view, models should be where all the magic happens.
This is exactly right, and diametrically opposed to J2EE "best practices," where pretty much every model "object" ends up as a Java Bean with a no-args constructor, public accessors for every field, and no business logic whatsoever. And to think they have the nerve to still call this "object oriented programming."
I'm perfectly content with the Smalltalk-inspired object model Ruby uses. :)
magic: changing the scope in which a block is eval'd so you can inject BlankSlates that have method_missing defined on them that then do some string manipulation in order to pick which code path to take.
Sometimes you need to lean pretty hard on the super-dynamic features to get the api you want. But is it worth it?
If anyone wants to get a head start in understanding the magic, Ryan Bates has done excellent walkthroughs of the routing DSL and the activerecord query building method chaining source code:
http://railscasts.com/episodes?utf8=%E2%9C%93&search=wal...
edit: to add to the list of stuff that rails does which is 'magical,' I still get uncomfortable over the way that instance variables I set in the controller scope are 'copied' to the view scope. This is obviously a necessary evil though.
The real cost of rails' magic is the rampant and wanton Demeter Violation, which can make testing very difficult in some circumstances.
"What about calling it a 'DSL' rather than an API? Then nobody will be able to claim you're abusing Ruby, because it's an entirely new language!"
"I doubt anyone would ever buy that..."
I take your point though, I do get that feeling sometimes. There is a lot of showing off by ruby API developers.
I think there comes a time in every ruby hackers life when they get the urge to write an API that makes use of every single metaprogramming/reflection/self-modification feature in the language, because it looks like so much fun. We spend our work days writing rails with all its fancypants DSL-like bits, and we think "I want to do one of them!"
Mine is a DSL for defining regular expressions in natural language, and my god does it abuse metaprogramming. All the methods are defined at runtime by iterating over datastructures that list the regex spec. instance_eval(&block) all over the place. It is fucking brilliant. And not finished. Obviously.
Think of it like Struts, Spring or the Zend framework with all the configuration done for you with excellent documentation.
Ignoring the people that just reiterate poorly formulated ideas heard somewhere else, the complaints about magic were quite valid: originally the Rails source-code was too hard to read and comprehend.
When I used Django, I read most of the source-code from django.core and even stuff from django.contrib.
Django also has its quirks. I could understand pretty easily how a ForeignKey works (I don't know, it just clicked), but understanding how a FileField works was hard because the object I was receiving was just a proxy that forwarded all messages to an object that I couldn't figure out how it got instantiated (or the logic behind the decision). And when I did figure out how the thing worked, I puked a little and came up with an inelegant hack for what I was trying to do.
Figuring out how stuff works is really useful when you want to extend the provided functionality or work around a bug that has to be fixed RIGHT NOW or break free of those conventions that sometimes are just too limiting. Not to mention incomplete documentation which many times is seriously lacking.
Django's source code (when compared to Rails), while also full of conventions, has this neat property that I like: you can read and understand 70% of its source-code (going line-by-line with a debugger) without fully understanding Python's meta-programming capabilities, which makes it really friendly to beginners.
I mean, the convention for "has_many :tags" is really neat, but such conventions have to have complementaries in the Rails source-code ... i.e. clear conventions for how to find and read the source-code of this mechanism.
Fortunately Rails 3 got a major refactoring effort, that I could read portions of it. It's more modular and reader-friendly now: and this is partly because people complained about magic. With a couple of additions here and there, it can be the web framework I've been waiting my whole web-dev carrier :-)
People had reasons to call Rails as something "magic" some time ago. But "magic" at that time really translated to poor design and lack of documentation.
Most of Rails has changed since then. Rails has good documentation for already some time, the internals are cleaner than ever before and should continue improving (for example, check Aaron Patterson's work on Active Record for Rails 3.1). But people still call it magic, because it became an habit.
Even simpler and smaller things in Rails, like the "find_by_email" method in Active Record that relies on Ruby's method_missing, were for a long time called as "magic finders".
Another proof of that habit was my take on Inherited Resources. The code is clean, modular, well-tested since day one, but I still stamped "magic" on the README when I first released it because it sounded cool. This is the mistake I want to prevent people from doing it all over again.
Maybe a better moto would be: "There is not such thing as magic, only bad and poorly-documented code."
However, I'd dispute the assertion that Rails has excellent docs, it certainly hasn't always been the case. When I started with Rails, in 2006, the docs where woefully out of date. All the latest information that was available was in a variety of disparate blog posts, written by Rails enthusiasts. That was a significant barrier to learning at the time.
I want to add authentication - every tutorial recommends different packages to use, but I don't want som prewritten code, I want to set a session cookie, I want to read it, I want to add stuff to databases manually, I don't want some random code providing this without understanding what's going on!
I'm sure that it's an easy thing to work out, but every time I get fed up with not knowing where anything is coming from so I give up and go back to what I know.
You must not have tried Rails past say 1.2 or so (I can't remember when they took that out). Scaffolding has been generated for some time, which means the code is just spit into the app/ directory. You can go in and change whatever you want with it.
As for the rest of your complaint, then perhaps something as abstract as Rails isn't really for you (Sinatra maybe?). Though really, why do you want to do all that manually? Just read the framework docs, which are quite good now, and code, understand how they work (really, it's not hard I promise), and use the abstractions. You'll thank yourself later.
It's an open source framework. Gems and plugins are nearly all open source by nature. And meanwhile, I'd assume you're OK using web browsers and operating systems without reading all of the source code.
For people like me, Rails is at least at first glance very unsettling. I followed the tutorial on their site about making a guestbook, on which they proudly boast how fast you'll have it up and running. So I punched in the code they suggested and bang, guestbook. They certainly weren't lying (maybe exaggerating a tad) about the speed, but ...
Wait. What the fuck? You've made a lot of assumptions about how I wanted this to work. What say I didn't want the form to look like that? Why are you writing CSS for me? That's my job! Going further into it made me feel even more uncomfortable, and after seeing the ORM database abstraction and taking my beloved SQL away from me, I left Rails behind.
It's one thing to provide a clever wrapper method to efficiently sort integers in PHP or Ruby without having to import or implement quicksort or whatever. That's abstraction me and my self-taught ilk are comfortable with. But the way Rails assumes what you meant from your code is just distressing. You don't feel like you wrote it, and this code is running and producing a finished webpage without you needing to understand how it works. You could reasonably respond that this is just another layer of abstraction, but producing an entire webpage for you based on some very cursory instruction does not have the same "pure" feel that a sort() implementation does.
My friends think it's great. I think it's scary. And reading some other elated posts from Rails nuts around the web about the whole "just works" thing and the magic going on really is unsettling. You're not building from the bottom up -- schema -> logic -> markup -> style -> scripts. It's all coming together in one big vaguely uncomfortable clump, and you didn't write it. Anything more than a vim macro/TextMate snippet or two that generates code for me -- even if I can edit it afterwards -- gives me a cold shiver, and makes me feel like I'm using Dreamweaver again.
You could read the code to see what it's doing and tweak accordingly, but then, why not write the code yourself in the first place?
It provides a slow introduction to noobs and introduces them to the mindset that you shouldn't have to do a lot of configuration for things to just work out of the box.
Remove the magic and pretty soon we'll start having to use factory classes. Or a web.config file. Or any of the other annoying things you have to configure to some sane value every time you start a project with any other framework.
What the blog post advocates is for giving good explanations, books, documentation instead of blaming magic as the reason everything works.
I think that one of the reasons Rails appears to be magic to me is that I find it harder to do web programming in rails without the framework than with it. Hear me out, please, I'm coming from Java...
I can easily hack something together with jdbc, jsp, servlets, sql, pojos, and so forth. I'm not saying it's a good idea, but I can do it. Maybe this is because I started with java before all the mvc, orm, DI frameworks were in place. Maybe if I'd started with mod_ruby on apache prior to encountering rails, it would be different.
Now, I don't mean that it's easier to create a large, complicated site with servlets and jdbc instead of spring, hibernate, and so forth. What I do mean, though, is that if I need to do something in framework-less java, I can do it, whereas doing it the "spring way" is "harder" - ie., I have to go research how spring does it, figure it out, and so forth. And if I can't, or if it takes too long, I can (and do) say fuckit and just hack it all up in java.
In rails, if I don't get it, I'm still incapable of dropping to a lower level of programming. And that means that if I end up in a bind, I'm really screwed, because I don't understand the magic. Here's the thing - I really dig Rails, but eventually something always happens, and then the fact that I don't really understand how this magic wand I stole from the rails guys actually works bites me in the ass.
I've carefully avoided ever saying "it's confusing", or "rails can't", because I'd be wrong. So definitely, I want to read this book.
I played with it a bit and then read the source. Poof! Magic gone.
When people say it's magic, what they're really saying is: "It's unfamiliar to me, and I'm to lazy to go find out how it works. So rather than just STFU, I'm gonna complain about too much 'magic'." :-)