DaedTech

Stories about Software

By

A Rider to the Law of Demeter

In case you were wondering who is responsible for the bounty provided by harvests each year, the answer is the goddess Demeter. In the age of global transport, harvests have stabilized somewhat, but that wasn’t always the case. There was a time when Hades, the God of the Underworld, captured Demeter’s daughter, Persephone, and held her prisoner. A desperate Demeter responded to this calamity as any parent would, by quitting her job and committing herself to a rescue effort. Trouble for the world was that Demeter being absent at her post led to widespread famine, prompting Zeus to intervene and some sort of compromise to be reached. And so, it stands to reason that a principle of software development discouraging the use of statements like Hotel.Rooms[123].Bathroom.Sink was named for her.

Demeter, of Law of Demeter fame
Read More

By

ChessTDD 36: Acceptance Tests for Queen Movement

This episode went smoothly until I discovered a bug.  Philosophically, I suppose this is the natural state of software development.  For my purposes here, though, hunting down the bug caused the episode to balloon to 26 minutes, so I’m going to try a new thing so as to keep the videos a reasonable length of time.  I’m splitting it into 2 videos: parts A and B.  Please let me know if this approach is preferable to sometimes having long videos or not; if you leave feedback, I’ll more likely do it the way you prefer, since I’m just trying to go with what people like.

What I accomplish in these clips:

  • Created a couple of code snippets in CodeRush to get rid of the hand typing in the specflow scenarios.
  • Wrote acceptance tests for the queen’s movement.
  • Squashed a subtle bug (or at least half of one).

Here are some lessons to take away:

  • Projects go better when there are more eyeballs on them.  Run things you’re doing by other people and see if they have suggestions that might help.  They may think of things that never would have occurred to you and might later seem obvious.
  • Whenever you make mistakes copying and pasting, it’s a crapshoot whether fixing them takes more time than you would have spent hand-typing or not.  In my experience, most of the time you don’t come out on the winning end, and wholesale copy-paste obscures your understanding.  This is why I try to avoid the practice.
  • What I find is that unit tests should be very directed and specific about system behaviors.  But acceptance tests let you put on your exploratory testing hat, dreaming up scenarios in which users might use this thing that could potentially break it.  For you unit testing newbies, fight the urge to write unit tests with lots of assertions that cover a lot of ground.  You can express that in your acceptance tests.
  • Once again, don’t do low-hanging fruit refactorings (e.g. deleting dead code) when you have red tests.  It might seem like it’s not a problem, but it will come back to haunt you at some point.
  • Another example in this episode of finding a bug with a failing acceptance test, and drilling in to get closer by writing failing unit tests.  This is an excellent and helpful practice.
  • TDD facilitates Eureka moments where you try something you think might work and you see all of your tests go green.  However, just like trying something in your code and seeing the application magically behave correctly next time you run it, it’s important to cement your understanding of why it worked.  Don’t program by coincidence, even if you have a green test suite backing you.  Keep writing tests and/or reasoning about the code until you’re sure you understand what’s happening.  (Writing tests provides an excellent way to prove your understanding to yourself).

By

ChessTDD 35: Acceptance Tests for Knight Movement

Things are really starting to flow with the acceptance tests now. In this episode, not only did I mercifully not uncover any important bugs, but I defined knight movement in acceptance tests in a way that I feel pretty good about. I’m learning as I go about using SpecFlow, which is cool, and as the cherry on the sundae, I actually got episode length back under control with a 17 minute episode.

 

What I accomplish in this clip:

  • Fixed the poor naming I left off with last time.
  • Wrote acceptance tests for the knight’s movement.

Here are some lessons to take away:

  • Naming is so, so, so important.  It may seem like a trivial thing, but leaving a method about chess piece movement where “origin” and “destination” were reversed would, sooner or later, cause someone a serious headache.  It would also probably make them hate me when they looked at the history.  Make sure your names are good.
  • You have to do a fair bit of fumbling when you’re figuring out a new tool/tech/framework on the fly.  Stick to your principles and be sensitive to the idea that there’s probably a better way to do a lot of the things that you’re trying to do.  Ask people, and read a lot if you can.
  • There’s a lot of out of the box stuff that comes when I make a SpecFlow feature, but I just get rid of it.  For me, it’s helpful to eliminate everything that I’m not using so as not to be confused about what’s mandatory and what isn’t and also not to be confused later about what functionality I’m even using.
  • An interesting tradeoff emerges in my use of SpecFlow.  Duplication is, by and large, pretty bad in a code base.  But, in the case of visualization, showing the chess board for each individual acceptance test may be helpful in that it makes it crystal clear what’s going on in each test.  There are probably various strategies to try optimizing for minimized duplication and maximized visualization simultaneously, but it’s worth bearing in mind that everything in software development is a matter of tradeoffs and it’s best to be deliberate about whatever choice you make.

