This article is written with developers in mind, but it applies equally to other team members, such as testers, business analysts, or product owners.

Also, the post isn’t a quick skim, so set aside a little extra time for reading. It’ll be worth it. โ˜•๏ธ๐Ÿช


Truth tables are frequently seen in academic mathematics and logic, and they represent the complete set of permutations for input variables along with the corresponding results. ๐Ÿ“

When applied to real-world problems in software development though, they can be an invaluable tool for tackling difficult requirements and test scenarios. ๐Ÿ†

What are truth tables?

This is a truth table as seen in academic circles:

P Q ย ย ย ย ย ย  P ^ Q
TRUE TRUE TRUE (Scenario 1)
FALSE TRUE FALSE (Scenario 2)
TRUE FALSE FALSE (Scenario 3)
FALSE FALSE FALSE (Scenario 4)

^ represents the logical AND, often seen as && in C-based languages.

How to read this table

The header row is the header and labels the columns.

Each row underneath the header is a single scenario.

On the left-hand side, P and Q are input variables.

On the right-hand side, P ^ Q is the result, or the output.

ie. “Given that the value of P is TRUE and the value of Q is TRUE, then the result of P AND Q is TRUE.” (Scenario 1)

The important thing is that the table represents the complete set of permutations of P and Q.

Making a case for them

When and why would you want to apply one of these to your job?

You start to feel overwhelmed with requirements as they currently are

Putting things into this level of detail can add clarity both for you and everybody around you. It can also help reveal or uncover when there are hidden assumptions about how the system should work. ๐Ÿ•ต๏ธโ€โ™€๏ธ

It might feel daunting or even counter-intuitive to undertake the task of creating one of these tables for your requirements; but creating a truth table organizes the mental jumble into something tangible that can be worked on piece by piece. ๐Ÿงถ

You want to clarify scenarios so that everybody’s in agreement

When working with a table like this, the spoken agreement is that if the system works exactly as the scenarios in the table specify, then everybody is happy.

When hashing out how a system it supposed to work, it’s not unusual for a group of people to get caught up on a couple things. Conversations go in circles. People get lost and confused. Time is wasted. Everybody loses. ๐Ÿ˜ญ

Using a truth table can highlight what those things are while also providing a sense of cohesion around everything the team already agrees on. ๐Ÿ˜Ž

There might be hidden edge cases

You have that nagging feeling that you’re missing something or that things feel overly simplistic. ๐Ÿ˜ฐ

Functionality needs to be solid

Sometimes pieces of software need to work with little-to-no margin for error. Truth tables are great for helping ensure that what you’re building is solid and meets expectations. ๐Ÿ’ฏ

So, now…

Constructing a table, a complete example

If you’re already comfortable with the idea of creating these tables, it might be worth reading this section anyway. I make a couple mistakes and, in doing so, I demonstrate how building a table can drive and clarify requirements making for a more accurate system. Otherwise, just skip on down to making a case in the real world. ๐Ÿ™‚

Business rules

I recently got to work with a library system. A scenario that came up for modifying holds on items has this set of business rules:

  • Certain items must be approved before being checked out.
  • Only certain people should be allowed to do the approval.
  • The UI should only show whether it needs an approval if the item is in-hand (ie, it’s not checked out or at a different branch).
  • If the item is currently “In Use” (from its “Status”), then we cannot edit the approval status. (Think about “In Use” for materials which need to stay in the library.)

1. Define your variables

Kind of like doing algebraic word problems in school, we should figure out our variables, both the inputs and the outputs. I’ve conveniently ordered them so that the inputs come first.

In this case:

  • (item) requires_approval (INPUT)
  • can_user_approve (INPUT)
  • item_status (INPUT)
  • should_ui_show (OUTPUT)

Spoiler: These variables aren’t enough. We’ll see that come out later, though.

2. What are ALL the possible values for each of these variables?

  • requires_approval (INPUT) : TRUE, FALSE
  • can_user_approve (INPUT) : TRUE, FALSE
  • item_status (INPUT) : NOT_AVAILABLE, AVAILABLE, IN_USE
  • should_ui_show (OUTPUT) : TRUE, FALSE

Since this is a blog, I’ve kept things simple and stuck to boolean values and a limited number of statuses. You may find yourself needing to be more creative, such as using number ranges. I’ve also ordered the statuses to most closely follow a hold’s lifecycle. It’s small, but it helps reduce mental load.

3. Create your table of inputs One. Column. At. A. Time.

