- •Contents
- •Preface
- •Acknowledgments
- •About the author
- •About the cover illustration
- •Higher product quality
- •Less rework
- •Better work alignment
- •Remember
- •Deriving scope from goals
- •Specifying collaboratively
- •Illustrating using examples
- •Validating frequently
- •Evolving a documentation system
- •A practical example
- •Business goal
- •An example of a good business goal
- •Scope
- •User stories for a basic loyalty system
- •Key Examples
- •Key examples: Free delivery
- •Free delivery
- •Examples
- •Living documentation
- •Remember
- •Tests can be good documentation
- •Remember
- •How to begin changing the process
- •Focus on improving quality
- •Start with functional test automation
- •When: Testers own test automation
- •Use test-driven development as a stepping stone
- •When: Developers have a good understanding of TDD
- •How to begin changing the team culture
- •Avoid “agile” terminology
- •When: Working in an environment that’s resistant to change
- •Ensure you have management support
- •Don’t make test automation the end goal
- •Don’t focus on a tool
- •Keep one person on legacy scripts during migration
- •When: Introducing functional automation to legacy systems
- •Track who is running—and not running—automated checks
- •When: Developers are reluctant to participate
- •Global talent management team at ultimate software
- •Sky Network services
- •Dealing with sign-off and traceability
- •Get sign-off on exported living documentation
- •When: Signing off iteration by iteration
- •When: Signing off longer milestones
- •Get sign-off on “slimmed down use cases”
- •When: Regulatory sign-off requires details
- •Introduce use case realizations
- •When: All details are required for sign-off
- •Warning signs
- •Watch out for tests that change frequently
- •Watch out for boomerangs
- •Watch out for organizational misalignment
- •Watch out for just-in-case code
- •Watch out for shotgun surgery
- •Remember
- •Building the right scope
- •Understand the “why” and “who”
- •Understand where the value is coming from
- •Understand what outputs the business users expect
- •Have developers provide the “I want” part of user stories
- •When: Business users trust the development team
- •Collaborating on scope without high-level control
- •Ask how something would be useful
- •Ask for an alternative solution
- •Make sure teams deliver complete features
- •When: Large multisite projects
- •Further information
- •Remember
- •Why do we need to collaborate on specifications?
- •The most popular collaborative models
- •Try big, all-team workshops
- •Try smaller workshops (“Three Amigos”)
- •Pair-writing
- •When: Mature products
- •Have developers frequently review tests before an iteration
- •When: Analysts writing tests
- •Try informal conversations
- •When: Business stakeholders are readily available
- •Preparing for collaboration
- •Hold introductory meetings
- •When: Project has many stakeholders
- •Involve stakeholders
- •Undertake detailed preparation and review up front
- •When: Remote Stakeholders
- •Prepare only initial examples
- •Don’t hinder discussion by overpreparing
- •Choosing a collaboration model
- •Remember
- •Illustrating using examples: an example
- •Examples should be precise
- •Don’t have yes/no answers in your examples
- •Avoid using abstract classes of equivalence
- •Ask for an alternative way to check the functionality
- •When: Complex/legacy infrastructures
- •Examples should be realistic
- •Avoid making up your own data
- •When: Data-driven projects
- •Get basic examples directly from customers
- •When: Working with enterprise customers
- •Examples should be easy to understand
- •Avoid the temptation to explore every combinatorial possibility
- •Look for implied concepts
- •Illustrating nonfunctional requirements
- •Get precise performance requirements
- •When: Performance is a key feature
- •Try the QUPER model
- •When: Sliding scale requirements
- •Use a checklist for discussions
- •When: Cross-cutting concerns
- •Build a reference example
- •When: Requirements are impossible to quantify
- •Remember
- •Free delivery
- •Examples should be precise and testable
- •When: Working on a legacy system
- •Don’t get trapped in user interface details
- •When: Web projects
- •Use a descriptive title and explain the goal using a short paragraph
- •Show and keep quiet
- •Don’t overspecify examples
- •Start with basic examples; then expand through exploring
- •When: Describing rules with many parameter combinations
- •In order to: Make the test easier to understand
- •When: Dealing with complex dependencies/referential integrity
- •Apply defaults in the automation layer
- •Don’t always rely on defaults
- •When: Working with objects with many attributes
- •Remember
- •Is automation required at all?
- •Starting with automation
- •When: Working on a legacy system
- •Plan for automation upfront
- •Don’t postpone or delegate automation
- •Avoid automating existing manual test scripts
- •Gain trust with user interface tests
- •Don’t treat automation code as second-grade code
- •Describe validation processes in the automation layer
- •Don’t replicate business logic in the test automation layer
- •Automate along system boundaries
- •When: Complex integrations
- •Don’t check business logic through the user interface
- •Automate below the skin of the application
- •Automating user interfaces
- •Specify user interface functionality at a higher level of abstraction
- •When: User interface contains complex logic
- •Avoid recorded UI tests
- •Set up context in a database
- •Test data management
- •Avoid using prepopulated data
- •When: Specifying logic that’s not data driven
- •Try using prepopulated reference data
- •When: Data-driven systems
- •Pull prototypes from the database
- •When: Legacy data-driven systems
- •Remember
- •Reducing unreliability
- •When: Working on a system with bad automated test support
- •Identify unstable tests using CI test history
- •Set up a dedicated continuous validation environment
- •Employ fully automated deployment
- •Create simpler test doubles for external systems
- •When: Working with external reference data sources
- •Selectively isolate external systems
- •When: External systems participate in work
- •Try multistage validation
- •When: Large/multisite groups
- •Execute tests in transactions
- •Run quick checks for reference data
- •When: Data-driven systems
- •Wait for events, not for elapsed time
- •Make asynchronous processing optional
- •Getting feedback faster
- •Introduce business time
- •When: Working with temporal constraints
- •Break long test packs into smaller modules
- •Avoid using in-memory databases for testing
- •When: Data-driven systems
- •Separate quick and slow tests
- •When: A small number of tests take most of the time to execute
- •Keep overnight packs stable
- •When: Slow tests run only overnight
- •Create a current iteration pack
- •Parallelize test runs
- •When: You can get more than one test Environment
- •Try disabling less risky tests
- •When: Test feedback is very slow
- •Managing failing tests
- •Create a known regression failures pack
- •Automatically check which tests are turned off
- •When: Failing tests are disabled, not moved to a separate pack
- •Remember
- •Living documentation should be easy to understand
- •Look for higher-level concepts
- •Avoid using technical automation concepts in tests
- •When: Stakeholders aren’t technical
- •Living documentation should be consistent
- •When: Web projects
- •Document your building blocks
- •Living documentation should be organized for easy access
- •Organize current work by stories
- •Reorganize stories by functional areas
- •Organize along UI navigation routes
- •When: Documenting user interfaces
- •Organize along business processes
- •When: End-to-end use case traceability required
- •Listen to your living documentation
- •Remember
- •Starting to change the process
- •Optimizing the process
- •The current process
- •The result
- •Key lessons
- •Changing the process
- •The current process
- •Key lessons
- •Changing the process
- •Optimizing the process
- •Living documentation as competitive advantage
- •Key lessons
- •Changing the process
- •Improving collaboration
- •The result
- •Key lessons
- •Changing the process
- •Living documentation
- •Current process
- •Key lessons
- •Changing the process
- •Current process
- •Key lessons
- •Collaboration requires preparation
- •There are many different ways to collaborate
- •Looking at the end goal as business process documentation is a useful model
- •Long-term value comes from living documentation
- •Index
Chapter 7 Illustrating using examples |
113 |
In summary, instead of using the categorization “nonfunctional requirements” to avoid a dificult conversation, teams should ensure they have a shared understanding of what their business users expect out of a system, including cross-cutting concerns. Even if the resulting examples aren’t easy to automate later on, having an up front discussion and using examples to make expectations explicit and precise will ensure that the delivery team focuses on building the right product.
Remember
•Using a single set of examples consistently from speciication through development to testing ensures that everyone has the same understanding of what needs to be delivered.
•Examples used for illustrating features should be precise, complete, realistic, and easy to understand.
•Realistic examples help spot inconsistencies and functional gaps faster than implementation.
•Once you have an initial set of examples, experiment with data and look for alternative ways to test a feature to complete the speciication.
•When examples are complex and there are too many examples or too many factors present, look for missing concepts and try to explain the examples at a higher level of abstraction. Use a set of focused examples to illustrate the new concepts separately.
8
Reining the speciication
‘‘In its rough form, a diamond is a lusterless, translucent crystal that resembles a chip of broken glass. For it to be transformed into a jewel, it ’’must be cut into a particular gem shape and then polished, facet by facet.
Collaborative discussion is a great way to build a shared understanding, but that isn’t enough to drive any but the simplest of projects. Unless the team is very small and the project is very short, we need to record this knowledge in a way
that doesn’t depend on peoples’ short-term memory.
Taking a photo of the whiteboard after a discussion on key examples is a simple way to capture this knowledge, but the examples are just raw material. Raw examples are like uncut diamonds—very valuable but not nearly as much as in a processed form. Separating real diamonds from rock, polishing them, and breaking them into sizes that are easy to sell increases the value signiicantly. The same can be said for the key examples we use to illustrate a requirement. They’re a great starting point, but in order to get the most value out of them we have to reine them, polish them to show the key points clearly, and create speciications that teams can use both now and in the future.
One of the most common reasons for failing with Speciication by Example is not taking the time to process these raw examples. Discussion about speciications often leads to experimentation. We discover new insights and restructure examples to look at them from a higher level of abstraction. This results in some great examples but also a lot of dead ends and rejected ideas. We don’t necessarily need to capture all these intermediary examples or record how we got to the result.
1 http://www.edwardjayepstein.com/diamond/chap11.htm
114
Chapter 8 Refining the specification |
115 |
On the other hand, just recording the key examples we want to keep without any explanation won’t allow us to communicate the speciication effectively to anyone who hasn’t participated in the discussions.
Successful teams don’t use raw examples; they refine the specification from them. They extract the essence from the key examples and turn it into a clear and unambiguous deinition of what makes the implementation complete, without any extraneous detail. This acceptance criterion is then recorded and described so that anyone can pick up the resulting speciication and understand it at any time. This speciication with examples captures the conditions of satisfaction, the expected output of a feature, and its acceptance test.
Specifications with examples are acceptance tests
A good specification, with examples, is effectively an acceptance test for the described functionality.
Ideally, a speciication with examples should unambiguously deine the required functionality from a business perspective but not how the system is supposed to implement it. This gives the development team the freedom to ind the best possible solution that meets the requirements. To be effective in these goals, a speciication should be
•Precise and testable
•A true speciication, not a script
•About business functionality, not about software design
Once the functionality is implemented, the speciication that describes it will serve a different purpose. It will document what the system does and alert us about functional regression. To be useful as long-term functional documentation, the speciication has to be written so that others can pick it up months or even years after it was created and easily understand what it does, why it’s there, and what it describes. To be effective in these goals, a speciication should be
•Self explanatory
•Focused
•In domain language
This chapter focuses on how to reine speciications to achieve all these goals. But irst, to put things into a more concrete perspective, I show examples of good and bad speciications. At the end of this chapter, we’ll reine the bad speciication by applying the advice given in this chapter.
116 Speciication by Example
An example of a good speciication
An example of a very good speciication with examples is shown here.
Free delivery
•Free delivery is offered to VIP customers once they purchase a certain number of books. Free delivery is not offered to regular customers or VIP customers buying anything else than books.
•Given that the minimum number of books to get free delivery is ive, then we expect the following:
Examples
Customer type |
Cart contents |
Delivery |
|
VIP |
5 |
books |
Free, Standard |
|
|
|
|
VIP |
4 |
books |
Standard |
|
|
|
|
Regular |
10 |
books |
Standard |
|
|
|
|
VIP |
5 washing machines |
Standard |
|
|
|
|
|
VIP |
5 books, |
Standard |
|
|
1 washing machine |
|
|
|
|
|
|
This speciication is self-explanatory. I often show this example to people at conferences and workshops, and I’ve never had to say a single word to explain it. The title and the introductory paragraph explain the structure of the examples so that readers don’t need to work back from the data to understand the speciied rule. Realistic examples are also there, to make the speciication testable and explain the behavior in edge cases, for example, what happens when someone buys exactly 10 books.
This is a speciication, not a script for how someone might test the examples. It doesn’t say anything about application worklow or session constraints. It doesn’t explain how the books are purchased, just what the available delivery mechanism is. It doesn’t try to talk about any implementation speciics. That’s all left to the developers to work out in the best way possible.
This speciication is focused on a particular rule for free delivery. It includes only the attributes relevant for that rule.
Chapter 8 Reining the speciication |
117 |
An example of a bad speciication
Compare the previous speciication to the example shown in igure 8.1. This is a great example of a very bad speciication.2
Simple Acceptance Test for Payroll
First we add a few employees
Employees |
|
|
|
|
|||
|
|
|
|
|
|
|
|
id |
name |
|
|
address |
salary |
||
|
|
|
|
|
|
|
|
1 |
Jef Languid |
10 |
Adamant St; Laurel MD 20707 |
1005.00 |
|||
|
|
|
|
|
|
|
|
2 |
Kelp |
Holland |
128 |
Baker St; Cottonmouth, IL 60066 |
2000.00 |
||
Next |
we |
pay them. |
|
|
|
||
|
|
|
|
|
|
|
|
Pay day |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pay |
day |
|
check |
number |
|
|
|
|
|
|
|
|
|
||
1/31/2001 |
|
1000 |
|
|
|
||
|
|
|
|
|
|
|
|
We make sure their paychecks are correct. The blank |
cellls |
will |
be |
illed in by the |
Paycheckinspector ixture. The cells with data in them |
already |
will |
be |
checked. |
Paycheck inspector
id amount number name date
11005
22000
Finally we make sure that the output contained two, and only two paychecks, and that they had the right check numbers.
Paycheck inspector
number
1000
1001
Figure 8.1 A confusing speciication
Although it has a title and some text around the tables, seemingly to explain what’s going on, the effect of that is marginal. Why is this document called “simple”? It’s payroll related, obviously, but what exactly is it specifying?
It’s not really clear what this document is specifying. We need to work backwards from the test data to understand the rules. It seems to verify that the checks are printed with unique numbers, starting from a number that’s given as a parameter. It also seems to validate the data printed on each check. It also explains in words that one check is printed per employee.
2 This |
example is from areal project and was previously |
included |
with FitNesse. We used it in |
||||
a workshop |
on |
reining the |
speciications |
in June |
2010 in |
London. As a result, the exa |
|
was |
changed |
in |
the FitNesse |
distribution. |
|
|
|
118 Speciication by Example
This document has a lot of seemingly incidental complexity—names and addresses aren’t really used anywhere in the document apart from the setup. Database identiiers appear in the tables, but they’re irrelevant for the business rules. The database identiiers are used in this example to match employees with the Paycheck Inspector, introducing technical software concepts into the speciication.
The Paycheck Inspector was obviously invented just for testing. When I read this for the irst time, I imagined Peter Sellers in a Clouseau outit inspecting checks as they go out. I’m sure that this isn’t a business concept.
Another interesting issue is the blank cells in the assertion part of this speciication, and the two Paycheck Inspector tables seem unrelated. This example is from FitNesse, and blank cells in that tool print test results for troubleshooting without checking anything. That effectively makes this speciication an automated test that a human has to look over—pretty much defeating the purpose of automation. Blank cells in FitNesse are typically a sign of instability in tests, and they’re a signal that something is missing. Either the automated test is hooking into the system in the wrong place, or an implicit rule is hidden there that makes the test results unrepeatable and unreliable.
The language used in the speciication is inconsistent, which makes it hard to make a connection between inputs and outputs. What is the 1001 value in the table at the bottom? The column header tells us that it’s a number, which is a technically correct but completely useless piece of information. The second box has a check number, but what kind of a number is that? What’s the relationship between these two things?
Presuming that the addresses are there because checks are printed as part of a statement with an address for automated envelope packaging, the test based on this speciication fails to verify at least one very important thing: that the right people got paid the right amount. If the irst person got both checks, this test would happily pass. If they both got each other’s salaries, this test would pass. If a date far in the future was printed on the checks, our employees might not be able to cash them, but the test would still pass.
Now we come to the real reason for the blank cells. Ordering of checks is not speciied. This is a functional gap that makes the system hard to test in a repeatable way. The author of this FitNesse page decided to work around that technical dificulty in the speciication, not in the automation layer, and created a test that gives false positives.
Without more context information it’s hard to tell whether this test is verifying one thing only. If the check printing system is used for anything else, I’d prefer to pull out the fact that check numbers are unique and start from a conigured value in a separate page. If we only print salary checks, it’s probably part of salary check printing.
We’ll reine this horrible document later in this chapter. But irst, let’s irst go over what makes a good speciication.