DaedTech

Stories about Software

By

Chess TDD 22: Friendly Pieces

This episode saw me make the first distinction between friendly and enemy pieces in determining available moves.  It had also been a while since I’d worked on the series, so I was a little uncomfortable with how well I was reasoning at compile time about what was happening.  The Board class and some of my implementations are getting a little awkward and I’d like to spiffy them up.  However, I think that I’m going to start focusing on writing acceptance tests right now to bolster the correctness of what’s going on.  This will allow me to separate fixing any flaws in my reasoning from making the code more readable, which really are two separate things.

Here’s what I accomplish in this clip:

  • Stopped knight from being able to land on friendly pieces
  • Implemented the concept of capture
  • Stopped allowing jump of any pieces for the purpose of capture

Here are some lessons to take away:

  • Sometimes you think it’s going to be a lot harder than it is to get everything green.  I was expecting a lot of red when I added the restriction that the move target couldn’t contain a piece, but none happened.  Better to know quickly via experiment than spend a lot of time squinting at your code.  It’s important to reason out why you were mistaken, but getting verification first and working backward will generally save time.
  • You can get a little too clever with what you’re doing.  I was trying to get to green by adding sort of a silly hard-coding, and it came back to bite me.  Such is the nuance of “do the simplest thing to go green.”  No matter how many times you do this, there will always be times you fumble or do dumb things.
  • I got a bit sidetracked trying to figure out how to push that base class constructor into the children, but came up empty.  I’m not going to lie — if I weren’t recording for an audience, I would probably have scoured the internet for a way to do that.  If you’re not in a time crunch or you’re willing to do that on your own dime, these can be great learning exercises.
  • As I work with these Linq expressions, you’ll note that I’m not especially concerned about whether I’m iterating over a collection too many times or performance in general.  Not that it’s directly applicable, per se, but I’ve always loved this post from Jeff Atwood.  There are only two things that make me care about performance in the slightest: unhappy customers and unhappy me with bogged down unit tests.  Until one of those things starts happening, I consider performance orders of magnitude less important than readability and just about any other concern you can think of.  I can easily make readable code faster, if necessary.  It’s really hard to make a pile of unreadable crap written “for performance purposes” into something that makes sense.
  • We’re getting fairly close to a full implementation of non-specialty moves (en passant, last row replacement, castling), so perhaps its time to take a real chess game and model the actual, possible moves to create an acceptance test suite.  Stay tuned.

By

ChessTDD 20: Refactoring in Earnest

In this post, I set out to do some real refactoring of the Board class.  It bothered me enough to take a crack at it and, since this is a fun side project, there really aren’t any constraints.  Were I committed to delivering some business value here, I might need to take a look at my priorities and evaluate whether making things clearer here is worth the delay.  But, luckily in this case, I don’t need to make that call.  And, refactorings are always fun.

Here is what I accomplished in this clip:

  • Refactored a couple of methods out of Board and onto BoardCoordinate.
  • Refactored path checking logic into a PathChecker class.

Here are lessons to take away:

  • If you have functionality that’s purely static in some class (as in, not referring to instance variables in that class), think about where else it might go.  If that static method is principally interested in operating on properties or with methods of another type, you might have the “feature envy” code smell.  This was the case with my static methods that evaluated whether two BoardCoordinates were on the same horizontal or vertical path.  They compared properties on two different BoardCoordinates — so why not make this a member of BoardCoordinate?
  • This isn’t really something I’ve been emphasizing here, but early on I decided to do a quick local commit with Git.  Commit early and often.  I’ve never regretted too many commits unless I was using a terrible source control tool.
  • Defining  a class in the same space as another class is a tool that can help me with extract class refactorings.  This is one of the more volatile refactorings that you can do, so make sure you don’t try to do too much at one and that you get green regularly as you go.  Recreate the functionality faithfully first and then think about how to refactor.
  • If you can factor a method toward not referring to any instance state, then you’re well on the way to letting it be moved to a different class.  This is a good intermediate step to reason about — see how much instance state you can abstract out.
  • When you extract a class as part of a refactoring, it’s fine to leave the tests that cover both classes in place.  In fact, it’s a natural set of tests to leave.  Add tests for the newly created class only to address new complexities that arise from the newly exposed functionality needing to tighten up guard conditions and such.

By

Chess TDD 19: DoesPieceExistAt and Housekeeping

Another night in the hotel, another episode of ChessTDD.  I’m doing my day to day work mainly in Java-land these days, so this is about the only time I write .NET code anymore.  Anywho, in this episode, I’m just planning to pick some housekeeping cards and move them across, starting with one I created after receiving an astute observation from Jeff in the comments from last episode.

Here’s what I accomplished in this clip:

  • Fixed a subtle bit of weirdness that may have caused future problems.
  • Cleaned up the screwy logic around default board size.
  • Factored the test classes more toward the new naming paradigm.
  • Implemented a DoesPieceExistAt() method to get away from GetPiece() == null

