Recently I wrote a therapeutic rant for myself, called “10 Ways To Suck At Programming“.  The article got syndicated to some link sharing sites and picked up quite a bit of traffic and comments.  The comments here on my site were, for the most part, nice.  Comments elsewhere were a mixed bag with many people saying the sarcastic nature of the post wasn’t helpful.  While I didn’t see it as sarcastic (after all, it was quite literally telling you how to suck), and even though I’ve written many, many helpful technical articles that did nothing but collect dust, I figured I would take a shot at offsetting my previous rant with real steps programmers can follow to make themselves better.

Obviously, this is not a comprehensive list and most experienced programmers should already be well versed in what’s here, but it’s a decent start for newbies and probably a worthwhile reminder to some of the more experienced.

… and it will be interesting to see if an article intended to be helpful gets as much traffic as a 20 minute rant. ;)

#10 Store settings in a configuration file

Configuration files are a necessity in today’s programming world.  With most applications connecting to databases, e-mail servers, file shares and other outside resources it’s imperative that a good programmer store any information that has a possibility to change outside of the release cycle of the application in a configuration file.  This will allow the application’s settings to be changed without having to recompile (retest, redeploy) the application.

It is important, however, not to overuse configuration files.  Some things belong, some things don’t; and experience is really the best way to know which is which.  You can ask yourself, “Is this something that will likely change in the future?”  If the answer is yes, consider putting it in a configuration file.  The more often you can change the behavior of your application without having to recompile it, the more often you’ll look like a hero.

Examples of good information to store in a configuration file:

  • Database connection strings
  • SMTP server information
  • Any standard to / from e-mail addresses
  • File upload / download / archive paths

#9 Scope and store your variables

Databases are awesome tools and nowadays pretty much any application you’ll be asked to develop will use one of some sort.  However, when thinking of application performance database access and transactions are very expensive operations.  With that in mind a good programmer will access the database as few times as possible in order to fill the needs of the current application request.

One way to facilitate this noble goal is to store any information that your application needs in memory once it has been retrieved from the database.  A “get once, use often” approach can go a long way towards helping with performance (and to a lesser degree code readability).  Some information that is used so often that is even worth storing as a session variable in order to eliminate a request (database, disk, whatever) altogether.  Be careful with those, though, as they are often targeted for hacks and should never be solely depended on for functionality and should never contain any private information.

#8 Never use arcane plugins

Plugins and third-party code can make development go much, much faster.  Often times you can get more complete functionality by using them but there are trade-offs for this convenience.

  1. You have to learn to think like the person who wrote the plugin in order to use it
  2. You usually don’t know how the internals work
  3. They’re almost never meant for the exact situation you’re in

With all that said, the right add-on or plugin can be a life saver and you must, must, must be careful when evaluating whether or not to use one.  Here are some questions to ask to help decide whether a plugin is right for your app:

  • Does it do everything I need exactly as I need it right out of the box?
  • Is it well documented?
  • Does it have an active user and support community?
  • Has it been updated to coincide with major platform releases?
  • Is the documentation in your native language (yes, seriously)?
  • Will it take longer to write the functionality myself than learn to work with this plugin?
  • When I (or someone else) inevitably has to maintain or change this app in the future will it be easy to work with or around this plugin?

If the answer to any of these questions is “no” you should be wary.

#7 Always remove unneeded functionality

This one kind of comes with a caveat:  every programmer should know to use a good and dependable source control tool.  Even if you are the only person working on the code, a good source control tool can (and likely will) prove to be a life saver at some point.  You’ll cruise along not even knowing you need it and then BAM – you implement sweeping code changes that break everything.  If you’re using a source control tool correctly, undoing your changes should be fairly quick and painless.  If not, you may have just lost a client or a job.

With that in mind, try to never, ever leave unneeded functionality in your code base.  If you have written a great piece of functionality that is no longer needed delete it immediately.

When you’re actually making changes that steer you away from existing functionality you understand why you no longer need the functionality and you likely have an idea of what else it touches.  When you come back in six months, after seeing two or three other projects, you will likely have NO idea why that functionality wasn’t previously removed.  You’ll think, “Boy, I didn’t remove this, something somewhere must be using it.”  This problem compounds itself when you’re forced to start writing code around undeleted, unnecessary functionality.  So in the end it’s easier to just remove code and keep your code base clean.

#6 Always consider performance

What makes a good programmer?  The ability to effectively juggle the following points and still deliver timely, effective solutions:

  • Performance – is the code minimal and fast?
  • Scalability – is the code able to be expanded upon easily?
  • Manageability – how quickly can modifications be evaluated, estimated and made?

The preference for which of these to focus on first differs from programmer to programmer and often from project to project.  This is part of what gives each programmer their individual style.  But good programmers always consider all three, no matter the situation.  Readability falls under manageability, abstraction falls under scalability and everything falls under performance.  So no matter what your programming personality and style is, you should be considering performance.

I’m not (necessarily) referring to spending hours pouring over 10 lines of code to make sure it executes as quickly as possible.  I’m talking about taking a solid fundamental approach to gathering and manipulating data that doesn’t do any one piece of functionality more times than absolutely necessary.  #9 above eludes to this, but to go a little further:

  • Get your data once and use it in as many places as possible before disposing of it.
  • Have the absolute minimum amount of functionality inside loops.
  • Never perform accesses (disk, database, service) from within a loop unless absolutely necessary.
  • (In strongly typed languages) Know and use appropriate data types.
  • (In web apps) Perform as few server requests as possible.

