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. A decision table is a lightweight formal specification: it has one consistency rule, needs no notation beyond a labeled grid, and anybody can learn to read one (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.
- Drift between policy and code. When the table is the source of truth, tests check the implementation against the table; any divergence is a code bug, not a policy bug.
Reviewers run these checks by eye on a markdown table or spreadsheet. On a table in DMN (Decision Model and Notation) format, dmn-check flags conflicting rules automatically.
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 decision tables. Drools and Operaton run DMN files directly; OpenL Tablets runs tables written in Excel. 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 duplicate, conflicting and shadowed rules and type errors in rule expressions. 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.
- 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; a rule engine or hierarchical decision tables handle that size.
- For continuous conditions. A table over buckets of the range (e.g., "age < 18", "18–64", "65+") has a finite case space.
- For control-flow decisions that have state. State machines model the states and the legal transitions between them.
Evidence¶
The support for decision tables is definitional, not statistical: the table is exhaustive by construction.
Related¶
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¶
- Guarantee · The axes
- Exhaustive coverage (MC/DC, MCC) · Methods
- Formal methods · Methods
- Model checking · Methods
- Requirements quality checking · Methods
- State machines and statecharts · Methods
- How AI fits into software quality · AI
- Choosing methods · Overview
References¶
-
Wayne, Hillel. 2018. Decision Tables. https://www.hillelwayne.com/post/decision-tables/. ↩