This post originated from an RSS feed registered with Ruby Buzz
by David Heinemeier Hansson.
Original Post: Beyond boilerplates: Structure generation
Feed Title: Loud Thinking
Feed URL: http://feeds.feedburner.com/LoudThinking
Feed Description: All about the full-stack, web-framework Rails for Ruby and on putting it to good effect with Basecamp
Early detractors of the Rails approach with application skeletons and component generators dismissed the framework at large under reference to "code generation". The thinking went that all Rails was really doing was creating a boilerplate mess that might give a quick taste of productivity, but would rapidly turn into a sour soup of mud.
Like those wizards of yesteryear that would ask you a bunch of questions through multiple screens, generate a ton of code you didn't understand, and then leave you stranded when a bug arose or extensions were needed. Needless to say, no sane software developer would be interested in bringing those dinosaurs back from the grave.
So the argument almost played itself. Rails is all code generation, code generation is bad, therefore, Rails is bad. Only one problem: What Rails is doing with its generators lie far enough away from the horror stories of the past to go under the same name.
The problem is that the code-spewing wizards gave the whole field of code generation a bad name. That in and of itself is certainly a shame. There are a lot of good forms of code generation (see the excellent Code Generation in Action for examples). But I admit that the term is somewhat tainted and its not really representative to what we do in Rails anyway.
Enter Structure Generation. See what we do in Rails is a lot less about generating lines of code and a lot more about generating structure. Herding the programmer down the path of conventions. Creating the right directories, the right files, and calling them the right names. It's conventions on rails.
Allow me to demonstrate:
$ ./script/generate model post
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/post.rb
create test/unit/post_test.rb
create test/fixtures/posts.yml
$ cat app/models/post.rb
class Post < ActiveRecord::Base
end
$ cat test/unit/post_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class PostTest < Test::Unit::TestCase
fixtures :posts
def setup
@post = Post.find(1)
end
# Replace this with your real tests.
def test_truth
assert_kind_of Post, @post
end
end
$ cat test/fixtures/posts.yml
first_post:
id: 1
another_post:
id: 2
As you can see, the actual code for the model is two puny lines of code. The important part is that the file is automatically put in the proper place, app/models/post.rb, and that it correctly descends from the proper super class. You don't have to think about how Rails is laid out, the convention is following from the use of the generator.
The second part is of course that this creates stub files for testing. This looks like code generation, but its really not. The code is not meant to keep. It's only there to explain the structure of how tests are supposed to work. Giving you an immediate sense of how to create your own test cases. So its nearly void on content, but rich in structure. Same goes for the fixtures. They're not there to keep, but to give an example of their usage.
But the effect of this is quite significant. It means that right after creating the model (and the corresponding database table), you can run your tests using rake test_units. The structure is in place, now you fill it in with your own content.
Structure generation drastically lowers the learning curve by teaching the conventions through code instead of documentation. It sets you up to succeed, to get the "hello world" (or, "I rule!") experience out the gates. Which will make you actually interested in putting in that content of your own.
Generating the model class is the simple example. We've just added script/generate plugin, which takes the same approach to we used for application development and applies it to framework extensions. I expect to see a whole new class of framework extenders pop up now that the structure is not a barrier to entry.
Structure generation is how dynamic languages that don't need the old-school code generation can still use automation. The domain-specific languages killed the need for the boilerplate, but anyone can still need a guiding light to where things go. Structure generation does just that.