Friday, December 28, 2007

Fluent Query Language Through Strategy Composition

In the last post we created a Fluent API that builds a domain object hierarchy. In this post we are going to create a Fluent API that acts as a domain specific querying language for this same domain. Let's take a look at a slightly modified example from a previous post:
CustomerQuery query = questionThatAsks.whichCustomers(bought(anything(), between("01/01/2006", "01/01/2007")));
List<Customer> customers = query.ask(listOfAllCustomers);

This example creates a CustomerQuery object that is capable of answering the question that has been asked, 'Which customers bought anything between 01/01/2006 and 01/01/2007?'. We could have picked any date or date range. We could have specified that are looking for Customers that bought compact discs. Pretty cool, huh? Can you imagine how it works?

We are doing a combination of two things to get this affect. First we are gathering information about the desired return type base on which builder method we call (ie. whichCustomers, howManyCustomers, haveAnyCustomers, etc.). When we ask 'whichCustomers' we know that we are going to return a query object of type <List<Customer>>. If we ask 'howManyCustomers' we know we should return an int.

Secondly we are using a composing the behavior of our query using a Strategy Pattern. In this case our strategy takes the form of a Predicate. You could expand on your interface with different types of Strategy objects. For instance, you could add a Strategy to do proper formatting base on which builder method you call. Or a Strategy to add select a particular property off of the Customer objects.

You don't even have to even create the intermediate CustomerQuery object. You would just as easily get your answer directly. Take some time to look over the full example source. Then think about your business domain and how a similar pattern could be used to allow you to code in your business logic in this incredibly expressive way.

Thursday, December 27, 2007

Fluent API pattern: Nested Interfaces

Multiple Fluent APIs can be used in a nested fashion in order to separate and organize responsibilities while keeping individual classes simple. Fluent APIs can become complex as more features are added if a designer is not careful. This pattern gives a clear and sustainable path for growth. Let's take a closer look at one of the examples from my last post:

Customer customer = createCustomer.named("Bob").that(bought.item(CompactDisc).on("02/17/2006"));

Reading the words reveals in English exactly what is going on with the code. It creates a customer named Bob that bought a compact disc on 02/17/2006. What is going on behind the scenes? That is not quite as clear, nor is it important to anyone other than the Fluent API designer!

Before diving in, let's talk briefly about the domain. We are creating a Customer. Customer's have Transactions. Transactions have Items and Dates.

The first thing to notice is that almost half of this code is fully enclosed in parenthesis. The result of 'bought.item(CompactDisc).on("02/17/2006")' is being passed to a method named 'that'. It is not obvious here, but the 'that' method is on a CustomerCreator object.

Now notice that 'bought' is an object. However, in this snippet this object is not instantiated. Don't be too bothered by this. The declaration and instantiation of this object is just fluff that distracts from the true intent of the code. With some creative use of static imports you can instantiate this object in just one place in your entire codebase and never have to look at it again. Know, though, that the 'bought' object is a TransactionCreator.

TransactionCreator has methods that set Items and Date. In order to chain methods, all methods on TransactionCreator return a TransactionCreator with all appropriate data set. Warning: Do not just return 'this' from such methods. You will need to do a deep clone or you will likely have very interesting things happen unexpectedly when you change data on one Transaction and it changes on all the others as well.

The object 'createCustomer' is very similar of type CustomerCreator. It creates a Customer instead of a Transaction. However, it follows the exact same pattern as TransactionCreator. Methods 'named' and 'that' are both on the CustomerCreator class and both return cloned CustomerCreators that have had some piece of data added to it.

The final piece of the puzzle is that CustomerCreator and TransactionCreator extend Customer and Transaction respectively. This allows for method chaining that can end at any time and still give you an object of the target class.

I strongly encourage you to download the full example source and look through it. Fluent APIs do not need to be overly complex, but they are a drastic shift from traditional interface design. Don't give up even if it takes a while to really understand. The benefits are worth the learning curve.

Sunday, December 16, 2007

Intro to Fluent APIs

A Fluent API is a interface or set of interfaces that allow one to express one's code in a way that is similar to English (or your natural language of choice). Such APIs are often incorrectly referred to as Domain Specific Languages (DSL). The difference, of course, is that a Fluent API is implemented within an existing general purpose language.

Example of creating a model object that represents a customer:
Customer customer = createCustomer.named("Bob").that(bought.item(CompactDisc).on("02/17/2006"));


Example of querying a list of customers:

List<Customer> question = questionThatAsks.whichCustomers(bought(anything(), between("12/31/2006", "01/01/2007"))).ask(customers);

Full code examples are available files section of the home page.

My team has created two comparable Fluent APIs to help us build and query model objects, and our productivity has increased substantially from it. It has allowed us to program at a very high level and in the terms of our business domain. There are trade-offs involved. For instance, it is difficult to look at a individual methods and understand how they fit into the system. You will likely have methods named 'with' and 'and' that do very little if any work. These methods exist entirely for the sake of readability. Fortunately, it is very easy to learn to use Fluent APIs from examples.

