Staying Green.

So, I’ve been busily working away on my Java TTT without much trouble, just slowly adding test driven features when I’ve started to notice a couple of things: One, my board class seems to be getting a bit too big. Coming from my Ruby TTT, I am somewhat distracted by the size of the methods that I’m producing in Java, so my first thought is:

“Is the Board class getting too big, or is it just that Java is more verbose than I’m used to”.

On further self inspection, I think the sensation/gut feeling I’m getting is one of, “I’m not sure what methods are in the board class, I’m losing track of its capabilities”. This sounds like a sign of a class that needs to be broken down, but I’m not immediately sure I know where it should be split. By way of an interim solution, the thought of making some of the methods simpler and shorter (more Ruby-ish) seems like a good idea.

Decision time then, whats the best way to quickly (oh, hindsight!) improve the methods in my Board class…change the underlying data structure. Yes, that’s definitely it, great idea.

Step 1

git commit

Step 2

Change this.cells = new char[9][]... to this.cells = Arrays.asList(...).

Step 3

Run test suite. Panic a little bit. Plow on changing methods until all your tests are green.

Step 4

Regret decision.

Step 5

git reset HEAD~1

Step 6

Stay Green!

Change the constructor assignment as before. However, this time use your showCells() method to encapsulate the change and keep the test suite green.

Step 7

Continue to change all the methods in your class to utilise the new data structure but also modify them to convert their returning value back into the old data structure where necessary. So for the entire refactoring process, the test suite stays green.

Step 8

Flick the switch. This point is where it will get a little hairy, and I’m not quite at this step yet. However, it is very clear that most of the leg work is now done, so it will be much simpler than the alternative and because the changes have been small and incremental, we haven’t broken the software in doing so.

Examples

constructor

public Board() {
  this.cells = new char[]{'1', '2', '3', '4', '5', '6', '7', '8',
    '9'};
  this.size = cells.length;
}
public Board() {
  this.cells = Arrays.asList('1', '2', '3', '4', '5', '6', '7', '8',
      '9');
  this.size = cells.size();
}

showCells()

public char[] showCells() {
  return cells;
}
public char[] showCells() {
  char[] results = new char[9];
  for(int i=0;i<9;i++) {
    char cell = this.cells.get(i);
    results[i] = cell;
  }
  return results;
}

rows()

public char[][] rows() {
  char[] row1 = Arrays.copyOfRange(cells, 0, 3);
  char[] row2 = Arrays.copyOfRange(cells, 3, 6);
  char[] row3 = Arrays.copyOfRange(cells, 6, 9);
  return new char[][]{row1, row2, row3};
}
public char[][] rows() {
  char[] row1char = new char[3];
  char[] row2char = new char[3];
  char[] row3char = new char[3];
  List<Character> row1 = cells.subList(0, 3);
  List<Character> row2 = cells.subList(3, 6);
  List<Character> row3 = cells.subList(6, 9);
  for (int i=0;i<3;i++) {
    char cell1 = row1.get(i);
    char cell2 = row2.get(i);
    char cell3 = row3.get(i);
    row1char[i] = cell1;
    row2char[i] = cell2;
    row3char[i] = cell3;
  }
  return new char[][]{row1char, row2char, row3char};
}

These changes were made in order to try and simplify the board class, and whilst they have achieved that, it still feels a bit unwieldy. So there is further work to be done.