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.