Friday, June 16, 2006

Agile In Action

I don't know to what extent the notions of up-front requirements analysis and design are still being actively used these days, but I've heard a lot of debate on the subject over the past few years. I'm currently working on an agile project and today I had a good experience in which three of us, a customer and two developers, worked together to flesh out a requirement in a way that simply would not be possible in a more traditional environment heavy on up-front requirement preparation. Since this is an example from the real world, I'll be using project-specific terminology, but I hope to make the general sense of what's going on clear to anyone reading this blog. If you're reading this and have something to say that may clarify matters, I encourage you to e-mail me and I'll update this posting.

In our application (oil and gas production accounting), we have the notion of a gas-equivalent factor (ge factor). It is a number that you multiply by a volume of light oil, also called condensate, to get an "equivalent" volume of gas. It's a bit like comparing, say, two grads from different schools. One grad has a GPA of 3.2 and the other one has a 78% average. To compare them, you may want to convert the gpa of 3.2 to a percentage, or vice versa. Anyway, the point is that this number is displayed on several screen of the application. Now, there are several different ways that this number is obtained, and as part of a story I was working on, I had to include the source of the ge factor along with the number itself. The story (similar to a use case) specified that one of two icons should be displayed along with the factor: "A" for analysis, and "E" for entered. In one case, an analysis (a breakdown of the molecular constituents of the condensate) is used to calculate a ge factor; in the other case, the user simply enters in the factor manually. As I began to get into code, I realized that there was a third case that the story didn't talk about. I turned to the customer who had put together the story, who sits just across from me, and asked him about it: Al, what happens when the ge factor is not necessarily derived from an analysis, but it's averaged from ge factors at several other measurements? After a bit of discussion, the user and I agreed to include a third icon as part of the story, "C" for calculated.

I implemented the requirement simply by putting a text label "A", "C", or "E" next to the ge factors on the appropriate screens. Then I went to talk to our resident gui (graphical user interface) expert about the story: Hey Chris, I've put these text labels next to the ge factor on our balancing screens. Could you cook up some icons that look a bit nicer? Chris came over and asked Al: What if instead of an extra icon next to the factor, we turned the factor itself into a link. If the number came from an analysis, the link would actually take the user to the analysis that was used. If the number was entered, the link would lead to the screen where that number was entered. The user really liked this idea. I objected: In the case that the number was calculated by averaging several measurements, it would be a fair amount of work to create a new screen that showed all of those measurements in one place. The user however told us that it wasn't necessary to go that far. If the number was an average, simply omitting the link was fine.

The buzzwordz "multidisciplinary" and "synergy" are used a lot these days, but in this case, we solved a problem by combining our skills and perspectives. Requirements are a bit like art. If you're a customer, you generally know what you want when you see it, but describing it ahead of time isn't so easy. In a non-trivial application, it's hard to think of all the possible scenarios for a given feature. As a developer, I'm close to the code and I can see those scenarios, so it's a lot easier for me to ask the kind of question that I asked. Finally, the user interface expert was concerned about clutter on the screen and how effective the user interface would be, whereas I just cared about the fact that the right information would show up as described in the story. We all worked together to come up with a better solution - without really extending the development time. The whole discussion probably clocked in at about 15-30 minutes, and nothing about the requirement caused an enormous amount of extra work. In the future, if someone decides to show all of the measurements that contribute to an "averaged" ge factor, we can implement that as a separate story. The important thing is that the users currently don't consider it to be especially useful or a high priority. We've built the software not to honor a general principle of orthogonality, but to meet our users' actual requirements.

I was really impressed with the process we went through today and I thought it was a nice simple example the kind of power an agile approach can have.

Sunday, June 11, 2006

Just-In-Time Performance Tuning

