October 25, 2012 By Mark Anderson 1 Comment

Metaprogramming and the Ruby Object Model

Having spent the last couple weeks reviewing Pragmatic Programmer’s screencasts on metaprogramming and the Ruby object model, I discovered one thing for certain. I shouldn’t be doing any metaprogramming any time soon. It’s a tricksy endeavor frought with peril, even for seasoned Rubyists.

I kind of had a feeling that would be my conclusion based on hearing this talk at Madison Ruby by Paolo Perrotta, the guy who wrote the book on metaprogramming. In the talk, he shows just how tricky metaprogramming can make your code.

Essentially, because metaprogramming is code that writes code, you can end up with a codebase that has hidden “gotcha” methods that are created as if by magic. This often conceals what is actually going on, makes the code hard to read, hard to debug and hard to extend or modify.

Definitely an endeavor left to someone who’s a bit more of an expert than me.

That’s not to say that I didn’t learn anything. Quite the contrary. The series starts with a great overview of the Ruby object model, the call chain for methods, inheritance versus mixins, singleton methods and a whole slew of other great stuff.

I plan to cover a couple of these topics here, but as a note to the reader, a lot more has been written on these topics by people infinitely smarter than me. My coverage of the topics here is intended to be more of an exercise of completion of the section of my 1up project than an attempt at a definitive screed on the subject.

The Call Chain
When you call a method in Ruby, the interpreter looks for the definition of that method in the object that maps to ‘self’ in the current context, if that method doesn’t exist on self, Ruby moves “up the chain” and checks self’s parent class, and so on until it runs out of parent classes. Here’s an example:

# define a specific string
my_string = "I'm a string!"
# call #reverse
# 1) this first checks to see if my_string has a method called reverse
# 2) it doesn't find one
# 3) it then checks for reverse on my_string's parent class, which is String
# 4) it finds the method and executes it and outputs the following:
my_string.reverse
=> "!gnirts a m'I"

# if we define a singleton method on my_string like so:
def my_string.reverse
  "I'm overriding .reverse"
end
# and then call .reverse on my_string
my_string.reverse
# we get the result of the new method and not that of
# the default behavior of String

my_string.reverse
=> "I'm overriding .reverse"

This concept becomes important in metaprogramming because the Ruby interpreter has several “hooks” for methods, classes and modules, marshalling and coercion that can be used to execute code that extends Ruby’s functionality. When you use these hooks, you need to be sure where exactly which member of the call chain you’re attaching your meta-functionality to. For example, in the screencasts, Dave Thomas demonstrates how to attach console tracing to methods by using the method_added hook. It’s really impressive to watch him implement the code, but there are a lot of nuances that he has to work around. A list of all these hook methods can be found here: stackoverflow.com/questions/5127819/is-this-a-comprehensive-list-of-ruby-hook-methods.

One of the more well-known uses of these hooks is to use the method_missing hook to create the semantically-rich find_by_xxxx methods in Active Record where xxxx is a model attribute that is essentially a column in a database. (I sure hope I said that right)

You must realize the truth: there are no class methods
Another interesting tidbit that stuck with me was this: class methods are really nothing all that special. In actuality class methods are really just singleton methods on a Class object. The following two examples are essentially the same:

class Foo
  def self.bar
    puts "I'm at the bar!"
  end
end

# is essentially the same as
Foo = Class.new 
def Foo.bar
  puts "I'm at the bar!"
end

While this kind of prototype-based development is valid, it’s not typical Ruby style. The screencast advised that that type of idiom is more prevalent in Javascript, so I’m going to squirrel that knowledge away for my future 1up investigations into Javascript and it’s popular libraries like jQuery, Backbone, etc.

I’m sure there was a ton of information in these screencasts that just didn’t stick. It’s my hope that I’ll learn more on subsequent viewings and more practice. I’d definitely recommend them to anyone who wants to learn more about the Ruby object model and how important it is to have a deep understanding of those concepts before embarking on any metaprogramming adventures.

Also, if I’ve made any egregious errors in my explanation of concepts above, please let me know. I really want to keep this stuff straight in my head.

For my next topic, I’m going to tackle Test Driven Design (TDD) with Ruby and Rspec in an effort to write cleaner, better-designed code. I’m always amazed when I watch some of the giants in the industry sit down and drive out features and functionality with TDD, and I’m looking forward to a lot of practice.

