How’s that for a catchy title, huh? Let me take a moment to re-read it. Done. Moving on, then.

I’ve been digging around GitHub and GoogleCode a lot lately. I’ve probably seen more of other people’s code this past month that in the year before that, and specially Java code, for obvious reasons.

Among OOP languages, Java is specially infamous for its average code quality and readability. I won’t argue with that: expressing certain kinds of behavior in Java through code that won’t offend the eyes of a reader is already quite a challenge, and that’s if you actually care. Lots of coders don’t. However, I noticed a peculiar trend I consider particularly dangerous, a trend not restricted to but much more frequent in Java, and thought I’d write a short post about it.

Getters, getters

Let’s say we start writing a class. In a sudden fit of originality, let’s call it Person, and create some of the members we’ll need — say id, name, birthDate and address.

class Person {

    private long id;
    private Date birthDate;
    private String name, address;

}

Since we’re are educated object-oriented programmers, we declare these fields to be private, and create accessors for them: getId() getName(), getAddress() and getBirthDate().

Now, we notice that most of the time we just want the person’s age, rather than its date of birth. Well, thanks to our encapsulation, we can offer that through the public interface without changing our internal data structure. Oh, and while we’re at it, we can also wrap the ugly java.util.Date into JodaTime’s superior DateTime to perform the calculation!

public int getAge() {
    Date now = new Date();

    /* Mmmh,... maybe I should make this blog's content column wider */
    return Years.yearsBetween(
        new DateTime(birthDate),
        new DateTime(now)

    ).getYears();
}

This last bit of code may seem trivial enough, but think about the amazing encapsulation it achieves! The user of this class is totally unaware of how we handle our data, he just interacts with our Person and obtains its age as fast as he can call a getter. He doesn’t need to know that to return that integer we created and discarded at least four objects, and did some math — that’s what encapsulation is about, right?

We then close the editor tab, satisfied with our beautiful OO implementation.

Some time later, another coder (let’s call him John — there’s just no end to my creativity today!) is asked to sort a list of Person instances by age. He saw our getter used somewhere else in the code, so he thinks “oh, good! I’ll just write a Comparator!”.

public class AgeComparator implements Comparator<Person> {

    @Override
    public int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }

}

And, armed with the Comparator, he sets off to sort a list of millions of people and spends half an afternoon wondering just why the Garbage Collector is working so much overtime.

The getter anti-pattern

Okay, I admit I could’ve come up with a better example, but you’re looking at a guy that named his class Person and his coder John. Let’s just pretend you are shocked by the sheer impact the previous section had on you, and move on to see why poor John wasted so much of his time.

I don’t think it’s our fault for storing a person’s date of birth, instead of his/her age. We are allowed to compute, aren’t we? We can’t just have a variable for every derived attribute out there, or the data redundancy would quickly get out of hand. No, I think the problem is in the following snippet:

    public int getAge();

Yes. The problem is we named the method getAge(). We could’ve named it calculateAge(), and John would’ve been much more careful, instead of instantly assuming the operation was as light-weight as returning an instance member.

I’ve seen getters perform all kinds of monstrous computations. I’ve seen classes with nothing but getters, half of them false accessors in disguise. I’ve even been fooled several times myself into using a getter that seemed innocent enough only to later discover it was doing all sorts of operations behind my back. I don’t just think this particular abuse of getters is bad, I think it qualifies as an anti-pattern by definition:

  • It initially appears to be beneficial, since getters go a long way towards hiding internal details, but ultimately produces more bad consequences than beneficial results, for abusing them lures users of your code into believing everything is easily accessible.
  • An alternative solution exists: just choose a different name.

There are thousands of verbs other than getcalculate, compute, build, create,… — and if my creativity can come up with four today, so can yours anytime.

All that, or maybe I’m just exaggerating. I do that. Have a nice week!

Advertisements