Typealias for TDD

There’s a tension when you introduce new objects: type checking can help, but it often gets in the way while you’re exploring. If your language supports it, typealias can smooth the transition from untyped to typed.

Typealias

Guy Fawkes mask (cropped) from Tnarg

In Swift, Kotlin, and other languages, a type alias defines a new name for a type, but treats any values as being of the original type.

For example, typealias Money = Int lets you write functions that take Money arguments, and pass integer values to them.

Depending on the language, you may be able to use Money as a constructor too. So you could create Money(3) and pass that to a function with a Money parameter.

However, aliases don’t provide full typing: assert(3 == Money(3)) will pass, where it wouldn’t even compile if Money were a true class.

Typealias in TDD

Without typealias, my flow during early exploration tends to be like this:

  1. Create the initial tests using primitives or raw collections
  2. Do this for too long:(
  3. Introduce proper types (eg., class or struct), and have to modify code to use the new types

Why do I wait too long? Because in early tests, I’m exploring the code that does things. Primitives have a number of methods or operators that can work immediately. Unfortunately, they’re too generous: they also have a number of operations that will never make sense for my object, and nothing to stop people from using them.

I may recognize I’ll want to wrap a type, but don’t want to stop to create the type and backfill the helpful operations I’ll need.

Typealias lets me use a different flow:

  1. Create the initial tests using primitives or raw collections
  2. Use typealias so I can start using the intended class name
  3. Switch to a proper class when it’s convenient

The difference is that I can start using the class name early, and later switch to a class or struct more easily.

For Example

For example, I might be in a situation like this:

order.add("medicine", 1, 40)
order.add("book", 3, 20)
assertEqual(order.total, 100)
assertEqual(order.tax, 5)

I want add() to take item, quantity, and cost. Right now those are (String, Int, Int). It won’t take me long to realize that I probably want those types to be (Product, Int, Money). But right now I’m focused on Order.

Using a typealias, I can use the type names without “really” defining those types:

order.add(Product("medicine"), 1, Money(40))
order.add(Product("book"), 3, Money(20))
assertEqual(order.total, Money(100))
assertEqual(order.tax, Money(5))

When I need to introduce a Product or Money class, I won’t have to go back into my tests and add all those constructor calls.

When to Introduce a Class?

You might think, “Why bother with a class at all?” As the design matures, you’ll feel pressure to create a more encapsulated type:

  • You start making mistakes, having to ask “What is this again?”
  • A primitive no longer holds enough information. E.g., you need dollars and cents, or product metadata.
  • You’re using a lot of operators (if you can’t or don’t want to define your own).
  • You’re losing track of the responsibilities. Without everything bundled together, you have to find all client uses to understand everything your typealias type needs.
  • You want encapsulation to force real type-safety. E.g., you don’t want to accidentally multiply Money * Money.
  • You need to redistribute responsibilities. E.g., you’re seeing duplication and feature envy because of the lack of a “true” type.

Pay attention to the design pressure that suggests your typealias is no longer sufficient. It’s mostly mechanical but tedious to make that change, and waiting too long means you spend more time on mindless work.

Conclusion

Typealias gives you an intermediate between a primitive and a new class. This can speed up your TDD when an early move to a class would slow you down. Give it a try!

References

“Type Alias Declaration” in “Declarations” (Swift)

Type Aliases” (Kotlin)

Aliases and typedefs” (C++)

Acknowledgments

Thanks to Ron Jeffries and Mike Hill for the Twitter thread inspiring this post.

>> Interested in TDD? Check out the “Start Here: TDD” section – more than 50 articles to help improve your skill.