Event storming icons

Most engineering disciplines specialize around a domain. Engineers trained in that field speak the same language as the people requesting them to build a system. In contrast, software developers need to learn the language of the domain. This makes it harder to elicit requirements.

Subject-matter experts (SMEs), by definition, are experts. They’ve accumulated a lot of knowledge over a long period of time. It’s hard for them to think back to when they didn’t have all that knowledge. This makes it hard for them to know what to explain or not, and even what to mention at all. And since the business analyst is new to the domain, they don’t know what questions to ask. The result is an iterative process that takes a lot of time to get things right.

Worse, it’s uncommon for SMEs to be experts in the entire domain. More often, multiple SMEs each have a clear picture of one part of the process and nobody of the whole. This results in conflicting points of view, which need resolution before building software. However, it takes a while before the analyst knows enough to ask the hard questions and bring conflicts into the open.

Event storming is a technique that solves these issues. It’s a workshop where the key stakeholders work together to build up a consistent picture of the entire process under consideration.

In event storming, the SMEs perform the integration of various perspectives rather than the business analyst. By giving them a standard notation, non-experts can follow what they’re doing and force them to be precise. It allows them to ask the hard questions and bring conflicts out for resolution. Everybody’s learning compresses while the domain model emerges as a natural byproduct.

Event storming use the following concepts:

  • A domain event is anything that happens that’s of interest to an SME. (orange)
  • A command triggers an event. (blue)
  • An aggregate accepts commands and emits events. (yellow)
  • A policy contains the decision on how to react to an event. (purple)
  • A read model holds the information necessary to make a decision. (green)
  • A person is a human being responsible for a given decision. (yellow)
  • An external system is another system that interacts with the system under consideration. (pink)

In an event storming workshop, sticky notes of a particular color represent each of these concepts. Workshop participants place the stickies on a wall in timeline order to visualize the business process.

A specific grammar governs event storming concepts, in the sense that certain items always come before or after others. It’s this grammar that allows people who aren’t domain experts to ask intelligent questions, like what command leads to this event, and who issues it?

I like event storming, because it employs useful concepts, like domain events, that are non-technical and yet naturally map to technical concepts, like messages published to a message broker. As such, the output of the workshop is useful long after the workshop is over.

That raises the question of how best to use that output. During the workshop, using stickies makes a lot of sense to facilitate interaction. Afterwards, however, a bit more formal notation would be nice.

I created a set of icons that represent the event storming concepts. These icons maintain the colors of the stickies, but add symbols to visually represent the concepts. Here’s the event storming grammar visualized using these icons:

I’ve used these icons to document processes in a way that both techies and non-techies can follow. The icons are released under the Creative Commons By Attribution 4.0 International license, so feel free to use them in your own work.

Performance and TDD

TDD works wonders for developing code that meets functional requirements. But what about non-functional requirements? Let’s take a look at one that most users care about: performance.

Most TDD examples are necessarily small, so that the author can see the process through to completion. That reduces the chances for intricacies like performance aspects. But it’s not impossible. Let’s try this with the WordWrap kata, where we have to ensure lines aren’t too long by inserting newline characters in appropriate places.

As usual, we start with input validation:

class WhenWrappingWords {

    @Test
    void shouldHandleEmptyText() {
        assertWrap(null, "");
    }

    private void assertWrap(String text, String expected) {
        assertThat(text, Wrapper.wrap(text, 5), is(expected));
    }

}

Which is easy enough:

public class Wrapper {

    public static String wrap(String text, int length) {
         return "";
    }

}

Next, the degenerate case, where the text doesn’t require newlines:

    @Test
    void shouldNotWrapShortText() {
        assertWrap("short", "short");
    }
    public static String wrap(String text, int length) {
        if (text == null) {
             return "";
        }
        return text;
    }

Now we get to the meat: longer texts require wrapping:

    @Test
    void shouldWrapLongText() {
        assertWrap("toolong", "toolo\nng");
    }
    private static final char NL = '\n';

    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        if (text.length() <= length) {
            return text;
        }
        return text.substring(0, length) + NL 
            + text.substring(length);
    }

But, if possible, we should wrap at word boundaries rather than in the middle of a word:

    @Test
    void shouldPreferToWrapAtWhitespace() {
        assertWrap("too long", "too\nlong");
    }
    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        if (text.length() <= length) {
            return text;
        }
        var index = text.lastIndexOf(' ', length);
        if (index < 0) {
            return text.substring(0, length) + NL
                + text.substring(length);
        }
        return text.substring(0, index) + NL
            + text.substring(index + 1);
    }

And finally, we should wrap into multiple lines if needed:

    @Test
    void shouldWrapVeryLongTextMultipleTimes() {
        assertWrap("toolongtext", "toolo\nngtex\nt");
        assertWrap("too long text", "too\nlong\ntext");
    }
    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        if (text.length() <= length) {
            return text;
        }
        var index = text.lastIndexOf(' ', length);
        if (index < 0) {
            return text.substring(0, length) + NL 
                + wrap(text.substring(length), length);
        }
        return text.substring(0, index) + NL 
            + wrap(text.substring(index + 1), length);
    }

Which we can clean up a bit:

    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        if (text.length() <= length) {
            return text;
        }
        var index = text.lastIndexOf(' ', length);
        var skip = 1;
        if (index < 0) {
            index = length;
            skip = 0;
        }
        return text.substring(0, index) + NL 
            + wrap(text.substring(index + skip), length);
    }

