Moving away from
legacy code
with BDD
Who?
!
BDD Evangelist

!
BDD Practice Manager @Inviqa

!
Creator of Behat, Mink, PhpSpec2,
Prophecy

!
Contributor to Symfony2, Composer

!
Host of the “Elephant in the Room”
podcast
This talk is about
•

Solving purely technical “TCIAM” problem with agile
business analysis and discovery processes

•

Building a delivery strategy on the idea of constant
change

•

Real-life experience
This talk is not about
•

Greenfield projects

•

Solutions for everyone

•

How to write code
This talk is not about
•

Greenfield projects

•

Maintenance-mode projects

•

Solutions for everyone

•

How to write code (well, mostly)
Legacy projects
How most developers see
their next project
My next
project
My next
project

His actual next
project
Agile, TDD, BDD,
General QA, etc…

// TODO: refactor this
later
Is it really that bad?
If the project can afford at least one full-time
specialist on a payroll that whines how horrible
this project is, then surely it did something right.
// TODO: refactor this
later
// TODO: refactor this
later
// TODO: refactor this
later
This world is full of brilliant projects that nobody
wants to whine about. Sadly, it’s often simply
because there’s no one left to pay for that.
The truth is:
You deliver value!
Just not as effectively as you could
Agile, TDD, BDD,
General QA, etc…

// TODO: refactor this
later
How?
Three options
1. Rewrite an entire application using “the right way”
2. Do functional refactoring
3. Do business-oriented rewrite using “BDD pipeline”
#1: Full Rewrite
#1: Full Rewrite
•

Scrum / Kanban

•

TDD / BDD / DDD / Pair-programming

•

New everything

•

Mirroring functionality
#1: Income
6 Months later…
#1: Almost there…
#1: Full Rewrite

Just spaghetti, please: 4 man years

Full London meal (TDD, BDD, Agile, QA): ??? man years
#2: FUNCTIONAL
Refactoring
#2: Functional Refactoring
•

Blackbox testing

•

New routing

•

New templating system

•

Migration of model layer (MySQL -> Mongo)
#2: Income
6 Months later…
#2: Ta-da!!!
“Exactly what did you do here?”

– Your client. (most likely)
#3: BDD PIPELINE
AKA Business-Oriented rewrite
Why do some legacy
projects suck?
Cost

Because of the
cost of change
Time
… Of change where?
Why do applications
change?
Welcome to the
wonderland
of Agile Business Analysis
Questionnaire
1. What is the goal and minimal valuable product?
2. What is the minimal set of features to support it?
3. Which features are more likely to change?
4. How fully those features should be implemented?
5. How to avoid gold plating?
“BDD Pipeline”
1. Impact Mapping
2. Feature Mapping
3. Prioritisation
4. Example Workshop
5. Full-stack BDD
1. What is the Goal &
minimal valuable product?
Impact Mapping
“Impact mapping is a strategic planning technique
that prevents organisations from getting lost
while building products and delivering projects,
by clearly communicating assumptions, helping
teams align their activities with overall business
objectives and make better roadmap decisions.”
– Gojko Adzic
Four levels of Impact Map
1. Why? are we doing all this (rewrite)? What is the
goal we’re trying to achieve?
2. Who? will be impacted by it?
3. How? can they help us to achieve the goal?
4. What? can we do to support them?
MVP
impactmapping.org
2. What is the minimal set
of features to support it?
Feature Mapping
“Feature mapping is a backlog grooming
technique. It is a graphical process which helps
teams in finding features that are necessary to
support discovered MVP”
– Marcello Duarte
Three levels of feature map
1. What? is the minimal marketable feature?
2. Who? will be impacted by this feature?
3. What? particular parts of this feature do they need
to create this impact?
Product Backlog
In order to buy more products
As a customer
I need to have a product autocompletion in the search field
3. Which features are
more likely to change?
Prioritisation workshop
In order to maintain my shopping history
As a site visitor
I need to be able to register on this site
In order to maintain my shopping history
As a site visitor
I need to be able to register on this site

benefit
!
actor
SELECT s.*
FROM backlog as s
ORDER BY s.role, s.benefit
LIMIT 25
4. How fully those features
should be implemented?
Example workshops
Three layers of a User-Story
•

Business rule(s)

•

Communication

•

Acceptance criteria
Three layers of a User-Story

•

Business rule(s) == Acceptance criteria

•

Communication
Three layers of a User-Story

•

Business rule(s) == Acceptance criteria

•

Communication == Examples
Three layers of a User-Story

•

Business rule(s)

•

Communication == Examples == Acceptance criteria
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site