I've been thinking a bit about performance tuning business applications lately, after reading some of Ted Ogrady's recent writings on the subject (see Empirical Performance , Elaboration, and Reponse to my concerns about risk). Ted pointed out that some authorities in the agile realm recommend avoiding premature optimization (see Fowler and Beck). It's true that optimizing code early can lead to problems, and especially that one should not optimize code without profiling it first. However, I do think that letting the performance get bad enough to upset users is a bad thing, and seems out of character in agile development. For example, Kent Beck writes:

Later, a developer pulled Kent aside and said, "You got me in trouble."

"About what?"

"You said I could tune performance after I got the design right."

"Yes, I did. What happened?"

"We spent all that time getting the design right. Then the users wanted sub-second response time. The system was taking as long as fifteen seconds to respond to a query. It took me all weekend to change the design around to fix the performance problem."

"How fast is it now?"

"Well, now it comes back in a third of a second."

"So, what’s the problem?"

"I was really nervous that I wouldn’t be able to fix the performance problem."

Kent's suggestion is to do some envelope calculations to assess performance early in the project, but that's just a written down artifact, the kind of thing that agile practices generally discount.

As I see it, the history of the performance tuning debate goes something like this: Early on, performance tuning had to be done all the time because hardware was so slow and memory was so expensive. Later on, a overall computer performance improved, there was a backlash against this kind of optimize-always behaviour. If you aren't desperately worried about memory, you don't need to use bit fields - that sort of thing. However, as a result of leaving performance issues for late in the project, I've seen a number of projects now where the performance becomes really terrible. Users get upset and the overall perception of management is not positive. The developers in this case say "Don't worry, we'll solve the performance problems later." However, these performance problems can start to affect the project. User who are testing that app spend too much time navigating from one screen to another, and even the time to run automated tests written by the development team suffers.

Basically, I think there is a better way: One of the best idea in software development I've come across in the last while is the notion of a FIT test. A FIT test is a customer-facing test. My suggestion is to devote time to developing a relatively small number of performance-oriented FIT tests during each iteration. These tests execute an area of code where performance is important under conditions that are as realistic as possible. Just as with normal FIT tests, performance FIT tests can be written before the actual code exists. Initially, there is no processing done and the test passes trivially. Each iteration, someone is responsible for maintaining the fit test - adding setup data and making sure it runs without errors. If the test meets the established performance criteria, the bar is green, otherwise it's red. That's when we jump in with the profiler to get the performance back to acceptable levels. The code should remain as clean as possible, and only the minimum amount of tweaking required to make the test pass should be done. That way the users won't run across unacceptable levels of performance as the app is being developed, thus reducing risk and stress for everyone. The basic point I am trying to make is not that performance cannot be improved late in a project, but that maybe it doesn't have to be that way.

Saturday, June 03, 2006

Further Lessons In Humility

In an earlier post, I discussed creating an abstract class Node and extending it with either TestNode (for unit tests) or Facility Node (for the actual production code) in order to move some functionality related to facility network topology out of the Facility class. I was kind of proud of my accomplishment, especially when it came to me that I had implemented a kind of "mixin" inheritance in Java. However, a friend of mine blew my bubble by pointing out that a simpler implementation existed. Namely, just move the topology code into something like a NetworkTopologyUtils class as static methods. Hence, we have something like this:

public class NetworkTopologyUtils {
public static findLoop(Node n) { /*code goes here ... */ }
//more applicable methods below...

This is just as easy to test, and makes more sense, since the responsibility for finding loops no longer rests with a hard to pin down "Node" class. Now all that remains is to implement the Node interface (e.g. sendsTo) in Facility. For unit testing, one can just as easily write a TestNode class that also implements the Node interface.

What's the lesson here? For me, it's that I shouldn't fall in love with my own code. Also, I should not let my ingrained biases (against such static singleton classes for example) get in the way of putting together the right design. Finally, there's nothing wrong with keeping it simple. Simplicity is good. Even though my example wasn't a great one, I still do like mixins in Ruby though and think that Java should have implemented them (not to mention C#)! :)