Now let’s consider the performance of this code. Can we use it to format a book? A novel has around 100,000 words and an English word consists of 5.1 letters on average. Let’s say we want to wrap lines at 80 characters:

    private static final int NUM_WORDS_IN_BOOK = 100_000;
    private static final float AVG_NUM_CHARS_PER_WORD = 5.1f;
    private static final int MAX_BOOK_LINE_LENGTH = 80;
    private static final int NUM_TRIES = 10;
    private static final float MAX_WRAPPING_MS = 1000;

    private final Random random = new SecureRandom();

    @Test
    void shouldWrapBook() {
        var time = 0;
        for (var i = 0; i < NUM_TRIES; i++) {
            var text = randomStringOfBookLength();
            var start = System.currentTimeMillis();
            Wrapper.wrap(text, MAX_BOOK_LINE_LENGTH);
            var stop = System.currentTimeMillis();
            time += stop - start;
        }
        assertThat(1.0f * time / NUM_TRIES, 
            lessThanOrEqualTo(MAX_WRAPPING_MS));
    }

    private String randomStringOfBookLength() {
        var numCharsInBook = (int) (NUM_WORDS_IN_BOOK * ( 1 + AVG_NUM_CHARS_PER_WORD));
        var result = new StringBuilder(numCharsInBook);
        for (var i = 0; i < numCharsInBook; i++) {
            result.append(randomChar());
        }
        return result.toString();
    }

    private char randomChar() {
        if (random.nextFloat() < 1.0 / (1 + AVG_NUM_CHARS_PER_WORD)) {
            return ' ';
        }
        return (char) (random.nextInt(26) + 'a');
    }

Normally, you’d use the Java Microbenchmark Harness to investigate the performance of an algorithm like this. I don’t want to introduce new tech for this already long post, however, so this test will have to do. Note that we have to run multiple tries, since we’re using randomness.

Running this test gives a stack overflow, so clearly we need to do something about that.

In this case, it would be easy to replace the recursion with a while loop, so we could just go do that and see the test pass. In the real world, however, things usually aren’t that simple.

This is where the Strategy pattern can come in handy. With multiple implementations of the strategy interface, we can run our tests against all of them. We can develop alternative implementations from scratch, using TDD, or copy some code into a new implementation and start modifying it. Once we’re satisfied with the results, we can keep the best implementation and remove the others.

But hang on, we used TDD to get to this implementation, so how is doing that again going to give us a different result?

Well, when we did it the first time, we weren’t focused on performance. We shouldn’t have been, since premature optimization is the root of all evil. Now that we have proof that our performance isn’t good enough, things are different. Let’s see how that plays out.

The implementation of the first two tests can remain the same:

    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        return text;
    }

To make shouldWrapLongText() pass, we need to pay more attention to performance this time. We don’t want to use substring() and add two Strings together, since that involves copying characters. So let’s use a StringBuilder instead:

    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        var result = new StringBuilder(text);
        if (result.length() > length) {
            result.insert(length, NL);
        }
        return result.toString();
    }

This still means we have to copy some arrays around to make room for the newline. We can avoid that by allocating enough capacity from the start:

    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        var capacity = text.length() + text.length() / length;
        var result = new StringBuilder(capacity);
        result.append(text);
        if (result.length() > length) {
            result.insert(length, NL);
        }
        return result.toString();
    }

This would normally be looking ahead a bit too much for my taste, but since we already implemented the algorithm once, we know for sure we’re going to need this, so I’m cool with it.

Next let’s make shouldPreferToWrapAtWhitespace() pass:

    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        var result = new StringBuilder(text.length() + text.length() / length);
        result.append(text);
        if (result.length() > length) {
            var spaceIndex = text.lastIndexOf(' ', length);
            if (spaceIndex < 0) {
                result.insert(length, NL);
            } else {
                result.setCharAt(spaceIndex, NL);
            }
        }
        return result.toString();
    }

Finally, we can generalize the if to a while to make the last test pass:

    public static String wrap(String text, int length) {
        if (text == null) {
            return "";
        }
        var capacity = text.length() + text.length() / length;
        var result = new StringBuilder(capacity);
        result.append(text);
        var columnEnd = length;
        while (columnEnd < result.length()) {
            var spaceIndex = result.lastIndexOf(" ", columnEnd);
            if (spaceIndex < columnEnd - length) {
                result.insert(columnEnd, NL);
                columnEnd += length + 1;
            } else {
                result.setCharAt(spaceIndex, NL);
                columnEnd = spaceIndex + 1 + length;
            }
        }
        return result.toString();
    }

This passes all our tests, including the one about performance.

The above do-over may seem like a wasteful approach: why wouldn’t we do it “right” from the start? Like I said earlier, we didn’t because we didn’t know that our implementation wasn’t going to perform well. But what if we did know from the start that performance was important?

We could’ve written our tests in a different order, tackling the test for performance earlier in the process. That would’ve prevented us from getting to green with recursion in this example, saving us a bit of time. In a real-world scenario, it might have saved a lot more time. Yet again, we see that the order of tests is important.

I would argue, however, that not much time was lost with the initial approach. I still believe that the proper order is make it pass, make it right, make it fast. One of the reasons TDD works so well is the explicit distinction between making the test green and then refactoring. Doing one thing at a time is solid advice when it comes to addressing performance as well.

I’ll accept a little bit of rework, knowing that I’ll win back that time and more in all the cases where the “right” solution is also fast enough and I don’t waste time on premature optimization.

