Perfectionism is a pitfall. For those who, like me, love elegant design and see its utility, there is a slippery slope waiting when a satisfying design does not emerge in a reasonable time. It takes constant self-discipline to recognize this and accept, let go, ship and move on – or return in a later cycle, if it matters. It doesn’t always matter. For many parts of our systems, a good-enough design is good enough. And for those few strategically important parts, where an incisive model and a crisp design are actually likely to affect the outcome of the project, a great initial design doesn’t usually emerge immediately. We’ll need iteration and experimentation. None of our goals is furthered by grinding and dawdling, waiting for a design we can be proud of in version one.

For my own part, I try to go a bit beyond acceptance. When I am struggling with some part of the design, I often make design choices that explicitly responds the design problems themselves. This helps me let go and move on, and it can improve the chance for change in a later iteration.

In this short series I’ll describe a few techniques I use that help me take the step of shipping something I’m not happy with while also potentially leaving a good path for improvement in future iterations. We’ll start the series with a look at very fine-grained design decisions.

Part 1: Honest Names

An honest name isn’t always an intention-revealing name. That is only the case when we succeed in fulfilling our intention with a design element. But this does not always happen. In this article, we are considering those unfortunate times when the nice solution doesn’t come.

I need a specific example to illustrate the approach. It would be easy to pick apart some poorly designed software, but it is much more interesting to examine the imperfections in something that is generally well-designed. JodaTime is a Java library for date/time, very widely used as an open source library and eventually adopted, in a modified form, as a standard library for Java. It is well-designed – but not perfect, of course. (After all, it shipped!)

Consider ‘Plus’

The JodaTime library allows us to declare times, such as a date, and periods of time:t = 2021-01-20 p = 3 days For many applications, the storage of such values is itself an important capability. Of course, there are many common time related operations, and the library also implements some of those, such as:t.plus(p) 2021-01-20.plus(3 days) ⇒ 2021-01-23 Nice! In JodaTime, all the values are designed as value objects. There are no mutations or side-effects. So in the example above, after executing t.plus(p), the value of t is unchanged: 2021-01-20, and the operation has returned a new value of 2021-01-23.

The ‘plus’ operation is versatile. It works seamlessly with different kinds of periods:2021-01-20.plus(2 days) ⇒ 2021-01-22 2021-01-20.plus(2 months) ⇒ 2021-03-20

The code seems very expressive and clear. And yet… What do you think the following would return?

2021-01-30.plus(1 month) ⇒ ?

Remember, February is a short month! I can think of at least three plausible responses. To know what it actually does, I ran the code:

2021-01-30.plus(1 month) ⇒ 2021-02-28

This seems like a reasonable default behavior, but it is not obvious. The fact that I had to run the code (or look up a document somewhere) to know what would happen, even after some experience using the operation, highlights a flaw in the model. But what is wrong with it, and what could be done?

In this article, I’ll focus on the name. The word ‘plus’ seems to fit what is happening in my first few examples, but it gives no hint about how we handle irregularities, such as months of different lengths.

And this brings us to “Honest Names”. A simple name like ‘plus’ can actually be misleading if the behavior of the operation is complicated. What could it be called instead? Exploring many options for the name of an important thing is usually a good practice. Let’s try a few:

t.plusRounded(p) t.constrainedPlus(p) t.plusWithCeiling(p) t.monthAwarePlus(p)

Any of these would have at least given me a clue. They are also awkward! We don’t like awkward designs. But we need honest names.

Give Awkward Names to Awkward Concepts

Let’s look some more at the ‘plus’ operation in JodaTime, and why ‘plus’ is a confusing name. (Here I’ll just write ‘plus’ as ‘+’ for easier reading.)