giant robots smashing into other giant robots

Written by thoughtbot

cpytel

Isn’t the last stage of grieving acceptance?

In episode #10 of the Giant Robots Smashing into other Giant Robots podcast, Ben Orenstein is joined by Joe Ferris and Mike Burns.

They start off with some recommendations for awesome programming books and then dive right in to questions about not following “Tell don’t ask” in the view, how MVC and the Single Responsibility Principle may be at odds with “Tell don’t ask” in the view, and what a more object oriented approach may look like. They also discuss “Class-oriented programming”, what it is, why it is bad, how Rails does it, and how to avoid it. They take a quick trip through Mike’s experiments in Ruby and Smalltalk in creating his own programming language. The three codecateers then take on the really important topic of method order and code organization, and finally they reflect on how their code has changed over the years, how no solution is foolproof, and how to move to the next level as a programmer. These topics and more, in this installment of the GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS podcast!

To have us answer your questions on the air

Email your questions to info@thoughtbot.com or tweet to us @thoughtbot.

Notes & Links

Upcoming Events

Follow @thoughtbot, @r00k, @joeferris, @mikeburns on twitter.

codeulate

Tell, Don’t Ask

And now, a friendly message from your local Tell, don’t ask Department.

Example 1

Not so good:

<% if current_user.admin? %>
  <%= current_user.admin_welcome_message %>
<% else %>
  <%= current_user.user_welcome_message %>
<% end %>

Better:

<%= current_user.welcome_message %>

Example 2

Not so good:

def check_for_overheating(system_monitor)
  if system_monitor.temperature > 100
    system_monitor.sound_alarms
  end
end

Better:

system_monitor.check_for_overheating

class SystemMonitor
  def check_for_overheating
    if temperature > 100
      sound_alarms
    end
  end
end

Example 3

Not so good:

class Post
  def send_to_feed
    if user.is_a?(TwitterUser)
      user.send_to_feed(contents)
    end
  end
end

Better:

class Post
  def send_to_feed
    user.send_to_feed(contents)
  end
end

class TwitterUser
  def send_to_feed(contents)
    twitter_client.post_to_feed(contents)
  end
end

class EmailUser
  def send_to_feed(contents)
    # no-op.
  end
end

Example 4

Not so good:

def street_name(user)
  if user.address
    user.address.street_name
  else
    'No street name on file'
  end
end

Better:

def street_name(user)
  user.address.street_name
end

class User
  def address
    @address || NullAddress.new
  end
end

class NullAddress
  def street_name
    'No street name on file'
  end
end

Good OOP is about telling objects what you want done, not querying an object and acting on its behalf. Data and operations that depend on that data belong in the same object.

Tell, don’t ask!

Next Steps & Related Reading

Ruby Science

Detect emerging problems in your codebase with Ruby Science. We’ll deliver solutions for fixing them, and demonstrate techniques for building a Ruby on Rails application that will be fun to work on for years to come.

Grab a free sample of Ruby Science today!

qrush

stupid ruby tricks

Over the past few months of slinging Ruby here at Thoughtbot, I’ve picked up quite a few stupid ruby tricks smart ruby techniques that really help out your code. If you’ve got your own, feel free to leave a comment.

Destructuring yielded arrays

def touch_down
yield [3, 7]
puts "touchdown!"
end

touch_down do |(first_down, second_down)|
puts "#{first_down} yards on the run"
puts "#{second_down} yards passed"
end

=> "3 yards on the run"
=> "7 yards passed"
=> "touchdown!"

At first glance, this barely looks like valid Ruby. But somehow, it just makes sense: it splits up the array. If you’re going to pull out the values of the array inside of the block, why not just do it when you’re defining the block-level variables? This doesn’t seem to work nicely (in 1.8.7 at least) for Hashes, though.

Pulling out elements of an array

>> args = [1, 2, 3]
>> first, *rest = args

>> first
=> 1

>> rest
=> [2, 3]

I knew about splitting up arrays before into individual arguments, but I didn’t know that you could easily get an array of the rest. Perhaps this is Lisp inspired?

Hash#fetch

>> items = { :apples => 2, :oranges => 3 }
=> items = {:apples=>2, :oranges=>3}

>> items.fetch(:apples)
=> 2

>> items.fetch(:bananas) { |key| "We don't carry #{key}!"}
=> We don't carry bananas!

This is just a nice little way to provide some default behavior that might be nicer than checking if the value exists in the hash first.

Hash#new with a block

>> smash = Hash.new { |hash, key| hash[key] = "a #{key} just got SMASHED!" }
=> {}

>> smash[:plum] = "cannot smash."
=> {:plum=>"cannot smash."}

>> smash[:watermelon]
=> {:plum=>"cannot smash.", :watermelon=>"a watermelon just got SMASHED!"}

This is a really neat way to cache unknown values for Hashes (read: memoization!) I also heard it’s awesome for implementing a Fibonacci sequence.

Array#sort_by

>> cars = %w[beetle volt camry]
=> ["beetle", "volt", "camry"]

>> cars.sort_by { |car| car.size }
=> ["volt", "camry", "beetle"]

So, Array#sort_by sorts based on the return value of the block. It’s like a built in #map and #sort that rules even more with some Symbol#to_proc magic.

String#present?

>> "brain".present?
=> true

>> "".present?
=> false

I’m sure most Rails developers know about blank? from ActiveSupport, but what about present?. Yeah, it blew my mind too. I like being as positive as possible in conditionals, so toss out those !something.blank? calls today and start using this.

jyurek

Leaving business in the office

I’ve always had a hard time separating work and home. The problem with being paid to think is that you don’t need your tools in front of you to keep working; you have your brain, you’re good to go. The problem comes in where you can’t stop thinking about a particular difficulty in your job.

I attended Mike’s 30th birthday party on Friday, but was completely unable to get a problem out of my head that had been there since the beginning of November or so (and before you ask, no I didn’t work it out Friday either). Unfortunately, the inability to stop thinking (which is one of my big personal faults), plus the fact that I didn’t know anyone else there, plus the fact that I’m a habitual pacer meant that for the first hour or so I was just walking around a room of people I don’t know, not talking to anyone. I must have looked like a complete loon!

And to think, this could have been avoided if Java would have allowed multiple inheritance. But that’s a post for another time.