Defensive Programming is the way to go.

Defensive programming is like defensive driving: Anticipate everything that might go wrong. If a function is passed an Id to a database table, do not assume that it is a valid Id, or an integer, or even that it has a value.

What is most important in defensive programming is to communicate clear and precise error messages when things are not as they aught be.

Here are some examples error messages:

Less then ideal error messages:

AttributeError: 'NoneType' object has no attribute 'last_name' 

_mysql_exceptions.OperationalError: (1054, "Unknown column 'Jerry' in 'where clause'")

IndexError: list index out of range

KeyError: 'Jerry'

Better ones:

BookError: Book not found: id = Jerry

AuthorError: Author not found: id = 506

getCustomers command: Expected 3 parameters, only 2 given.

FoomWebsiteError: Unable to read from http://foom.com: HTTP 500

These better error messages are not hard to do if we think about it ahead of time. Here are some examples:

class BookError(Exception): pass

class Book(object):
   def get(self, id):
      results = self.db.query(select * from books where id = ?, id)
      if not results:
         raise Bookerror('Book not found: id = %s' % id
   return results[0]

Another example:

URL = 'foom.com'
class FoomWebsiteError(Exception): pass

class FoomWebsite(object):
   def scrapePage(path, params):
      website = Website(URL)
      page = website.go(path, params)
      if website.error:
         raise WebsiteError('Unable to read from %s: %s'
            % (URL, website.error)
      lines = page.split('<p>')
      name = lines[3]
      return page

 

It is okay to have bugs if they are easy to find and easy to fix. Applying a little defensive programming to everything we write make debugging a breeze, and helps everyone using the system.

Leave a Reply

Your email address will not be published. Required fields are marked *