Building for readability

Spot the difference

Readability of code should not only be pursued in production code. It is also very important to make your (unit)tests as readable as possible. One of my favourite patterns for enhancing readability is the builder pattern.

Take a look at the following code snippet of a unit test. As you will notice, the creation of the User object involves a lot of lines. Not also does it involve a lot of lines of code, it isn't quite readable as I would like it to be.

    ...

    @Test
    public void not_return_any_tweets_when_user_is_not_followed_by_logged_in_user() throws UserNotLoggedInException {
        tweetService = new TweetService(PIERCE, tweetDAO);

        User james = new User();
        james.setName("James Bond")
        james.addFollower(ROGER);
        james.addFollower(TIMOTHY);
        james.addFollower(DANIEL);
        james.addTweet(ABOUT_ACTORS);
        james.addTweet(ABOUT_MOVIES);

        assertThat(tweetService.getTweetsByUser(james).size(),is(0));
    }

    ...

Don't get me wrong, the code above is quite readable but if you take a look at the code below it reads a bit more nicer. It is almost like you are reading a normal sentence. That is what the builder pattern gives you. Fluent readable object creation.

    ...

    @Test
    public void not_return_any_tweets_when_user_is_not_followed_by_logged_in_user() throws UserNotLoggedInException {
        tweetService = new TweetService(PIERCE, tweetDAO);

        User james = aUser()
                        .named("James Bond") 
                        .followedBy(ROGER, TIMOTHY, DANIEL)
                        .withTweets(ABOUT_ACTORS, ABOUT_MOVIES)
                        .build();

        assertThat(tweetService.getTweetsByUser(james).size(),is(0));
    }

    ...

Note that the static import is used in order to call aUser() without the class name. Otherwise it would read Userbuilder.aUser(). The latter is also readable but the first one reads a bit more natural. (But that is nitpicking 2.0)

Getting it done

How does that pattern work, you might think. The basic idea is that while creating the object the the builder saves all the data and when all is ready the build() method is invoked and at that point the object is created.

In order to chain the methods together all the methods that collect data (e.g. named an followedBy) should return the Builder object itself.

Creating the builder contains three steps:

  • Creating the static method which returns a new Builder (opening method)
  • Creating the data collecting methods which return the builder (intermediate methods)
  • Creating the build method (terminating method)

Opening method

This static factory method (not to be confused with the Factory design pattern) is added pure for enhanced readability.
If we didn't have this static method the builder would has to be invoked something like this: new UserBuilder().followedBy(...). The intent is less clearer as opposed to using the static factory method.

    ...

    public static UserBuilder aUser() {
        return new UserBuilder();
    }

    ...

Intermediate methods

In order to chain the methods each intermediate method should return itself. Notice the usage of the varargs parameter. By using the varags we delegate the adding of followers one-by-one to the builder itself. This is also the case for the withTweets(...) method.

    ...

    public UserBuilder followedBy(User... followers) {
        this.followers = followers;
        return this;
    }

    ...

Terminating method

For actually creating the User object, the builder must have a terminating method. This method is responsible for creating the actual object needed by the client. In this method we see that every piece of data, collected by the intermediate methods, is transferred to the User object and finally the constructed user is returned to the client.

    ...

    public User build() {
        User user = new User();
        setNameFor(user);
        addTweetsTo(user);
        addFollowersTo(user);
        return user;
    }

    ...

The full builder

public class UserBuilder {
    private String name = "";
    private User[] followers = new User[]{};
    private Tweet[] tweets = new Tweet[]{};

    public static UserBuilder aUser() {
        return new UserBuilder();
    }

    public UserBuilder named(String name) {
        this.name = name;
        return this;
    }

    public UserBuilder followedBy(User... followers) {
        this.followers = followers;
        return this;
    }

    public UserBuilder withTweets(Tweet... tweets) {
        this.tweets = tweets;
        return this;
    }

    public User build() {
        User user = new User();
        setNameFor(user);
        addTweetsTo(user);
        addFollowersTo(user);
        return user;
    }

    private void setNameFor(User user) {
        user.setName(name);
    }

    private void addFollowersTo(User user) {
        for (User follower : followers){
            user.addFollower(follower);
        }
    }

    private void addTweetsTo(User user) {
        for (Tweet tweet : tweets){
            user.addTweet(tweet);
        }
    }
}

Conclusion

According to Wikipedia "The intention of the builder pattern is to find a solution to the telescoping constructor anti-pattern that occurs when the increase of object constructor parameter combination leads to an exponential list of constructors. Instead of using numerous constructors, the builder pattern uses another object, a builder, that receives each initialization parameter step by step and then returns the resulting constructed object at once.

