Mastodon

What is the Golden Master Technique

In preparation of my new workshop, I read about the Golden Master technique in detail. Because this is an important method to deal with legacy code and is easy to explain, this article is an extract from my workshop.

When changing legacy code, the most important goal is safety. Under no circumstances would you want to change the behavior of the code in an unwanted way. If you do so accidentally, there should be some kind of “flashing red light” that indicates the changed behavior. This light is normally a high test coverage and automated tests. However, old codebases often lack a test base. Furthermore, the structure of the code makes it hard to write good JUnit tests. The Golden Master method is one possible solution for this situation.

The general idea is to not use insight into the implementation, but use the behavior of your code instead. I recommend (if you haven’t already) using a (local) Git repository. Tag the current code version as “Golden Master”. Now you can add commits as you like, jumping back to the Golden Master if necessary.

Usage

  1. Write some kind of execution for the part of code under test. This can be a small program or a JUnit test. The goal here is to just click a button to run your code.
  2. Most likely, your code produces some kind of output. Maybe it’s log file or just the console. Create a snapshot of this output and save it as a template.
  3. Refactor your code step by step. After every step, compare the output of the refactored code with your template.
  4. Whatever you do, the output of the changed code must match your template! If it doesn’t match after a change, revert this change because it breaks things.

Possible Problems

If the code under test doesn’t produce output, you have to introduce log statements.

Maybe the code under test produces non-deterministic output. In the famous ugly trivia game, rolls are randomized. The solution for this is taking control of the random number generator and seeding it with the same numbers every time.

If the code under test is too complex to generate templates for every possible input, you have to use sampling. Use only a few of the many possible inputs. As an example, let’s have a look at a simple method that operates on an integer. Samples could be -1, 0, 1 and 1.000. The greater the number of samples, the greater your trust in those. The importance of the code should match the number of samples. Better go slow with many samples than be fast and fail.

Example

In the great article Surviving Legacy Code with Golden Master and Sampling there is a chapter “The techniques in action”. The author J.B. Rainsberger demonstrated the application of the Golden Master method on the Ugly Trivia Game. Start at this commit and read the commits added later. Also, note how tiny and easy to understand these commits are.

Falk Sippach gave an interesting addition for changing the output channel for existing log statements. Normally, these would be switched to a file using a try-catch-block inserted into the code under test. Falk talked about using test infrastructure instead of altering existing code at Java Forum Nord 2016 (slides here):

@Before
public void init() {
    originalSysOut = System.out;
    consoleStream = new java.io.ByteArrayOutputStream();
    java.io.PrintStream printStream = new PrintStream(consoleStream);
    System.setOut(printStream);
}
 
@Test
public void testSimpleOutput() {
    System.out.println("Hello folks!");
    System.out.println("Hello programmer!");
    assertEquals("Hello folks!\r\rHello programmer!", consoleStream.toString());
}
 
@After
public void teardown() {
    System.setOut(originalSysOut);  
}

Compare Output

There are several ways to compare output produced by the Golden Master method:

text editors like notepad++ with compare-plugin (download and extract zip, in Notepad++ Settings -> Import -> Import Plugin) automated (for example) by saving golden master template into file and parse it using a JUnit test

TL;DR

The Golden Master technique provides a great way to test if changes made on legacy code change this code. Instead of having to understand the code, the output of the code is compared to a previously created template.