Tuesday, February 22, 2005

Death of the salesman (or power to the customer)

One of the main reasons why XP has been such a success for us is that the customer is so much happier when they get something they actually want. It's probably the only reason that the customers still want to work with us, despite our little idiosyncrasies. And so we have to make sure that they continue to get what they want.

Unfortunately, following the XP rules doesn't strike me as enough to ensure this is true. Following XP only guarantees that we deliver software that is in line with the stories. We also need to make sure that the stories accurately reflect what the customer wants.

We regularly get together to discuss future stories, constantly putting new stories in, taking old ones out, and tweaking the ones we have. We tend to introduce stories into the mix in two stages. First the customer (which is a team) discusses their new functionality requirements and gets the outline of the stories together, writing up some draft cards. The development team then sends a delegation to meet and discuss those stories (at length normally) and the true stories are written.

We do this in two stages so that the customers can have time to get their ideas straight in the their own minds before they approach us, whilst ensuring that every story is seen by the development team so we can work out any gaps in the knowledge embodied in those stories. In the second meeting we may put together estimates, or we may take the stories away and estimate later. The important fact is that a story isn't a story until its been through the second meeting.

On the face of it, this should ensure that the stories contain both the customer's requirements of the system and the developer's requirements of the description.

It generally does, until the salesman gets involved:

As developers we 'know' that we've been involved in system development for a lot longer than most, if not all, of our customers. This can make us feel as though we know more about system design than our customers. This may be true, but we don't know as much about this system as our customers. If we did, then we probably wouldn't be doing XP ;-)

The salesman is the developer in the story review meeting that forgets this. They 'understand' the requirements of the story as written and know of the 'best' solution. They will explain this solution loudly and then deflect any criticism fired at it with lengthy explanations or snappy comebacks. Whilst they're doing this they'll become more and more certain that their solution is the only solution to the problem. And the whole time they're doing this they'll forget that:
1 - Whilst the customer may not get it written down first time, they're more than qualified to specify what they need the system to do, that's why they're still on the team.
2 - The developers are not here to provide the solution, they're here to ensure that the problem is clearly stated.
3 - It's good to have ideas, but not all ideas are good.
4 - When the customer speaks, the developers should be listening.

It's easy to drop into this persona as a flash of brilliance pierces the fog, but it's important to remember:
When you have an amazing idea, just state it, don't sell it, and accept it's probably not as amazing as you first thought.

Tools are products too

With any project there will be a plethora of tools that need developing. The unit tester may need extending, some code generators would come in handy, you could do with some patch mechanism to upgrade the database.

The code that implements these is exactly the same as any other code. It may only be a 3 line batch file, or it may be a million lines of Java code. It doesn't matter, it's still output from the project and it still needs to be created in line with XP.

Pair program it, refactor mercilessly on it and if you're not using it then throw it away.

Monday, February 21, 2005

No-brainer #674

If you have an on-access virus scanner running on your DB server, tell it to NOT scan your database files.

Sunday, February 20, 2005

Extreme Oracle... part 3

In the previous part I described how we use ref cursors for passing data from the Oracle layer into the PHP layer. Unfortuantely ref cursors are resticted to SQL SELECT statements. If you're retriving a set of data that is derived from something that is not clearly expressed as a SQL statement then we can easily find that we are breaking our XP rule of simplicity.
This can be especially true when producing reports:

For complex return sets, build PL/SQL table structures and cast into SQL tables.
From Oracle 9i onwards there is the ability to cast certain PL/SQL table structures into tables and select from them with standard SQL. As an example: given that the function sales_figures_by_day returns a PL/SQL table of data with its structure defined in a globally declared nested table, we can SELECT from this using the statement SELECT * FROM TABLE( sales_figures_by_day() )