Sprint considered harmful

At this time of the year, many people like to slow down and reflect. It seems as good a time as any then, to take offense at the word “sprint” in the context of software development.

I firmly believe that words have meaning, semantic diffusion be damned. Merriam-Webster defines sprint as “to run or go at top speed especially for a short distance”. Most software development doesn’t go just “a short distance”. And as far as I know, nobody ever won a marathon by running 422 consecutive 100m sprints. So the sprint analogy breaks down pretty badly.

The marathon analogy isn’t any better, however. Runners often hit a wall between 30 and 35 kilometers, also known as the man with the hammer. This is due to depletion of glycogen stored in the muscles, which forces the body to transition to alternative energy sources, like breaking down fat. Since this is much less efficient, the runner’s body struggles to maintain the same level of performance.

The equivalent in software development is known as a death march. The team is pushed to their limits at the expense of work-life balance, the well-being of its members, and the quality of the work they produce.

This isn’t a good model for what we want to happen. We want a sustainable pace that developers can keep up for as long as it takes to complete the project. We need them sharp to do their best work. Sleep deprived or stressed out people don’t perform well and software development is hard enough as it is.

So let’s not talk about sprints anymore, shall we?

What then, is a good alternative?

Well, the word “sprint” is used in software development in the context of Agile methods, in particular Scrum. Agile methods are iterative in nature: they split up delivery into small pieces. The word iterative comes from iteration, which is exactly the word that eXtreme Programming and other Agile methods use instead of “sprint”. Turning to Merriam-Webster again, we find that iteration is “a procedure in which repetition of a sequence of operations yields results successively closer to a desired result.” That sounds about right.

Exercise for the reader: What’s wrong with the phrase “best practices?” (And why do we always seem to need more than one?) Hint: look up the Cynefin framework.

Canon TDD example: Roman numerals

People continue to misunderstand Test-Driven Development (TDD). Kent Beck, who wrote the book on it, recently published an article called Canon TDD, which aims to remove some of those misunderstandings. This post shows an example.

Suppose you need Roman numerals in your application. Maybe you want to show years that way, or the hours of a clock, or the titles of Superbowl games. The problem we’ll look at is to calculate a string that represents the Roman representation of a number. We’ll solve that problem using Canon TDD.

The first step is to write a list of test scenarios we want to cover. We use Wikipedia as a reference to compile this list:

  1. Input validation: Roman numerals can’t express numbers smaller than 1 or bigger than 3999.
  2. Numbers are written using a subset of the Latin alphabet (I, V, X, L, C, D, and M), which each have a fixed integer value (1, 5, 10, 50, 100, 500, 1000).
  3. Roman numerals are constructed by appending partial solutions, e.g. 1005 = MV.
  4. We should always start with the highest valued symbol, e.g. 5 = V rather than IIIII.
  5. Subtractive notation shortens some numerals, e.g. 40 = 50 – 10 = XL rather than XXXX.

Step two is to pick one test from this list and express it in code. The order of tests matters. Some tests may force you to make a large change in your code. Always pick the next test such that you make it pass in an obvious way. It’s usually good to start with input validation, so that your programs are secure from the beginning. An additional benefit is that input validation is usually simple.

Here’s the first test:

class WhenConvertingNumbersToRomanNumerals {

    @Test
    void shouldRejectInexpressibleNumbers() {
        assertThrows(RomanNumeral.InexpressibleException.class, () -> 
                RomanNumeral.from(0));
    }

}

This is where we design our interface: we want a RomanNumeral class with a static method from() that accepts a number, returns a String, and throws an InexpressibleException exception on invalid input. To make the test compile, we have to add this code:

public class RomanNumeral {

    public static String from(int value) {
        return null;
    }


    public static class InexpressibleException 
            extends IllegalArgumentException {
    }

}

This fails because there is no exception thrown.

The third step is to make the test pass. The easiest way is to unconditionally throw the expected exception:

    public static String from(int value) {
        throw new InexpressibleException();
    }

The fourth step is to optionally refactor. There isn’t enough code yet for that to make sense.

Now we continue with the next cycle at step two. For the next test, we could add another check for invalid input, but that wouldn’t change the code, so that’s not a smart choice. Tests for items 3-5 on the list all depend on the symbols in 2, so that’s the obvious next choice:

    @Test
    void shouldConvertBaseSymbols() {
        assertThat(RomanNumeral.from(1), is("I"));
    }

This fails, as expected, with an exception. We need to throw the exception in some cases, but not others. In other words, we need an if statement:

    public static String from(int value) {
        if (value == 0) {
            throw new InexpressibleException();
        }
        return "I";
    }

Note how the code deals exclusively with the two tests that we wrote, and nothing else. Not only is the test coverage 100%, any other test than these two would fail. Such tests will force us to generalize the code.

Let’s first do the easy part and complete the input validation. First, generalize from 0 to non-positive numbers:

    @ParameterizedTest
    @ValueSource(ints = {-1, 0})
    void shouldRejectInexpressibleNumbers(int value) {
        assertThrows(RomanNumeral.InexpressibleException.class, () ->
                RomanNumeral.from(value));
    }
    public static String from(int value) {
        if (value <= 0) {
            throw new InexpressibleException();
        }
        return "I";
    }

