Showing posts with label BDD. Show all posts
Showing posts with label BDD. Show all posts

Monday, September 16, 2013

The language you code in could say a lot about your developer culture


In his essay on "Race and Language" Edward Augustus Freeman suggested that language, rather than race (genetic similarities), might be a surer indicator of cultural kinship among peoples. Professor Freeman wrote: "Every word that a man speaks is the result of a real, though doubtless unconscious, act of his free will. ... A man cannot, under any circumstances, choose his own skull; he may, under some circumstances, choose his own language. He must keep the skull which has been given him by his parents; he cannot, by any process of taking thought, determine what kind of skull he will hand on to his own children. But he may give up the use of the language which he has learned from his parents, and he may determine what language he will teach to his children." As such, the choice of language made individually and in the aggregate points to attributes of the language and those already speaking it which the new speaker of the language appreciates.

Perhaps this is why few topics among developers can start a 'religious war' faster than that of programming language.

The use of language is in essence a tool to capture an idea and communicate it to another. In IT we largely look at languages as tools to efficiently solve a problem. By 'solve' we really mean 'communicate an algorithm to the machine'. Just as some spoken languages are better for communicating facts or legal concepts and others are better for poetry or philosophical abstractions, each programming language is more efficient at 'solving' some technical problems than others. One may be excellent for modeling relationships, another for solving concurrency problems.
Looking at language this way is a good pragmatic approach to choosing 'the right language for the job', but it also can subtly mask or neglect other factors in language choice. Namely, the speaker and prospective audience plays a large part in what language communication is captured and how that communication is shaped. The above take on the use of programming language measures its efficiency in processes or cycles or memory consumed. It is the run-time efficiency - or how easily the computer understands and can execute the message. However, when using high-level programming languages, that is really misleading. It is really more of a measure of how good the compiler or interpreter for a given language is at translating the solution into efficient byte-code. So, compilers and interpreters aside, the real audience to gauge the efficiency of the language used is - humans.
Looking at how we use language it seems to lie upon a continuum between communicating to a large or a small audience. On one hand we have the language of media news reports, which linguists will often point to as a general epitome of the common speech of a people. It is intended to be understandable and consumed by the largest portion of a population. Prose is also near this end of the spectrum. On the other end you may find cryptography, where the audience is narrowed to perhaps only one other person. Sonnets, slang and technical jargon are closer to this end. They use conventions and specialized vocabulary which only a smaller subset of the population would have exposure to. Obviously a particular communication can lie closer to one end or the other given both the speaker and the audience. For instance a technical treatise might use highly exclusive vocabulary, but be written utilizing the most standard academic grammar and style. This 'regulated language' ensures that the message, while directed to technical specialists, will be understandable to the widest range of that population. It could even be accessed by outsiders armed with a good dictionary. Slang, on the other hand, often develops out the needs of the speaker... Complex grammar and punctuation is boiled down sometimes to only partial words. This makes the message easier and faster to say. To achieve this, the complexities of grammar and punctuation are replaced by context. One must understand this context, often cultural, to unpack the meaning behind this terse communication. It is particularly difficult for outsiders to master, and often intentionally so.

The intended range of audience has certain temporal effects as well. A loose jargon may make it easy for a small, tight knit group to communicate efficiently. However, it will be much harder to decode the meaning years later, perhaps even by members of that same community. Formal and standardized grammars and punctuation provide a degree of staying power to a language, allowing it to be understood for generations.
On can see this in development shops where one language is the exclusive language of development. On one hand a particular language may have been chosen for its similarity to human language. This may make translating business requirements into code easier. The same language may make it extremely difficult to describe the algorithm for performing a particular calculation. With greater complexity, it makes it more likely that a mistake will be introduced. The wordiness of this complexity can also make it harder to find the mistake. It also assumes that those writing code write well in their natural language. Run-on sentences can exist in code. A run-on piece of code is recognizable by loose cohesion, which is well known to negatively impact its brittleness and maintainability.

