- •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
62 Specification by Example
When the developers got a story card, they’d very much want to deliver everything within it, to make it technically as fabulous as possible, even though the steer was “do the minimal thing possible to get the value given.” It’s got to be eficient, but we can always bring in the stories later to reine it. This was addressed using conversations and continually working out if we’re able to draw the business model that we’re trying to achieve. By domain modeling you can very easily break down this into tasks. Those tasks are then the only thing you can do. Because the tasks are small, you can go off on one of them, but if you do it’s very easily spotted by the rest of the team and the team would speak up. When someone’s been on a task for several days, we’d have that conversation in the standup.
Watch out for people who implement more than what was agreed on and speciied with examples. Another good way to avoid just-in-case code is by discussing not only what you want to deliver but also what’s out of scope.
Watch out for shotgun surgery
Shotgun surgery is a classic programming antipattern (also called code smell ) that occurs when a small change to one class requires cascading changes in several related classes. This telling sign can be applied to living documentation; if a single change in production code requires you to change many executable speciications, you’re doing something wrong. Organize your living documentation so that one small change in code leads to one small change in tests (see “Listen to your living documentation” in chapter 11 for some good tips on how to do so). This is one of the key steps to reducing maintenance costs of automation over the long term.
Remember
•Speciication by Example is a good way to provide development teams with just-in-time speciications, so it’s a key factor for success with short iterations or low-based development.
•Handle small chunks of software eficiently to enforce quick turnaround time and feedback.
•Emphasize effective, eficient communication instead of long, boring documents.
•Integrate cross-functional teams where testers, analysts, and developers work together to build the right speciication of the system.
•Plan for automation overhead upfront.
PART 2
Key process patterns
5
Deriving scope from goals
The F-16 Fighting Falcon is arguably the most successful jet ighter ever designed. This is all the more remarkable because it succeeded against all odds. In the 70s, when the F-16 was designed, jet ighters had to be built for speed;
range, weaponry, and maneuverability were of little importance to get a production contract.1 Yet it was the range and maneuverability of the F-16 that made it ideal for its role in combat and ensured its success.
In 97 Things Every Architect Should Know,2 Einar Landre quotes Harry Hillaker, the lead designer of the F-16, saying that the original requirement for the aircraft was that it reach speeds of Mach 2-2.5. When Hillaker asked the U.S. Air Force why that was important, they responded that the jet had to “to be able to escape from combat.” Although Hillaker’s design never got above Mach 2, it allowed pilots to escape from combat with superior agility. It featured many innovations, including a frameless bubble canopy for better visibility, a reclined seat to reduce the effect of g-forces on the pilot, a display that projects combat information in front of the pilot without obstructing his view, and side-mounted control sticks to improve maneuverability at high speed. With these features, the F-16 was superior to alternative designs—and less expensive to produce. It won the design competition. More than 30 years later, it’s still in production. With more than 4,400 aircraft sold to 25 countries,3 the model is a great commercial success. It’s also one of the most popular ighter jets and is often featured in action ilms, such as X2 and Transformers: Revenge of the Fallen.
The F-16 was successful because the design provided a better and cheaper solution than what the customer asked for. The original requirements, including the demand for Mach 2.5 speed, formed one possible solution to a problem—but this problem wasn’t
1 |
See |
Kev Darling’s bookF-16 Fighting Falcon (Combat Legend) (Crowood Press, 2005). |
2 |
Richard Monson-Haefel,97 Things Every Software Architect Should Know (O’Reilly Media, |
|
|
2009). |
|
3 |
See |
http://www.lockheedmartin.com/products/f16 |
|
|
65 |
66 Speciication by Example
effectively communicated. Instead of implementing the requirements, the designers sought a greater understanding of the problem. Once they had it, they could pinpoint the real goals and derive their design from those, rather than from suggested solutions or arbitrary expectations about functionality. That’s the essence of successful product design, and it’s just as important in software design as in aircraft development.
Most of the business users and customers I work with are inclined to present requirements as solutions; rarely do they discuss goals they want to achieve or the speciic nature of problems that need solutions. I’ve seen far too many teams suffer from the hazardous misconception that the customers are always right and that what they ask for is set in stone; this leads teams to blindly accept suggested solutions and then struggle to implement them. Successful teams don’t do this.
Like the F-16 designers, successful teams push back for more information about the real problem and then collaborate to design the solution. They do this even for scope. Scope implies a solution. Instead of passing the responsibility for deining scope onto someone else, successful teams are proactive and collaborate to determine good scope with the business users, so that their goals are met. This is the essence of deriving scope from goals.
Collaborating on deriving scope from goals is undoubtedly the most controversial topic in this book. In the last ive years, the surge in popularity of value chains in software development has increased awareness of the idea of collaborating on scope and deriving it from business goals. On the other hand, most teams I work with still think that project scope isn’t under their control and expect customers or business users to fully deine it. In the course of my research for this book, I found a pattern of teams deriving their project scope from goals collaboratively—but this practice is much less common than other key patterns.
I originally thought about leaving this chapter out. I decided to include it for three reasons:
•Deining scope plays an important role in the process of building the right software. If you get the scope wrong, the rest is just painting the corpse.
•In the future, this will be one of most important software development topics, and I want to raise awareness about it.
•Deining scope its nicely into designing processes from value chains, which are becoming increasingly popular because of lean software development.
In the following two sections I present techniques for inluencing scope for teams that have direct control over it and for teams that don’t. Teams that have high-level control of their project scope can be proactive and begin to build the right scope immediately. Unfortunately, many teams in several of the large organizations I work with don’t have that kind of control—but this doesn’t mean they can’t inluence scope.