Learning your tools

This time I’d like to talk about tools, the tools and frameworks we use every day.

I often relate to the Gardening metaphor when talking about software. A gardener knows his tools, he knows when to use a certain type of trowel not to damage the plant, he knows when using a bigger type of spade so that his work will be more efficent. Furthermore a professional gardener knows how to take advantage of a given technique, one that may not be relevant in theory, but in a specific context may be useful.

We are professional software engineers, we need to use the right tools, we even need to look into other tools in the market and then use a similar one that we have in our storage.

We tend to make one mistake though: we get trapped into our own habits.

Habits are good, habits are the realization that we have come to learn something that deeply that we don’t even think on doing that. The trap here is that we may follow certain habits when they are not applicable or even when there is a better pattern to apply in that context.

One Example is worth a Thousand words

Test cases in your testing framework:

Recently I was doing the FizzBuzz coding kata. In this kata we need to print a sequence of numbers but transforming some of them into “Fizz”, “Buzz” or “FizzBuzz”, given certain rules.

My tests were as follows:

public class FizzBuzzTest
{
  [Fact]
  public void FizzBuzz_for_two_elements_outputs_two_numbers()
  {
     var fizzBuzz = new FizzBuzz.FizzBuzz();

     string fizzBuzzSequence = fizzBuzz.Get(2);

     Assert.Equal("1 2", fizzBuzzSequence);
  }

  [Fact]
  public void FizzBuzz_for_three_elements_includes_fizz()
  {
     var fizzBuzz = new FizzBuzz.FizzBuzz();

     string fizzBuzzSequence = fizzBuzz.Get(3);

     Assert.True(fizzBuzzSequence.Contains("Fizz"));
  }
}

I wanted to be explicit so that people could read my tests as documentation. While that is correct, imagine following this pattern in a larger and more complex solution. Tests become overcomplex, we need to maintain more lines of code.

In this scenario I have a single function that transforms the data: I send an input sequence and I get back an output sequence. It seems the perfect match to use TestCases.

I’m using XUnit test framework so that I did some research and found about InlineData, then I changed my tests like this:

[Theory]
[InlineData("1", 1)]
[InlineData("1 2", 2)]
[InlineData("1 2 Fizz", 3)]
[InlineData("1 2 Fizz 4", 4)]
[InlineData("1 2 Fizz 4 Buzz", 5)]
[InlineData("1 2 Fizz 4 Buzz Fizz", 6)]
public void FizzBuzz_sequence_for_given_number_of_elements(string expectedFizzBuzz, int numberOfElements)
{
    var fizzBuzz = new FizzBuzz.FizzBuzz();

    string fizzBuzzSequence = fizzBuzz.Get(numberOfElements);

    Assert.Equal(expectedFizzBuzz, fizzBuzzSequence);
}

Tests have become more concise and simple, yet they are explicit.

Creating tools, test cases in Mocha.

A trully proficient gardener may find that in a given context, none of the tools do a good job. What they do in that case is that they apply patterns that they know from other contexts, even creating new tools, to solve the new problem.

We, as proffesional software engineers, should learn more than one language. Even if you are a Ruby developer, by learning different languages, different paradigms, you will see other ways, you will find different solutions to similar problems. I ensure, you will come back to your regular environment to find out that you have become a more efficient profesional developer.

Imagine our friend the gardener using always the same shovel, no matter what the context is… Probably he won’t be hired that often.

A few days after doing the kata, we are doing some work in Javascript. Again in our scenario, test cases are the right approach.

We use Mocha as our testing framework so we did some research and found out that Mocha doesn’t support Test cases. It didn’t matter, we knew the language and we knew the concepts, so let’s try to implement test cases.

Here is a test implementation of the tests above for FizzBuzz in Javascript using test cases:

import FizzBuzz from '../fizz-buzz';

describe('For given number of elements', () => {
  const testCases = [
    {'1', 1}, 
    {'1 2', 2}, 
    {'1 Fizz', 3},
    {'1 Fizz 4', 4},
    {'1 Fizz 4 Buzz', 5},
    {'1 Fizz 4 Buzz Fizz', 6}
  ];
  
  testCases.forEach((testCase) => {
    const { expectedFizzBuzz, numberOfElements } = testCase;
    
    it('generates FizzBuzz sequence', () => {
      let fizzBuzzSequence = FizzBuzz.get(numberOfElements);
      
      fizzBuzzSequence.should.equal(expectedFizzBuzz);
    });
  });
});

Even though Mocha doesn’t have an in-build functionality for TestCases, we have learnt our tools well, in this case Javascript ES2015.

Learn your tools well to reduce work. Thanks for reading!