Defensive Programming

Don't build digital Maginot Lines. Program your defenses in depth.

Defensive Programming

Let's talk about World War II.  

Following World War I, the French worried about a future German invasion.  To ward off such an attack, they undertook a massive engineering effort.  They constructed a series of concrete fortifications, fitted with machine guns and mortars.

The Maginot Line

The Maginot Line provided the French populace with a welcome sense of security. It was a false sense of security.  What's worse, the massive effort redirected resources that could have been put to use elsewhere.  The French military based their entire defensive strategy on a faulty assumption.  They assumed the fortifications would at least slow down the German army long enough to mobilize French forces for a counterattack.

Alas, the Germans did not use the World War I playbook.  They unleashed their blitzkrieg on the unsuspecting French forces.  They went around the Maginot Line, but with much more speed than the French expected.  There was no time to mount a counterattack.  The French had exactly one line of defense.  And it failed.

Defense in depth

The lesson of the Maginot Line is that it highlights the importance of defenses-in-depth.  One should never rely on a single line of defense--a single point of failure.  Rather, one should construct multiple lines of defense.  

Feudal compounds used this approach.  Don't just build a wall.  Surround the wall with a moat.  Install a drawbridge that could be raise when under attack.  Within the outer walls, build a small, heavily fortified keep.  Post sentries far outside the walls to provide early warning of approaching enemies.

Defensive Programming

Let's talk about defensive programming.

Defensive programming is more a state of mind than any single technique. It's choosing to build defenses in depth, rather than a single digital Maginot Line.  It's always assuming the worst of yourself, your fellow programmers, and your users.  Trust me: all three will live down to your expectations.

The best way to illustrate this is to go through a few examples.

Never trust your future self

What happens if someday you decide to add tt_CinnamonAndSugar as a ToastTopping?  (Also, why tt__ToastToppings?)

Enum tt__ToastToppings
End Enum

If Topping = tt_Butter Then
    Debug.Print "Mmm, butter"
    'Wait, anything that's not butter is jelly?  Are we sure about that?
    Debug.Print "Ooh, jelly"
End If

'Logically equivalent, but safer
Select Case Topping
Case tt_Butter
    Debug.Print "Mmm, butter"
Case tt_Jelly
    Debug.Print "Ooh, jelly"
Case Else
    'This is a custom function I wrote as a wrapper around Err.Raise
    Throw "Unexpected Topping: {0}", Topping  
End Select

Take advantage of compile-time checks

Here's yet another reason not to strive for lightweight forms:

'What happens when we rename it "navMainMenu"?
If FormName = "MainMenu" Then

'Logically equivalent, but safer
If FormName = Form_MainMenu.Name Then

Don't hide the warnings

It's like swallowing errors.  Sure, you may think you're just hiding the message that asks if you want to update x rows, but you're also hiding the future error when you try to insert a duplicate record into a unique key.  In general, stay away from any of the DoCmd methods when running querydefs or SQL statements.

'What if there's more than one Smith?  Will we know there's a problem?
DoCmd.SetWarnings False
DoCmd.RunSql "INSERT INTO Customer (LastName) VALUES ('Smith')"
DoCmd.SetWarnings True

'Semantically equivalent, but safer
CurrentDb.Execute "INSERT INTO Customer (LastName) VALUES ('Smith')", dbFailOnError

You get the idea

I could go on.  But it's really not about the individual examples.  It's about surfacing errors earlier in the development process.  It's about having the humility to realize you will never stop making mistakes.  And that you'll never stop discovering new ways to make mistakes.

Take your lessons from the French.  Don't build digital Maginot Lines.  Program your defenses in depth.

The amunitions entrance to Ouvrage Schoenenbourg along the Maginot Line in Alsace. By John C. Watkins V, uploaded to by en:User:Jorge1767 - Own work, Public Domain, Link

All original code samples by Mike Wolfe are licensed under CC BY 4.0