Jake Scruggs

writes ruby/wears crazy shirts

Recently Josh Cronemeyer and I were working on writing a game in Ruby. Gosu, a 2D game library for Ruby and C++, and Chipmunk, a 2D Physics engine, do lots of the heavy lifting so we thought it would be a fun Saturday afternoon thing to do. However, the examples had no tests so when we tried to change some stuff, and of course it didn't work, we were all sorts of clueless as to why.

Well, wrapping tests around legacy code is not a lot of fun but it is an effective way of debugging. Here's how I like to do it:
Step one:
Identify potentially troublesome code (As in "What the hell is that doing?").
Step two:
Write some tests that verify the functionality of the code.
Step three:
Pull out the offending code into a method or methods.

There's a fair bit of interplay between steps two and three, testing one piece may require extracting it.

Step four:
Either you've found your problem or you've accomplished four things:
1. You really understand the troublesome code.
2. You've refactored it into a more readable version.
3. You've put some code under test.
4. You at least know where the problem isn't.

I adopted this strategy after reading Michael Feathers "Working Effectively with Legacy Code" -- which is good reading.

Eventually we found the problem to be an erroneous substring.
"hello"[0] doesn't return "h"
Ex:


irb(main):001:0> "hello"[0]
=> 104
Which is the character code of 'h', so we tried:

irb(main):002:0> "hello"[0,1]
=> "h"
irb(main):003:0> "hello"[4,5]
=> "o"

Aha! Now we thought that "string"[x,y] gives you the characters between position x and y. But no, we got some really strange behavior until we realized that "string"[x,y] gives you y number of characters starting at x position. The reason "hello"[4,5] gives "o" is because if you ask for 5 things starting at position 4 there's only one character left, which Ruby is only too happy to hand over. "hello"[0,1] is the way to get the first letter, just as "hello"[1,1] is how to get the second letter.

Now one of the things that drew me to Ruby in the first place was it's intuitiveness. Often I found that if I didn't know how something worked, I could just write what I thought would work and it did. But substrings are a rare anomaly -- I find I have to look up how they work every time. And I still make mistakes even after I check the ruby doc. Does anyone know the history behind this weird syntax?

Inject has been stalking me for over 2 years.

The year was 2005 and I had decided that I would write a website in this new fangled Rails thing. But while debugging some plugin code I ran into inject. To my java encrusted eyes, it looked like this:

weird_thing = dont_know.inject({}) {|m, o| m[o] = some_crazy_method o; m}

Holy crap. I had no freakin' clue. I looked up the docs on inject and saw that inject, from what I could understand, was used to add up numbers in an array. Which confused me even more. Of course since then I've come to understand inject, but have remained wary as it can be awful confusing to those new to Ruby. Just recently I wrote about how some teammates and I decided against using it to shorten a method, because the particular use sacrificed readability. Then Brian Dainton wrote about how he loves inject. And finally, my team got in a rather spirited discussion over its use. One side of the argument was that it should be used with care as it's hard to read, especially for Ruby newcomers (whom we will be handing this project over to sooner or later). And the other side pointed out, rightfully so, that the reason we use Ruby in the first place is precisely because of powerful methods like inject. If we have to stay away from inject, or method_missing, or metaprograming, or anything else that is deemed 'too hard' then why not just write in Java or C# or Visual Basic?

All this reminded me of one my favorite quotes form George Carlin:

Have you ever noticed that anybody driving slower than you is an idiot, and anyone going faster than you is a maniac?

The funny thing is that I can see both sides of this argument. Back in 2005 I would have thought you crazy to use such a method. Now it would take only a moment to figure out that in:

weird_thing = dont_know.inject({}) {|m, o| m[o] = some_crazy_method o; m}

dont_know is probably an array full of objects and the author of the code wants to pass each one of them into some_crazy_method, get the result, and then put that result in a hash with the original value as the key. When I was a slow driver in Ruby I thought all the other speed daemons were crazy to write such complex code. Now that I'm a budding speed racer myself, it's temping to see people who can't understand my code as stupid.

