Wednesday, March 30, 2011

Stop Being Lazy

Like all human beings, programmers are naturally lazy. Sometimes this laziness can be positive, when they build an easier way to do something, or avoid complexity. But laziness usually causes problems. It trades a quick fix today for a long, arduous bug fixing session down the road. Unfortunately, programmer laziness is harder to recognize than other kinds, especially when many programmers cover it up by inventing fake technical reasons for it. Let's look at how programmers can be lazy.

Programmers usually look for a solution that’s simple for them to implement, not something that’s simple for anyone to use. This gets things done quickly which pleases management, but it makes users' lives a misery. This preference for programmer performance over user performance has serious consequences. The whole point of automation is to reduce the workload and increase the productivity of users. If the program is sacrificing users' productivity to programmers' laziness, it's flying in the face of what programming is supposed to be about. What's easy to use should always be more important than what's easy to program.

Programmers grab the first solution they think of, instead of looking for other, better ones. In most cases, the first solution is not the best, so looking further afield is necessary to program well. Getting locked in to a design is another case of saving time at first and paying for it later. With any big decision a few alternatives should be considered before going ahead with one. But never believe that there is a perfect design waiting out there for you. Every design has trade-offs and compromises, most of which you won’t understand until it’s already implemented.

This laziness about selecting alternatives plays out in another way too. When writing something, a programmer makes a huge number of decisions; some right, some wrong. To be a good programmer you need to recognize your bad decisions and rip out the code that implements them. Unfortunately, programmers naturally resist tearing apart something they’ve already written. There’s an element of laziness to it, but it’s more a problem with focus. It’s hard to step back and look dispassionately at what you’ve done and admit you made a mistake. As a result, systems get clogged with all kinds of junk. This not only makes it harder for the maintenance programmers, it can slow down the system.

When the system goes into production, it's too late to clean up. Pulling out the bad code might create more bugs than it fixes, so you'll be discouraged from doing so. As a result, production systems get filled with zombie code – dead code that no one dares touch, so it never gets deleted. The bad ideas in the code eventually percolate up to the interface, making the users miserable. Once the users complain enough, the junk will have to be removed. Wouldn’t you rather fix things before it gets to that point?

Not only should you fix things before the users find out, it’s easier to recognize bad ideas as you write, and easier to remove them while they’re still fresh enough that you understand what you were doing. Young programmers are usually resistant to cleaning up after themselves. Coding anything is such an effort for them that they abandon their mess in frustration and stagger off to the next disaster. But once programmers become confident and experienced enough, they should learn to reread their code and reorganize things that don’t work well. This will actually speed up the coding process because time won’t be wasted programming around junk.

Programmer laziness causes a lot of the problems we see in computing today – kludgey interfaces, inefficient code and poor performance. The solution is no different from what a good writer does; reread code as it's written, try it out, and keep the ultimate goal in mind. The goal of programming is making things easier for users. When that's central to what you're doing, it's easier to make the right programming decisions.

Tuesday, March 15, 2011

Writers As Designers

In too many offices, the documentation specialists are isolated from the rest of the team. The programmers usually think of documentation as nonsense, and don't think that writing clear English is a skill even though they can't do it themselves. The doc specialists are frustrated by confusing software which nobody can seem to explain, and insulted by programmers who hold in contempt anyone who can't write code. Since both sides dislike each other it's easier to not talk. This is too bad, because a writer's skills are necessary to program well. Writers can contribute in many more ways than just putting together manuals. Every step of a programming project can be improved by having writers as a part of the team.

A project begins with listening to what users want, and then trying to translate that into a consistent story. If this isn't done, or is done badly, it's likely that the users will be missing things they want, require extra training to understand the system, and possibly reject the system out of hand. Building a system out of the user's language forestalls these problems. This skill, of translating an undifferentiated mass of ideas into a narrative is what writing is. Doing this requires no technical knowledge, just an ability to listen and think, and then translate that into a system. This is an area that writers shine in.

