Deep Simplicity

So, I am a huge fan of ThoughtWorks. I really think that the crew over there are on the edge of everything I strive to be as a good developer. Many of the software development best practices are pioneered by people like Martin Fowler that work there. I recently picked up the book The ThoughtWorks Anthology and was impressed by many of the articles. Probably my favorite was the the one written by Jeff Bay titled "Object Calisthenics." He talks about 9 steps to better software design through a concept called "Deep Simplicity", and I like them. A lot.

  1. Use only one level of indentation per method
  2. Don't use the else keyword
  3. Wrap all primitives and strings
  4. Use only one dot (-> in PHP) per line
  5. Don't abbreviate
  6. Keep all entities small
  7. Don't use any classes with more than two instance variables
  8. Use first-class collections
  9. Don't use any getters/setters/properties

Holy cow, I bet some of you are freaking out already! Don't use getters or setters?!? Don't use more than two instance variables per class? Impossible! Although I am not sure you have to comply to these rules 100% of the time, I think keeping them in mind when developing is going to help you write better code.

I recently posed the following chunk of code to a co-worker:

class WidgetStockRoom
{
    protected  $widgets;

    public function getStockedWidgets($limit)
    {
        $inStockWidgets = array();

        if ($limit <= 0) {
            return $inStockWidgets;
        }

        foreach ($this->widgets as $widget) {
            if($widget->isInStock()) {
                $inStockWidgets[] = $widget;
            }
        }

        return $inStockWidgets;
    }
}

I then asked him to "make it better". He ended up with the same basic loop just with less lines. I then showed him my improved version taking the first rule into account.

class WidgetStockRoom
{
    protected $widgets;

    public function getStockedWidgets($limit)
    {
        if ($limit <= 0) {
            throw new IllegalParameterException('Limit should be a positive integer');
        }

        return new LimitIterator($this->allInStock(), 0, $limit);
    }


    public function allInStock()
    {
        return new InStockFilter($this->allWidgets());
    }


    public function allWidgets()
    {
        return new ArrayIterator($this->widgets);
    }
}

class InStockFilter extends FilterIterator
{
    public function accept()
    {
        return $this->getInnerIterator()->isInStock();
    }
}

Now, as I often say, there is no such thing as "the right way" to solve a problem. I do feel that the solution I came up with is better, the improvements being garnered through applying rule #1: one level of indentation. In fact, I only indented once in the check to see if the $limit value was valid. Everything else is at the default indentation style for class methods. What we got as a result was an improved API that allows a consumer to get all widgets, all widgets that are in stock or a limited number of widgets that are in stock, which was the original requirement. We also get a completely reusable filter object that can accept a list of anything as long as the objects in the list implement the isInStock() method.

Next post will be about rule #2: Don't use the else keyword.

blogroll

social