For each column, create a row for each input permutation. Then duplicate the entire table so far for each of the permutations for your next column. Rinse, repeat, as below:

a. First column: requires_approval

requires_approval
TRUE
FALSE

b. Second column: can_user_approve

Copy and paste.

requires_approval can_user_approve
TRUE
FALSE
TRUE
FALSE

Add the second column’s possible inputs to get the complete matrix of possibilities.

requires_approval can_user_approve
TRUE TRUE
FALSE TRUE
TRUE FALSE
FALSE FALSE

c. Third column: item_status. Which is also the last of our Inputs.

I copy-pasted the table three times, once for each item_status option, then filled in the statuses.

requires_approval can_user_approve item_status
TRUE TRUE NOT_AVAILABLE
FALSE TRUE NOT_AVAILABLE
TRUE FALSE NOT_AVAILABLE
FALSE FALSE NOT_AVAILABLE
TRUE TRUE AVAILABLE
FALSE TRUE AVAILABLE
TRUE FALSE AVAILABLE
FALSE FALSE AVAILABLE
TRUE TRUE IN_USE
FALSE TRUE IN_USE
TRUE FALSE IN_USE
FALSE FALSE IN_USE

Notice how every row is unique and we’re not missing any permutations. That’s critical - don’t skip permutations! If you want to do math, the total number of rows should be equal to the product of the number of options for each input. Aka. Total_Rows = (A_NumberOfOptions) * (B_NumberOfOptions) * (C_NumberOfOptions) (etc.) In this case: Total_Rows = 2 * 2 * 3 = 12. Checks out! โœ…

4. Fill in your output column(s)

This is where you figure out the behavior based on the business rules. I frequently like to add a “comments” or “remarks” column, but it’s not required. Additionally, I like to have some kind of visual cue between inputs and outputs. Because this is markdown, I’m going to add a small empty column. In a spreadsheet program, I’d make the vertical cell border have a heavy outline. Maybe I’d still add a small empty column with a different background color.

requires_approval can_user_approve item_status ย ย ย ย ย ย  should_ui_show remarks
TRUE TRUE NOT_AVAILABLE FALSE because not AVAILABLE
FALSE TRUE NOT_AVAILABLE FALSE because not AVAILABLE
TRUE FALSE NOT_AVAILABLE FALSE because not AVAILABLE
FALSE FALSE NOT_AVAILABLE FALSE because not AVAILABLE
TRUE TRUE AVAILABLE TRUE
FALSE TRUE AVAILABLE ??? the rules aren’t clear
TRUE FALSE AVAILABLE ??? should it show but not be editable???
FALSE FALSE AVAILABLE ??? the rules aren’t clear
TRUE TRUE IN_USE FALSE? because not IN_USE, can’t edit
FALSE TRUE IN_USE FALSE? because not IN_USE, can’t edit
TRUE FALSE IN_USE FALSE? because not IN_USE, can’t edit
FALSE FALSE IN_USE FALSE? because not IN_USE, can’t edit

Uh oh.

Do you see what happened? By filling out this out, we uncovered a couple scenarios that weren’t clear:

  • the item needs approval but the user doesn’t have permissions. What should happen? should_ui_show isn’t detailed enough.
  • the item is in hand, but doesn’t need approval… then what?

A clearer set of business rules

In this case, after checking back in with the business, they said that if there’s no approval required, they don’t want it to show at all.

Additionally, if an approval is required AND the item is available, they always want that information displayed.

For completion, here is the updated set of rules:

  • Certain items must be approved before being checked out. (no change, it’s really a premise)
  • Only certain people should be allowed to do the approval. The field should only be editable if somebody is allowed to edit the approval. Otherwise, the UI should show whether or not it’s been approved.
  • The UI should only show whether it needs an approval the approval field if the item is in-hand (ie, it’s not checked out or at a different branch) AND the item requires approval.
  • If the item is currently “In Use” (from its “Status”), then we cannot edit the approval status. (Think about “In Use” for materials which need to stay in the library.)

The updated table

I’ve fast-forwarded building the updated table based on the new rules.

Most notably, I changed the output variables to reflect the fact that visibility and editability are distinct.

requires_approval can_user_approve item_status ย ย ย ย ย ย  should_field_show should_field_be_editable remarks
TRUE TRUE NOT_AVAILABLE FALSE - item not in hand
FALSE TRUE NOT_AVAILABLE FALSE - item not in hand
TRUE FALSE NOT_AVAILABLE FALSE - item not in hand
FALSE FALSE NOT_AVAILABLE FALSE - item not in hand
TRUE TRUE AVAILABLE TRUE TRUE
FALSE TRUE AVAILABLE FALSE - approval not required
TRUE FALSE AVAILABLE TRUE FALSE item requires approval
FALSE FALSE AVAILABLE FALSE - approval not required
TRUE TRUE IN_USE TRUE FALSE
FALSE TRUE IN_USE FALSE - approval not required, no need to show
TRUE FALSE IN_USE TRUE FALSE
FALSE FALSE IN_USE FALSE - approval not required, no need to show

- denotes that the value is irrelevant

I also bolded things that I think somebody reading this should pay attention to as noteworthy or exceptional scenarios.

And it’s done! ๐Ÿ™Œ

For formatting, I generally recommend against, say, coloring every “TRUE” a certain color, or coloring by status, for example. Such coloring in bulk doesn’t necessarily aid comprehension. I do think, though, that judicious use of color can be invaluable for calling out edge-cases. However, because these tables are read row-by-row, it’s often more valuable to color key rows or fields. For example, using color to highlight unknown or tricky scenarios can draw attention to where it’s most needed.

5. (Optional) Trim your table

Looking at the table, there are some obvious things which could be distilled:

  • When an approval isn’t required, the field should never show.
requires_approval can_user_approve item_status ย ย ย ย ย ย  should_field_show should_field_be_editable remarks
FALSE *** *** FALSE - approval not required
TRUE TRUE NOT_AVAILABLE FALSE - not AVAILABLE
TRUE FALSE NOT_AVAILABLE FALSE - not AVAILABLE
TRUE TRUE AVAILABLE TRUE TRUE
TRUE FALSE AVAILABLE TRUE FALSE item requires approval
TRUE TRUE IN_USE TRUE FALSE
TRUE FALSE IN_USE TRUE FALSE
  • If the user can not approve, the field should never be editable.
requires_approval can_user_approve item_status ย ย ย ย ย ย  should_field_show should_field_be_editable remarks
FALSE *** *** FALSE - approval not required
*** FALSE *** *** FALSE user does not have permissions
TRUE TRUE NOT_AVAILABLE FALSE - not AVAILABLE
TRUE TRUE AVAILABLE TRUE TRUE
TRUE TRUE IN_USE TRUE FALSE

And that’s it! Now we can go build our code and tests with confidence. ๐Ÿ™‚

I actually hesitate to make the second distillation. I feel very confident that if we were to turn the first table into test cases, we wouldn’t be able to accidentally introduce any bugs. But I’m slightly less confident in the second scenario. Logically it works out, so I’ll leave it as an example; but I don’t think it necessarily makes the table easier to read (and hence more valuable) in the same way that the first trim did.

Handling many scenarios

You may have noticed that as we add variables and permutations, these tables can become large quickly. While it may be daunting as scope grows, it’s worth going through the process.

Applying tables to a real-world scenario, and why

When demonstrating how to construct a table, I chose an example that was relatively basic; and maybe you impatiently skimmed waiting for me to realize that of course visibility and editability needed to be distinct.

Below is a second scenario describing how, in the face of very complex rules, a truth table like this served as the basis for both establishing business rules and the subsequent coding.

In particular, I really want to demonstrate how these tables can drive and reveal business rules and serve as the baseline for development. And it’s a bonus that the scenarios translate directly into test cases.

Establishing rules

So… let’s talk about two-way data synchronization. Messy, right? The thought of it makes me cringe and look for other options, but we don’t always have that luxury. And sometimes we have synchronize between systems with dramatically different data models.

In the particular scenario I’m thinking of, it was a side-by-side migration from a mainframe into a commercial-off-the-shelf (COTS) system for judicial person records. In the mainframe, each of an individual’s Aliases were Person records linked together, and in the COTS system, each Alias was just a string in a list of names associated to the person. In both systems, Cases were associated with a Person. However, in the mainframe, Person-Aliases owned Cases and in the COTS system, Cases didn’t even reference an Alias. Addresses were similarly distributed and un-aligned.

In summation, we needed two-way synchronization between data models that were drastically different. Business did their best to create some rules, but the rules focused on field mapping and less on scenarios. The direction was basically “do C(R)UDy things that happen in one system in the other system.”

It wasn’t specific enough to create code that wasn’t riddled with bugs. What about when somebody was renamed? What about when an Person-Alias in the mainframe had a change of address? (There was NO link between aliases and addresses in the COTS.)

I don’t want to bore either of us by recreating the past, but here are some scenarios to get an idea of scope:

Mainframe person actions: Created, other modification1, name updated, record “deleted”, alias link created, alias link removed

COTS person actions: Created, other modification1, primary name updated, alias added, alias deleted2

Target System: Person exists, person doesn’t exist, address is current/not-current, name exists/doesn’t, etc.

1 other modifications might include changes in their drivers license number, physical characteristics, or address. Addresses were a whole different mess.

2 The COTS system didn’t have the concept of renaming an alias. It only allowed Add and Delete.

Fast-forward a little to having a fairly large table with all the input scenarios laid out.

Using the table of scenarios, we were able to work directly with business to fill in the expected outcome for each scenario.

It wasn’t fast. In an initial meeting, we were able to fill in maybe three-quarters of the table.

In a series of follow-ups, after they had time to think and confer with other stakeholders and the COTS vendor, we almost finished it. However, there was one scenario that dragged so long that us developers just started drawing pictures of roller-coasters going off a cliff (that scenario) and pointed to it whenever somebody asked about status. (I think it had to do with deleting an alias. ๐Ÿ™„ )

The manyfold benefits of this tool

I really, really want to point out some beneficial side-effects that came from creating a giant table and sharing it:

  • ๐Ÿชจ We were confident that if all of the scenarios were covered, our system would be solid.
  • ๐ŸฆŸ There were no developer assumptions – either something the developer actively decided, or an outcome that was implied in conditional logic but never actively considered.
  • ๐Ÿ‘ We had business buy-in on exactly what we were building and how it would behave.
  • ๐Ÿงช We had a list of test scenarios that, if they passed, would guarantee that the logic was correct.
  • ๐Ÿงฑ We were able to clearly point out where we were blocked on decisions.
  • โ›ต๏ธ By forcing the business (and ourselves) to go through this process, we were able to notice similarities in conditions and outcomes which surfaced business rules.
    • For example, some of the rules we came up with were “If an Alias is added in the COTS and doesn’t exist, make a new Person record in the mainframe and link it to the primary Person record.”, “If an Alias is renamed in the mainframe, just drop and re-create all the Aliases in the COTS.”, “Overwrite an Address in the mainframe with whatever the COTS system says is current”, etc.
  • ๐Ÿก By getting to clearer business rules, we were able to code the system in an efficient and maintainable fashion. (The initial coding (ahem, a prior dev) for this was a very long list of if-else statements that was impossible to grok, much less maintain or debug. By having clarity, it ended up being a small handful of classes with almost completely set-based logic. And I ended up with a lot of extra time on my hands for doing other important things, like assembling jigsaw puzzles in the lunchroom ๐Ÿงฉ, reading the stack exchange hot network questions ๐Ÿ”ฅ, and building a dashboard to help with synchronization debugging ๐Ÿž.)

Other thoughts and guidelines

To conclude, here are some final tips for getting value:

  • ๐Ÿ“ˆ Always start with the intention of creating the complete set of scenarios in the table. As you fill it out, you’ll likely arrive at some simple rules that let you distill it down. Nonetheless: Always default to verbosity over brevity.
  • ๐Ÿง  Using a spreadsheet program is far easier to work with than a word document or markdown file.
  • ๐ŸŽจ Use color coding where it adds clarity. Also, it’s better to reserve color for indicating exceptions or grouping scenarios rather than, for example, coloring true = green, false = red.
  • ๐Ÿ‘ฉโ€๐Ÿ’ผ Keep things meaningful for business. (TRUE/FALSE or YES/NO instead of 1/0)
  • ๐Ÿ‘€ Where possible, choose words that scan easily. (YES/NO instead of Y/N – the different number of characters means our brains only need to notice how much space is used.)
  • โ“ A “Comments/Remarks” column can be very useful to help document why a particular conclusion was reached or why there’s still uncertainty.
  • โœ๏ธ Don’t hesitate to spell out some guiding business rules above the table, especially as they’re uncovered.
  • ๐Ÿ“ข Make it public.
  • ๐Ÿฆป Ask for input.
  • ๐Ÿฅณ Celebrate when the hard work pays off.

Join the conversation about this post on our N.E.A.T community

Not a N.E.A.T. community member yet? More info.

Eve Ragins

Person An icon of a human figure Status
Sleeper Agent
Hash An icon of a hash sign Code Name
Agent 00138
Location An icon of a map marker Location
Semi-Nomadic; Olympia, WA