With the lower bound in place, let’s add the upper bound:

    @ParameterizedTest
    @ValueSource(ints = {-1, 0, 4000, 4001})
    void shouldRejectInexpressibleNumbers(int value) {
        assertThrows(RomanNumeral.InexpressibleException.class, () ->
                RomanNumeral.from(value));
    }
    public static String from(int value) {
        if (value <= 0 || value >= 4000) {
            throw new InexpressibleException();
        }
        return "I";
    }

This works, but doesn’t look great, so let’s do some refactoring to make it more expressive:

    private static final int MIN_EXPRESSIBLE = 1;
    private static final int MAX_EXPRESSIBLE = 3999;

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        return "I";
    }

    private static boolean isExpressible(int value) {
        return MIN_EXPRESSIBLE <= value && value <= MAX_EXPRESSIBLE;
    }

Now we can cross item 1 of our list of tests. For our next test, we can pick from either 2 (more symbols) or 3 (additive form). The former would introduce an if statement that then generalizes into a switch with a bunch of random facts, while the latter would force us to develop a bit of an algorithm. That algorithm we can then apply to the other symbols. This sounds like an easier hill to climb than the reverse, where we would have to develop an algorithm that can deal with all the symbols. OK, here goes:

    @ParameterizedTest
    @CsvSource({"1,I", "2,II"})
    void shouldPerformAddition(int value, String expected) {
        assertThat(RomanNumeral.from(value), is(expected));
    }

Note that we renamed to test to better reflect what it is that we’re testing. The simplest way to make this test pass is to generalize the constant into a variable and to add to that variable inside an if:

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        var result = "I";
        if (value > 1) {
            result += "I";
        }
        return result;
    }

This looks messy, but bear with me. Things will become clearer after we add the next test:

    @ParameterizedTest
    @CsvSource({"1,I", "2,II", "3,III"})
    void shouldPerformAddition(int value, String expected) {
        assertThat(RomanNumeral.from(value), is(expected));
    }

To make this pass, we have to generalize the if to a while:

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        var result = "I";
        while (value > 1) {
            result += "I";
            value--;
        }
        return result;
    }

If we clean up a bit, we’re starting to see an algorithm form:

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        var result = "";
        while (value >= 1) {
            result += "I";
            value -= 1;
        }
        return result;
    }

The constants in this piece of code are related: "I" is the symbol for 1, so the algorithm adds "I" for as long as it needs. Let’s make this relationship clearer:

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        var result = "";
        var numeral = new Numeral("I", 1);
        while (value >= numeral.value()) {
            result += numeral.text();
            value -= numeral.value();
        }
        return result;
    }

    private record Numeral(String text, int value) {
    }

We can improve this code further. The from() method deals with a nice abstraction of inexpressible numbers, but also with a whole bunch of details about adding texts and subtracting numbers. So let’s extract all those details into its own method:

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        return convert(value);
    }

    private static String convert(int value) {
        var result = "";
        var numeral = new Numeral("I", 1);
        while (value >= numeral.value()) {
            result += numeral.text();
            value -= numeral.value();
        }
        return result;
    }

Another code smell here is that we change the value of the parameter. We can solve that in two ways. The first is to assign the parameter to a local variable and then use that variable everywhere we now use the parameter. The second is to introduce a local variable and compare it to the parameter. This turns out to be more instructive:

    private static String convert(int value) {
        var result = "";
        var progress = 0;
        var numeral = new Numeral("I", 1);
        while (value - progress >= numeral.value()) {
            result += numeral.text();
            progress += numeral.value();
        }
        return result;
    }

Now we can see something interesting: the combination of result and progress is very much like a Numeral. But in order to express that, we need to be able to add two Numerals:

    private static String convert(int value) {
        var result = new Numeral("", 0);
        var numeral = new Numeral("I", 1);
        while (value - result.value() >= numeral.value()) {
            result = result.add(numeral);
        }
        return result.text();
    }

    private record Numeral(String text, int value) {

        Numeral add(Numeral addens) {
            return new Numeral(text + addens.text,
                    value + addens.value);
        }

    }

Now the contours of the algorithm are starting to become more apparent: we will build up the result by processing our numeral. Presumably, we’ll add processing of other numerals later. In order to prepare for that, let’s tidy the code a bit more by extracting the part that handles the numeral variable. If we did that on the current code, however, the extracted method would need to take result and value as parameters, in addition to numeral. That’s because this is a static method, and thus not able to use fields. Let’s fix that. First we make convert() an instance method:

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        return new RomanNumeral().convert(value);
    }

    private String convert(int value) {
        var result = new Numeral("", 0);
        var numeral = new Numeral("I", 1);
        while (value - result.value() >= numeral.value()) {
            result = result.add(numeral);
        }
        return result.text();
    }

Then we can turn result and value into fields. We also rename value to target and convert() to complete() to better express their meaning:

    private final int target;
    private Numeral current = new Numeral("", 0);

    private RomanNumeral(int target) {
        this.target = target;
    }

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        return new RomanNumeral(value).complete();
    }

    private String complete() {
        var numeral = new Numeral("I", 1);
        while (target - current.value() >= numeral.value()) {
            current = current.add(numeral);
        }
        return current.text();
    }

Now we can finally extract the handling of one numeral into its own method:

    private String complete() {
        var numeral = new Numeral("I", 1);
        add(numeral);
        return current.text();
    }

    private void add(Numeral numeral) {
        while (target - current.value() >= numeral.value()) {
            current = current.add(numeral);
        }
    }

