Skip to content

Software Quality

Decision tables

A decision table is a grid: one row per combination of input conditions, one column per condition, one final column for the decision. Writing the table forces enumeration of every case; missing rows become visible at a glance. The implementation becomes a lookup against the table. This is the lowest-cost formal method in the catalog; the technique requires no specialist notation beyond a labeled grid. Hillel Wayne's Decision Tables is a clear, accessible introduction (Wayne 2018)1.

What it catches

  • Missing rows in decision logic. Three boolean conditions produce eight rows; eligibility logic that handles seven of them ships a policy gap.
  • Inconsistent rows. Two rows that match the same inputs but prescribe different decisions are a contradiction; the table surfaces them as duplicates.
  • Dead conditions. A condition that never affects the outcome shows up as a column whose values don't change the result. Often a sign of dead code or over-specification.
  • Stakeholder ambiguity. Product, legal, compliance, ops can read a table where they cannot read source code. Decision tables are often the one formal method non-engineers will engage with.
  • Drift between policy and code. When the table is the source of truth, the implementation tests against the table; any divergence is a code bug, not a policy bug.

On a markdown table or spreadsheet these checks are done by eye at review time; on a table in DMN (Decision Model and Notation) format they can be run automatically: dmn-check statically flags missing and overlapping rules, and an in-source enumeration hands the completeness check to the compiler.

Decision tables catch nothing outside the case space they enumerate.

Tools

The right form depends on who needs to read and edit the table.

  • A markdown table in the repo. The recommended baseline. The PR review surfaces missing rows; the table lives next to the code that implements it.
  • A spreadsheet (Excel, Google Sheets). When stakeholders outside engineering need to read or edit the table. A CSV export carries the rows back to the test suite or into a markdown doc.
  • DMN — an Object Management Group (OMG) standard for decision tables; used by rule engines and business-process-management (BPM) platforms.
  • Drools, OpenL Tablets, and Operaton: open-source rule engines that execute DMN tables directly. Operaton is the Apache-2.0, community-owned fork of Camunda 7; the commercial Camunda 8 platform's DMN engine does the same job. Useful when business analysts own the rules.
  • dmn-check — static analysis for DMN files: detects missing rules (completeness gaps), overlapping or conflicting rules, and type errors, and merges redundant rows. Runs in CI or as a Camunda Modeler plugin.
  • In-source enumerations. A typed sum type that enumerates the rows, plus an exhaustive match / switch, gives the same guarantees the table does, and the type checker enforces them.

When to use, when not

Use:

  • For any feature whose decision combines two to five conditions. The cost is minutes, and a missing combination shows up as a missing row.
  • For regulated decisions where stakeholders outside engineering must read and approve the rules. The table is the contract.
  • When porting eligibility or pricing logic across implementations. The table is the durable artifact; the code is not.
  • As an entry point to formal methods on a team that has none. The notation is a labeled grid, nothing more.

Don't:

  • When the case space is large. Past ~5 binary inputs the table has 32+ rows and is no longer scannable. Use a rule engine or hierarchical decision tables.
  • For continuous conditions. Bucket the range first (e.g., "age < 18", "18–64", "65+") and write the table over the buckets.
  • For control-flow decisions that have state. Use state machines instead.

Evidence

Empirical literature directly comparing teams that adopt decision tables to teams that don't is sparse: the technique is too small and pre-dates the modern empirical-SE era. The case rests on the definitional point that the table is exhaustive by construction.

Exhaustive enumeration of a bounded input space, compressed several ways

These methods all exhaustively enumerate a bounded input space; each compresses the exponential blow-up a different way. Decision tables compress losslessly: a "don't-care" entry folds together combinations that share an outcome, so every case still maps to one rule, and the row carries its own expected decision. Combinatorial and pairwise testing sample: a covering array keeps every t-way interaction and drops the higher-order ones, with the oracle supplied separately. Bounded-exhaustive property testing bounds the size: it enumerates every value up to a depth/size k (SmallCheck), relying on the small-scope hypothesis that faults surface small. Exhaustive coverage runs from MCC (the full 2ⁿ truth table) down to MC/DC's n+1 independence criterion, and audits an existing suite rather than generating one. Type systems reach the same completeness by construction: an exhaustiveness check on a match / switch over a sum type has the compiler verify every variant is handled, with no case written by hand. State-, path-, and schedule-space enumerators such as model checking, symbolic execution, and systematic concurrency testing share the idea over a different space; see the reachability clusters.

Classification

  • Quality dimensions: Functionality: conformance (a regulated rule set is a declared standard, and the table is the artifact stakeholders outside engineering read and approve).
  • Area: Eligibility rules, pricing, access control, regulatory rules, insurance and tax logic, feature-flag decisions, anywhere business logic combines several conditions into one decision.
  • Guarantee: Exhaustive — by construction, no case is missing.

Referenced by

References