I think code generators are evil.
There. I said it.
That’s why this article struck me as strange. It makes all the right arguments, but misses on the conclusion:
To me the important lesson for the Java community to take away from Rails is that you should consider using code generation where appropriate. I think doing code generation is something you have to be careful about, however. If you make a code generator, then you have to pay time up front building the generator, and you have to support the generator thereafter. It makes sense when you’re going to get a good payback, which means you’ll be using it regularly. It also helps if you can use an existing tool to generate code. For example, you could use Ruby on Rails. Or, you could use existing Hibernate tools to reverse engineer mapping files and POJOs from existing database schemas.
My personal experience
I try to avoid code generators as much as possible. I learned that lesson the hard way.
I once worked on a client-server application written using Visual C++. I generated the application skeleton using the MFC wizard, and then went on to build the application and customize the UI. Week three into development, I managed to break the application.
I spent the next couple of days peering over thousands of lines of undocumented code which I never wrote, trying to figure out what I broke. It ended up being a one-line change in some generated MFC class. I don’t know how it got there, I do know that I learned a lot about MFC internals during those two days, but made no progress on the project.
The second lesson, when I decided to use an O/R code generator. To tweak the code to work better the object-oriented way, you change the class representing the database entity. But when you change the database schema, you re-generate the code and lose your changes. Reapplying those changes is a pain, not to mention unmaintainable.
Or you can put your changes in subclasses, but that creates a different problem. That took me a while to realize: I’m writing thousands of lines of code that do lookups to get factories to create abstract objects that are typecasted. All that so I can make a two-line change to some generated class. That’s not less code, that’s more code.
I appreciate what code generators are trying to do: simplify development. But they look at one slice of the development lifecycle, and ignore the big picture.
Ruby: Augmentation, not generation
Rails doesn’t require code generators. It has generators that create skeleton files for controllers, models and test cases, but those just save you the two minutes it takes to create a new file. Most of the time I just copy files around instead of using them. Most important: they never get in my way.
And what about the magic that is ActiveRecord? Again, Rails doesn’t generate code, it augments existing code with default behavior. Dynamic languages are great at that.
Any change you make to your code will override the default behavior, so customizing is easy. And you only write code for the parts you need to customize, so it gets you up and running quickly.
Now, make a change to the database schema. Since Ruby doesn’t generate code, you don’t need to re-generate it and you don’t lose your changes. But you do get new default behavior based on the new database schema. Without running anything. It just works.
Best of all, you only deal with one class for each database entity, so you don’t have to mess around with factories, typecasts, IoC or any other design pattern invented to fight complexity.
The beauty of Rails is that it does’t require code generation, and only does the bare minimum. It works by augmenting your source code with fallback behavior that deals well with the common case. And it does so dynamically, you don’t need to run anything to keep it synchronized.
If there’s a lesson here for the Java community is: don’t build more code generators, build less code generators.
Thought Leadership