We may even want to extract another method to express the algorithm better:

    private void add(Numeral numeral) {
        while (remainder() >= numeral.value()) {
            current = current.add(numeral);
        }
    }

    private int remainder() {
        return target - current.value();
    }

That was a lot of refactoring, but look at what it did to the design.

We have now finished item 3 on our list. Let’s continue with item 2:

    @ParameterizedTest
    @CsvSource({"1,I", "5,V"})
    void shouldConvertBaseSymbols(int value, String expected) {
        assertThat(RomanNumeral.from(value), is(expected));
    }

We can make this pass by generalizing our single numeral into a list:

    private String complete() {
        var numerals = List.of(new Numeral("V", 5), new Numeral("I", 1));
        numerals.forEach(this::add);
        return current.text();
    }

Note that our algorithm only works if we process the numerals from high to low (item 4 on our test list). It’s now easy to add the other base symbols:

    @ParameterizedTest
    @CsvSource({"1,I", "5,V", "10,X", "50,L", "100,C", "500,D", "1000,M"})
    void shouldConvertBaseSymbols(int value, String expected) {
        assertThat(RomanNumeral.from(value), is(expected));
    }
    private String complete() {
        var numerals = List.of(
                new Numeral("M", 1000),
                new Numeral("D", 500),
                new Numeral("C", 100),
                new Numeral("L", 50),
                new Numeral("X", 10),
                new Numeral("V", 5),
                new Numeral("I", 1));
        numerals.forEach(this::add);
        return current.text();
    }

This concludes items 2 and 4 of our test list. The only thing left to do is item 5:

    @ParameterizedTest
    @CsvSource({"4,IV"})
    void shouldShortenWithSubtractiveNotation(int value, String expected) {
        assertThat(RomanNumeral.from(value), is(expected));
    }

We can make this pass simply by adding that numeral explicitly:

    private String complete() {
        var numerals = List.of(
                new Numeral("M", 1000),
                new Numeral("D", 500),
                new Numeral("C", 100),
                new Numeral("L", 50),
                new Numeral("X", 10),
                new Numeral("V", 5),
                new Numeral("IV", 4),
                new Numeral("I", 1));
        numerals.forEach(this::add);
        return current.text();
    }

While that works, it isn’t pretty. There is duplication in the values, since "IV" == "V" - "I" == 5 - 1 == 4. Let’s express that better:

    private String complete() {
        var v = new Numeral("V", 5);
        var i = new Numeral("I", 1);
        var numerals = List.of(
                new Numeral("M", 1000),
                new Numeral("D", 500),
                new Numeral("C", 100),
                new Numeral("L", 50),
                new Numeral("X", 10),
                v,
                v.subtract(i),
                i);
        numerals.forEach(this::add);
        return current.text();
    }

    private record Numeral(String text, int value) {

        public Numeral subtract(Numeral subtrahens) {
            return new Numeral(subtrahens.text + text,
                    value - subtrahens.value);
        }

    }

The others are similar:

    @ParameterizedTest
    @CsvSource({"4,IV", "9,IX", "40,XL", "90,XC", "400,CD", "900,CM"})
    void shouldShortenWithSubtractiveNotation(int value, String expected) {
        assertThat(RomanNumeral.from(value), is(expected));
    }
    private String complete() {
        var i = new Numeral("I", 1);
        var v = new Numeral("V", 5);
        var x = new Numeral("X", 10);
        var l = new Numeral("L", 50);
        var c = new Numeral("C", 100);
        var d = new Numeral("D", 500);
        var m = new Numeral("M", 1000);
        var numerals = List.of(
                m,
                m.subtract(c),
                d,
                d.subtract(c),
                c,
                c.subtract(x),
                l,
                l.subtract(x),
                x,
                x.subtract(i),
                v,
                v.subtract(i),
                i);
        numerals.forEach(this::add);
        return current.text();
    }

Now we see another form of duplication in the way the list of numerals is constructed. There is a pattern that repeats itself for every power of 10. We should extract that pattern:

    private String complete() {
        var i = new Numeral("I", 1);
        var v = new Numeral("V", 5);
        var x = new Numeral("X", 10);
        var l = new Numeral("L", 50);
        var c = new Numeral("C", 100);
        var d = new Numeral("D", 500);
        var m = new Numeral("M", 1000);
        var numerals = new TreeSet<>(comparing(Numeral::value).reversed());
        numerals.addAll(includeSubtractives(i, v, x));
        numerals.addAll(includeSubtractives(x, l, c));
        numerals.addAll(includeSubtractives(c, m, d));
        numerals.forEach(this::add);
        return current.text();
    }

    private Collection<Numeral> includeSubtractives(Numeral one,
            Numeral five, Numeral ten) {
        return List.of(
                one,
                five.subtract(one),
                five,
                ten.subtract(one),
                ten);
    }

Note that we have to use a set to remove duplicate numerals and we need to sort that set in the correct order for the algorithm to work.

We’re still not done, though. The way we add the pattern of subtractives isn’t random; there’s a pattern to that too:

    private String complete() {
        var i = new Numeral("I", 1);
        var v = new Numeral("V", 5);
        var x = new Numeral("X", 10);
        var l = new Numeral("L", 50);
        var c = new Numeral("C", 100);
        var d = new Numeral("D", 500);
        var m = new Numeral("M", 1000);
        var baseNumerals = List.of(i, v, x, l, c, d, m);
        var numerals = new TreeSet<>(comparing(Numeral::value).reversed());
        for (var index = 0; index < baseNumerals.size() - 1; index += 2) {
            numerals.addAll(includeSubtractives(
                    baseNumerals.get(index),
                    baseNumerals.get(index + 1),
                    baseNumerals.get(index + 2)));
        }
        numerals.forEach(this::add);
        return current.text();
    }

