Thursday, August 8, 2013

Writing Small Methods... No, I Mean Really Small Methods

Mouse and Elephant

Like many programmers, I've typically aimed to keep my methods small. On average, my methods have been probably around 8-12 lines long. But lately, I've had a blast challenging myself to see just how small I can make them!

Let's hit the bits with an example in C#. Imagine you're working on the physics side of a video game. Each video game character has physics properties like Mass, Position, Velocity, Forces that are acting upon it, and a Maximum Velocity. We've encapsulated those in a class called PhysicsBody. On each frame of the game, we'll call into the physics body to apply some simple physics rules to update the position and velocity. Here's what we've got.

The poor specimen we'll dissect is the OnTick() method, which gets called each frame of the game. Even counting whitespace, it checks in at a mere 10 lines. Not bad. But let's really wring that stinker for all we can get out of it!

First Pass

  1. The biggest bang for the buck would be to take the logic that constrains your velocity, and move it out to its own method.
  2. Let's also take the three formulas and give each of them their own method. After all, method size isn't just about the vertical -- it's also about the horizontal.

Here's the result (omitting the class context, setters, etc):

Well, we reduced the OnTick() method to six lines, but thanks to my verbose method names, we actually ended up increasing our horizontal size! But we'll take that, as it more clearly tells us what's happening on each line.

So, we've got four statements over six lines. Let's see what else we can squeeze out.

Second Pass

This round, things get a little more drastic.

  1. First, we're translating milliseconds to seconds. That kind of conversion doesn't really have much to do with our physics calculations. So instead of a float with the elapsed milliseconds, let's make a new class for the elapsed time, and give it some getters to provide the elapsed time in either milliseconds or seconds.
  2. Next, we've got the velocity constraint. Let's move the call to ClampToMaximumVelocity() into the Velocity setter. That way it'll constrain velocity no matter where you set it.
  3. Then there's just the velocity and position. Even though it won't really make the method any smaller, let's put each of those into their own well-named methods, so that readers will understand what's happening in each line.

Here's where that leaves us:

Wow, we got our OnTick() down to just two lines – and at two lines, it's the longest method in the class!

Now, although we reduced the line count of the method by 6, we actually increased the line count of the class by a good 30 lines! (Here's where all the Java programmers say, "if you had put your curly brace on the same line instead of the next line, you would have only increased the class size by 25 lines!)

Are We Better Off?

So, what do you think?

  1. Comparing our original file to our final file, which one do you like better?
  2. Was our final class more or less readable than our first class?
  3. How could the final class have been improved even further?
  4. When have we taken this "small method" thing too far?

No comments:

Post a Comment

Profile Picture
Dave Leeds
My Hobbies:
  • Programming
  • Cartooning
  • Music Writing
Full Profile