Functional FizzBuzz Kata in Java

A while ago I solved the FizzBuzz kata using Java 8 streams and lambdas. While the end result was functional, the intermediate steps were not. Surely I can do better.

As always, let’s start with a failing test:

+ package remonsinnema.blog.fizzbuzz;
+
+ import static org.junit.Assert.assertEquals;
+
+ import org.junit.Test;
+
+
+ public class WhenFunctionallyFuzzingAndBuzzing {
+
+   private final FizzBuzzer fizzBuzzer = new FizzBuzzer();
+
+   @Test
+   public void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {
+     assertEquals(“1”, “1”, fizzBuzzer.apply(1));
+   }
+
+ }
+ package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+
+
+ public class FizzBuzzer implements Function<Integer, String> {
+
+   @Override
+   public String apply(Integer n) {
+     return null;
+   }
+
+ }

Note that I start off on a functional course right away, using Java’s Function.

I fake the implementation to make the test pass:

  public class FizzBuzzer implements Function<Integer, String> {
    @Override
    public String apply(Integer n) {
–     return null;
+     return “1”;
    }
  }

And refactor the test to remove duplication:

  public class WhenFunctionallyFuzzingAndBuzzing {
    @Test
    public void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {
–     assertEquals(“1”, “1”, fizzBuzzer.apply(1));
+     assertFizzBuzz(“1”, 1);
+   }
+
+   private void assertFizzBuzz(String expected, int value) {
+     assertEquals(Integer.toString(value), expected, fizzBuzzer.apply(value));
    }
  }