Creating Fluent APIs is another story all together. It is not difficult or complex, but it is a radical departure from tradition programming paradigm. For this reason it often takes some mental acrobatics to design a new Fluent API, but it gets easier with time. I believe, though, that this learning curve is partly because common patterns pertaining to creating Fluent APIs have not adequately been formalized and documented. These techniques have been used by visionaries for many years particularly in the Ruby community (often called DSLs). However Fluent APIs are just starting to gain popularity in the mainstream Java and C# communities. One reason that this movement was started in the dynamic language communities is that the flexibility of such languages makes creating elegant Fluent APIs much easier. Part of the reason that Fluent APIs are starting to catch on in the Java community is that Java 5 introduced some features that, when used together, make such expressive APIs both possible and practical. Static imports, generics and enums play crucial roles in achieving English-like readability.

The success and productivity that I have experienced using Fluent APIs in Java has given me a new appreciation for Java. This appreciation is not for Java as a solution for real world problem, but as a means of creating the tools necessary for solving real world problems.

Popular tools using Fluent APIs:

Saturday, December 15, 2007

Synergy Between Guice, Easymock and JUnit

I have recently written separate posts about Guice and Easymock. Those posts were really just preparation for this one. Guice and Easymock are impressive tools each on their own. However they really shine when used together and in conjunction with JUnit (or your testing framework of choice). If you are unfamiliar with either of these tools please read the previous posts to get up to speed before continuing reading.
Synergistic Effects:
Arrows indicate that one tool is increasing the value of the tool to which the arrow points.

Easymock --> JUnit:
  • Higher signal to noise ratio in tests since manual mocks are unnecessary. This increases the expressiveness of the tests and increases the value of the tests as executable documentation.
JUnit --> Guice:
  • Unit testing code leads most people eventually into some form of dependency injection. Thus Guice often just makes easier the best-practices that a developer is already following.
Guice --> JUnit:
  • Classes can use injected dependencies rather than relying on concrete implementations, allowing tests to be targeted on solely on the class under test.
  • Individual test classes do not need to construct collaborator objects as a prerequisite for instantiating the class under test. They can simply have Guice build an instance of the class under test.
  • Collaborators that are necessary for the intent of the test can be injected directly into test classes (see below).
  • Collaborators that are not important in achieving the goal of the test can be ignored.
Guice <--> Easymock:
  • Mock collaborators can be configured in a Guice configuation Module intended specifically for testing.
  • The testing Module is reusable to the same work to generate mocks won't have to be done in multiple test classes.

Object can be injected directly into tests. You still want to instantiate your own class under test, but this is very useful for collaborator objects that are not the focus of the test. The following example does not show the use of the injected object, only that the injection is possible:


@RunWith(InjectingTestClassMethodsRunner.class)
public class InjectionTest {
@Inject IClock clock;

@Test
public void myTest() {
assertNotNull(clock);
}
}


Here is a snippet to show you how to use Guice to instantiate your test classes in JUnit:

public class InjectingTestClassMethodsRunner extends TestClassMethodsRunner {
public InjectingTestClassMethodsRunner(Class klass) {
super(klass);
}

@Override
protected Object createTest() throws Exception {
Injector injector = Guice.createInjector(new TestModule());
return injector.getInstance(this.getTestClass());
}
}

Simple Dependency Injection with Guice

Google's Guice is a very slick, annotations-based Dependency Injection framework. It allows you to easily create class instances even if they have complex dependencies on other classes. The knowledge of what concrete implementation to use for a dependency is contained in simple configuration classes called Modules. Injection sites for these implementations may be constructors, methods, or fields. Anywhere you want a dependency to be injected you just add the @Inject annotation to. The is pretty much all there is too it. Guice is very simple and has a relatively small learning curve.

Here is a code snippet showing injection of a dependancy into a constructor:

@Inject
public TimeChecker(IClock clock) { ... }


And here is the Module to tell Guice which concrete implementation to use:

@Inject
public TimeChecker(IClock clock) { ... }


Now to get an instance of TimeChecker you no longer need to build it's dependancies:

TimeChecker timeChecker = Guice.createInjector(new ProductionSettingsModule()).getInstance(TimeChecker.class);


For one dependency this looks like a lot of work, but if your class has four or five dependencies the above line does not get any bigger.

Less Tedious Tests with Easymock

If you have small, simple classes with clearly defined responsibilities you will inevitably have dependencies between them. You could use these collaborator classes directly with the 'new' operator, but if you do you will not be able to test your classes in isolation of each other and you will wind up with much duplication between your tests. It will also be difficult to test all of the scenarios that you might want to because of the behaviors of these collaborator classes. So instead you inject these collaborators into you class under test. This is better, but it does force you to create mock classes. These mock classes will often require behaviors in order to perform your test or gather information about the behavior of your class under test. One problem with this is that this behavior in your mock classes becomes difficult to maintain as the complexity of the behavior of your class under test increases. Another problem is that if you follow this strategy repeatedly you will develop a lot of test code that is redundant.

Easymock helps to avoid these problems. It will create mock objects for you and allow you to easily specify how your class under test is expected to use them. The following is a bit incomplete for the sake of explanation, so I encourage you to read the documentation.

Getting a new clock object:

IClock clock = Easymock.createMock(IClock.class);


Telling Easymock how the clock is expected to be used:

Easymock.expect(clock.getTime()).andReturn(new Date());


Then you give the clock object to your class under test to use and Easymock is able to notify JUnit of when and how your class under test used the collaborator in an unexpected way.