View web version

Good Morning/Afternoon/Evening as the case may be.

I've been hoping you are well, and thinking about naming.

Estimated reading time: 7 minutes, 37 seconds.

A Small Digression

You may have heard Phil Karlton's famous saying:

There are only two hard things in Computer Science: cache invalidation and naming things.

I first heard this as 'There are only two hard things in Computer Science: cache invalidation, naming things, and off-by-one errors.'

I passed this phrase on for many years before realizing that the 'off-by-one errors' bit was a joke.

Truth.

I am so literal that it pains me. I confess this in case it's paining you too. Puns, for example, fly right over my head, and any that I make are most likely inadvertent. I don't believe that there are any puns in the text that follows—but how would I know?

Thoughts on Using Pattern Names in Class Names

I've always heard that it's best to avoid using pattern names in class names. As one so often does, I've cargo-culted this rule without truly examining it. I habitually obey it myself, and teach it to folks in my OOD classes, but until recently I couldn't have articulated a convincing defense.

But then, while writing the 2nd Edition of 99 Bottles of OOP, I broke it. I created a new class whose name included the name of a pattern. I did this because it just felt right.

This put me in a pickle.

I very much believe in being guided by feelings about code, but when writing a book one can't just say, 'Okay, now do this because I, the author, feel like you should'. Respect for the reader requires investing sincere effort into dragging feelings about code into the light of day, and at least trying to justify them with convincing words.

Below I've included the excerpt from the book where I attempt just such convincing. The excerpt explains the purpose of the no-pattern-names-in-class-names rule and defends its utility.

I've built a newsletter around this rule not only because I believe that it's useful, but also because my initial attempts to explain it exposed deep holes in my understanding. This was a revelation. Had I not been writing a book, I might have hand-waved around these gaps in my knowledge forever.

Some Context

Before moving on to the excerpt, here's a bit of context to orient you. At this point in the book:

  • The code contains a CountdownSong class that gets injected with a player of the verse template role.

  • BottleVerse is the only class that plays this role. It's used as the default verse template in CountdownSong.

So, CountdownSong has-a verse template, whose concrete implementation is supplied by BottleVerse.

  • I'm writing tests for CountdownSong, and have just decided to create a new player of the verse template role to inject for use during these tests.

  • I've named this new class VerseFake.

The excerpt below also mentions a BottleNumber class. This class wraps a number to add bottle-ish behavior.

The Excerpt

With that, here's a bit of chapter 9:

The VerseFake class above is perfect for your needs, though it must be acknowledged that it unrepentantly breaks several common programming rules.

First, Chapter 8 suggested that you put domain behavior on instances. This class violates that rule; its behavior is on the class/static side.

Next, there's an as-yet-unmentioned object-oriented programming rule that prohibits the use of pattern names in class names. The word "Fake" above refers to a testing pattern, so naming this class VerseFake violates that rule.

Fake things first. You're probably familiar with the idea of design patterns, which are named, re-usable solutions to common software problems. Pattern names act as shortcuts to big ideas and allow programmers to communicate with speed and precision. Pattern thinking has so influenced software design that most programmers are familiar with a number of patterns. For example, you've likely heard of Decorator, Adapter, Enumerator, and so on, even if you're a bit fuzzy on the specifics of some of their definitions.

Since pattern names are so meaningful, it can be tempting to stick them in class names. For example, you might use the Decorator pattern to enclose a number in a new class that adds additional responsibility. Initially, NumberDecorator might seem like a good name for the result. The problem with including the name of a pattern in the name of a class is that this permits you the feeling of having created a useful name without actually having done so. Pattern names don't generally reflect concepts in your application. Appending them to class names pollutes your domain with programmer-y words and circumvents the search for names that add semantic meaning. Class names that include patterns are a signal that you've given up too soon on the hard problem of naming.

Class names should reflect concepts in your domain, not the patterns used to create them. Compared to BottleNumber, the much-richer name you gave this class in Chapter 4, NumberDecorator is so abstract as to be meaningless. Future readers won't care that the class was created using Decoration but they'll be grateful to know that it's a bottle-ish kind of number.

The xUnit Test Patterns book by Gerard Meszaros standardizes the pattern names of a set of objects that are used to simplify testing. TestDouble is his generic name for all of the patterns. Within TestDouble he further delineates the Dummy, Stub, Spy, Mock, Fake, and Temporary Test Stub patterns.

Meszaros defines Fake as a TestDouble that provides a lightweight implementation of a collaborator that is needed by the class you are actually unit testing. A Fake is a regular old object; no testing magic is involved. In this case the new VerseFake class is a real player of the verse template role; it's called a Fake because it's only used during testing. BottleVerse plays the role of verse template in production. VerseFake was created to play this role during Bottles' unit tests.

The upshot is that Fake is the name of a pattern, so VerseFake violates the don't-include-pattern-names-in-class-names rule.

Rules exist to save money, and the two rules that VerseFake breaks are primarily meant to save money in production code; they might not be so applicable in code created to simplify tests. For example, the purpose of VerseFake is to fake the role of verse template. In this case, VerseFake might be the most intention-revealing name possible. If you end up needing a number of different kinds of fakes, you might need additional qualifiers in their names (SimpleVerseFake, ComplicatedVerseFake) but the word "fake" still adds meaning in the domain of your tests.

Similarly, it's important that the shape of production code not interfere with your ability to change it. The put-domain-behavior-on-instances rule serves this goal. In tests, however, you're less concerned with preserving the fake's changeability and more interested in directly communicating its responsibilities. Putting the behavior in a class or static method simplifies the code in VerseFake at the expense of making it less adaptable. This is a trade-off you'll happily make in code used only by the tests.

I am convinced by that explanation, and I hope you are too. Now that I comprehend it, the no-pattern-names-in-class-names rule seems both simple and inevitable.

The deeper point is that I didn't really understand this rule until I had to write an explanation—believe me, my early attempts were neither brief nor convincing. The above is the result of a few days of walking around in my office, muttering, groping for insight.

It's not necessarily bad to cargo-cult a rule. Most rules that have risen to the level of cargo-cult-ability are actually pretty reasonable, and even if you don't completely understand their subtleties, following them might improve your code.

However, you'll get more value from a rule if you comprehend its underlying purpose. And even better, understanding its true purpose allows you to justify yourself when you decide to break it.

Thanks for reading. I very much hope you are safe and well.

Best,

Sandi


99 Bottles of OOP, 2nd Edition is complete!

Use coupon code 2ND-IS-DONE! through Sept 7

for a 25% discount on the book.

The new edition:

  • has three new chapters (it's almost 50% longer).
  • comes in separate books for two programming languages (Ruby and JavaScript) and two beverages (beer and milk), with a free PHP upgrade coming this fall.
  • is available as an ebook only, in epub, kepub, kobi, and pdf formats.
  • bundles every book variant. A single purchase gets you all of the books.

I am so glad to be done with this edition that I'm passing that good cheer on to you.

Note:
Those of you who already own the book should have recently receivedyour own personal upgrade coupon.

If you plan to upgrade, remember to use this coupon before it expires on September 7th.  Ping domestique@sandimetz.com if you need a reminder of the code!

 
 
Copyright © 2020 Sandi Metz, All rights reserved.

Our mailing address is: human@sandimetz.com

Unsubscribe