Then I add another test to generalize the implementation:

  public class WhenFunctionallyFuzzingAndBuzzing {
    @Test
    public void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {
      assertFizzBuzz(“1”, 1);
+     assertFizzBuzz(“2”, 2);
    }
    private void assertFizzBuzz(String expected, int value) {
  public class FizzBuzzer implements Function<Integer, String> {
    @Override
    public String apply(Integer n) {
–     return “1”;
+     return Integer.toString(n);
    }
  }

OK, pretty standard stuff so far. Next I need to replace 3 with “Fizz”:

  public class WhenFunctionallyFuzzingAndBuzzing {
    public void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {
      assertFizzBuzz(“1”, 1);
      assertFizzBuzz(“2”, 2);
+     assertFizzBuzz(“Fizz”, 3);
    }
  nbsp;
    private void assertFizzBuzz(String expected, int value) {
  public class FizzBuzzer implements Function<Integer, String> {
    @Override
    public String apply(Integer n) {
–     return Integer.toString(n);
+     return numberReplacerFor(n).apply(n);
+   }
+
+   private Function<Integer, String> numberReplacerFor(Integer n) {
+     return n == 3
+         ? i -> “Fizz”
+         : i -> Integer.toString(i);
    }
  }

Here I recognize that I need to apply one of two functions, depending on the input. This code works, but needs some cleaning up. First, as a stepping stone, I extract the lambdas into fields:

  import java.util.function.Function;
  public class FizzBuzzer implements Function<Integer, String> {
+   private final Function<Integer, String> replaceNumberWithStringRepresentation
+       = n -> Integer.toString(n);
+   private final Function<Integer, String> replaceNumberWithFizz
+       = n -> “Fizz”;
+
    @Override
    public String apply(Integer n) {
      return numberReplacerFor(n).apply(n);
    private Function<Integer, String> numberReplacerFor(Integer n) {
      return n == 3
–         ? i -> “Fizz”
–         : i -> Integer.toString(i);
+         ? replaceNumberWithFizz
+         : replaceNumberWithStringRepresentation;
    }
  }

Next I emphasize that “3” and “Fizz” go together by extracting a class:

  public class FizzBuzzer implements Function<Integer, String> {
    private final Function<Integer, String> replaceNumberWithStringRepresentation
        = n -> Integer.toString(n);
–   private final Function<Integer, String> replaceNumberWithFizz
–       = n -> “Fizz”;
+   private final Fizzer replaceNumberWithFizz = new Fizzer();
    @Override
    public String apply(Integer n) {
    }
    private Function<Integer, String> numberReplacerFor(Integer n) {
–     return n == 3
+     return replaceNumberWithFizz.test(n)
          ? replaceNumberWithFizz
          : replaceNumberWithStringRepresentation;
    }
+ package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+ import java.util.function.Predicate;
+
+
+ public class Fizzer implements Function<Integer, String>, Predicate<Integer> {
+
+   @Override
+   public boolean test(Integer n) {
+     return n == 3;
+   }
+
+   @Override
+   public String apply(Integer n) {
+     return “Fizz”;
+   }
+
+ }

Here I’m using the standard Java Predicate functional interface.

To add “Buzz”, I need to generalize the code from a single if (hidden as the ternary operator) to a loop:

  public class WhenFunctionallyFuzzingAndBuzzing {
      assertFizzBuzz(“1”, 1);
      assertFizzBuzz(“2”, 2);
      assertFizzBuzz(“Fizz”, 3);
+     assertFizzBuzz(“4”, 4);
+     assertFizzBuzz(“Buzz”, 5);
    }
    private void assertFizzBuzz(String expected, int value) {
  package remonsinnema.blog.fizzbuzz;
+ import java.util.Arrays;
+ import java.util.Collection;
  import java.util.function.Function;
    private final Function<Integer, String> replaceNumberWithStringRepresentation
        = n -> Integer.toString(n);
–   private final Fizzer replaceNumberWithFizz = new Fizzer();
+   private final Collection<ReplaceNumberWithFixedText> replacers = Arrays.asList(
+       new ReplaceNumberWithFixedText(3, “Fizz”),
+       new ReplaceNumberWithFixedText(5, “Buzz”)
+   );
    @Override
    public String apply(Integer n) {
    }
    private Function<Integer, String> numberReplacerFor(Integer n) {
–     return replaceNumberWithFizz.test(n)
–         ? replaceNumberWithFizz
–         : replaceNumberWithStringRepresentation;
+     for (ReplaceNumberWithFixedText replacer : replacers) {
+       if (replacer.test(n)) {
+         return replacer;
+       }
+     }
+     return replaceNumberWithStringRepresentation;
    }
  }
– package remonsinnema.blog.fizzbuzz;
– import java.util.function.Function;
– import java.util.function.Predicate;
– public class Fizzer implements Function<Integer, String>, Predicate<Integer> {
–   @Override
–   public boolean test(Integer n) {
–     return n == 3;
–   }
–   @Override
–   public String apply(Integer n) {
–     return “Fizz”;
–   }
– }
+ package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+ import java.util.function.Predicate;
+
+
+ public class ReplaceNumberWithFixedText implements Function<Integer, String>,
+     Predicate<Integer> {
+
+   private final int target;
+   private final String replacement;
+
+   public ReplaceNumberWithFixedText(int target, String replacement) {
+     this.target = target;
+     this.replacement = replacement;
+   }
+
+   @Override
+   public boolean test(Integer n) {
+     return n == target;
+   }
+
+   @Override
+   public String apply(Integer n) {
+     return replacement;
+   }
+
+ }

Oops, old habits… That should be a stream rather than a loop:

  import java.util.function.Function;
  public class FizzBuzzer implements Function<Integer, String> {
–   private final Function<Integer, String> replaceNumberWithStringRepresentation
+   private final Function<Integer, String> defaultReplacer
        = n -> Integer.toString(n);
    private final Collection<ReplaceNumberWithFixedText> replacers = Arrays.asList(
        new ReplaceNumberWithFixedText(3, “Fizz”),
    }
    private Function<Integer, String> numberReplacerFor(Integer n) {
–     for (ReplaceNumberWithFixedText replacer : replacers) {
–       if (replacer.test(n)) {
–         return replacer;
–       }
–     }
–     return replaceNumberWithStringRepresentation;
+     return replacers.stream()
+         .filter(replacer -> replacer.test(n))
+         .map(replacer -> (Function<Integer, String>) replacer)
+         .findFirst()
+         .orElse(defaultReplacer);
    }
  }

Much better. The next test is for multiples:

  public class WhenFunctionallyFuzzingAndBuzzing {
      assertFizzBuzz(“Fizz”, 3);
      assertFizzBuzz(“4”, 4);
      assertFizzBuzz(“Buzz”, 5);
+     assertFizzBuzz(“Fizz”, 6);
    }
    private void assertFizzBuzz(String expected, int value) {
  public class FizzBuzzer implements Function<Integer, String> {
    private final Function<Integer, String> defaultReplacer
        = n -> Integer.toString(n);
–   private final Collection<ReplaceNumberWithFixedText> replacers = Arrays.asList(
–       new ReplaceNumberWithFixedText(3, “Fizz”),
–       new ReplaceNumberWithFixedText(5, “Buzz”)
+   private final Collection<ReplaceMultipleWithFixedText> replacers = Arrays.asList(
+       new ReplaceMultipleWithFixedText(3, “Fizz”),
+       new ReplaceMultipleWithFixedText(5, “Buzz”)
    );
    @Override
+ package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+ import java.util.function.Predicate;
+
+
+ public class ReplaceNumberWithFixedText implements Function<Integer, String>,
+     Predicate<Integer> {
+
+   private final int target;
+   private final String replacement;
+
+   public ReplaceNumberWithFixedText(int target, String replacement) {
+     this.target = target;
+     this.replacement = replacement;
+   }
+
+   @Override
+   public boolean test(Integer n) {
+     return n % target == 0;
+   }
+
+   @Override
+   public String apply(Integer n) {
+     return replacement;
+   }
+
+ }
– package remonsinnema.blog.fizzbuzz;
– import java.util.function.Function;
– import java.util.function.Predicate;
– public class ReplaceNumberWithFixedText implements Function<Integer, String>, Predicate<Integer> {
–   private final int target;
–   private final String replacement;
–   public ReplaceNumberWithFixedText(int target, String replacement) {
–     this.target = target;
–     this.replacement = replacement;
–   }
–   @Override
–   public boolean test(Integer n) {
–     return n == target;
–   }
–   @Override
–   public String apply(Integer n) {
–     return replacement;
–   }
– }

The last test is to combine Fizz and Buzz:

  public class WhenFunctionallyFuzzingAndBuzzing {
      assertFizzBuzz(“4”, 4);
      assertFizzBuzz(“Buzz”, 5);
      assertFizzBuzz(“Fizz”, 6);
+     assertFizzBuzz(“7”, 7);
+     assertFizzBuzz(“8”, 8);
+     assertFizzBuzz(“Fizz”, 9);
+     assertFizzBuzz(“Buzz”, 10);
+     assertFizzBuzz(“11”, 11);
+     assertFizzBuzz(“Fizz”, 12);
+     assertFizzBuzz(“13”, 13);
+     assertFizzBuzz(“14”, 14);
+     assertFizzBuzz(“FizzBuzz”, 15);
    }
    private void assertFizzBuzz(String expected, int value) {
  package remonsinnema.blog.fizzbuzz;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.function.Function;
+ import java.util.stream.Collectors;
+ import java.util.stream.Stream;
  public class FizzBuzzer implements Function<Integer, String> {
    @Override
    public String apply(Integer n) {
–     return numberReplacerFor(n).apply(n);
+     return numberReplacersFor(n)
+         .map(function -> function.apply(n))
+         .collect(Collectors.joining());
    }
–   private Function<Integer, String> numberReplacerFor(Integer n) {
–     return replacers.stream()
+   private Stream<Function<Integer, String>> numberReplacersFor(Integer n) {
+     return Stream.of(replacers.stream()
          .filter(replacer -> replacer.test(n))
          .map(replacer -> (Function<Integer, String>) replacer)
          .findFirst()
–         .orElse(defaultReplacer);
+         .orElse(defaultReplacer));
    }
  }

I generalized the single Function into a Stream of Functions, to which I apply the Map-Reduce pattern. I could have spelled out the Reduce part using something like .reduce("", (a, b) -> a + b), but I think Collectors.joining() is more expressive.

This doesn’t pass the test yet, since I return a stream of a single function. The fix is a little bit tricky, because I need to know whether any applicable replacer functions were found, and you can’t do that without terminating the stream. So I need to create a new stream using StreamSupport:

  package remonsinnema.blog.fizzbuzz;
  import java.util.Arrays;
  import java.util.Collection;
+ import java.util.Iterator;
+ import java.util.Spliterators;
  import java.util.function.Function;
  import java.util.stream.Collectors;
  import java.util.stream.Stream;
+ import java.util.stream.StreamSupport;
  public class FizzBuzzer implements Function<Integer, String> {
    }
    private Stream<Function<Integer, String>> numberReplacersFor(Integer n) {
–     return Stream.of(replacers.stream()
+     Iterator<Function<Integer, String>> result = replacers.stream()
          .filter(replacer -> replacer.test(n))
          .map(replacer -> (Function<Integer, String>) replacer)
–         .findFirst()
–         .orElse(defaultReplacer));
+         .iterator();
+     return result.hasNext()
+         ? StreamSupport.stream(Spliterators.spliteratorUnknownSize(result, 0), false)
+         : Stream.of(defaultReplacer);
    }
  }

And that’s it. The full code is on GitHub.

I learned two lessons from this little exercise:

  1. Java comes with a whole bunch of functional interfaces, like Function and Predicate, that are easily combined with streams to solve a variety of problems.
  2. The standard if → while transformation becomes if → stream in the functional world.

 

Advertisement

FizzBuzz Kata With Java Streams

black-beltAfter only a couple of weeks of Judo practice, my son got bored. He complained that he wasn’t learning anything, because he kept doing the same thing over and over.

It’s not just young children that confuse learning and doing new things. For instance, how many software developers go through the trouble of deliberate practice by performing katas or attending dojos?

It may seem silly to repeat exercises that you’ve already done many times, but it’s not. It’s the only way to become a black belt in your field. And remember that mastery is one of the three intrinsic motivators (the others being autonomy and purpose).

Practicing means slowing down and moving focus from outcome to process. It’s best to use simple exercises that you can complete in a limited amount of time, so you can do the same exercise multiple times.

I’ve found that I virtually always learn something new when I practice. That’s not because I’ve forgotten how to solve the problem since last time, but because I’ve learned new things since then and thus see the world through new eyes.

For example, since Java 8 came out I’ve been trying to use the new stream classes to help move to a more functional style of programming. This has changed the way I look at old problems, like FizzBuzz.

Let’s see this in action. Of course, I start by adding a test:

+ package remonsinnema.blog.fizzbuzz;
+
+ import static org.junit.Assert.assertEquals;
+
+ import org.junit.Test;
+
+
+ public class WhenFizzingAndBuzzing {
+
+   private final FizzBuzz fizzbuzz = new FizzBuzz();
+
+   @Test
+   public void shouldReplaceWithFizzAndBuzz() {
+     assertEquals(“1”, “1”, fizzbuzz.get(1));
+   }
+
+ }

This test uses the When…Should form of unit testing that helps focus on behavior rather than implementation details. I let Eclipse generate the code required to make this compile:

+ package remonsinnema.blog.fizzbuzz;
+
+
+ public class FizzBuzz {
+
+   public String get(int i) {
+     return null;
+   }
+
+ }

The simplest code that makes the test pass is to fake it:

  package remonsinnema.blog.fizzbuzz;
  public class FizzBuzz {
    public String get(int i) {
–     return null;
+     return “1”;
    }
  }

Now that the test passes, it’s time for refactoring. I remove duplication from the test:

  public class WhenFizzingAndBuzzing {
    @Test
    public void shouldReplaceWithFizzAndBuzz() {
–     assertEquals(“1”, “1”, fizzbuzz.get(1));
+     assertFizzBuzz(“1”, 1);
+   }
+
+   private void assertFizzBuzz(String expected, int n) {
+     assertEquals(Integer.toString(n), expected, fizzbuzz.get(n));
    }
  }

Next I add a test to force the real implementation:

  public class WhenFizzingAndBuzzing {
    @Test
    public void shouldReplaceWithFizzAndBuzz() {
      assertFizzBuzz(“1”, 1);
+     assertFizzBuzz(“2”, 2);
    }
    private void assertFizzBuzz(String expected, int n) {
  package remonsinnema.blog.fizzbuzz;
  public class FizzBuzz {
–   public String get(int i) {
–     return “1”;
+   public String get(int n) {
+     return Integer.toString(n);
    }
  }

OK, now let’s get real with a test for Fizz:

  public class WhenFizzingAndBuzzing {
    public void shouldReplaceWithFizzAndBuzz() {
      assertFizzBuzz(“1”, 1);
      assertFizzBuzz(“2”, 2);
+     assertFizzBuzz(“Fizz”, 3);
    }
    private void assertFizzBuzz(String expected, int n) {
  package remonsinnema.blog.fizzbuzz;
  public class FizzBuzz {
    public String get(int n) {
+     if (n == 3) {
+       return “Fizz”;
+     }
      return Integer.toString(n);
    }

Similar for Buzz:

  public class WhenFizzingAndBuzzing {
      assertFizzBuzz(“Fizz”, 3);
+     assertFizzBuzz(“4”, 4);
+     assertFizzBuzz(“Buzz”, 5);
    }
    private void assertFizzBuzz(String expected, int n) {
  public class FizzBuzz {
      if (n == 3) {
        return “Fizz”;
      }
+     if (n == 5) {
+       return “Buzz”;
+     }
      return Integer.toString(n);
    }

Here I just copied and pasted the if statement to get it working quickly. We shouldn’t stop there, of course, but get rid of the dirty stuff. In this case, that’s duplication.

First, let’s update the code to make the duplication more apparent:

  package remonsinnema.blog.fizzbuzz;
  public class FizzBuzz {
    public String get(int n) {
–     if (n == 3) {
–       return “Fizz”;
+     MultipleReplacer replacer = new MultipleReplacer(3, “Fizz”);
+     if (n == replacer.getValue()) {
+       return replacer.getText();
      }
–     if (n == 5) {
–       return “Buzz”;
+     replacer = new MultipleReplacer(5, “Buzz”);
+     if (n == replacer.getValue()) {
+       return replacer.getText();
      }
      return Integer.toString(n);
    }
+ package remonsinnema.blog.fizzbuzz;
+
+
+ public class MultipleReplacer {
+
+   private final int value;
+   private final String text;
+
+   public MultipleReplacer(int value, String text) {
+     this.value = value;
+     this.text = text;
+   }
+
+   public int getValue() {
+     return value;
+   }
+
+   public String getText() {
+     return text;
+   }
+
+ }

I just created a new value object to hold the two values that I had to change after the copy/paste.

Now that the duplication is clearer, it’s easy to remove:

  package remonsinnema.blog.fizzbuzz;
+ import java.util.Arrays;
+ import java.util.Collection;
+
  public class FizzBuzz {
+   private final Collection<MultipleReplacer> replacers = Arrays.asList(
+       new MultipleReplacer(3, “Fizz”), new MultipleReplacer(5, “Buzz”));
+
    public String get(int n) {
–     MultipleReplacer replacer = new MultipleReplacer(3, “Fizz”);
–     if (n == replacer.getValue()) {
–       return replacer.getText();
–     }
–     replacer = new MultipleReplacer(5, “Buzz”);
–     if (n == replacer.getValue()) {
–       return replacer.getText();
+     for (MultipleReplacer replacer : replacers) {
+       if (n == replacer.getValue()) {
+         return replacer.getText();
+       }
      }
      return Integer.toString(n);
    }

I’m not done cleaning up, however. The current code suffers from feature envy, which I resolve by moving behavior into the value object:

  package remonsinnema.blog.fizzbuzz;
  import java.util.Arrays;
  import java.util.Collection;
+ import java.util.Optional;
  public class FizzBuzz {
    public String get(int n) {
      for (MultipleReplacer replacer : replacers) {
–       if (n == replacer.getValue()) {
–         return replacer.getText();
+       Optional<String> result = replacer.textFor(n);
+       if (result.isPresent()) {
+         return result.get();
        }
      }
      return Integer.toString(n);
  package remonsinnema.blog.fizzbuzz;
+ import java.util.Optional;
+
  public class MultipleReplacer {
      this.text = text;
    }
–   public int getValue() {
–     return value;
–   }
–   public String getText() {
–     return text;
+   public Optional<String> textFor(int n) {
+     if (n == value) {
+       return Optional.of(text);
+     }
+     return Optional.empty();
    }
  }

Now that I’m done refactoring, I can continue with multiples:

  public class WhenFizzingAndBuzzing {
      assertFizzBuzz(“Fizz”, 3);
      assertFizzBuzz(“4”, 4);
      assertFizzBuzz(“Buzz”, 5);
+     assertFizzBuzz(“Fizz”, 6);
    }
    private void assertFizzBuzz(String expected, int n) {
  public class MultipleReplacer {
    }
    public Optional<String> textFor(int n) {
–     if (n == value) {
+     if (n % value == 0) {
        return Optional.of(text);
      }
      return Optional.empty();

The final test is for simultaneous “Fizz” and “Buzz”:

  public class WhenFizzingAndBuzzing {
      assertFizzBuzz(“4”, 4);
      assertFizzBuzz(“Buzz”, 5);
      assertFizzBuzz(“Fizz”, 6);
+     assertFizzBuzz(“7”, 7);
+     assertFizzBuzz(“8”, 8);
+     assertFizzBuzz(“Fizz”, 9);
+     assertFizzBuzz(“Buzz”, 10);
+     assertFizzBuzz(“11”, 11);
+     assertFizzBuzz(“Fizz”, 12);
+     assertFizzBuzz(“13”, 13);
+     assertFizzBuzz(“14”, 14);
+     assertFizzBuzz(“FizzBuzz”, 15);
    }
    private void assertFizzBuzz(String expected, int n) {
  public class FizzBuzz {
        new MultipleReplacer(3, “Fizz”), new MultipleReplacer(5, “Buzz”));
    public String get(int n) {
+     StringBuilder result = new StringBuilder();
      for (MultipleReplacer replacer : replacers) {
–       Optional<String> result = replacer.textFor(n);
–       if (result.isPresent()) {
–         return result.get();
+       Optional<String> replacement = replacer.textFor(n);
+       if (replacement.isPresent()) {
+         result.append(replacement.get());
        }
      }
+     if (result.length() > 0) {
+       return result.toString();
+     }
      return Integer.toString(n);
    }

This code is rather complex, but this is where streams come to the rescue:

  public class FizzBuzz {
        new MultipleReplacer(3, “Fizz”), new MultipleReplacer(5, “Buzz”));
    public String get(int n) {
–     StringBuilder result = new StringBuilder();
–     for (MultipleReplacer replacer : replacers) {
–       Optional<String> replacement = replacer.textFor(n);
–       if (replacement.isPresent()) {
–         result.append(replacement.get());
–       }
–     }
–     if (result.length() > 0) {
–       return result.toString();
–     }
–     return Integer.toString(n);
+     return replacers.stream()
+         .map(replacer -> replacer.textFor(n))
+         .filter(Optional::isPresent)
+         .map(optional -> optional.get())
+         .reduce((a, b) -> a + b)
+         .orElse(Integer.toString(n));
    }
  }

Note how the for and if statements disappear. Rather than spelling out how something needs to be done, we say what we want to achieve.

We can apply the same trick to get rid of the remainingif statement in our ode base:

  public class MultipleReplacer {
    }
    public Optional<String> textFor(int n) {
–     if (n % value == 0) {
–       return Optional.of(text);
–     }
–     return Optional.empty();
+     return Optional.of(text)
+         .filter(ignored -> n % value == 0);
    }
  }

The code is on GitHub.

Three Ways To Become a Better Software Professional

The other day InfoQ posted an article on software craftsmanship.

In my view, software craftsmanship is no more or less than being a good professional. Here are three main ways to become one.

1. See the Big Picture

Let’s start with why. Software rules the world and thus we rule the world. And we all know that with great power comes great responsibility.

Now, what is responsible behavior in this context?

It’s many things. It’s delivering software that solves real needs, that works reliably, is secure, is a pleasure to use, etc. etc.

There is one constant in all these aspects: they change. Business needs evolve. New security threats emerge. New usability patterns come into fashion. New technology is introduced at breakneck speed.

The number one thing a software professional must do is to form an attitude of embracing change. We cope with change by writing programs that are easy to change.

Adaptability is not something we’ll explicitly see in the requirements; it’s silently assumed. We must nevertheless take our responsibility to bake it in.

Unfortunately, adaptability doesn’t find its way into our programs by accident. Writing programs that are easy to change is not easy but requires a considerable amount of effort and skill. The skill of a craftsman.

2. Hone Your Skills

How do we acquire the required skills to keep our programs adaptable?

We need to learn. And the more we learn, the more we’ll find that there’s always more to learn. That should make us humble.

How do we learn?

By reading/watching/listening, by practicing, and by doing. We need to read a lot and go to conferences to infuse our minds with fresh ideas. We need to practice to put such new ideas to the test in a safe environment. Finally, we need to incorporate those ideas into our daily practices to actually profit from them.

BTW, I don’t agree with the statement in the article that

Programmers cannot improve their skills by doing the same exercise repeatedly.

One part of mastering a skill is building muscle memory, and that’s what katas like Roman Numerals are for. Athletes and musicians understand that all too well.

But we must go even further. There is so much to learn that we’ll have to continuously improve our ability to do so to keep up. Learning to learn is a big part of software craftsmanship.

3. Work Well With Others

Nowadays software development is mostly a team sport, because we’ve pushed our programs to the point where they’re too big to fail build alone. We are part of a larger community and the craftsmanship model emphasizes that.

There are both pros and cons to being part of a community. On the bright side, there are many people around us who share our interests and are willing to help us out, for instance in code retreats. The flip side is that we need to learn soft skills, like how to influence others or how to work in a team.

Being effective in a community also means our individually honed skills must work well with those of others. Test-Driven Development (TDD), for example, can’t successfully be practiced in isolation. An important aspect of a community is its culture, as the DevOps movement clearly shows.

To make matters even more interesting, we’re actually simultaneously part of multiple communities: our immediate team, our industry (e.g. healthcare), and our community of interest (e.g. software security or REST), to name a few. We should participate in each, understanding that each of those communities will have their own culture.

It’s All About the Journey

Software craftsmanship is not about becoming a master and then resting on your laurels.

While we should aspire to master all aspects of software development, we can’t hope to actually achieve it. It’s more about the journey than the destination. And about the fun we can have along the way.

Adventures in JavaScript: Getting Started

Node.jsOne of the high potentials for a Frictionless Development Environment (FDE) is Cloud9.

It is one of a growing number of web applications that uses JavaScript as the programming language for both front-end and back-end. The latter brought to you by Node.js.

So I thought it was time to start playing around with JavaScript and Node. Here is an account of my very first adventure into this Brave New World.

Preparations: Adding JavaScript Support to Eclipse

To keep the number of changes low, I wanted to keep my trusted old Eclipse. So the first step was to install Nodeclipse and jshint-eclipse.

To support documentation in the Markdown format that Node uses, I installed the Markdown Editor plugin for Eclipse.

This left me with nothing for unit tests. So I installed the JavaScript tools from Eclipse. That gave me some JS support, but nothing for creating unit tests.

Some googling told me there is such a thing as JsUnit, the JS port of my beloved JUnit. Unfortunately it doesn’t seem to come with Eclipse support, even though this thread indicates it does (or did).

JsTestDriverMaybe I’m just doing it wrong. I’d appreciate any hints in the comments.

Some more googling informed me that Orion is using JsTestDriver.

This introduction to JsTestDriver explains in detail how it works.

First Exercise: Roman Numerals

Now that I’m all set up, it’s time to do a little exercise to get my feet wet. For this I picked the Roman Numerals kata.

I started out by following this JsTestDriver example. I created a new JavaScript project in Eclipse, added src/main/js and src/test/js folders, and created the JsTestDriver configuration file:

server: http://localhost:9876

load:
  - src/main/js/*.js
  - src/test/js/*.js

Next, I opened the JsTestDriver window using Window|Show View|Other|JavaScript|JsTestDriver and started the JsTestDriver server. I then opened the client in FireFox at http://127.0.0.1:42442/capture.

The next step was to create a new run configuration: Run|Run Configurations|JsTestDriver Test. I selected the project and the JsTestDriver configuration within the project, and checked Run on Every Save.

Now everything is set up to start the TDD cycle. First a test:

RomanNumeralsTest = TestCase("RomanNumeralsTest");

RomanNumeralsTest.prototype.testArabicToRoman
    = function() {
  var romanNumerals = new TestApp.RomanNumerals();

  assertEquals("i", romanNumerals.arabicToRoman(1));
};

And then the implementation:

TestApp = { };

TestApp.RomanNumerals = function() { };

TestApp.RomanNumerals.prototype.arabicToRoman
    = function (arabic) {
  return null;
};

I completed the rest of the kata as usual.

Reflections

The cool thing about JsTestDriver is that it automatically runs all the tests every time you change something. This shortens the feedback cycle and keeps you in the flow. For Java, InfiniTest does the same.

The problem with my current tool chain is that support for renaming is extremely limited. I got Operation unavailable on the current selection. Select a JavaScript project, source folder, resource, or a JavaScript file, or a non-readonly type, var, function, parameter, local variable, or type variable.

Other refactorings do exist, like Extract Local Variable and Extract Method, but they mess up the formatting. They also give errors, but then work when trying again.

All in all I feel satisfied with the first steps I’ve taken on this journey. I’m a little worried about the stability of the tools. I also realize I have a more to learn about JavaScript prototypes.

Towards a Theory of Test-Driven Development

Red, Green, RefactorThis post examines how well we really understand the practice of Test-Driven Development (TDD).

Red, Green, Refactor

By now we all know that Test-Driven Development (TDD) follows a simple cycle consisting of these steps:

  1. Start by writing a test. Since there is no code, it will fail (Red)
  2. Write just enough code to make the test pass (Green)
  3. Clean up the code (Refactor)

The beauty of this division is that we can focus on one thing at a time.

Specify, Transform, Refactor

Although simple, TDD isn’t easy. To execute the TDD cycle well, we need a deeper understanding that we can only get from experience.

For instance, after doing TDD for a while we may look at the steps as:

  1. Specify new required functionality
  2. Improve the functionality while keeping the design constant
  3. Improve the design while keeping the functionality constant

When we look at the TDD cycle in this light, we see that the Green and Refactor phases are each others opposite.

Refactorings and Transformations

In the Refactor phase, we use Martin Fowler‘s refactorings to clean up the code.

TransformationRefactorings are standard alterations of the code that change its internal structure without changing its external behavior.

Now, if the Green and Refactor phases are each others opposite, then you might think that there are “opposite refactorings” as well. You would be right.

Robert Martin‘s transformations are standard alterations of the code that change its external behavior without changing its internal structure.

Automated Transformations?

Most of us use powerful IDEs to write our code. These IDEs support refactorings, which means that they can do the code alteration for you in a manner that is guaranteed to be safe.

So do we need something similar for transformations? I think not.

Some transformations are so simple in terms of the changes to code, that it wouldn’t actually save any effort to automate them. I don’t see a lot of room for improving the change from if to while, for instance.

Other transformations simply have an unspecified effect. For example, how would you automate the statement->statements transformation?

RefactoringThe crux is that refactorings keep the external behavior the same, and the tools depend on that to properly implement the refactorings. However, transformations don’t share that property.

Standardized Work

In the Specify/Transform/Refactor view of TDD, we write our programs by alternating between adding tests, applying transformations, and applying refactorings.

In other words, if we look at the evolution of our non-test code through a series of diffs, then each diff shows either a transformation or a refactoring.

It seems we are getting closer to the Lean principle of Standardized Work.

What’s still missing, however, is a deeper insight into the Red/Specify phase.

How to Write Tests

The essential part of the Red/Specify phase is obviously to write a test. But how do we do that?

For starters, how do we select the next test to implement?

Unit test failureThere is almost always more than one test to write for a given requirement.

And the order in which you introduce tests makes a difference for the implementation.

But there is very little advice on how to pick the next test, and this is sorely needed.

Kent Beck has a kata for experimenting with test order, which helps in gaining understanding. But that’s a far cry from a well-developed theory like we have for refactorings.

So what do you think? If we understood this phase better, could we come up with the test writing equivalent of transformations and refactorings?

Please share your thoughts in the comments.

The Differences Between Test-First Programming and Test-Driven Development

Red, Green, RefactorThere seems to be some confusion between Test-First Programming and Test-Driven Development (TDD).

This post explains that merely writing the tests before the code doesn’t necessarily make it TDD.

Similarities Between Test-First Programming and Test-Driven Development

It’s not hard to see why people would confuse the two, since they have many things in common.

My classification of tests distinguishes six dimensions: who, what, when, where, why, and how.

Test-First programming and Test-Driven Development score the same in five of those six dimensions: they are both automated (how) functional (what) programmer (who) tests at the unit level (where) written before the code (when).

The only difference is in why they are written.

Differences Between Test-First Programming and Test-Driven Development

Test-First Programming mandates that tests be written before the code, so that the code will always be testable. This is more efficient than having to change already written code to make it testable.

Test-First Programming doesn’t say anything about other activities in the development cycle, like requirements analysis and design.

This is a big difference with Test-Driven Development (TDD), since in TDD, the tests drive the design. Let’s take a detailed look at the TDD process of Red/Green/Refactor, to find out exactly how that differs from Test-First Programming.

Red

Unit test failureIn the first TDD phase we write a test. Since there is no code yet to make the test pass, this test will fail.

Unit testing frameworks like JUnit will show the result in red to indicate failure.

In both Test-First Programming and Test-Driven Development, we use this phase to record a requirement as a test.

TDD, however, goes a step further: we also explicitly design the client API. Test-First Programming is silent on how and when we should do that.

Green

In the next phase, we write code to make the test pass. Unit testing frameworks show passing tests in green.

In Test-Driven Development, we always write the simplest possible code that makes the test pass. This allows us to keep our options open and evolve the design.

JUnit passing testWe may evolve our code using simple transformations to increase the complexity of the code enough to satisfy the requirements that are expressed in the tests.

Test-First Programming is silent on what sort of code you write in this phase and how you do it, as long as the test will pass.

Refactor

In the final TDD phase, the code is refactored to improve the design of the implementation.

This phase is completely absent in Test-First Programming.

Summary of Differences

So we’ve uncovered two differences that distinguish Test-First Programming from Test-Driven Development:

  1. Test-Driven Development uses the Red phase to design the client API. Test-First Programming is silent on when and how you arrive at a good client API.
  2. Test-Driven Development splits the coding phase into two compared to Test-First Programming. In the first sub-phase (Green), the focus is on meeting the requirements. In the second sub-phase (Refactor), the focus is on creating a good design.

I think there is a lot of value in the second point. Many developers focus too much on getting the requirements implemented and forget to clean up their code. The result is an accumulation of technical debt that will slow development down over time.

TDD also splits the design activity into two. First we design the external face of the code, i.e. the API. Then we design the internal organization of the code.

This is a useful distinction as well, because the heuristics you would use to tell a good API from a bad one are different from those for good internal design.

Try Before You Buy

KataAll in all I think Test-Driven Development provides sufficient value over Test-First Programming to give it a try.

All new things are hard, however, so be sure to practice TDD before you start applying it in the wild.

There are numerous katas that can help you with that, like the Roman Numerals Kata.

Software Development and Lifelong Learning

The main constraint in software development is learning. This means that learning is a core skill for developers and we should not think we’re done learning after graduation. This post explores some different ways in which to learn.

Go To Conferences

Conferences are a great place to learn new things, but also to meet new people. New people can provide new ways of looking at things, which helps with learning as well.

You can either go to big and broad conferences, like Java One or the RSA conference, or you can attend a smaller, more focused event. Some of these smaller events may not be as well-known, but there are some real gems nonetheless.

Take XML Amsterdam, for example, a small conference here in the Netherlands with excellent international speakers and attendees (even some famous ones).

Attend Workshops

Learning is as much about doing as it is about hearing and watching. Some conferences may have hands-on sessions or labs, but they’re in the minority. So just going to conferences isn’t good enough.

A more practical variant are workshops. They are mostly organized by specific communities, like Java User Groups.

One particularly useful form for developers is the code retreat. Workshops are much more focused than conferences and still provide some of the same networking opportunities.

Get Formal Training

Lots of courses are being offered, many of them conveniently online. One great (and free) example is Cryptography from Coursera.

Some of these course lead to certifications. The world is sharply divided into those who think certifications are a must and those that feel they are evil. I’ll keep my opinion on this subject to myself for once 😉 but whatever you do, focus on the learning, not on the piece of paper.

Learn On The Job

There is a lot to be learned during regular work activities as well.

You can organize that a bit better by doing something like job rotation. Good forms of job rotation for developers are collective code ownership and swarming.

Pair programming is an excellent way to learn all kinds of things, from IDE shortcuts to design patterns.

Practice in Private

Work has many distractions, though, like Getting a Story Done.

Open source is an alternative, in the sense that it takes things like deadlines away, which can help with learning.

However, that still doesn’t provide the systematic exploration that is required for the best learning. So practicing on “toy problems” is much more effective.

There are many katas that do just that, like the Roman Numerals Kata. They usually target a specific skill, like Test-Driven Development (TDD).

Practicing TDD using the Roman Numerals kata

Test-Driven Development (TDD) is a scientific approach to software development that supports incremental design. I’ve found that, although very powerful, this approach takes some getting used to. Although the rules of TDD are simple, they’re not always easy:

  1. Write a failing test
  2. Write the simplest bit of code that makes it pass
  3. Refactor the code to follow the rules of simple design

This is also called the Red-Green-Refactor cycle of TDD.

Writing a failing test isn’t always easy. Lots of TDD beginners write tests that are to big; TDD is all about taking baby steps. Likewise, writing the simplest bit of code to make the test pass is sometimes difficult. Many developers are trained to write generic code that can handle more than just the case at hand; they must unlearn these habits and truly focus on doing The Simplest Thing That Could Possibly Work.

The hardest part of TDD, however, is the final step. Some TDD novices skip it altogether, others have trouble evolving their design. Code that follows the rules of simple design

  1. Passes all the tests
  2. Contains no duplication
  3. Clearly expresses the programmer’s intent
  4. Minimizes code

The first is easy, since your xUnit framework will either give you Red or Green. But then the fun begins. Let’s walk through an example to see TDD in action.

We’ll use the Roman Numerals kata for this example. A kata is a term inherited from the martial arts. To get really good at something, you have to practice. The martial arts understood this long before the Software Crafsmanship movement was born.
They use katas to practice their basic moves over and over again. Software katas are similar. They focus on fundamental skills like TDD and incremental design.

In the Roman Numerals kata, we convert Arabic numbers (the one we use daily: 1, 2, 3, 4, 5, …) into their Roman equivalent: I, II, III, IV, V, … It’s a good kata, because it allows one to practice skills in a very concentrated area, as we’ll see.

So let’s get started. The first step is to write a failing test:

public class RomanNumeralsTest {

  @Test
  public void one() {
    Assert.assertEquals("1", "I", RomanNumerals.arabicToRoman(1));
  }

}

Note that this step really is not (only) about tests. It really is about designing your API from the client’s perspective. Think of something that you as a user of the API would like to see to solve your bigger problem. In this kata, the API is just a single method, so there is not much to design.

OK, we’re at Red, so let’s get to Green:

public class RomanNumerals {

  public static String arabicToRoman(int arabic) {
    return "I";
  }

}

But that’s cheating! That’s not an algorithm to convert Arabic numerals into Roman! True, it’s not, but it isn’t cheating either. The rules of TDD state that we should write the simplest code that passes the test. It’s only cheating if you play by the old rules. You must unlearn what you have learned.

Now for the Refactor step. The test passes, there is no duplication, we express our intent (that currently is limited to convert 1 into I) clearly, and we have the absolute minimum number of classes and methods (both 1), so we’re done. Easy, right?

Now we move to the next TDD cycle. First Red:

public class RomanNumeralsTest {

  @Test
  public void oneTwo() {
    Assert.assertEquals("1", "I", RomanNumerals.arabicToRoman(1));
    Assert.assertEquals("2", "II", RomanNumerals.arabicToRoman(2));
  }

}

No need to change our API. In fact we won’t have to change it again for the whole kata. So let’s move to Green:

public static String arabicToRoman(int arabic) {
  if (arabic == 2) {
    return "II";
  }
  return "I";
}

OK, we’re Green. Now let’s look at this code. It’s pretty obvious that if we continue down this path, we’ll end up with very, very bad code. There is no design at all, just a bunch of hacks. That’s why the Refactor step is essential.

We pass the tests, but how about duplication? There is duplication in the Arabic number passed in and the number of I’s the method returns. This may not be obvious to everyone because of the return in the middle of the method. Let’s get rid of it to better expose the duplication…

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  if (arabic == 2) {
    result.append("I");
  }
  result.append("I");
  return result.toString();
}

…so that we can remove it:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  for (int i = 0; i < arabic; i++) {
    result.append("I");
  }
  return result.toString();
}

What we did here was generalize an if statement into a for (or while). This is one of a bunch of transformations one often uses in TDD. The net effect of a generalization like this is that we have discovered a rule based on similarities. This means that our code can now handle more cases than the ones we supplied as tests. In this specific case, we can now also convert 3 to III:

@Test
public void oneTwoThreeRepeatIs() {
  Assert.assertEquals("1", "I", RomanNumerals.arabicToRoman(1));
  Assert.assertEquals("2", "II", RomanNumerals.arabicToRoman(2));
  Assert.assertEquals("3", "III", RomanNumerals.arabicToRoman(3));
}

Now that we have removed duplication, let’s look at expressiveness and compactness. Looks OK to me, so let’s move on to the new case. We got 3 covered, so 4 is next:

@Test
public void four() {
  Assert.assertEquals("4", "IV", RomanNumerals.arabicToRoman(4));
}

This fails as expected, because we generalized to far. We need an exception to our discovered rule:

  public static String arabicToRoman(int arabic) {
    StringBuilder result = new StringBuilder();
    if (arabic == 4) {
      return "IV";
    }
    for (int i = 0; i < arabic; i++) {
      result.append("I");
    }
    return result.toString();
  }

This uses return in the middle of a method again, which we discovered may hide duplication. So let’s not ever use that again. One alternative is to use an else statement. The other is to decrease the arabic parameter, so that the for loop never executes. We have no information right now on which to base our choice, so either will do:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  if (arabic == 4) {
    result.append("IV");
  } else {
    for (int i = 0; i < arabic; i++) {
      result.append("I");
    }
  }
  return result.toString();
}

It’s hard to see duplication in here, and I think the code expresses our current intent and is small, so let’s move on to the next test:

@Test
public void five() {
  Assert.assertEquals("5", "V", RomanNumerals.arabicToRoman(5));
}

Which we make pass with:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  if (arabic == 5) {
    result.append("V");
  } else if (arabic == 4) {
    result.append("IV");
  } else {
    for (int i = 0; i < arabic; i++) {
      result.append("I");
    }
  }
  return result.toString();
}

This is turning into a mess. But there is no duplication apparent yet, and the code does sort of say what we mean. So let’s push our uneasy feelings aside for a little while and move on to the next test:

@Test
public void six() {
  Assert.assertEquals("6", "VI", RomanNumerals.arabicToRoman(6));
}

Which passes with:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  if (arabic == 6) {
    result.append("VI");
  } else if (arabic == 5) {
      result.append("V");
  } else if (arabic == 4) {
    result.append("IV");
  } else {
    for (int i = 0; i < arabic; i++) {
      result.append("I");
    }
  }
  return result.toString();
}

Hmm, uglier still, but at least some duplication is now becoming visible: VI is V followed by I, and we already have code to append those. So we could first add the V and then rely on the for loop to add the I:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  int remaining = arabic;
  if (remaining >= 5) {
    result.append("V");
    remaining -= 5;
  }
  if (remaining == 4) {
    result.append("IV");
    remaining -= 4;
  }
  for (int i = 0; i < remaining; i++) {
    result.append("I");
  }
  return result.toString();
}

Still not very clean, but better than before. And we can now also handle 7 and 8. So let’s move on to 9:

@Test
public void nineIsXPrefixedByI() {
  Assert.assertEquals("9", "IX", RomanNumerals.arabicToRoman(9));
}
public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  int remaining = arabic;
  if (remaining == 9) {
    result.append("IX");
    remaining -= 9;
  }
  if (remaining >= 5) {
    result.append("V");
    remaining -= 5;
  }
  if (remaining == 4) {
    result.append("IV");
    remaining -= 4;
  }
  for (int i = 0; i < remaining; i++) {
    result.append("I");
  }
  return result.toString();
}

There’s definitely a pattern emerging. Two ifs use ==, and one uses >=, but the rest of the statements is the same. We can make them all completely identical by a slight generalization:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  int remaining = arabic;
  if (remaining >= 9) {
    result.append("IX");
    remaining -= 9;
  }
  if (remaining >= 5) {
    result.append("V");
    remaining -= 5;
  }
  if (remaining >= 4) {
    result.append("IV");
    remaining -= 4;
  }
  for (int i = 0; i < remaining; i++) {
    result.append("I");
  }
  return result.toString();
}

Now we can extract the duplication:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  int remaining = arabic;
  remaining = appendRomanNumerals(remaining, 9, "IX", result);
  remaining = appendRomanNumerals(remaining, 5, "V", result);
  remaining = appendRomanNumerals(remaining, 4, "IV", result);
  for (int i = 0; i < remaining; i++) {
    result.append("I");
  }
  return result.toString();
}

private static int appendRomanNumerals(int arabic, int value, String romanDigits, StringBuilder builder) {
  int result = arabic;
  if (result >= value) {
    builder.append(romanDigits);
    result -= value;
  }
  return result;
}

There is still duplication is the enumeration of calls to appendRomanNumerals. We can turn that into a loop:

private static final int[]    VALUES  = { 9,    5,   4 };
private static final String[] SYMBOLS = { "IX", "V", "IV" };

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  int remaining = arabic;
  for (int i = 0; i < VALUES.length; i++) {
    remaining = appendRomanNumerals(remaining, VALUES[i], SYMBOLS[i], result);
  }
  for (int i = 0; i < remaining; i++) {
    result.append("I");
  }
  return result.toString();
}

Now that we look at the code this way, it seems that the for loop does something similar to what appendRomanNumerals does. The only difference is that the loop does it multiple times, while the method does it only once. We can generalize the method and rewrite the loop to make this duplication more visible:

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  int remaining = arabic;
  for (int i = 0; i < VALUES.length; i++) {
    remaining = appendRomanNumerals(remaining, VALUES[i], SYMBOLS[i], result);
  }
  while (remaining >= 1) {
    result.append("I");
    remaining -= 1;
  }
  return result.toString();
}

private static int appendRomanNumerals(int arabic, int value, String romanDigits, StringBuilder builder) {
  int result = arabic;
  while (result >= value) {
    builder.append(romanDigits);
    result -= value;
  }
  return result;
}

This makes it trivial to eliminate it:

private static final int[]    VALUES  = { 9,    5,   4,    1   };
private static final String[] SYMBOLS = { "IX", "V", "IV", "I" };

public static String arabicToRoman(int arabic) {
  StringBuilder result = new StringBuilder();
  int remaining = arabic;
  for (int i = 0; i < VALUES.length; i++) {
    remaining = appendRomanNumerals(remaining, VALUES[i], SYMBOLS[i], result);
  }
  return result.toString();
}

Now we have discovered our algorithm and new cases can be handled by just adding to the arrays:

  private static final int[]    VALUES  = { 1000, 900,  500, 400,  100, 90,   50,  40,   10,  9,    5,   4,    1   };
  private static final String[] SYMBOLS = { "M",  "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };

There is still some duplication in the arrays, but one can wonder whether eliminating it would actually improve the code, so we’re just going to leave it as it is. And then there is some duplication in the fact that we have two arrays with corresponding elements. Moving to one array would necessitate the introduction of a new class to hold the value/symbol combination and I don’t think that that’s worth it.

So that concludes our tour of TDD using the Roman Numerals kata. What I really like about this kata is that it is very focused. There is hardly any API design, so coming up with tests is really easy. And the solution isn’t all that complicated either; you only need if and while. This kata really helps you hone your skills of detecting and eliminating duplication, which is a fundamental skill to have when evolving your designs.

Have fun practicing!

Update: Here is a screencast of a better version of the kata: