Runtime errors are better than logic errors.
That's all well and good, but it leads to an obvious follow up question. How does one turn a logic error into a runtime error?
Here is a list of techniques you can use to turn a logic error into a runtime error:
- Guard Clauses
- Double Checks
- Avoid Excessive Error Handling
- Throw Errors via Case Else
- Use the "Unset" Enum
Let's explore each strategy in more detail.
Use guard clauses to validate program state at the start of a procedure and exit or throw an error if there is a problem with procedure inputs or external dependencies. When combined with my custom Throw() function and vbWatchdog error handling, guard clauses are a low-friction way to guard against potential logic errors.
For critical calculations, use two different algorithms to arrive at the value and throw an error if the independent calculations produce different values.
Avoid Excessive Error Handling
Not every routine requires an error handler. Sometimes, if you are calling a procedure as part of a larger routine, the best way to "handle" an error is to let it bubble up to the calling routine.
Throw Errors via Case Else
Every Select Case statement should include a Case Else, even if you have covered all the possible code paths. Because, in that situation, you've only covered all of the possible code paths that you know about (or that exist at the time). If you don't think you need the Case Else, add one anyway and raise an error if the code ever reaches that path.
Use the "Unset" Enum
Enums in VBA are little more than glorified Long datatypes. That means that they have a default value of 0, which just happens to match the default value of the first item in an enum. Thus, if a variable based on an enum has a numeric value of 0, there is no reliable way to know whether that value was set explicitly or is simply the implicit default value. If we make logic decisions based on the faulty assumption that every enum has been explicitly set, we introduce the possibility of a logic error. To avoid this potential problem, we can make the first item in every enum an "Unset" value. This allows us to know with certainty whether an enum variable has been explicitly set or only reflects its default value.