Table-Driven Programming: An Underrated Superpower


When you’re cranking out business logic, nothing beats a good lookup table. It’s simple, legible, and keeps the “ifs” from exploding all over your codebase.

From Spaghetti to Spreadsheet

def get_unit_price(seats):
    if seats >= 100:
        return 12.0
    elif seats >= 50:
        return 14.0
    elif seats >= 25:
        return 16.0
    elif seats >= 10:
        return 18.0
    else:
        return 20.0

Swap in a table and watch the clutter disappear:

pricing_table = [
    {"min":    0, "rate": 20.0},   # 0-9 seats -> $20/seat
    {"min":   10, "rate": 18.0},   # 10-24 seats
    {"min":   25, "rate": 16.0},   # 25-49 seats
    {"min":   50, "rate": 14.0},   # 50-99 seats
    {"min":  100, "rate": 12.0},   # 100+ seats
]

def get_unit_price(seats):
    for rule in reversed(pricing_table):
        if seats >= rule["min"]:
            return rule["rate"]

Works in any language. No fancy pattern-matching required — just a loop.

Why Bother?

  • Readable: Every rule looks the same, so you’re skimming, not spelunking.
  • Flexible: Need a new tier? Tweak the table — no code surgery.
  • Test-Friendly: Your test cases are the data. Validate the rows, not a forest of conditionals.
  • Brain-Friendly: Most messy branches are just an implicit table anyway. Make it explicit and move on.

Hot take: Nine times out of ten, “business logic” is just a spreadsheet waiting to happen.

Multi-Dimensional? No Problem.

Category     | Origin Group | Band  | Tariff Rate (%)
-------------|--------------|-------|-----------------
Electronics  | FTA          | low   | 2.0
Electronics  | FTA          | mid   | 1.5
Electronics  | FTA          | high  | 0.5
Electronics  | non-FTA      | low   | 5.0
Electronics  | non-FTA      | mid   | 4.0
Electronics  | non-FTA      | high  | 3.0
Apparel      | FTA          | low   | 8.0
Apparel      | FTA          | mid   | 6.0
Apparel      | FTA          | high  | 3.0
Apparel      | non-FTA      | low   | 12.0
Apparel      | non-FTA      | mid   | 10.0
Apparel      | non-FTA      | high  | 8.0
tariff_dict = {
    ("electronics", "FTA", "low"): 2.0,
    ("electronics", "FTA", "mid"): 1.5,
    ("electronics", "FTA", "high"): 0.5,
    ("electronics", "non-FTA", "low"): 5.0,
    ("electronics", "non-FTA", "mid"): 4.0,
    ("electronics", "non-FTA", "high"): 3.0,
    ("apparel", "FTA", "low"): 8.0,
    ("apparel", "FTA", "mid"): 6.0,
    ("apparel", "FTA", "high"): 3.0,
    ("apparel", "non-FTA", "low"): 12.0,
    ("apparel", "non-FTA", "mid"): 10.0,
    ("apparel", "non-FTA", "high"): 8.0,
}

# Band classification based on quantity
def resolve_band(quantity):
    if quantity < 100:
        return "low"
    elif quantity < 1000:
        return "mid"
    else:
        return "high"

# Main lookup function
def find_tariff_rate(category, origin_group, quantity):
    band = resolve_band(quantity)
    key = (category, origin_group, band)
    return tariff_dict.get(key, None)  # None if no match found

This mindset alone can improve code clarity — even if you don’t fully implement it.

Externalize Your Logic

With first-class functions in most modern languages, you can also store behaviors — not just constants — in tables and apply them dynamically.

Because rules are just data, you can:

  • Store them in JSON, a DB table, or even a Google Sheet.
  • Let non-devs edit promo rates or tax rules without a code push.
  • Skip deploys for every tiny tweak. Change data, hit save, done.

Business Impact

From Code to Data

The real power? You’re transforming business logic from hardcoded control flow into externalized data. This enables:

  • Non-engineers to own rule updates
  • Logic changes without redeploys
  • Lower risk and faster iteration

Bonus point: AI won’t rewrite your logic in a table-driven style unless you ask it to. But if you do, it can refactor it instantly.

That means table-driven design isn’t just human-friendly. It’s AI-friendly too.

Fewer Tests, Fewer Bugs

If your logic is just data, there’s no need to write unit tests checking whether your code correctly re-implements those rules. You just verify the data.

Faster Release Cycles

Releasing application code is often slow, risky, and tightly coupled to engineering cycles. Logic-as-data enables sub-minute updates with near-zero rollback cost.

Roll forward via code: 0.5 day

Rollback via infra: 10 min

Rollback via config/data: 1 min

Empower Business Users

Provide an admin UI. Let domain experts own their logic. Engineering effort drops to zero.

⚠️ Caveats to Keep in Mind

  • Always include a sensible default or fallback.
  • If you change the table’s shape, the surrounding code must change too — plan ahead.
  • Data isn’t type-checked at compile time. Add validation or linting for safety.
  • Rules-as-data doesn’t protect you from bad rules. Only paranoia survives.
  • Memory access is expensive. If you’re squeezing every last nanosecond out of the hot path, pause and benchmark before trading branches for a lookup table.

Final Thought

As Code Complete reminds us (ch. 18, “Table-Driven Methods”), turning sprawling branch logic into a data table doesn’t just shrink the code you have to reason about. It also slashes the bug surface area and puts the knobs straight into the hands of the people who actually own the rules.