Improving Code With Fluent Interfaces

Fluent What…?

Fluent interface. A “fluent interface” is a concept originally coined by a couple smart guys called Martin Fowler and Eric Evans back in 2005. Rumor has it that once upon a time both guys were eating a huge bag of Cheetos while watching at an old episode of Dr. Who late at night and then aliens came out of the TV screen and granted them this coding style as a gift. Since then, it has become widely used by developers who have gradually started to worry more and more about their source code readability. OK, the story is all BS but it is more interesting than saying they just agreed on the concept in like 10 minutes after a workshop. :(

Anyways, as I just mentioned, the main purpose of this concept is to improve code readability by using a wrapper class that exposes existing functionality in the form of chained methods. Chained methods are methods that after they complete their work, they return an instance of the objects that contains them so more methods can be called subsequently. Of course, this is all quite confusing so let’s look at some code.

Fluent Threads

For this particular topic, I am going to create an example using one of the most loved features in Java: Threads and Runnables. So, let’s say I want my application to fire a long-running operation in a separate thread so, after the operation starts, my application can get stuck in a loop printing a message notifying the user that the operation is still running. After the operation completes, we print a message saying it so. Quite useless application we have here, but will help demonstrate our example.

Traditionally we would have some code like this to achieve what we want:

package com.codenough.demos.fluentthreads;

public class Main {
    private static Boolean operationThreadIsRunning = false;

    public static void main(String[] args) throws Exception {
        setOperationStatus(false);

        System.out.println("Creating thread...");

        Runnable runnableOperation = new Runnable() {
            @Override
            public void run() {
                setOperationStatus(true);

                try {
                    Thread.sleep(5000);
                    System.out.println("Operation execution finished.");
                } catch (Exception e) {
                    System.out.println("An error ocurred while executing operation.");
                }

                setOperationStatus(false);
            }
        };

        Thread operationThread = new Thread(runnableOperation);

        operationThread.start();

        System.out.println("Thread created. Now running.");

        while(true) {
            Thread.sleep(1000);

            if (operationThreadIsRunning) {
                System.out.println("Still waiting for thread...");
            }
            else {
                break;
            }
        }

        System.out.println("Thread execution completed.");
    }

    public static void setOperationStatus(Boolean isRunning) {
        operationThreadIsRunning = isRunning;
    }
}

Again, this code does is just fine. But someone with limited knowledge of Java (or programming at all) would have a hard time trying to figure out  what the hell is a Thread or Runnable. Let alone @Override. So, for the sake of easy readability we can modify the code structure a little bit so, instead of creating threads and runnables, we can do something like this:

createTaskFor(new Action() {
    @Override
    public void onExecute() {
        // Long-running operation..
    }
})
.onErrorUse(new ErrorHandler() {
    @Override
    public void onErrorCaught(Exception exception) {
        // Handle errors..
    }
})
.thenExecute();

Much better, huh? Now readers should only worry about guessing what the friendly @Override annotations are for.

Behind The Scenes

This lovely syntax is possible thanks to a wrapper class working behind the scenes called Task which is full o’ chained methods which return its own instance so we can keep calling and calling methods like there’s no tomorrow until we are ready to run the actual task by calling the thenExecute() method. All for the sake of syntactic sugar.

Here is the implementation of the Task class:

package com.codenough.demos.fluentthreads.threading;

public class Task {
    private Boolean isRunning;
    private ErrorAction errorAction;
    private final Action action;

    public Task(Action action) {
        this.action = action;
        this.isRunning = false;
    }

    public Boolean isRunning() {
        return this.isRunning;
    }

    public Task onErrorUse(ErrorAction errorAction) {
        this.errorAction = errorAction;

        return this;
    }

    public Task thenExecute() {
        Runnable runnableAction = new Runnable() {
            @Override
            public void run() {
                try {
                    isRunning = true;
                    action.onExecute();
                    isRunning = false;
                }
                catch(Exception exception) {
                    errorAction.onErrorCaught(exception);
                }
            }
        };

        new Thread(runnableAction).start();

        return this;
    }

    public static Task createTaskFor(Action action) {
        return new Task(action);
    }
}

As you might notice on most methods, they return their own class instance. These are chained methods and, in this case, are used to configure the task. I have taken advantage of Java static imports so I can call the createTaskFor method in the main method without having to reference the Task class at all on it; making our fluent interface totally unobtrusive. What a good boy. ;)

Now our main method looks a little something like this:

package com.codenough.demos.fluentthreads;

