Intro to Writing "Good" Code



http://www.icarusindie.com/DoItYourSelf/rtsr/fyi/fyi.goodcode.php

Intro to Writing "Good" Code

Determining whether code is good code or not is dependent on what the code
is supposed to do. If your code is supposed to run fast then efficient code
is good code. If the code is educational then readable code is good code.
There are a number of things to consider.

Functionality - Does the code do what it's supposed to do
Readability - How easy it is to read the code and follow it
Usability - How easy it is actually use the code
Efficiency - How well it does what it is supposed to do
Stability - How hard it is to get the code to fail
Reusability - How easy it is to use the code in other projects

Functionality: This is the most important thing about any piece of code. It
doesn't matter how "nice" the code looks or how fast it is, if it doesn't do
what it's suppsed to do, then it's junk. Nonfunctioning code is most common
on forums. This is because people are more interested in getting the first
word in than actually being helpful. Or they simply think they know
something when they actually don't. There really is no excuse to publish
nonfunctioning code anywhere. If you havn't compiled and tested it to verify
it works the way it's supposed to, then don't distribute it. It's rediculous
how many open source projects just flat out don't work. After all "it's
somebody elses job to fix it." The first rule of programming is "take
responsibility for the crap you write." If you wrote it, it's your job to
make it work.

Readability: Eventually somebody (most likely yourself) is going to have to
look at the code a long time after it was first written. If your intent is
to publish the code for other people to use then readability is number two
after functionality. If nobody can understand your code then there's no
point for it being out there. If you can't understand your code even as
little as a month after you wrote it then you're in trouble. If you rely
heavily on comments in order to understand the code then either you simply
don't understand the language well enough or the code is just plain sloppy.
Comments should provide a summary of what's going on. Not detail every
little thing. "This is a for loop" or "This is x, he's very fond of being
used in for loops" are bad comments.

You should use descriptive function and variable names.
//bad programmer, no pay check
void ThisIsFunctionMooWhichPrintsMoo()
{
printf("moo\n");
}

//good programmer
void printMoo()
{
printf("moo\n");
}

Proper whitespacing and naming makes it obvious what functions do without
wasting time writing redundant comments.
For prime examples of how not to write good code, check out Magic Software.
If you take a look at WmlSphere3.h, WmlSphere3.cpp you see an excessive
amount of code for what amounts to a class which contains three values for
the position of the sphere and the radius. Compare that to the sphere class
we've been using. The first mistake of this code is using templates. The
second is breaking the class up into two files needlessly. The class frankly
does absolutely nothing but requires you pair up two files on top of a
vector class which I'm afraid to look at. You'll find a number of vector
related files in the mathematics section and the code contains memcpy's for
what appears to be returning a copy of the current vector. This can also be
accomplished by doing a

class1 a,b;
b=a;

This code fails miserably on readability. The reason for this is that the
author probably knows a lot about programming and has long forgotten a key
rule of programming: Keep It Simple Stupid.

Usability: If a piece of code requires a million things outside it's scope
to work then it's not particularly usable. The more self contained a
function is, the more useful it is. As a general rule a function should not
require any external values that are not passed in as parameters.

//that's it, uninstall your compiler
//you will never work in this town
//again
int add()
{
return a+b;
}

Although global variables are often necessary they should be avoided where
possible. The above example is completely useless in any code where a and b
are not defined globaly.

//that's better
int add(int a, int b)
{
return a+b;
}

We've been using classes quite a bit in the tutorials. Just like functions,
classes should be as self contained as possible. They should also be as
single minded as possible. A vector class for instance should not contain
functions that handle rendering graphics.

Looking back at the code at Magic Software, usability is also in question
because of all the dependencies. We need Vector.h for the sphere class but
who knows what corresponding cpp file we need to compile with it. There are
a number of vector h files and vector cpp files. And even then, once you get
it compiled, good luck figuring out how to use it for anything.

I'm assuming the person who has assembled this mass of code is doing it for
educational purposes since there's no indication it has a specific use for
anything. This makes the choice to use templates even more questionable. If
you're writing code with the intent to teach concepts then you focus on
readablity and simplicity. The less code you use, the better. The less
"fancy" code you use, the better. You simply can't write code without
considering your audience. You cannot become so obsessed with C++ and Object
Orientated Programming or you will lose the ability to write useful code. A
"one size fits all" mentality is a very bad thing.

Efficiency: For our lessons the focus is on real-time which needs efficient
code but we also want to teach lessons so the code is maybe less efficient
than it could be. We've done a number of optimizations as we increase in
complexity. The idea is that we show you how it works and then show you how
to make it work faster. You never want to optimize too soon. All code should
be written first to work and second to work fast. If you optimize too soon
the code could become more difficult to debug if problems come up later.
Imagine trying to debug Wolf5K in it's obfuscated state.

