Consistency in Features
Writing good features is difficult. One way to write better features is to read them critically. Two criteria useful for this are consistency and exclusivity. So a feature should be consistent and exclusive, what does this mean.
Consistency
For a feature to be consistent the following needs to apply
The filename (including path) of the feature should be consistent with the title of the feature
- inconsistent:
features/purchasing.featureandFeature: Writing a blog - consistent:
features/blog/new_article/andFeature: New article
- inconsistent:
The narrative should be consistent with the title
A scenario title should be consistent with the narrative
A scenarios steps should be consistent with the scenario title
n.b. In addition each thing lower down the list should be consistent with all the things above it.
Typical Inconsistencies
- Change of vocabulary: e.g. changing from talking about
articlesto talking aboutposts - Introducing concepts outside the context. A classic in web applications is introducing different behaviour for different user types.
- Scenarios about separate content that appears on the same web page but has nothing to do with the feature.
Exclusivity
This is partially covered by being consistent. What it is saying is that a feature should only contain scenarios that are part of its narrative. It might also be saying that these scenarios belong here and nowhere else. In practice having no overlap between features is probably impossible. However lots of overlap is probably a good indicator that things could be better
Summary
Reading your features critically and applying rules of consistency and exclusivity is useful in creating simpler features that have greater focus. This should be done before, during and after implementation. In the long run its far more important that your features make sense than go green. If they make sense but are red you will have lots of context to help create your fix. If they make no sense then when they go red (and they will some day) then finding a fix will be much harder.
JRuby too slow for development 3
A controversial title which I hope I will be able to amend.
I'm new to JRuby, and the following may be due to my ignorance, which I am trying to address.
Two identical rails projects with almost identical Gemfile's. One running under JRuby 1.6.3 and the other on MRI 1.8.7p352. Running exactly the same specs. JRuby is 20x slower!!!
Git-Svn Workflow
The following is from a post by Jim Lindley in 2008. This seems to have from the net, so I'm reposting here (with some amendments) so I have a reference.
Composable Features
In Eloquent Ruby, Russ Olsen applies the composed method technique to a class. He says
"The composed method technique advocates dividing your class up into methods that have three characteristics. First, each method should do a single thing—focus on solving a single aspect of the problem ...
Second, each method needs to operate at a single conceptual level: Simply put, don’t mix high-level logic with the nitty-gritty details. A method that implements the business logic around, say, currency conversions, should not suddenly veer off into the details of how the various accounts are stored in a database.
Finally, each method needs to have a name that reflects its purpose.
"
When you apply this technique to classes you end up with classes with a relatively large number of methods each which is very simple. In applying this in detail I find that I create two sorts of methods.
- Methods that do something
- Methods that call other methods to do something
And in applying this technique I NEVER mix the two.
These techniques have been around for along time, as have a number of refactoring to get your code more composable. Use them and you'll never write another 20 line method ever again - personally anything over 5 lines sends of my alarm bells.
Anyhow if this technique is good for classes, might it also be good for features? And if it is how do we apply it?
A clue lies in how composed method technique helps eliminate proceduaral code. Perhaps we can make our features less procedural
Feature: Title
In order to encourage return visits
As a site owner
I want to support user accounts
Scenario: login
Procedural | | How |
-----------|----------------------------------|--------|
↓ | When I go to the home page | ↓ |
↓ | And I fill in login with 'me' | ↓ |
↓ | And I fill in my password | ↓ |
↓ | And I press submit | ↓ |
↓ | Then I should be logged in | ↓ |
↓ | | ↓ |
↓ | When I go to the home page | ↓ |
↓ | And I login | ↓ |
↓ | Then I should be logged in | ↓ |
↓ | | ↓ |
↓ | When I login | ↓ |
↓ | Then I should be logged in | ↓ |
-----------|----------------------------------|--------|
Declarative| | Why |
-----------|----------------------------------|--------|
Here we see a simple feature being refactored down to its bare minimum. The final feature format may make you uncomfortable
When I XXXX
Then I should be XXXX
seems to simplistic to be valuable. However in practice finding a good XXXX is really useful, and expressing basic functionality in this way is a great starting point for further exploration.
For example we can start dealing with failure very easily
When I login badly
instead of putting in fake credentials into a table.
So what do we get when we apply this sort of technique to a large set of features?
- A very succinct specification of what the application should do and why it should do it.
- No indication of how the application should do something.
- Features that are technically very easy to turn into step definitions
- Features that are very readable
- Features that have just the right amount of information
This last point is contentious. I know many people feel that features need to have more information in them. In particular the idea of features needing to have descriptive examples so you can explore how to do things is a strong argument. However I think this exploration and description is best done by implementation, review and iteration. If you iterate very quickly you don't need to explore the how up front, you can explore how things are done as you go along.
Why Would You Be Uncomfortable with This
Agile in general is not comfortable, and working in this way builds on that. This discomfort shows itself as
the need to plan what will happen, rather than reacting to what is happening.
the need to specify how things will be done, rather than provide feedback on how things are being done
the need to micro manage rather than delegate responsibility
the inability to trust
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.
ergonomics, guitar arpeggios, mac keyboards and mice
For the longest time I've been plagued by a chronic inability to play arpeggios on my guitar using my index finger. Playing a simple pim has at times become almost impossible, yet pma is fine and precise. Similarly playing scales with 'im' alternation has become very difficult, my speed being less than half that when playing with ma. Things have got so bad that I've resorted to hybrid picking, that is holding a plectrum between my thumb and index finger and using the other three fingers when playing fingerstyle pieces.
The Evils of Cut and Paste
Its a given in programming that bad habits are hard to get rid off. Its also a given that when you try and go fast, and when you feel pressure bad habits re-surface.
Cut and paste programming may be the worst habit of all. Its so enticing, easy to do and so productive! At least that's how it appears, but really its a cancer, destroying the joy of programming and at the same time destroying your code.
Such strong words, can they be justified? Well lets have a closer look at cut and paste and see what it does
Array.inject
Having had a lot of fun last week doing Uncle Bob's prime factors kata, I've been doing the Codebreaker example from the RSpec book this week. In section 9.2 the number_match_count method is refactored to be
def number_match_count
total_match_count - exact_match_count
end
And the problem of implementing total_match_count is discussed. The book starts with
def total_match_count
count = 0
secret = @secret.split('')
@guess.split('').map do |n|
if secret.include?(n)
secret.delete_at(secret.index(n))
count += 1
end
end
count
end
I didn't like this so in a separate branch I came up with
def total_match_count
total_match_count = 0
secret = @secret.clone # need a copy as we will slice destructively
@guess.each_char do |char|
pos = secret.index(char)
secret.slice!(pos) and total_match_count +=1 if pos
end
total_match_count
end
Which is OK, but fairly similar.
What the RSpec book is leading upto though is
def total_match_count
secret = @secret.split('')
@guess.split('').inject(0) do |count, n|
count + (delete_first(secret, n) ? 1 : 0)
end
end
def
delete_first(code, n) code.delete_at(code.index(n)) if code.index(n)
end
This uses Array.inject, something I have always avoided. This is the second time the book has focused on Array.inject, and I started thinking why the fascination with inject. What is it that Ruby programmers like about it that I'm missing.
Some googling produced
This thread, of which the best bits are:
-
How I remember: Inject takes a binary operation (e.g. +) and injects it between each element of a list. [1,2,3].inject { |a,b| a+b } => 1+2+3 -- Jim Weirich-
... there is a fundamental difference between the inject and each versions. The "each" verison is procedural. It defines state (the value of b) and how that state changes in each iteration (b += a). The "inject" version is functional. There are no extra state variables in our code that need initialization. And the expression itself is the value, rather than having a side effect on a local variable. Not that one way is better than the other, just noting differences. -- Jim Weirich-
So, in math-speak, I think one could say: inject applies a block pairwise as an n-ary operation over an Enumerable, with an optional initial value. -- A LeDonne
Perhaps Array.inject is worth investigating further as a step towards doing more functional programming.
Blogging with Vim
In my attempts to become more proficient with VIM I thought I would try and push some standard editing tasks in its direction. My first choice was blog posting. For this to work I need VIM to:
- Understand that my blog posts are in markdown
- Get and retrieve posts from typo like the textmate blogging bundle does.
As usual with anything VIM things are not easy. Much of this is down to my ignorance, but the steep learning curve VIM never ceases to amaze me with its incline :)
After much googling I came across a vimblog.vim, and was able to get and retrieve posts ... SORT OF
However post retrieval doesn't quite work (partly my fault for using Typo and not Wordpress!) as not all the post is returned when I use a "Continue reading...".
So know I have to learn how to debug vim scripts so I can examine the XML object returned and see if either
- Vimblog is making the wrong call and getting only the article summary rather than the full article
- Vimblog is not extracting the correct field from the XML object
- Something else is going wrong
I guess if VIM really was the editor for me, I would just hack a solution to this. Perhaps I will, but I feel that I've got better things to do than spending tens of hours learning how to script VIM.
Using Vim
Currently I use textmate as my main editor, but I find myself often using Vim as a secondary editor for small tasks run from the command prompt. I'm thinking about extending my use of VIM for the following reasons
- Its available on all the VM's that I have to use
- I really like modal editing
However textmate still has a number of very attractive features that I will want VIM to emulate including:
- Excellent markdown support
- Good cucumber and rspec support
- OK RVM support
- ctrl-T find file support