Then I remembered a project my friend had mentioned to me earlier. This project was Ruby Koans. Koans is a collection of unit tests where most of the code is written, but the expected values in all the asserts are left blank.
The first few are dead simple, and it seemed really silly to be doing things like:
def test_fill_in_values assert_equal __, 1 + 1 end
When first starting I wondered how it could be useful to have tests that simple. But then I ran into this one:
def test_nil_is_an_object assert_equal __, nil.is_a?(Object), "Unlike NULL in other languages" end
Still dead simple. But as someone who's used to C++ and Java the correct answer was surprising.
Some of the tests are really simple like that, geared to show you some of the basic syntax and concepts of Ruby, like array access and flow control. But later on you get to more complex tests, including ones that have you write some classes to fit the tests.
Another nice thing about Koans is that the "__" that you have to replace in the tests does not cause compile errors. It's an actual object defined by the koans infrastructure that, when run, provides a value something like
"<FILL ME IN>"
. This lets you actually run the tests before you're filled in the code, and the test output will show you what the proper answer is.I ended up slowly working on Koans while waiting for builds at work, and I couldn't get enough. I was actually kind of depressed when I stopped getting test failures. I have a feeling that Koans is one of the primary reason I stayed motivated enough to keep poking at Ruby without having any real projects to use it on.
I've always found that I learn languages fastest by actually writing code in it, and that's exactly what Koans let me do. It really is one of the best learning tools for a programming language I've ever seen. Before now I never would have considered using unit tests to create a tool for learning a language, but now I'm hoping that something like this will exist for any language I end up needing to learn in the future.
Ruby koans is an incredibly awesome way to learn ruby. More languages should have things like that.
Fascinating stuff; I'll have to try out Ruby Koans later.
ReplyDeleteI've been experimenting with test driven design in a personal project. I, too, am finding that the act of writing the tests is useful as a teaching tool; for instance, I didn't realize that the 'code' field in a Net::HTTPResponse is a string, not an integer. That would have been an annoying bug to trip over in a larger construct.
I used to think TDD got in the way of exploratory coding, but I'm beginning to think that it helps catch the problems I'm not thinking of while my brain is busy focusing on the "hard" challenges.
Unit tests let you try things much sooner than you'd otherwise be able to. I've found them very useful for verifying my code well before it was usable in the actual application. I just hadn't ever thought of using them as a way to learn a language.
ReplyDeleteWould probably work for libraries too. I'd hope that libraries would have unit tests defined already (would be worried about any that didn't), and perhaps taking a subset of those tests out and formatting them like Koans would work as a good introduction to the library for new users. I'll have to keep it in mind if I ever end up writing a library.