We can clean that up further by extracting the base numerals into a constant:

    private static final List<Numeral> BASE_NUMERALS = List.of(
            new Numeral("I", 1), 
            new Numeral("V", 5), 
            new Numeral("X", 10), 
            new Numeral("L", 50), 
            new Numeral("C", 100), 
            new Numeral("D", 500), 
            new Numeral("M", 1000));

    private String complete() {
        var numerals = new TreeSet<>(comparing(Numeral::value).reversed());
        for (var index = 0; index < BASE_NUMERALS.size() - 1; index += 2) {
            numerals.addAll(includeSubtractives(
                    BASE_NUMERALS.get(index),
                    BASE_NUMERALS.get(index + 1),
                    BASE_NUMERALS.get(index + 2)));
        }
        numerals.forEach(this::add);
        return current.text();
    }

And extracting the creation of numerals into its own method:

    private String complete() {
        numerals().forEach(this::add);
        return current.text();
    }

    private Collection<Numeral> numerals() {
        var result = new TreeSet<>(comparing(Numeral::value).reversed());
        for (var index = 0; index < BASE_NUMERALS.size() - 1; index += 2) {
            result.addAll(includeSubtractives(
                    BASE_NUMERALS.get(index),
                    BASE_NUMERALS.get(index + 1),
                    BASE_NUMERALS.get(index + 2)));
        }
        return result;
    }

The code now expresses all concepts well and our test list is empty, so we’re done.

Here’s the complete solution:

import java.util.*;

import static java.util.Comparator.comparing;


public class RomanNumeral {

    private static final int MIN_EXPRESSIBLE = 1;
    private static final int MAX_EXPRESSIBLE = 3999;
    private static final List<Numeral> BASE_NUMERALS = List.of(
            new Numeral("I", 1),
            new Numeral("V", 5),
            new Numeral("X", 10),
            new Numeral("L", 50),
            new Numeral("C", 100),
            new Numeral("D", 500),
            new Numeral("M", 1000));

    private final int target;
    private Numeral current = new Numeral("", 0);

    private RomanNumeral(int target) {
        this.target = target;
    }

    public static String from(int value) {
        if (!isExpressible(value)) {
            throw new InexpressibleException();
        }
        return new RomanNumeral(value).complete();
    }

    private static boolean isExpressible(int value) {
        return MIN_EXPRESSIBLE <= value && value <= MAX_EXPRESSIBLE;
    }

    private String complete() {
        numerals().forEach(this::add);
        return current.text();
    }

    private Collection<Numeral> numerals() {
        var result = new TreeSet<>(comparing(Numeral::value).reversed());
        for (var index = 0; index < BASE_NUMERALS.size() - 1; index += 2) {
            result.addAll(includeSubtractives(
                    BASE_NUMERALS.get(index),
                    BASE_NUMERALS.get(index + 1),
                    BASE_NUMERALS.get(index + 2)));
        }
        return result;
    }

    private Collection<Numeral> includeSubtractives(Numeral one,
            Numeral five, Numeral ten) {
        return List.of(
                one,
                five.subtract(one),
                five,
                ten.subtract(one),
                ten);
    }

    private void add(Numeral numeral) {
        while (remainder() >= numeral.value()) {
            current = current.add(numeral);
        }
    }

    private int remainder() {
        return target - current.value();
    }


    public static class InexpressibleException
            extends IllegalArgumentException {
    }


    private record Numeral(String text, int value) {

        Numeral add(Numeral addens) {
            return new Numeral(text + addens.text,
                    value + addens.value);
        }

        public Numeral subtract(Numeral subtrahens) {
            return new Numeral(subtrahens.text + text,
                    value - subtrahens.value);
        }

    }

}

No need to manage technical debt

There are a lot of articles and presentations out there that discuss how to manage technical debt. In my opinion, most of these approaches are workarounds to fix a broken system. As usual, it’s much better to treat the disease than the symptoms.

Most of the discussions around technical debt take for granted that technical debt is unavoidable and will increase over time until it grinds development down to a halt. Unless we figure out a way to manage it.

This rests on two debatable assumptions.

The first assumption is that there has to be a battle of some kind between development and “product” or “the business” where “product” always wins, leading to technical debt. Consider an excerpt from this article:

The product manager describes the next feature they want to be added to the product. Developers give a high estimate for the time it takes to implement, which is seen as too long. The developers talk about having to deal with the implications of making changes to lots of hard to understand code or working around bugs in old libraries or frameworks. Then the developers ask for time to address these problems, and the product manager declines, referring to the big backlog of desired features that need to be implemented first.

The assumption is that a product manager or “the business” decides how software developers spend their time. While this might seem logical, since “the business” pays the developers’ salaries, it’s a very poor setup.

First of all, let’s consider this from a roles and responsibilities angle. Who will get yelled at (hopefully figuratively) when technical debt increases to the point that delays become a problem? If you think the product manager, then think again. If the developers are accountable for maintaining a sustainable pace of delivery, then they should have the responsibility to address technical debt as well. Otherwise we’re just setting developers up to fail.

Secondly, let’s look at this from a skills and knowledge perspective. Technical debt is just a fancy term for poor maintainability. Maintainability is one of several quality dimensions. For example, here’s how ISO 25010 defines quality:

