Pitfalls of Defensive Programming

planeReferencing and de-referencing objects in an Object Oriented Environment can be a challenge. These are real life examples; the names of the objects have been changed to preserve the identity of the victims. Please fasten your seat belt.

When I take an airplane, I cannot help but think of all the poor programming practices I have witnessed –some committed by myself– over the years. I often wonder if the on-board computers have been programmed by my earlier engineering peers.

Architectural Concerns

The present article is about poor coding practices resulting from poor risk analysis, poor critical thinking, all culminating in poor implementation. You cannot build resilient software if you foundations are weak, whether from the tools you use or how you use them. Let’s approach robust coding with my favorite quote from an engineer with whom I do not share the view. I could see the benefits and even possibly some logic behind it, but this is why I hate to fly:

If a bug cannot occur, it is not a bug.
W.W.(ref.)

corruptedDataCrashI guess that I am not inclined to take the risk; a condition could have been overlooked, or simply created at a later maintenance stage. New situations will arise as the software evolves, and code that was once safe may be misunderstood and misused.

From the same engineer, I’ve also heard «Well. Of course it will crash if you pass it corrupted data…» when talking about one of the drawing API.


Crash on landingGear.deploy()

Overview

overview


1. A short Object Oriented Programming Refresher

1.1 Object Inheritance

Say you have three classes. An airplane, a commercial airliner and a private jet. We can all agree that both the jet and the airliner are kinds of airplanes.
object-inheritance

This is the basis of object-oriented development. You model abstract objects after entities in the real world.

1.2. Object Properties

Say that an airplane has landing gear, I reckon all airplanes have landing gear. Assuming we are not discussing here the very specific case of hydroplanes, the gear (at least a generic one) should probably belong to the airplane object.
object-properties

1.3. Inherited Properties

So in the real world, having landing gear is not particularly specific to the private jet or the commercial airliner. Being fitted with landing gear, retractable or not, is general to all airplanes.

inherited-properties

1.4. Class Members

The landing gear, in itself, can be a pretty complex device.

  1. Member variables

    It has members that remember states, such as stowed away vs. ready for landing.
    Example: isReady

  2. Member methods

    It also has functions, which generally, but not always, will change its state. Such functions can be deploy vs. stow.

    Example: deploy()


class-members

This is where encapsulating functionality into an object starts to make a lot of sense. You need not to know the specifics of how a mechanism (or an algorithm) is implemented. You only need to know how to invoke it: in this example, it’s Deploy().

1.5. Delegate Behavior

In this simplified model, it matters not which kind of airplane you fly. All you need to do is to flip a switch to initiate the landing procedure, and the airplane object just “knows” what to do.
delegate

1.6. Larger Picture

largerPicture


2. A Programming Error Crash Course: Dont’ fly with those!

I have gathered below a few errors I have seen in the past. Do not try this at home!

2.1. public static

public-static

 BAD:
// Whenever needed
if( nil == Airplane.staticLandingGear) {
    Airplane.staticLandingGear = create an instance of LandingGear
}

// ... followed somewhere upon destruction of the object:

// Upon destruction of the creator
if( nil != Airplane.staticLandingGear) {
    delete Airplane.staticLandingGear
    Airplane.staticLandingGear = nil
}

While this may look proper at first glance, and possibly even work depending on the situation, I have seen this code create havoc when placed in the “Private Jet” or “Commercial Airliner” sub-class. Create more than one plane and you have a disaster.

BETTER:
// Whenever needed
aLandingGear = Airplane.getLandingGear()

// ...and the LandingGear instance in turn created and maintained by a singleton

getLandingGear() {
    // Ensures only one LandingGear instance exists
    if( nil == staticLandingGear) {
        staticLandingGear = create a unique instance of LandingGear
    }
    return staticLandingGear
}
  1. Problem: More than one object may destroy the public static variable
  2. Suggestion: Use a singleton and a private static.

2.2. silent error

silent-error

BAD:
if( nil != aLandingGear) {
    aLandingGear.deploy()
}

Defensive programming has it’s price. In this case, the software will not crash if the LandingGear object does not exist. Good.
Conversely, the plane will crash because no landing gear has been deployed. Bad.
This situation could have been detected early on if the software had not failed silently during the development phase, before it was deployed.

BETTER:
assert( aLandingGear); // Will alert QA that something went terribly wrong
if( nil != aLandingGear) {
    aLandingGear.deploy()
} else {
    // Something is terribly wrong and we should not be there
   engageRecoveryProcedure
}
  1. Problem:Failure goes undetected and unreported during development
  2. Suggestion:Use assert() and error_log() to report unexpected conditions


2.3. uninitialized object

 

 uninitialized-object

For this example, assume that the landing gear needs to be connected to an airplane.

BAD:
if( ! aLandingGear) {
    aLandingGear = new LandingGear()
}
// The app will not crash, because aLandingGear exists
aLandingGear->deploy() // Will do nothing. Plane will crash!

If an object MUST be initialized, one possibility is to make the default constructor private, forcing the engineer to use a designated initializer.

BETTER:
if( ! aLandingGear) {
    aLandingGear = new LandingGear( anAirplane)
}
  1. Problem:Failure to initialize an object
  2. Suggestion:Make constructor private to force the use of proper initializer, otherwise source code will not compile in the first place.

UML References

  • https://yuml.me/diagram/scruffy;scale:200/class/[Airplane].
  • Format described at yuml.me

References

  1. W.W. an ex-engineer from J.N. with a 14:1 lack of productivity ratio

Xavier Schott

0010 0000 years of algorithm crafting, software architecture, and bringing visionary mobile apps to market.