Defensive Programming 101 August 30, 2007
Defensive Programming 101
For any given programmer the following statement should
always be treated as truth:
My code sucks, but
your
code sucks more.
Good version control habits and test coverage will get you out of most jams
related to your own code but we rarely write apps that are comprised of just
our code. There are almost always libraries from other people code that you’ll
include to save yourself from having to re-invent the wheel. Obviously you
don’t want to start writing unit tests for code from other projects (you’d
never finish) but there are some basic steps you can take to minimize your
chances of failure.
Untrustable code
The fact is that no matter how good your code is you just can’t trust anything
you didn’t write. Furthermore, you can’t trust what people will
do with their code.
You can’t trust other people’s code because it rarely has good test coverage
or documentation so you can’t be sure if it is broken, or if it works the way
you think it does. And unless it’s a huge open source project you can
generally assume that not many people have looked at it either.
You can’t trust what they will do with their code because it’s
their code not
your code. Whoever “they” are they’ve
got their own ideas about where it’s going next and how to get it there, and
they may not jive with how you want to use it.
Your project must never rely on the successful build of another project,
because it may depend on the successful build of yet another project, or even
worse, end up in a sea of circular dependencies.
The results of another project’s “current” build should similarly not be
trusted. It’s probably not tested well, the implementation could change
completely tomorrow, and it may just be buggy. Whenever possible only use
release builds. If you can’t use a release build at least try and use one that
other people have had success with for a little while.
Untrustable people and environments
Even if you take all the steps possible to defend against other people’s bad
code there’s still the fact that humans are incredibly fallible.
You can not assume that the correct libraries will be where they’re “supposed
to be” or that the version that is there is 100% compatible with the version
you coded against. Even if it is you can’t assume that someone won’t go and
“upgrade” it to a version that isn’t compatible. Always bring your own
libraries and keep them local to your app. Disk space is cheap and unless
you’re on an embedded device it’s better to bring along copies of the
libraries you coded against. It doesn’t matter if the ones you bring along are
completely outdated relative to the latest version; what’s important is that
you can guarantee that the version you coded against works.
Your project must never rely on another
project or its libraries. Period. You can not assume that the other project will
be on every box your project is installed on or that the version on those boxes
be in a state that is either working or compatible with yours. Take whatever you
need from their project and copy it into yours. If you need libraries that it
generates or contains, copy them. If you
must use source code copy it but be very
careful. You don’t want to end up forking it and having to maintain your own
version. Instead, copy it in but do whatever it takes to make it blazingly
obvious that the code should not be
edited unless absolutely necessary. When you do copy over make sure to copy the
smallest amount possible. If you can, build it into a separate library file that
you can update when the need arises.
You also can’t assume that someone isn’t going to screw up a config file, and
that includes you. Just like libraries, bring your own. Maybe you’re working
on a webapp which has some global configuration file that’s shared by other
webapps on the same box. Don’t trust it. Yes use it so that you’ll be in sync
with the other apps but since you can’t guarantee that some sysadmin won’t
accidentally delete or change some piece of it that’s crucial to your app
bring along a fallback with some bare bones settings that should work under
any circumstance you can prepare for. This is exactly why your operating
system has a “safe mode”. The operating system developers know you can’t trust
the users not to accidentally screw something up or install an app that screws
something up. Have a fallback.
If your app is configured differently for different deployments (maybe you’ve
got a dev box, a QA box, and a production box, each with their own different
database settings) then have a separate config file for each deployment. Don’t
have a single config file with different sections that get commented or
uncommented based on which deployment it is. You simply can’t guarantee that
you, or your coworkers, won’t forget to comment or uncomment the right bits
when deploying.
Leave a Reply