Thursday, 29 May 2008

Evolving features

Yesterday's post ended with a teaser - why store the result of a function before returning it? The answer is (unsurprisingly, given the nature of this blog) to make it easier to access for a human. Specifically, when somebody (most often myself) is debugging a function that I have written, it's much nicer to be able to see the result of a function call immediately in the debugger or watch window, than having to step into the function and see what the result will be.

Today I'd like to post a response to Abhinaba Basu's The WOW factor in software. There are quite a few blogs that I'm reading at the moment, Abhinaba's being the most recent I've added to my list, and I'm enjoying reading it.

Abhinaba talks about the "nifty" features that turn good software into great software. Then he mentions

"the other category of software which doesn't work in first place and tries to be smart on top of it. There's nothing worse than this. You look at these in disgust and head over to the dumber but working competition."

Now the end-user doesn't care about how many hours a programmer has put into a project, lovingly crafting it, starting from an empty source file, and putting not just time, but pouring their heart and soul into a piece of software. The end-user doesn't care that the software is like one of the programmer's children. No, the end-user wants a piece of software that will do what he wants it to do, and won't crash, or loose his work. And Abhinaba is right when he says that the user will look at these in disgust and head over to the working competition. But I get the impression that the message is "get the thing working before adding the polish".

My point (I knew we'd get to it sooner or later) is that when a user sees this happen, they would assume that the programmer has been working on the nifty features to the detriment of the core functionality. But I don't think this is true.

Programmers don't like their creations to have bugs in them. The bugs are a poor reflection on themselves. They don't deliberately leave bugs in, add some sparkle and hope nobody notices the flaws. Software is released when the creator thinks it is ready. Unfortunately, the software isn't always ready and as we all know, bugs are always ready to rear their ugly heads, right when we least expect it.

In an ideal world, maybe all the core functionality would be written and tested, and there would still be budget for the extras. In reality, what often happens is once the core functionality is in, the product is shipped and we're off onto the next task. If features aren't evolved alongside the rest of the project, then they'll often fall by the wayside.

Recently I was writing a tool for drawing flow diagrams. Now basic functionality was there - lines could be drawn from one shape to the next. Straight lines. No routing. If you wanted to go around corners, you could add nodes - one at a time - to the line, and drag these nodes into the correct place. This was painstakingly slow, but it was functional - it provided all the functionality required to describe flows.

But then in my own time I spent a whole day putting in automatic routing for lines. Now lines will have a sensible number of nodes, in sensible positions, by default. This makes the tool a lot more natural to use. Is it required for core functionality? No - it's a feature. Is the software finished? No - there are still plenty of bugs to be ironed out and core work to be done. It's constantly being updated. But before I added automatic routing, it took ages to draw a flow. Now it takes minutes.

Shock! Horror! Working on features when there's still core work to be done! But if I hadn't written these features before the core work was finished, then they wouldn't have been added at all - it would have been time to move on.

If you want your software to stand out from the rest, you need the wow factor. If you want the features for wow factor, then you need to be working on them NOW. Otherwise, they'll be left behind - as will your software.

Wednesday, 28 May 2008

Dots and Double Dots

I love the phrase "train wreck". To clarify, I'm not talking about real life transport accidents here. I'm talking about the phrase used to describe code.

I think I first discovered the phrase in Code Complete, though I can't pin down the exact quote.

Basically it refers to code that refers to members of members of members of members... so for example

Ammo GetCurrentAmmo()

(I guess the dots "." are the coupling between carriages and the method names are the carriages. Or something).

The phrase seems to say "some terrible disaster has happened here". When there are that many decompositions in a single line of code, if the disaster hasn't already happened yet, it soon will.

One accident (or several) waiting to happen here is - one of the functions along the way could return a null pointer. If any of the intermediate elements is an invalid value then this piece of code is going to crash.

So at the very least, we should be testing for null values. Now, say we wanted the inventory of player 1, and assuming we know that the PlayerManager is valid, one way of writing this (with null value testing included) is:
if (PlayerManager.GetPlayer(1) != null)
inv = PlayerManager.GetPlayer(1).GetInventory();

However, I'm not happy with that piece of code. I'm an advocate of Programming for People. But a person reading that code sample would have to do more mental decomposition than necessary. Which I would find impolite. Here's what I mean by mental decomposition:

First we read "PlayerManager" (right, so I've got this player manager), then we read ".GetPlayer(1)" (right so we've got player 1 of the player manager). Then we test this for null with " != null". (Ok, test if the player manager's player 1 is null).
Once we've got past this line of code, it would be nice to assume we could throw away our mental stack, and start with a clean slate, if you will. So we've passed the test in the "if" statement. Then we're going to assign to our inv variable. We'll take the playerManager, we'll get player 1 of the player manager, then we'll take the inventory of player 1 of the player manager. Ouch - my head hurts.

I would nearly always write that previous code sample as the following:
Player player = PlayerManager.GetPlayer(1);

if (player != null)
inv = player.GetInventory();

Now, when I read that code, I see that Player 1 of the player manager is being assigned to a local variable - so I know this player is of interest. So I'll keep this player in my mental stack. Then I'll test that "this player" is not null. Then if I pass the test, I'll get the inventory of "this player". And this time, I had less mental decomposition.

And if nothing else, we've given the code more room to breathe! The train wrecks of the first example are hard on the eyes - it's hard to see where one element ends and the next begins. With the rewrite, the test and assignments are in much smaller and easier-to-digest chunks.

Rewriting the entire example, I would almost always write out the original train wreck as follows:
Ammo GetCurrentAmmo()
Player player = PlayerManager.GetPlayer(1);

if (player == null)
return null;

Inventory inv = player.GetInventory();

if (inv == null)
return null;

Weapon[] weapons = inv.GetWeapons();

if (weapons.Length == 0)
return null;

Weapon currentWeapon = weapons[0];

if (currentWeapon == null)
return null;

Ammo currentAmmo = currentWeapon.GetAmmo();
return currentAmmo;

The Law of Demeter says that you're only allowed to talk to your immediate neighbours. Strictly in the example above, I think I am allowed to ask the PlayerManager to do something, but I'm not allowed to ask the player to do something. Or the inventory. Or the weapons. And so on. But there are always exceptions to rules.

In this case, I think that if the GetCurrentAmmo function is in a class that made the most sense to know about getting the current player's ammo, then I'm fine with the multiple levels of indirection here. Otherwise each of the intermediate classes between this class and the Weapon class would need a "GetCurrentAmmo" forwarding function, which I feel would be a lot of extra code for little gain.

One last note on the code example - I've stored the result of the final "GetAmmo" function call before returning it. I'll explain why next time :)

Whenever I see the same "dot" phrase being used more than once in a function, I cringe. If the dot phrase happens to be a "double dot" phrase, I'll cringe even more. If a phrase repeats when it has more than 2 dots in it then I'll be sad that the person who wrote that code wasn't Programming for People.

Tuesday, 27 May 2008

Crossing the Road

I was crossing a road after just walking past a woman with 2 kids - one kid in the pram she was pushing, the other on foot.

The kid on foot ran across this road, without looking, and a taxi driver had to slam on his brakes to avoid hitting the kid.

The woman yelled "Slow Down, Asshole!".

I was bemused by this; and you know how you always think of the right thing to say AFTER it would have been the right time to say it?

Well I thought to myself, what I should have said in that situation was "Just because your child runs across the street without looking, it's no excuse to call him an asshole!".

I wish I'd said it at the time. The story makes me smile, even now.

Sunday, 25 May 2008

Programming for People

I believe that the best piece of programming advice I ever read was "Write your code so it's easy to read."

I've been programming for about 20 years, and I've read advice like "always comment your code" and "choose sensible variable names", but it never really sunk in. I didn't understand the reason behind this advice. Now in the last couple of years I think I finally understand the reason why: Code is written once, but read many times.

It might take you a long time to write a good, solid routine that performs the exact function that you want. And it might take you even longer to write the code so another person can understand it, so you think "why bother?" But at the end of the day, the investment is worth it, because whilst you only write that function once, coders will read that function many many times. And when I say coders will read that function, I'm also including you. You will re-read that function. Whenever you need to perform some maintenance coding, when you need to make a subtle change to the effect of the function, when you need to refactor your code - even when you're just looking through the code, trying to find "that routine that I wrote last week - I know it was something to do with...", you'll appreciate the extra effort you went into to make the code easy to read.

Because I finally came to realise, that if I want to be a good programmer, then I need to write my code primarily for a person to read, and only secondarily for a computer to read!

That was probably a bit of a controversial statement there! But the way I see it, for all but the most trivial functions, if a piece of code is written without human-readability in mind, and there's a bug, it's gonna take a heck of a long time to track that bug down. But if the code was written for a person to read, then it will take a fraction of that time to find the bug, because less time is spent trying to understand the code - the code is amenable to human understanding, and so time can be spent, more effectively, hunting down that bug.

In conclusion:
  • Code is Write Once Read Many
  • Write the code so it's easy to read
  • Code primarily for a person to read, and secondarily for a computer to read.

Blog Motiviation

I've made several attempts at blogging, with varying degrees of success (in terms of readership, content, schedule, etc). Previously however, I haven't really had a focus for my blogs.

Right now, I would like to write what I would hope would be interesting, informative, entertaining posts on topics that appeal to me. Hmm. Sounds like the description of any blog in the world. D'oh.

Ok, let me try again. In the last couple of years I've become a keen reader of technical blogs on the internet, and I think I'm a better programmer because of them. So now I'd quite like to have a go myself.

So topics (as the title of the blog suggests) will probably have a focus on programming, but I may slip in anecdotes which I find amusing from time to time as well.

I have no idea what the schedule might be. I'd quite like to commit to posting regularly. I've been noting down topics over the last few days and hopefully I'll be able to come up with new content regularly too (since the downfalls of my previous blogs seem to have been lack of inspiration).

Enough rambling. On with the blog.