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.

Advertisement

Managers and Individual Contributors in Code

manager-individualContributorI’m lucky to work for a company that makes it possible to have a good technical career, so that I don’t have to become a manager just to get more money.

I like being an individual contributor because it gives me a sense of accomplishment when I get stuff done myself.

Anyway, I believe the distinction between manager and individual contributor is useful when writing code as well.

Let me show that using the example of Conway’s Game of Life.

Baby Steps

At code retreats, you’ll find people who start working on the problem from the bottom (cell) and those who start at the top (universe, world, grid, game, or whatever they call it).

Interestingly, both groups tend to run into a similar problem.

baby-stepsStarting at the bottom makes it easy to quickly implement the rules in a cell. But then the problem becomes how to connect the cells into a universe.

This often looks like too big of a step to properly test, e.g. with a new green test every two minutes.

Starting at the top makes sure we are not doing anything unnecessary or building any parts that would not connect properly. But here too it’s difficult to keep chipping away in baby steps.

The Single Responsibility Principle

To evolve a whole universe, at least these things need to happen:

  1. Iterate over all cells
  2. Determine each cell’s neighbors
  3. Count the number of alive neighbors
  4. Determine the cell’s next state based on its current state and the number of alive neighbors

Depending on some implementation choices (like keeping the universe immutable), there may be more work.

Yet the Single Responsibility Principle tells us that a class should have only one reason to change. You may count items #2 and #3 as one responsibility (or #3 and #4), but clearly there is more than one involved.

Manager Classes and Individual Contributor Classes and How to Test Them

Now remember the manager/individual contributor (IC) distinction. Managers manage ICs; that’s their whole job. We should count managing other classes as a responsibility too.

That would mean that a class either implements some logic (IC), or coordinates with other classes (manager), but not both.

mockI think this also ties into the state-based versus interaction-based testing debate: we should use state-based testing for IC classes and interaction-based testing (using mocks) for manager classes.

That would explain why both code retreat groups seem to get stuck: they have to switch from state-based to interaction-based testing and it seems that many developers don’t have a lot of experience with the latter.

Test-Driving Manager Classes

So let’s try interaction-based testing of a manager class. I’ll keep with the example of the Game of Life.

I’d like to begin with an architectural choice: I want the universe to be immutable, so that it would be easy to introduce multi-threading later. As the game evolves, I’ll have to create a new universe for every generation:

public class GameTest {
  @Test
  public void clonesImmutableUniverseWhenEvolving() {
    Universe universe = mock(Universe.class, "old");
    Universe nextGeneration = mock(Universe.class, "new");
    when(universe.clone()).thenReturn(nextGeneration);

    Game game = new Game(universe);
    assertSame("Initial", universe, game.universe());

    game.evolve();
    assertSame("Next generation", nextGeneration, 
      game.universe());
  }
}

I’m using Mockito to define how the Game interacts with the Universe. Mocking works best with interfaces, so Universe is an interface.

That means the game doesn’t know the type of universe and therefore can’t create a new instance of it. The universe provides a factory method clone() for this purpose.

If the universe is to be immutable, then its state should be provided in its constructor. This constructor is called by clone(), so that method needs the new state as its input.

What does that state look like? At this point we don’t know anything about the universe other than that it contains cells. Let’s keep it simple and provide the cells as input:

public class GameTest {
  @SuppressWarnings("unchecked")
  @Test
  public void clonesImmutableUniverseWhenEvolving() {
    Universe universe = mock(Universe.class, "old");
    Universe nextGeneration = mock(Universe.class, "new");
    when(universe.clone(any(Iterable.class)))
        .thenReturn(nextGeneration);

    Game game = new Game(universe);
    assertSame("Initial", universe, game.universe());

    game.evolve();
    assertSame("Next generation", nextGeneration, 
        game.universe());
  }
}

OK, so who is going to supply those cells to clone()? The game is a manager, so it should only manage, not provide logic. The universe is an IC that is responsible for the cells and their interconnections, so it already has a responsibility.

So it seems like we need a new type. The new type should be managed by the game, since that’s the only manager class we have. Thus we should add a new test in GameTest for this interaction.

The new type should be responsible for determining the new state of the universe from the old one. This is where the game’s rules come into play, so let’s call the new type Rules.

Let’s start with testing that the game manages the rules:

public class GameTest {
  @Test
  public void consultsRulesWhenEvolving() {
    Rules rules = mock(Rules.class);

    Game game = new Game(null, rules);
    assertSame("Rules", rules, game.rules());
  }
}

Now we want to test that evolve() consults the rules. Since the game is a manager, it can only request output from a collaborator and provide that as input to another collaborator. It shouldn’t contain any logic itself, since that would make it an IC.

