Thursday, February 25, 2010

The other build. The one that SHOULD be broken.

I was recently on site with a client where I was sharing my experiences with Test Driven Development (TDD), and how it can help with different types of problems. Note that this client has nothing but sharp, enthusiastic, and friendly employees. Unfortunately their development process has severely limited how quickly they can release new products to the market. A large new infusion of capital was called for to modernize their systems and their practices. My little software consultant shop was hired to help with both endeavors: help improve the software and help improve the process.

This particular week, I met with the head of the QA department and had a good one hour discussion about the merits of TDD and specifically my experiences in different types of organizations: teams with technologically-savvy QA staff and those without.

This positive first meeting lead this manager to ask me to demonstrate to a larger audience a very specific technique: how do you test something that isn't built yet?

Developers practicing disciplined TDD do this often, many times a day, with our unit and integration tests. We write tests that at first don't even compile, much less pass and “go green”. Our IDE's feedback mechanisms are practically screaming at us to fix these problems. We get to the point where we don't even consider this practice odd (or "backwards") at all. Many of us come to like it so much that we never want to go back. But from a product QA perspective, where they're (mostly) thinking about acceptance testing, I realized that as a community- perhaps we Agilistos have done a poor job communicating how this can happen. For example, I was asked, "How in the world can I test a web page that hasn't been built yet?".

Having the most experience solving this particular problem using Selenium, I rehearsed for about 20 minutes before the meeting to make sure I could pull off something useful. I made sure I coded a few simple, but non-trivial acceptance tests that failed (because the web page didn't exist yet), and then incrementally developed the (dreamed up) feature so that within 20 minutes or so all the tests passed.

Then the meeting: I proceeded to do the same demonstration for the larger audience, which took about two hours. Why so much longer? Well, first of all- it was less a demonstration and more of a discussion: we discussed the techniques; the technology (Java, Spring, Groovy, Selenium, MVC); switching roles between product owner, tester, and developer; and encouraging them to do the same. They also came up with a much better idea for a feature to build in this demonstration, which happened to be slightly more complex but still feasible. I resisted the urge to fall back on exactly what I had rehearsed, but felt a little like I was living without a net.

I'll share the feature because I think it's important to illustrate just how small of scope we aimed for: the beginnings of a Help section of a web site. We wanted a Help-Menu page with links to other Help sections: help with cookies and help with signing in. They wanted the page accessible when the user was signed in and when they weren't yet. As we continued in product owner role, we realized we didn't want the "Trouble signing in?" link on the page in the case when you've already signed in. And lastly, we needed a link, from the top navigation, to this new Help-Menu page, visible in both user states (signed in and not). That was it. Pretty simple.

The real meat of the "How to test a web page that doesn't exist yet?" was mostly explaining how we can use Selenium's API and locators to expect certain text or behavior on any web page, even one that hasn't been built. We had healthy discussion about how some locators (such as overly specified XPath expressions) end up influencing and restricting how the developers build the page. In our case, I recommended using the link text as the locator, so that the developer would be free to develop the markup however she saw fit. So after writing just a few Selenium/JUnit test cases, we now had 4 tests that failed. 4 red lines. Perfect.

Switching now to the developer role, I designed and implemented the smallest increment of work I could think of. And of course- it was the smallest amount of work I could think of to make just one test pass. Boom- it did. 3 red lines. One green.

I really wanted to hammer the importance of this home to this team: this was, on a very small scale, the very essence of TDD. Product owners, testers and developers working very closely together early in the life-cycle of the feature. The feature isn't releasable on some arbitrary subjective metrics: it's ready when the tests pass. Who wrote the tests? The product owner, tester, and developer- together. And also- visible progress.

Then within another 20 minutes we finished the entire story and made all 4 tests go green.

We then attempted some extrapolation: imagine what our daily standup meetings would be like if we agreed to always have them around a dedicated projector that was showing two screens: yesterday's red and green bars, and today's red and green bars. I realized we had happened onto something important that isn't expressed often at all in Agile development: a Continuous Integration build that we intend to be broken. Most of the mindshare around Continuous Integration is having a build that is always green- and when the build does break (and it will rarely), it is addressed immediately. But that's a different sort of build: that one is extremely valuable from a development integration perspective, but arguably worthless from a "delivering business value" perspective. And our "epiphany" was that most executive sponsors and stakeholders don't give the smallest damn about development integration- they care about progress. They shared how their executives are often frustrated because they don't see the results of all their hard work until just before the team releases to production. Which, at the moment, is infrequent.

Now imagine having this projector always on, centrally located in an open and informative workspace, where stakeholders can look at it on their way to get coffee. They'd see red bars with items like "Signed in users do not see the 'Trouble signing in?' section on the Help Menu." - but they see green bars for items like "Both signed in and non-signed in users can navigate to the Help Menu easily from the top navigation area". The next day (or an hour later) they walk by and see all green for the tests for the Help Menu feature.

How could there not be a huge increase in trust between the stakeholders and the team if this happened daily or hourly? How could this not improve communication between all roles on the team? How could this not shift the end-of-iteration burden off QA's shoulders (where it is in every single waterfall process). And wouldn't it be fun too?

Of course, these practices have been written about- Steve Freeman and Nat Pryce write eloquently and practically about it in their excellent "Growing Object-Oriented Software, Guided by Tests" book- perhaps my favorite of 2009.

And some thought leaders like Jeff Patton are starting to talk less specifically about Agile when trying to help teams. Instead they argue that visibility is everything: just make all these unintentionally hidden things visible, and most good software teams will invent their own improvements without needing to know anything about Agile.

In conclusion, TDD is practiced at several levels in the life-cycle of shipping new business value: unit testing, integration testing, acceptance testing, even deployment testing. Let's start sharing more about the other levels- the other builds, not just the development integration builds. The ones that fail most of the time, but get greener and greener as we move through the iteration: illustrating progress, quality and commitment.

What do you think?

No comments: