How I write software
Crenshaw's Law #42 says: Before setting out to solve a problem, find out what the problem is. Law #43 says design it before you build it, not after.
In the software world, this means performing requirements analysis. Write down, in as much detail as you can, what problem you want the software to solve, how you want it to solve the problem, and how you want people to interface with it.
In the 1980s, the popular project plan was to start with an analysis of the system requirements. Then you decompose into software requirements, design requirements, etc. At the end of each phase, you hold a formal review before moving onto the next step. No fair skipping ahead.
They called this process the "waterfall" approach. If you were writing a formal proposal to NASA, DoD, or whoever, a clever picture of the waterfall could win you the contract. In the waterfall diagram, the "code and unit test" phase of the plan was usually the next-to-last step in the process (the last being integration and test). And woe be upon anyone who skipped ahead to writing code.
Today, the waterfall approach has been completely discredited and deemed ineffective. Personally, I think the only reason it seemed to work was that nobody actually followed it. Some of us practitioners broke the rules, and skipped ahead to try out our ideas on the side. The whole thing was a sham. We had slick-looking and impeccably dressed salespersons giving formal presentations to the customer, showing them how wonderfully the waterfall approach was working, and assuring the customer that we were 90% complete. Meanwhile, a few of us slaved away in a secret back room, using approaches that actually worked.
But those were the bad old days. Today, the hot keywords are spiral development, prototyping, incremental and agile approaches, and extreme programming (XP). I'm a big fan of XP, though I'm not sure that what I do fits the mold.
Today, no one in their right mind would still support the waterfall approach, right? Well, I don't know. In 1984 our software managers had a rule: you were not allowed, on penalty of--something bad--to even run the compiler, until your software had passed code review. Even then, the compiler was never to be used for developing test drivers and supporting unit testing. It was only to be used on the entire system build, after all integration had been done.
You should go back and reread that paragraph, to really get your arms around the concept. We had a nice, and relatively modern, timeshare system (Unix), with a nice compiler, programming editor, debugger, and other aids, but we weren't allowed to use the compiler. We were perfectly free to use the editor to write the code but only to document our designs for the code reviews. We were expressly forbidden to actually run the compiler. How brilliant was that?
But that was 25 years ago. We don't do anything so ridiculous now, right? Well, let me see ....
On a more recent project, I heard a manager berate a colleague for actually writing code before the requirements review. If he had been working in his old company, the manager said, he would have fired the guy for such a violation of the rules.
That was way back in . . . let me see . . . 2008.
I won't say much more about project planning or about requirements analysis here. In part, it's because using my approach, the requirements evolve with the code. Call it spiral development, if you like.
I start with code
The method I use to develop software may surprise you. In the worst possible tradition of the anti-waterfall plan, I jump right into code. I sit down at the keyboard, flex my fingers, crack my knuckles, and type:
That's right: I write the null program. I do this on every new start. If I'm in a really adventurous mood, I'll add:
cout << "Hello, Jack!" << endl;
and maybe even:
x = 2; y = 3; cout << x + y << endl;
This is not a joke. I really, really do this. Every time.
Why? I think it's just my way of assuring myself that the genie behind the glass screen is still awake, and still doing his job. And my computer and its operating system haven't gone berserk overnight (not all that unlikely, these days),
Mostly, I do it to get myself in the mode of expecting success, not failure.
Several years ago, educators came up with the notion of "programmed learning." The idea was to write the textbook very much like a computer program, complete with loops and goto's. After teaching a few facts (never more than three or so), the text asks a series of questions. If you give the right answers, you get to skip to the next section. Otherwise, you may be directed to loop back to the beginning of the section, and read it again. Programmatically, this is the familiar:
infinite loop structure. If you're particularly dense, you could be stuck here forever.
Alternatively (and better), you might be directed to a separate section, which explains the facts in more detail. It's a sort of hypertext. Ideally, the writers of the text were smart enough to tell when a given student needed extra instruction.
The inventors of programmed learning were careful to point out that those writing such textbooks should give the information in very small steps. You don't write a whole chapter on, say, the quadratic formula, and save all the questions for the end of the chapter. You teach a very few simple concepts--two or three at most--and ask the questions immediately.
The reason, they say, is that people need lots of positive feedback. If they get too many answers wrong, they get discouraged and give up. By giving them easy questions often, you give them lots of warm fuzzies, and make the study seem a lot more fun than drudgery. Everybody knows that people like to succeed more than to fail, and they like the feeling that they can actually complete the task. The notion of programmed learning capitalizes on these natural tendencies.
I think that's why I start with the null program. I like my warm fuzzies early and often.
When I'm writing code, I want to expect success. I'm mildly surprised if a bit of code doesn't compile without error, the first time. I'm shocked to my core if it compiles, but doesn't run properly, or doesn't give the right answer.
Some programmers, I submit, have never experienced that feeling. Certainly not those poor souls that had to write and integrate the entire system before even trying to compile it. How certain of success would they be?