This article expands on some of the thoughts we presented in our original Agile in a Flash blog post on shu ha ri (complete with card facsimile). Shu ha ri is one of the cards we present in the soon-to-be-published PragProg deck.
This is the problem with having multiple Blogger accounts starting with A, and writing at night when you are less wary about checking site names when writing. Apologies to readers and to my coauthor for the slip-up.
See the official Pragmatic Bookshelf page!
See the O'Reilly catalog entry!
See the Amazon catalog entry!
See the ongoing series of articles in PragProg Magazine!
See the happy authors!
Thanks to everyone for the support and reviews and ideas and permissions. It's fun to see a dream come true!
Now it's time to go replace my exclamation mark key. ;-)
Latest update: The Agile in a Flash project is nearing final draft, close to being sent to production! Once that happens (perhaps end of next week), it's 6-8 weeks away from shipping to you.
Meanwhile, our latest PragPub article (available in multiple formats--see the PragPub magazine index--is out. It's called "What Agile is Not" and talks about some of our experiences with agile. Looking at the article, though, I wonder about the lead-off sentence for our conclusion paragraph:
"The advice from Kent Beck and Ron Jeffries for successful adoption of Agile Software Development has always been to start with the values. "
But is that true? I believe there have been some recent statements to the contrary on one of the mailing lists. My apologies to Ron/Kent--that's how I've always looked at things, so perhaps I'd projected my misinterpretation on their teachings. Feedback please?
We've gone a few weeks without a new card here, but it's because we've been working on the final versions of our cards to be published by Pragmatic Publishers "Real Soon Now." You will find a lot of familiar content, but even more polished and even more condensed. You'll get to enjoy physical cards, suitable for sticking and sharing with your whole team or company. Even better yet, they'll have been edited by actual professional editors.
We're not going to quit the blog, but we are going to be available in more forms than ever before. PragProg will release AgileInAFlash as physical cards and as ebooks. Imagine how cool "Courage" or "ABCs of Pair Programming" will look on your hot little iPad or Android phone! You'll have virtual Tim & Jeff everywhere you want to take us. This blog continues to be a place to write your comments, or to see cards never before released into the wild.
When you get your deck(s), take a picture of yourself using the cards and send it to us. We'll be thrilled and honored to see how you use your AgileInAFlash in your daily work!
Tim Ottinger and Jeff Langr
There are many ways to conduct an agile project. Some work with huge backlogs, some with spur-of-the moment requirements, some have continual release, some have non-time-boxed continual flow. We recommend starting with the structure shown on this Agile in a Flash card.
Following this plan, the customer team puts together a prioritized list (feature backlog) of desired features for the upcoming product release. The release is broken into iterations, and the team and customer agree on what will be delivered at the start of each iteration (no sooner). The iteration is of fixed length, something that allows the team to begin gathering consistent data, which in turn they feed back into their estimates and subsequently a larger plan. Upon incrementing and iterating the software a few times, the software reaches a state that it may be released to the customer. Does the system implement the agreed-upon features (did it pass all of its acceptance tests)? Yes: Release to production!
The flow outlined above is a reasonable starting point for a team transitioning to agile. It represents a kind of "Shu" in the Shu-Ha-Ri cycle, where one follows a certain technique or style for a while to build up their ability to perform it. In fact, both of us started with this basic pattern and found that it worked just fine.
As you move to more "Ha" stage, you might experiment with reducing the size of stories so that more of them are done and "in the can" before the end of the iteration. You might work on making the software releasable at every iteration boundary. You might shorten your iteration period so you can gather data more often, provide smaller increments to certification, and get feedback from users more quickly. You might pick fewer stories per iteration. You may experiment with self-organizing to get work done. It is a waste to spend a lot of time detailing features which may be done in the remote future or not at all, so you may reduce the entire feature backlog to perhaps a handful of stories. You may learn (as Deming recommends) to use more effective quality practices and eliminate a "certification" stage, as indeed many software shops are doing (research topic: continual release).
Once you are into the Ha and the Ri stages, using agile principles and values should lead you to more informal yet more effective approaches. Here's an "agile flow" card for the more seasoned agile team:
In a bit more detail:
- The customer describes a small subset of needs orally, to the team.
- Through negotiation with the customer, the team commits to completing code that satisfies some, most, or all those needs in a given period.
- The team agrees on a working set of rules that define how they will deliver quality code, under good, sustainable working conditions, in the specified period. (Hint: The team might use retrospectives to help derive and tweak the rules.)
Acceptance tests (ATs) are as enduring and important an artifact as your code. The proper design of each will minimize maintenance efforts. You'll recognize some familiar concepts--Kent Beck's rules for simple design and some classic OO principles apply well to the design of acceptance tests.
Abstract. A test is readable as a document describing system behavior. Uncle Bob's definition for abstraction applies equally well to tests: Amplify your test's essential elements, and bury its irrelevant details and clutter. Anyone, including non-DBA and non-programming staff, should be able to follow the steps taken in the test, and understand why it passes. Extracting duplicate behavior to a common place--the AT analog of programming's extract method--is the main workhorse that allows you to increase abstraction at the same time you remove duplication.
Bona fide. To ensure continual customer trust, a test must always truly exercise a system as close to production as possible. Passing acceptance tests tell the customer that what they asked for is complete and working. But once the customer has doubt as to what your tests exercise, you have severely damaged your ability to continue using them as contracts for completion.
Cohesive. A test expresses one goal accomplished by interacting with the system. Don't prematurely optimize by combining multiple scenarios into a single test. Keep single-goal tests simple by splitting common content into separate fixtures. Yes, this will mean your acceptance test suite runs more slowly, but it's far more important to avoid compromising clean test design. (It's also why your unit test suites should be as fast as possible.)
Decoupled. Each test stands on its own, not depending upon or being impacted by results of other tests. A failure caused by problems in another test can be difficult to decipher.
Expressive. A test is highly readable as documentation, not requiring research to understand. Name it according to the goal it achieves. As with unit tests, refactor each test to improve the ability of a third party to understand its intent. You should always eliminate magic numbers, replacing them with constants as appropriate. Improve visual accessibility by formatting your test using Arrange-Act-Assert (AAA). You should also make it clear what context is being set up in the test; one way is to incorporate additional assertions that act as preconditions.
Free of duplication. Eliminate duplication across tests (and even within the same test) before it eliminates you! Duplication increases risk and cost, particularly when changes to frequently-copied behavior ripple through dozens or more tests. Duplication also reduces the use of abstraction, making tests more dense and difficult to follow.
Green. Once a story is complete, its associated ATs must always pass. A failing AT should trigger a stop-the-line mentality. Don't allow your test suite to fall into disarray by allowing failures to be ignored!
Jeff Langr and Tim Ottinger
Font: Brown Bag Lunch
Pop quiz, hotshot.
Q. "You're not agile if you don't ... "
A. Select one more of the following:
|a.||Have daily stand-up meetings|
|d.||Employ a metaphor|
|e.||Have a ScrumMaster|
|f.||Run iteration planning meetings|
|g.||Use index cards|
The answer is H, none of the above. Practices are just that--specific techniques a team might or might not employ to aid them in being agile--whatever agile means. Here's our definition: Agility means you are able to frequently and continually deliver high-quality software that meets the customer's needs.
The agile manifesto lays out four core values ("working software over comprehensive documentation," e.g.) and a dozen or so principles. But what factors truly make an agile team successful?
Attention to quality. The code is your product, and, unlike most other products, one you will continually build on and shape to meet continual new customer demand. If you fail to pay attention to quality, you will eventually slow down in your ability to meet demand, sometimes to the point of stagnation. The team must ensure that the code is clean enough to accommodate new incremental customer needs. Attention to quality is never a separate task on a plan; it must be embodied in everything you do to build your product, including coding, design, documentation, testing, automation, tracking, communication, and so on. Quality must be incrementally and continually addressed.
Incrementalism Most of the practices you employ in agile have something to do with ever-smaller steps. Instead of a massive requirements document, you allow the customer to provide features just in time, in small chunks described on little index cards. Instead of a comprehensive up-front design document, you learn how to design on a task-by-task and test-by-test basis. And so on. You must learn to think incrementally.
You must also look to correct course continually and incrementally. For every few lines of code added or changed, take time to ensure the design is as good as you can get it. (Which you can only do if you have enough controls in place to allow frequent code improvement. Best way we know how to get there: TDD.) Not only do you need to correct course in the product, you need to always correct course in your team. You should always be introspecting about your team, probing for ways it's not performing optimally, and working to correct these problems. Retrospectives are a good start.
A successful agile project is not a bunch of hare-like sprints to the finish line. It is a cool-headed, tortoise-like, slow 'n' steady approach of small, well-reasoned steps. Each step is an opportunity to look up and see where it got you--closer to the finish line or further away? It's easy to correct a single misstep. In contrast, a single mad sprint in the wrong direction can take you pretty far off course from the finish line.
Automation. There are numerous ways to waste people's time on a software development effort--running automatable regression tests manually, for example, or suffering a build process that unnecessarily requires multiple manual steps or manual verification. Agile cannot work unless you automate as many menial, tedious, and error-prone tasks as possible. There's simply not enough time across a two-week period to get any real work done if you have to slow down for numerous manual gating processes.
Tim Ottinger and Jeff Langr
Font: Brown Bag Lunch
In keeping with the agile value of Communication, agile teams often place large charts and graphs in their workspaces to radiate important information such as defect rates, rate of completion, and measures of code goodness (CRC, bugs, test counts). Much is made of Informative Workspaces or Big Visible Charts (BVCs).
You'll find numerous graph types in the agile literature. Some types, such as burn-up, burn-down, and cumulative flow are commonly used to graph progress against a goal such as an epic story. Defects and velocity are also useful things to track, but don't limit yourself. Let your team determine--and let these information radiator principles guide--what you track and publicize.
A chart or graph should not require minutes or hours of study. Ensure it is brief and concise. Anything dense or complicated will fail to communicate. Also, don't use highly derivative, biased, weighted information. Simple facts speak more profoundly than clever algorithms.
BVCs don't exist to convince the public of your team's excellence. Nor should you mask errors or problems with them. The purpose of the graphs is to display progress and expose problems. Don't subvert the honesty of the graphs, otherwise your team will stop trusting them, and therefore stop using them to improve their work.
Any information that is not kept current is quickly ignored. You may want to have the CI build graphs based on automatically-generated stats. Information more than a few days old is too stale to have evocative powers.
Radiators that only expose problems shouldn't be up there long, otherwise it's clear that you aren't solving your problems. Choose a BVC to highlight a current challenge for which you can demonstrably show improvement over the next several days or iterations. Once it's clear the team has gotten the message, and things are back on track, take down the BVC.
A good information radiator influences the team's daily work. It may also influence managers, customers, developers, or other stakeholders. Ideally it will empower the whole team to make better decisions, otherwise it is not worth preparing and presenting.
- Highly visible
An effective information radiator needs to not only have information on it, but must transfer it to team members, stakeholders, and passers-by.
- Minimal in number
Having too many graphs or charts will cause all of the charts to lose evocative power. Also, exposing too many problems on the wall at one time can demoralize any team, so choose either the most important, timely, or fixable problem to highlight, and defer the rest. Sometimes less truly is more.
Jeff Langr and Tim Ottinger
Font: Brown Bag Lunch
These half-dozen items provide the core set of principles around the iteration workflow for delivering stories to an eager customer. (Most of the principles would also apply to a kanban environment, with a bit of tweaking.)
Team commits to stories they can complete. Each iteration begins with a short planning session. The primary goal of this session is to ensure that the development team (hereafter "the team" in this blog post) and customer are in sync on what the team will deliver by iteration end. The customer and team jointly produce acceptance criteria that act as the contract for completion. The team commits to only the set of stories they can confidently deliver by iteration end. The workload is thus fixed for the duration of the iteration, although the customer can negotiate a change to the workload with the team. Hopefully this occurs only rarely, and hopefully the team has the sense to insist on work being taken off the iteration's plate.
Team works stories from prioritized card wall. The customer is responsible for managing the flow of work. Their job is to ensure that available stories are presented in priority order. Available developers grab the card with highest priority and move it into an "in progress" bucket. The card wall, whether real or virtual, is visible to everyone involved in the project.
Team minimizes stories in process. Applying non-collaborative approaches to agile asks for the same, lame results you got from waterfall. A typical anti-pattern we've seen (we'll call it "Indivigile"): Every story is close to a full iteration in size, and each developer grabs their "own" story to work on. So much for any of the significant benefits that you might have gained from collaboration (primarily better solutions, increased mindshare, and thus minimized risk). Worse, you dramatically increase the probability that stories will not be delivered by iteration end. A better approach: Team members work on the smallest sensible number of stories at one time, maximizing collaboration and ensuring that each story is truly done before moving on to the next.
Following this approach, you should see almost half of the committed stories 100% complete by midway through the iteration. Overall, the number of stories fully complete by iteration end should increase. Also, many activities that would have otherwise been blocked until iteration end can start earlier (additional testing, clarification/correction, documentation, etc.).
Team collaborates daily. A daily stand-up meeting is a good start for getting the team on the same page, but never sufficient. If the stories-in-process are few, the team must find ways to collaborate frequently throughout each day, to avoid wasting additional time.
Customer accepts only completed stories. Stories must pass all programmer and acceptance tests before the customer looks at the the software. The customer needs to play hard-ball at this point: Any story shy of 100% passing gets the team zero credit: Incomplete work provides no business value. The lesson for the team to learn (and apply in subsequent iterations) is to not over-commit.
Team reflects on iteration and commits to improvements. Agile is built around frequent incremental delivery, in order to maximize feedback, which in turn provides opportunities to improve. Iterations are not only opportunity points to improve the product, but also for the team to reflect on what the team needs to change, whether to improve quality, throughput (which improving quality will do), team morale, or any other execution concerns that the team recognizes. See our Retrospectives card for guidance on this critical agile practice.
Everything else that happens with respect to iteration execution is "implementation details," and thus up to your team to determine. We don't care if you use software tools or physical card walls. We don't care if your team is distributed, whether you run a formal stand-up meeting, whether you use velocity, planning poker, load factors, yesterday's weather, Scrum Master whip cracking, or any other specific practices for planning and organization. All is generally good as long as you adhere to the above principles for flowing work.
We've talked about what agile development is, how to do it, and why people object to it, but the big question that remains is "Why Go Agile At All?" If you or your employer are considering a conversion to agile, you should know what to expect from the change.
Agile is a work system, not just a style of writing code or a set of tracking tools. It is a very disciplined and orderly way to work, and it is also a lot of fun. It is intense, requiring a high degree of personal involvement (which is why Agile teams cap their work weeks at roughly 40 hours).
- Improve Customer Involvement Agile methods put the customer in the drivers' seat. Customers choose which bit of functionality comes next, and when a feature is complete enough for their needs. Agile is intentionally customer-intimate, so customers and developers (including testers, tech writing, and customers) are on the same team. It is a strong alternative to an adversarial relationship
- Increase Quality Agile depends heavily on testing, both at the acceptance test level and at the unit test level. Tests are written constantly and run constantly. The legacy code you have lying about in piles may not be amenable to testing, so expect some early delays as the team converts it. These delays are more than offset by the lack of bugs (and days lost to bug-finding research) a few months down the road. Improved quality results in fewer customer complaints, reducing support costs.
- Simplify Releases Agile teams release early and often, and try to maintain their code base in a perpetually-releasable state. Tests and Continuous Integration ensure you don't have long dark times when the code does not run. Periodic integration hell and mad release rush are reduced, even eliminated.
- Increase Operational Awareness Agile teams keep their work-in-progress to a minimum, and track their progress on visible charts and the kanban wall. One can walk into the group work area and tell what tasks are in progress and how close they are to being completed. You can glance at a burn-down or burn-up and tell how close the team is to completing some critical functionality. It is an orderly and visible work system.
- Drive Down Risk
Agile teams work in tiny increments of functionality, not huge end-all features. This allows them to have working software ready early on. They do not necessarily produce software faster than non-agile shops, but it is in a usable state earlier. This means that the software can be used while it is being developed. It might even pay for itself.
Because software is usable so soon, features are assessed sooner. The Customer can see immediately if they are really as useful as he expected. Corrective steering is possible. There is a greatly reduced risk of building the wrong thing, or a gold-plated excess of the right thing.
- Reconnect With Geek Joy Boy, did I ever detest sitting through all-day meetings debating use cases or refining requirements documents in the name of JAD or RAD or RUP or whatever. Agile focuses on getting things done well and often, which according to studies is the primary factor that drives job satisfaction. Having working code nearly at all times is empowering. Having tests to rely upon is comforting. Having steady progress is refreshing. It is great to be making real progress (learning and coding) all of the time. It's why many of us chose this vocation.
The most common reason does not appear on the list above, "What we were doing was not working." That is a reason to change from what you were doing, but not necessarily a reason to change to anything in particular. If you are considering a change, consider whether you want the qualities listed here enough to give Scrum and/or XP a shot.
Agile's raison_d'être stems from backlash against "heavyweight" methodologies that insisted upon voluminous documentation, never-ending and never-useful meetings, and vendor-lovin' high end tools. Yet in 2010, there are at least three major high-price, high-profile agile project management tools and dozens of lower-end ones.
We contend that using one of these expensive software tools says, "you don't get it, and maybe shouldn't bother, because agile may not work well for you." No doubt this will perturb those of you who have found some value in agile management tools, so let's step back and talk through the issues.
Agile is primarily about team communication and collaboration. It is predicated on continual face-to-face interaction. Every step in the opposite direction decreases the chance of success. Kent Beck had it right: The best opportunity for success, still, is having all project members sit in a single room and work as a team, instead letting a bunch of self-interested individuals retreat to the isolated comfort of their cube.
There is no room in agile development for "avoidance technology." If you can't find a way to meet its demand for close-contact, continuous communication, then you are not ready. If you don't want your programmers sitting together, talking through problems, writing code socially, then try something else. Attempting to bolt avoidance technology onto agile methods is like castrating a stud horse.
Once you diminish teamwork, you have to compromise other agile principles. If we're not in the same room, we need more meetings to talk to one another. We need to write more things down and produce more centrally-stored documentation. We need to have more contractually-oriented agreements between people who really work on the same team, because we can't trust one another, because we're can't see each other face-to-face every day. The agile practices topple like dominoes.
There is always questionable rationale about why things must be that way. "Every project has to be split evenly between low-cost [read: offshore] labor and high-cost [local] labor." That's not a definition of project success, just a broad-brush attempt at cost control. Having some remote team members should never force all team members to work as if they were remote.
Perhaps the executives could use their hard-won corporate smarts to organize the teams differently. "Half our projects must be low-cost" should appease the bean-counters, and could just work. Here come the excuses: "But we don't have business experts who can act as customers in Bangalore." Really, that's a problem you can't solve? Having two truly agile teams producing quality code should be better than having two teams pretending to be, and failing at, agile.
If you want to succeed at agile, find a way to put each team in its own room. Give them the tools we list on the card, and they'll rarely ask for more. We guarantee they won't ask for a high-end agile tool, because they don't need one and don't want to be bothered with one. Executives of various stripes might ask for one, but all they really want is a simple way to view and present status across significant numbers of projects. You don't need a high-end, specialized, complex tool to do that, and you definitely don't need to waste the time of everyone across every agile team to do that (hint: see Tracker and Coordinator on Agile Roles card. This is what you pay project managers to do).
Some of you might be surprised that there are no farm animals on this card. We'll talk about that later.
You'll also note that each role definition is preceded with the word "helps." Everyone on an agile team can act as any role at any given time, helping the team toward its ultimate goal of producing quality product.
Extreme Programming (XP) originally designated two roles, programmer and customer (for whom XP described little--it is extreme programming after all). Each camp had specific rights, to protect each camp's interests against likely infringements by the other. A bit divisive? Indeed. You will be hard-pressed to find much remaining literature that mentions "XP Rights."
Within the programmer camp, XP eschewed specialists and hierarchies, fostering instead experts and team collaboration. But things other than programming and steering as a customer still needed to be done. Various adjunct needs, such as coaching and tracking, emerged. Who would do these things? These part-time needs were fulfilled by XP team members (customers or programmers) shifting in and out of secondary roles.
Proponents of Scrum (which predates XP a bit) were never so trusting in a teams' ability to self-manage, so they introduced the Scrum master, whose job is to keep the team on track. As for XP, the reality of human behavior brought its lofty goals down a peg, more so as Agile took off. Organizational interests and self-preservation took over. The concept of a self-organizing, title-ignoring team threatened HR, project managers, managers, and others who had vested interests in promoting and maintaining specific titles. In an attempt to keep us from falling back into isolationist and divisive behavior, Kent Beck began referring to the collection of all team members as "the whole team," instead of discussing specific roles.
Today, the agile organization doesn't usually look terribly different than the pre-agile organization, except within some programming teams. You'll still hear long-standing, specific names for specific customer roles, such as "business analyst," "product manager," "UI design specialist," "subject matter expert (SME)," and "stakeholder." But on the programming side of the fence, a team working within an open workspace and pairing usually has lost any real concern over titles and artificial divisions such as "front end programmer vs. back-end programmer." Since these roles are temporary, it is futile and undesirable to to tie hierarchical positions or increased benefits to them.
It is best for us to concentrate more on putting out quality product, and least on relative positions. We understand that it may not be realistic in your organization to shed your title, but you should still consider the ego-less organization a general direction to move toward. Sometimes simply thinking that there are no titles can help you find an answer to your problems.
Astute readers will note that "manager," "project manager," and "Scrum Master" do not appear on this list. We have instead substituted "team coordinator," someone who buffers the day-to-day development team from outside interference and distraction. A team coordinator can communicate scheduling issues, handle incoming requests, and smooth interpersonal problems. Within Scrum, this team coordinator also takes on the responsibility of enforcing the rules, something that a team is certainly capable of doing on their own. We suggest that the best Scrum Masters plan their own obsolescence: Their primary job should be to help us mature to the point where the team no longer needs a Scrum Master.
The lack of official leaders and managers in agile is off-putting to some. We've noted that most software teams do not suffer from a shortage of management, but a drastic overage as different departments try to exert control over the isolated "programmers" and "testers." In an agile team we come together as a team, and the work has us busy enough that little traditional management is necessary.
As far as the chicken and pig roles that some of you might have expected to see on this card: Everyone we've met on a well-functioning agile team has been unsurprisingly human. We don't believe people who might have something important to say should be stifled. If someone says inappropriate things at inappropriate times, we muster the courage to ask them to take it elsewhere. "Chicken" was deliberately chosen as a derisive moniker, the spirit of which has no place on a real team. (We quote Jeff Sutherland here, because his original blog post has been archived and may soon rightfully be buried entirely: "People who are not committed to the project and are not accountable for deliverables at the meeting do not get to talk. They are excess overhead for the meeting. ... Whatever we call them it should have a negative connotation because they tend to sap productivity. They are really suckers or parasites that live off the work of others. Sorry to be political [sic] incorrect but others should come up with a euphemism that conveys the right balance between being "nice" and communicating clearly that eavesdroppers must minimize their impact on the productivity of the team." Perhaps the goal is laudable, but the sentiment is so wrong as to be repulsive.)
- Inhibited Refactoring. Mock-based tests must have special knowledge of a class' interactions with its collaborators. We gladly accept this special role of tests, as it allows us to test otherwise impenetrable code. By testing interactions, however, we create dependencies on design structure. Refactoring changes the structure of code, which breaks naïve structure-dependent tests. Tests that extensively use test doubles can exhibit structure-sensitive breakages which dissuade programmers from refactoring. Fear of refactoring is death to system evolution.
A proper unit test should have a clear intent, signaled by the name, and should read as though it is explaining the code. To a certain extent, though, the test will rephrase or paraphrase the system under test. If the system under test is not structure-shy, then the mock-enabled tests will also not be structure-shy. In general, the tests should be as simple as you want the code to be.
A test with extensive mock setup signals a class with many dependencies or too little encapsulation. A class designed with the Law Of Demeter in mind will be structure-shy, making it more cleanly and easily tested with partial mocks.
- Tool complexity. Third party mock libraries like Rhino Mocks and Mockito are getting better at allowing you to write expressive tests, but they all introduce complexity. You must first learn a tool's extensive API and unique view of mock usage, which can include subtle nuances around things like partial mocks and void methods. Some tools even support multiple styles of mocking, each with its own special syntax. You must also learn how to read often-idiomatic code required to implement these various nuanced mock recipes.
Refactor tests to eliminate redundant test double detail*. Good tests require high levels of abstraction, emphasizing readability and de-emphasizing mock implementation details. Extract the idiomatic, tool-dependent code to small, declaratively-named helper methods.
- Passing tests that indicate nothing. A naive mock-based test may tell you that function X is called twice, and function Y is called once, but it does not tell you if you have a good design or even if you will get a good result. A heavily-mocked test suite may not behave in the same way that the underlying code will behave in production. It may have assumptions about handling of nulls or exceptions that are not coherent with production code. Worse yet, a test generated via 'tracer bullet' method may exercise a class or method but provide no useful information or evidence of correctness.
A proper unit test is more than function counting. To combat unrealistic mock scenarios, examine the code as-written to determine weaknesses that can be simulated and explained in further tests. Avoid writing tests that are mere exercises of code, and have no clear intent.
- Testing mocks rather than the SUT. In a maze of test doubles, stubs, mocks, and partial mocks, one can become lost in the entanglement between tests and production code. A feature may appear covered by tests, all passing, but fails in production. Deeper exploration reveals that someone unwittingly replaced the method being tested with a stub. This always happens in subtle and indirect ways, and always results in face-palming.
It is important to be careful when mock setup has been extracted from test methods. One may not be aware that the method under test has been replaced by a mock in some shared setup method. Avoid using stubs that are distanced from the direct class target of a test.
- Low readability. Tests can require significant amounts of detailed setup ("record") and verification ("expect"). Such clutter makes it hard to tell which expectations are simulation-enabling and which are the crucial assertions of the test.
The primary goal of test doubles is to emulate collaborators in as simple a fashion as possible. Well-designed test doubles have virtually no logic, and well-designed classes only directly interact with a few collaborators. When interactions are many and span many classes it is because the system under test is too structure-sensitive. Refactoring the system under test to be structure-shy will help reduce the number of collaborators that demand mocking, which in turn will simplify its test. Extracting methods which interact with other classes or APIs will allow effective use of partial-mocking.
- Ambitious mock implementations. Fakes--objects that completely emulate all aspects of a collaborator--require implementing redundant behavior, which sometimes requires involved logic. The problem with real logic, as opposed to simple stubbed methods, is that it's easy to screw up. Recently both of us have been working with code that uses a massive faking scheme, and both of us have wasted considerable time in implementing, deciphering, and debugging the fakes.
If you have many tests that require variant test double behaviors for a single collaborator, absolutely resist the temptation to combine these into a "mock mother." One mock, one behavior. Combining behaviors into a single test double class will quickly lead you down the divergent path of maintaining mocks for a living. Keep your test doubles simple and discrete!
- Vendor dependency. You'd think we would have learned our lesson years ago. We created Java systems that rampantly interacted with JDBC (an almost direct mapping to SQL statements). Most of us moved to APIs that provided higher levels of abstraction, such as JDO, entity beans, and Hibernate. That transition was painful, mostly because of the highly-redundant, highly vendor-dependent code that we allowed to seep into hundreds of classes and thousands of methods.
Mock tools are no different. Some of you chose RMock several years ago, and some of you probably feel that you're stuck with it due to its pervasive use in your system's tests. Too bad. Mockito is a great tool, but we imagine a better one will come along when Java finally sports closures (Java 8? 9? ...). We want to transition to this new tool without so much pain.
The recommendation is, once again, devise small, cohesive methods that encapsulate mock tool details.
By Jeff Langr and Tim Ottinger
Well, the title of this post is just wrong. The generic term for "things we use in testing to emulate production behavior" is test double, not mock. The casual programmer may bandy about the term mock when they mean test double, but it is technically incorrect and may lead to misinterpretation. We've never seen it make much of a difference to the end result of a programming conversation, but there are distinct definitions for the various implementations and uses of test doubles.
The term mock object stems from a 1999 paper by Tim Mackinnon, Steve Freeman, and Philip Craig, "Endo Testing: Unit Testing With Mock Objects." The authors' simple definition: "a substitute implementation to emulate or instrument other domain code." Mocks, or whatever you might call them in 2010, still serve the same purpose.
Use of mock objects in TDD circles grew dramatically over the next several years. Debate grew dramatically, too. The community debated about (a) whether or not to use them at all, (b) in what situations they were most appropriate, and (c) whether or not to use one of the mock tools that were starting to proliferate and pro-create.
In 2006, Gerard Meszaros published the book XUnit Patterns, which enshrined a handful of nuanced terms for the various kinds of test doubles. These terms had been shopped around in various agile forums for some time leading up to publication of the XUnit Patterns book. Today the taxonomy is commonly accepted by programmers and mock frameworks alike (oops, but "mock frameworks" itself is a misnomer, as these frameworks usually support all sorts of test doubles, not just mocks).
- Test Double is the generic term, the phylum for all our species of testing dopplegangers.
- Stub - An object that returns a specific, fixed value to the system under test (SUT). Stubs are usually constrained to a small subset of methods defined on a collaborating class. "When someone calls the
pricemethod, return the value 9.99."
- Fake - An object that completely emulates its production equivalent. The classic example of a fake is a lightweight, in-memory "database" object that allows for simple, fast emulation of a relational database interface.
- Mock - An object that self-verifies. A mock asserts that information sent to it is as expected. A test that uses a mock defines and verifies this expectation.
- Partial mock - An object that contains a mixture of production method implementations and mock method implementations. Partial mocks are generally used when you need to emulate non-existent behavior (i.e. abstract methods) or troublesome behavior defined on the same class you are testing, something that might indicate questionable design.
- Spy - An object that simply captures messages sent to it, so that the test can later verify that the SUT interacted correctly with its collaborator.
So, where do we stand on the debate? (a) Yes, use test doubles (b) when you must, (c) and use a tool if it makes things easier or clearer. Next time, we'll talk about more important things, such as what pitfalls to avoid when working with test doubles.
By Jeff Langr and Tim Ottinger
Font is Andrew Script
It is no surprise that organizations struggle when attempting to transition to agile methods. As with any new venture that threatens the status quo, the list of objections is long and varied. In developing this card we collected over a hundred typical sentiments and grouped them into about a dozen categories--too many for a single card. In keeping with our personal vows of brevity, we present here the first card: Objections borne out of organizational and cultural circumstances. We will present reasons that stem from individual belief systems and biases separately.
In order to help transitional consultants and rank-and-file people who are struggling, we provide commentary and counter-arguments.
- "It Can't Work Here" There is a common assumption that Agile methods require a special set of initial conditions. Most companies believe that their own situation is unique, their software uniquely complex, their market position too tenuous, or their management system too inflexible. Given such specialized initial conditions, how could a general-purpose method based on simplicity possibly work?
Agile is not so much a set of a constraints and rules as it is a framework in which a team can continually discover its own limitations and then derive better approaches. There are few necessary initial conditions beyond an agreement to work together in an incremental and iterative way.
- "They Won't Let Us" is a special condition of "It Can't Work Here." Agile methods may be deemed feasible and even advantageous among the technical crowd, but may seem counter to the organizational culture and/or management habit. For instance, there may be a competitive personnel evaluation system for staff which frustrates attempts at collaboration. The management might have a strong command-and-control model which prevents self-organization. Perhaps the organization is built upon the concept of a strong lead programmer directing a squad of "code monkeys." Maybe schedule pressures are so great that there is no slack to spend on organizational learning. It may be that the team cannot modify the layout of the office due to union issues or concern for decor.
Agile methods are advantageous to development and product management since they provide more data about the team's real progress, allow better focus on important features, and require very limited limited overhead to practice. While some aspects of Agile practice are clearly focused on management practices and product management strategies, an increasingly capable team can usually cope with difficult organizational practices in the short term and can win over leaders in the long run.
- "Guilt By Association" refers to the situation where Agile methods have not been tried, but at first blush seem to resemble other methods or practices that have fallen from favor. Sometimes Agile is associated with uncontrolled "cowboy coding." Other times Agile is perceived as a trick by management to force programmers to work harder. It may be confused with ceremony-heavy consulting-driven methodology. The poor image is often tarnished further by tool vendors hoping to cash in on the latest buzz with tools that are rarely necessary, of limited helpfulness, hard to learn, tedious to use, or even detrimental to collaboration and communication. An Agile conversion project may follow on the heels of other failed "flavor of the month" methodology attempts.
Agile is a low-ceremony, disciplined way of working built on concepts and ideas that have been successfully applied in the software industry for many decades, and longer in other industries that still embrace these principles today. It is a simple, incremental approach to team software development that requires little tooling beyond a place to sit, a whiteboard, a good supply of index cards, and a few rolls of tape. It would be a shame if an unfair prejudice caused us to miss out on an opportunity to build a truly great team.
- "Means/Ends Juxtaposition" is a variation on "cargo cult" mentality. A typical non-agile company will have layers of policy and management practices built on strict phase separation, copious up-front documentation, individual accountability, rigidly-defined hierarchical roles, and/or tail-end quality control processes. Artifacts produced by these practices become the primary output of teams, and enforcing mandated behaviors becomes the primary concern of managers, even though neither contribute meaningfully to quality software development.
An organization attempting to transition to agile may fall into the same trap by rigidly applying so-called agile practices. Numerous teams claim (capital-A) "Agility" because they hold interminable feckless retrospectives, prescribe stand-up meetings that provide only vertical status, or prolong interminable pair "marriages." Stand-ups, retrospectives, and pairing are extremely valuable tools, but only if you are able to align them with agile values and principles.
To succeed at agile, we must first understand that it is a continual journey of team discovery, and not a rigid set of practices. We must have some sense of where we want agile to take us, and that the journey will reveal unforeseen challenges and opportunities. Agile development is about growth rather than conformity.
- "Inferiority Complex" The team that ships quality software on a consistent and frequent basis exhibits a high level of confidence. A team that lives with frequent failure and inability to estimate quality of product will exhibit a low level of confidence. An observer may attribute the confidence and ability of the team as an initial condition and not as an eventual outcome of the process, surmising that confident superstars are a necessary initial condition of agile success.
The Pareto distribution suggests that most teams simply don't have enough star developers to conquer this mistaken understanding of agile. Real concerns over minimizing entropy in a rapidly changing system engender pure fright: "How can we possibly introduce new features without pre-conceiving the entire design? Our code is horrible to start with, and we've tried to write some unit tests, and it's just too hard." A large number of teams ultimately feel they lack the skill to produce anything of value in a short iteration.
Agile software development is about teamwork, not about superstars. For example, pair programming helps make TDD less difficult (for everyone, superstars and supernovices alike); TDD in turn provides us with the means to safely refactor code; refactoring sustains quality design in an extremely dynamic environment. Likewise, introspection and teamwork allow for continual improvement. Agile is a means to raise the competence of a team and lower the difficulty of working with a code base.
- "Superiority Complex" is when an organization feels that they have a pretty good handle on things. They have a process that has allowed them to deliver successfully in the past, and regard any change in practice as a step down. Practices like TDD and pair programming are regarded as training wheels for junior programmers, and wholly inappropriate for serious software professionals. They may believe that they have a special gift for up-front design that makes incremental design wasteful and unnecessary. The organization believes they have transcended the need for Agile practices.
There will always be those who think that the world has nothing left to teach them. If the organization is perfect, there are no flaws to uncover, no waste to reduce, and no improvements for agile to bring. Since agile methods are about doing, measuring, and reflecting on the work, we often find that Superiority Complex is based mostly in wishful thinking and a lack of measurement.
If, on the other hand, a company has found the techniques that leave Agile in the dust, we would love to learn about and adopt this superior method at work. Agile methods are perhaps not the best methods possible, only the best ones we know as of this writing.
- "Rejection of Insufficient Miracle" is the tendency to refuse to use a practice which leaves any current problems unsolved. "It's all or nothing, baby!" A team that cannot automate all testing sees little point in automating tests at all. Incremental development does not guarantee that a certain date will be met with all features in place, so there is no reason to iterate. The team must collaborate with other groups which do not work in an Agile way--what is the sense in only part of the company being agile? If we can't guarantee everyone will refactor the code, why should anyone spend the time cleaning up the design? By refusing incremental improvements, the organization rejects the very soul of the Agile way of working.
Samuel Johnson once said, "Nothing will ever be attempted if all possible objections must first be overcome." All software projects, even one that might be hypothesized to be free of technical error, are prone to failure from myriad reasons. All products, teams, and organizations are "insufficient miracles," leaving many of life's problems unsolved. Seeing that we have all gotten out of bed and come to the office, the question is whether we want to try a process that maximizes learning and quality (without guarantees), or an equally guarantee-free process that does not.
We fully recognize that there are teams that will not want to use Agile methods, and we suspect that there are organizations unwilling to modify their practices to accommodate a new style. We suspect that any method will not be successful in such organizations and that abandonment may be a reasonable strategy. As they say, "Change your company, or change your company."
In time, we may discover ways of fulfilling the promises of Agile with other methods. Agile is not the only possible way to improve an organization, even though we have found it to be one exceptional way to improve software-developing companies.
If, on the other hand, an organization is not interested in the kinds of benefits Agile methods promise (teamwork, growth, quality, productivity) we recommend that they become our competitors.
Font: Mechanical pencil for body, Erwin for heading
Sources: Tim Ottinger, George Dinwiddie (via mail list), Jeff Langr
Branch-per-feature is a common SCM strategy in which a branch is created on a central server for each feature that is under development. As a feature is completed, the branch is integrated back into the main development code line.
In some organizations, releases are composed by merging selected, completed features together. This seems quite rational, and can be made to work with enough effort applied in bursts. Every merge creates a unique, new configuration in the system that must be tested for side effects. If the merge has unintended consequences, then one or more features must be modified or the release re-composed without it. As a result, releases become major events in the life of the company with huge testing parties and great schedule risk. These times are frequently called "hell week" or "hell month" depending on the release periodicity.
In addition, the more two lines of code diverge, the harder it is to reconcile their changes. When work is integrated several times a day, it tends to be a fairly trivial effort. When it is integrated only a few times per month, it is rather harder. A few times a year, and it is surprisingly difficult. Likewise, if many branches are held for a long time, each branch will not only diverge from the main codeline but from other branches as well. This effect can make it rather difficult to estimate the effort of integrating branches, which contributes to the nervousness around hell week.
Agile teams integrate continually with great ease and success. Why, then, do some organizations hail branch-per-feature? Teams that use branch-per-feature as regular practice are often compelled to do so because they don't know which tasks/stories will actually be completed by the end of the sprint. It seems easier to hedge bets with version control systems than to tackle the organizational/political problems that frustrate planning and execution of sprints.
- Too much WIP (work-in-process) means that too many tasks are undertaken at once. Branch-per-feature helps the team deal with the fact that work is not being finished predictably or reliably within the iterations. Many tasks are reported complete on the last days of the iteration, yet some of those are rejected. Branch-per-feature allows management to decompose and recompose the release at the tail-end as they find out what is actually completed.
In an agile team, as many as half of the features are done by the midpoint of the iteration and are being tested frequently. Very few changes are actually at risk of being left incomplete. In the best teams, missing an iteration boundary is a rare event, so branched features are unnecessary.
- Features are too large if they cannot be completed in a small part of a single iteration. Otherwise the uncertainty prompts the team to fork the code base. The forked code base is more difficult to integrate as it diverges from the original code line. Fear of difficult integrations actually encourages the team to hold isolated branches longer.
Agile teams instead look to ensure features are small enough to completed within a few days. Small features completed in a day or two rarely require complex merging. Any overlap of effort can be easily coordinated with other team members during stand-ups or ad hoc conversations across the team table, further minimizing the chance that a merge will be necessary.
- Structure is poor if changes routinely span many files in many libraries or assemblies (something Martin Fowler refers to as "shotgun surgery"). When a feature's implementation is scattered all over the code base, it is harder to accurately make changes and harder to predict when work will be truly done. This uncertainty drives the team to isolate rather than integrate.
Agile teams are highly cognizant of the value of simple, SOLID design. They understand that systems exhibiting true cohesion and minimal duplication dramatically lower the need for shotgun surgery.
- If there is no way to turn off incomplete features then the team will fear customers stumbling into incomplete sections of code and causing damage to data or additional customer support burden. This force drives developers to develop code in isolation from the main codeline, which of course increases the cost of integration.
Agile teams view changes to the system holistically, breaking down each new feature as a series of incremental changes to the mainline. They understand that while this requires some level of overhead, it means that merge hell is minimized, and that it demands a better system design. For larger changes, they look to solutions such as branch by abstraction as helping provide both benefits.
Authors: Tim Ottinger and Jeff Langr
Font: Burst My Bubble
Programming pundits often decry the dismal state of code in the world. We hear speakers demand professionalism or a more craftsmanlike value system, rigorous certification, etc. In response to these very demands we find contradiction of these very concepts. The argument is frequently made that whether code is "good" or "bad" is subjective and situational. We beg to differ.
To promote a shared set of programming values, we propose these seven virtues of code:
- Working, as opposed to incomplete
A program that works is simply superior to one that doesn't work. We contend that a working program now is of higher value than one that might work some day. To this end, incremental and iterative methods (such as agile methods) push us to complete small features as soon as possible, with improvements and expansions to follow.
We ensure code is working by writing tests before and after writing code as we consider more success and failure modes. We can tell code is working by running the tests and by using the software.
- Unique, as opposed to duplicated
The worst thing we can do to working code is to duplicate it. Copies and near-copies scattered willy-nilly across the code base makes code difficult to maintain. We struggle to eliminate duplication each time we refactor in our red, green, refactor cycle.
A dirty software industry secret: Many "stepback" or "regression" errors are not really re-broken code, but are instead examples of fixes to duplicated code.
We can tell that code is duplicated visually (common paragraph structures) or by the use of duplicate detecting tools like Simian.
- Simple, as opposed to complex
Simplicity here refers to the number of entities, operations, and relationships present in any particular routine/function, and not to the readability of that module (which we call "clarity").
The best way to increase simplicity is to use simpler structures and algorithms. Reducing complexity in this way often translates to improved runtimes, smaller code size, and easier optimization.
We can also improve simplicity of one routine by extracting methods so that a series of manipulations becomes a single step as far as all of its callers are concerned. By moving the extracted methods to the appropriate classes, we also further develop the type system. After extraction, the code still takes all of the same steps, but those steps are evident in far fewer places in the code. The extracted methods are also simpler because they are unencumbered by their original context, a fact which aids us in finding yet simpler algorithms and structures.
Such simplifying code migration is at the heart of object-oriented design.
- Clear, as opposed to puzzling
The meaning and intent of code must be obvious to the reader. Code misunderstandings generate errors. Confusion over code creates delays.
While high-level languages make it easy to see what code is doing, there is still an art to producing code which communicates its goal and intent. The consensus of multiple readers is nonetheless a reasonably consistent measure of clarity. Therefore, the most reliable way to make code clear is to have multiple colleagues reading it.
When one sees an improvement in readability from merely renaming variables, classes, or functions it is because one has improved clarity without changing any of the other virtues of the code. Clarity is further amplified by other virtues such as simplicity and brevity.
- Easy, as opposed to difficult
Adding and modifying code should not be an arduous process. Ease is largely a matter of how much code must be typed in how many places, and how much configuration must change. In a particularly ugly code base, the easiest way to get code working is to implement a hack in an inappropriate place. In a truly clean and simple code base, putting a correct design into place is often as easy as a hack. Uncle Bob Martin has stated that design has degraded when the doing "the right thing" is significantly harder than making "an ugly hack."
- Developed, as opposed to primitive
A primitive system is not necessarily simpler (fewer parts), nor easier (less thinking and typing), nor more clear than a developed system. Primitive code tends to be characterized by Duplication, Feature Envy, and Primitive Obsession code smells. These make a primitive solution more complex, more difficult, and less clear than one built with a well-developed type system.
In an object-oriented system, the developed type system of an application provides well-thought-out classes whose methods make continued development easy.
A system is well-developed when functionality appears to be just where one might expect it. String methods on strings, account methods on accounts, and button activations and the like merely make calls on "business objects."
- Brief, as opposed to chatty
It is valuable for code to be as brief as possible without sacrificing other virtues. This is part of the reason that language tools like LINQ and list comprehensions and closures have become so popular of late. All programmers, including the one who writes it, benefit from writing and reading less code (as long as this smaller amount of code is otherwise clean).
Code that is long and chatty is much more likely to contain hidden errors. An overly cryptic method is likely to be misunderstood. Either one is hard to take in at a glance and understand.
Playing "programming golf" is actually a meaningful activity. If one can make the solution to a problem smaller without sacrificing clarity (or indeed may improve clarity by reducing the solution to a smaller form), then one is reaching a more brief form. The distance from an ideally brief, clear form is unwanted verbosity (chattiness).
By Tim Ottinger and Jeff Langr
Font is Kristen ITC
We have already discussed organizational objections to adopting Agile work methods. Here we discuss the personal objections.Agile development has never claimed to be an easy fit for all organizations.
We understand most of the reasons that agile transitions can be quite difficult for organizations. Likewise, individuals may be emotionally invested in certain structures and practives so that converting to an agile workstyle is perceived as threatening and undesirable. We again spent time collecting and categorizing a great many complaints, finally boiling (most) of them down to fit on our 7 +/- 2 bullet point format. We find the categorizations given here to be helpful, and hope that they will be useful to the coaches, managers, and developers who visit the Agile in a Flash blog.
- Personal Bubble/Social Dysfunction The software development industry's long history of attracting anti-social sorts aside, there are some legitimate reasons that people retreat into a personal bubble. Some team members may have bad history together, ranging from the awkward (ill-fated past romance) to unpleasant (adversely opinionated pair) to intolerable (abusive partner). Some suffer from issues such as a simple timidity, fear of exposure for doing non-work tasks at the office, or a tendency toward introversion. There are iron-clad issues such as actual mental or emotional disabilities. Cultural issues can make understanding each other in a team more difficult.
The personal bubble is a tough issue to overcome, but we don't work in tight teams because it is comfortable. We work in this manner because of the advantages it can bestow:
- improved code quality
- ongoing opportunities to learn new techniques
- wider exposure to the code base
- a trustworthy, open communication channel with the customer
- process improvement based on experiential data
- a team aligned on common goals
- Lone Ranger Teamwork is the Agile Way, but some individuals prefer immediate gratification with immediate recognition. The fictitious Lone Ranger would ride into town, solve a mystery, rescue the innocent, restore the peace, and disappear, leaving behind a single silver bullet as a signature. This romantic vision is appealing to many programmers. Everyone dreams about being the hero.
The downside is that a team is functional to the degree that it does not need to be rescued. The Lone Ranger may have been the hero of the day, but he did not share the knowledge and techniques that led to his success. The Lone Ranger does little to help the rescued learn how to solve similar problems in the future.
A better role model is the Karate Kid's mentor, Mr. Miagi, who not only rescues Ralph Macchio's character, but also teaches him to fend for himself. Skilled practitioners who can teach others are superior assets to the team and the organization. Agile teams provide superior mentoring, which leads to teams developing the art of making good decisions.
- Old Dog "Habit is habit," said Mark Twain, "and not to be flung out of the window by any man, but coaxed downstairs a step at a time." This is especially true for those productive habits which have served us in the past. Sometimes people don't want to learn any new technologies or methods, and even those who are excited about new skills will revert to old habits under pressure.
Agile presents significant challenges to the old dog. Practices like TDD require developers to think about solving problems in a different, even inverted manner. Agile planning can invert the flow of how everyone thinks about their work--people once at the tail end of the cycle must think about how their role changes as they look to provide value earlier and more incrementally.
It may help to realize that agile is not only a change to how the code is written, but a way to ensure that the individuals in the team can develop personally and as a team. It is a way to optimize the meaningfulness of the work that is done. It is a means to gain respect for a developer's contribution. It is likely to increase the perceived value of the Old Dog's work, rather than merely inconvenience him.
- Zero Sum Game It is especially hard to engender cooperative behaviors when the development team (or its leaders) are competing against each other for position, respect, compensation, or autonomy. If the team thinks in terms of a zero-sum game, then they feel that they can only win if their teammates lose. In organizations with a history or risk of layoffs, developers will scramble to avoid being at the top of the pay hierarchy or at the bottom of the performance stack, knowing that those ends tend to be chopped first. In organizations that reward individual effort, one feels the need to be the last to leave and the first to arrive to beat out his so-called "colleagues."
Agile promotes a different system. There is more than enough work to go around, and more than enough improvement possible for us all. There is plenty of credit to share. The Mr. Miagi sharing-and-mentoring model comes into play, and we can grow through our contributions to our teammates and our project. We can all have more success, and it lessens none of us.
- Inferiority Complex The individual may fear he is less capable than his teammates, and may seek to hide his inabilities by working alone. He may be concerned about slowing down his teammates, or dreading daily humiliation at the hands of his teammates. Looking at the famous "rock star" agile developers, the insecure developer may fear that he could never measure up. The most senior persons on a team often fear displaying their few deficiencies in a pairing session.
The nice thing about a functional agile team is that you eventually will get over that sore ego hurdle. Things like switching pairs frequently to avoid silo pairing, collaborating in an open workspace, and delivering working software every few weeks all create true transparency.
A motivating fact is that pair programming is a path to personal improvement. Pairing with star programmers tends to make one into a star programmer. In relatively short time, any interested individual can become surprisingly competent. It is mostly a matter of seeing how it is really done, asking questions, and getting some guided practice.
- Superiority Complex An individual who feels she has a pretty good handle on things may also believe that it is beneath her dignity to be "forced" to work with "mediocre" teammates. She may feel that she is the only one capable of working in agile, or that she is far above the use of common methods. Sometimes she even feels that she's already learned everything worth knowing about software development. To her, teamwork requires her to drag along incompetent partners, a practice that will slow her down and provide no personal upside.
As agile coaches, we react most strongly to the intransigent, overly cocky developer--but we need to remember that a projected superiority complex can actually be a mask for inferiority complex.Pairing can let the overconfident member fail more visibly, which can allow coworkers to help correct her shortcomings.
Some rightfully confident developers find that they also enjoy coaching and developing their coworkers. Bluster fades when developers realize that they are not competing against each other, but against errors and code faults. Finally, a developer with top chops in a pre-agile organization will usually emerge as a leader in an agile organization as well.
- Rejection of Insufficient Miracle The individual experiences problems in the development team that are not addressed by agile methods. She realizes that it will not make all the teammates act like best friends, and won't make customer pressures or payscale changes any better. It may not make them happier in their workspace. Since the new system does not solve their individual issues, they have no reason to use it at all. It is not miracle enough for them.
The agile focus is on unencumbered and incremental development of the product, the team, the customer relationship, and the organization. Agile is more of a system in which to identify and address problems than it is a method or methodology.
One might choose to wait for an absolute solution to all problems, but in the meantime it might be good to invest in daily incremental improvements. Agile--in our view, the currently best bet for most software projects--will eventually fall out of favor for a better approach. We don't know what will supplant it, but we can confidently bet that the new methods won't involve eliminating incremental growth. Good things come to those who wait, but only if they work hard while waiting.
source: Tim Ottinger & Jeff Langr
font: Brown Bag Lunch
Do agile teams require leaders? Neither the agile manifesto nor its principles speak about leaders. Instead, the principles emphasize teams, and the penultimate principle says that the "best architectures, requirements, and designs emerge from self-organizing teams." A self-organizing team would seem to obviate the need for a leader, at least in the classic organization's notion of being "singular and fixed."
But all teams, agile or not, need leadership. "Self organizing" is tough, and it's often far more effective for someone to guide a team along at times, through its various challenges. This leadership comes from someone who at the moment has the experience, the clarity to help drive the best plan, and the people skills to make it happen. Such leaders can be external to the core team (such as the ever-present line manager), but a successful agile team accommodates more dynamic leadership. Leaders arise from within as needed. The team learns how to support individuals in this role, however temporary it might be.
A successful agile team embraces incrementalism for all activities required as part of software development: planning, requirements gathering, analysis, testing, design, coding, review, and delivery. Leadership is but one more team activity that is best executed on an incremental and continual basis. At times an agile team member may fulfill the role of leader for perhaps a couple minutes.
Effective leadership requires four values that agile team members should also hold dear:
- Benevolence: The team must trust that their leader won't throw them individually or collectively under a bus, that the team's achievements will not be used against them, and that their faults will not be grist for public humiliation. A benevolent leader is not a pushover, but even in confrontation, his interest is in improving the team and its members.
- Effectiveness: If one cannot get things done, one cannot lead others. A recent study shows that the greatest motivator for "working people" is the ability to make progress. An effective leader will help make it possible for the team to make real progress every day. Within a team, the person who knows how to get started often emerges as a leader; this leader must also know how to keep moving forward when others would be blocked.
- Strength: A leader does not lose her head in a crisis. A leader's infrequent NO carries weight. She does not beat up on her inferiors in order to look tough. If necessary, a strong, benevolent leader will remove some people for the good of the rest of the team. She provides feedback appropriately, instead of sweeping things under the rug or embarrassing team members with needless public confrontation. (Remember the old adage, "praise in public, punish in private.") Respect is best earned, not extorted.
- Temporariness*: A good leader does not install himself as a fixture in the company or team by building reliance on his personality and special knowledge. Knowing that success may lead him to new places, he is always helping others understand what it will take to replace his leadership. His actions when he is present will allow the team to continue successfully when he is absent.
* "Temporariness" is a real word. We looked it up.
font: Daniel Black
Refactoring is perhaps the most significant part of sustaining a system in an agile environment. Entropy in a system is reality: Code degrades unless you make strong efforts to stave off the degradation. You need good controls (tests) that provide rapid feedback in order to effectively keep a system clean. If the system attains a state where its design is poor, maintenance costs can become an order of magnitude larger. This can happen more rapidly than you think.
Agile can exacerbate poor practice. You don't do a lot of up-front design, and you constantly add new features that were not pre-conceived in an original comprehensive design. Repeatedly forcing features into a design will result in a disaster unless you have a means of righting the design over time. That's what refactoring is about.
With the need to avoid degradation, it's important to recognize anything that might prevent a team from refactoring as much as they must. This card provides some inhibitors to refactoring that you should watch for.
- Insufficient tests. Experienced developers know when they do the wrong thing, something that degrades the quality of the code. Yet much of the time, they don't follow up and fix the problems they just created. Why not? Too much fear over shipping a defect. "It ain't broke, don't fix it." They don't want to do the right thing, because that would require mucking with code that's already working--code that's not even "their" code.
The right thing is to retain a high-quality design through continual incremental refactoring, which requires the confidence to change the code. That confidence derives from very high levels of unit test coverage, which you can obtain through TDD. You won't get the confidence from test-after development (TAD), which at best nets around 70% (and often the complex areas are in that 30% of uncovered code). TDD enables confident refactoring.
- Long-lived branches. The right thing is to ensure the system has the best possible design through continual refactoring. But developers working on a branch want to avoid "merge hell," and will plead for minimal refactoring as long as the branch exists. Branches should be short-lived.
- Implementation-specific tests. "Changing the design of existing code" should not create the need for a lot of test rework, particularly if you are changing details not publicized through the class interface. The need to mock generally exposes information to a client (the test) that could otherwise remain private. The use of mocks should be isolated and abstracted. Make sure you're refactoring your tests! Minimize test-to-target encapsulation violations created by mocks.
- Crushing technical debt. If you've not refactored enough, you'll soon be faced with a daunting challenge--code rampantly duplicated throughout the system, long (or short!) inscrutable methods, and so on. Once a problem gets bad enough, we tend to look at it as a lost cause and throw our hands up into the air, not knowing where to even begin. Don't let technical debt build up--refactor incrementally, with every passing test!
- No know-how. Understanding how to properly transform code is one educational hurdle. Knowing if it's a good move or not requires continual learning about design. Developers without significant background in design will be reluctant to refactor much, as they're not sure what to do. Learn as much as you can about design, but start by mastering the concept of Simple Design.
- Premature performance infatuation. The goal of refactoring is better design, which to most means more cohesive and decoupled. That means a good number of small classes and small methods. A simple refactoring, like extracting a method solely to improve cohesion and thus understanding of code, can frighten some programmers. "You're degrading performance with an unnecessary method call." Such concerns are almost always unfounded, due to things like HotSpot and compile-time optimization. A true performance expert, working on a system with some of the highest transactions in the world, backed me up on this one. Make it run, make it right, make it fast. -Kent Beck (and make it fast only if you measure first and after)
- Management metric mandates. Management governance (wow, do I hate that word) by metrics can have nasty, insidious effects. Examples:
- "You must increase coverage by x percent each iteration." Actual result: Developers tackled each story with a hacked-together written integration test, not a unit test, that blew through as much code as possible. Developers then hastily created new tests by copy-paste-vary. No time left to refactor--they just need to hit their coverage numbers! Later, changes to the system would break many tests at once. Since the tests were barely comprehensible, developers began turning them off.
- "We need to reduce defect density." Defect density = defects / KLOC. Well, anything based on lines of code is useful only as far as you can throw it, and you can't throw code (the bits fall everywhere). You can improve defect density by reducing defects. Or, you can increase the amount of code. Most programmers aren't as evil to deliberately create more code than necessary. But if you say to your pair, "hey, we should factor away the duplication between these two methods that are 500 lines each," there will be either a conscious or subconscious decision to resist, since it worsens the metric.