Local Links

External Links

Contact

Search this site

TT's very basic coding guidelines for programmers


Document your intentions

When documenting your code, it's not a bad idea to prepend a set of lines, e.g. a loop or an if...else...end block, with a summary of that's going to happen there. Makes it easier later to find yourself quickly around the code.

Even more important, though, is to write what the code intends to accomplish. Because when you or someone else later tries to add new features to a function or class, or wants to find a bug in it, modifications to existing algorithms may be necessary. And then it's necessary that one understands what the purpose of the code is, so that the change will observe to keep that code working the way it should.

Document external conditions

If you write a new function (method, procedure, subroutine), it is usually done to serve a specific purpose. Not only document that purpose at the head of the function's code (or, if you use a language such as C, preferrably where it's declared in its header file), and understand this documentation being the contract under which it shall operate. This means to write down what kind of input it expects, what output or effect it causes, and which preconditions must be met.

Use "assert" functions to make sure your expectations are met.

It's always good to verify the conditions you need to see met by writing them into your code, using so-called assert funtions. Their basic use is that you pass a condition that you expect to be true, plus optionally a text describing the expectation in words. The assert function will check if the condition is met, and if not it will somehow report this and optionally abort the program or currently handled event with an exception mechanism.

While many programming frameworks provide procedural (i.e. those that do not return a value) assert calls, I often find it useful to add my own that actually return the condition's result again. Then I can code it like this:

if assert (index > 0, "index must be > 0") then

  ... do something with the index

end

That way, I can record failure while avoiding the need to terminate the code immediately. While there are situations where a failed assertion should definetely terminate the current process, others can be worked around in a way to keep the rest of the application working, at least in a state where the user could still save his data after being informated by the assert function that something went internally wrong, for instance.

Important note: Assertions are meant to be used where coding expectations have to be met. E.g, it's wrong to use assert on input from a user or a file or something else that is not under full control of your code. However, a function that gets passed user input, may set the expectation that the input has been validated and asserts on this. If the assertion then fails, it means that the code that was supposed to validate the user's input didn't do this properly and needs fixing therefore.

If you "comment out" your code, add a note saying why

Way too often I see code like this:

  // x = aFunction (1);
  x = aFunction (2);

Then I have to ask: What is going on here? Is the first line outdated, thus can be deleted? Or is the second line a temporary test while the first line is the right one, and it has been forgotten to undo the test again?

Hence, to avoid such confusion, make it your rule to always explain why you comment out code. Write something like "tmp test only", or "outdated". And, if it's outdated, there should be no need to keep the old code in there for long - use a Version Control System (such as subversion or git) to record your previous versions of your code, while keeping your current version tidied up.

Test every code path

When you've completed a function or even a class, make sure you use a debugger's breakpoint feature to make sure every line of your code is actually not only working be really used.

For instance, if you subclass a class and overwrite a function in it, make sure that this function really gets called. Because, in many programming languages, you can't tell the compiler that you meant to overwrite a function from the superclass. So you may make a spelling error, thus create a new function which will never get invoked.

In any case - get used to set a breakpoint into every newly written code, function and if-block, and then test your code, making sure every line gets run into eventually, maybe even verifying the values of variables against your expectations. Once the code has been verified to be executed, remove the breakpoint.

That way, you have a simple yet quite effective way to test your code properly.

And yes, unit tests are the more professional way to do this, but seriously, who makes the effort to write a unit test for everything he creates in code? My suggestion here, on the other hand, requires no extra coding, yet is a very efficient way to detect most coding errors right away.

Summary of rules to remember

  • If you write a new function or class, add some lines explaining what its intention is.
  • If you comment out lines, add a note explaining why.
  • For every new function and every conditional code path you're writing, set a breakpoint to remind you that this code still needs to be tested to run at least once through the debugger.
  • Code that's left around but does nothing should be removed for readability (this often happens when adding new source files from templates where there are dummy functions that you may extend - if you don't then remove them).
  • Use Assert to verify the "contract" between you and the outside. This means to verify arguments you got passed, returned values from functions you invoked, and state of other globals that you access.

Further reading


Page last modified on 2013-07-15, 17:52 EDT
Powered by PmWiki