Seven Ways to Add Agile to Your Project
Traditional—with a Twist
7 Simple Ways to Add a Little Agile without Going to Extremes
Are you in the midst of a traditional development project that cannot take a leap toward Agile, but you know could benefit from being nudged in that direction? Does your project have stakeholders or management who are willing to discuss the merits of Agile development but won’t give you the time to investigate an Agile methodology, much less switch to it? Are you a project manager or team lead who has read or heard a bit about Agile development and wants to experiment with it but are, yourself, too skeptical to make a large upfront investment?
You’ve come to the right place.
Over the past year, the Agile community has begun to discuss and experiment with grafting Agile practices onto projects that do not follow Agile values and principles. Many teams in environments of waterfall processes, predefined requirements, and fixed costs have adopted Agile practices and delivered successfully. It can be done. After all, most Agile practices did not originate with the Agile methodologies. Rather, Agile development has identified practices that project teams have been using for decades, explored these practices in depth, documented them extensively, marked routes and hazards, and—where necessary—blazed trails.
Project teams without the authority, time, or inclination to cast aside traditional development processes still can improve code quality, respond to change faster, and even deliver more valuable functionality by adopting some Agile practices. The reality one must keep in mind is that operating in non-Agile environments can make implementing Agile practices more difficult, threaten morale, and significantly slope up the Agile learning curve. Agile practices have been deemed agile because they work best within, and support the continuation of, Agile values and principles. Remember that old cliché about the building being only as strong as the foundation it rests upon? Well, it applies here. Finally, following the paths that others have trodden (i.e., the named Agile methodologies) often is easier than charting your own. That’s not to say non-Agile projects shouldn’t adopt bits of Agile; they just need to do it with realistic expectations.
So, with the introduction and caveats out of the way, let’s get on to the list.
1. Automate and share the build process
Automating and sharing the build process should provide the biggest and quickest bang for your project buck. In a traditional development process, an anointed team buildmaster may perform the hour-long ritual of manually compiling all the project code on a daily or even (insert gasp here) weekly or monthly basis. The goal you seek is a simple push-of-a-button build process that may be performed by any member of the team.
When I say the build I mean all the code related to the application, regardless of what component or interface a programmer is working on. Compiling all the code helps to verify the correctness of assumptions, recent checkouts, and unknown dependencies. Push-of-a-button is an ideal state. The process still could be a few simple steps. (What really matters is that any programmer on the team can do a build and, if the build takes more than a few minutes, it can be left to run in the background while the programmer focuses his attention on something else.)
This practice saves a team time on two fronts. First, it frees programmers from performing mundane and repetitive work, leaving that time to be spent on more important and interesting activities. (Hey, thirty minutes a day adds up, in both real time and motivation.)
Second, an automated build that can be performed by any programmer will reduce the time the team spends chasing down compilation and convergence issues. Why? Because, suddenly, a programmer no longer need wait hours or perform a set of arduous tasks to confirm that the code he has just written compiles and integrates cleanly with the official build. Now, moments after he has written his code, he will know whether that code (at least from the standpoint of compiling) plays well with the other children in the codebase. But, you may ask, what is the motivation for an individual programmer to actually use this new tool? That’s simple. Most competent programmers will intuitively understand that a few minutes of building is well spent when it decreases the likelihood that they will be stuck at work late with the buildmaster—or called at home by a fellow programmer—to sort out their code.
While you’re at it, why stop with the build process? Consider automating build promotion. This provides testers and customers with the latest and greatest build faster, minimizes the time the team will spend on this activity, and drastically reduces the mix-ups that too often result from manual build promotion: Remember that time we accidentally pointed the demo environment at the production database? Exactly.
2. Implement a testing framework and start writing unit tests
This practice takes more investment than build automation and can necessitate some serious cajoling to get skeptical programmers (and perhaps management) on board, but its benefits are well worth the effort. To make this happen, a project team must supplant the traditional beliefs that (1) testing is for testers, and (2) one-off tests are good enough. Your goal is to create a suite of unit tests (ideally, the complement to an automated build) that can be run at the push of a button and that relies on restorable data.
There are unit testing frameworks—aka xUnits—available for a wide variety of scripting, programming, and even markup languages. (See this issue’s StickyNotes for more links to free and open source tools.) To benefit from automated testing, a team does not need to stop and write unit tests for existing code. Rather, a team simply needs to implement a rule that all new and modified code will be covered by unit tests; the comprehensiveness of the testing framework will grow over time. Tests should validate small and discrete bits of meaningful functionality. The testing framework should be run at every build, and a failing test should be treated with the same weight as a broken build. To avoid devastating team morale the first time someone wipes the database, each unit test should rely solely on restorable data.
Just as an automated build reduces the time a team spends on compilation and convergence issues, so, too, will unit tests reduce the time spent identifying and correcting defects. A testing framework that has been correctly implemented and cared for will also improve code quality and save time over the long haul as automated tests written for one release become the regression tests for future releases.
A rational programmer will be inclined to use the testing framework frequently for the same reason he will use an automated build process—to save himself from the pestering and calls at home he would otherwise get from checking in code that inadvertently breaks other functionality. Or, taking a more positive view of human nature, programmers will gain additional confidence and motivation from seeing all the tests run successfully in the midst or at the end of a coding session.
The team as a whole most likely will understand the benefits of a testing framework in one of two ways. Ideally, there will be a gradual realization that everyone is spending less time reacting to critical defects. One way to encourage this outcome might be to track and graph in a public place the number of defects reported per week. Conversely—and the outcome we prefer to avoid—the team may realize how good they had it only after they fall off the testing wagon and get run down by the Defect Express!
3. Adopt a continuous integration process
The benefit of continuous integration is less obvious than an automated build or test framework, but its potential to save programmers time and reduce defect rates is huge. The traditional process that we are trying to bump off (with Agile prejudice) is the practice of allowing separate branches of code to reside on programmer workstations and the daily, weekly, or (you can’t be serious) monthly convergence of that code into a single workable build. In its place, we want to institute a process where small bits of functionality are integrated, as they are completed, into an up-to-date and clean codebase.
There are two equally useful approaches to continuous integration. The first is a serialized process where programmers queue up one at a time to integrate their completed code into the current codebase. This approach does not require an automated build, but it is not too helpful without some form of testing to verify that new code has not adversely impacted old. The second approach allows concurrent checkins and does rely on fully automated build and testing frameworks. It is based on a build machine that monitors the source control system and—after detecting a checkin—automatically compiles and tests the current codebase. Both approaches rely on programmers checking in code as they complete small bits of functionality (typically one or more times a day).
Practiced regularly and team-wide, continuous integration is like slapping a homing beacon on the code convergence gremlin. Click the build and test button, and you will spot the little twerp almost every time. The obvious benefit is that many (dare I say, most) defects are discovered hours after they are introduced into the codebase, not weeks later after days of digging. (For more on continuous integration, see this issue’s StickyNotes.)
4. Plan and deliver in short iterations and small releases
The traditional approach to structuring software projects entails an upfront and phased plan (e.g., define, design, build, test, deploy, complain) broken down into individual task packets and rolled up into a hierarchical Work Breakdown Structure (WBS). If you do not know what a WBS is, think Microsoft Project. Agile development, meanwhile, advocates one- to four-week iterations, each with its own define-design-build-test cycle, and requires the team to release at least every couple of months. Oh, yeah, and the customer is supposed to be able to choose what functionality goes into each iteration. As you can see, putting an Agile planning process in place of a traditional one will be easy—yeah, right.
Short iterations and small releases (aka sprints) can be thought of as project plans with their binding ripped out and their tasks aggregated as features (aka user stories—the terminology depends upon your Agile methodology of preference). Features are functionality-based and sized so that they can be completed in either an iteration or a release. When a feature is complete, it should provide a new, usable, and useful experience for the user. Whether or not it actually goes to the customer, every release should contain only completed features and be fully tested.
There are several factors associated with moving from a traditional planning process to iterations and releases. If your project has a fixed scope and/or duration but no formal project plan, you should be able to readily adopt many of the trappings of Agile planning. If your project must follow traditional development phases (and there is little likelihood of getting that restriction repealed), you might be able to run iterations within the phases. Further, you might even reduce the size of the define, design, and test phases so that the low-level activities from those phases can be performed in an extended, iteration-laden build phase. (If this is your situation, you also should investigate Feature Driven Development, an Agile methodology that stipulates some upfront define and design activities.) Lastly, if your project has a strict WBS and somebody holding it like a club over your head, you still may be able to adjust the timing of tasks to resemble monthly iterations within the WBS.
Agilists live by short iterations and small releases for a number of reasons (there’s space for only a few here). First, they provide regular cycles that can be used as feedback loops to measure project progress and team productivity. Second, they allow project stakeholders to change the direction of a project (thereby queuing up whatever functionality is actually most relevant and valuable) at the beginning of each iteration. Third, because functionality is meant to be completed at the end of each iteration, the project is never far from a deployable state. Finally, Agile planning provides for an easy end to a project—that is, when the stakeholders no longer value any backlogged functionality enough to pay for an additional iteration, they can call it quits.
5. Identify and collaborate with your customer
Traditionally, the analysis and requirements definition for a project is completed by or with the help of the users and stakeholders. The development team then is left alone to get the system built on time; the users and stakeholders re-engage at some point during the testing phase. This could sum up the lifetime of a one-month or even two-year project, following traditional processes. Agile development wants a customer available throughout the project lifecycle both to drive an iterative planning process (as we discussed above) and to assist with requirements refinement issues as they arise. Projects following a traditional planning approach (as described above) may not be ready for a customer willing to queue up functionality by iteration or even release. Yet, a customer who has come to know the nature and capabilities of a good team may help convey the benefits of Agile planning to the powers that be.
The Agile methodologies have varying names and slightly different duties for the team’s customer. However, the role can be generalized (and idealized) as an individual who has both a user- and a management-based understanding of the system in development, is always available to the team, and is empowered and willing to make decisions. A customer could be more than one person and does not need to be able to make all decisions without consulting colleagues or supervisors. Ultimately, whether one or more persons, the customer needs to be able to deliver answers in a timely manner and with a single voice.
You typically will not get a customer without asking for one, and then explaining why you want one and how he would benefit the project, and then explaining the same thing again to two or three more people. You should be clear about what you are requesting. Nearly any project can benefit from having an individual available who can provide quick explanations and decisions on the inevitable gaps between requirements.
A good customer collaborating with a good development team can increase the ROI of a project by an order of magnitude. An available, on-demand customer means that programmers code the system to do what users require, eliminating the need for users to file do-over requests during the testing phase. Customer-driven Agile planning all but ensures that only relevant functionality goes into the system, instead of a plan or contract dictating a laundry list of functionality (any item of which may or may not still be relevant). Finally, superfluous analysis activity is reduced if feature and requirements definition is performed only when it is most relevant: days or even moments before the code is written.
6. Manage your test data; don’t let it manage you
I mentioned restorable data in Step 2. If the team already has a test framework that is actively being used, this is a next step to adding some agility to your project. The traditional approach to test data, even for teams that write repeatable tests, is to use whatever data is hanging around the database (yes, some applications do not use databases, but I think you get the idea). This approach works great until two tests alter the same bit of data, or the database is cleansed, or someone does some manual testing (Oh, that was your data?), or one of a dozen other things goes wrong. Many Agile teams, because they live by their tests, develop some mechanism to ensure the availability and maintainability of the data those tests rely upon.
Agile programmers have cooked up myriad ways to implement test data management solutions. One solution would be to mandate that each test creates and deletes its own data. Some teams take a more coordinated approach, using reloadable data sets (contained in files like spreadsheets or SQL scripts) chock full of data that are loaded into the database before the tests run. These are relatively straightforward systems to understand and not so complicated to establish, but they can become difficult to maintain as data relationships shift, and (in the case of the reloadable data set solution) new tests affect the data that old tests rely upon. It is, however, better than nothing.
Other strategies involve code-based frameworks that provide fresh and customized data for each test. I helped develop and wrote a paper on a pattern that fits this mold, dubbed ObjectMother. This is my preferred approach to test data maintenance, but it does involve an upfront cost and a disciplined development team to build the data structures. (For more details, see this issue’s StickyNotes.) "Mock Objects" is another approach to the issue of test data maintenance, but it attacks the problem from the inside out. Instead of creating test data, this strategy entails building tests that "mock" real objects, passing them into the application as though they were real objects, and then inquiring whether they were mistreated in any way.
You can roll out test data management the same way you would a testing framework. Use it in all new tests and any tests that have broken or otherwise need updating. Unfortunately, if the team is aware of an impending disaster (e.g., the database is going to be erased), days may be needed to convert old tests to the new system—at least it is the last time this action will need to be taken.
Test data management gives teams flexibility. They can run their test framework in the user testing environment and load the latest and greatest production data into the development database. A development team that is diligently writing data structures one-off in each test can still benefit by moving to a real maintenance system that reduces the time spent on rework, in terms of both writing duplicate data structures and updating test data when the relationships between objects change. Last, but not least, the availability of ready-to-use and ready-to-extend data leads to more tests and better tests.
7. Embrace collective ownership and share the code
Traditionally, some programmer named Scott gets assigned the invoicing system for the dapper new leasing application, bangs away at it in his cube for about six months, shoves it off to testing at 2 am, steps off a curb in front of the proverbial bus, and there goes the project. Okay, perhaps that extreme example is not entirely fair to the traditional process. However, it does help illustrate the issue many Agilists have with assigning specific application areas to specific programmers: Nobody understands anybody else’s code. Because of that, defects fester in code that is never fully reviewed by a second set of eyes, shifting programmers to troubled areas of the system halfway through the project is difficult at best, and turnover can really smart.
Collective ownership repeals the implicit or explicit relationships between programmers and components. Instead, programmers are encouraged to work in areas they have not worked in before. Meanwhile, everyone on the team is allowed time to assist other members in areas that they know well. This initially can slow down the progress of the team, but its benefits can save significant time and increase productivity in the long run.
Short iterations and small releases provide the easiest way to implement collective ownership, because they provide regular points in the project where programmers can pick up new tasks in different regions of the code. Projects that do not have an Agile planning approach may still operate on some form of iterative basis (be it multiple releases or functionality-based milestone dates) that would provide similar points where programmers can shift to responsibilities in other areas of the application. It’s not necessary for one programmer to know the entire application in order for the team to benefit from collective ownership. Many benefits can come from each programmer knowing only half of the codebase (and this is the most you can expect on larger projects). Finally, teams implementing collective ownership should consider employing regular stand-up meetings to discuss who is working on what area of the code. This will minimize toe-smashing and foster collaboration.
Collective ownership provides benefits of its own and can serve as a springboard to other Agile practices. Of interest to nearly any project (and as noted above), collective ownership eases the transition of programmers on and off the team. It improves the quality of the system because most any line of code will be viewed by more than one set of eyes. It makes code more consistent because programmers will begin to write code by standards common to the team (thus, we inch closer to a common coding standard). It fosters communication among programmers (another big goal of Agile). Finally, collective ownership encourages programmers to code together when a tricky piece of code requires a two-heads-are-better-than-one approach.
Closing points – and these are important
Summing up top-ten (or in this case, seven) lists is a bit tricky, so I won’t bother. Rather, I would like to conclude with two important and general points about implementing the above practices.
First, if you have successfully adopted one of the above practices, then select and attack another. If you have two down, move on to a third. Remember that old cliché that if things don’t grow they die? It applies here.
Second, do not bill yourself as Team Agile. Do not make a big deal about trying Agile. In fact, try to bring as little additional attention to the team as possible. The team will need time to work through even a single practice, to measure its benefit, to tweak its implementation, and to ultimately embrace or reject it. You do not want to tie your team’s hands or put them under the microscope.
Let the results of your foray into Agile speak for themselves. If the team’s performance is improved, your customer, your boss, and your customer’s boss are all likely to notice. Answering that Agile practices were the key to your success will serve your team much better than heralding the results that Agile practices are going to bring to your project once you’ve explained them to everyone … and once the team has implemented them … and worked through all the issues … and then explained why it all took longer than you thought.
AUTHOR BIO
Peter Schuh is an independent consultant with more than six years of experience leading and managing IT projects in the leasing, healthcare, and e-commerce fields. Mr. Schuh has written and spoken about Extreme Programming, the adoption of Agile processes, and Agile development"s impact on database administration. His current focus, and a major theme of his upcoming book, is the integration of Agile processes into traditionally non-Agile environments. He can be reached at agile@peterschuh.com.