Learn More About The Computer Programming

What exactly is software development, and why is it so hard? This is a question that continues to engage our thoughts. Is software development an engineering discipline? Is it art? Is it more like a craft?

We think that it is all of these things, and none of them. Software is a uniquely human endeavor, because despite all of the technological trimmings, we’re manipulating little more than the thoughts in our heads. That’s pretty ephemeral stuff. Fred Brooks put it rather eloquently some 30 odd years ago[Bro95]:

“The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. Few media of creation are so flexible, so easy to polish and rework, so readily capable of realizing grand conceptual structures. (As we shall see later, this very tractability has its own problems.)”

In a way, we programmers are quite lucky. We get the opportunity to create entire worlds out of nothing but thin air. Our very own worlds, complete with our own laws of physics. We may get those laws wrong of course, but it’s still fun.

This wonderful ability comes at a price, however. We continually face the most frightening sight known to a creative person: the blank page.

1. Writer’s Block

Writers face the blank page, painters face the empty canvas, and programmers face the empty editor buffer. Perhaps it’s not literally empty—an IDE may want us to specify a few things first. Here we haven’t even started the project yet, and already we’re forced to answer many questions: what will this thing be named, what directory will it be in, what type of module is it, how should it be compiled, and so on.

The completely empty editor buffer is even worse. Here we have an infinite number of choices of text with which to fill it.

So it seems we share some of the same problems with artists and writers:

  1. How to start
  2. When to stop
  3. Satisfying the person who commissioned the work

Writers have a name for difficulties in starting a piece: they call itWriter’s Block.

Sometimes writer’s block is borne of fear: Fear of going in the wrong direction, of getting too far down the wrong path. Sometimes it’s just a little voice in your head saying “don’t start yet”. Perhaps your subconscious is trying to tell you that you’re missing something important that you need before you can start.

How do other creative artists break this sort of logjam? Painters sketch; writers write a stream of consciousness. (Writers may also do lots of drugs and get drunk, but we’re not necessarily advocating that particular approach.)

What then, is the programming equivalent of sketching?

Software Sketches

Sometimes you need to practice ideas, just to see if something works. You’ll sketch it out roughly. If you’re not happy with it, you’ll do it again. And again. After all, it takes almost no time to do, and you can crumple it up and throw it away at the end.

For instance, there’s a pencil sketch by Leonardo da Vinci that he used astudy for the Trivulzio equestrian monument. The single fragment of paper contains several quick sketches of different views of the monument: a profile of the horse and rider by themselves, several views of the base with the figures, and so on. Even though the finished piece was to be cast in bronze, da Vinci’s sketches were simply done in pencil, on a nearly-scrap piece of paper. These scribblings were so unimportant that they didn’t even deserve a separate piece of paper! But they served their purpose nonetheless.[1]

Pencil sketches make fine prototypes for a sculpture or an oil painting. Post-It notes are fine prototypes for GUI layouts. Scripting languages can be used to try out algorithms before they’re recoded in something more demanding and lower level. This is what we’ve traditionally called prototyping: a quick, disposable exercise that concentrates on a particular aspect of the project.

In software development, we can prototype to get the details in a number of different areas:

  1. a new algorithm, or combination of algorithms
  2. a portion of an object model
  3. interactions and data flow between components
  4. any high-risk detail that needs exploration

A slightly different approach to sketching can be seen in da Vinci’s Study for the Composition of the Last Supper. In this sketch, you can see the beginnings of the placement of figures for that famous painting. The attention is not placed on any detail—the figures are crude and unfinished. Instead, da Vinci paid attention to focus, balance and flow. How do you arrange the figures, position the hands and arms in order to get the balance and flow of the entire piece to work out?

Sometimes you need to prototype various components of the whole to make sure that they work well together. Again, concentrate of the important aspects and discard unimportant details. Make it easy for yourself. Concentrate on learning, not doing.

As we say in The Pragmatic Programmer, you must firmly have in your head what you are doing before you do it. It’s not at all important to get it right the first time. It’s vitally important to get it right the last time.

Paint Over It

Sometimes the artist will sketch out a more finished looking piece, such as Rembrandt’s sketch for Abraham’s Sacrifice Of Isaac in 1635. It’s a crude sketch that has all of the important elements of the final painting, all in roughly the right areas. It proved the composition, the balance of light and shadow, and so on. The sketch is accurate, but not precise. There are no fine details.

Media willing, you can start with such a sketch, where changes are quick and easy to make, and then paint right over top of it with the more permanent, less-forgiving media to form the final product.

To simulate that “paint over a sketch” technique in software, we use a Tracer Bullet development. If you haven’t read The Pragmatic Programmer yet, here’s a quick explanation of why we call it a Tracer Bullet.


By the time you’ve set up, checked and rechecked the numbers, and issued the orders to the grunts manning the machine, the target has long since moved.

In software, this kind of approach can seen in any method that emphasizes planning and documenting over producing working software. Requirements are generally finalized before design begins. Design and architecture, detailed in exquisite UML diagrams, is firmly established before any code is written (presumably that would make coders analogous to the “grunts” who actually fire the weapon, oblivious to the target).

Don’t misunderstand: if you’re firing a really huge missile at a known, stable target (like a city), this works out just great and is the preferable way to go. If you’re shooting at something more maneuverable than a city, though, you need something that provides a bit more real-time feedback.

Tracer bullets.

With tracer bullets, you simply fill the magazine with phosphorus-tipped bullets spaced every so often. Now you’ve got streaks of light showing you the path to the target right next to the live ammunition.

For our software equivalent, we need a skeletally thin system that does next to nothing, but does it from end to end, encompassing areas such as the database, any middleware, the application logic or business rules, and so on. Because it is so thin, we can easily shift position as we try to track the target. By watching the tracer fire, we don’t have to calculate the effect of the wind, or precisely know the location of the target or the weight of the ammunition. We watch the dynamics of the entire system in motion, and adjust our aim to hit the target under actual conditions.

As with the paintings, the important thing isn’t the details, but the relationships, the responsibilities, the balance, and the flow. With a proven base—however thin it may be—you can proceed in greater confidence towards the final product.

Group Writer’s Block

Up till now, we’ve talked about writer’s block as it applies to you as an individual. What do you do when the entire team has a collective case of writer’s block? Teams that are just starting out can quickly become paralyzed in the initial confusion over roles, design goals, and requirements.

One effective way to get the ball rolling is to start the project off with a group-wide, tactile design session. Gather all of the developers in a room[2] and provide sets of Lego blocks, plenty of Post-It notes, whiteboards and markers. Using these, proceed to talk about the system you’ll be building and how you think you might want to build it.

Keep the atmosphere loose and flexible; this gets the team comfortable with the idea of change. Because this is low inertia design, anyone can contribute. It’s well within any participant’s skills to walk up to the whiteboard and move a PostIt-note, or to grab a few Lego blocks and rearrange them. That’s not necessarily true of a CASE tool or drawing software: those tools do not lend themselves readily to rapid-feedback, group interaction.

Jim Highsmith offers us a most excellent piece of advice: The best way to get a project done faster is to start sooner. Blast through that writer’s block, and just start.

Just Start

Whether you’re using prototypes or tracer bullets, individually or with a group, you’re working—not panicking. You’re getting to know the subject, the medium, and the relationship between the two. You’re warmed up, and have started filling that blank canvas.

But we have one additional problem that the painters do not have. We face not one blank canvas per project, but hundreds. Thousands, maybe. One for every new module, every new class, every new source file. What can we do to tackle that multiplicity of blank of canvases? The Extreme Programming[Bec00] notion of Test First Design can help.

The first test you are supposed to write—before you even write the code—is a painfully simple, nearly trivial one. It seems to do almost nothing. Maybe it only instantiates the new class, or simply calls the one routine you haven’t written yet. It sounds so simple, and so stupid, that you might be tempted not to do it.