By using this we can split our complex SQL statements into smaller, more clearly understood steps. Each step adds data to, or transforms data in our PL/SQL table structure. We can unit test each of these steps in isolation. Once we have completed building our PL/SQL table we can retrieve the results using SQL. Since we can use SQL to SELECT from the PL/SQL table we can use a ref cursor to pass this SELECT statement back to the PHP layer. The PHP layer is not aware that the PL/SQL table ever existed.

Alternatively,
For complex return sets, build in 'global temporary table' structures and SELECT from them instead.
From Oracle 8i onwards we can create temporary tables which store data only for the current session, hiding it from all other sessions and cleaning up either when the current session or transaction ends. In all other respects we treat the global temporary table as if it was a standard SQL table. We can build complex result sets in a similar way as with our PL/SQL tables and return the data to the PHP layer by selecting from the resulting temporary table.

Again, the task is split into smaller, clearer chunks of work and the result is a more clearly understood series of actions.

Whilst the temporary table option requires less work, I personally favour the PL/SQL table option for returning complex datasets. Since the global temporary table is dealt with in exactly the same way as a SQL table it is unclear when reading the code that the resulting data is not permanent. It has the potential to cause confusion. Whilst the PL/SQL table method does take a little more work it is obvious from the form of the code that a result set is being created.

Before returning complex result sets, remind yourself what you're hiding from the PHP layer
Whilst we hide the physical structure from the PHP layer, the logical structure is still very much the responsibility of the system as a whole.
By 'physical structure' I mean that fact that, say, products and sales are kept in seperate tables within the database. By 'logical structure' I mean that a sale must relate to a particular product as it makes no sense to have a sale without one.
If you find that you are writing a lot of functions that return complex return data, then there may be cause to take a step back. Ask yourself, would it be inappropriate for the PHP layer to call several distinct database functions to retrieve data and then build the more complex structures itself. Is the stucture you are attempting to hide a physical one, or a logical one? Is the fact that you need to return a complex structure pointing to a problem with the PHP object model, or the underlying database physical model?

Friday, February 18, 2005

Extremely Helpful

Ron Jefferies suggests that you can write user documentation in an XP project, lagging only couple of iterations behind (here). Ellen Ferlazzo agrees and goes a step further, here, and says that it can be done at the same time as the part of the system it supports is being developed.
I agree.

One of the design goals of our current project is that it should be useable without a manual. Definately no manual. It needs to support our customers in a "really natural way", and manuals don't suggest natural. It does though, have help. That help isn't written by technical authors, it's written by the customers.

They're pretty good about writing the help, it's definately good, well thought out stuff, and it's updated pretty regularly. It's not too far behind us most the time, but at the start of the release iteration, things are usually pretty slack.

But the articles got me thinking. If the system's natural to use, then we should need a pretty small amount of help. There can't be a lot of it, or you're really shipping a large manual in small chunks. And if the system's to meet their "natural way" user interface, then should the help be more about how to use the tool to support the job more than how to use the system itself.
And then I thought... isn't the story really a description of the part of the job that this little bit of the system's supporting?

So what has this got to do with Ron and Ellen?

Well, the stories and the help are intrinsicly linked. And the customers are writing both. If they can be writing the help at the same time as, or even before we're developing the stories, then that'll help them understand what they want. This could help them guide us better in producing the system they need.

Getting customers to think about this 'job support' kind of help could also be useful in getting the customer away from thinking about user interface design and concentrating on what is actually going on in this part of the system.

If the help is difficult to write, or needs lengthy explainations then maybe the understanding of the story isn't quite there yet.
If the help doesn't make things obvious, then maybe there's some rework to be done on the user interface.

Of course it's difficult to measure the success of your help when you're so close to the project. So maybe it's worth getting customers from outside the team to take a look at the project pretty regularly. This is your test for your help. Give them the help, and no training and see what happens. Find out where users make mistakes and fix the problems that caused them (both system and help). You've got a production quality system, and you've got production quality help, so this should be easy to do. And the real customers do like to see what they're getting next...