It's easy these days to write sloppy code and not even realize it because
the processors are so fast. Where possible you should develope your code on
a machine that is much slower than your target system. You also need to
learn what is a reasonable and not reasonable speed for something to run at.
That just comes with experience. Wolfenstein 3D runs very very fast on a
modern system. If you write a version and it only goes say 15 frames per
second on a 1.5Ghz system then your code is obviously inefficient. Wolf3D
can run twice that on a 486 machine.

You need to have a reasonable view of the complexity of your code in order
to judge whether the code is inefficient or you're just doing something very
complex that a slower speed is to be expected. If you're plotting a single
pixel on the screen at one frame per second then your code is bad. If you're
plotting a billion pixels on the screen at one frame per second then your
code is probably just fine. It doesn't matter how efficient your code is,
you simply can't render Toy Story in real time.

Stability: Stable code is code which doesn't break no matter what inputs you
pass into it.

float xdivy(float x, float y)
{
return x/y;
}

The problem with that of course is that if y is 0 you will get a divide by
zero error. To make the code stable we need to add a check to see if y is 0
and if it is, return a very large number or some other valid value. As code
becomes more and more complex it becomes more and more difficult to spot
conditions that will cause the program to break. As a result, code needs to
be tested and retested.

Java, C++ and C# as well as other languages give you the ability to use try
and catch statements.

try
{
x = x / y;
}
catch(...)
{
printf("divide by zero error\n");
}

It might be tempting to wrap your code up in those but you shouldn't. They
add overhead and are suitable for debugging and catching invalid user input
only. If your code is causing an exception then you need to fix the code so
it doesn't generate the exception. Not just throw a try catch around it in
an attempt to hide the problem.

if(y!=0.0f)
x=x/y;

That is a much more solid solution. It addresses and accounts for a
potential problem which results in preventing a problem instead of just
addressing it after the code breaks.

Reusability: After you program for awhile you realize that you are often
writing the same code over and over again. Reusable code is code that you
can take from one place and use in another without having to rewrite
anything. If you're doing the same operations over and over then it's a good
idea to consider writing a single function which does the operation and then
call that function where needed instead of reimplementing it over and over
again.

The ultimate goal of reusable code is Plug and Play classes. Plug and Play
classes are classes which are entirely self contained. You simply add them
to the project and you can use them. No assembly required. All batteries are
included. The Core that we've been using in these tutorials isn't quite plug
and play. It is missing a couple functions and variables that the user must
supply. The cVector class which we will cover in Lesson 29 is a plug and
play class. You simply include the single h file and you have access to
vectors and vector operations without having to write a single line of code.

And that concludes this side lesson. Being able to write good code is just
like being able to write legibly. Some people just simply have sloppy
handwriting. Some people just let their technical knowledge of a language
override their common sense or simply can't see their work from someone
else's (the audience's) point of view. The only time it only matters that
you can understand it, is if you are the only one who will ever see it.

Find more programming information and resources at www.icarusindie.com


.



Relevant Pages

  • Re: Check a radio button
    ... Statements about writing code from scratch without using wizards, ... emulate sequential programming in an asynchronous event-based systems, ... He added gratuitous complexity for the wrong reason. ... I've watched products fail because of bad decisions, bad coding practices, ...
    (microsoft.public.vc.mfc)
  • Seek Contract Programming Work - 17 Years Experience
    ... where I did nothing but debugging and optimization. ... electric keyboard), so I enjoy writing MIDI, audio and music applications. ... file format to the C++ API) for a financial firm in the Bahamas, ... to handle any sort of programming task. ...
    (comp.programming)
  • Seek Contract Programming Work - 17 Years Experience
    ... where I did nothing but debugging and optimization. ... electric keyboard), so I enjoy writing MIDI, audio and music applications. ... file format to the C++ API) for a financial firm in the Bahamas, ... to handle any sort of programming task. ...
    (comp.lang.java.programmer)
  • Re: Whats the name for this?
    ... you're the only one mentioning it in connection to programming. ... > is no connection between the philosphy of Plato and Computer Science. ... French philosopher, who pointed out that at the dawn of writing, Plato ...
    (comp.programming)
  • Re: Dijkstra gets it wrong [was: Re: D gets it right]
    ... if the language isn't too whacky). ... All programming languages are formal languages although the converse ... A reading of hero computer scientist Dijkstra would teach us to treat ... the very idea of "program readability" with that lofty disregard ...
    (comp.object)