Lance's Coding Rules
Below are some of the things I have found in my years as a developer and 'code repairman' that
will help you make your projects cleaner; easier to read, test, and maintain or modify. If you
follow these rules and know what each area of your code is doing, when something goes
amiss, you will have a pretty good idea what is going wrong and where before you even look at
the code. I've even met people who know some or most of these rules but when I look at their
code, they don't seem to follow them very much. I have learned that in the long run, it takes
more effort and will cost you much more time if you code sloppily than if you do it right the
first time. I'm sure there are more good rules than just the ones here, just be sure to follow
them and you will more than likely have order instead of chaos in your code.
1. Eliminate Duplication
2. Organize Your Code
3. Use Self Documenting Code
4. Use Visual Separators
5. Be Consistent
6. No Multiple Statements On Single Lines
7. No Multiple Returns In Functions
8. All Functions Should Return Something
9. Don't Declare Variables In Loops
10. Properly Define Classes
11. Build In Testing
12. Write For Future Modification
13. Write For Future Portability
14. Keep Things As Simple As Possible
15. Databases: Organize Your Schema
16. User Interfaces: Think About The User
17. Test And QA Before Release
18. Version Your Code
19. Design Before You Code
20. Use The Top/Down Method
21. Know When To Start Over
22. Don't Rush To Publish
23. Know When Not To Use Objects
24. Learn From Others
25. Revisit Your Code
26. Don't Be Too Clever
27. Good Coding Is An Art
28. Enjoy Writing Code
29. Writing Games Is Good
30. Perform A Post Mortem On Projects
31. Don't Refactor in the 11th Hour
32. Be A Team Player
33. Get Final Specifications Before Design
- Whenever a function or code thread appears exactly the same or even
almost the same with a few minor variations more than once, then put that in an accessible
library or class. You would not believe how many times I have seen this in people's code. I
guess they are too lazy to make a proper function/class/method that takes a few variables.
Too easy for them to just 'cut & paste' the same lines of code around. I have even seen this for
a series of multiple functions in which all they vary in is in what datatype their arguments are.
In those instances, use a template class or if all of them are returning a success/fail boolean,
then use small wrapper functions/methods that convert the to the largest precision datatype and
have that function/method be the main working one. Doing just this rule alone can reduce
the size of your code substantially and reduce significantly the places where errors can occur.
Organize Your Code
- Whenever a function or method goes beyond my rule of thumb of a page
or two or it grows too large in size because it is doing too many things, I will break it up into
smaller functions/methods. I have seen some C programs where the main body was doing over 90% of
the work and taking up several pages of code. The main should be very small and follow the
following format and sequence regardless of what it is; script/app/daemon and whether or not it
needs human interaction or output or an interface:
1. Check Requirements (system, user, arguments, etc)
3. Main Event Loop
4. Cleanup, Restore
With the exception of Step 5, the other steps can be broken down further and branch out.
Use Self Documenting Code
- What this means is not writing comments all over the place or by
having bloated function header sections, instead it means simply to name your variables and
functions/methods that directly relate to what they are doing in an easy to read fashion. If
you have a function/method that reads in and parses a config file for example, then call it something
like "ReadParseConfigFile" or "ConfigFileReadParse". If that function becomes too large as in
Rule #1, then split it into two functions named "ConfigFileRead" and "ConfigFileParse".
I then know by their names without even looking at their code bodies what they do. The same goes for
variables, if I have a counter that represents the number of parameters in my config file for example,
then name it somthing like "numConfigParms" not "ncp" or even worse, "i". A further tip; when
you need to use globals or variables that are used in more than one file, prefix them with an
abbreviation or acronym of the file/class that they came from. This little trick and a legend of
what those prefixes mean can save you hours of hunting around for where certain variables originated
from particularly if someone has sloppily used the same name elsewhere for a variable, you can
quickly determine which one is which. If you do this rule, then you will notice that you
don't seem to need very many comments at all in your code as the names speak for themselves.
Use Visual Separators
- What this means is use something simple like a dashed or dotted line
to separate functions and class methods. You won't believe how greatly this speeds up your ability
to quickly scan files when you are lkooking for something. Of course if you are using a good IDE
like Microsoft's Visual Studio and if it is wriiten in an object oriented language like C++, then
you can use the builtin class browser and click to wher eyou need to go. But what if you don't
have something like that or you want to print it out? Believe me, having a "blank line, dashed line,
blank line" between functions/methods is very nice. I even use smaller "dash,space,dash" lines
inside functions/methods to further separate areas in them. Visual separation also includes using good
indentation for nested sections of code. It's quite time consuming to try to read someone's code when
it's all mashed up against the left edge.
- Don't name things one way in one file or module, then do something different
in others. If you use camelcase, then stick with it, if you use underscores, then use that. In short,
whatever your style is, make sure you don't change it throughout your program. This includes using
code or functions or classes written by someone else. It takes some effort, but rewrite them in your
style to be both easier on yourself anybody else who has to look at your project in the future. This
especially applies to team development where you may have several coders working on the project. All
coders need to adhere to an agreed upon coding standard before work begins else you will end up with
No Multiple Statements On Single Lines
- This is sloppy and makes code very hard to read. You
now have to scan horizontally to locate that ';' and then proceed again to find what you want.
Further, inserting or adding additional calls only further grows the line and obscures the code.
Probably the most common abuse of this is a block of successive if/then's or if/elsif's with the
action for the statement immediately following the test. If you decide to put a breakpoint inbetween
statements, you will have to separate the lines anyway to do so.
No Multiple Returns In Functions
- I can't tell you how often I've seen this crap, even
in examples from books on programming! It takes a little more effort to declare an error flag at
the beginning of your function/method and to test for it at various sections to continue or not
but it makes your code much cleaner. Remember, single entry and single exit for your functions
All Functions Should Return Something
- How can you prevent unforseen things from happening if
don't return at the very least a success/fail (0 or 1) from functions/methods? If you call a
function that has void for a return value and something prevents that function from executing
properly and you follow that call with another function call or code thread and don't do any
success test, bad things will happen. A simple example would be trying to read a file without
knowing if the opening of the file was successful first. The only possible exceptions to this
are when you are calling built-in functions or methods from the OS's API or some other 3rd party
library that doesn't return anything. Another rare exception might be for testing or when you
absolutely positively don't care whether the function succeeds or not.
Don't Declare Variables In Loops
- This is really sloppy and will cause
memory leaks. Unless you are purposely building a dynamic structure such as a linked list, all
variables and objects that are used only once should be declared and instanstiated/initialized
at the very beginning of your function/method. In addition, this leads to duplication as in
Rule #1. I have seen functions that had variables/objects instantiated with each iteration within
a loop structure such as a 'for' or 'while' or 'do'. That is bad, very bad.
Properly Define Classes
- This means that for a language like C++, properly separate
your header and implementation files. I have seen classes defined and the methods declared inline
within them so that everything is now in the class definition itself! That is very sloppy. Just
make the extra effort and write them correctly. It makes both reading and maintaining them alot
Build In Testing
- This may seem at first to greatly increase the size of your code and
you might be thinking, "But that is what the debugger is for." Ha! I can honestly say that over
the years, I have never relied upon a debugger and have only used them once or twice. In addition
to this, if you have a globally defined "DEBUG" variable and say 0, means no debugging, and 1, 2,
3... etc are successively greater levels of debug, then you can put in debug/testing statements
wherever you want. Plus, the greater implication is that now there is no separation between your
"test" and "production" versions. That means that if a user is experiencing problems with your
application, they can just enable the appropriate level of debugging/tracing/logging and send the
output back to you.
Write For Future Modification
- This means that for everything you code, ask yourself the
following question, "If I or someone else has to add or change things later on, will it be easy
to do?" This rule really leads to adhering to alot of the previous rules. Even if your functions
or classes are not going to be reused in any other application, write them as though they were
going to be. Sometimes this means just including a few more unused fields in a database table or
some unused variables in your structures or classes. What you are thinking here is reducing the
effort at some later point when the changes are so extensive that it requires 'major surgery' to
Write For Future Portability
- If your original project was written in C++ and you or
someone else is now tasked with porting it to JAVA, C#, or another OS, will it be a straightforward
and simple thing to do? If not, then go back and re-examine your code for anything that is
language or compiler specific. If you absolutely have to have it, then isolate it with comments.
This applies to individual functions, methods, and classes too. By writing a very generic middle
layer that does all the work but interfaces to one or more specific layers, you can more easily
translate your projects wherever they need to go by just just changing an existing OS/language/API
layer or adding a new one. A typical example of this is in the display of graphics where a program
can use OpenGL, DirectX, or some other API. The main working layer deals with generic objects and
scenes then sends it to the selected graphics API layer.
Keep Things As Simple As Possible
- Stay at as high a level for your language or API that
you can. This not only reduces your coding work/size, but makes things much more likely to be
compatible with OS or compiler changes in the future. Do not, I repeat do not use low level
API calls or some sort of inline assembly trick. Do your research before you decide to reinvent
a function or class that the language already has. Don't try to duplicate a database in a flatfile.
If that is what you are doing, then use a friggin database! MySQL is a very good free database
that has connector hooks from C++ or even Perl's DBI interface. Try to be efficient in your coding
style without being cryptic. If 2 or 3 lines of code can suffice instead of 10, then write only
2 or 3 lines of code, providing you and others can read it without thinking about what the heck
is going on there. This too can be taken to extreme in that say for instance, pages or windows are
too simple and could better be served by combining them to reduce mouse clicking. Albert Einstein
once said, "Everything should be made as simple as possible, but not simpler."
Databases: Organize Your Schema
- Don't put everything into one or a few tables. If all your
rows differ is by a few or even many known values in one field, then take those values and put
them in a lookup table. If you have a many to many relationship somewhere or suspect that it
could become so in the future, then make an intermediate relationship table table that contains
the 1st and 2nd tables pairs of their primary keys.
User Interfaces: Think About The User
- Imagine the user as though they know nothing technical and that
they are used to, no expecting, things to be logically and convieniently arranged and not overly
cluttered or confusing or time consuming to get to where they need to go when they use your program.
The customer is using your application for a reason, make it not only easy for them to work with
your program, but pleasing to the eye to do so. Reduce unessary mouse movement. Don't have the 'OK'
button on the left in some windows and then on the right in others. Be consistent (Rule #5). Have
some non-developer people look at your UI and ask them to try it and give feedback. Think of yourself
as a user of your own work. Do you enjoy using your own program? If your program is frustrating to
you, then an end user will most likely experience that same frustration tenfold. Use color to both
emphasize and de-emphasize things. Use bolding appropriately. Groups things accordingly. In short,
you are striving for a user to be able to start using your interface without even looking at the manual.
That is the definition of 'intuitive'.
Test And QA Before Release
- Have a development or test environment to do all your alpha
and beta work on. If you don't then you are playing the coding equivalent of Russian Roulette. In
fact some companies will terminate you for that even if nothing goes wrong. The fact that you
skipped any sanity checking is a big violation.
Version Your Code
- Even if you aren't using a formal code management system like CVS, RCS,
SCCS, or commercial products like ClearCase, you should always, I repeat, always, make a backup copy
of your source files and put them in a date stamped directory. Then if something goes really wrong
during your coding session, you can always restore to your saved version. Every time you modify a
source file, put those changes at the top of the file and version it. The most popular way of doing
this is by using a numbering system like "w.x" or "w.x.y" or "w.x.y.z" where:
w - major version number (major features)
x - minor version number (minor features, multiple patches)
y - major patch number (major fixes and updates)
z - minor patch number (minor fixes and cleanup)
Design Before You Code
- Not much to say here. Just do it. I have another rule of thumb for
this. For every hour or day you spend in design, you will save at least 10 times that in coding,
testing, and bug fixing. This is the parent rule to Rule #2 though it exists at the pre-coding design
phase of the project. All developers should be familiar with design principles and be able to do so
properly. It doesn't matter if you know the latest and greatest and fanciest design tools, the proof
is in the quality of what you can produce. I have seen self styled 'designer/developers' that were
very familiar with UML and various tools, but their project layout including database schema was crap.
The end user could care less what the qualifications or resumes are like for the designers and developers,
he only cares about and sees the final product, which sadly to say, I have seen some shareware out there
that was done by single individuals that rivals commercially developed software by whole teams of people.
Use The Top/Down Method
- I was taught this way back in college years ago and I have yet to see
anything that even comes close to replacing it for logic and simplicity at all levels of design and
coding. Think about it, everything else in life is has a top/down structure, so why shouldn't your code?
You have a manager who has a higher level manager and so forth. Cities have states or provinces that
have national governments. Even in terms of animals, people jokingly refer to the 'food chain' to
describe most hierarchical systems. Your application starts with an entry point. It should then branch
out as in Rule #2 or like a pyramid getting more detailed and specific as you go lower. In fact, only
the lowest most classes or functions should contain any language or compiler differences. This then
makes your code very portable; all you have to do is change the low level distinct parts, everything
else will remain the same.
Know When To Start Over
- When you are attempting to fix or modify previous code and are
daunted by the task because of well, not following any of the above rules by the original programmer,
you should be able to accurately gauge the amount of time it will take you. Then make an estimate
of the time it will take you to fully duplicate what the program or subsection is doing from scratch.
If starting over is even close to the time it will take you to do extensive repair on the existing
code, then start over. Why? Because you will end up with (hopefully) a cleaner, smaller, more
efficient, piece of code that you fully understand. This rule also extends to the entire project.
If your next major version or patch is so big and time consuming, you might want to salvage the parts
you can and do a rewrite.
Don't Rush To Publish
- This is where you need to stand up or 'push back' to your management.
Just because they want it done in 6 months and you know for a fact from previous projects that even
working 60 to 80 hours a week you could not get the scope of the project done in even 9 months, don't,
and I say again, DON'T agree to a ridiculously short time limit or milestone or completion date.
This is setting up not only you but everybody else connected to the project for burnout and failure.
Know When Not To Use Objects
- I have seen some projects where objects were so over used that
it looked as though the developer or developers were drunk or high on object oriented programming.
Remember that if you want speed, you may have to forego the use of objects. Why? Because when you
use objects, you incur a penalty in terms of memory usage, code size, and speed. In following Rule
#14, try to keep your class hierarchy to roughly 4 to 5 levels deep from the base class max. I once
worked on a commercial product that had over a dozen levels of objects and one at the very bottom
was merely a wrapper around a standard C library function, printf. Don't make object wrappers for
standard library routines. That makes no sense at all. Remember, the use of OOP is a convenience
for the developer and company with the possible reuse of those parts later on. The end user can't
tell and could care less if it was object oriented or procedurally developed, all he or she cares
about it how well it works.
Learn From Others
- Most of the things you will code have more often than not, have already
been done one way or another. Go find examples of similar things on the internet, in books, or even
by talking to coworkers or friends. Don't reinvent the wheel or duplicate what somebody has already
done that you can get and modify to your needs quickly. Just make sure that when you take from others
work that you give credit to whom you got it from and that you make an effort, if you can, to apply
Rule #5 to the borrowed code.
Revisit Your Code
- Just because you finished your project doesn't mean you should never look
at it again even if nothing is wrong with it. I have a saying that no code is ever perfect, it can
always be improved. If you have the time, go back and cleanup sections where they need to be. You
might be surprised as I am sometimes when you do this at what you will learn. Plus, API's and other
things like protocols or standard compiler classes change over time. Your code might need to be
redone just to stay current. Also, your skill should be improving over time. Your past section of
strctures or functions or classes and methods was done as best you could at that time. As your skills
and technique improves, you may look at that code and know right off that you could shorten it
considerably by applying what you know now. Sometimes this is dramatic, like maybe your code size
shrinks to half or even less of what it was and runs much faster.
Don't Be Too Clever
- This rule is closely tied to Rule 14. Don't mix and match C and C++ unless you have a very very
good reason for doing so. I was recently shown a way to instantiate a C++ class by using malloc.
What in the name of "blank" is this person's reasoning for doing so?!?! The only way you might get
away with that is for a class that has an empty constructor and destructor since malloc doesn't call
the constructor and you would have to make darn sure you free'd the memory afterwards since the
destructor wouldn't be called either. Again I say why? Just use the New directive. That is what
it's for. I don't care and have no desire to find or dream up of little tricks like this. You are
only asking for trouble. Use the language and its constructs and syntax the way it was intended else
you are committing true foolishness and impressing no one except yourself. If the language specification
is ever changed to prevent such things, then your code is broke once you try to build with the newer compiler.
Good Coding Is An Art
- This is my personal attitude towards coding. I think of my
code as more than just functional lines of computer instructions. I think of them as an artist thinks
of a picture. Why? Because I know that others will be looking at in the future. With that thought,
I ask myself, "Will they like what they see?", "Is it pleasing to look at?". I also think of my code in
terms of the user much like a chef thinks of a meal he has to prepare for a patron. Sometimes you
just need to cook up something fast and quick with little preparation (usually scripts). Other times
you need to go through the whole process of deciding your ingredients, gathering them, preparing them,
and then the actual cooking, then presentation of the complete meal. Will your end user like your dish
especially if you have had them wait a long time for it? And in terms of the competition, how will it
compare to other dishes of similar nature? Even if your program does the same things as the others,
does it have that little extra something to distinguish it? This is where you get into the final phase
of a project which is often neglected, and that is to polish and spice up your program. That button or
graphic might be functional, but what if it was smaller, larger, toned down or up in color, or placed
in a more mouse convienient location?
Enjoy Writing Code
- This rule is rather obvious and purely pragmatic. If you don't like, no, really enjoy
spending countless hours figuring stuff out and being frustrated and typing away, then I suggest
strongly that you choose another profession. Adequate coders or "just another developer" are the
ones that code what the company wants from 9 to 5. Great coders go home and code some more for
fun and even on the weekends. They also typically are learning and experimenting with things
that are much more difficult than most business software needs.
Writing Games Is Good
- This rule is more often true whether you want to believe it or not. Name me one piece of
business software that can hold a candle to a state of the art game engine? The vast majority of
business software is sequential, low bandwidth stuff written years ago whereas today's games are
evolving faster than anything else. They have thousands of users in complex worlds with full
3D graphics, 3D sound, and countless objects and creatures with AI all rendered in real time and
playable anywhere over the internet. If you truly want to become a 'coding guru', then try to
write even simple games without looking at anybody else's code or take someone's example and then
enhance it or take it to the next level. That is how you will learn to do wondrous things in code.
Perform A Post Mortem On Projects
- This rule is invaluable for both learning what went wrong in your project and also what went
right. Were designs and architecture decisions made correctly with forethought or were they
sometimes made on the spur of the moment without investigation or analysis? Were any steps
skipped or poorly done? Were any team members given too much to do and others not enough? Were
any average or slow coders put on any crucial parts? Are any parts of the project now robust
enough, generic, and versatile to be reused in future projects? Should any parts be redone for
the next release or patch? Make sure that your findings are accessible to other teams as well
as they could be experiencing the exact same things and would greatly benefit from your results.
Don't Refactor in the 11th Hour
- This rule comes up out of the blue from developers who think of themselves as being able to do
whatever they want whenever they want with impunity. Not only do they cause many problems with
other developers as they change things without checking with the rest of the team or even end users
if UI changes are made, they often introduce unforseen consequences or even outright non-working
code at the last minute. I'm talking about changing things radically in code and classes and
structure or design when the project is in the home stretch shortly before release. Even midway
through the project sometimes may be too late to change things architecturally. Just make a note
of it to revisit it in the post mortem (Rule #30). If a person who essentially torpedoes a project
like this and causes others to rework their stuff at the last minute shortly before release and
delays its completion for another few weeks or even months, then I feel this person should not be
part of the project or any other projects for that company in the future.
Be a Team Player
- This rule is absolutely mandatory with multiple developers on a project. If you have any rogue
developers in a project, then they will slow things up as they want their way, introduce changes
without consulting the rest of the team (Rule #31), and generally cultivate an attitude of unhealthy
competition and suspicion and engage in other negative office behavior like like bad-mouthing,
gossiping, politiking (sucking up to or convincing a manager in private to go your way without the
other team members), and rumor mongering. These types are nothing more than a cancer in your
development team and should be quickly cut out and removed from the project. Non-Team-Players are
easy to spot, they will do all the work of identifying themselves.
Get Final Specifications Before Design
- This rule must, I repeat, MUST be followed no matter how much you want to proceed with design and
coding. If you do not, then you will have a moving target that can and often does, change without
notice and many things will have to be redone at the last moment. This can cause weeks or even
months of delay to release. How can you design or code something for which the user specification
either does not exist or has not yet been fully defined? Those who violate this rule are just
wasting time and money and the developers' morale. A primary benefit to this rule is that it makes
the spotting of any inconsistencies much easier and much less painful to deal with. This happens
when something apparently minor changes that will then cause something else to change that then
causes something else to change and so on and so on. This is the notorious ripple or domino effect.
Last updated 03/04/06