As a developer it is important to know the ways of expressing algorithms that is most natural to the language being developed in. This is called Idiomatic Code. However, a more seasoned Lead or Architect may realize that the eventual human viewers of the code may dictate different ways of expressing the same algorithm. This may even call for a completely different language to be used. Perhaps it makes sense to write code in one language, but to write the tests against that code in another. Testing in another language is often a good way to extend the audience of code written to an otherwise smaller audience.

This also brings up the impact of language on developer culture. Code written in a language which is only understood by one group within a team can lead to a closed culture. Think of those developers who almost have a visceral reaction to coding in anything but their favorite language. This language is usually that of a closed culture. Entire myths can be constructed about the superiority of both the language and those who code in it. Ultimately, this can threaten to alienate the developers from others on their team (testers, BA's, designers) as well as the development community at large. Uncle Bob Martin touched upon this in his 2009 talk "What killed Smalltalk could kill Ruby too".

Then there is the case where the language is chosen for you. The experience in this scenario can range from mind-expanding to dehumanizing. Surely the Junior Developer can learn much from being made to code in another language, particularly if that language has been chosen by a group of seasoned veterans across an appropriate section of the team. In this case the developer may be introduced into whole new ways of communicating and problem solving. On the other hand, there is the case where the language is imposed by a corporate decision made years earlier which may have little bearing upon the way your team works today or the problems it is being asked to solve now. This is the fallacy of simply 'buying' a language as a tool among equal tools. When that happens, the choice can become less about the effectiveness of the 'tool' and more about the packaging/marketing (e.g. - IDE's, plugins, reporting tools, support plans, name recognition, third-party-apis and frameworks, etc.). In these cases, the developers may often feel as if they are being forced to use an inferior tool for what seems like an arbitrary reason.

Finding pragmatic ways to introduce other languages where appropriate can mitigate some of the negative cultural impacts and keep communication flowing. It also can make the developers 'smarter' by making them look at and 'speak' about the problem using different paradigms than they are used to. This is much the same as people who speak multiple languages. Becoming a polyglot programmer may just make you a better designer or architect as your pool of ways of looking at a problem will be larger.

What other ways does the language you code in impact your team or say something about you?

Tuesday, October 25, 2011

When the Cucumber is mightier than the Pen - Fixing Rails 3 in Action

Aslak Hellesoy and the good people behind Cucumber have realized there was a problem in the Cucumber community. People were using web_steps to build, rather than just as a set of examples. So, the latest versions of cucumber have removed the creation of web_steps and the attendant files when you run the generator.

As Mr. Hellesoy noted in his blog entry, this is going to break a lot of Rails training materials which have come to rely on these files being available.

Having recently gotten a copy of Rails 3 in Action and noticing that an edit seems to be a ways off, I offer my humble solution for getting through chapter 3 of this book using the latest Cucumber. You can and probably should still read through the text that I skip in the book, as it does give you insights, but my path below will allow you to use Cucumber the 'right' way.


The trouble starts on Page 55

I have rewritten the Gherkin for the feature file. Notice the more domain language syntax?

Listing 3.8 
Feature: Create projects
In order to have projects to assign tickets to
As a user
I want to create them easily 
Scenario: Creating a project
Given I am on the homepage
When I navigate to the new project creation page
And I create a new project
Then I should be shown the project created verification message

Then skip to the portion about doing the db migration

rake db:migrate (page 56)
rake cucumber:ok

You can implement step definitions for undefined steps with these snippets:

Given /^I am on the homepage$/ do
  pending # express the regexp above with the code you wish you had
end
When /^I navigate to the new project creation page$/ do
  pending # express the regexp above with the code you wish you had
end
When /^I create a new project$/ do
  pending # express the regexp above with the code you wish you had
end
Then /^I should be shown the project created verification$/ do
  pending # express the regexp above with the code you wish you had
end


stick this in features/step_definitions/project_steps.rb


Given /^I am on the homepage$/ do
  visit('/')
end
When /^I navigate to the new project creation page$/ do
  click_link('New Project')
end
When /^I create a new project$/ do
  fill_in('Name', :with => 'TextMate 2')
  click_button('Create Project')
end
Then /^I should be shown the project created verification$/ do
  page.should have_content("Project has been created.")
end


The visit('/') is substituted for the path_to stuff from web_steps that is mentioned on page 56

basically we are sending it to the root 

continue to page 57-58

when editing the routes.rb file


  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => 'welcome#index'
  root :to => "projects#index"
...

continue through to page 61

when editing routes.rb


  # Sample resource route (maps HTTP verbs to controller actions automatically):
  #   resources :products
  resources :projects
You can continue on till Page 73 adding a title:

add the following line to the creating_projects.feature

And I should be on the project page for the new project

running rake cucumber:ok will give you the following step def to add to your file (project_steps.rb)

Then /^I should be on the project page for the new project$/ do
  pending # express the regexp above with the code you wish you had
end 
Then edit this to:
Then /^I should be on the project page for the new project$/ do
  current_path.should == project_path(Project.find_by_name!('TextMate 2'))
  page.should have_content("TextMate 2 - Projects - Ticketee")
end

This replaces the paths.rb stuff and the other web_steps.rb stuff referred to on page 73

do read the stuff on the bottom of page 73-74 about the dynamic method invocation

rake cucumber:ok

will give following error:


"expected there to be content "TextMate 2 - Projects - Ticketee" in "Ticketee\n\n  \n    Project has been created.\n  \nTextMate 2\n\n\n" (RSpec::Expectations::ExpectationNotMetError)"
(instead of the expected #has_content? error mentioned in the text)

both are Rspec type errors though

continue on with page 74-77

New Cucumber Feature for Page 77

make your features/creating_projects.feature look like:

Feature: Creating projects
  In order to have projects to assign tickets to
  As a user
  I want to create them easily 
  Background:
     Given I am on the homepage
     When I navigate to the new project creation page

  Scenario: Creating a project 
    And I create a new project                           
    Then I should be shown the project created verification
    And I should be on the project page for the new project 
  Scenario: Creating a project without a name
     And I try to create a project without a name
     Then I should be informed that the project has not been created
     And I should be told that the name is required

rake cucumber:ok

Add these to the project_steps.rb

When /^I try to create a project without a name$/ do
  pending # express the regexp above with the code you wish you had
end
Then /^I should be informed that the project has not been created$/ do
  pending # express the regexp above with the code you wish you had
end
Then /^I should be told that the name is required\.$/ do
  pending # express the regexp above with the code you wish you had
end

Implement them as per below:

When /^I try to create a project without a name$/ do
  click_button('Create Project')
end
Then /^I should be informed that the project has not been created$/ do
  page.should have_content("Project has not been created.")
end
Then /^I should be told that the name is required\.$/ do
  page.should have_content("Name can't be blank")
end

This should get you on track to continue at the bottom of page 77.


I realize my Tests are not ideal. For instance the second scenario could also check that on a failed verification you stay on the New Project page. I was simply trying to mirror what the book had and put it into a more business domain syntax. It also nicely shows the division between the Gherkin and the step definitions.

Hopefully this is helpful to others. As I have time to go through the book, I will try to add further updates, but this should give most a good start in the right direction.

I am eager to see other modifications others make to this.

Eat your meat AND your vegetables!

No matter what dietary fads are upon us, most of us realize that we need to eat a balanced diet.*

Why is it in the software industry that I so often see teams binging on just one thing when it comes to testing?

What I mean specifically, is testing frameworks. In the Rails world the frameworks du jour are RSpec, Cucumber and Steak - with a little Capybara sauce. Mmmm sounds tasty!

RSpec has become a solid core for all layers of testing with the other parts. Cucumber was initially created to make the BDD'ness more domain specific... so that customers/project owners/BA's could read and even write them. Unfortunately, many Gherkin examples in the wild tend to be anything but non-coder friendly. This seems to have occurred due to many factors which may come to play on a team. 

One of these factors seems to be part of what has attracted many people to Ruby on Rails in the first place. You often hear Rails coders talking about how they love it that RoR 'gets out of the way' and 'just lets them code'. This is definitely laudable when what is getting in the way is technical scaffolding or other technical encumbrances. It is like using a power tool over the old manual ones. Where it becomes a problem is when what is being 'gotten out of the way' is meaningful communication and collaboration across the team. Teams who have tried to get their 'business folks' involved through BDD have run into the problem that either the business loses interest or can't write the tests well enough. I believe at least a good portion of this is due to how the tests are being written. They are often too low level - basically a series of instructions for filling out web forms, clicking buttons, etc.  The folks behind Cucumber have tried to force a solution by removing one of the culprits they provided early on: web_steps.rb. Web_steps was a sample collection of step definitions around many boring day to day activities. Instead of serving simply as an example, teams baked their tests around it - creating many awful to read, low level test suites.

While I applaud the removal of web_steps on the part of Cucumber, it is having the oposite effect. Teams are just moving away from Cucumber to Steak (because it is more 'coder' friendly) for their Acceptance/Integration tests. What lies at the core is a one-two punch of badness that I am seeing more and more: Teams are confusing Integration Testing with Acceptance testing AND coders are writing those tests.

Acceptance tests should be written in the domain language of the business. They are meant to be high level - to provide the coders a place to start. 
Integration tests should be written to test across 'the stack' and as such are more focused on the implementation details. These are therefore in the more code like language of the implementation domain.
Unit Tests test the code directly... everyone knows the coders are supposed to write these. 

Cucumber is good for BDD acceptance tests. Steak is great for integration tests. Eat your meat and vegetables!

Let me suggest a possible test driven development team and their roles in testing under the above approach.

"The Business" (Story owners/Customers/BAs/etc) - write high level Acceptance Test Scenarios - These could even be part of the story. In essence they write the Cucumber Tests. (Someone else might actually cut and paste the tests into a 'feature' file, but you get the idea).

"Coders" (Software Engineers/Programmers/etc) - write the step definitions behind the Gherkin. Step definitions can be more implementation specific. Writing these can be the first time the coders actually start doing Test Driven Design. Then the coders write their Unit tests however they see fit.

"Testing Team" (Test Engineers/QAs) - write Integration tests using Steak, etc.

The above scenarios are based upon testing using Cucumber and Steak. It could just as well apply to the myriad other testing frameworks (Fitnesse, JBehave, Selenium, etc). The essence is that integration and acceptance testing should be separate endeavors.

I can hear the objections already.  

"We don't have a testing team.":  Fine, there are projects which are small enough, simple enough where the coders serve this role. The point is, integration testing is a different animal from acceptance testing.

"Our business people are not involved/would never write tests)": Really? Who writes your stories? Maybe they were driven away by previous bad cukes. Listen to your business people describe the functionality they want. "So I am on the home page and when I go to create a new account then I should get some indication that the account creation succeeded". That is practically Gherkin already! If they won't physically write the tests, then the BA's could certainly be following them around 'taking dictation' as the acceptance tests drip from the Owners' lips. 
On the other hand, if your business people are not involved, it is likely you have a deeper issue than what testing framework you are using. Do you have an Agility Coach?

"That is totally going to slow us down!": Again, fine! Speed by itself is not a good thing. Without direction it simply means you are going to drive off the cliff faster. If you are a business owner and the 'acceptance tests' you are being fed make you want to cry with their technical level of detail - ask why they are being written this way - or better yet - write them yourself. If the testing is being taken away from you completely, don't let them. Don't let anyone tell you that integration tests are the same thing as acceptance tests. Coders, if you want your business owners to engage more, realize that giving them pages of cryptic, coder centric tests to review does not really encourage their engagement. As stated before, the idea of BDD was to simplify acceptance gathering so that coders would know where to start. It supports Agility by giving a venue for business people and programers to collaborate frequently. In the end, the slight reduction in speed along a more prudently chosen path will likely save you way more time than a radical course change much later in the project.

All of this raises a number of other questions I have been pondering for years - such as having different types of 'Customers', What sufficiency of testing levels for a given project, optimizing testing approaches... 

It also makes me hungry...


* - my wife wanted me to note that our household is vegetarian and that I am only promoting Steak in the 'software' sense. Thank you dear! :-)