PHP in Action Rotating Header Image

Bad code is good for you?

Spaghetti Code
Image by Balakov via Flickr

In The importance of bad code (or, WordPress and why I am a psychic), Marco Tabini proposes the idea that we need bad code. Or at least that we should be tolerant of bad code in open source projects because that invites participants that might otherwise not contribute.

This is an interesting idea that struck me as novel. But after thinking more about it, I believe it’s not a radical departure from what we’re all implicitly accepting, no matter how fanatical we might be about clean code.

Continue reading →

Share/Save/Bookmark

Don’t refactor without unit tests

Google "Testing on the Toilet"
Image by niallkennedy via Flickr

Brandon Savage is writing a series on code improvement using a code example (starting with Peer Review: Taking Code And Making It Better). In other words, it’s about refactoring, which is practically my favorite subject. Although I don’t agree with all of it, it’s mostly good advice. I recommend it.

That said, I do have something important to add. The series is missing the first, most basic rule: Don’t refactor unless you have good automated test coverage (typically with unit tests). And if there are no test, write them before you start refactoring. If you don’t, you’ll make mistakes and get lost in a frustrating bug search, unless you’re very stingy and don’t refactor too much. With test coverage, you have freedom to experiment, to change something and change it back if you don’t like the result. This, above all, is what makes refactoring such a great learning experience.

Some of those who have commented on the post Peer Review: Looking Into Abstraction (Greg Beaver, Jeff Carouth) mention testing and point out the need to inject objects so that they can be replaced with mock objects for testing. This is a wise move, and practically unavoidable in this case. To support refactoring, unit tests need to be run frequently, without accessing outside services (twitter or email in this case) that take time to process.

This means that in this case, it’s actually necessary to refactor a bit before proper unit tests can be implemented. This is what Michael Feathers calls the Legacy Code Dilemma in his book Working Effectively with Legacy Code. Certainly building this dilemma into new code is not a good idea. Make the code unit-testable before it’s too late.

Reblog this post [with Zemanta]

Share/Save/Bookmark

Real programming with PHP 5.3 (part 4): A more realistic example

Let's be realistic
Image by hartboy via Flickr

My previous example in part 2 was just “hello world”, so I’m going to try for something more like the real world. You may find this example unusual, but it does work. I took the PageRange class I used in my July 2007 php|architect article and converted it to the JavaScript style. The class is a variation on Martin Fowler’s Range pattern, and is the hub of a re-implementation of the main functionality of PEAR Pager, using a more object-oriented style.

A Range object is defined by just two values (three in my variation), so it might seem like too much to have an object just to keep these values, but as you can see from the example, a Range class can have behaviors to change and compare ranges.

As before, I’m defining most of the methods inside the constructor.

<?php
class PageRange {
    public $start;
    public $end;
    public $length;

    private $moveToStartAt;
    private $moveToEndAt;
    private $changeLengthToEndAt;
    private $includes;
    private $isInside;
    private $extendsBeyondStartOf;
    private $extendsBeyondEndOf;
    private $truncateToFitInside;
    private $moveToFitInside;
    private $asArray;

    public function __construct($start,$end,$length) {
        $self = $this;
        $this->start = $start;
        $this->end = $end;
        $this->length = $length;

        $this->moveToStartAt = function($start) use ($self) {
            return PageRange::withStartAndLength(
                $start,$self->length);
        };

        $this->moveToEndAt = function($end) use ($self) {
            return PageRange::withEndAndLength($end,$self->length);
        };

        $this->changeLengthToEndAt = function($end) use ($self) {
            return PageRange::withStartAndEnd($self->start,$end);
        };

        // Comparisons

        $this->includes = function($page) use ($self) {
            return $page >= $self->start
                && $page <= $self->end;
        };

        $this->isInside = function($range) use ($self) {
            return $range->includes($self->getStart())
                && $range->includes($self->getEnd());
        };

        $this->extendsBeyondStartOf = function(PageRange $range) use ($self) {
            return ($self->getStart() < $range->getStart());
        };

        $this->extendsBeyondEndOf = function(PageRange $range) use ($self) {
            return ($self->getEnd() > $range->getEnd());
        };

        // Changes

        $this->truncateToFitInside = function(PageRange $larger) use ($self) {
            if ($self->isInside($larger)) return clone $self;
            return $self->changeLengthToEndAt(
                $larger->getEnd());
        };

        $this->moveToFitInside = function(PageRange $larger) use ($self) {
            if ($self->isInside($larger)) return clone $self;
            if ($self->extendsBeyondEndOf($larger))
                return $self->moveToEndAt($larger->getEnd());
            if ($self->extendsBeyondStartOf($larger))
                return $self->moveToStartAt(
                    $larger->getStart());
        };

        // Convert to array

        $this->asArray = function() use ($self) {
            return range($self->start,$self->end);
        };

    }

I’ve defined the static methods in the usual way, non-JavaScript style. And there is, of course, the mandatory __call() method.

class PageRange...