Product managers are great at functionality and (hopefully) usability, but they aren’t qualified to make tradeoffs between all these quality attributes. That’s what we have architects for. (Whether a team employs dedicated architects or has developers do architecture is besides the point for this discussion.)

If we take a more balanced approach to software development instead of always prioritizing new features, then technical debt will not grow uncontrollably.

The assumption that product managers should make all the decisions is wrong. We’ve long ago uncovered better ways of developing software. Let the product manager collaborate with the development team instead of dictating their every move. Then most of this self-inflicted pain that we call technical debt will simply never materialize and doesn’t need to be managed.

The second assumption underlying most of the discussions around technical debt is even more fundamental.

In the text above I mentioned a tradeoff between quality attributes and a collaboration to resolve priorities. But a sizable portion of what people call technical debt isn’t even about that. It’s about cutting corners to save a couple of minutes or hours of development time to make a deadline.

Let’s not go into how many (most?) deadlines are fairly arbitrary. Let’s accept them and look at how to deal with them.

Many developers overestimate the ratio of development time to total time for a feature to become available to end users (lead time). The savings of cutting corners in development really don’t add up to as much as one would think. Re-work negates many of the initial savings.

But the costs down the road are significant, so we shouldn’t be cutting corners as often as we do. Even under time pressure, the only way to go fast is to go well.

Developers have a responsibility to the organization that pays them to deliver software at a sustainable pace. They shouldn’t let anyone “collaborate” them out of that responsibility, much less let anyone dictate that. What would a doctor do when their manager told them just before an emergency operation not to wash their hands to save time? Maybe first do no harm wouldn’t be such a bad principle for software development either.

Technical debt will most likely not go away completely. But we shouldn’t let it get to the point that managing it is a big deal worthy of endless discussions, articles, and presentations.

Celebrate Learning in Software Development

Every event is either a cause for celebration or an opportunity to learn.

celebrateI don’t remember where I came across this quote, but it has stuck with me. I like how it turns every experience into something positive.

Sometimes I need to remind myself of it, however, especially when there are a lot of, well, learning opportunities in a row.

One recent case was when I had started a long running performance test overnight. The next morning when I came back to it, there was no useful information at all. None whatsoever.

What had happened?

scdfOur system is a fast data solution built on Spring Cloud Data Flow (SCDF). SCDF allows you to compose stream processing solutions out of data microservices built with Spring Boot.

The performance test spun up a local cluster, ingested a lot of data, and spun the cluster down, all the while capturing performance metrics.

(This is early stages performance testing, so it doesn’t necessarily need to run on a production-like remote cluster.)

Part of the shutdown procedure was to destroy the SCDF stream. The stream destroy command to the SCDF shell is supposed to terminate the apps that make up the stream. It did in our functional tests.

But somehow it hadn’t this time. After the performance test ran, the supporting services were terminated, but the stream apps kept running. And that was the problem. These apps continued to try to connect to the supporting services, failed to do that, and wrote those failures to the log files. The log files had overflown and the old ones had been removed, in an effort to save disk space.

All that was left, were log files filled with nothing but connection failures. All the useful information was gone. While I was grateful that I still had space on my disk left, it was definitely not a cause for celebration.

So then what could we learn from this event?

Obviously we need to fix the stream shutdown procedure.

kubernetesCome to think of it, we had already learned that lesson. The code to shut down our Kubernetes cluster doesn’t use stream destroy, but simply deletes all the replication controllers and pods that SCDF creates.

We did it that way, because the alternative proved unreliable. And yet we had failed to update the equivalent code for a local cluster. In other words, we had previously missed an opportunity to learn!

Determined not that make that mistake again, we tried to look beyond fixing the local cluster shutdown code.

One option is to not delete old logs, so we wouldn’t have lost the useful information. However, that almost certainly would have led to a full disk and a world of hurt. So maybe, just maybe, we shouldn’t go there.

Another idea is to not log the connection failures that filled up the log files. Silently ignoring problems isn’t exactly a brilliant strategy either, however. If we don’t log problems, we have nothing to monitor and alert on.

release-itA better idea is to reduce the number of connection attempts in the face of repeated failures. Actually, resiliency features like circuit breakers were already in the backlog, since the need for it was firmly drilled into us by the likes of Nygard.

We just hadn’t worked on that story yet, because we didn’t have much experience in this area and needed to do some homework.

So why not spend a little bit of time to do that research now? It’s not like we could work on analyzing the performance test results.

It turns out that this kind of stuff is very easy to accomplish with the FailSafe library:

private final CircuitBreaker circuitBreaker = new CircuitBreaker()
    .withFailureThreshold(3, 10)
    .withSuccessThreshold(3)
    .withDelay(1, TimeUnit.SECONDS);
private final SyncFailsafe&lt;Object&gt; safeService = Failsafe
    .with(circuitBreaker)
    .withFallback(() -> DEFAULT_VALUE);

@PostConstruct
public void init() {
  circuitBreaker.onOpen(() -> LOG.warn("Circuit breaker opened"));
  circuitBreaker.onClose(() -> LOG.warn("Circuit breaker closed"));
}

private Object getValue() {
  return safeService.get(() -> remoteService.getValue());
}

learnI always feel better after learning something new. Taking every opportunity to learn keeps my job interesting and makes it easier to deal with the inevitable problems that come my way.

Instead of being overwhelmed with negativity, the positive experience of improving my skills keeps me motivated to keep going.