I would like to add that the builder pattern can also be used for enhanced readabilty and easier creation/validation of objects.


Dependency Inversion Principle... Say what???

Dependency Inversion Principle

noun [C] / dɪˈpen.dən.si ɪnˈvɜː.ʒən prɪn.sə.pəl /

  • "A principle in OO-programming which states that high-level modules should not depend directly on low-level modules. Instead, both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions."

Well, that clears it up... errm... Not really! I mean, I can read. I understand the words. I am fairly bright. I even think that I 'kinda' know what it means. But it is still kind of vague...
... And that is exactly what it should be.... Vague. That's what a principle is about. It's a guide line, a moral rule, a code of conduct, a fundamental source, a basis (I think you get the point). Nothing more, nothing less!

Principles are just like politicians, they say a lot of stuff but they never provide a real solution. For example, in my hometown the local authorities enforce a policy called "The polluter pays". Period. It doesn't say what pollution exactly is. It doesn't state how it should be paid. Should it be paid in money? And if so, how much? When are you considered a polluter? It doesn't really give an answer, it simply says that when you are going to live here... be aware, we tend to let you, the polluter, pay for the damage you cause to the environment!

Applying this to the Dependency Inversion Principle, it just says, when writing our code we should try to stick to the fact that high(er) level objects should not depend on concrete implementations of low(er) level objects. It doesn't say how, why or when. It even does not say that we have to invert "everything" in the code that we write from now on. It just means that, this is our way of thinking!

Dependency Injection

But, what about Dependency Injection? Is that the same? Is it also vague? Nope... Dependency Injection is one of the ways of implementing the Dependency Inversion Principle. Let's try an analogy. In my spare time I am a musician. So a music analogy it is! Here goes...

Let's say that you recently discovered a kick-ass rock band called The Licks & Grooves All-Stars (insert band name of your liking here) which plays all of your favorite funky tunes.

