Tag Archives: object_creation_patterns

Object Creation Patterns #2 : Everybody’s building

The right time to build

We’ve talked at length about the costs of builders, and yet… they persist. I can think of at least three examples from popular java libraries that work well:

Although, having looked at StringBuilder‘s doc – augh! It’s so big! Five or six builders could come out of that, starting with AppendOnlyStringBuilder.

What do these master builders (That’s enough linguistic hyphens between the Builder pattern and actual builders – Ed) have in common?

Well, they all have trivial build implementations. Really though, that’s an artifact of the thing that they’re building – there’s a well defined null type for each – Description‘s is simply an empty description, StringBuilder‘s is "", and ImmutableList.Builder‘s is simply ImmutableList.of(). All three of these things are essentially list builders: Description and StringBuilder are looking after [Char], and ImmutableList.Builder is looking after some appropriate [T].

This gels well with good experiences I have had with builders in code I’ve been near: applications with publishers and subscribers, tuples with arbitrary numbers of arbitrarily typed fields, user lists built from clicks in a UI, before a batch action is selected. When you hit build on all of these things, the type you get back is either [T], or a type that depends heavily on a [T]

Careful now.

We could quite easily conclude here that the only good builders are those that build lists. The original point bears repeating:

Builders work best when there’s a well defined null type for the thing being built.

Even that, though, is not quite right. It’s quite possible for a Builder to work nicely if the thing being built is a composite of several types, each with a well defined null type. The following definition might be better:

Builders work best when it’s impossible for them to be in a state where invoking build generates an invalid object

That feels like a corollary of this, though:

Builders work best when all of their fields have a well defined null type

In addition, the interplay between the dependencies should also have a well defined null type. Defining that, however, is tricky, so I will assume we’re all one the same page and gracefully move on to defining it for single fields…

A well defined null type

Some examples:

  • List‘s null type is the empty list
  • String‘s null type, is, unsurprisingly, an empty String, given that a String is just a List of chars.

Arbitrary objects do not have a well defined null type. null in Java is not well defined, because at some point it’s either going to cause NPE, or a giant tangle of obj == null ? doStuff(obj) : panic(); cruft. Using null to signify emptiness or default values in builders is a crime I hope no-one is tempted to commit.

So, each field can either be a primitive, for which a default value can be specified, an interface, for which a default implementation is specified (perhaps a no-op one), or a type like List, Iterable or Maybe (these have well defined null types). We could start talking about builders within builders here, but we won’t.

Cowboy Builders (You’re fired – Ed)

It’s difficult not just to define these as being !good builders. So instead, here are some things we may see if a builder is being used inappropriately (I say!):

Unnecessary builders

Fewer than four fields. One usage. Inline with extreme prejudice.

Irresponsible builders

Built objects propagate across the system after construction, and each part of the system does some more validation of the object to see if it is suitable.

Perhaps each receiver needs a slightly different builder? Perhaps they all need the same builder, and we’ve found a case where a non trivial build implementation is required, which performs the validation just once.

Alternatively, this could be because of null or sentinel defaults (Long.MAX_VALUE, anyone?) leaking out from the built object. We can either establish a sort of null protocol at call sites or find a more appropriate default.

A simple example null protocol for Maybe unfriendly lingoes: null can never escape. hasField is obvious and is elided.

void doThingWithFoo() {
   if (hasField()) doThing(getField()) else doThing(default());
}

Foo getField() {
   Preconditions.checkState(hasField(), "go away!");
   return fooField;
}

Overexposed builders

Often, the fluent style of building is used to mimic the sort of pass-by-name arguments we see in more fun programming languages:

my_burrito = burrito(size: "large", filling: "pork",
                     beans: "both", salsa: "hot",
                     guacamole: "yes please")
final Burrito myBurrito = newBurritoBuilder().withSize(Size.Large)
                                             .withFilling(Filling.Pork)
                                             .withBeans(Beans.Both)
                                             .withSalsa(Salsa.Hot)
                                             .withGuacamole()
                                             .build();

So. This is the first quandary I find myself in. I really like this style, it’s descriptive, leaving me confident that the constructed burrito will be as requested. How many of these fields really have a well defined null type, though? What are the mandatory requirements for a burrito? Could we just use a builder for the optional parts? Perhaps the following might be more appropriate:

