Fizz Buzz Example
As a simple example, I’ll go through the classic Fizz Buzz. I’ve implemented and tested it with and without immutable value objects. Please keep in mind that this is a toy example, where problems are obvious and easily fixed. I try to highlight at small scale the same problems that get hidden by the complexity of a large scale program.
Let’s start with a typical FizzBuzz implementation.
1 2 3 4 5 6 7 8 9 10 11
Suppose you need to add some tests around the code. The most straightforward way is to mock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
Unfortunately, there are a few problems with this code :
- With nested logic and complicated mock setup, both code and tests aren’t very readable
- They both seem to violate the single responsibility principle as well
- It’s depending on a mutable output. Within a larger program, something could be messing around with this output stream. That would break FizzBuzz.
Let’s now try to use as many immutable values objects as possible, and see what happens to the mocks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
As we can see, using immutable value objects got us rid of the mocks. Obviously, this new code will not be as efficient as the original version, but most of the time, this does not matter. As a bonus though we get finer grain and more readable tests.
Other testing advantages
Appart from preventing mocks, Immutable Value Objects have other advantages related to testing.
- We can directly assert their equality, without having to dig into their guts
- We can call methods as many times as we want, without the risk of changing anything and breaking the tests
- Immutable Value Objects are a lot less likely to contain invalid state. This removes the need for a whole range of validity tests.
💡 Immutable Value Objects simplify testing in many ways.
Convincing your teammates
We’ve seen that Immutable Value Objects have a ton of advantages when testing. People have found that they also have many other benefits :
- 6 Benefits of Programming with Immutable Objects in Java
- 5 Benefits of Immutable Objects Worth Considering for Your Next Project
Surprisingly though, it’s difficult to persuade programmers to use more immutability. It’s tricky to explain why returning a modified copy is simpler than just adding a setter.
💡 Why is it so hard to persuade other developers to use immutable data structures ?
I had the most success by far when encountering a bug resulting of share mutable state. When this happens, the long term benefits and safety of the immutable design wins people over. The good thing is that as you convince more people in the team, immutability will spread like a virus !
Outside of this situation, you might try some of the following arguments to move people :
- Immutable values prevent bugs caused by different parts of the system changing the same mutable state
- They make it easier to deal with the program in smaller parts and to reason about the system in general
- Immutable values don’t need any synchronization and make multithreaded programming easier
- When tempted to add a simple setter instead of keeping a class immutable, highlight the stressful debugging time to come
- If you’re dealing with a Design By Contract adept, explain how immutability has it built-in
- Admit that mainstream languages have bad support for Immutable Value. Point to patterns like Data Builders that work around these limitation
I’m done with immutable value objects. It was a far longer post than I thought, but there was a lot to say. This was the third post in a series about avoiding mocks. In next post, I’ll dig into another small scale mock fighting pattern : Test Data Builders.