Cucumber Scenarios : The Dilemma

Off late I am exploring BDD with Cucumber & RSpec in Rails.

The first step in BDD after understanding the customer requirements is to come up with the User Stories in a particular structure. Read this brilliant article from Dan North if you want to know more on the structure of User Story in BDD.

Let’s say I am creating a simple blog app, a sample Scenario for Creating a Post can be written in two ways as shown below. These scenarios are as coded for Cucumber.

A pithy way

Scenario: Create Post
Give I am a registered User
And I have signed in
When I go to Create Post Page
And Create a Post and Publish it
Then I should see the Post in the Index Page

or a Detailed way

Scenario: Create a Post
Given I am a registered User with name "Arun", email "foo@bar.com" and password "foobar"
And I sign in as "foo@bar.com/foobar"
When I visit Create Post Page
And I fill up Title as "Foo Post"
And I fill up Content as "Bar Contents for Foo Post"
And I publish the Post
Then I should see message "Post was successfully created."
And I should see post in the index page

The RSpec Book touches on this topic. It calls the first approach Declarative Style and second one Imperative Style. The Book also advises to use the former way if the project is more like a single man show where developer dons analyst/tester/coder hats and go for 2nd approach if the project has a bigger team and a business analyst for writing scenarios.

But its really a touch and go topic and its really difficult to gauge to how much in depth we have to go. The declarative seems to be pretty concise with loaded step definitions, but the imperative style gives a fair idea of what it takes to accomplish something in the system. So if we have a little bit informed tech savvy customer, probably second approach may add lot of value and clear lot of confusion. The imperative style is kind of walking the customer through the UI flows of the system.

But the conundrum with imperative style is if we already have good RSpecs for the Views/Controllers our RSpecs may read a lot like the imperative scenario and may look redundant.

So I can do rspec spec --format doc to get detailed documentation of the flows like the Cucumber imperative style. But of course it may not be good idea to share RSpecs with a Business User.

As the RSpec book says perhaps we need to mix judiciously both and perhaps experience only will teach to balance that.

The trigger for me to write this post was I was trying to create Scenarios for a sample project I am doing and just one hour I spend switching a scenario between declarative and imperative and was pretty confused where I would/should settle.

Advertisements

Cardinal Sins of Programming

What I am going to put here is nothing new or enlightening for a seasoned software developer, it’s just my trials and tribulations working through some heavily screwed projects over the course of my career.

So what are those software (mal)practices which sound death knell and ensue disaster? Well, here are my top recipes for embracing pain

1. Code Repetition – Remember DRY aka Do not Repeat Yourself. Even if you repeat a mere 3/4 lines of code in 10 odd places just pause and think over. Something ought to be fishy, try to put that repetition into a function, reuse the code. I have burnt my fingers fixing repeated lines of code in 10 to 100 odd places, even a full package of Java files being completely duplicated to another package. Just remain ruthless if you see duplication, it should never be there, don’t hesitate to select and hit del, even if your manager is going to fire you for that.

2. Intermixing logic – Or simply violating SRP (Single Responsibility Principle). Its really catastrophic to mix UI logic with business logic. It just makes the whole code very difficult to read/debug and even more difficult to change anything. Suppose you want a new UI for the same logic, you are screwed, you have to recode the entire business logic again or refactor the current code to separate out business logic from UI. In this aspect I need to point out a horrible technological offering from Java Stable – JSP. If not used carefully JSP spell death knell. It’s so easy to mix db calls/business logic and UI HTML into the JSP. But what we get out of this shortcut is a code mass which totally undecipherable, not at all debuggable and what more stack traces point to the dynamic servlet code line numbers of the JSP. I loathe JSPs and wish Sun never gave so much power to the naive user to intermix things and screw up life.

3. Conventions – How do you feel when you see code with variables test1, test2, test5, i, j, looper, arraylist, map1, list1 etc. Terrible and horrible. You read method half way then you wonder what this test1 actually is then you scroll up then find out what is getting assigned to it, then come down and re-read. The naming convention is not confined to Java variables or methods, even for HTML tags. Its really a bad idea to give tag ids as myForm or myButton. I faced really a real night mare when we decided to consolidate all JavaScrips littered over JSPs to a single JS and include it every where. In the end you have 10 functions with name submitForm. You are screwed, you have a real pain to correct them If your form is an Order entry form right name for form id would be orderForm and submit of that form would invoke submitOrder() method in JavaScript.

4. Looong methods – How long can a method be? 1000 lines, 4000 lines? Well I had opportunity to debug upto 10k lines of code in a method. My pea brain just could not hold on that and I just had to leave that and pray before I run those methods. I personally feel 50 is the max number of lines you can have, 50 is upper limit of tolerance, ideally a method need to be 10-15 lines of code in a well crafted software.

5. Exposing the internals – If you have class, don’t expose the internals of it to outside. If you maintain list of names as HashMap inside a class, don’t tell world that you are using HashMap. Just keep it with you and give neat interfaces to outside like
void addStudent(int id,String name)
Iterable getStudentNames()
void getStudentName(int id)

rather than using
HashMap getStudentMap()

In the latter case call can even modify the Map without you being aware of it and at later point if you are going to change the Map to a Student Class, you are screwed up because all those who are exposed to your internals need to be updated.

6. Building the code on ArrayList, HashMap – ArrayList and HashMaps are good, but should be the lowest level of implementation never exposed out through public APIs or methods. I had tremendous experiences where a HashMap contains 10 keys, 1st key returns another HashMap which intern has 10 keys and each of those keys have ArrayList, Array, String, Integer etc. Then there were wonderful data structures like an Array of ArrayList. These kind of things drive you nuts and crazy, unless you debug line by line and print line by line its never clear what goes where. Class is the most powerful abstraction you have and try to encapsulate things within the objects and pass around objects rather than Lists and Maps.

7. Think a little bit ahead – Yea its not good to code for requirements which you are not having today, but still for some cases it’s good to assume certain things and give that flexibility in the code. A case in point is internationalization, just don’t litter messages and boiler plate texts in Java/JSP/JavaScripts, have mechanism in place from beginning itself, even though you may just show things in English alone. Another aspect is db, it’s not good to assume one db and code it, code ought to be db agnostic. I had seen code where things were assumed to be always on Oracle and they take liberty of using sequences or sysdate (both Oracle specific) and one fine morning customer comes and tell you, well I want only SQL/Server. You are doomed.

8. Passion – (or lack of it) Majority of those who write code, do it for getting pay cheque at month end. Building code is cheap and easy. Anyone with a reasonable aptitude can do it. But crafting it to be readable, extensible, maintainable requires lot of pain, learning and rework. If you are not willing to take that pain, not willing to learn how to write testable software, then don’t just do it.