Tim Ottinger & Jeff Langr present the blog behind the versatile
Pragmatic Programmers reference cards.
Weinberg's (First Three) Laws of Consulting
Font: AndrewScript 1.6
Source: Gerald M. Weinberg, The Secrets of Consulting
I re-read Gerald Weinberg's book The Secrets of Consulting (Dorset House, 1985) once every year or two. The first time I read it, about a dozen years ago, half of it seemed obvious while the other half seemed counter-intuitive. But I discovered that I too often ignored its obvious advice (i.e. "common sense"), and that its counter-intuitive advice is spot on.
Weinberg spills so many secrets ("give away your best ideas" being one of them) that it seems unfortunate to mention only the first three (and their corollaries), but getting past these is key to understanding the rest. And yes, I highly recommend getting a copy of the book so that you can discover the rest of the secrets, even if you don't consider yourself a consultant. Substitute "problem solver" or "agile coach" for "consultant," and most of the book will apply equally well (except perhaps the parts about marketing and pricing).
I actually lost a potential new client because of my inattention to the first law, or more specifically to its corollary. After having a phone conversation about the client's interest in transitioning to XP (this was about 5 years ago, when people still uttered the term XP), I met with the leadership team at their offices. On the phone, the person looking to bring me in talked about some of the serious challenges they had. But when I arrived, I heard little about these serious problems, only some vague notions that they wanted to improve how they did things.
Never mind, I was too wrapped up in my grandiose scheme to solve all problems for them using XP. I mentioned the challenges I had heard about on the phone, and indicated that I'd be able to help them fix it all. "What makes you think we have such serious problems?" Oops!
What Weinberg points out is that it's very difficult for us to admit it when we have serious problems. I didn't get the gig, because were I to have waltzed in and solved many large problems, it would have been far too embarrassing for the people in that room. Since then, I've promised as much improvement as their pride is willing to admit--per Jerry, 10%. (Of course, there's nothing that says you can't deliver more, as long as you are cautious about who gets the credit--see rule #3). Just last week, I found the rule to be dearly applicable in my personal life.
As far as the second law is concerned, we all tend to follow comfortable patterns, and this is often the cause of the problem: Once you're in a rut, it can be hard to get out. "We've always done things this way, that's just the way it has to be." The trick for a consultant is to help someone get out of a rut--which requires a change in direction--without themselves starting to fall into the same rut. You don't want to stay in one place too long as a consultant.
Some people have found Weinberg's "secrets of consulting" to be nothing short of greedy and cynical. They suggest the third law is all about taking as much money as possible from the client on an hourly basis. But Weinberg points out that this notion of not getting paid by the solution hearkens back to the first law: A solution expensive enough to require a consultant requires a problem too big to admit. Is it cynical to work in a manner that meshes realistically with normal human behavior? I don't think so.
I hadn't looked at The Secrets of Consulting in about two years. That's evidence of the rut I was tracking in. I've recently been shoved out of my rut, and I am thankful that someone reminded me (with the utmost subtlety) to revisit the book. I'm looking forward to re-amplifying my impact!
Stopping the Bad Test Death Spiral
Fonts: Daniel, Daniel Black
Source (SCUMmy Cycle): Ben Rady, Rod Coffin of Improving Works from their Agile2009 presentation.
Source (Remedies): Tim Ottinger & Jeff Langr
The "SCUMmy Cycle" is all-too-common. A team with legacy (untested) code tries TDD hoping they will be able to continue making improvements. First efforts result in integration tests, perhaps because the code is tightly coupled and not cohesive. The team intends to someday replace them with proper unit tests. A team lacking essential understanding of the qualities of a good unit test will write integration tests unwittingly.
Months or years later the tests are abandoned, with a significant investment in their construction and maintenance having gone to waste. How does this happen?
Here's how the cycle generally plays out:
- Only integration tests are written. One common cause: business logic is intertwined with UI or database code, perhaps as a reflection of examples found in framework and library tutorials.
- More tests are added, until running them is slow/painful. Fifty to 100ms to interact with a database doesn't seem bad. But multiply that by a few hundred or thousand tests, and a even small test suite execution takes several minutes.
- Tests are run less often because developers can't afford to run them. Developers will resist running ten-minute test suites more than a few times a day. Less-frequently-run tests are much harder to resolve when they fail. Large tests tend to be fragile and fail intermittently. They have runtime dependencies on external elements that are not controlled by the tests, and perhaps dependencies on side-effects other tests.
- Tests are disabled because they are unreliable, obsolete from lack of maintenance, or simply too slow to tolerate.
- Bugs become commonplace just as they were before the team started doing automated testing. Disabling too many tests lowers coverage and the remaining tests become ineffective.
- Value of automated testing is questioned--"we're no better off than before!" And yet the team still wastes time writing and (sometimes) running tests.
- Team quits testing in disgust, or managers mandate a stop to testing. The experiment is deemed an expensive failure. Teams are now free to return to the good old days of rapid coding and expensive manual testing. As W. Edwards Deming said, "Let's make toast the American way: I'll burn, and you scrape."
One possible lesson: it's cheaper to have no tests than to have bad tests. A better lesson: life is too short to settle for crummy tests.
The flip side of this card lists some therapeutic strategies for each downward step:
- Only integration tests are written -> Learn unit testing. This also ties in with a better understanding of (and adherence to) the SRP and LoD. Consider hiring a short term coach to teach healthy habits in the team, or invest in better reading materials and the time to absorb the material. Attend a training session.
- Overall suite time slows -> Break into "slow/fast" suites. Establish a time limit for the fast suite, and strive to keep the fast suite large and fast. Thousands of unit tests can easily run in under 10 seconds. Consider a tool like Infinitest to help keep tests running fast (but note that everything works better in a system that exhibits low coupling).
- Tests are run less often -> Report test timeouts as build failures. The measures you institute will be arbitrary, but the key focus is on continually monitoring the health of your test suite. If the suite slows dramatically, developers will soon skimp on testing.
- Tests are disabled -> Monitor coverage. New functionality should have coverage in the mid-to-high-90% range, and the rest of the system should exhibit stable or increasing coverage. System changes resulting in reductions in coverage should be rejected. Integration tests provide broad coverage, but you should either replace these with unit tests or elevate them to acceptance tests. You should otherwise delete disabled tests.
- Bugs become commonplace -> Always write tests to "cover" a bug. These tests should always be written first, a la TDD. A defect is evidence of inadequate test coverage. Make sure you always track defects and understand the root cause of each and every one! Insist that these tests be fast tests.
- Value of automated testing is questioned -> Commit to TDD, Acceptance Testing, Refactoring. Committing to TDD means learning how to do it properly--it is of low or negative value otherwise! Also note that many "regressions" are rooted in code duplication. Refactoring to eliminate duplication is critical for quality improvement. It is reasonable that a quality crisis causes a reduction in new features production.
- Team quits testing in disgust -> Don't wait until it's too late! If a team's gotten to this point of admitting defeat, it's often too late--management won't normally tolerate a second attempt at what they think is the same thing.
If you must self-coach, then ensure that team members don't view TDD as simply "management forcing programmers to test their code." Ensure that programmers understand the significant design and documentation benefits that TDD can deliver. Ensure they understand the scalability advantages of fast automated tests over manual testing.
A team that understands TDD and strives to attain the benefits it offers will avoid the Bad Test Death Spiral.
Test SCUM
Font is "Pen of Truth"
Source is Ben Rady and Rod Coffin of Improving Works, given in an agile presentation at Agile2009.
In sharp contrast to the FIRST principles of good unit tests, Rady and Coffin give us these properties of completely bad (scummy) unit tests.
- Slow: We discussed now important speed is in unit tests. I find that when tests are more than 40 seconds, people have to decide to run them, rather than feeling free to run them immediately after every small step. Rady's Infinitest runs tests automatically and analyzes the tests to selectively exclude those which have no (discernable) transitive dependency on the system under test, just to eek out some extra speed. While it is preferable to run all the tests all the time, in many circumstances culling the unrelated tests will give back some speed.
Tests are generally slow because thy provide insufficient insulation from the environment. They tend to spend a lot of time waiting on clocks, file systems, databases, web services, or the like. Slow tests are best rewritten with isolation from the environment.
How fast is fast? I find that I can tolerate a usefully large battery of tests if each of them takes about .002 seconds. I can tolerate any number that starts with a dot and two zeroes. I might be able to tolerate a very few with only one zero immediately after the dot. More than that is "slow". It doesn't take many multi-second tests before developers feel reluctance to run them. - Confusing: We have emphasized that good tests isolate errors and their causes. A confusing test is one that fails to isolate a specific error. This may be because it has too many things going on, or because it is simply unreadable. It is preferable that the combination of the test class name, the test method name, and the assertion gives all the information a developer needs in order to correct a misstep. In a confusing test, those three items are not enough an the entire body of the test may not shed light on the failure mode. Confusing tests are best rewritten as smaller, more clear tests.
- Unreliable: Tests should be repeatable: they should always fail the same way, or always pass for the same reasons. Tests that run only in isolation or on certain days or times of day are not reliable tests. One of the best ways to judge reliability is to run tests repeatedly. Note that overspecification often causes tests to fail in unexpected and non-useful ways.
- Missing: The tests that you don't run provide you no benefit, and quite a bit of harm. Tests help you to design your production code, and also help you to tell if you are making decisions that break the system in unexpected ways. Not having the tests means that you just don't know. Maybe your design is iffy in ways you hadn't noticed. Maybe you've broken other code with your last line of code. Maybe the behavior you hand-verified last hour is no longer occurring as you expected it to. The tests you did not write are the ones that are really holding back your productivity.
12 Principles for Agile Software Development
Font (once again): MechanicalPencil
The canonical source for these principles is the agile manifesto website.
These are the basic agile principles, abbreviated to fit onto a 3x5 card without requiring the reader to hold a magnifying glass. They are "sound bites" and not the whole story. Each of these principles can (or has) launched myriad blogs/articles, and indeed many of the other Agile in a Flash cards touch on these principles. We could easily build a distinct card for each, though that would inflate the size of our eventual card deck quite a lot.
It has long been Tim's perspective that Agile is about having a short reach so we are allowing that point of view to color our summary of agile principles.
- Satisfy the customer through early and continuous delivery--We shorten the distance between requirements gathering and customer feedback. The period is shorter because we plan less change at a time, and in return we get more opportunities to steer the software in a direction the customer appreciates. Notice that the principle actually says "continuous delivery", not just "quarterly" or "bimonthly." Early and continuous delivery is not about working faster, only about working sooner.
- Welcome changing requirements, even late in development--We shorten the distance between conceiving and implementing an important change. We don't have to wait for a redesign of the whole system, or for the next system to be built. This is not to say that no features will be delayed; feature requests are frequently reordered or even dropped. The agile difference is that such changes take effect sooner.
- Deliver working software frequently--We shorten the distance between the system-as-designed and the system-as-built. Both will evolve as we learn more about the system as it should be built. We also shorten the distance between planning and delivery, giving more opportunity to improve the efficiency and effectiveness of our work.
- Business people and developers work together daily--We shorten the physical distance between a question and its answer. Moving the customer to a different building, area, room, or even to a cubicle just around the corner dramatically reduces the number of questions we ask the customer. With collocation, the business and technology sides learn to better understand each other and to make more mutually-beneficial decisions.
- Build projects around motivated individuals--We shorten the distance between intent and action. The goal is to build an agile team of skilled professionals who care about all the business concerns including schedule and content, and who will work in a highly-engaged and result-oriented way. Such individuals need no babysitting and very little direction. Such a team will refused to be blocked, and will produce their best work at all times. Management does not have to spend time on motivational issues or "cat herding" so common to less-motivated teams.
- Convey information via face-to-face conversation--We shorten the time between a question and its answer. Agile teams work in bullpens because it makes it much easier to ask questions and offer suggestions. Things that should be communicated get communicated, not forgotten, diluted, or otherwise insufficiently communicated. While there are many attempts to go agile without co-locating team members, we are not aware of any which have the kind of success which is typical in co-located teams.
- Working software is the primary measure of progress--We shorten the distance between thinking we're done and knowing we're done. The team should be judged by the product it produces, not by the rate of typing or number of degrees, or hours worked per month, or how quickly the members walk from the parking lot, or how quietly they work from their individual cubicles. A good team frequently produces quality software the customer wants. All other measures are subordinate or irrelevant.
- Maintain a constant pace indefinitely--We shorten the distance between productive bursts. This doesn't mean that management sets a large minimum hour limit for developers to endure months or years at a time. Excessive overtime cannot continue indefinitely without severely impacting quality. Instead, we choose a pace that allows us to go home tired and satisfied in the evening, and then return fresh and ready to rock in the morning. For normal people with families and bodily needs, that pace will not be 90 hours a week, and it probably won't even be 50 hours a week. We are never impossibly far from our life-sustaining relationships and activities.
- Give continuous attention to technical excellence--We shorten the distance between implementation and ideal. An agile developer is never more than a few minutes away from the last time all the tests passed. Collaborating classes are not at the opposite ends of long chains of contains/references/inherits relationships (e.g. "train wrecks"). Developers need not wait to clean up redundant or confusing code. If working code is the measure of agility, then excellent code must be defined as code that accepts changes gracefully. An agile team takes steps to ensure that code gets better with each iteration.
- Simplify: maximize the amount of work not done--We shorten the distance between comprehension and completion. We eschew things that don't matter. If we're less encumbered by unhelpful tasks and unwanted features, we've shortened the reach to useful work. We also attempt to simplify code (reducing the amount of reverse-engineering other programmers must do). Agile programmers tend to follow the rules of simple design.
- Teams self-organize--We shorten the distance between need and action. We don't wait around to be told who does what. We do what needs to be done, not waiting for direction or supervision. We attack problems with fervor, mitigating risks and clearing obstacles.
- Teams retrospect and tune their behaviors--We shorten the distance between introspection and adaptation. Improvement is never far away. Each iteration, we explicitly find ways to improve process simplicity, code quality, technical excellence, and predictability of results. We analyze problems and obstacles, and look for root causes and their solutions. We actively plan to use better techniques, tools, and process flows. We act on the plan in the subsequent iteration, without delay.
These principles are fairly simple in concept, but are profoundly deep in practice. If you are transitioning to an Agile work style or are looking for ways to improve your current Agile practice, we suggest you begin again with the principles espoused here.
Essential Unit Test Cards
- F.I.R.S.T.
- The Three Rules
- Red Green Refactor
- Characterization Tests
- TDD Smells
- Ice Breakers
- Antipatterns
- Why Test-After Sucks
Plan-Do-Check-Act
Font: Daniel Black
Thanks to Igor Czechowski for suggesting this card.
At the core of agile is short cycles of Plan-Do-Check-Act (PDCA). These steps are also what it means to be scientific in approach, at least per the definition of science that says you are following the scientific method: hypothesize, experiment, evaluate. Those who say agile isn't disciplined have not made this connection.
Plan-Do-Check-Act is echoed in agile practices, particularly TDD. The Plan step is about "making the expected output the focus," per Wikipedia. Writing a test that first fails captures your plan. After observing test failure, Do means you write enough code to make the test pass, and Check tells you to verify the actual results against the expected output. If there are differences you must Act to determine their cause and correct your implementation (or sometimes your expectations). In any case, you must also Act by observing the changes to the environment--the rest of the system--and "determine where to apply changes that will include improvement," which can mean some doing some incremental refactoring.
The iterative-incremental development core of agile also follows the cycle:
- Plan - iteration planning/definition of acceptance tests
- Do - day-to-day iteration execution
- Check - verification of results using acceptance tests
- Act - retrospectives and subsequent planning
As with many of the best modern ideas for quality control, PDCA in part comes from Dr. W. Edwards Deming. While Deming credited Walter Shewhart for the original concept of PDCA, Deming gets credit for popularizing the cycle.
Naming Fail or Comment Fail?
/// Adds Sessions which fit in specified date-time range
private void ReadSessions() {
Abbreviations
Font is Mechanical Pencil
Source: Vadim Suvorov, Tim Ottinger
When can we use abbreviations as names in our source code? Can we ever use abbreviations as variable names? Vadim and I explored this issue, and Vadim in his orderly way of thinking enumerated these these principles. I'm sure that not everyone will find these to his liking, but I think these principles are well-reasoned and sufficient. I think these nest nicely into my naming rules in general, though my preference is to avoid any kind of encodings.
- Shared, not Personal: the abbreviation should not be something the author has invented, and which other programmers will not recognize on sight.
- Consistently Used: the abbreviation is not punned, so that it means one thing in one context and another thing entirely in a different context. Note that a very short abbreviation has a greater likelihood of collision (fn = function or filename or ...?).
- Must Be Justified: If the programmer is to use abbreviations, then he should have clear reasons why the abbreviation is required. If, for instance, the abbreviation helps the reader see the unique part of the name without being distracted by context warts (prefix ofr suffix). My addition here is in the case of parallel names Persistant.User v. Domain.User if only one name is present, then no prefix is justifiable. My partner in this enterprise may not agree (likely with well-considered reason).
- Special Latitude Given for Domains: in solution domains, some abbreviations are common and it is beneficial for the programmers to know them. If I worked with military jet software and didn't know IFF, or in education and didn't understand ILT, or if I worked in accounting and didn't grasp AP or AR then I would be less effective when communicating with the Business/Customer.
To the extent that your team deems to use abbreviations, we recommend these criteria for your consideration. Clean naming is one of the most important factors in writing understandable code, and has no negative effect upon compilation or runtime speed, and so is very precious to me. Yet, in the appropriate context, I am open to sacrificing the "no encodings of any kind" rule to appropriate use of well-reasoned abbreviations, with the caveats given above.
Planning Poker (R)
Source: Wikipedia
Font: AndrewScript 1.6
Planning poker, trademarked by Mike Cohn, is a modernizing of a 50+-year-old estimating process known as Wideband Delphi. Estimating is not far from the dark arts, and attempts to make the process serious and exacting are ill advised. James Grenning devised planning poker as a quick and entertaining way to come to consensus on estimating stories in agile. I've found it can help dramatically minimize the tedium of estimating through a large stack of stories.
A typical point scale might be 1, 2, 3, 5, 8, 13. Resist larger scales--toss the higher-value cards. You might replace them with one card that says "too big."
You might want to include a few additional cards: 0, ? ("I don't have clue"), and infinity. The value of adding a 0 card is debatable (nothing is free, and even if development is "free," testing a story is never free), but you may find some usefulness in having it: Sometimes, completing one story automatically includes another. Or, a story might simply represent a milepost achieved.
The wikipedia site provides good detail on the steps involved, but I highly suggest you make your own rules and stick to them. The section on anchoring is particularly useful: part of the reason James devised planning poker was to counteract the heavy influence on estimates coming from one individual. Make sure that when people divulge their card selection, they aren't watching and waiting on certain other individuals to show theirs first!
Before starting the meeting, figure out how long you'd like to spend estimating. If your backlog of stories looks pretty good, and there's a good understanding of the project by most people in the room (obviously not always the case), you might find that 5 minutes per story works well. Appoint a facilitator who can keep time and help keep the estimating session on track.
If the product you're building is less well-known to the participants, this process will take considerably longer, maybe 10-15 minutes per story. Do the planning poker estimates, regardless, and plan on doing them again during a quicker second meeting. If you feel like you are bogging down on a story, and understanding of it is not "critical path," set it aside, and plan to come back to it after other stories are visited.
For a backlog of not-well-understood stories, you will probably want a couple sessions. Some stories will need to be set aside to split or researched offline. Some stories will need to be revisited by the customer. One of the best things to do is give people time to go off and think about things (and having at least one night between sessions is always a good idea).
Still, you want to avoid investing too much time in estimation. The more time you invest, the higher the expectation that the numbers coming out of it are anywhere near perfect. Estimates are guesses!
Instead, the estimation meeting is best seen as a way to ensure that we have good, appropriately sized stories that are fairly well understood by everyone involved. The consensus mechanism in planning poker will quickly let you know if this is not the case. Getting confidence from a good ballpark project plan is almost a bonus!
Principles of Package Cohesion
Post: Tim & Jeff
Source: Uncle Bob
Font: Segoe Print
Coupling and cohesion are the two most important principles guiding the quality of an object-oriented class design. Most programmers learned about these principles in their first week of exposure to OO. The rise of TDD has helped reinforce the value of low coupling and high cohesion (although many programmers still unconsciously and even consciously resist truly small, cohesive classes and methods).
Uncle Bob teaches us that these core OO principles apply equally to packages. The Agile in a Flash card for Principles of Package Coupling covers the dependency side of the dynamic duo--how do you structure packages so as to improve the coupling relationships between them? This card covers the other side--how should you compose a package? What is the definition of "cohesive," as it applies to packages?
- The Reuse-Release Equivalence Principle (REP) - The REP tells us that classes should be packaged together because they are used together. This seems obvious, but many package structures are instead based around ideas like "functional areas," "architectural layers," or "originating team." The result? Users are inconvenienced, for example, by having to recite a litany of import lines at the top of each file. REP tells us to consider the destination instead of the source or even the structure of the code itself. It urges us to group things together for user convenience.
An entire system shoehorned into a single package/library would comply with this principle. But if the rate of change in the library was not extremely low, it would suffer from the problems addressed by the remaining principles.
- The Common-Reuse Principle (CRP) - This almost seems like a restatement of the REP, but the emphasis here is on limiting the impact to consumers. Imagine an API package with two sets of reusable class clusters. A programmer might choose to consume only one reusable component, but changes to the other component necessitate redistribution of the entire package. An unwanted release unnecessarily burdens the consuming programmer, who must re-integrate and re-test the entire library in order to stay current. Where the REP leads us to conglomerate, the CRP leads us to split packages apart. This tension between the principles leads us to find the level of granularity that provides greatest convenience (least negative impact) to users.
In spirit, the CRP is a package-level restatement of the Interface Segregation Principle, which says to keep interfaces small and focused for similar reasons.
- The Common-Closure Principle (CCP) - The CCP is an application of the Open-Closed Principle at the next level up. This principle suggests that you should group your classes around the impact of change. A change should optimally impact only one package; as many other packages as possible should be closed to that change. This varies from the other two principles as it recommends grouping classes around the way the code is maintained, rather than the way it is used. Modules with a high rate of change might need to be grouped by closure rather than by use. Highly stable packages might be better conglomerated (REP).
The principles of package cohesion are not absolute. Sometimes a packaging may satisfy all three principles at once, but often the principles represent competing principles. The development team will have to make trade-offs in order to find a balance that works. In general, smaller (and even smaller) packages provide the best chance for adherence to the CCP and CRP principles, although the REP says there is a limit to how small you will want to go.
Following these principles will require occasional re-packaging, which is upsetting to many users. However, correcting less-than-optimal packaging is a single deep cut that can halt the "death of a thousand paper cuts" caused when changes ripple across packages, or when users of a package have to deal with frequent irrelevant updates.
TDD Antipatterns
- The Liar is a test that runs, but does not test what it claims to test. It could be named after a class, but actually be testing another. The test might be called ShouldNotThrowExceptionsForPositiveValues, but actually use the natural numbers less than 5. Liars give a false sense of security.
- Excessive Setup is common when the architecture is badly coupled and mocking is not well-used. This is often evidence of insufficient pre-factoring. A little dependency injection and a little interface use can go a long way. This is also common when programmers give in to the urge to test software "in context." One hopes that when they get to the assert they'll remember what scenario they were testing.
- The Giant is a single test that tests more than a single scenario. It may have excessive setup, but then follow with a large number of manipulations and assertions. It may test entire subsystems. Adding a new assertion requires a programmer to reverse-engineer his way through the Giant to find an assertion insertion point, and requries the programmer to exercise care to not leave side-effects that will cause the last half of the Giant to fail. Giants are ticklish and hard to understand.
- The Mockery is a real piece of work. A pair/team/programmer has actually replaced the system under test with a test double. The test proves only that the mocks worked as expected.
- Generous Leftovers are left behind by tests that dont clean up after themselves and cause later tests to fail when run in the suite but not when run in isolation. The leftovers are typicall in static memory, on disk, in a database (for shame!) or some other persistent store. When leftovers are found, it's often puzzling whose they are, and what they are.
- Local Hero is a test that runs well, and tests a system well, but only passes on the author's machine or network. Being environmentally-sensitive, such tests fail for peers and CI systems. Typical failures involve hardcoded paths, locally-installed libraries, and OS-specific assumptions.
- The Loudmouth is a test that produces copious output. It is like the boor at the party who thinks every trivial event in his live is worthy of an epic tale. At one time, the loudmouth's story may have been worth hearing, but now it's just idle chatter that gets in the way of a real conversation with more interesting guests/tests.
- The Secret Catcher is a test that seems to do nothing at all, but is secretly (implicitly) depending on any errors to produce exceptions. The fact that the code executed without exception is expected to evidence that the code works. These tests can eventually be reverse-engineered by every programmer on the team. Failure of the test always results in code spelunking, an unpopular passtime.
- The Hidden Dependency is a test that secretly requires setup that is not present in the test itself. Perhaps it requires a certain data setup script, or a change in a configuration file, or another test to have already run with generous leftovers. Hidden Dependency tests are a special kind of evil.
- The Stranger is a perfectly good test in a perfectly wrong place. It is not a liar, it's just not testing the same system (SUT) that the other tests are testing. Strangers don't cause problem except when you're looking for tests for class X and it's hiding among the tests for class Y.
- Success Against All Odds is a test that will always pass, no matter what. Due to a series of missteps, the test won't fail even if the code is wrong. Often these turn into complicated indirect versions of "assert true == true" or "false == false". These can be a variation on Mockery or The Liar. It is likely that a test with Success Against All Odds was written as a green test, without ever having seen the "red" part of the Red->Green->Refactor loop.
- The Slow Poke is a test that takes too long to run. If you have 15000 tests, and you want them to run in less than 45 seconds, you have a budget of 0.003 seconds per test. A five-second test will cause some irritation. A few 10-second tests will make people think twice about running the tests at all. A test that takes a minute is unlikely to ever be run by a programmer. Imagine what hell awaits the author of some of the three-to-ten minute monstrosities that exist in the wild! In a TDD shop, slow pokes cannot be tolerated. Note that many slow pokes are also Giants with Excessive Setup. Be warned.
What is missing?
Pairing Workstation Configuration
(font is SD Marker still)
Teams beginning to use pair-programming often struggle because of poor workstation configuration as they attempt to use their individual programming space. There is more to it than merely adding a second chair. Take a moment to review Pair Programming Smells and recall that there are physical limitations as well as psychological limitations to overcome.
Pair programming is not a utopian practice. Some people don't enjoy it at first, and some never warm up to it. Regardless, it makes the code better. If your team wants to make the code better through pair-programming, then it is important that their attempts are not hobbled by a poor workstation configuration. For a little bit of money, a leader can make a big difference in the way a company puts out software.
SMART goals
Font: Sterofidelic
The best lists never die. The SMART mnemonic has been around for at least half a century, per Wikipedia. SMART is similar to INVEST, evaluating criteria for goals and objectives instead of for stories.
SMART has generated many different word expansions over the years. Sometimes M is meaningful, manageable, or even motivational(!). Our Agile in a Flash card uses the supposedly preferred words. But as a result of this inconsistency, I struggled yesterday to recall the best choice for the letter R. "Realistic?" No, that's too close in meaning to attainable. A quick search revealed relevant (duh!). I supplanted my mild self-annoyance (at my inability to remember the better choice) with elation at the prospect for a new, relevant agile card!
In the context of agile, I've found SMART goals to be useful when discussing action items to come out of retrospectives. True, there's no reason these couldn't be treated just like INVEST stories. But I've found that selling something half-a-century-tried-and-true can be a little easier with some crowds.
Here are my thoughts about the relevance of the SMART criteria with respect to retrospectives.
- Specific - Vague promises of improvement usually don't generate results. Think of the 5 W's: who, what, when, where, and why. Instead of "we'll try to get stories done earlier in the iteration," how about "the developers will deliver at least one story every two to three days to QA, who will complete testing of them within a day of delivery, so that we can ensure stories are 'done done' by iteration end." (And don't forget that "try" is a word you want to banish.)
- Measurable - Attainment of our specific example goal might be validated by answering some questions: What was the average number of stories completed within two to three days? How many stories did not complete in this time? You can think of iterations as fixed time periods in which to run experiments; you can express a hypothesis that validates or disproves the value of each experiment by capturing relevant data.
- Attainable - It's important that a team can check off completed goals, to reinforce the sense of achievement. Obviously goals that your team can complete in an iteration best meet this criterion, but you don't want to have only short-term goals. There's nothing wrong with long-term goals; just make sure there's a way to measure incremental progress.
- Relevant - Too many trivial goals can give a bloated sense of achievement. Shortening daily stand-up meetings by limiting them to five minutes might seem beneficial, but does it really change anything? What's the real problem? Don't hesitate to attempt dramatic changes, and don't hesitate to think outside the box that pseudo-agile dogmatists might otherwise paint you in.
- Time bound - Like stories, many teams tend to have a problem with letting things creep past iteration boundaries. "We just need a little more time." Set up the experiment, define completion and success criteria, and grade the experiment: it was either completed or abandoned, and the hypothesis either held true or was disproved.
Get SMART today!
Team Smells for Coaches
Every agile coach will have a number of factors they monitor constantly. Many are barely aware of the "smells" they are looking for, but will have a constant awareness of issues that indicate that a transition is not progressing well. We provide a short list of common smells that indicate your agile project is not going as well as you hoped:
- Heaping piles of unfinished work will appear when assigned work is not being finished as quickly as new work is being assigned. This is generally a problem when the velocity is not being respected. The Theory of Constraints tells us that we have to subordinate the business to the bottleneck, a simple idea which is very hard to sell. Work may pile up in development or QA, especially if it is also piled up in sales.
- Individual work assignments are typical in non-agile shops, but agile developers team up and pair on production code. Managers may demand that individuals are assigned work prior to starting an iteration so that they may track the productivity of individuals. This is a disincentive for agile teams, because pairing with a colleague risks the work one is personally assigned. By pitting team members against each other in the fight for individual rankings, work assignments can destroy true productivity.
- Back-channeling is occurring if certain interests outside the development team (Customer or outsider) go directly to programmers and give them individual work assignments. This prevents the programmer from applying his abilities to the completion of the iteration. It also damages true productivity as others are required to pick up the slack, and the targeted programmer is forced to task-switch unpredictably. Back-channeled communications are a complex flow with political complications that prevent a team from doing their best work. It is better to work with a simpler, transparent management and communication structure. Note that sometimes back-channeling is an attempt by a leader whose work has been de-prioritized to get it pushed through anyway in defiance of the management structure.
- Blame-avoidance behaviors cause programmers to fear refactoring, redesign, and any important practice outside of a narrow job description. In fearful organizations, blame-avoidance prevents both productivity-wasting activities and productivity-enhancing activities. Fear is a reason to stay wrong, or at least to be right only in familiar ways.
- The urge to matrix-manage the team is a result of a lack of trust in the team by outside forces. When pressure is on any team, the certain leaders may seek to control other teams. When managers from outside a team try to manage the team by force or fiat instead of through normal channels (planning, prioritizing, etc) then it is clear that there are unaddressed problems in the management chain. These problems need to be resolved before they break down the team.
- Cargo-cult ceremonies are ceremonies carried out for the sake of the ceremony, rather than performed for good effect. Examples are planning ceremonies where estimates are not accepted and stories are not scoped to the iteration, scheduled retrospectives where no problems are really solved, iteration boundaries where work is carried over to the next iteration with full credit for "completion", etc. These are signs that the team is "seeming" agile, rather than "becoming" agile. It shows a lack of real change in values.
- Test negligence is a particularly nasty sign of an team's lack of agility. It shows that work is not being done by testing, and any pairing that is occurring does not support the agile practice. Agile teams depend on copious automated tests to accelerate their production. If tests are not being written, or not being run, then the team is not going to expand its capacity to produce. It is common that this happens in conjunction with back-channeling and/or work piling up. Skipping testing is a time honored way to seem to cut corners while actually making the software harder and harder to modify.
- Guarded speech is a sign that the real values and the spoken values of the team are not the same. It may be that the team is trying to be agile, but certain leaders or managers are not willing to hear it or else that the management is bought into Agile development and the developers are not buying it. It may be that there is some barrier to productivity that is being held in place by political or personal power of some leaders. Barriers to transparency tend to be political. It may be necessary to change the team's political situation so that they may work openly.
Acceptance Tests
Font: Complete In Him
The word "acceptance" implies that we have a high level of confidence that we can ship quality product. The goal for acceptance tests is to provide self-verifying, self-documenting executing examples of how the system is intended to be used. In a rough sense, they are use cases taken to the next level.
- Define “done done” for stories. The acceptance tests for a story provide a contract for completion. As programmers, we know we are truly done when the code passes all of the acceptance tests. As consumers of the system, we know we can accept it when all of its tests pass. Progress in an iteration is often best tracked by the number of acceptance tests passing.
- Are automated. Our Automating Tasks card provides detailed recommendations on when and when not to automate. Most importantly, this directive doesn't preclude the existence of tests that aren't automated!
- Document all uses of the system. Think about the tests as examples that demonstrate valid uses of the system. This mindset will help you develop tests that can be read and understood by people wanting to understand the system. Such documentation never becomes stale (although it requires good effort to design the tests to be so expressive).
- Don't just cover "happy paths." Stories usually require a family of tests to comprehensively cover alternate cases and exceptional situations. Inevitably, you will ship a defect that an automated test would have prevented. This previously "missed" acceptance test now becomes part of the complete test suite.
- Do not replace exploratory tests. We will always want some manual testing above and beyond the tests that define acceptance criteria for a new story. Exploratory testing highlights the more creative aspects of how a user might choose to interact with a new feature. It also helps teach testers how to improve their test design skills. Don't forget to knee test!
- Run in a near-production environment. How many nickels have you earned for hearing the phrase "It worked fine on my machine!?" Acceptance tests must execute in an environment that emulates production as closely as possible. This means they hit a real database and external API calls, as much as possible. By definition, then, acceptance tests are slow.
Still, minute to minute, I might want my suite of acceptance tests to run as fast as possible, as part of a continuous integration build. As a developer, I want rapid feedback, to provide high short-term confidence that I can move on. I know we'll still run the full suite in a proper environment overnight; having this fallback allows me to look at tactics such as using an in-memory database. - Are defined by the customer. Hopefully we know who the customer is. Agile acceptance tests are an expression of customer need (aka requirements). While all parties can contribute to statements of requirements, it's important that a "single customer voice" defines their interests as an unambiguous set of tests. (This also means that it's perfectly ok for a programmer to help with testing--they just can't be the one defining the tests.)
I'm often asked, "what about regression tests?" Most people define regression tests as "tests that make sure we didn't break something already in the system." My answer is that they imagine we had built this entire system in an agile, acceptance-test-driven fashion, i.e. where we ship only code that passes pre-defined acceptance tests. In this world, regression testing can thus happen every iteration--we simply run the entire suite of automated tests for all stories delivered to date.
Four Options for Agile Projects
Source: Extreme Programming Explained, chapter 3, The Economics of Software Development.
Kent Beck, et al, say that XP makes a lot of sense if you examine the options that it gives management. These options are less open to managers whose teams follow a more traditional, specification-heavy method, but become feasible with early and continual feedback.
With XP, there is regular measurement of progress in running, tested features. Because running, tested, demo-ed features is a concrete and meaningful kind of completion, the data can be used as the basis for making decisions.
This from www.dmst.aueb.gr:
The theoretical basis for XP is an options-based pricing model of software development. As software is developed in an environment where technological, business, and human risk abounds, investing for the future through careful architectural design, elaborate code structures that will support all possible future requirements, and producing matching documentation can be a waste of effort. Changing requirements or technology may render parts of the system obsolete; design and coding energy expended in those parts will have been wasted. Kent Beck's insight lies in discounting elaborate design for future needs in favor of today's simplicity. Big and important design decisions are deferred until a particular feature is needed. Most important features are developed first, rapidly providing the customer with the functionality required and minimizing the risk of total project failure. As code evolves it can always be refactored in response to new needs. Surprisingly, Beck takes for granted that current technology state-of-the-art and programmer skills will not stand in the way of these continuous design changes.
The options an XP customer or development organization is granted through early, accurate management:
- Option to abandon the software project. If the team is not gaining traction, or the functionality provided by the software is not a useful as expected, the project can be canceled. The ability to "fail fast" is a benefit of XP.
This has the additional advantage of allowing XP advocates to refer to canceled projects as "agile successes". :-) - Option to switch direction. Because the software is ready for use so early, there is an opportunity for the business to decide that they don't really want the system they specified. Agile teams can change direction because they don't have a lot of investment in the system "as specified", only in the system "as built".
- Option to defer before investing. Since building is done incrementally and interatively, the business can choose not to produce features that may not have the same potential as others. Does the social networking bit have to be done before e-commerce? Should the e-commerce bit happen before we have full catalog capability? Being able to defer means that we can have the pieces we want most now. Of course, we can defer indefinitely (AKA: abandon) some features for further savings.
- Option to grow to take advantage of a market that is taking off. This includes building scalability into the application as needed. It clearly also can mean growing the app in the direction of its uptake, such as adding social networking features or commerce features if those are drawing people to the application or SAAS.
Programmer Practices for Agility
font: Another
source: Beck, Kent. Extreme Programming Explained, 2e.
This card lists programmer practices, both team and individual (or pair!), that can help us meet some of the rather daunting challenges of agile: How do we continually deliver increments of quality software that meet the changing and evolving needs of our customer, at a reasonable cost?
- Continuous integration (CI) - Agile promotes continual forward progress. We expect programmers to frequently update the system with code changes, so that we can verify that the complete, integrated system is still working.
- Test driven development (TDD) - TDD tells us to break down programming into technical tasks, each specified by tests that document small pieces of behavior. TDD provides us with feedback that we've built code that does what the tests specify. Most importantly, TDD supports the practice of design improvement.
- Design improvement - With each change, programmers must reflect upon the code's new state, and correct any design deficiencies. Continual holistic attention to the system's design helps keep development costs from rising dramatically.
- Coding standard - Navigating a code base without standards is like riding on a rough road: At the end of the day, the constant battle against all the little bumps, nuisances, and noise simply wears you down. A team that can't establish workable standards is a weak team. In addition to including naming and formatting, coding standards should include things like handling of build system warnings, build output standards (e.g. no stdout/stderr or stack dumps!), build timing standards, and test standards.
- Collective code ownership - Uncle Bob's prime directive for agile development is "never be blocked." Class ownership standards create unnecessary blocking issues. We should all be comfortable with anyone touching any area of the code--as long as they're following all of these other programmer practices!
- Simple design - Keeping the design as simple as possible allows for easier incorporation of new changes. Introducing unnecessary abstractions or complexities increases the cost of development. You ain't gonna need it! (YAGNI) More specifically, the practice of simple design is best described by Kent Beck's four rules.
- System metaphor - A global understanding of the system and its concepts is essential for an agile team. We all need to build a common, ubiquitous language that helps us communicate with each other, and that includes non-programmers. The system metaphor is a system of names for its primary entities (classes) and how they relate.
- Pair programming - How in the world will your team ensure that other developers are adhering to the common practices if no one reviews what is done? How will we ensure that we keep on track, and developer on time, if developers are left to suffer their own insecurities in their cubes? How can we shift from finding bugs to preventing them? Try it. If you have a real team, you'll like it.
Hmm, this card looks suspiciously like the technical practices of XP. How about that!
Priority Mechanisms
Font is Marker SD
Setting priority for tasks is essential to agile/lean software development. Agile teams strictly limit the number of tasks in flight in order to have greater efficiency and effectiveness. The improved focus means code is completed sooner (not faster) and that product may be delivered to production more often. This focus is frustrated if we have too many "#1 priority" items and "emergency" items thrown in on top. Controlling the flow makes teamwork possible, and actually speeds the process.
We sometimes refer to the system that filters tasks into priority order as the magic funnel. All tasks and features are metaphorically dumped into the top of the big funnel. Ideally, the first (or next) item that falls out of the bottom of the funnel is the absolute most important thing we could possibly be doing. It has won the prize. It is the task we should be working on.
Setting priority is unsurprisingly one of the hardest things a customer can do. Do you pick the story that satisfies the most "important" customer (where "important" varies daily, almost hourly, and by which person you ask), or the greatest number of customers? Do you pick tasks that you think will bring the greatest number of new customers, or please the existing customers? Do you streamline processing or go with aesthetics? What makes one story more valuable than another?
Since the problem is large, and depends on local standards, there are many ways of prioritizing stories. The method shouldn't be something a team should agonize about for weeks. The most important point is that the product owners are able to reach a consensus, and that the features they pick are truly important. Tactics can vary, provided the strategy is good.
Here are some schemes and techniques that might help build a working "magic funnel":
- A simple priority triage system (one short sentence) was reported by Mary Poppendieck in Lean Software Development as one of the simplest things that could possibly work. The rule doesn't have to be subtle or obscure. A maintenance team might adopt a three-part rule, where production crises came first, followed by bugs on the release-in-testing, followed by everything else. Features that affect all customers may come first, followed by those that primarily affect million-dollar customers, followed by those that affect half-million dollar customer, followed by whatever. It is possible that product stakeholders already have a rule of thumb that suffices 80% of the time. The other 20% of the time is settled through escalation.
- Determine "The Constraint" as in Goldratt's writings The Goal and Critical Chain. If you can define the one thing that inhibits you from being successful, then you can prioritize all outstanding bugs and backlog items in such a way that those that remove the primary obstacle become top priorities. Goldratt was speaking of process steps and production, but why not apply it to features that sell or flaws that inhibit? It may be that scalability of your web application is more important right now than enhanced functionality. It may be that a difficult feature is the primary reason you are losing sales or even customers. It may be that one issue prevents you from expanding, growing, producing. Critical Chain shows us that we need to solve this one big problem. And then the one after it.
- Covey's Quadrants from First Things First will have us divide work into quadrants, so that #1 are those things that are both important (to the future of the company or product) and urgent, #2 are those that are important but not urgent, #3 are those that are urgent but have little long-term impact, and any unimportant non-urgent work is simply eliminated from the backlog. These items are taken in quadrant order, so that important, non-urgent tasks are done before urgent, non-important tasks are considered. Covey, et al, were talking about personal importance and daily tasks, but why not apply it forward to planning other work that has potential value and obvious levels of urgency? Remember that urgency and (to a lesser degree) importance are dynamic properties, to be revisited frequently.
- Value-First is the rather like the Covey and Goal approaches, where the work that provides the greatest value (frequently represented in customer satisfaction or decreased support) goes first. This sounds easy, but of course the problem is defining "value" and dealing with "value to whom?" One could place value to the customers or to the sponsors or to the shareholders first.
- Risk-First would tell us to start on those things that need the most research and testing sooner. High-risk items have unpredictable schedules, and may not pan out at all. Such stories would be prioritized earlier because they cannot reliably be produced on a schedule. Alternatively, some will choose to use risk-last planning, so that the so-called "low hanging fruit" may be completed before moving on to less predictable work. Some organizations may want to plan a mix (70/30 or 80/20) of low-risk to high-risk features.
- Greatest Good to the Greatest Number works like the other "value first" kinds of schemes, but adds voting to the scenario. Each customer, role, or market segment that would benefit from a change votes for it (consider dot-voting). Among items of the same importance/urgency quadrant, those with the greatest number of votes would go first. Changes with fewer stakeholders would be done later. This is a customer-focused version of "Bargain for Success."
- Fixed-length action queue would work by using a short list of only a few bug fixes or marketable features. This list would be overseen by executives, and to push an item from "backlog" to "action queue" requires high-level approval. Items in "action queue" can be retracted only by executive order, since stopping a feature-in-progress represents a financial decision to throw away development dollars. The customer works to push items into the fixed queue as other things are completed or redacted. Customers will have a list of two or three items that might be next if approved. This tight focus helps the Customer not lose focus on immediate delivery. It is a lot like the Biblical "Law of the Medes and Persians", famous for being unrevokable.
- “Only One Thing” is a little game best used when the priority rule is more intuitive than explicit. The stakeholders are given a hypothetical situation that only one feature can be reliably developed in the next iteration/month/quarter, and are tasked with picking which one feature it would be. Once they have picked the solitary feature, they are asked why it is important to them. This game can be played with "only three" or "only five" for a larger sample size. Most organizations, having argued through the exercise, will have a Simple Triage System they can use for future priority meetings.
- Bargain for success is another game-like system. Each product stakeholder is given a number of votes/dollars/tokens/chips to spend. They are allowed to buy into features in order to bring their priority up in the queue. Stakeholders can make deals with each other ("I'll give 7 tokens to your feature Y this time if you'll give 7 to my feature Z next month"). The game-like nature of the exercise may cause some to see personal "winning" as the goal, rather than the greatest good for the company, but it will drive consensus nonetheless. Ultimately, the stakeholders have decided either way.
The ultimate power card (not included) is "CEO/Owner Demands". Most development organizations will pitch in and do all they can to get the feature completed well and soon. As long as the demands are within reason it should not be a problem. Most executives should understand the realities of development hours and sustainable pace, and are pretty hard-working guys themselves. The CEO DEMANDS power card is rightfully used sparingly and in cases most deserving of it.
Overplayed, all power cards will result in demotivation, loss of quality, slowed pace, and/or attrition. Coaches, managers, stakeholders, and product owners should move cautiously.
Principles of Package Coupling
Principles: Robert C. Martin
Post: Tim Ottinger and Jeff Langr
These three principles, devised by Uncle Bob, describe how to structure relationships between packages (arbitrary collections of classes). A related (forthcoming) card, Principles of Package Design, talks about the forces that bear on how to optimally group classes.
There arise occasional shouts of "But that was in C++!" Yet we find that these principles can apply also to dynamic languages, where abstraction works rather differently than in interface-declaring languages.
- Acyclic-Dependencies Principle (ADP) - You stay late to finish up some work, but come in the next morning only to find that your code is broken--someone else stayed later and checked in changes that make your code very unhappy. Fixing your code breaks a third developer's code, and his fixes break yours again. This "morning-after syndrome" can be an unending nightmare of changes breaking other code, which in turn must be changed, which in turn...
Cycles begin to make all packages dependent upon all other packages in the system. They dramatically increase build times to the point of pain (something one of us lives with daily on the C++ project he's working).
Some languages, like C#, have facilities to prevent circular dependencies among packages. But even modern, dynamic languages like Python can suffer in surprising ways from round-trip dependencies.
Dependency cycles among modules are a very serious problem, slowing development and wrecking deadlines. Note that mutual dependencies among classes are usually a problem if the classes are split across modules/packages/assemblies. - Stable-Dependencies Principle (SDP) is based on the understanding that code has volatility, and that changes ripple through a system along dependency lines. From the point-of-view of volatility, dependency is transitive.
If the majority of the system's classes are dependent upon a volatile bit of code, then we can expect a high frequency of system breakage and rippling changes. If, instead, a system depends on nonvolatile code, then breakage should not ripple through the system very often at all.
Some modules should change frequently, and should be volatile. Other modules are essential core abstractions and should not change very often.
Therefore the package dependency graph should flow from instable packages (packages that are easy to change) to stable or "responsible" packages (packages that are hard to change). In a sense, this is the dependency inversion principle applied to packages: You should depend only upon things that are unlikely to change. - Stable-Abstractions Principle (SAP) - Per Uncle Bob, this principle sets up a relationship between stability and abstraction. A stable package should be as abstract as possible, thus ensuring that its "stability does not prevent it from being extended." In contrast, an instable (not responsible) package should contain lots of concrete classes whose details can be easily changed.
This further reflects the Stable Dependencies principle, with the added observation that the reason for interfaces is to give safe, stable dependencies to clients of an abstraction. This drives us to the understanding that we should depend on the parts of the system built specifically to provide freedom from volatile bits (implementations).
In dynamic languages, SAP is a harder metric to automate. Clearly the principle still applies. There will be classes whose purpose is to provide a stable interface and other classes that provide easily-changeable behaviors. The only problem is that not having declared interfaces makes it harder to automate the process of assessing abstractness.
A "benefit" of working in C++ is that poor package coupling choices are all the more noticeable. Build times of several hours are not uncommon, yet these wasteful cycles can be quickly brought down with a bit of appropriate package reorganization. Without dramatically increasing build times, developers in languages like Java might not notice as quickly the cause of their morning-after sicknesses.
So how do we figure out where the problems are and what to do about them? The flip side of the card provides metrics that you can use as the basis for graphing the relationships between packages. Such a graph can point out nonsensical packages, such as maximally abstract packages that no other packages depend upon, or maximally concrete packages that all other packages depend upon. Uncle Bob's stability article provides some detail on how to put this graph together (but there are also tools that can help!).
Software Craftsmanship Ethics
Source: Doug Bradbury, Dave Hoover, Robert Martin, cast of dozens
This is the outgrowth of a conversation among Doug Bradbury and a number of Craftsman Manifesto signers. The goal of the collaboration was to come up with a statement of the Ethics of Software Craftmanship. In the course of the conversation, one of our participants suggested the pillars shown here (the brainchild of Jason Gorman).
The long form is quite beautiful, and presented here in entirety as an explanation of the four points above:
- We consider it our responsibility to gain the trust of the businesses we serve; therefore, we take our customer's problems as seriously as they do and stake our reputation on the quality of the work we produc.
- We consider it our responsibility to write code that is defect-free, proven, readable, understandable and malleable; therefore, we follow our chosen practices meticulously even under pressure and practice our techniques regularly.
- We consider it our responsibility to hone our craft in pursuit of mastery; therefore, we continuously explore new technologies and read and study the work of other craftsmen.
- We consider it our responsibility to perpetuate the craft of Software; therefore, we enlist apprentices to learn it and actively engage other craftsmen in dialogue and practice.
FURPS+
Source: http://en.wikipedia.org/wiki/Furps
Nowhere does it say that you must dispense with all prior knowledge in order to be agile. The FURPS+ card is a good example of a tool I've found useful in non-agile years long past, and still useful in the context of an agile project.
In agile, we don't refer to requirements; instead we talk about stories. Stories are really reminders for customer needs (requirements, in the general sense). We will refine these needs into product through continual discussion. We demonstrate confidence in our ability to ship software product by executing tests that represent acceptance criteria for each story.
Deriving a list of stories to represent a deliverable product is something that must happen in order to plan a release cycle. This backlog of stories must of course include all the customer's functional needs, as well as their non-functional needs. Non-functional? Many "real" customers don't think about such things.
The FURPS+ acronym, devised by Robert Grady of HP, provides a bit more meat around what we mean by non-functional stories, and also provides a good way to categorize such needs. The breakdown here suggests some representative questions around potential needs.
- Functionality - What the customer wants! Note that this includes security-related needs.
- Usability - How effective is the product from the standpoint of the person who must use it? Is it aesthetically acceptable? Is the documentation accurate and complete?
- Reliability - What is the maximum acceptable system downtime? Are failures predictable? Can we demonstrate the accuracy of results? How is the system recovered?
- Performance - How fast must it be? What's the maximum response time? What's the throughput? What's the memory consumption?
- Supportability - Is it testable, extensible, serviceable, installable, and configurable? Can it be monitored?
The + reminds us of a few additional needs that a customer could have:
- Design constraints - Do things like I/O devices or DBMS constrain how the software must be built?
- Implementation requirements - Do the programmers need to adhere to standards? Is the use of TDD required? Is statistically sound testing in the context of Cleanroom required?
- Interface requirements - What downstream feeds must be created? What other systems must this one interface with? How frequent are feeds produced?
- Physical requirements - What hardware must the system be deployable on? Must we be able to deploy to a machine no larger than 12" square, to be stationed in the Iraqi desert?
Just remember, in agile, stories are negotiable (but end product is usually not)!