If you think of things like this from the beginning of your project you are less likely to have performance issues in the end.  If you don’t agree with me now that it’s worth the initial extra effort you will after you spend 4 weekends straight rewriting poor performing code because you tried to save 10 minutes on the front end.

#5 Never nest major logic / functionality in loops

I mentioned this one under heading #6 above, but it bears repeating.  Loops are often the heart of any application, but they will absolutely kill your app if used improperly.  So you must be wary of anything that falls into a loop.

Loops are something we have to use often, so every good programmer should know how to abstract functionality out of a loop (see #1 below for a simple example).  Besides the performance hits, tracing through functionality that is inside of a loop can be much more difficult because of all of the variables that come into play while looping.  Modern debuggers help tremendously with this task, but better tools shouldn’t excuse poor programming practices.

When you have time to review your code, start by reviewing loops and seeing if anything can be moved outside of them.

#4 Document effectively

There is a school of thought among some programmers that says, “Either you can read code or you can’t, why should I document it for you?”  And while this is true in theory, in practice adding appropriate documentation inside code makes it far, far easier to maintain.

Proper documentation is a skill and overdoing it is almost as big of an annoyance to those trying to maintain code as not doing it all.  Consider the following:

  • DO – denote reason and logic
  • DO NOT – denote functionality or process

What that means is:  tell the future programmer looking at this code why you did something, not necessarily how.  The “how” is the stuff they should usually be able to read on their own (unless you have to do some crazy, non-standard stuff).  More often when looking at the code they need to know “why” you did things a certain way.  Consider the following simple example:

1
2
3
for (int i = 0; i < var.length; i++) {
    doSomething(var[i]);
}

Now let’s consider two commenting options:

1
2
3
4
// iterate over each var
for (int i = 0; i < var.length; i++) { // increment i if it's less than vars.length
    doSomething(var[i]); // do something with the var at position i
} // finish the loop

- or -

1
2
3
for (int i = 0; i < var.length; i++) {
    doSomething(var[i]); // mark inactive vars for deletion
}

Now the first one tells you what is happening, about as pointlessly as a voice-over in a movie saying exactly what the characters on screen are doing. The second one assumes that you know what is happening functionally and instead just tells you what’s going on logically, which is far more valuable information when you’re in “put out the fire of the forest variety” mode.  In the first case, the future programmer would need to look up doSomething(var) and figure out what it was accomplishing. In the second version that information is at hand and valuable.

Which would you prefer if you got a call from an executive at 4:45PM on Friday that forced you to review this code?

#3 Use effective and logical variable names

There are a LOT of thoughts on this one and almost every programmer has a slightly different way of doing it.  So I’ll try to be ambiguous so we don’t start a war over it.

It is important to consider your variable names carefully.  Sometimes having the data type as part of the name is appropriate (intId) and sometimes that sort of thing can be inferred (id).  Either way, the name of the variable should hint towards the usage of the variable (note that “id” was in both).  Names like (vulSpok) and (humKirk) are not useful.

Now possibly just as important as choosing your style of naming variables carefully is being consistent.  As a programmer your code will have a certain “style” that others who inherit your code will have to learn in order to quickly and easily maintain your code.  That “style” may not be the same as theirs, but as long as it is consistent (and logical) you’ve done what you can do.

#2 Catch errors, or don’t

Let me start by saying that I know, academically, all errors should be caught and handled gracefully.  Let me also say that realistically, that almost never happens when deadlines are looming.

Hopefully the days of “Dr. Watson encountered an error” are behind us for good.  Most modern platforms will let applications die with a pretty decent error message.  So while it may not be ideal, letting errors fall through to the default error handling is better than manually mishandling the errors.  On internal or limited usage applications this can actually provide a pretty good idea of what the actual error is and where to start looking to fix it.

Now in an ideal world, programmers would have time to code a catch for anything that went wrong and do something cool, super-ninja style.  So if you have time and budget you should catch all possible errors and handle them.  If not, don’t catch them at all.

Just never, ever catch errors and do nothing.

#1 Never duplicate functionality

Reusable code is the holy grail of good programmers.  A good programmer should always be on the lookout for a way to write functionality once and then use it all over the place.  The benefits to this are too numerous to count.

So what is reusable code?

Let’s say, using our example above that you need to loop through your vars and doSomething() with them.  You could do it this way:

1
2
3
4
5
6
7
8
for (int i = 0; i < var.length; i++) {
    // mark inactive vars for deletion
    if (!var[i].isActive) {
        var[i].readyToDelete = true;
    } else {
        var[i].readyToDelete = false;
    }
}

- or -

1
2
3
4
5
6
7
8
9
10
11
private void doSomething(var) {
    if (!var.isActive) {
        var.readyToDelete = true;
    } else {
        var.readyToDelete = false;
    }
}
 
for (int i = 0; i < var.length; i++) {
    doSomething(var[i]); // mark inactive vars for deletion
}

It ends up being 3 extra lines of code in this example that will save you 4 lines of code each time you use it somewhere else.  So the first time you re-use the code in this rudimentary example you’ve saved yourself 75% effort across the board (coding, debugging, refactoring, etc).  Pretty nifty, huh?

Additionally, if you ever need to change the evaluation logic to, say, make sure that there weren’t any records that may be orphaned by deletion, you could change that logic in a single place and it would work everywhere throughout your code.

If you have any major items to add, feel free to do so in the comments.  If I get enough good ones perhaps I’ll update this article to include them.