Monday, February 28, 2005

Fundamentally, there are no No-Brainers

I've just started reading Mike Mason's new book on implementing version control using Subversion.

It's a nice easy read that starts from the fundamentals of why we use version control; it's got a really nice little illustration of how and why version control works. As any book on version control will, it mentions software configuration management, and on that topic it mentions the great book 'Software Configuration Management Patterns', which I remember Mike suggesting I read when I first described to him what Oracle development workspaces are normally like.

That little reminder made me think back to when a lot of what I do now wasn't anywhere near on my radar. I knew that I did things badly, but I wasn't sure how it could be fixed. A lot of things that I do now, that I think of as 'no-brainers', are things that I hadn't even considered.

It got me thinking that maybe it's time I took a step back and looked at how we've set up our workspace. I figure it's time for an honest appraisal. Hopefully I'll even spot something that can be improved upon.

It's reminded me that it's worth reading books on the things we regard as 'fundamental' every now and again for just this reason. It reminds us why we do what we do, and why we do it the way we do it, and that we need to think about both those things even if we regard those things as 'no-brainers'.

Also, it made me think that maybe I should describe our workspace setup in a future blog entry, to sanity check it and see if it's of use to anyone else. Mike may have pointed out that it's not as standard as I might like to think...

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.

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?