The Oversimplified Specification Anti-pattern

I was running through a group talk I do at the recent Philly CodeCamp (which was a huge success by the way, special thanks to Brian Donahue for doing the heavy lifting in organizing an ALT.NET track) and we were ping pong pairing on the well known bank example. The first story we covered looked like this:

Deposit Funds

As an account holder, I want to deposit funds into my account, so that I can save funds for a rainy day.

Criteria

When depositing funds into an account, the balance should be incremented by the amount deposited.

So someone or another mentioned the whole “simplest thing possible” ethos of pair programming and Agile at large. I have to say I agree, but to a point. For example, this specification would pass (using the “specs” base class I recently published on Google Code):

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, “Courier New”, Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}

.csharpcode .lnum { color: #606060; }

using NUnit.Framework;
using XEVA.Framework.Specs;
 
namespace Banking.Model
{
   [TestFixture]
   public class When_depositing_funds_into_an_account : Spec
   {
      private Account _account;
 
      protected override void Before_each_spec()
      {
         _account = new Account(0M);
      }
 
      [Test]
      public void Increase_the_account_balance_by_the_amount_deposited()
      {
         _account.Deposit(20M);
         Assert.AreEqual(20M, _account.Balance);
      }
   }
 
   public class Account
   {
      private decimal _balance;
 
      public Account(decimal balance)
      {
         _balance = balance;
      }
 
      public decimal Balance
      {
         get { return _balance; }
      }
 
      public void Deposit(decimal amount)
      {
         _balance = amount;
      }
   }
}

The problem with this is that the spec (remember: not test) oversimplifies things. It doesn’t express enough value in and of itself. It’s a very test-driven approach as opposed to a behavior-driven approach. When possible, I think BDD specifications should resemble the acceptance criteria attached to the story over leaving a breadcrumb trail of “the dead simplest possible thing” design.

Instead of writing two specs, I’d choose one to that illustrates that two deposits to an account are additive:

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, “Courier New”, Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}

.csharpcode .lnum { color: #606060; }

using NUnit.Framework;
using XEVA.Framework.Specs;
 
namespace Banking.Model
{
   [TestFixture]
   public class When_depositing_funds_into_an_account : Spec
   {
      private Account _account;
 
      protected override void Before_each_spec()
      {
         _account = new Account(0M);
      }
 
      [Test]
      public void Increase_the_account_balance_by_the_amount_deposited()
      {
         _account.Deposit(20M);
         Assert.AreEqual(20M, _account.Balance);
         _account.Deposit(10M);
         Assert.AreEqual(30M, _account.Balance);
      }
   }
 
   public class Account
   {
      private decimal _balance;
 
      public Account(decimal balance)
      {
         _balance = balance;
      }
 
      public decimal Balance
      {
         get { return _balance; }
      }
 
      public void Deposit(decimal amount)
      {
         _balance += amount;
      }
   }
}

This shouldn’t come as a revelation to anyone, but I think it’s extremely important that we represent how we’d cover these problems in the real world. To me, a specification is a whole concept in and of itself. Even though they are extremely granular, specifications express how the software implements business value. Leaving a wake of half-implemented tests in order to adhere to some kind of arbitrary “single expectation/assertion” rule is far, far less important than authoring meaningful and conceptually integral specifications.

This entry was posted in Agile, BDD, simplicity, TDD. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

8 Responses to The Oversimplified Specification Anti-pattern

  1. alberto says:

    Well, I think it’s not really a problem of oversimplifying, but rather a bug in the code AND a bug in the test itself. The test says “increase the account balance”. So, to test that, you have to be able get the account balance before the deposit to see if it’s really being added. This is telling me that your set-up assumption of an initial 0 balance is not adequate.

  2. Dave Laribee says:

    Not to pick on you guys; I’ve done the same thing in demo many times. I think I’ll offer this opinion going forward though.

  3. I wrote that code! The funny thing about this is that, while I do believe that keeping it as simple as possible for people new to TDD/BDD, my “bug” was a total accident that I only realized a couple minutes after I wrote it, and then (jokingly) brushed it off as being the simplest thing that worked :)

    I will say that I do keep my specs pretty simple. I had a hard time really grokking TDD because of my tendency to think too far ahead, so I put restraints on myself to make sure I don’t move too fast and miss something. I do strive for one expectation/assert per spec, but it’s more like testing one interaction, or one *type* of state change. So if my method calls a service, acts on the results, and updates a view, I’d have at least 3 specs to cover those 3 actions (and use SetupResult.For() for anything I wasn’t explicity specifying in a spec)

    I am really due for some blog posts.

  4. Dave Laribee says:

    @Christopher –

    > Have you encountered a spec that was difficult to express because it was “multi dimensional”?

    I’d differentiate between spec and acceptance criteria. Sometimes you get composite acceptance criteria:

    When writing an auto-policy from a quote, close the quote and add a link to the new policy.

    In this case we have an acceptance criteria. We’d break that up into two specifications in the model layer (at least) but we’d have a number of specifications in, say, our MVC front end. Specifications, to me, really mean “class specifications.” It is only a side-effect (a happy one) that in certain layers of our applications specifications are business facing (entities, model).

    The more important use of specifications is that we have readable documentation of our code for various audiences: developer, BA, tester, domain expert…

    I’d love to see an example; it’s very possible I’m not understanding your problem.

  5. Dave Laribee says:

    @Jimmy – All specs all the time. I would make the argument that not all specs have the luxury of an acceptance criteria. You might drive out specs in the course of fulfilling a story. What changes between TDD and BDD is that a) we’re using the specification formation and b) sometimes the intended reader of the specification is the user (model) and sometimes it’s the developer (cross cutting components). Generally speaking though you will end up with more executable specifications than scenarios or acceptance criteria. Back to “BDD is TDD done right” and with a big change in language (spec over test).

  6. The problem I have ran into is that sometimes a desired behavior cannot be expressed in a single clause. The bank example can be misleading because of it’s simplicity. Have you encountered a spec that was difficult to express because it was “multi dimensional”? Next time I run into one I’ll post about it…

  7. Jimmy Bogard says:

    Just curious, do you do both BDD specs and TDD tests? BDD specs matching acceptance criteria only doesn’t really lead to the full design and doesn’t give the coverage traditional TDD might give.

  8. Ian Cooper says:

    Funny how a lot of people misinterpret the simplest thing for the stupidest thing.

    Of course the paradigm is not ‘a single assert’ but test one thing. Kent Beck has a number of techniques to getting the green bar. ‘Fake it ’til you make it’ is the approach a lot of people think of when they reference this, the idea that you get the test passing by doing the dumbest thing, and then, and here is the key: implement it sensibly in the refactor step. I’ve never really warmed to the approach, but Kent does describe it as ‘first gear’ a warm up when you begin TDD.

    I’ve always quite liked his Triangulation technique where you build up a body of tests, each one adding testing another feature. So here we might have two tests. The first would make one deposit, the second would make two deposits, etc.

    But once the engine is running you are allowed to shift up into third: Obvious Implementation, where you know what the valid implementation should be and you code it straight away rather than waiting for a triangulating test or refactoring step.

    Kent’s advice is to stat in low and them move up to high gear, but switch down again if you find your tests are not helping your design enough. the trouble with most examples is that they are so obvious that we can never see the point of these low gears, but they are useful when we are hill climbing through areas where we are uncertain of our design.

    But a lot of folks quote that ‘do the simplest thing mantra’ at you without really getting it.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>