By

ChessTDD 34: Specflow for Pawn Movement

This episode featured a return to progress toward shippable features.  I refactored the first feature that I’d started to use the new, idiomatic Specflow approach.  This resulted in it making the most sense to have this be the feature for pawn movement and thus progress toward implementing the pawn’s movement as well as shaking out more bugs.

What I accomplish in this clip:

  • Refactored the old Specflow feature to look like the newer one.
  • Deleted a bunch of now-dead code and made the Specflow backing class a lot more concise.
  • Implemented HasMoved from the board perspective.
  • Fixed a bug in GetMovesFrom

Here are some lessons to take away:

  • I made a mistake in deleting dead code when I had a red test.  Part of the reason I got this wrong was that the IDE crashed and I sort of lost my place, but there’s a lesson here.  It’s easy to get distracted when you see dead/unused code (or something else similar) and go off on a tangent.  That’s fine, but be sure you’re green when you go off on tangents.
  • Thinking ahead about how they code you’re writing will be useful elsewhere is a double edged sword.  It’s good because it can lead to more efficiency and less future rework, but it’s also the first step along the path to gold-plating.  There’s no exact how-to I can offer for walking this line, but just being aware of it will help.
  • When things go wrong with acceptance tests, which are coarser-grained, integration tests, your next stop in figuring out the problem will generally be to move down the test pyramid and look for more details in your unit tests.  Unit tests are going to exercise the code in more granular fashion, so you should get good insights there.
  • I recommend favoring domain-specific, communicative exceptions coming out of your code rather than allowing boilerplate exceptions to be thrown to your callers.  If someone using your code gets an array index out of bounds exception or a null reference exception, they can’t be sure whether you screwed up in your code or whether they screwed up calling your code.  If you, instead, throw “BadBoardCoordinateException”, it’ll be very clear to callers of your method that you’ve anticipated what’s going on right now, and that they’re doing something wrong.
  • Deferred execution with Linq is really powerful and allows you to do some great things, but it also leads to subtle bugs.  I’ve written about this in the past, even.  Be careful and always remember to make sure you’re aware of whether or not you’re enumerating the sequence when you run into stuff like this.

By

ChessTDD 33: Scenario Housekeeping

Having fixed some bugs in the last few episodes, it would have been nice to make some progress with functionality, but there was housekeeping to be done first. I did some refactoring for board setup using the tables, compacting methods, and made the implementation of the moves checker correct. This will put me on much more sustainable ground as I go forward implementing game scenarios.

What I accomplish in this clip:

  • Fixed incorrect/incomplete implementation of checking for moves.
  • Refactored BuildBoardFromTable method.

Here are some lessons to take away:

  • When you make a test go red, don’t then take the opportunity to do a refactoring — even a small or inconsequential one.  Go back to green and then do it.  You want to be taking actions in batches as small as possible.  Doing 2 things at once is a recipe for confusing cause and effect.
  • I’m not sure how others feel about this, but I did something in this video that I do from time to time.  I had a green test covering an implementation that was too permissive — too easy to get right.  So I altered the test temporarily to green in a situation where it should have been red.  I then modified the production code to get the expected red, then reverted the test and verified that it was green.  This is the equivalent of writing another test, framed in the negative, and then taking that test from red to green.  I shortcutted that process because I didn’t want that other test to be left around when I was done.
  • I consider baking the names of types into class, method, and variable names to be a bad practice.  You might change the type they use and forget to update the name accordingly, and you’re also leaking implementation details.
  • A refactoring may well never seem perfect to you.  If you make sure it seems cleaner or better as compared to where it was, that’s progress.  Stick a pin it it and make a note to revisit later.  Not only is this good for avoiding diminishing returns on a given day’s effort, but it also removes you from the problem so that you can better assess readability later.