Here are lessons to take away:

  • This is kind of a combined lesson from last time to this time.  The comment I received and my resulting attention to the issue he pointed out is an excellent example of why pair programming (or at least code review) is full of win.  I may or may not have caught that logic error before shipping this thing to (an imaginary) QA or production, but with that review, it’s at the fore and I can do something about it.
  • “Boy Scouting” isn’t just about improving production code.  It applies to anything, including your tests.  Wholesale, quixotic refactoring efforts are not necessary if you’re constantly improving the code a little bit in the areas that you’re touching anyway.  In other words, you needn’t always go out of your way to refactor — it’s often advisable to wait to touch production code until you’ll be in there anyway.
  • I like to default to immutability whenever possible.  In the case of board size, why make that a settable property?  How often does it come up that you want to change the size of a chessboard that already exists with scissors or tape and cardboard?  (Modeling the physical world just makes for a funny mnemonic — faithfully modeling it isn’t actually that important.)  Seriously, what advantage is there to that being mutable. In my book, none.  You want a different board size, make a new board.  Not having board size be mutable makes your life much easier — no reasoning about what happens if you shrink the board when pieces are on it and other things like that.
  • Class level preconditions passed into a constructor are important to guard against.  Don’t let your consumers pass you things that would render you in a nonsensical state, such as accepting negative 1 as a board size.  When this happens, fail quickly, loudly, and visibly with an exception, and make it clear why and how in your tests.

By

ChessTDD 18: RemovePiece and Housekeeping

In this episode, I managed to pry myself away at a slightly shorter length of recording time.  You can seem me at the end wavering and and wanting to continue, but I know myself, and I’d have been hustling to wrap up under 25 minutes next thing I knew, so I thought I’d call it at a reasonable stopping point.

Here’s what I accomplished in this clip:

  • Implemented RemovePiece.
  • Made the public interface of Board a little nicer.
  • Minimized the usage of the array in favor of readable abstractions.

Here are lessons to take away:

  • Make yourself feel the pain of duplication.  Around 3:15 I fought off the temptation to copy and paste the setup of another test class to the new one, but I retyped it instead.  Copy and paste is like taking morphine and then walking on lava — you’re easing your pain when you should be letting it inform your actions to improve the situation.
  • Having identical setup in multiple classes is a test smell that’s making subtle suggestions.  Maybe the tests should be in a single class or, perhaps, there should be something in production code making that setup easy, if it’s really that common.  (I view the alternative, a lot of helper code in tests, not to be a better option).
  • At around 7:20, I did something subtle.  I looked for references to Board’s _pieces array and looked to eliminate as many references to it as possible.  The idea here is to minimize the use of a primitive abstractions in favor of the more descriptive ones I’ve created (GetPiece, RemovePiece, MovePiece).
  • More compact isn’t always better.  If you inline a variable, check for readability.  The beauty of a robust test suite is that you can really whip things around to maximize readability and feel good that you’re not breaking anything.

By

Chess TDD 17: Implementing Piece Movement

In this episode, I switched gears a bit to focus on the comparably easy task of moving pieces. I’d had enough of wanting to move pieces for setup, so it was time to take care of that.  I also might (will at some point) revisit the test classes and perhaps consolidate to always starting with the normal board and adding/removing as needed for setup.

Here’s what I accomplished in this clip:

  • Renamed that method from last time.
  • Added basic implementation of move.
  • Added a bit of parameter checking for move.

Here are lessons to take away:

  • Simplicity isn’t just for “do the simplest thing to make it pass.”  It applies on the test side as well.  I started to implement MovePiece() by moving a piece two squares away, but moving it one square away is sort of a simpler case, so it’s probably better to do that first.  The same kind of logic doing, say, prime factors.  Start with 2 — don’t start with 2497.
  • When deciding what test to write next, imagine how you might break up the work that needs to be done in terms of decomposition.  When I was writing MovePiece(), I thought, “move piece means delete a piece from origin and add a piece to destination, so I’ll write a test that accounts for one of those things only: piece exists at destination.”  MovePiece() may seem simple, but it’s decomposable, so let that guide your testing effort.
  • If you think of a refactoring for the test method while you’re writing it, just keep writing the test.  Go red then make it green, then do whatever you’re thinking in the refactor phase.  Having a half-written test is no time to start refactoring.
  • TDD makes you the first consumer of your API.  View your API through someone else’s eyes and use that to make your code better.  I discovered that I could accomplish RemovePiece(Coordinate) by calling the existing method AddPiece(null, coordinate).  But that’s weird and awkward from a semantics perspective.  What strikes you as awkward as you’re coding will strike your consumers as confusing, maddening, or horrifying.  Don’t put them through this.