    public function __call($method,$args) {
        return call_user_func_array($this->$method,$args);
    }

    public function getStart() { return $this->start; }

    public function getEnd() { return $this->end; }

    public function getLength() { return $this->length; }

    private static function calculateEnd($start,$length) {
        return $start + $length - 1;
    }

    private static function calculateStart($end,$length) {
        return $end - $length + 1;
    }

    private static function calculateLength($start,$end) {
        return $end - $start + 1;
    }

    public static function withStartAndLength(
        $start,$length)
    {
        return new self(
            $start,
            self::calculateEnd($start,$length),
            $length
        );
    }

    public static function withEndAndLength($end,$length) {
        return new self(
            self::calculateStart($end,$length),
            $end,
            $length
        );
    }

    public static function withStartAndEnd($start,$end) {
        return new self(
            $start,
            $end,
            self::calculateLength($start,$end)
        );
    }

}

An interesting aspect of this class is the fact that the constructor is private, so you have to use one of the creation methods. That’s part of my variation on the range pattern.

Share/Save/Bookmark

Sounds like an average PHP app to me

Delete key on PC keyboard
Image via Wikipedia

Dean Wampler blogs: Is the Supremacy of Object-Oriented Programming Over?

“The fact is, for a lot of these applications, it’s just data. The ceremony of object wrappers doesn’t carry its weight. Just put the data in a hash map (or a list if you don’t need the bits “labeled”) and then process the collection with your iterate, map, and reduce functions. This may sound heretical, but how much Java code could you delete today if you replaced it with a stored procedure?”

Share/Save/Bookmark

Most confused discussion in the known universe

If You're Not Confused
Image by B Tal via Flickr

How confused can a discussion get? As confused as the discussion in the comments to Benjamin Eberlei’s Explicit Code requires no comments – Only bad code does. This discussion has a fake identity, and nobody seems to notice. As you can see, the blog post claims to be about code comments, but it isn’t. The example given does not adress the issue of commenting. In the refactored version, Benjamin has not removed the comment from the original, and done nothing (OK, a tiny bit) to replace it with expressive code.  Since the example is irrelevant to the subject matter, it fails to keep the discussion grounded, allowing it to degenerate into dogmatic opinion and subjective speculation.

Also contributing to the confusion is an apparent lack of understanding of the process of refactoring. Refactoring is not a deterministic process, nor is it a strait jacket. You have choice, and you should learn to exercise it judiciously. You take a chunk of code, change it somewhat, and then you decide whether there’s actually been an improvement. If there hasn’t, as many think in this case (and I’m somewhat inclined to agree with them, although Benjamin has great principles and valid points), you have three choices:

  1. Refactor further, hoping to arrive at something more satisfactory.
  2. Undo the change and try something else.
  3. Undo the change and keep the original version if you think that’s the best you can do.

These are the normal choices for those of us who refactor routinely. It happens often enough. Even if you undo the change, it doesn’t necessarily mean you’ve wasted your time. You’ve probably learned something.

In this case, too, there is a chance to learn something worthwhile if you can distance yourself from the noisy confrontation. The most obvious thing to observe is that trying to extract methods from a 6-7 line method is a suicide mission in the circumstances. It’s bound to increase the volume of code a lot, and it’s only natural that the result gets labeled “bloated”. If you do something similar with a longer method, the percentage increase is much less, and you have a chance of not drowning in irrelevant criticism.

Share/Save/Bookmark

Show me your code comments and I’ll show why you don’t need them

Brandon Savage has written a blog post On Code Commenting And Technical Debt. He believes that code comments are a good way to minimize technical debt.

I’m surprised to find the term technical debt mentioned without being accompanied by the term refactoring. Refactoring is generally recognized (outside the PHP world) as the way to pay down technical debt. Commenting may help, but is clearly the second-best practice.

Martin Fowler puts it this way:

Technical Debt is a wonderful metaphor developed by Ward Cunningham to help us think about this problem. In this metaphor, doing things the quick and dirty way sets us up with a technical debt, which is similar to a financial debt. Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice. We can choose to continue paying the interest, or we can pay down the principal by refactoring the quick and dirty design into the better design. Although it costs to pay down the principal, we gain by reduced interest payments in the future.

Brandon’s argument in favor of commenting is perfectly valid, but misses the crux of the matter, since he ignores the option of actually improving the code itself rather than just adding comments.

Let me also comment briefly on Marco Tabini’s reponse:

What I suspect Brandon really means is that the comments are there to illustrate the intentions of the author when those intentions are not immediately made obvious by the code itself.

Yes. And no. There is no absolute boundary, no limit in principle, to how intention-revealing code can be. It’s not necessarily easy in practice, though. As I’ve said before, it’s primarily inline comments that I’m objecting to. The comments I feel a need to write are often at the class level and address the interaction between different classes.

Anyway, arguing about it theoretically is not the way to resolve the issue. Show me some good examples of comments that serve to make code clearer and that supposedly can’t be usefully eliminated by refactoring the code into something more readable. I’ll either admit that you’re right or show you (or at least outline) how to do it differently. I do recognize that even inline comments are useful…occasionally.

(By the way, I seem to have missed Brandon’s comment (Where Comments Are Useful) to my comments considered harmful post last December.)

Share/Save/Bookmark

10 ways to improve your code

Neal's Drink of Choice
Image by Jared Richardson via Flickr

I discovered a video presentation available from QCon SF 2008 by Neal Ford called 10 Ways to Improve Your Code. Although the examples are in Java, most of the presentation is relevant to PHP. There are some ideas here that I’ve never heard of myself, such as “anti-objects”.

Some of the main headings are a bit cryptic, so you may have to see the video itself to have them explained.

Here are the 10 ways:

  1. Composed method
  2. TDD (test-driven development/design)
  3. Static analysis
  4. Good citizenship
  5. YAGNI (you ain’t gonna need it)
  6. Question authority
  7. SLAP (single level of abstraction principle)
  8. Polyglot programming
  9. Every nuance (=learn every nuance of your programming language)
  10. Anti-objects

I recommend this presentation. It’s about the things that really matter if you want to be productive.

Reblog this post [with Zemanta]

Share/Save/Bookmark

Real programming with PHP 5.3 (part 3): Links

Two curves with linking number 2.
Image via Wikipedia

After the previous post in this series, additional independent implementations of the idea of JavaScript-style classes have turned up. So I’m going to list them and comment briefly on the differences. I hope this will be helpful to anyone who actually wants to use this in practice and needs to decide on the details of the implementation. Here are the links in chronological order:

One difference is how JavaScript-like the implementations are. Some of them implement a syntax that is deliberately made to resemble JavaScript. Andrea Giammarchi’s version even uses ArrayAccess to make it possible to access object properties using both object and array syntax, as in JavaScript. At the other extreme is my implementation. I’ve tried to make it as similar to a regular PHP class as possible. You can instantiate an object in the same way as with an ordinary PHP class. This comes from defining the methods inside the class constructor.

After seeing all of these, I prefer my own way of doing it, except that it lacks what I mentioned in the previous article: an exception when you try to call an unrecognized method. But I’m obviously not objective, and I may have have missed something.

Share/Save/Bookmark

Real programming with PHP 5.3 (part 2): JavaScript-style classes

In part one of this series, we looked at the ability to use lambda functions or closures to process arrays. In this part, we will see how closures can be used to build classes in a completely new way.

After I did my own research, I discovered that someone had beat me to it. As early as September last year Fredrik Holmström wrote about Javascript-OO & Python-DuckTyping in PHP5.3.

I’ve done the same thing independently and somewhat differently, so it’s interesting to compare. Unlike Holmström, I’m defining the closures inside the constructor for the class that’s using them. That makes the code that uses the class a little more similar to what we’re used to.

Let’s start with a “Hello world” example.

class HelloWorldWithClosures {
    private $hello;
    private $goodbye;

    public function __construct() {
        // If we try using $this inside the closure, we get a syntax error.
        // So we need another variable name, which is basically arbitrary.
        $self = $this;

        // $self is not actually used inside this method/closure, but we want to be consistent.
        $this->hello = function() use ($self) {
            echo "hello world...\n";
        };

        $this->goodbye = function() use ($self) {
            $self->hello();
            echo "...and goodbye for now\n";
        };
    }

    public function __call($method,$args) {
        return call_user_func_array($this->$method,$args);
    }
}

The closures are instance variables in the class, and the __call() method is set up to call the correct closure when calling the method in the usual way in PHP.

Now we can call a plain method that uses nothing else from the class:

$obj = new HelloWorldWithClosures;
$obj->hello(); // prints "hello world..."

And we can call the goodbye() method that starts by calling hello():

$obj = new HelloWorldWithClosures;
$obj->goodbye();
// prints "hello world...
//...and goodbye for now"

We can also add new methods to object that’s already instantiated without changing the class:

$obj->helloAgain = function() use($obj) {
    $obj->goodbye();
    echo "...and hello again\n";
};

This last example exploits the somewhat vulgar fact that you can still add public instance variables on the fly to an object, as in PHP 4.

