Subscribe
Elsewhere
Wednesday
10Jun

Where We Came From

I had many favorite books when I was growing up, but one has always stuck with me. The book is The Cartoon Guide to Computer Science by the great Larry Gonick. It traces the history of computer science and explains how logic gates work, why a computer subtracks by adding, and why sloths count in binary. it’s as good as David Macaulay’s The Way Things Work which is, after all, the greatest book ever written. (The Way Things Work rates slightly higher, on account of its sheer inexhaustibility.)

When I arrived at Bard College as a freshman, I wanted to study Computer Science History. I had stories of Charles Babbage, Ada Lovelace, and Alan Turing bubbling in my mind. I wanted to learn more about where it all came from. What happy accidents and brilliant insanities had built on top of one another to construct our modern computational world?

No one would teach me the history of computer science, so I settled for what I could pick up on my own. Soon I discovered the computational pioneers of the modern era. I learned how Alan Kay created Objects; how his GUI at PARC inspired Steve Jobs and Apple to create the Macintosh, which in turn inspired Windows and set the standard for computer interfaces; how his Smalltalk inspired Objective-C and Ruby, which was also highly influenced by John McCarthy’s Lisp. I learned how Linus Torvalds and Richard Stallman built the two great empires of Free Software, Linux and GNU, living in symbiosis, and leading the way for the Open-Source Movement. I learned of giants, gods, and titans, and I learned that they were my ancestors. And then I realized something:

These people are still alive.

This still boggles my mind. These are great men and women of history, and they’re not dead yet. We can still go ask them questions. We can even work with them, learn directly from them. How lucky we are to live in an age of such rapid change that our Great Old Ones are still among us!

May we young grasshoppers be wise enough to seek their wisdom.


Corey Haines is touring the country pairing with all sorts of great programmers. As he’s travelled, he’s filmed a series called “Road Thoughts”. In his latest entry, Corey discusses the importance of learning and remembering our history. I think he’s absolutely right.

Tuesday
09Jun

tracker_chat 2: Chat Harder.

I’ve updated the tracker_chat script. Now you can:

  • Drag a story to the chat. Its URL will be added to the chat input box so you can say something about it.
  • Click a story URL someone has posted to the chat. That story will be revealed in Tracker without opening a new page.

Hopefully these changes will make it easier to discuss Tracker stories in chat.

To install tracker_chat, install Greasemonkey in your Firefox 3, and then click here: Install tracker_chat

Wednesday
03Jun

Pivotal Tracker & drop.io chat, together as one.

My Tracker has chat built in, and so can yours.

At drop.io, we’re in the process of moving from Lighthouse to Pivotal Tracker. Lighthouse is great for storing bugs, for searching them, and for maintaing a threaded conversation on each one. It works well for the open source development model. That’s basically what we used to do.

Now we’re moving to an Agile model. We create and deliver many small amounts of customer value, we work in an iteration-based rhythm, and we work together as a team, or at least we’re aware of what everyone else is working on. Tracker is perfect for that workflow. But this isn’t a post about how awesome Tracker is. This is a post about how I made it a little more awesome.

tracker_chat

We all sit in chat all day, and naturally we use drop.io as our chat service. It works really well, because when it doesn’t, we fix it. I usually keep it up on my laptop screen while I work on my external monitor.

But Tracker updates itself in real time, so it’s nice to keep it up all the time too. So now I want to have it on my laptop screen.

Now I have both.

Requirements

  • Firefox
  • Greasemonkey

To Install

  1. Navigate to the script.
  2. If you haven’t created a drop to chat in, create one at drop.io. (One click, no signup.)
  3. Go to your Tracker project.
  4. From the Views menu, choose “Chat…”.
  5. Give it the name of your drop.
  6. Enjoy!

GreaseKit

Unfortunately, tracker_chat doesn’t work perfectly in GreaseKit. The chat will appear in Tracker, but with the full chrome you’d see if you viewed the chat normally. In Firefox/Greasemonkey, extraneous chrome is hidden to save as much real estate as possible.

More Info

Check it out on GitHub at http://github.com/Peeja/tracker_hacks.

Wednesday
22Apr

Harder, Better, Faster, Stronger

Today marks the end of the first week of Agility at drop.io!

One week earlier…

Every Tuesday we start the day with a full-team meeting which we call a scrum (though it’s not quite a real scrum meeting). At last week’s scrum, Sam and Jacob introduced our new development practices:

  • We operate in two-week cycles (or iterations).
  • There are four areas of development to work on.
  • Each cycle is dedicated to working on one of the four areas.
  • Stories are written on the board.
  • To claim a story, a developer puts their name next to it.
  • When a story is complete, it’s erased and put on a piece of paper, which is taped to the “Ready for Staging” area.
  • When a story is deployed to staging, it’s moved to “Staging”.
  • When everything in staging has passed QA, we can deploy to production.
  • When a story is deployed to production, it’s moved to the production wall.