A band usually consists of:

  • a band leader (that guy who tells other musicians in the band what to play, when to play certain grooves, licks, solo's and all kinds of stuff.
  • other musicians that follow the instructions of the band leader, in order to produce awesome groovy tunes as a band

The band leader is our high-level object. He is the one who is responsible for songs being played. However, he cannot do it alone. He needs the other musicans, to produce some cool music. No musicians, no music. In other words our band leader depends on the other musicians. So the other musicians are our low-level objects in this case.

Because of the busy touring schedule of the band, each member has at least one stand-in/substitute musician. If a member cannot make it to a gig, the substitute musician will take over and the gig can still go on instead of being cancelled. Every musician has his own unique style of playing. Let's take the drummer (yes, a drummer is also a musician!!!) and his substitute colleague for example. They could be implemented like this:

Low-level objects

The Drummer...

public class DaveGrohl {
    public void beatTheCrapOutOfTheBassDrum(){
        System.out.println("BOOOOOM");
    }

    public void whackTheSnareDrum(){
        System.out.println("TAK!!");
    }
}

... and his substitute

public class CharlieWatts {
    public void gentlyHitTheBassDrum(){
        System.out.println("dum");
    }

    public void strikeTheSnareDrum(){
        System.out.println("chik");
    }
}

As you can see, they basically do the same thing... They both can play a bass drum and a snare drum. They just do it in their own unique way!!!

High-level object

For the sake of keeping things simple, The Licks & Grooves All-Stars band consists of a band leader and a drummer only. Assume that our band leader wants to play "We Will Rock You!" (A famous song from a band called Queen). The code might look something like this:

public class BandLeader {
    private String drummer;

    public BandLeader(String drummer){
        this.drummer = drummer;
    }

    public void playWeWillRockYou() throws NoSongPlayedException {
        if (drummer.equals("Dave")){
            DaveGrohl daveGrohl = new DaveGrohl();
            daveGrohl.beatTheCrapOutOfTheBassDrum();
            daveGrohl.beatTheCrapOutOfTheBassDrum();
            daveGrohl.whackTheSnareDrum();
        } else if (drummer.equals("Charlie")){
            CharlieWatts charlieWatts = new CharlieWatts();
            charlieWatts.gentlyHitTheBassDrum();
            charlieWatts.gentlyHitTheBassDrum();
            charlieWatts.strikeTheSnareDrum();
        } else {
            throw new NoSongPlayedException("No drummer available!!!");
        }
    }
}

If we want to play "We Will Rock You" with "Dave Grohl" on drums, this would be our client code:

public class GigApp {
    public static void main(String[] args) throws NoSongPlayedException {
        BandLeader bandLeader = new BandLeader("Dave");
        bandLeader.playWeWillRockYou();
    }
}

The console would show:
BOOOOOM
BOOOOOM
TAK!!

If we pass "Charlie" into the constructor of our Band Leader, the output would be:
dum
dum
chik

Excellent!!! Mission acomplished! Our band leader can handle two different drummers and still play the same song. And we didn't even use Dependency Injection!!!

It works, doesn't it?

Yes it works. But, There is only one problem though: Not only does the band leader has to know what to play (Two bass drum hits followed by a hit on the snare drum). He also needs to know how he has to address each drummer to make them play that sequence of notes. And on top of that, he also needs to know how to create/construct each drummer.

So he is essentially stuck to these two drummers. If we want to add more drummers to the band then we would be in really big trouble! Each new drummer added to the band means an extra else-if clause in the BandLeader.playWeWillRockYou method.

And to make things worse, what if the sequence of notes changes and the band leader wants to add an extra hit to the snare drum when playing We Will Rock You? Every if clause must be altered then!!! Maintenance hell will surely follow now, if the band and/or the song keeps changing...

To solve these problems, we are going to invert the control regarding object creation. You can invert lots a things as a programmer like the flow, interfaces and object creation (This is called Inversion of Control). Nowadays, the term Inversion of Control is considered the same as Dependency Injection. But in reality IoC is a little bit broader. Inversion of control with regard to object creation is called Dependency Injection! That sounds cool, so let's see how a little bit of Dependency Injection works out for the band:

High-level object (in the case of DI)

We want two things solved:

  • The band leader should only have knowledge of what.to play (Two bass drums followed by a snare drum). He should not be bothered with knowing how to address each drummer in order to let them play what he wants
  • We don't want the band leader to be responsible for creating/constructing each drummer. (See above: "He should not be bothered with knowing how to address each drummer..."

Looking at the requirements, the ideal implementation of our Band Leader is:

public class BandLeader {
    private Drummer drummer;

    public BandLeader(Drummer drummer){
        this.drummer = drummer;
    }

    public void playWeWillRockYou() throws NoSongPlayedException {
        if (drummer == null)
            throw new NoSongPlayedException("No drummer available!!!");

        drummer.playTheBassDrum();
        drummer.playTheBassDrum();
        drummer.playTheSnareDrum();
    }
}

What just happened here? We made an abstraction (a simplification) of Charlie and Dave. They are drummers, so we created a Drummer Interface.

public interface Drummer {
    void playTheBassDrum();
    void playTheSnareDrum(); 
}

The band leader depends on an interface now (which is good, in this case). He can now speak in one language to a drummer. The band leader can interact with any drummer, as long as the drummer object implements the Drummer interface.

Low-level object (in the case of DI)

public class DaveGrohl implements Drummer {
    @Override
    public void playTheBassDrum() {
        System.out.println("BOOOOOM");
    }

    @Override
    public void playTheSnareDrum() {
        System.out.println("TAK!!");
    }
}

... and

public class CharlieWatts implements Drummer{
    @Override
    public void playTheBassDrum() {
        System.out.println("dum");
    }

    @Override
    public void playTheSnareDrum() {
        System.out.println("chik");
    }
}

Our main client code looks quite similar. The only difference is that we now pass a "Drummer" into the Band leader instead of a String. And now for our band leader it doesn't matter how many drummers we add to the band. As long as a concrete implementation of a drummer knows how to behave like a drummer, everything is peachy.

Instead of Dave Grohl telling the band leader how he should be addressed. It is the Band leader (or better, the abstraction) saying to Dave how he should play the drums if he wants to be part of the band... Inversion of Control!

We can now truly inject a drummer into the band leader.

public class GigApp {
    public static void main(String[] args) throws NoSongPlayedException {
        BandLeader bandLeader = new BandLeader(new CharlieWatts());
        bandLeader.playWeWillRockYou();
    }
}

Is this really better?

Yes it actually is. Our band leader object is much cleaner. No messy if statements. When a new drummer is added to the line-up, no more changes to the band leader object is required.

If the structure of a song changes, it would mean a single modification. Without Dependency Injection we would have to change each if statement in this case.

A bonus would be, easier unit testing. We could now easily use a Mock or a 'fake' Drummer.

So... We should use Dependency Injection all the time now? Hm, no... Certainly not. It depends on the requirements and the likeliness of changes to come. It wouldn't make much sense to implement Dependency Injection if the band has now (and in the future) got only one drummer... The first version of the band leader would be an okay alternative in that case

It all depends...