import static com.codenough.demos.fluentthreads.threading.Task.*;
import com.codenough.demos.fluentthreads.threading.*;

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("Creating task..");

        Task task =
            createTaskFor(new Action() {
                @Override
                public void onExecute() {
                    try {
                        Thread.sleep(5000);
                        System.out.println("Task internal action execution finished.");
                    }
                    catch(InterruptedException exception) {
                        throw new Error("Thread sleep was interrupted.", exception);
                    }
                }
            })
            .onErrorUse(new ErrorHandler() {
                @Override
                public void onErrorCaught(Exception exception) {
                    System.out.println("An error ocurred while executing task internal action.");
                }
            })
            .thenExecute();

        System.out.println("Task created. Now running.");

        while(true) {
            Thread.sleep(1000);

            if (task.isRunning()) {
                System.out.println("Still waiting for task...");
            }
            else {
                break;
            }
        }

        System.out.println("Task execution completed.");
    }
}

Benefits

Fluent interfaces leverage existing language features (which are not that user-friendly) to improve code readability. This allows us to produce awesome code with superior quality since is a lot easier to read, understand and maintain (QAs will be grateful, which is good). Of course, additional code and effort is required to implement fluent interfaces but in the end it all pays when we, for example, have to implement additional features or modify existing code in a codebase we might have last touched ages ago. You’ll save thousands of dollars on aspirin tablets.

Example

Further Reading

About these ads

4 thoughts on “Improving Code With Fluent Interfaces

  1. Quite interesting, above all because I was not familiar with the name. I was familiar with the concept of method chaining, and I have seen it many times when we use a Builder pattern, where this is very common, but I was not familiar with Martin Fowler’s coined name. Do you have a reference for this? I would be great to read Martin’s article as well.

    I have to say that I, personally, would have preferred an example that had nothing to do with threads, because the multithreading may deviate the attention from the actual beauty of the post, which is “the power of fluent interfaces” and I think that if us, the readers, wouldn’t have to consider the multithreading side of the story, the examples would be simpler and more enlightening.

    For example, I have several comments about threading issues in the examples that have nothing to do with the main idea of the post. My comments do not undermine the power of fluent interfaces, but they do question some unconsidered multithreading scenarios in the examples.

    For instance, I believe there there is a race condition over the static variable operationThreadIsRunning. It is static, and therefore shared by all threads in your example. Here you spawn a single thread, but if there were more than one thread, they all would share this variable, therefore, creating a race condition when it comes to verifying the state of this variable within a thread (not to mention that this would only work for one thread, because you only have one static variable, and so this contradicts the how idea of this being a mutithreading example). So, ideally, this variable should have been a native boolean and it should have been declared as volatile to ensure it is fully read or written by the time is used by multiple threads. Also I have the impression that in line 31, where you print to the console “Thread created, Now running”, there is no way to ensure that the thread is actually running. When we invoke start on a thread, we have no guarantees regarding the exact time when that will actually happen. So, maybe the thread has not been started yet by the time we print that to the console, and so the message could be misleading. The only place where we could ensure that it is running is in the run method itself. The line 36 is the bone of contention here, you could be trying to read it while another thread is trying to write it. Since each thread have their own caches, the main thread may not see the changes done in the spawn thread cache unless the variable in question is declared as volatile or unless you create mutual exclusion over the variable using synchronization. Finally, somebody may argue that, perhaps, the best way to make the main thread to wait for the task to finish is by using the Object.join() method, which has been designed for this purpose, namely, make one thread wait for another to finish.

    So, you see, now I have deviated from the topic of the post, we should be here discussing about fluent interfaces, but the threading side of the story made me comment on different direction and that’s why I said I would have preferred an example that did not have to do with threading at all.

    • Hi, Edwin. Please check the “Further Reading” section to find the links to Martin’s original article on the subject.

      Regarding the examples, I agree with you in the fact that they leave out several threading scenarios. I have not forgot your Java courses yet. ;) However, in order to keep the code examples as short as possible, I have not wandered too much on these scenarios (such as the race condition issue).

      I decided to use threading for the example since it is loosely based on .NET’s Task Parallel Library, which I thought would help illustrate the idea more clearly with ideas usable in real life.

      By the way, check out the TPL. Is quite interesting and is full of lambdas and that sort of things. :)

      • Duh! I saw the link after I had written the comment, sorry about that. Yes, I get your point. As I said, I the important thing is the concept of fluency not so much the multithreading so I believe I got the message. What do you mean TPL?

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s