September 8, 2014

...Learn TDD with Codemanship

Iterating Is Fundamental

Just like it boggles my mind that, in this day and age of electric telephones and Teh Internets, we still debate whether an invisible man in the sky created the entire universe in 6 days, so too is my mind boggled that - in 2014 - we still seem to be having this debate about whether or not we should iterate our software designs.

To me, it seems pretty fundamental. I struggle to recall a piece of software I've worked on - of any appreciable complexity or sophistication - where getting it right first time was realistic. On my training courses, I see the need to take multiple passes on "trivial" problems that take maybe an hour to solve. Usually this is because, while the design of a solution may be a no-brainer, it's often the case that the first solution solves the wrong problem.

Try as I might to spell out the requirements for a problem in clear, plain English, there's still a need for me to hover over developers' shoulders and occasionally prod them to let them know that was not what I meant.

That's an example of early feedback. I would estimate that at least half the pairs in the average course would fail to solve the problem if I didn't clear up these little misunderstandings.

It's in no way an indictment of those developers. Put me in the exact same situation, and I'm just as likely to get it wrong. It's just the lossy, buggy nature of human communication.

That's why we agree tests; to narrow down interpretations until there's no room for misunderstandings.

In a true "waterfall" development process - bearing in mind that, as I've said many times, in reality there's no such thing - all that narrowing down would happen at the start, for the entire release. This is a lot of work, and requires formalisms and rigour that most teams are unfamiliar with and unwilling to attempt.

Part of the issue is that, when we bite off the whole thing, it beecomes much harder to chew and much harder to digest. Small, frequent releases allow us to focus on manageable bitesized chunks.

But the main issue with Big Design Up-Front is that, even if we pin down the requirements precisely and deliver a bug-free implementation of exactly what was required, those requirements themselves are open to question. Is that what the customer really needs? Does it, in reality, solve their problem?

With the best will in the world, validating a system's requirements to remove all doubt about whether or not it will work in the real world, when the system is still on the drawing board, is extremely difficult. At some point, users need something that's at the very least a realistic approximation of the real system to try out in what is, at the very least, a realistic approximation of the real world.

And here's the the thing; it's in the nature of software that a realistic approximation of a program is, in effect, the program. Software's all virtual, all simulation. The code is is the blueprint.

So, in practice, what this means is that we must eventually validate our software's design - which is the software itself - by trying out a working version in the kinds of environments it's intended to be used in to try and solve the kinds of problems the software's designed to solve.

And the sooner we do that, the sooner we learn what needs to be changed to make the software more fit for purpose.

Put "agility" and "business change" to the back of your mind. Even if the underlying problem we want to solve stays completely static throughout, our understanding of it will not.

I've seen it time and again; teams agonise over features and whether or not that's what the customer really needs, and then the software's released and all that debate becomes academic, as we bump heads with the reality of what actually works in the real world and what they actually really need.

Much - maybe most - of the value in a software product comes as a result of user feedback. Twitter is a classic example. Look how many features were actually invented by the users themselves. We invented the Retweet (RT). We invented addressing tweets to users (using @). We invented hastags (#) to follow conversations and topics. All of the things that make tweets go viral, we invented. Remember that the founders of Twitter envisioned a micro-blogging service in the beginning. Not a global, open messaging service.

Twitter saw what users were doing with their 140 characters, and assimilated it into the design, making it part of the software.

How much up-front design do you think it would have taken them to get it right in the first release? Was their any way of knowing what users would do with their software without giving them a working version and watching what they actually did? I suspect not.

That's why I believe iterating is fundamental to good software design, even for what many of us might consider trivial problems like posting 140-character updates on a website.

There are, of course, degrees of iterativeness (if that's a word). At one extreme, we might plan to do only one release, to get all the feedback once we think the software is "done". But, of course, it's never done. Which is why I say that "waterfall" is a myth. What typically happens is that teams do one very looooong iteration, which they might genuinely believe is the only pass they're going to take at solving the problem, but inevitably when the rubbers meets the road and working software is put in front of end users, changes become necessary. LOTS OF CHANGES.

Many teams disguise these changes by re-classifying them as bugs. Antony Marcano has written about the secret backlogs lurking in many a bug tracking system.

Ambiguity in the original spec helps with this disguise: is it what we asked for? Who can tell?

Test-driven design processes re-focus testers on figuring our the requirements. So too does the secret backlog, turning testers into requirements analysts in all but name only, who devote much of their time to figuring out in what ways the design needs to change to make it more useful.

But the fact remains that producing useful working software requires us to iterate, even if we save those iterations for last.

It's for these reasons that, regardless of the nature of the problem, I include iterating as one of my basics of software development. People may accuse me of being dogmatic in always recommending that teeams iterate their designs, but I really do struggle to think of a single instance in my 30+ years of programming when that wouldn't have been a better idea than trying to get it absolutely right in one pass. And, since we always end up iterating anyway, we might as well start as we will inevitably go on, and get some of that feedback sooner.

There may be those in the Formal Methods community, or working on safety-critical systems, who argue that - perhaps for compliance purposes - they are required to follow a waterfall process. But I've worked on projects using Formal Methods, and consulted with teams doing safety-critical systems development, and what i see the good ones doing is faking it to tick all the right boxes. The chassis may look like a waterfall, but under the hood, it's highly iterative, with small internal releases and frequent testing of all kinds. Because that's how we deliver valuable working software.

Posted 7 years, 8 months ago on September 8, 2014