I’m about to start a big flash project, so I was looking at Flex. I watched their video demo, and besides obviously leaving out some key steps (such as where the hell that side panel came from—they didn’t make that during the video!), I didn’t really like the RoResque boilerplate approach that they took.
In fact, I don’t like boilerplates at all. It’s against my coding philosophy. Sure, it’s nice not to have to type something that doesn’t need to be there, but if it doesn’t need to be there, why is it there at all? It’s a bunch of garbage the reader needs to muck through.
This bit me the first time I wanted to distribute a Perl module. h2xs gives you a module distribution template, but I didn’t know about h2xs at the time. So I opened up one of Damian’s modules to see what I needed. I opened Makefile.PL and started copying by hand1. I didn’t understand some of it; some of the empty definitions seemed unnecessary, but I obliged and copied anyway. Little did I know that what I copied was almost the exact boilerplate. Why was all that crap there? Why didn’t Makefile.PL look like this?
name => 'Parse::RecDescent',
That has all the information you need. “Oh, that’s straightforward” I would think, as opposed to “hmm, what’s this here for, hmm, this seems unnecessary, hmm, this seems unnecesary, hmm, this seems unnecessary”.
Boilerplates are a sad excuse for inheritance. I mean, that’s what it is, isn’t it? “I want everything the same as it was in this other project, except this thing.” But we know that it’s not a good idea to just copy an old project and start modifying it. What if there was a bug in the one you copied; there’s now a bug in the new one! So why are boilerplates any better?
“Well, because they’re small enough that you can verify that all the bugs are out of them.” I doubt that. But let’s suppose that’s true for this paragraph. That’s not the only benefit of inheritance. If you refactored some functionality into a convenience feature to the project you copied, you don’t benefit from it in your new project. If you added support for some slick graphical slide in in one project, you have to re-implement (or copy-paste again, and think of the bugs man, think of the bugs!) in the other.
Needing a boilerplate for a library, be it Flex or Ruby on Rails or whatever, is not a good thing. It’s an indication of a bad library design: a library that makes you specify more than you need to think about. If a project requires loading up a boilerplate and changing one line, the size of this project should be three lines, not the 500 from the boilerplate:
- Use the library
- What to override
- The thing you override it with
You get some benefits this way. First, readers of your code who are familiar with the library can immediately see what your program does without having to read through the whole boilerplate (or diff against the boilerplate). Second, you are free to change anything in the library code and the benefits will filter down into client programs (again, without forcing them to do a diff/patch).
But boilerplates do have their advantages, too. For example, in the library design I just presented, the library designer has to be aware of everything you’ll want to override. Now, that’s sort of a good thing, because the library designer is aware of what his interface is so he knows what will and what won’t break backward compatibility. But this is also sort of a bad thing, because library designers generally suck at deciding that. They think their word is absolute, “you shouldn’t have changed that part, it belongs to me“, when at the end of the day what matters is whether your application got written. If you need to change a configuration timeout that was stored in a source file of the library and not abstraction (see RakNet :-), you’re pretty much boned.
To do a boilerplate in an efficient manner, you have to have excellent version control support. svk can do the job, git probably can too (I actually haven’t looked into it). Basically, your codebase needs to be a branch of the boilerplate’s codebase. This means that when the guy who wrote the boilerplate (even if it’s you) changes something, you can integrate the changes back into your application. Merge conflicts will tell you when you need to rethink how part of your application works because someone rethought how the boilerplate worked.
Using version control like that is like using prototype-based OO on the entire project scale. Prototype OO tends to be high on flexibility and low on abstraction. Which is okay, but when you try to make a project that uses components from two branched projects, you have a lot of work ahead of you.
There really is no process excuse for writing code the right way. You can get some of what you want by using boilerplates and version control, but your code’s reusability will eventually suffer. At some point, you have to be a mathematician: you have to think about the essential algebra of your program and factor that into a core, and program the fluff functionality as plugins. Not soft-coding: keep general extensions in a Turing-complete language. But there is no substitute for good ol’ modular, well-thought-out design2.
Preachy rants for everyone!
1I never use copy/paste when I’m programming. In this case it means that I have to read what I’m putting in my code base, so I can start to understand it instead of just relying on “it works, leave it be”. In cases where I know what I’m doing, it forces me to refactor and abstract because I get tired of typing.
2Please note that I did not say object-oriented. Object oriented design is a great methodology to achieve modularity most of the time. But being object oriented neither implies being modular nor vice versa.