Scenario: Successful registration when visitor provides all the required info
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site

Scenario: Successful registration when visitor provides all the required info

Scenario: Unable to register when visitor misses required info
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site

Scenario: Successful registration when visitor provides all the required info

Scenario: Unable to register when visitor misses required info

Scenario: ...
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site

Scenario: Successful registration when visitor provides all the required info

Scenario: Unable to register when visitor misses required info

Scenario: ...
Scenario: ...
Scenario: ...
Scenario: ...
Scenario: ...
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site

Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
5. How to avoid
gold plating?
Delivery
Architecture
Architecture
HTTP layering
[GET] /products

Infrastructure

Legacy system
[GET] /products
[GET] /products/123

Infrastructure

Legacy system
[GET] /products
[GET] /products/123

New system

Infrastructure

Legacy system
[GET] /products
[GET] /products/123

New system

Infrastructure

Legacy system

New system
Implementation
Implementation
Full-stack BDD
Stories
Examples

Describe

Design

Implement
Stories
Examples

Describe

Scenario-BDD
Design

Implement
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site

Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Feature:
in order
as a
i need

Scenario: Successful registration when visitor provides
Given I am on the
When
And I fill in
And I submit it
Then
And I should be on the homepage

What could be automated
should be automated
assertEquals(Your Feature, Your App)
Setup
1. Dump your sprint features into text files
2. Put those text files into the `features/` folder inside
project
3. Install behat (via composer or behat.phar)
4. Initialize behat test suite by running `bin/behat —init`
Feature Context
<?php
!
use BehatBehatContextClosuredContextInterface,
BehatBehatContextTranslatedContextInterface,
BehatBehatContextBehatContext,
BehatBehatExceptionPendingException;
use BehatGherkinNodePyStringNode,
BehatGherkinNodeTableNode;
!
class FeatureContext extends BehatContext
{
}
First run
$> bin/behat
...
You can implement step definitions for undefined steps with these snippets:
!
/**
* @Then I should see :arg1
*/
public function iShouldSee($arg1)
{
throw new PendingException();
}

...
Append snippets
$> bin/behat --append-snippets
Feedback loop
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
TODO: write pending definition
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Stories
Examples

Describe

Scenario-BDD
Design

Implement
Colour it Red
Colour it red
/**
* @Given /^I am on the homepage$/
*/
public function iAmOnTheHomepage()
{
$crawler = new SomeCrawlerLibCrawler();
$crawler->goto(“http://localhost:8080/”);
if (200 !== $crawler->getCurrentStatusCode())
{
throw new RuntimeException(‘Can not open homepage’);
}
}
Colour it red
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
Can not open homepage (RuntimeException)
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Stories
Examples

Describe

Scenario-BDD
Design

Implement
Change the message
As quickly as possible
Change the message
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
Can not open homepage (RuntimeException)
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Change the message
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
Route … not found (FrameworkException)
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Change the message
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
Template … not found (FrameworkException)
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Change the message
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
When I follow “sign up”
TODO: write pending definition
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
behat.org
Change the message
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
Object `User` and its method `isRegistered` does not exist (RuntimeException)
And I should be on the homepage again
Stories

Spec-BDD

Examples

Describe

Design

Implement
Setup

1. Install phpspec via composer
2. use it
Stories

Spec-BDD

Examples

Describe

Design

Implement
Prepare your first spec
$> bin/phpspec desc Acme/Userbase/User
Describe your first message
<?php
!

namespace specAcmeUserbase;
!

class User extends ObjectBehavior

{
function it_is_registered_by_default()
{
$this->shouldBeRegistered();
}
}
Colour it red
$> bin/phpspec
!
Class “AcmeUserbaseUser” does not exist. Create? [Y/n]
y
!
Method `AcmeUserbaseUser::isRegistered()` does not exist. Create? [Y/n]
y
Stories

Spec-BDD

Examples

Describe

Design

Implement
Stories

Spec-BDD

Examples

Describe

Design

Implement
Stories

Spec-BDD

Examples

Describe

Design

Implement
phpspec.net
Verify feature
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Verify feature
$> bin/behat
!
Feature: registration
in order to maintain my shopping history
as a site visitor
i need to be able to register on this site
!
Scenario: Successful registration when visitor provides all the required info
Given I am on the homepage
When I follow “sign up”
And I fill in registration form
And I submit it
Then I should be successfully registered
And I should be on the homepage again
Stories
Examples

Describe

Design

Implement
#3: Income
6 months later…
#3: Same ashtrays, better car
We do that for clients
http://

.com

We do that for clients
And teach others in those rare
moments when we don’t

Moving away from legacy code with BDD