The only other collaborator that the game currently has is the universe and that seems the correct candidate to provide the cells. But we need more than the cells to implement the rules: we also need to number of alive neighbors of each cell.

The universe is clearly the correct place to determine a cell’s neighbors. Should it also count the number of alive ones?

I guess it could, but I don’t particularly like that: the rules for Life use the number of alive neighbors, but it’s not hard to imagine a different set of rules that also depend on the number of dead neighbors. So I feel that the rules should do the counting.

This means that the input to the rules is a cell and its neighbors. Since Java doesn’t allow returning two pieces of information, we need to combine them. Let’s call the combination a neighborhood:

public class NeighborhoodTest {
  @Test
  public void holdsACellAndItsNeighbors() {
    Cell cell = mock(Cell.class, "cell");
    List<Cell> neighbors = Arrays.asList(
        mock(Cell.class, "neighbor1"), 
        mock(Cell.class, "neighbor2"));

    Neighborhood neighborhood = new Neighborhood(cell, 
        neighbors);

    assertSame("Cell", cell, neighborhood.cell());
    assertEquals("Neighbors", neighbors, 
        neighborhood.neighbors());
  }
}

Now we can make the universe return a neighborhood for each of the cells it contains and verify that those neighborhoods are used as input for the rules:

public class GameTest {
  @SuppressWarnings("unchecked")
  @Test
  public void clonesImmutableUniverseWhenEvolving() {
    Universe universe = mock(Universe.class, "old");
    Universe nextGeneration = mock(Universe.class, "new");
    when(universe.clone(any(Iterable.class)))
        .thenReturn(nextGeneration);
    when(universe.neighborhoods()).thenReturn(
        new ArrayList<Neighborhood>());

    Game game = new Game(universe, mock(Rules.class));
    assertSame("Initial", universe, game.universe());

    game.evolve();
    assertSame("Next generation", nextGeneration, 
        game.universe());
  }

  @Test
  public void consultsRulesWhenEvolving() {
    Universe universe = mock(Universe.class);
    Neighborhood neighborhood1 = new Neighborhood(
        mock(Cell.class), 
        Arrays.asList(mock(Cell.class)));
    Neighborhood neighborhood2 = new Neighborhood(
        mock(Cell.class), 
        Arrays.asList(mock(Cell.class)));
    when(universe.neighborhoods()).thenReturn(
        Arrays.asList(neighborhood1, neighborhood2));
    Rules rules = mock(Rules.class);

    Game game = new Game(universe, rules);
    assertSame("Rules", rules, game.rules());

    game.evolve();
    verify(rules).nextGeneration(neighborhood1);
    verify(rules).nextGeneration(neighborhood2);
  }
}

The next step is to make sure that the output from the rules is used to construct the new universe:

public class GameTest {
  @Test
  public void consultsRulesWhenEvolving() {
    Universe universe = mock(Universe.class);
    Neighborhood neighborhood1 = new Neighborhood(
        mock(Cell.class), 
        Arrays.asList(mock(Cell.class)));
    Neighborhood neighborhood2 = new Neighborhood(
        mock(Cell.class), 
        Arrays.asList(mock(Cell.class)));
    when(universe.neighborhoods()).thenReturn(
        Arrays.asList(neighborhood1, neighborhood2));
    Rules rules = mock(Rules.class);
    Cell cell1 = mock(Cell.class, "cell1");
    Cell cell2 = mock(Cell.class, "cell2");
    when(rules.nextGeneration(neighborhood1))
        .thenReturn(cell1);
    when(rules.nextGeneration(neighborhood2))
        .thenReturn(cell2);

    Game game = new Game(universe, rules);
    assertSame("Rules", rules, game.rules());

    game.evolve();
    verify(universe).clone(eq(
        Arrays.asList(cell1, cell2)));
  }
}

At this point we’re done with the Game class. All that is left to do, is create implementations for the three interfaces we introduced: Universe, Cell, and Rules. Each of these is an IC class, and thus fairly straightforward to test-drive using state-based testing.

Conclusion

I find that the distinction between manager and individual contributor classes helps me in deciding what the next test should be.

What do you think? Could this be part of the missing piece for a proper theory of Test-Driven Development?

Conway’s Game of Life and the Flyweight Pattern

flyweightConway’s Game of Life is fascinating, both from a functional and from a technical perspective.

This may explain why it’s often used for code retreats. Code retreats are a fun way to learn.

It’s amazing how working with new pairs gives you new insights virtually every time.

At the last code retreat that I attended, one of my pairs suggested we use the Flyweight pattern for cells:

A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context — it’s indistinguishable from an instance of the objects that is not shared.

When the Design Patterns book (which contains the above quote) came out, I remember having many aha moments. It was so cool to see all these patterns that I had used before and finally have a name for them so I could discuss them with my peers more efficiently!

