DaedTech

Stories about Software

By

ChessTDD 28: Preparing for Idiomatic SpecFlow

This week I’m starting the process of engaging more yak-shaving, but I think it’s important yak-shaving. If we’re going to be doing this SpecFlow thing in the series, let’s get it done right. In a post I made last week, Darren Cauthon took the time to put together this gist. I read through it and my eyes bugged out. That kind of visualization is solid gold for this problem space. How powerful is it to be able to show other developers (and hypothetical business stakeholders) these ASCII chess boards and say, “look, this movement works?!” So, I’m asking you to indulge me in the journey to get there.

Here’s what I accomplish in this clip:

  • Created AsciiBoardBuilder class to take strings like “BQ” and “WP” and turn them into pieces added to a Board instance.
  • Got half-ish way through implementing that class.

Here are some lessons to take away:

  • I created something called “AsciiBoardBuilder.”  There was a time when I would have immediately thought to have it implement an IBoardBuilder interface, but I’ve gravitated away from this over the years as it tends to lead to unnecessary abstraction at times.  We can always do this alter if we need some other means of constructing boards aside from just using the Board class itself.
  • In case you’ve forgotten, one trick I use is to create the production class in the same file as the test class at first, when convenient.  NCrunch runs a little quicker this way and you don’t have to flip back and forth between two files.  I leave it in here until it no longer makes sense to, usually (e.g. when some other production class needs to use my new class).
  • I did something that’s a little more complex than your average TDD scenario, wherein I was modifying two different production classes as I went.  This isn’t particularly common and you might not want to do it if you’re new to this or you run into trouble trying it.  But if it works for you, there’s no reason not to do this.
  • If you go look up a solution, such as how to implement a bit of Linq-fu, it’s probably worth writing an extra test or two that you expect to go green just to confirm that you really understand the behavior of the solution that you found.
  • What I did with factoring out GeneratedBoard may not be to your liking.  This has the upside of eliminating duplication but the downside of introducing a bit of indirection.  For me, the improvement in how succinct the test cases are is worth it, but you may not agree.  This isn’t always an exact science — taste does factor in.
  • I’m pretty rigid about strongly favoring one assert per test method.  Not everyone feels this way, but I felt it worth refactoring to assert only one thing: that the piece is a white bishop.  (As opposed to asserting that it’s white and then that it’s a bishop).  I suggest that unless there’s really no option but to have multiple asserts, you factor toward one.

By

ChessTDD 27: Parameterized Acceptance Tests and Scenarios

At this point, I’m not going to bother with excuses any longer and I’ll just apologize for the gaps in between these posts.  But, I will continue to stick with it, even if it takes a year; I rarely get to program in C# anymore, so it’s fun when I do.  In this episode, I got a bit more sophisticated in the use of SpecFlow and actually got the acceptance tests into what appears to be reasonable shape moving forward.  I’m drawing my knowledge of Specflow from this Pluralsight course.  It’s a big help.

Here’s what I accomplish in this clip:

  • Implemented a new SpecFlow feature.
  • Discovered that the different SpecFlow features can refer to the same C# class.
  • Implemented parameterized spec flow components and then scenarios.
  • Got rid of the “hello world-ish” feature that I had created to get up to speed in favor of one that’s a lot more useful.

Here are some lessons to take away:

  • When using new tools, you’re going to flounder a bit before the aha! moments.  That’s okay and it happens to everyone.
  • As your understanding of tooling and your environment evolves, be sure to evolve with it.  Don’t remain rigid.
  • Fight the urge to copy and paste.  It’s always a fight myself, but on the occasion that I don’t have a better solution right in the moment, getting a test green, than duplicating code, I force myself to feel the pain and re-type it.  This helps me remember I’m failing and that I need to make corrections.
  • When I got my bearings in SpecFlow and realized that I had things from the example that I didn’t actually need, I deleted them forthwith.  You can always add stuff back later, but don’t leave things you don’t need laying around.
  • Notice how much emphasis I placed throughout the clip on getting back to green as frequently as possible.  I could have parameterized everything wholesale in a broad refactoring, but I broke it up, checking for green as frequently as possible.
  • Sometimes sanity checks are necessary, especially when you don’t really know what you’re doing.  I was not clear on why 8 was succeeding, since I was querying for a piece off the board.  Just to make sure that I wasn’t messing up the setup and it was never even checking for 8, I added that exception in temporarily.  Use those types of checks to make sure you’re not tilting at windmills.  As I’ve said, getting red when you expect red is important.
  • No matter what you’re doing, always look to be refactoring and consolidating to keep your code tight.

By

ChessTDD 26: At Last, Acceptance Tests

Let’s get the excuses out of the way: busy, more work coming in, vacation, yada-yada.  Sorry for the delay since last time.  This episode is a short one just to get back on track.  I haven’t been writing much code lately in general, and I was already stumbling blindly through SpecFlow adpotion, so this was kind of just to get my sea legs back.  I wanted to get more than one acceptance test going and start to get a feel for how to divide the acceptance testing effort up among “features” going forward.

Here’s what I accomplish in this clip:

  • Cleaned up the dead code oops from last time.
  • Defined an actual feature file for spec flow, with four real acceptance tests.

Here are some lessons to take away:

  • I don’t really know how Specflow works very well, so that floundering around after pasting in the same text seemed to fix the problem is my way of avoiding programming by coincidence.
  • No matter what you’re doing (unit tests, production code, or, in this case, acceptance tests) you should always strive to keep your code as clean and conformant to the SRP as you can.
  • When you don’t know a tool, go extra slowly with things like rename operations and whatnot.  I’m referring to me changing the name of the spec flow files.  It’s easy to get off the rails when you don’t know what’s going on, so make sure you’re building and your tests are green frequently.

By

ChessTDD 24: Cleaning Up for Acceptance Testing

It’s been a little while since I posted to this series, largely because of the holiday time.  I’ve wrapped up some things that I’d been working on and am hoping here in the next few weeks to have some time to knock out several episodes of this, so look for an elevated cadence (fingers crossed).  To get back into the swing of things in this episode, I’m going to pull back a bit from the acceptance test writing and clean up some residual cruft so that when I resume writing the acceptance tests in earnest, I’m reacquainted with the code base and working with cleaner code.

Here’s what I accomplish in this clip:

  • Refactored awkward test setup to push board population to production code.
  • Got rid of casting in acceptance tests (and thus prepared for a better implementation as we start back up).

Here are some lessons to take away:

  • Refactoring is an interesting exercise in the TDD world when you’re moving common functionality from tests to production.  Others’ mileage may vary, but I consider this to be a refactoring, so even moving this from test code to production code, I try to stay green as I go.
  • I made a mistake in moving on during a refactoring when my dots went dark green.  Turns out they were green for the project I was in even while another project and thus the solution were not compiling.  It’s good to be mindful of gotchas like this so that you’re not refactoring, thinking that everything is fine, when in reality you’re not building/passing.  This is exactly the problem with non-TDD development — you’re throwing a lot of code around without verification that what you’re doing isn’t creating problems.
  • It’s not worth agonizing over the perfect implementation.  If what you’re doing is better than what existed before, you’re adding value.
  • If you’re working experimentally and trying things out and your tests stay green for a while when you’re doing this, make sure you can get to red.  Take a second and break something as a sanity check.  I can’t tell you how frustrating it is to be working for a while and assume that everything’s good, only to learn that you’d somehow, inadvertently made the tests necessarily always pass for some trivial reason.

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

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.

Acknowledgements | Contact | About | Social Media