Basic principles of programming
This post is meant to serve as advice for beginner programmers. If you don’t consider yourself a beginner, read on and check if you agree.
So here are a few basic principles which a programmer should follow to write good code, no matter what the language is.
When I started my adventure with programming back in fall of 1993, I wish somebody laid these out for me. There are many good books about the dos and don’ts of programming, such as Effective C++, but I think it’s still difficult to find to find the more simple basic principles like the ones below, esp. for novice programmers.
These principles apply to most areas of programming. They should be taught at the beginning of programming courses. Unfortunately most programming courses focus on tools, such as programming languages, environments, data structures, etc. but they don’t touch the craft and art of programming.
Copy & paste
When writing one of my first programs in Turbo Pascal, I quickly learned that pasting pieces of copied code around in a program leads to a lot of unnecessary work at a later time. Let’s say you have exactly the same piece of code in N places, and that code is meant to do the same thing, or even if there are N places with very similar code doing very similar thing. One day you will have to change that code slightly or enhance it. Or you will find a bug in that code. You will have to find all N places and apply the same change N times. There is a high probability that you will miss some of the places – the larger the N the higher the probability. This will lead to either not fixing existing bugs entirely or introducing new ones.
The takeaway from this is that multiple copies of the same pieces of code should be avoided. Similar code should be collapsed into one function and that function invoked wherever it’s needed. Avoid copy & paste.
Variables, functions, members etc. should be named after what they do. Most variables should be nouns. Most functions should be verbs (e.g. variable num_args vs. function count_args()). The names should be short, but long enough to give a clue to the reader what they mean. There are some schools which teach that variables should never have long names. This is OK, but in some circumstances it’s necessary to give longer names so that the reader can easily understand what is happening in the code.
There is another term for using meaningful identifier names: self-documenting code. When clear names are used, there is less need for comments and other kind of documentation.
Comments should be used whenever the names of variables, constructs etc. are not sufficient to understand what’s going on. This applies especially to more complicated pieces of code, algorithms, etc.
But why bother with all of this? One word: maintenance. Sometimes a person other than the author has to maintain the code – fix bugs, add new functionality, refactor or reuse. The less time that person needs to spend to understand what’s going on, the better. Often even the author may need to return to the code he’s written and may not remember why certain decisions were made.
Language constructs which promote bugs
Every language has constructs which promote bugs. Such constructs should be avoided. They may be useful or necessary in certain situations, but in these situations they are the necessary evil. In most other cases we’re better off without them.
In general any language feature which has gotchas, which may behave in an unexpected way (e.g. friend or protected in C++), should be avoided, unless specifically beneficial in a certain situation. When used, precise comments should be added describing the use case.
The unfortunate thing is that until you know a particular language really well, you don’t know what these tricky constructs are. They are usually not advertised in the language manuals. Sometimes there are books which help to learn about why particular features are dangerous. So the best advice one could give here is: stay alert!
Diligence vs. ignorance
The advice here is: be diligent. Learn about the environment surrounding the code you write (i.e. callers, callees, etc.). Learn about all the use cases. Try to think of all things that your approach may break. It does take experience to write good code, but it also takes common sense.
It’s good to have an additional pair of eyes review your code. If you’re writing code for fun, have a friend take a look at it. If you’re working for a company, have a coworker review your code and review his code in return. I don’t know why code reviews are not a custom at many companies. Reviews take only a small amount of time, but they have a big benefit of unifying the code to ease future maintenance, promote coding style conventions, promote good behaviors and suppress the bad ones, etc. It’s even more beneficial if somebody more experienced reviews your code, you will learn from him.
Reviews are not an ultimate solution, they will not help to find all bugs, in fact many bugs will slip through reviews, but reviews help improve code quality in the long run.