I did not have an aha moment when reading about flyweight, however. The example in the book, sharing character objects in a text editor, seemed a bit far fetched at the time. This example is not unlike the cells in a Game of Life grid, however, so I happily went along with my pair’s idea to explore the pattern’s applicability in this context.

After the code retreat was over, I gave this pattern some more thought. (This is usually where the code retreat really starts paying off.)

We actually use a potential flyweight all the time: booleans. A boolean is a class with only two instances, and those instances could easily be shared. In Java they are not: new Boolean(true) != new Boolean(true). However, the Boolean class does provide two constants, TRUE and FALSE, for the instances that you could use for sharing.

That got me thinking about using Enums for flyweights. Most of the time, I use enums for grouping related but mutually exclusive constants, like days of the week. However, Enums in Java can define methods:

  public enum Cell {

    ALIVE(true), DEAD(false);

    private final boolean alive;

    private Cell(boolean alive) {
      this.alive = alive;
    }

    public boolean isAlive() {
      return alive;
    }

    public Cell evolve(int numLiveNeighbors) {
      boolean aliveInNextGeneration = alive
          ? 2 <= numLiveNeighbors && numLiveNeighbors <= 3
          : numLiveNeighbors == 3;
      return aliveInNextGeneration ? ALIVE : DEAD;
    }

  }

One of the fun parts of code retreats is that in some sessions, you will have constraints on the way you work. Such constraints force you to be more creative and think beyond the techniques you would normally use.

One constraint that is interesting in this context is to not use any conditionals, like if or switch statements or ternary operators. The idea behind this constraint is to force you to replace conditionals with polymorphism, making your program more object oriented.

The only way that I see to keep the current Cell enum and not use conditionals, is to introduce a map:

  public enum Cell {

    ALIVE(true), DEAD(false);

    private final boolean alive;
    private static final Map<Boolean, Map<Integer, Cell>> 
        NEXT = new HashMap<>();

    static {
      Map<Integer, Cell> dead = new HashMap<>();
      dead.put(0, DEAD);
      dead.put(1, DEAD);
      dead.put(2, DEAD);
      dead.put(3, ALIVE);
      dead.put(4, DEAD);
      dead.put(5, DEAD);
      dead.put(6, DEAD);
      dead.put(7, DEAD);
      dead.put(8, DEAD);
      dead.put(9, DEAD);
      NEXT.put(false, dead);
      Map<Integer, Cell> alive = new HashMap<>();
      alive.put(0, DEAD);
      alive.put(1, DEAD);
      alive.put(2, ALIVE);
      alive.put(3, ALIVE);
      alive.put(4, DEAD);
      alive.put(5, DEAD);
      alive.put(6, DEAD);
      alive.put(7, DEAD);
      alive.put(8, DEAD);
      alive.put(9, DEAD);
      NEXT.put(true, alive);
    }

    private Cell(boolean alive) {
      this.alive = alive;
    }

    public boolean isAlive() {
      return alive;
    }

    public Cell evolve(int numLiveNeighbors) {
      return NEXT.get(alive).get(numLiveNeighbors);
    }

  }

This approach works, but is not very elegant and it breaks down when the number of possibilities grows. Clearly, we need a better alternative.

The only way we can get rid of the conditional, is by getting rid of the boolean state of the cell. That means we need to have different classes for the two instances, so that the type implicitly embodies the state. That in turn means we need a factory to hide those classes from the client:

  public interface Cell {

    boolean isAlive();
    Cell evolve(int numLiveNeighbors);

  }

  public class CellFactory {

    private static final Map<Boolean, Cell> CELLS 
        = new HashMap<>();

    static {
      CELLS.put(false, new DeadCell());
      CELLS.put(true, new AliveCell());
    }

    public static Cell dead() {
      return cell(false);
    }

    public static Cell alive() {
      return cell(true);
    }

    static Cell cell(boolean alive) {
      return CELLS.get(alive);
    }

  }

  class DeadCell implements Cell {

    @Override
    public boolean isAlive() {
      return false;
    }

    @Override
    public Cell evolve(int numLiveNeighbors) {
      return CellFactory.cell(numLiveNeighbors == 3);
    }

  }

  class AliveCell implements Cell {

    @Override
    public boolean isAlive() {
      return true;
    }

    @Override
    public Cell evolve(int numLiveNeighbors) {
      return CellFactory.cell(numLiveNeighbors == 2 
          || numLiveNeighbors == 3);
    }

  }

Indeed, when you look up the Flyweight pattern, you’ll see that the proposed structure contains a flyweight factory that creates instances of concrete flyweight classes that implement a common flyweight interface.

Thanks to the code retreat and my partner, I now know why.

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).