Filed Under: 1up Project Tagged With: 1up, metaprogramming, Pragmatic Programmers
October 13, 2012 By Mark Anderson 3 Comments

The End of Learn Ruby the Hard Way

I’m finished with Learn Ruby the Hard Way. It took me way longer than I thought it would. All in all, it was a really great overview of the Ruby language, test-driven development, and project organization.

I found Chapter 37 to be one of the more valuable in the course. It’s simple enough: go through a few dozen of Ruby’s symbols and keywords, guess at what they do, look up what they really do, then write some code that shows what they do. While this may sound tedious to some, I found it incredibly valuable to get a better grounding in the Ruby toolbox and a reminder to spend time studying the entirety of the languages I use instead of just nibbling around the edges.

The course involves a good deal of repetition. Revisiting concepts and projects throughout to help drive home the fundamentals of the language. Practice and drilling on fundamentals is something that you don’t always hear about when people talk about learning to program, but it’s probably the best way to learn. Like the 10,000 hour rule says: if you want to master something you just have to do it. A lot.

One of the the aspects of the course that didn’t resonate with me was that the larger exercises focused on creating games of one sort of another. I had a difficult time dreaming up a text-based “you’re in a hallway with a door in front of you” type of game.

Luckily, my office has a mostly-weekly Ruby quiz. One of the challenges was to develop a blackjack program and it coincided nicely with one of the game development chapters. I was excited to dive in and began making good progress. As I implemented rules, the card deck, and other aspects of the game, I discovered something. My code was a mess. Blech. There were instance variables all over the place, methods that did all kinds of different things…an unmitigated disaster. But it ran!

Great, so I had basically created the AMC Pacer of blackjack programs, the Spruce Goose of Ruby scripts. When it came time to show my code, I told everyone how dissatisfiled I was with the way it turned out. Thankfully, I work with a supportive group of people (MINiSWAN) who had a lot of great suggestions. The most useful feedback I got was the following: “your code works, but it’s not clean.”

So, I’ve got some things to add to my research list: SOLID principles and Clean Code, by Kent Beck. I hope to return to my blackjack trainwreck and fix it after some practice with these concepts.

It’s clear that my study of Ruby as a language will take me longer than one month. I had a feeling when I set out to cover a different topic every month that some would probably spill well over that limit. In those cases, I can either “call it” and move on or take the extra time, depending on the situation.

In this case, I feel it’s well worth it to stick with my study of Ruby for at least another month. The next topic I plan to cover is Pragmatic Programmer’s screencasts on metaprogramming and the Ruby object model. I’ve watched a few of these already and I’m looking forward to going through the rest.

Special thanks to Joe Nelson for sending me a virtual pants-kick via Twitter.

Filed Under: 1up Project Tagged With: 1up, ruby
August 30, 2012 By Mark Anderson 3 Comments

Learn Ruby the Hard Way – the Halfway Point

I’ve been plugging away at Zed Shaw’s Learn Ruby the Hard Way and made it to the half-way point tonight. So far, so good. I haven’t discovered anything earth-shattering just yet. I think the biggest thing that’s stood out for me thus far is an idiom of string substitution I’ve not seen before. It involves [...]

Continue reading...
Filed Under: 1up Project Tagged With: 1up, ruby, string interpolation
August 28, 2012 By Mark Anderson 2 Comments

The 1-Up Project, Player 2

spacer

Earlier this summer, Joe Nelson embarked on a quest to become a world-class developer over the course of one year. He calls it his “1up Project“. The approach is 2-week iterations of concentrated study on a variety of topics ranging from the HTML5 Canvas to PPC advertising. Each 2-week sprint culminates with a blog post, [...]

Continue reading...
Filed Under: 1up Project Tagged With: 1up, Rails, ruby, self-study
July 7, 2012 By Mark Anderson Leave a Comment

Go to UXMad. Seriously. It’s gonna be awesome.

spacer

UXMad is coming. Some of the greatest minds in User Experience will be descending on the Overture Center in Madison, Wisconsin on July 19 through the 21st. If your product, application or service has any room for improvement you owe it to yourself to attend. The conference is single-track, so you won’t miss a thing. [...]

Continue reading...
Filed Under: Culture, Design, Doodle Tagged With: Doodle, UXMad
January 6, 2012 By Mark Anderson 1 Comment

Priorities

spacer

A quick reminder on a Friday: nobody’s dying words are “I wish I had spent more time at the office.”

Continue reading...
Filed Under: Doodle
« Older Posts
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.