Effective Programming Strategies
Postscript
and
pdf
versions are available.
Abstract:
A person's success in programming is dependent, in large part, upon the
strategy used. A strategy that involves designing a solution from the
top-down and coding the design from the bottom-up while maintaining a
short code-compile-test cycle often produces desired results.
I remember the first time that I became vaguely aware of the importance of
strategy in writing computer programs. I was a fairly accomplished, third
year computer science major and was in the computer lab working on an
assignment. A couple of second year students were also in the lab working
on an assignment. One of the students had just “finished writing”
her program and was attempting to compile it! Needless to say, her several
page program produced over a hundred compiler errors. This student was
accomplished enough that she had anticipated a large number of errors. She
proceeded to produced a line-numbered printout of her source code along
with the list of errors. She then spread the huge stretch of fan-fold
paper, fresh from the printer, out on the floor and took a pen and began to
write corrections on the printout. After quite some time of correcting she
returned to the computer to enter her corrections. She was elated to
discover that the number of compile-time errors had been reduced to less
than fifty! After three iterations of the print-correct cycle she had
narrowed the errors down to one or two, at which point she abandoned the
printing and simply made corrections in the text editor.
At the time I was intrigued by her approach but took note of the fact that
my own approach was significantly different. Although I was fairly sure
that my approach must be a better one, I wasn't absolutely convinced of
that and certainly didn't know how to even describe “my” approach. One
thing was certain, though: “my approach” didn't seem to require printing
pages and pages of source code in order to eliminate compiler errors.
Since that time “my approach” has evolved somewhat, but it differs only
slightly from the time I first learned to program. It is silly, actually,
to call it “my approach” because it is the same approach used by
virtually every successful programmer. The approach does not require great
intelligence or discipline. It is not difficult to employ except insofar
as it may require you to unlearn your current strategy.
In many years of teaching hundreds of students with varying abilities I
have found that the difference between success and failure in a programming
course has much more to do with the strategy employed than with the
inherent abilities of the student. I have been on record for also making
the claim that the primary determinant of success in a programming class is
the student's level of enjoyment of the subject! I believe now, that
ultimately, these are two interrelated concepts. If a student employs a
successful strategy they will be much more likely to enjoy the subject. If
a student enjoys the subject they are more likely to find and exercise a
strategy for success.
Writing a computer program can be a difficult task. Most of us who are
called upon to write such programs do not enjoy exaggerated giftedness.
For this reason, many of the concepts presented here serve the purpose of
taking a complex problem and breaking it down into smaller, manageable
pieces.
A woodworker would never consider using a tool with which they are
unfamiliar on a masterpiece in progress. Yet many students will attempt to
take a brand new programming concept (or language) and try to apply it to a
difficult assignment without first understanding the concept. If you are
using a language or language feature with which you are not familiar you
should write one or more “dummy” programs that simply test that you
understand the syntax and semantics of that feature. In doing so you will
almost certainly discover that your understanding was limited. Also, you
will produce working code which can be used as a reference when you are
using the same language feature to solve a difficult problem.
This step serves to isolate new concepts until they become familiar ... only then do you attempt to use the concept in the context of a larger
problem. This is simple enough to understand and to do, but it is often
omitted as a step because, to the novice, it appears to be a “waste of
time” since the dummy programs may have little to do with the problem
actually being solved. If we return to the carpenter analogy, one could
argue that the carpenter who tests the new tool on scrap wood is wasting
time (and wood) because the same cuts could have been made on the project
already in progress. I'm no master carpenter, but I feel confident that
any experienced carpenter would agree that practice cuts represent time
well spent. That is certainly true in computer programming!
Numerous books have been written on the analysis and design phases of
program production. This document is written in terms of relatively small
programs produced in an academic environment. Before you start on your
program should have designed a solution. Identify the major tasks that
need to be performed and list them. For each tasks list sub-tasks and for
each sub-task list individual steps. This should be continued until you
have at least a vague idea of how to accomplish every aspect of the
program. At this step you should draw pictures of any data structures you
need to use and have an idea as to how to begin. It is difficult to
provide highly specific suggestions for this phase of writing a program
without knowing the paradigm being used and the specific problem you are
solving. Suffice it to say, if you are unsure how to accomplish this step,
seek help from your instructor.
The biggest fault in the second year student's approach (from the first
section) was that she failed to build her program incrementally. She used
a two phase approach: write the entire program and then debug the entire
program. For all but the most trivial programs that strategy is poor.
Even when the program is eventually convinced to compile the much more
pressing (and difficult to resolve) concern of whether or not the program
works must be addressed.
When you write code it should start with a simple, bottom-level task.
If you are a beginner you should write just a few lines of code before you
stop, compile and test. Do not proceed with the program until you are
convinced that the few lines of code you've added really work. Then add a
few more lines of code. Depending on how thoroughly you completed the
previous step you may want to write all code as individual functions or you
may want to initially write new code in main and then move that code into a
function once you feel comfortable you've found a natural break.
The most important part of this process is the incremental approach! Do
not write large sections and then test. Write only a small segment
and then test that small segment. It should be noted that if you take this
approach you will be writing quite a bit of “extra” code to check the
values of variables, etc. Also, it can seem like a waste of time to stop
typing and compile and test. That is only true if your goal to is type a
lot of source code. If you goal is to produce a working program then the
only waste of time is typing in big chunks of code and then trying to debug
them.
In this document I've claimed that your strategy for writing computer
programs will determine your success in that endeavor. I've further
claimed that the strategy I've outlined has proved highly successful.
Thankfully, that strategy is relatively simple and is very easy to
understand. A successful strategy involves learning language features in
isolation, planning your solution (top-down), and building your solution
(bottom-up) in an incremental fashion.
It may be difficult to employ this approach if you have never seen it
demonstrated. If you need help, ask your instructor to demonstrate this
approach on a small program.