Gregg and Stefanie have described some management perspective on Agile programming. As a participant in several of the team rooms they mentioned, I would like to make a few comments.
- Active involvement with customers: the more the developers know about what end users will want, the better.
- Emphasis on refactoring: rearranging code to avoid duplication while adding capabilities is critical for any developer.
- Retrospective: with any important activity it is important to take some time to think about what you are doing right and what could be done better.
When done correctly, pair programming is exhausting. One especially rewarding session (where Mayank and I coded up how quad trees are intersected with face boundaries) produced very good code, but left us hoarse every day for a week! What made that session work is that we both challenged each other’s intuitions freely. The end result was reasonably well tested and reliable. We had enough clash to write code better than either of us would have alone.
Unfortunately, a pace like that cannot be sustained for long. It is much easier to develop a hierarchy, where someone “knows the most” about a particular area of the code, and the other partner either watches for typos, or is supervised by the more knowledgeable person. Even this mode of pairing is tiring.
Anything that makes a team’s efforts better than the sum of individual efforts (if you just divide the work by N and give everyone something to do) is good. But pairing requires continuous effort, and won’t improve the code without everyone’s sustained efforts. There is a lot of middle ground between pairing and not. Code reviews and having people frequently bounce ideas off each other gets a lot of the benefit with less stress.
If tools are set up correctly, most of the errors are semantic (i.e., the code looks good and compiles, but it’s not doing what it is supposed to). Unit testing only helps when you know the right tests to apply. It can’t catch poor scaling (e.g, using an n-squared algorithm where an O(n) or O(nln(n)) would work. ) I have become a big fan of writing out the contract for a function before I write the code, then placing assertions to specify pre and post conditions.
I think the big take away should be: if you are testing your code correctly, mistakes should be obvious. When you do something wrong,
- Your code should fail to compile
- Half a dozen or more unit tests should fail
- Assertions should be going off all over the place, etc.
Long undiscovered bugs cost more than those found early in testing. Good programming demands a high level of focus on details: the more time you have to forget the code you wrote, the harder it is to fix.
- Thin Vertical Slices/Design as you go.
Positives: Thin vertical slices make sense because there is business value in quickly getting small but usable pieces functionality to customers. If they like it, you follow up and develop it further until it meets their needs fully. If no one buys it, the project stops and you haven’t really lost that much (because you didn’t develop more than you needed).
Negatives: The notion that software can be redesigned on the fly is only partially true. The more people are using something the more risk there is in changing it. No amount of testing eliminates regression risk. If customers aren’t on board with iterative development, having a new drop every few weeks could cost you some credibility (why didn’t they do it right the first time?). Finally, it takes a lot of skill and good judgment to balance the goal of refactoring to get better code quality with regression risks.
What do you think? I was reading a recent survey on Agile and the results seemed largely positive. Does this fit with your experience?