Deep Simplicity - Rule 3

The next rule is one that I think is vitally important to the PHP community: Wrap all Primitives and Strings. I think there are two reasons that PHP developers struggle to grasp the concepts of Domain Modeling. Both are related to the PHP language itself. The first is that I think many, if not most, PHP developers start out with procedural programming and then move on to object-oriented development. The second is the concept that many object orientated languages have that "everything is an object". In PHP nothing is really an object. As a result, PHP developers tend to think of everything in terms of arrays. This prevents them from making the fundamental leap from simple OOP to Domain Model development, which means that you break everything down into objects with distinct responsibilities and well-defined relationships.

A key way to start thinking in objects is to literally try to make everything an object. I find many PHP developers are afraid of objects. They often avoid them by using the excuse that they are "slow", this of course it total crap. Objects have been plenty fast ever since PHP 5 came out - years ago now. Okay, let's get to some code. Our example this time will be a simple function that takes hours, minutes and seconds and converts them into number of elapsed seconds.

public function elapsed($hours, $minutes, $seconds)
{
   $elapsed = 0;

    if ($hours < 0) {
        throw new InvalidParameterException('Hours must be a positive integer');
    }

    if ($hours > 0) {
        $elapsed += $hours * 3600;
    }

    if ($minutes < 0) {
        throw new InvalidParameterException('Hours must be a positive integer');
    }

    if ($minutes > 0) {
        $elapsed += $minutes * 60;
    }

    if ($seconds < 0) {
        throw new InvalidParameterException('Seconds must be a positive integer');
    }

    if ($seconds > 0) {
        $elapsed += $seconds;
    }

    return $elapsed;
}

Although this example is very contrived, it is a valid problem to be solved. The key to writing bug-free code is to make sure that you make no assumptions about the data you are processing. We have to verify that the provided values are valid for numeric processing, because we are dealing with simple scalar values we must ensure that we are not assuming that the variables are positive integers. The code in the previous example is made more semantically clear by the naming of the function arguments as $hours, $minutes, $seconds but what if they were named $a, $b, $c? Without commenting, we would need to assume that the value in $a was indeed hours. If someone passed in the values in an incorrect order, we then have a difficult to debug problem. By wrapping our scalar values in a simple Value Object, we end up with a much simpler function free from dangerous assumptions:

public function elapsed(Hours $hours, Minutes $minutes, Seconds $seconds) {
    return $hours->inSeconds() + $minutes->inSeconds() + $seconds->value();
}

As you can see, we once again have drastically reduced the complexity of the solution to our problem. In the end, we have no assumptions left as the interpreter is going to guarantee that the parameters are passed in the correct order, even without type hinting we are not tripped up by the variables being named $a, $b and $c since we are only performing simple addtion in our method.

Next time we look at rule #4: Use only one -> per line.

blogroll

social