Burrito myBurrito =
    new Burrito(Size.Large, Filling.Pork, Beans.Both,
                options().withSalsa(Salsa.Hot).withGuacamole().build());

We should carefully match the fields we use a builder for based on whether the object about to be constructed really needs them or not. Exposing the mandatory dependencies as builder parameters is potentially confusing and costly.

As my friendly, local ruby guru points out though, you can get the nice fluency of this pattern without the cost:

Broadly I agree with this. I have seen times where it works beautifully, particularly in creating objects in test. There have also been times, however, where I have come across that pattern, felt it inappropriate and simply inlined until the builder disappeared.

Conclusion

We now have a reasonable guideline for when to use builders, and some example smells which might allow us to spot a cowboy more quickly (I give up – Ed).

Where now?

If this series manages the difficult third album, we’ll perhaps start to touch on more general object creation concerns, and perhaps a little bit of wiring.

Object Creation Patterns #1 : Factory beats Builder

Well, really, this should be obvious. My mental image of factories is the Toyota plant; an efficient production line of high tech robots automatically executing specialized constructive tasks as part of a well honed process (perhaps with a nearby overseer sternly observing, making regular marks on some sort of handheld checklist device). Whereas my builder image is a bloke leering at young ladies from the safety of some dodgy looking scaffolding.

Ahem

Uh. Yeah. I actually wanted to talk about the Factory and Builder patterns. They’re inescapable in modern OO codebases. I want to talk about the right time to use both patterns. In this part, we will discuss why Factory ought to be the default, and Builder‘s niche is, well, a niche. Later posts will examine the niche further, and probably digress into wider object creational concerns.

A little discipline

Alright, alright. We should define these terms.

Factory

Given a class Foo, a given Factory is a one shot method to construct a Foo.

Rule of thumb

Once we have a Factory, we are precisely one method call away from having a Foo. Factory objects might contain some pre-bound dependencies of Foo that they can inject on invocation, but usually this has occurred long before the invoker came into being.

Side note – Factory methods, usually implemented as static functions on Foo definitely get pulled in by this definition. (Q: what about Foo‘s constructor? Is that a Factory too?)

Builder

Given the same class Foo, a Builder allows us to piece together the dependencies of Foo in its internal state until we are ready to construct our Foo by invoking the build method.

Rule of thumb

Once we have a Builder, we could be n + 1 calls away from having a Foo, where n is the number of constructor parameters Foo has.

A completely irrelevant equivalence

One can immediately see that one could generate a Factory for a given Builder usage. Somewhat more generally, any Factory could be replaced with some equivalent calls to a complete Builder for a given class.

Takeaway from this section: Builders are more ‘general’ than Factories.

Wait a minute. Are you going to argue for or against generality?

Yes. What we are really seeking here is the appropriate level of generality for the situation we are in.

Factories are low risk; one might say they have low entropy. All the arguments we need in order to create a new object are clearly listed, passing the wrong number and/or the wrong type of arguments and the compiler will (assuming null is verboten) let us know long before the missiles have launched.

Builders come at a far higher cost; just as their construction is at least two phase, their contract is split too, between compile and run time. N.B The cost goes up if the builder’s implementation uses mutable fields, as they commonly do!

We can know fairly well that each of our calls parametrizes some aspect of the object under construction correctly, but do we know if all the dependencies it needs to construct our object have been provided when we invoke build? The only time we find out is at runtime, which may be too late. Let’s examine Builder from three different perspectives.

Using a Builder

We should be sure to write a test for our particular construction. If our usage is based on values only known at runtime, that might be quite a few tests, and a bundle of validation logic for our inputs. Ouch.

Writing a Builder

We’ll have a lot of fun considering the possible default values for fields, writing the validate method, and putting together the documentation that gives our clients the faintest chance of not failing it. You know the sort of arduous fun I speak of here, I am sure.

Receiving ‘built’ objects

We will be fortunate if we can work out all the different species of object that might occur! We’re probably going to want to use a property based testing tool to attempt to cover the vast range of objects we might end up dealing with. If we’re really lucky, a kind person might have hidden the built value behind a well defined interface that we can test against instead. I don’t know about you, but I don’t tend to be that lucky.

Conclusion

One hopes the above example gives some weight to the message of this piece, i.e there must be a strong need for the sort of generality a builder provides given the costs that come along with it.

Coming up next time: some strong needs, and master builders versus cowboy builders