What else could we have learned from this incident? What have you learned recently? Please leave a comment below.

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.

 

How to manage dependencies in a Gradle multi-project build

gradleI’ve been a fan of the Gradle build tool from quite early on. Its potential was clear even before the 1.0 version, when changes were regularly breaking. Today, upgrading rarely cause surprises. The tool has become mature and performs well.

Gradle includes a powerful dependency management system that can work with Maven and Ivy repositories as well as local file system dependencies.

During my work with Gradle I’ve come to rely on a pattern for managing dependencies in a multi-project build that I want to share. This pattern consists of two key practices:

  1. Centralize dependency declarations in build.gradle
  2. Centralize dependency version declarations in gradle.properties

Both practices are examples of applying software development best practices like DRY to the code that makes up the Gradle build. Let’s look at them in some more detail.

Centralize dependency declarations

In the root project’s build.gradle file, declare a new configuration for each dependency used in the entire project. In each sub-project that uses the dependency, declare that the compile (or testCompile, etc) configuration extends the configuration for the dependency:

subprojects {
  configurations {
    commonsIo
  }

  dependencies {
    commonsIo 'commons-io:commons-io:2.5'
  }
}
configurations {
  compile.extendsFrom commonsIo
}

By putting all dependency declarations in a single place, we know where to look and we prevent multiple sub-projects from declaring the same dependency with different versions.

Furthermore, the sub-projects are now more declarative, specifying only what logical components they depend on, rather than all the details of how a component is built up from individual jar files. When there is a one-to-one correspondence, as in the commons IO example, that’s not such a big deal, but the difference is pronounced when working with components that are made up of multiple jars, like the Spring framework or Jetty.

Centralize dependency version declarations

The next step is to replace all the version numbers from the root project’s build.gradle file by properties defined in the root project’s gradle.properties:

dependencies {
  commonsIo "commons-io:commons-io:$commonsIoVersion"
}
commonsIoVersion=2.5

This practice allows you to reuse the version numbers for related dependencies. For instance, if you’re using the Spring framework, you may want to declare dependencies on spring-mvc and spring-jdbc with the same version number.

There is an additional advantage of this approach. Upgrading a dependency means updating gradle.properties, while adding a new dependency means updating build.gradle. This makes it easy to gauge from a commit feed what types of changes could have been made and thus to determine whether a closer inspection is warranted.

You can take this a step further and put the configurations and dependencies blocks in a separate file, e.g. dependencies.gradle.

And beyond…

Having all the dependencies declared in a single location is a stepping stone to more advanced supply chain management practices.

The centrally declared configurations give a good overview of all the components that you use in your product, the so-called Bill of Materials (BOM). You can use the above technique, or use the Gradle BOM plugin.

The BOM makes it easier to use a tool like OWASP DependencyCheck to check for publicly disclosed vulnerabilities in the dependencies that you use. At EMC, about 80% of vulnerabilities reported against our products are caused by issues in 3rd party components, so it makes sense to keep a security eye on dependencies.

A solid BOM also makes it easier to review licenses and their compliance requirements. If you can’t afford a tool like BlackDuck Protex, you can write something less advanced yourself with modest effort.

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.

Software Engineering in 2016

engineeringI write computer programs for a living. Many people therefore refer to me as a software engineer, but that term has always made me uncomfortable.

Mary Shaw from the Software Engineering Institute explains where that unease comes from: our industry doesn’t meet the standards for engineers as set by real engineering fields like structural engineering.

Shaw defines engineering as “Creating cost-effective solutions to practical problems by applying codified knowledge, building things in the service of mankind.” (my italics) While we certainly do this some of the time in some places, I believe we are still quite a ways away from doing it all of the time everywhere.

Examples abound. Code is still being written without automated tests, without peer review, and without continuously integrating it with code of fellow team members. Basic stuff, really.

The State of DevOps 2015 report goes into some more advanced practices. It presents compelling evidence that these practices lead to better business results. High-performing companies in the study deploy code 30x more often and have a 60x higher success rate and 168x lower Mean Time To Recovery (MTTR) than low-performing companies.

Yes, you’ve read that right: lower risk of failure and quicker recovery when things do go wrong!

So why aren’t we all applying this codified knowledge?

DevOps practices, as well as more advanced Agile practices like test-driven development and pair programming, require more discipline and that seems to be lacking in our field. Uncle Bob explains this lack of discipline by pointing to the population demographics in our field.

go-fast-go-wellThere still seems to be a strong belief that “quick and dirty” really is quicker. But in the long term, it almost always ends up just being dirty, and many times actually slower.

Yes, going into a production database and manually updating rows to compensate for a bug in the code can be a quick fix, but it also increases the risk of unanticipated things going wrong. Do it often enough, and something will go wrong, requiring fixes for the fixes, etc.

Following a defined process may seem slower than a quick hack, but it also reduces risk. If you can make the defined process itself quicker, then at some point there is little to gain from deviating from the process.

The high-performing DevOps companies from the aforementioned study prove that this is not a pipe dream. With a good Continuous Delivery process you can make fixing urgent critical bugs a non-event. This is good, because people make poorer decisions under stress.

This finding shouldn’t be news to us. It’s the same lesson that we learned with Continuous Integration. Following a process and doing it more often leads to an optimization of the process and an overall increase in productivity.

Until the majority in our field have learned to apply this and other parts of our codified knowledge, we should probably stop calling ourselves engineers.