I wrote an article recently about the dangers of Coding Before Designing.  In that article, I wrote about the pitfalls of writing code before properly designing the overall project itself.

In this article, I'm going to focus on how to avoid that same problem at a much lower level: writing routines.  This technique will force you to design your solution before you start programming it.

In Steve McConnell's classic software construction tome, Code Complete, he dedicates Chapter 9 to this technique.  The entire book is outstanding.  It's the #1 book on my reading list for software developers.  Steve's advice is all practical, but it's also backed up extensively by research.  I highly encourage you to buy a copy of the book today if you don't already have one.

A brief overview of the process

Here are the basic steps:

  1. Write out the routine's purpose in plain English as a code comment
  2. Write a pseudocode comment for each step required to implement the routine
  3. Write the routine declaration below the comment stating the routine's purpose
  4. Write the implementing code below each pseudocode comment
  5. If the implementing code is too long, factor it into a separate routine

A simple example

In my personal code library, I have a standard module named Compression.  It contains a variety of functions and methods to compress and decompress files for both file system and database storage (via binary large object [BLOB] fields).

I wanted to add a function that would extract and decompress the contents of a BLOB field into a temporary file, then return the full path to the temporary file.

Step 1. Write the routine's purpose

'---------------------------------------------------------------------------------------
' Purpose   : Extracts a .7z archive from a db BLOB field and decompresses its contents
' Notes     - Returns the full path to the extracted file in the user's temp folder.
'           - Retrieves a file that was stored using CompressAndInsertBlob().
'---------------------------------------------------------------------------------------

Step 2. Write pseudocode for each step

'---------------------------------------------------------------------------------------
' Purpose   : Extracts a .7z archive from a db BLOB field and decompresses its contents
' Notes     - Returns the full path to the extracted file in the user's temp folder.
'           - Retrieves a file that was stored using CompressAndInsertBlob().
'---------------------------------------------------------------------------------------

'Extract the 7-zip archive from the db field
    
'Decompress the single file's contents from the archive
    
'Return the path to the fully extracted file

Step 3. Write the routine declaration

'---------------------------------------------------------------------------------------
' Purpose   : Extracts a .7z archive from a db BLOB field and decompresses its contents
' Notes     - Returns the full path to the extracted file in the user's temp folder.
'           - Retrieves a file that was stored using CompressAndInsertBlob().
'---------------------------------------------------------------------------------------
Public Function ExtractAndDecompressBlob(Fld As Object) As String
    'Extract the 7-zip archive from the db field
    
    'Decompress the single file's contents from the archive
    
    'Return the path to the fully extracted file
    
End Function

Step 4. Write the implementing code

NOTE: I use the fp prefix to denote that a variable contains a "full filepath."

'---------------------------------------------------------------------------------------
' Purpose   : Extracts a .7z archive from a db BLOB field and decompresses its contents
' Notes     - Returns the full path to the extracted file in the user's temp folder.
'           - Retrieves a file that was stored using CompressAndInsertBlob().
'---------------------------------------------------------------------------------------
Public Function ExtractAndDecompressBlob(Fld As Object) As String
    'Extract the 7-zip archive from the db field
    Dim fpExtractedArchive As String
    fpExtractedArchive = BlobExtract(Fld, ".7z")
    
    'Decompress the single file's contents from the archive
    Dim fpTempWildcard As String
    fpTempWildcard = TempFileName(Ext:="*")
    Dim fpOriginalFile As String
    fpOriginalFile = Decompress(fpExtractedArchive, fpTempWildcard)
    
    'Return the path to the fully extracted file
    ExtractAndDecompressBlob = fpOriginalFile
End Function

Step 5. Factor long code blocks into separate routines

In this example, there's nothing to do in this step because the long code blocks already existed as separate routines: BlobExtract(), TempFileName(), and Decompress().  There's no real hard and fast rule for what constitutes a "too long code block," but my own rule of thumb is that the code for a single routine should generally fit on screen without needing to scroll the IDE window.

Final thoughts

This is a very powerful way to build routines in code.  Pseudocode is easier to write than code.  More importantly, though, pseudocode is easier to throw away than code.  I don't mean this technically, of course, but rather emotionally.  When you take the time to write, debug, and test code, you form an emotional bond with that code.  This dynamic is greatly reduced, if not eliminated, when writing pseudocode.

The other benefit to this approach is that your code is well commented.  You do end up with some comments that are arguably unnecessary, such as 'Return the path to the fully extracted file.  That's not a comment I would advise adding after writing code, because it describes what the code does and not why.  However, in the context of PPP, I leave these sorts of comments in place.  With the syntax highlighting of the VBIDE, it makes it very easy to read each green line and know exactly what the routine is supposed to be doing.

Image by StartupStockPhotos from Pixabay