Including writers on the design team can also help because they aren't programmers. Programmers can get bogged down in technical detail to the detriment of the design. Also programmers have a tendency to make up technical excuses for being lazy. Many times programmers will settle for a poor design because a good one seems like too much work. Another thing programmers are lazy about is the look and feel of applications, mostly because fixing cosmetic problems is usually arduous and boring. Having someone on your team that can push back against that mentality is important. It keeps the team honest.

Writers help with the design in other ways. When a writer finds something difficult to document, that's a warning sign. It usually means you need some clarification from the users, or the programmers need to go back to the drawing board and think up something that's easier to explain. Forcing writers to document things that are confusing or ambiguous means forcing bad design on your users. But if writers are full members of the team, they can tell you about these problems before the users see them.

Writers are also part of the test team. Every piece of documentation is also a test plan. The first thing a writer should do after finishing a piece of documentation is fire up the application and test what they've written. If things don't go as they should, that's another warning sign. Either the documentation needs to be rewritten to explain extra steps, the program needs to be fixed or the design needs to be revisited. In any case, the mismatch between documentation and code lets you know that some more work needs to be done.

Writers should be full members of programming teams. They can contribute to the design of the project, and are able to spot problems before the users see them. If writers are considered full team members, they'll be more willing to share problems they're having, which many times are signs of deeper problems in the application. Writers should be brought out of their isolation and into the team.

Tuesday, March 1, 2011

Label Considered Harmful

Code is straightforward and logical, but because it's written by human beings, it's as vulnerable to superstition as anything else. One of the most detrimental superstitions is the fear of early return. Convoluted nested ifs and pointless temporary flags are created just to avoid early returns. Early returns are feared because they are believed to be the same as gotos, but more awful code has been written to avoid early returns than was ever written with the goto statement. Although the return statement is superficially like a goto, it was never the goto statement that was the real problem with goto programs. If we look at why the rule forbidding goto was made, we'll see the real culprit.

Superstition begins when a rule's reason is forgotten, and the rule is blindly obeyed. Most programmers today know that goto is wrong, but never worked on a goto program, so don't know why goto is forbidden. The answer has to do with readability and information hiding. Each statement in a program changes the state of the program. How easy it is to understand the state change depends on what statement is called. Let's look at some examples.

b = 10;
c = a – b;
if (a <= 25) return;

After these statements execute, we know that a is greater than 25, b is ten, and c is ten less than a, so c is greater than 15. Notice that the return statement actually increased our knowledge about program state, by eliminating any a's less than 25. If we replace the return statement with a goto statement, we can reason similarly about program state.

b = 10;
c = a – b;
if (a <= 25) goto label1;

The goto statement is not quite as meaningful as return. A return means we're done with whatever the current method is trying to do, so if the current method has a meaningful name, we understand what the return means. A goto has different meanings depending on where it goes. Is it going back in the program to try and get a better value of a? Is it going to a special routine to calculate something different? Is it skipping over the next chunk of code since it doesn't have a good value for a? But even though there's this ambiguity with the goto statement, we can still reason fairly well about program state.

Now look at the label statement, the statement that gets executed after a goto.

  b = 10;
  c = a – b;
label2:

After label2 is executed, what do we know about program state? Nothing. The statement 'goto label2' could be anywhere in the program and before that statement a, b and c could be set to anything. We would have to find every instance of 'goto label2' in the program and read the code around it before we could have any idea what the program state is. This could be exceedingly hard in languages where labels are numbers and can be computed. This is what makes goto programming so difficult to understand and debug. It was never the goto statement itself that caused these problems; instead it was the passive label that received the goto.

And here's where the human mind gets into trouble. Because people are naturally attracted to an action like goto instead of a passive statement like label, all the negative press is directed toward goto. But the real problem with unstructured programming is having spots in the program that can be gotten to from anywhere else in the program.