Composable Features and Tables
Recently I’ve been commenting on the this blog article. I think it would be better to gather my thoughts here.
The Problem With Tables
I consider tables in features a smell. They are a warning that maybe something
is not quite right, and that there is some more work to do. Lets consider the
following from the watirmelon
article.
At first view this table seems like an elegant summary of ‘Beautiful Tea Shipping Costs’, but lets examine this a little bit further.
If we expand the table into individual features we can get something like
There are a few things to notice here:
- There is no need for comments. The scenarios specify the rules
- There is alot of repetition
Lets address the second point by refactoring
Here we have split the feature up by differentiating between domestic and overseas
We could have split the feature by amount purchased or even by GST, which one we choose is very much dependent on context.
Now we have two small very simple features that cover all the ground that the table feature does. There are a few points that we are now in a position to look at in greater detail
Where has the order total gone
The original table specified the threshold at which shipping was set which is
$100. Implementing this in the application would almost certainly be done by
using a constant - shipping_threshold
and then basing all the calculations
on this constant.
So what happens when the value of the constant changes?
- The features will fail - even though the application is working fine
The price of changing this constant is that the feature has to be rewritten, but actually nothing is wrong with the application. Now this is a real pain for the site owners. Doing things like having a free shipping promotion at Christmas now becomes something that requires development work and rewriting features, or worse that we actually run with failing features.
Questioning the Business Rules
The most important part of writing a feature file, and the part that most people skip over is the first three lines of the feature. What happens if we compare these from our two features
As a site owner
I always want domestic customers to get free shipping
Because free shipping increases profitability by encouraging
more purchases.
As a site owner
I always want overseas customers to pay for shipping
Because shipping overseas is to expensive to ever do free
Lets question these justifications. If free shipping always encourages more purchases, then we would like to do free shipping for overseas customers. However we’ve said its always too expensive. But is it? Are there some situations where it would be profitable to free ship to overseas e.g. a large order that doesn’t weigh much; an order for very expensive goods. Separating the feature into these components give us the ability to ask these questions before we do any work
Implementing the Step Definitions
Implementing the step definitions for the table is going to be difficult. We have to process a table of hashes, use custom processing for ‘Pays GST’ and convert the numeric values in the table. All of this is error prone.
Consider the refactored steps. There are no tables to deal with, no arguments to process. Each step is much easier to implement, is reusable and is reused. This means we can go faster. Just by changing the language of our feature we have reduced the cost of implementing it.
Summary
If you come across a table in a feature, or if you feel the need to write a table STOP and have a think. Its likely that there is a simpler approach which will achieve what you want with less work and easier to read features