December 24th, 2003 05:57 PM
Guide to making a program
Guide to making a program
Step 1: Choose a language
This step is very important. Commonly, people use a
general-purpose language and code almost everything in it. If you know
multiple programming languages (most coders do), select the language
most fit for the task at hand. Choosing a language that's not very
appropriate for the task will result in a lot of hair-pulling and
working around things that you might never even have to deal with when
using a different language that is more suited to that task. For
example, why would you write something in assembler that does pattern
matching in text files when perl or awk are much better choices? The
language chosen should be suited to the application. If you only know
one language and find that doing something in particular is very
difficult, i would suggest learning another language.
Step 2: What's the problem?
Identify the problem. What do you want the program to do. I
believe this is the leading cause of discouragement in beginners, either
they want to do everything and can not yet plan to build something on
that scale, or they can't decide what to do and just start writing code
and wondering why the code doesn't work. For example, say you wanted to
write a small program that can find the average of a set of numbers.
That's your main problem.
Step 3: Break it into smaller problems
Try to break the main problem into little problems that are easy
to solve so that you can make more sense of the program. In the above
example of finding an average, there are two other problems. First, you
must find the sum of the sequence. Then, you must divide that by the
length of the sequence. They can then be broken down into smaller
problems of "When do i know i've added all the elements together?" and
"How long is the list?". So you see, by taking it to the fundamental
level, we come up with a list of little problems that are easy to solve.
Step 4: Explore other algorithms
Exploring other algorithms is important. Just because you
thought of one way to solve a problem, doesn't mean it's the best way to
do it. In many cases, there is no best way. You can try to go for speed,
or memory efficiency, or other criteria. For example, say we didn't have
the full set of numbers to average and we only got them one at a time.
Using the previous method, we'd have to store every piece of data and
then find the average again every time we got a new piece. This isn't
very efficient now is it? We still have to store all the numbers, re-sum
them every time, and divide again every time. As the program goes on,
our memory usage increases. Also, we run the risk of the sum overflowing
the datatype we're using.
One way to address the problem is to do some math and find that
the average of all aligned averages in a set equals the average of the
set itself. With this design, every time we reduce things, we take up
less memory and worry a little less about overflow each time because
we're only finding averages of small groups. Now, this addresses the
problem of overflow and memory usage, but it's still very processor
intensive and will not work on lists of prime length or very well on
lists whose length has few factors. We still haven't addressed the
dynamic issue yet. This algorithm would have the same problem as the
A way to address this problem is to do some more math and figure
out how to reweight the averages. For example, the average of two
numbers is their sum divided by 2. Now, say we wanted to find the
average of those two numbers and another number. We could multiply our
old average by two, giving us the sum of the two numbers, then add our
new number, then divide by 3. Well, that sounds like a good idea, but we
still have that nasty overflow problem don't we? Well, we can fix that.
Using the distributive property, we can multiply our old average by 2/3
and then add one third of our new number. This will result in the same
thing and will avoid the overflow problem. But now, a new problem
arises. What happens as the divisor gets bigger and bigger? Well, it's
possible to experience an underflow, which is what hurts this algorithm.
So, you see, there's really no "right" algorithm for some
problems. Depending on your criteria, any of these three could be your
best choice, and i'm sure there are others out there too. I suggest
repeating steps 2 and 3 for this step (you won't get far without them).
Repeat this step until you can't think of any other ways to solve the
problem, then pick the one that best suits the task. If you need to, you
can write up an efficiency program (i know i did for my prime generators
and modulus functions).
Step 5: Designing and Planning
Now that you have your algorithm picked out, you should consider
how the program will work. Ask yourself these questions:
1) What's the input?
2) What's the output?
3) What do i need to do to turn the input into the output?
Now, they may sound like silly questions, but believe me, it's where
most mistakes occur. People aren't sure what the input should be (not
like a string or number, but like file, keyboard) and how the input is
formatted when the program sees it. People aren't sure what the output
should look like and don't know how to format it properly so they get
what they want. The biggest problem is the intermediate changing of data
though. What format is the data in when you start processing it? Should
it be changed? What do you need to do with the data?
Once you've answered these questions on the abstract level, go
back into steps 2 and 3 and figure out how to make it work in general at
least. After this, you should have a good idea of what you want the
program to do, what purpose it serves, and what it'll be broken down
For example, a good password generator should have the following
1) A pseudo-random number generator (to make random numbers)
2) A way to store the passwords
3) A way to secure these passwords such that only the person that made
them can get to them
4) A way to protect data integrity (checksums and such)
So, those are the general program parts we need. We can start to develop
ways to solve these problems in steps 2-4. Once the problems are solved,
you're ready to make your design plan somewhat concrete.
This part is where some coders disagree. Some feel that you
should continue refining your design plans until you write pseudo-code
for them (fake code that basically tells what it should do in english,
but not exactly how to implement each piece). Converting from
pseudo-code to any programming language generally isn't hard and if you
keep the language you chose in mind, you can make pseudo-code that's
more accomadating to that particular language. Some coders feel that
isn't necessary. That you should be able to sit down and write code once
you have all your ideas straight.
This is a hard one though. If you're willing to invest the time
to make out the pseudo-code for the program (and do it well), it's
generally easier when you sit down to code it because all you're doing
is implementing the code on your paper in a programming language. But,
if you're not willing to invest the time, it's usually not too bad to
just sit down and code if you're familiar enough with your ideas.
Step 6: Coding
Yay! The fun part at last! Okay, this is the important part. Up
until now, it's all just been preparation. All you do now is implement
the ideas you had. This section is kinda sparse because there's not
really a lot to talk about. This is actually the easiest part if you
plan well. If you plan poorly, you'll be stuck in steps 6 and 7 for
quite some time.
Step 7: Debugging
There are problems with any program. Commonly the first that
crop up are syntax errors, errors that occur when you misspell things
and try to do something you're not allowed to. Once you've worked out
all of those errors, you may have problems with the logic in the
program. Perhaps you did something that caused exactly the opposite of
the result you wanted. There are several ways to debug and most of that
depends on your language and tools.
The first debugging method is just to look over your code and
see if you just did something stupid. Don't feel bad, it happens to all
of us. For example, a hash function program i wrote wasn't working and i
found out after sifting through 36 pages of diagnostic material that i
typed buf2 where i should have typed outbuf. This method can save you
lots of headaches (and lots of paper).
The second method is to use a program that lets you step line by
line through your program code. This way, you can see what your
variables are doing and everything else that's going on. This is
probably the handiest way to debug, but sometimes we don't have the
ability to do this.
If you can't step through your program, but your platform has
good error reporting (like Euphoria, who dumps out all your variables at
the crash instance), you can use an intentional crash method. This is a
good way to determine what exactly is going on and how far your program
Another way is to install diagnostic code and just dump every
variable and its contents to the screen along with some other general
information about the current place that's being executed. This method
will allow you to check everything that happens on the run-through.
However, this method isn't always the best. It results in lots of data
you have to sift through. But sometimes, you gotta do it that way.
The last resort method of debugging is by hand. Simply step
through your code and write down all the variables as they change and
their new values. This is just like diagnostic code, but you don't have
to write any code. This method is prone to error unless you really act
like a computer and do exactly what the code tells you to. If you don't,
you'll have a case of human error where the program seems to work fine
but it's because you did what you wanted the code to do, not what the
code said to do.
At this stage in programming, commonly, you run into technical
problems where you find out that what you planned to do didn't work.
This is more common in projects where you don't plan all the way down to
the trivial level, but leave things more open. So, you go back and
change your design plan, that's the only thing you can really do.
Once you have found the problem in the code and figured out how
to fix it, go back and recode it. You'll go between steps 6 and 7 quite
Step 8: Documentation
Well, i've been talking about documentation in planning a little
bit. But, it's also important to comment your code as you go so that
it's easier for others to understand or for you to understand later when
the ideas in your head aren't so fresh. It makes it easier to understand
what you were trying to do. Now, if you did a good design, most
everything should be in there and you can just say to reference that,
but sometimes that's not enough. I won't cover comment style in this
because that's really personal preference.
It's always a good idea to write up a formal design plan so that
everything you're doing is laid right out in front of you. I have a
general form that i follow below:
--Formal design form--
Reason for coding:
General program purpose/What problem does this solve?:
List of problems to solve:
Abstract ideas on how the problems whould be solved:
With this form, i allow myself to organize what parts of the program
there are, what i want to do with them, and i still leave room for
techspec's for when i run into problems or when i'm cementing ideas
(applying your abstract idea to this particular application).
It's always good to write follow-ups for your designs after you
finish the program, or as you finish modules. This way, you can see what
went well, what didn't go so well, and what you'd do differently if you
were to attack this problem again without any code at your disposal.
It's also good practice to keep an "oopsies" list of mistakes
you commonly make so that you can go back and check for those things
when debugging a program. (This has saved me hours of debugging in
Well, that's about it i think. There's not really much else for steps of
programming, feel free to email me and give suggestions so this can be
Is there a sum of an inifinite geometric series? Well, that all depends on what you consider a negligible amount.
December 25th, 2003 04:34 AM
Good post, this is classic CS wisdom, and unfortunately is not being followed today in many shops.
Only thing I would add to it is decide on a Version Control system (e.g. CVS, Perforce, PVCS, etc.) and
use it religiously from the beginning. The best designs often come from making a few forks of the project
at some design-critical point, and being able to do usability tests on each fork later to determine the best
working design for customer use.
Again, good post.
Get OpenSolaris http://www.opensolaris.org/