That’s about it. Now there’s a lot about Agile that’s not here. There’s no story estimation. There’s no iteration planning. Stories can be added mid-iteration (and often are). The product owner role is almost non-existent. The developers implement stories in the order they choose.

But it’s a start. Even this much is a huge change for us, and a very welcome one. It’ll be a while before we’re comfortable enough to wade further in, and I’m ok with that. We’re learning every day about how to make this work.

We’ve included the most important element of Agile development, however: regular retrospectives. As long as you review your process and your progress regularly (and honestly), it’s hard to go wrong. Over the next few months I expect we’ll rapidly adopt even better practices for our team as we discover what those are.

Next week I’ll write up how our first retrospective goes.

Sunday
12Apr

Abstract Classes, For Ruby: Abstraction

Let’s say you’ve got a class called Car. There are two subclasses of Car: Convertible and Sedan. And it turns out that all cars are either convertibles or sedans. (Who knew?) So really, there’s no reason that a car object wouldn’t be an instance of Convertible or Sedan, and in fact an object that’s a direct instance of Car itself won’t even work correctly.

class Car
  def go_forward
    # ...
  end
end

class Convertible < Car
  def door_count
    2
  end
end

class Sedan < Car
  def door_count
    4
  end
end

How would you write Car#doors? You wouldn’t, because unlike moving forward, that behavior isn’t shared across all cars. Car is an abstract class: a class that should never be instantiated directly.

But what’s stopping us? Nothing. And that’s a problem. So let’s fix it:

$ sudo gem install abstraction

Then:

require 'abstraction'

class Car
  abstract

  def go_forward
    # ...
  end
end

Car.new
#> AbstractClassError: Car is an abstract class and cannot be instantiated

But:

Convertible.new  # => #<Convertible:0x8fdf4>

Awesome.

Awesome? Why so awesome?

Ok, let’s take it back a step. You’ve got a Car class with no subclasses. They haven’t been necessary, and you don’t want to add complexity you don’t need. Good for you.

class Car
  def go_forward
    # ...
  end
end

Cars go forward, and that’s about it. Except, now some parts of the code want to know how many doors a car has. Remember, that depends on the kind of car it is, so we’ll need Car to know about its type. And since convertibles are pretty rare in your code, you have cars be sedans by default.

class Car
  attr_reader :type

  def initialize(type=:sedan)
    @type = type
  end

  def door_count
    case type
    when :convertible
      2
    when :sedan
      4
    end
  end

  def go_forward
    # ...
  end
end

Pretty soon you realize its time to refactor this puppy. You want a refactoring called Replace Type Code with Subclasses. What you end up with is the set of classes we saw at the beginning:

class Car
  def go_forward
    # ...
  end
end

class Convertible < Car
  def door_count
    2
  end
end

class Sedan < Car
  def door_count
    4
  end
end

The problem is that all of your tests are passing, but none of your code is using the subclasses yet. You could probably grep or ack through your source to find all of the times you use Car.new; in fact, you should. But you should still be testing that you’ve done it right. Also, if Car is backed by an ORM, it might be creating Car objects for you.

But as we’ve seen, Abstraction clears that all up. Just make the class abstract…

class Car
  abstract

  def go_forward
    # ...
  end
end

…and watch your tests fail. When they pass again, you’ve completed the refactoring.

Abstract Methods

(Warning: this section is a bit of a tease.)

Traditionally, abstract classes are found in strongly typed languages, where the compiler makes sure they’re never created by type checking. In the Ruby world, the test suite is essentially our type checker. No complier can statically prove that an abstract Ruby class will never be instantiated, but we can exercise the test suite and see if it ever happens.

Abstract classes usually have a way to notate abstract methods. These are methods which are declared in the superclass, but don’t have an implementation there. A concrete subclass has to implement all of the abstract methods. Again, this is checked by the type checker.

We have an example of an abstract method above, it’s just not denoted in any way: #door_count. Similar to the case of abstract classes, we can’t prove statically that abstract methods are implemented in the concrete subclasses. We have to run the tests and see if they’re defined when they’re called.

But: if they’re called and there’s no implementation, we’ll get a NoMethodError anyway. The declaration of an abstract method in the superclass is really only useful to the type checker, to tell it that, for instance, any Car object has a #door_count method. We don’t have a type checker. So we don’t need to declare abstract methods.

But wouldn’t it be useful?

It would be, if it were meaningful. The problem is: what does it mean to implement a method? In Ruby you really can’t know whether a method is implemented until you send it the message and see if it raises a NoMethodError. There’s no way to determine whether a class “implements” all of its superclasses abstract methods without making assumptions like that the class doesn’t use method_missing or that instances of the class won’t get their own singleton implementations. And the nail in the coffin: there’s no time when a Ruby class is done being implemented, so there’s no time to check.

On the other hand, maybe there’s a way to make it useful. If there is, it certainly belongs here, so drop me a line or just fork away.

Where’s the Code?

Grab the source from the GitHubs. Pull requests more than welcome.