The advantage to starting with such a trivial test is that it helps fill in the blank canvas without facing the distraction of trying to write production code. By just writing this very simple test, you have to get a certain level of infrastructure in place and answer the dozen or so typical startup questions: What do I call it? Where do I put it in the development tree? You have to add it to version control, and possibly to the build and/or release procedures. Suddenly, a very simple test doesn’t look so simple any more. So ignore the exquisite logic of the routine you are about to write, and get the one-line test to compile and work first. Once that test passes, you can now proceed to fill in the canvas—it’s not blank anymore. You’re not writing anything from scratch, you’re just adding a few routines. . . .

2. When to Stop

We share another problem with painters: knowing when to stop. You don’t want to stop prematurely; the project won’t yet be finished.[3] But if you don’t stop in time, and keep adding to it unnecessarily, the painting becomes lost in the paint and is ruined.

We had a client once who seemed to have some difficulty in the definition of “done” with regard to code. After toiling for weeks and weeks on a moderately complex piece of software, Matthew (not his real name) proudly announced the Code Was Done. He went on to explain that it didn’t always produce the correct output. Oh, and every now and again, the code would crash for no apparent reason. But it’s done. Unfortunately, wishful thinking alone doesn’t help us get working software out to users.

It’s easy to err on the other side of the fence too—have you ever seen a developer make a career of one little module? Have you ever done that? It can happen for any number of political reasons (“I’m still working on XYZ, so you can’t reassign me yet”), or maybe we just fall in love with some particularly elegant bit of code. But instead of making the code better and better, we actually run a huge risk of ruining it completely. Every line of code not written is correct—or at least, guaranteed not to fail. Every line of code we write, well, there are no guarantees. Each extra line carries some risk of failure, carries an additional cost to maintain, document, and teach a newcomer. When you multiply it out, any bit of code that isn’t absolutely necessary incurs a shockingly large cost. Maybe enough to kill the project.

How then, can we tell when it’s time to stop?

Painting Murals

Knowing when to stop is especially hard when you can’t see the whole thing that you’re working on. Mural painting, for instance, takes a special eye. In corporate software development, you may only ever see the one little piece of detail that you’re working on. If you watch mural painters up close, it’s quite difficult to discern that the splash of paint they’re working on is someone’s hand, or eyeball. If you can’t see the big picture, you won’t be able to see how you fit in.

The opposite problem is even worse—suppose you’re the lone developer on a project of this size. Most muralists are simply painting walls, but anyone who’s ever painted their house can tell you that ceilings are a lot harder than walls, especially when the ceiling in question covers 5,000 square feet and you have to lie on your back 20 meters above the floor to paint it. So what did Michelangelo do when planning to paint theSistine Chapel? The same thing you should do when faced with a big task.

Michelangelo divided his mural into panels: separate, free-standing areas, each of which tells a story. But he did so fairly carefully, such that the panels exhibit these characteristics:

  • High cohesion
  • Low coupling
  • Conceptual integrity

These are things we can learn from.


What is cohesion? As used here, cohesion refers to the panel’s focus and clarity of purpose. In the Sistine Chapel ceiling, each panel tells a single Old Testament story—completely, but without any extraneous elements.

In software, the Unix command line tool’s philosophy of small, sharp tools (“do one thing and do it well”) is one example. Each tool is narrowly focused on it’s primary task. Low cohesion occurs when you have giant “manager” classes that try to do too many disparate things at once.


Coupling is related to orthogonality[HT00]: unrelated things should remain, well, unrelated. Following the object-oriented principle of encapsulation helps to prevent unintended coupling, but there are still other ways to fall into the coupling trap. Michelangelo’s panels have low coupling; they are all self-contained; there are no instances of figures reaching from one panel into the next, for instance. Why is that important?

