5 Ways to Reduce Logic Errors Using Automated Double-Checks

Identify the critical functions in your application. Then, apply one or more of these techniques to ensure that if they break, someone will notice.

5 Ways to Reduce Logic Errors Using Automated Double-Checks

The best way to reduce logic errors is to perform critical calculations two different ways.

By definition, this involves twice as much work as only solving the problem one way.  The benefit, though, is that errors in logic become apparent before they can grow too large.  I learned how devastating uncaught logic errors can be the hard way with my $86,000 mistake.

Let's look at some practical ways that you can incorporate automated double-checks into your applications:

  • Test-driven development
  • Different algorithms
  • Third-party code
  • Multiple programming languages
  • Data validity checks

Types of Double Checks

Test-Driven Development

Also known as TDD, this approach to development forces you to write tests to verify the correctness of your routines before you write the actual routines.  

Entire books have been written on the topic of TDD.  A simple web search can send you down rabbit holes for days.  Before wandering through the woods investigating details, though, it helps to take a bird's-eye view of the whole forest.

Here's the high-level overview:

  1. Write tests and confirm they fail
  2. Write code until all the tests pass

Multiple Functions Using Different Algorithms

With this approach, you create two or more functions that take the same inputs and produce the same outputs.  The difference between the functions lies with the implementation details.  

For example, if your critical logic involves a sorting routine, you could use a bubble sort in one case and a quick sort in the other.  You would then compare the results of the two functions to ensure they always matched.  If the outcomes don't match, you raise a runtime error so that you can deal with it.

Remember, a big part of creating easy-to-maintain code involves finding ways to promote errors from the bottom of the following list to the top:

  1. Syntax errors
  2. Compile errors
  3. Misunderstood requirements (before you start writing code)
  4. Automated test errors (i.e., failing tests)
  5. Runtime errors
  6. Misunderstood requirements (after you've written the code)
  7. Logic errors

Turning a logic error into a runtime error is a big win.

Third-Party Code

It's not always easy to write two different algorithms to solve the same problem.

If a single developer writes both algorithms, they are more likely to make the same kind of mistake in both places than if two different developers create the algorithms.  If you are a solo developer, this puts you into a bind.  You have no choice but to write both algorithms.

Depending on the nature of the problem, you may be able to find an existing solution to the problem on the internet.  

Before blindly copying and pasting that solution into your program, I would challenge you to develop your own solution before reviewing the code you found online.  Once you've done that, you can compare the results of your calculations with the code you found online.

If both pieces of code produce the same outputs, then hey, great minds think alike!  If there are differences, then you can compare the two approaches and see where the problem lies (they might both be wrong!).

Multiple programming languages

Different languages have different ways of doing things.

Python articles and tutorials regularly refer to a Pythonic way of designing code.  This often involves thinking about a problem from a completely different angle than what you might be used to.  

The constraints and differences among programming languages will force you to vary the approach you use to solve a problem.

This is true among the primarily-procedural languages, like VBA, C#, Python, and JavaScript.  But the differences are even more profound when you get into different types of programming languages:

  • Procedural: VBA, C#
  • Functional: F#, Haskell, LISP
  • Declarative: SQL, XAML
  • Concurrent: Go
  • Scripting: PowerShell, AutoHotkey

Data validity checks

Referential integrity alone is not enough to ensure that your data is valid.

Some business logic rules are difficult or impossible to enforce within your database, even with the use of CHECK CONSTRAINTs or triggers in SQL Server.  For those situations, I create a series of SELECT queries that will identify invalid data.

Here are some example descriptions of data validity checks that I use in our real estate tax assessment (CAMA) software, Assessor2k:

  • Properties with approved homestead application but no dwelling.
  • Properties whose current ownership record does not reflect the most recent deed.
  • Properties with approved active homestead application but applicants who are not part of current ownership.
  • Clients with DEC'D in their name but no Date of Death listed.

Final Thoughts

I'm not suggesting that you write every function in your program twice.  

That would be insane.

Instead, apply the 80/20 rule.  Identify the critical functions that would cause the greatest damage if you got them wrong.  Then–and only then–use the techniques in this article to ensure that if your critical functions break, then someone will notice.

Referenced articles

Reduce Logic Errors in Critical Code
Software Developers Can Almost Eliminate Logic Errors With This Powerful Technique
Logic Errors
The logic error is the most dangerous and insidious of all software errors.
The Software Reliability Paradox
The most reliable software holds the potential to cause the greatest harm. Examples abound, from my own $86K mistake to a devastating Russian hack.
The Curse of Reliable Software
How does one avoid the reliability paradox? One option is to intentionally write unreliable, buggy software. There’s a better option.
Some Bugs are Better than Others
Not all bugs are created equal. Avoid the expensive ones by making more of the ones that are easy to find and fix.
What is Referential Integrity?
The concept of referential integrity explained in under 100 words.

External articles

List of programming languages by type - Wikipedia
Assessment - PA Tax Software
The first step in the process is tax assessment. The goal of this step is to assign a fair and equitable value to each parcel in the county relative to the value of every other parcel in the county. Our tax assessment system is designed to meet the unique needs of Pennsylvania counties. This incl…

Image by Dorian Krauss from Pixabay

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