A different approach that avoids this, but is a bit more verbose, would be to use an array to store the closures in the object:

class HelloWorldWithClosures2 {
    public $methods = array();

    public function __construct() {
        $self = $this;

        $this->methods['hello'] = function() use ($self) {
            echo "hello world...\n";
        };

        $this->methods['goodbye'] = function() use ($self) {
            $self->hello();
            echo "...and goodbye for now\n";
        };
    }

    public function __call($method,$args) {
        return call_user_func_array($this->methods[$method],$args);
    }
}

In addition, we would normally need to throw an execption when a method does not exist. The blog post I linked to at the beginning has this feature.

Those are the basics of how to write JavaScript-classes in PHP 5.3. Whether you actually want do it this way depends on your needs. There’s no point unless you actually want to use the flexibility this style of programmer affords.

Share/Save/Bookmark

Ada versus Mars and Venus

Augusta Ada King, Countess of Lovelace.
Image via Wikipedia

On the carafe belonging to our coffee maker, there is a barely discernible spot that tells you how far to unscrew the lid in order to open it so that you can pour coffee from it without getting a flood of it in your lap. I never found this spot until it was pointed out to me. For years I overlooked it. Fortunately, along with the helpful hint as to its location, came the explanation: I’m a man, so I don’t understand coffee makers.

I get it. Men are genetically programmed to understand power drills, women are programmed to understand coffee makers. They’re both electrical, relatively low-tech tools, but our chromosomes know the difference. There is that particular base pair sequence in women’s DNA that encodes the unique neurotransmitter that binds to the receptors on the coffee maker lid scanning neurons. (They’re in the occipital lobe.) And if women make coffee, it’s a feminine activity. And if it’s a feminine activity, women should do it, right? And if only men write computer programs, then of course it’s masculine. And if it’s masculine, then men should be doing it.

It’s called circular logic. It’s almost, but not quite, entirely unlike regular logic.

Marching on: As you may have noticed, today is Ada Lovelace Day. I didn’t sign the pledge. I read about it yesterday, but like a few others I’ve seen on Planet PHP, I’m uncomfortable with singling out one person. So, instead, I would like to perform a bit of mythbusting.

As I tried to hint in the beginning paragraph, gender sterotypes are not terribly logical. Nor are they supported by hard facts and scientific evidence.

So here is a fact that’s not much appreciated, but still a fact: men and women are more similar than people tend to believe. This has been known for decades, but is not universally recognized.

This snippet from Scientific American expresses the essence of it. (Unfortunately, the whole item is not freely available. It’s good, but short.)

Men and women are not nearly as different as the media and pop psychologists would lead us to believe, according to a new metastudy of gender research.

Girls don’t have the same mathematical proclivity as boys? Not true. Men can’t communicate as well as women can in relationships? Not so either. And it turns out that the self-esteem problems usually associated with teenage girls are just as pronounced in teenage boys.

Here is some more information on the same metastudy.

Another excellent source of information is this book extract.

In The Essential Difference [Simon Baron-Cohen] offers the following “scientific” careers advice: “People with the female brain make the most wonderful counsellors, primary school teachers, nurses, carers, therapists, social workers, mediators, group facilitators or personnel staff … People with the male brain make the most wonderful scientists, engineers, mechanics, technicians, musicians, architects, electricians, plumbers, taxonomists, catalogists, bankers, toolmakers, programmers or even lawyers.”

Baron-Cohen classifies nursing as a female-brain, empathy-based job (though if a caring and empathetic nurse cannot measure dosages accurately and make systematic clinical observations she or he risks doing serious harm) and law as a male-brain, system-analysing job (though a lawyer, however well versed in the law, will not get far without communication and people-reading skills). These categorisations are not based on a dispassionate analysis of the demands made by the two jobs. They are based on the everyday common-sense knowledge that most nurses are women and most lawyers are men.

Yes, it’s the coffee maker thing again, and it’s ridiculous.

The comment about nurses is particularly interesting to me. I’ve witnessed nurses at an intensive-care unit talking to each other, and I remember thinking “wow, these ladies know some heavy technical stuff”. They were not discussing feelings and people, they were talking about the apparatus. And not in a way that I could understand.

On the other side of the coin, even getting up at night to feed a baby doesn’t take a “maternal instinct”. I’ve done it, and I’m pretty sure I know what required: you have to understand that it’s necessary, and stop feeling sorry for yourself. Without the self-pity, the discomfort of interrupted sleep is tolerable. It’s a relatively mild physical hardship, certainly one that should be within the capacity of “real men”.

Gender discrimination and segregation in the workplace is harmful and irrational. But it’s not easy to abolish, partly because gender stereotypes and mythical differences seem to be considered much more interesting and edible to the media than gender similarities.

Share/Save/Bookmark