If you look closely at one of the panels that portrays angels gliding about the firmament of heaven, you’ll notice that one of the angels is turning his back to, and gliding away from, the other angels. You’ll also notice that said angel isn’t wearing any pants. He’s rather pointedly “mooning” the other angels.

There is surely a tale that explains the bare tail of the mooning angel, but for now let’s assume that the Pope discovered the mooning angel and demanded that it be replaced. If the panels weren’t independent, then the replacement of one panel would entail replacing some adjacent panels as well—and if you had to use different pigments because the originals weren’t available, maybe you have to replace thenext set of panels that were indirectly affected. Let the nightmare begin. But as it stands, the panels are independent, so the offending angel (who was apparently on Spring Break) could have been easily replaced with a less caustic image and the rest of the project would remain unaffected.

Conceptual Integrity

But despite that independence, there is conceptual integrity—the style, the themes, the mood, tie it all together. In computer languages, Smalltalk has conceptual integrity, so does Ruby, so does C. C++ doesn’t: it tries to be too many things at once, so you get an awkward marriage of concepts that don’t really fit together well.

The trick then is to divide up your work while maintaining a holistic integrity; each Sistine Chapel panel is a separate piece of art, complete unto itself, but together they tell a coherent story.

For our projects, we have several techniques we need to use inside code, including modularity, decoupling, and orthogonality. At the project level, consider architecting the project as a collection of many small applications that work together. These interacting applications might simply use a network connection or even flat files, or a heavier-duty component technology such as Enterprise Java Beans (EJB).


Up until now, we’ve concentrated on splitting up a project in space, but there is another very import dimension that we need to touch on briefly—time. In the time dimension, you need to use iterations to split up a project.

Generally speaking, you don’t want to go more than a few weeks without a genuine deliverable. Longer than that introduces too large of a feedback gap—you can’t get the feedback quickly enough in to act on it. Iterations need to be short and regular in order to provide the most beneficial feedback.

The other important thing about iterations is that there is no such thing as 80% done. You can’t get 80% pregnant—it’s a Boolean condition. We want to get to the position where we only ship what really works, and have the team agree on the meaning of words like “done”. If a feature isn’t done, save it for the next iteration. As the iterations are short, that’s not too far off.

In time or space, feedback is critical. For individual pieces of code, it is vital to have competent unit tests that will provide that feedback. Beware of excuses such as “oh, that code’s too complicated to test.” If it’s too complicated to test, then it logically follows that the code is too complicated to write! If the code seems to be too complicated to test, that’s a warning sign that you have a poor design. Refactor the code in order to make it easy to test, and you’ll not only improve the feedback loop (and the future extensibility and maintainability of the system), you’ll improve the design of the system itself.

3. Satisfying the Sponsor

Now comes the hard part. So far, we’ve talked about problems that have simple, straightforward answers. Organize your system this way; always have good unit tests; look for and apply feedback to improve the code and the process; etc. But now we’re headed into much more uncertain terrain—dealing with people. In particular, dealing with the sponsor: the person or persons who are paying to make this project happen. They have goals and expectations all their own, and probably do not understand the technology with which we create the work. They may not know exactly what they want, but they want the project to come out perfect in the end.

This must be the artist’s worst nightmare. The person paying for the portrait is also sitting for it, and says simply “Make me Look Good”. The fact that the sitter is royalty who commands a well-oiled guillotine doesn’t help. Sounds pretty close to the position we find ourselves in as we write software, doesn’t it?

Let’s look at it from the sitter’s point of view. You commission an artist to paint you. What do you get? Perhaps a traditional, if somewhat flat looking portrait such as da Vinci’s Portrait of Ginevra Benci in 1474. Or maybe the realistic, haunting face of Vermeer’s Girl With a Pearl Earring. How about the primitive (and topless) look of Matisse’s Seated Figure, the wild and fractured Portrait of Picasso by Juan Gris, or the stick-figured jumble of Paul Klee’s Captive?

All of these are portraits, all interpretations of a commonplace thing—a human face. All of which correctly implement the requirements, but all of which will not satisfy the client.