DaedTech

Stories about Software

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.

By

Chess TDD 16: Finishing Bishop Blocking

Once again I’m bringing you this code-cast from a Marriott, albeit a different one. In spite of a bizarre amount of noise over the course of the evening for a business hotel, I’ve managed to get at least passingly decent audio for this (and for some ongoing Pluralsight work as well). This is a pretty workmanlike episode where I dive into the refactoring I didn’t have time for last weekend and then use the resultant code to make my life easier as I finish the bishop implementation.

Also, as a quick aside, someone asked me a little while back for some advice about how I approach integration/system testing, and I was thinking I might just plow through this series to demonstrate where and how I’ll start bringing in broader tests. So, stay tuned for that, probably whenever the blocking implementation is finished.

Here’s what I accomplished in this clip:

  • Refactored a seriously bad piece of code for diagonal blocking.
  • Fleshed out the diagnoal blocking to handle all cases.
  • Satisfied myself that diagonal blocking is reasonably robust.

Here are lessons to take away:

  • If you’re not sure what to name a method that you’re pulling out, don’t interrupt your flow by obsessing over what to call it.  Naming is extremely important and you definitely want to come back to it, so just call it something like “Dunno()” and focus on the refactoring for the time being.  That silly, glaring name will prevent you from forgetting to come back and think through the name when you understand better what you want to do.
  • Oops.  Didn’t pay close enough attention to my little NCrunch notifier going red during a refactoring.  When that happens, don’t say, “uh oh” and go trying to fix the problem.  Start hitting undo until you’re green again.
  • Whenever something you want to do to the code strikes you, hurry over to Trello (or Excel or whatever) and add it.  TDD makes it easy to pick up where you left off, but you’ll often forget about stuff you want to do if you wait to note it.
  • If you’re not totally comfortable with your implementation, it’s perfectly fine to write a test that you expect (okay, maybe hope) will go green and then move on, more confident, when it does.  TDD discipline says that to change the behavior of production code you need a red test.  It doesn’t say that you always have to write tests expecting them to go red.  Anything that tells you more about the system or increases your confidence in it is a benefit.

By

Chess TDD 15

Prompted by comments from a few people, I’ve decided to see if I like using Trello for keeping track of the TODOs instead of Excel. Also, learning from past feedback, I’ve defaulted Trello to being really big when recording so everything is legible, and I copied everything over from Excel. Hopefully I like it as I go, but please let me know if it’s more pleasing to view as compared with the Excel spreadsheet, if it matters to you one way or the other.

Also, a meta-note. I apologize for the time between posts in the series and for the lack of posting in general, but I’ve been traveling nonstop and am pretty much living out of hotels, meaning my life is one of 3G-ish wifi and sub-optimal setups. Luckily, I’m driving everywhere and lugging my boom mic, desktop and monitors with me so I can still record in the hotel. 🙂

Here’s what I accomplish in this clip:

  • Make the “blocked” algorithm for horizontal/vertical less dumb.
  • Start the implementation for “blocked” diagonal.
  • Inadvertently create a potential solution for the problem of knight’s oddball movement.

Here are lessons to take away:

  • Even little things matter when it comes to readability.  For instance, at 0:40 I noticed that my test class name ended in should but the methods started with “returns.”  So, I took the time to fix this.  My advice is to get in the habit of avoiding sloppiness and inattention to detail at any level of code.
  • Bear in mind that changing prod code is fine while green in TDD, provided you’re not looking to introduce new behaviors.  It’s a refactoring if your goal is continue satisfying existing test cases in a different way.
  • A little before 10:00, I refactored a bit of a test while red for the sake of readability.  I shouldn’t have.  My bad.  Lesson is, no matter how much TDD you do, sometimes you flub it.
  • Sometimes a great way to get things passing when the implementation is getting hairy is to tease out a conditional that only applies to your new case and do something obtuse.  Use with discretion because it can lead you into blind alleys and cause problems, but there are times when getting to green can provide an aha! moment.
  • You’ll notice I refactored to a different method signature, changed some stuff around, and then refactored back.  This kind of waffling is fine.  With TDD, you’ll get used to fearlessly refactoring and slinging stuff around until you settle on something you like (or at least thing is the least bad, for now).
  • Get it working ugly now, make it pretty later.  It’s sometimes amazing how an algorithm will suddenly make itself obvious after a bit of brute forcing and futzing around.

By

Chess TDD 14: Figuring Out Blocking Pieces

In this installment, I’m looking to start defining the concept of “blocking” on a chess board. So far, I’ve been defining piece moves in a vacuum — put a rook down in (1, 1) and the rook can go anywhere in column 1 or row 1. But, what about when there’s a pawn at (1, 2)? That’s what’s on the docket in this episode.

Here’s what I accomplish in this clip:

  •  Started implementing the concept of pieces “blocking” one another.
  • Expanded the blocking logic to include horizontal and vertical blocking in both positive and negative directions.
  • Realized I’d been wrong about how Enumerable.Range() worked for a good long time because I had always used it for 0 indexed number generation, which masked my wrongness.

And here are some lessons to take away:

  • If you’re anything like me, sometimes you’ll thrash a bit between micro design decisions.  I introduced the concept of BoardCoordinate to avoid passing (int x, int y) to every method under the sun, but then I started to get annoyed by the ceremony of declaring new BoardCoordinate(x, y) everywhere.  Result was (for now) to implemented BoardCoordinate.For(x, y) which struck me as at least slightly more readable and elegant.  Point is, you probably won’t hit your most simple/elegant design on your first, second, or even third crack.  Keep at it, don’t be afraid to experiment, and solicit opinions and advice.  (Speaking of which, anyone with a good idea for this, please chime in!)
  • “Do the simplest thing you can to make the test pass” is not just a function of what you do in the production code but also of what test you’ve written.  In other words, make sure you don’t write an overly ambitious test like “test_that_all_end_user_requirements_are_satisfied” or the simplest thing you can do to make it pass will be really complicated.
  • TDD is the ultimate in “fail fast.”  I wasted about a minute of my time (twice) and a minute of yours (once) because I couldn’t figure out that I was calling Enumerable.Range(int, int) with the wrong second parameter.  But, seeing NCrunch’s dots turn red told me something was wrong very, very quickly while what I did was still fresh in my mind.  I didn’t know I was misremembering the method signature, but I did know that something about Enumerable.Range() in there was breaking things.  Without TDD, I’d have gone merrily on writing code for minutes or even hours until I fired up the whole application and wondered why the blocked rook could randomly move to one spot on the board in front of the opponent’s pawns or something.  I’d have wasted a lot more of both of our time trying to hunt down the problem then, when I had no clue which line of code was the offender.
  • There are times when the code smell of duplication or duplicate effort appears, but the solution isn’t immediately obvious (such as the case in this video where I was doing similar things for horizontal and vertical).  It’s my experience that you can find yourself in a blind alley when you try to abstract this to a common method where it becomes a snarl of conditionals or very dense, opaque mathematical logic.  Eliminating duplication is extremely important, but beware of times when you have “duplication elimination fools’ gold” and the gains in readability/maintainability actually go into the negative.  Be sure that your abstraction is actually making things simpler.
  • I didn’t like a number of things about this code when the clock started getting pas the 20 minutes mark and I felt the pressure not to make this a horribly long episode.  It might not be the same reason, but there are going to be times when you’re forced to get up and leave for the time being or for the day when you’re not thrilled with the code.  It’s okay — you’ll have another crack at it tomorrow with a fresh mind, and the TDD will help you pick right up where you left off.