At this point it would be pretty easy to wrap up this post by saying something useless like: “Use your best judgment when adding complexity, making sure to balance blah, blah, blah...” You, like everyone else on the planet, think you know the difference between too slow (code for dummies) and too fast (code for computers only). Even if you're only wrong 10% of the time (which I doubt) you're going to write a lot of horrible code.

So how do you know when you're wrong (or right)? You don't. Let me try to explain though two examples of complexity: one good and one bad.

In our application, we have a number of different ways to go through a sign up process. So we created an object called Flow. And each flow contains a number of FlowPages that specify the order of the flow. With a little bit of Ruby magic, we made it so you can define a flow like this:

NormalFlow << FirstPage << SecondPage << ThirdPage

Which is damn cool. But there was a bunch of code needed to support this. Over time we came to realize that we weren't seeing a lot of benefit from this notation. We didn't define flows that often and even if we did, the much simpler:

NormalFlow.new(“FirstPage, SecondPage, ThirdPage”)

expresses the intent just as well. When the time came to play a story dealing with putting flows into the database so the business can try different paths, we saw that the complexity was actually making it harder to use and so we threw out the old code and went with the totally unsexy “pass in a string” constructor. Lame, but way easier to maintain.

In the other example, we had a requirement that the business should be able to change any of the words on the page quickly (without a release). This, of course, meant putting the page content into the database. We created a PageContent object that, through the magic of Ruby, gets created before any view is rendered, looks up all the content that it might need, and dynamically defines methods on itself that correspond to its contents. A given page may have a title or an address_line_one_label and to access these methods in the view you can call: content.title or content. address_line_one_label and you don't have to do a thing to set this up (other that put content in the db) -- it's available in every view. And over the months since we implemented this feature it's been easy to use, extend, and maintain.

And that's really my point here. I can't just say “use your best judgment” because you already are. Furthermore, when you've just learned about, say, metaprograming you're probably going to use it more than you should. You won't have any idea if that super cool bit of Ruby is good or bad complexity until you get back in there and try to make it do something new. If the complexity fights you at every turn, it's bad and you should get rid of it. Good code you won't even notice because the tasks that touch it go so smoothly.

The other day I was showing Rails off to a friend of mine who wanted to know what all the fuss was about and I realized a shocking thing: I was horrible at starting a Rails site. Why? Because for the last year or so I've been working on large, established Rails codebases. Which is kinda cool as it shows how far Rails has come, but it sucks because one of the very cool things about Rails is how much you can do in a short amount of time.
So I resolved to create and deploy a small site as a way to exercise some atrophied muscles and have some good old fun with Ruby and Rails. My father, Leslie Scruggs, is a sculptor and I had written him a pure html site back in 1999. And he maintained it editing the raw html files, creating his own thumbnails, and uploading via ftp. Not the easiest of tasks for a man in his 60's. So I created lesliescruggs.com which has an admin section so he can upload pics and get them resized and thumbnailed with 10% of the effort.
Of course I used attachment_fu for image handling (resizing, saving, deleting, etc.) but I was impressed how much better it's gotten in the last year. You can now use ImageScience or MiniMagick as the back end image processor and you can save files to Amazon's S3. And, maybe it's just me, but it seems like it's easier to use than ever. Restful_authentication was also impressive in its gains. I've had mixed results with Rails plugins for authentication in the past, but everything went very smoothly. One of the things I really liked was the ability to omit the action mailer part of the plugin. Sometimes you just don't need to be able to email lost username/passwords and it's nice to be able to leave that code out. Another nice surprise was after upgrading to the latest IntelliJ I found that creating a project with RSpec was an option. Worked well, too.
And page caching, something I've been meaning to try, was pretty easy to implement and perfect for a site like this. All in all I highly recommend banging together a quick (this one took about 2 weeks of spare time) Rails website as you'll have fun and learn a bunch of things your day job won't teach you. Especially about deployment -- but that's another post.