Languages Should Be Growable
One of the fun things in Computer Science is finding new and mind-blowing stuff that turns out to be 15 years or more old.
I just watched Guy Steele’s 1998 OOPSLA talk, Growing a Language. If you haven’t watched it, go watch the first ten minutes and you’ll be hooked for the rest of the talk. I don’t want to give anything away but there’s a huge bomb that he drops in the first ten minutes that not only kept me riveted for the rest of the talk, but then made me rewind it and watch it again. (Remember how you watched Sixth Sense, and the bomb gets dropped at the end and you had to watch it again? And then the director explained his use of the color red in the movie, and you had to go watch it a THIRD time to see that the bomb was constructed right there in front of your face the whole time? Yeah, Guy’s talk is like that.)
In his talk, Guy discusses whether a language should be large or small; a large language lets you say many things easily but requires that you and your listener both learn many words before you can say anything. A small language lets you both start talking immediately, but requires that you spend a lot of time creating new words before you can say anything interesting.
I won’t tell you whether Guy thinks you should create a large language or a small one–in fact, Guy won’t tell you either. But he does make it clear that a good small language must be growable, and a good large language must be both well-groomed and still growable. He even goes so far as to say that most good large languages are the ones that started small and grew over time, with good cultivation.
Bless his misguided heart, he then says that Java is a good language. I have to point out that this establishes his crazy-person street cred right there, but in a way, he’s right: Java DID start small enough to be easily understood. It grew slowly, and with careful curation. This was in 1998, and Guy then goes on to point out that Java is fundamentally broken and ungrowable unless they add some growth mechanisms to the language, such as generics and operator overloading. Most Java programmers today think of these as “having always been there” in the language, and they’re probably part of the reason Java is not only still around, but a dominant language in the industry today.
Applications Should Start Small… and be Growable
So I’m working on an new app right now, and I want to do some good OO design up front to ensure that the app looks and works well. But I’m stuck trying to figure out where to start. Funnily enough, I opened Sandi Metz’ book, POODR (Practical Object-Oriented Design In Ruby) for some guidance, and I found this astonishing guidance right there at the top of chapter two:
“What are your classes? How many should you have? Every decision seems both permanent and fraught with peril. Fear not. At this stage your first obligation is to take a deep breath and insist that it be simple. Your goal is to model your application, using classes, such that it does what it is supposed to do right now and is also easy to change later.”
Sounds familiar, doesn’t it?
Libraries Should Be Growable… or Well-Grown
I’m a fan of RSpec. If you’ll permit me stretching Guy’s language metaphor, it’s a big language for testing, with many words. I can test very complicated ideas without extending the language, and someone who has learned RSpec’s language can read my complicated ideas without learning new words.
MiniTest is a very tiny testing language. It has only a few words. As a programmer not used to constructing new words in my testing language, I initially found MiniTest to be insufferably repetitious. Each test used ten words or so, and nine of them were identical in all of my tests. When presented with this frustration, Ryan Davis shrugged with annoyance and snapped “so write an abstraction method!” It wasn’t until I watched Ryan write tests at MountainWest RubyConf this year that I realized that he does this all the time. This means that a) he was not kidding b) he was not being dismissive and c) that adding words to minitest’s language is in fact exactly how MiniTest expects to be used.
Interestingly, while I think RSpec’s large language is elegant and well-curated, many programmers feel that RSpec has grown in the wrong direction, or has at least become buried by overgrowth. Ryan felt that even Test::Unit had too much cruft in it, let alone RSpec, so rather than prune the language back, he started fresh, started small, and most importantly, started growable.
When Ryan spoke at MWRC, he created a new testing word that I felt did not make much sense. Even watching him define it I thought “Okay, I understand the abstraction, but that word is horrible. It doesn’t communicate what the word does at all.” That’s the drawback to small languages: naming things is hard, and small languages require you to name things from the start. Had I been pairing with him we’d have had a splendid argument about the name of the abstraction method he wrote. But that sort of fits into Guy’s logic as well: growth should be carefully curated. As you grow, you’ll create new words, and those words should be easy to learn and understand or you can’t communicate well.
Growth Should Be Curated
I’m gritting my teeth as I type this, but I have to own up to it: The growth of Java has been well curated. C# has also been well-groomed, even if I think the language designers have carefully and consistently solved all the wrong problems with the language.
I think PHP is probably the poster child for bad growth*. That’s in addition to its internal syntax inconsistencies; I’m just talking about the language’s internal methods. For a quick example, see how many different clumps of consistency you can find just in the string functions. For a longer example, read @eevee‘s rant, PHP: A Fractal of Bad Design. (TL;DR? Fine, just click on the rant but don’t read it–just scroll down to see HOW LONG it is.) PHP’s problem is twofold: they added things inconsistently, and they were unwilling to prune things back out of the core once they had been added. PHP has grown much faster than Java and C#, because the maintainers were willing to make mistakes rather than deliberate for years in committee, but like Java and C#, PHP hasn’t gone back and fixed mistakes once made.
In my opinion, Ruby sort of gets a B+ on growth curation. A lot of words are unnecessary synonyms (count and size and length, for example) while other words are occasionally synonyms that suddenly change meaning when you’re not expecting them to (Array#count and ActiveRecord::Base#count, for example). Some things in the language are pretty bizarre edge cases (The Kernel#test method, for example) and in the new Ruby 2 release one major feature (Refinements) was brought in under strident protest. But by and large the methods across the entire language are consistent with each other, and when they vary it is usually to be consistent with some external protocol that they are modeling. Ruby 2 was willing to break backward compatibility in order to fix mistakes and grow sufficiently. I also cut Ruby some slack because it’s growing extremely fast in comparison to other languages, and having the breaking changes in Ruby 1.9 for 3 years before committing to Ruby 2 let the community keep pace.
So Grow, But Grow Carefully
And that’s sort of my whole point here: Size and growth are key tenets at every level of abstraction: for a single application, a broadly applicable test suite, or an entire language, two rules I’m drilling into my head right now are
Start Small. I can’t say “Always Start Small” because sometimes the problem you need to solve is big. But it is fair to say “Always Start As Small As Possible”.
Start Growable. This one IS gospel for me. However big I choose to start, I think growability is essential for success.
(Bonus Rule) Curate your growth, but don’t be so afraid of growing wrong that you become afraid to grow. Be willing to grow and then weed.
And if all else fails, start over with a new small thing and start growing again.
* Note: Every time I kick PHP’s tires I get hate mail from offended PHP programmers who assume I’ve never used the language. The fact that PHP programmers are the only group worse than rubyists when it comes to language fanboyism is a topic for another day, but for now, let me just say $$dispatcher->$$method. If you’ve never written your own framework in PHP, that little snippet of code means I am better at PHP than you. I have pushed out, much like an agonizing stool the day after an all-night taco binge, a little over a million lines of PHP code. It is the foul tongue of Mordor, but I have earned the right to dislike it purely on its lack of merit. If you like it, that’s fine. It’s your choice. I’m not saying PHP doesn’t have its good points or that I can’t write clean code in it. I’m just saying it’s not worth it to me.