Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add ryanthedev/code-foundations --skill "cc-table-driven-methods"
Install specific skill from multi-skill repository
# Description
Replace complex conditional logic with table lookups. CHECKER mode identifies opportunities where if/else chains or inheritance hierarchies should become tables. APPLIER mode designs table structure, access method (direct/indexed/stair-step), and key transformations. Use when writing 4+ if/else branches, switch statements keep growing, subclasses differ only in data not behavior, or data changes without code changes. Triggers on: too many if statements, switch growing, subclass per type, customer-controlled format, data-driven behavior, lookup table, mapping data to actions.
# SKILL.md
name: cc-table-driven-methods
description: "Replace complex conditional logic with table lookups. CHECKER mode identifies opportunities where if/else chains or inheritance hierarchies should become tables. APPLIER mode designs table structure, access method (direct/indexed/stair-step), and key transformations. Use when writing 4+ if/else branches, switch statements keep growing, subclasses differ only in data not behavior, or data changes without code changes. Triggers on: too many if statements, switch growing, subclass per type, customer-controlled format, data-driven behavior, lookup table, mapping data to actions."
Skill: cc-table-driven-methods
STOP - Table vs Logic
- 4+ if/else branches for same classification? → Convert to table
- Subclass differs only in data, not behavior? → Use table, not inheritance
- Data changes without code changes needed? → Table is mandatory
CRISIS TRIAGE (1 minute)
Code review flagged complex logic? Quick assessment:
- Count branches - If 3+ similar if/else branches for same classification → table candidate
- Check volatility - Does this data change without code changes needed? → table candidate
- Look for subclass proliferation - One subclass just to change a value? → table candidate
When tables clearly win:
- Character classification (letter/digit/punctuation)
- Days per month
- Insurance rates by demographic
- Message format parsing
- Grade ranges
Key Definitions
Table-Driven Method
A scheme that allows you to look up information in a table rather than using logic statements to figure it out.
Direct Access Table
Access table element directly using a key. Simplest form. Example: charType = charTypeTable[inputChar]
Indexed Access Table
Use primary data to look up key in index table, then use that key for main table. Trades space for direct-access capability with sparse keys.
Stair-Step Access Table
Entries valid for ranges rather than distinct points. Loop through range boundaries to find category.
Fudging Lookup Keys
Techniques for making data work as table keys when it doesn't map directly. Includes duplicating info, transforming keys, isolating transformations in routines.
Table Access Method Decision Flowchart
+---------------------------+
| Can data key directly |
| into table? |
| (e.g., month 1-12) |
+-----------+---------------+
|
+------+------+
| |
YES NO
| |
v v
+---------+ +---------------------------+
| DIRECT | | Large sparse keyspace? |
| ACCESS | | (e.g., 4-digit part #s, |
+---------+ | only 100 items) |
+-----------+---------------+
|
+------+------+
| |
YES NO
| |
v v
+---------+ +---------------------------+
| INDEXED | | Valid for ranges? |
| ACCESS | | (e.g., grade cutoffs, |
+---------+ | probability distributions)|
+-----------+---------------+
|
+------+------+
| |
YES NO
| |
v v
+-----------+ +-----------+
| STAIR-STEP| | Reconsider|
| ACCESS | | table fit |
+-----------+ +-----------+
Modes
CHECKER
Purpose: Identify opportunities to replace logic with tables
Triggers:
- "review this conditional logic"
- "is this if chain too complex"
- "should I use a table here"
- "audit my switch statement"
Non-Triggers:
- "design a table solution" -> APPLIER
- "review my class hierarchy" -> cc-routine-and-class-design
Checklist: See checklists.md
Output Format:
| Location | Current Logic | Table Opportunity | Access Method |
|----------|--------------|-------------------|---------------|
Severity:
- OPPORTUNITY: Logic could be replaced with table (complexity > 3 branches)
- CONSIDER: May benefit from table (volatile data, growing branches)
- OK: Logic is appropriate (simple, genuinely polymorphic)
APPLIER
Purpose: Design and implement table-driven solutions
Triggers:
- "convert this to a table"
- "design table-driven solution"
- "replace these if statements with table"
- "implement table lookup"
Non-Triggers:
- "is this a good table candidate" -> CHECKER
- "review my table implementation" -> general code review
Produces:
- Table structure design
- Access method selection
- Key transformation routines
- Migration from logic to data
Constraints:
- Isolate key transformations in routines (p.424)
- Consider external data for volatile tables (p.421)
- Address both issues: access method AND what to store
When Tables Beat Logic
| Situation | Logic Approach | Table Approach | Winner |
|---|---|---|---|
| Character classification | 20+ range checks | Single array lookup | Table |
| Days per month | 12-branch if/else | 12-element array | Table |
| Insurance rates (age/gender/status) | Deeply nested ifs | Multi-dimensional array | Table |
| Message format parsing | 20 routines/subclasses | Format description table | Table |
| Grade calculation | 5-branch if chain | Stair-step lookup | Table |
| Simple 2-way decision | Single if/else | 2-element array | Logic |
| Genuinely polymorphic behavior | - | - | OOP |
Complexity Threshold: When you're writing the 4th if/else branch for the same classification, consider tables.
When OOP Inheritance is NOT the Answer
"The fact that a design uses inheritance and polymorphism doesn't make it a good design." (p.423)
Anti-Pattern: Subclass per variant
- Creating FloatingPointField, IntegerField, StringField, etc. subclasses
- Each subclass differs only in data, not behavior
- Rote OOP can require MORE code than table-driven approach
Table Alternative:
// Table of objects - one line replaces 20 routines
AbstractField* field[Field_Last+1];
field[Field_FloatingPoint] = new FloatingPointField();
field[Field_Integer] = new IntegerField();
// ...
field[fieldType].ReadAndPrint(fieldName, fileStatus);
When OOP IS appropriate: When behavior genuinely varies polymorphically, not just data values.
Red Flags - Consider Table-Driven Instead
Logic Explosion:
- Writing 4th if-else branch for same classification
- Switch statement keeps growing with new cases
- Deeply nested conditionals for combinations
Data Masquerading as Code:
- Creating subclass just to change a data value
- Customer-controlled format with frequent changes
- Hardcoded values that "might change"
Duplication:
- Index calculation duplicated in multiple places
- Same classification logic repeated across functions
- Multiple switch statements on same discriminator
All of these mean: Put knowledge in data, not code.
Rationalization Counters
| Excuse | Reality |
|---|---|
| "OOP inheritance is the proper design" | Inheritance isn't automatically better. Well-designed table can be simpler than copious subclasses. |
| "Logic is clearer than tables" | Only for simple cases. As complexity grows, tables become clearer. |
| "It's just a few if statements" | "Few" grows. Tables scale better and are easier to modify. |
| "Tables are harder to debug" | Tables separate data from logic, making each easier to verify independently. |
| "I need different behavior per type" | Can behavior be encoded as data? (action codes, routine references) |
| "But the table needs setup code" | Setup code runs once; if-chains execute every call. |
| "It's only N branches now" | The threshold keeps moving. "Just 5" becomes 20. Act at 4+. |
| "Tables are premature optimization" | YAGNI to justify never refactoring. Pattern is already here. |
| "We need the type safety of subclasses" | Modern pattern matching provides type safety without explosion. |
| "This behavior might diverge later" | Speculative polymorphism. Add complexity when needed, not before. |
| "The team doesn't know tables" | Teach the pattern. Don't lock team into suboptimal approaches. |
| "OOP version is more testable" | Tables are testable via lookup function with boundary cases. |
Pressure Testing Scenarios
Scenario 1: Growing Switch
Situation: Switch statement has 8 cases, requirement adds 9th.
Wrong Response: Add another case. "It's just one more."
REQUIRED Response: Evaluate: Is this data-driven behavior? If pattern will continue growing, convert to table now.
Scenario 2: Customer-Controlled Format
Situation: Message format changes frequently based on customer requirements.
Wrong Response: Code each format variant.
REQUIRED Response: Make format data-driven. New formats = new table entries, no code changes.
Scenario 3: Subclass Explosion
Situation: Creating 20 subclasses for 20 message types.
Wrong Response: "This is proper OOP design."
REQUIRED Response: Question: Does each subclass have different BEHAVIOR or just different DATA? If data, use table.
Scenario 4: Range Classification
Situation: Classifying values into categories (A/B/C/D/F grades).
Wrong Response: if (score >= 90) ... else if (score >= 80) ...
REQUIRED Response: Use stair-step table. Easier to modify cutoffs.
Table Design Guidance
What to Store in Tables
- Data - Direct values (days per month, rates, limits)
- Action codes - Enum/constant indicating what action to take
- Routine references - Function pointers, lambdas, method references
Fudging Keys - Three Approaches
- Duplicate information - Straightforward but wastes space, risks inconsistency
- Transform the key -
max(min(66, Age), 17)to clamp range - Isolate in routine -
KeyFromAge(age)for consistent transformation
Always isolate key transformations in their own routines - eliminates inconsistent transformations, makes modifications easier.
Stair-Step Implementation
' Grade lookup with stair-step
Dim rangeLimit() As Double = { 50.0, 65.0, 75.0, 90.0, 100.0 }
Dim grade() As String = { "F", "D", "C", "B", "A" }
gradeLevel = 0
studentGrade = "A" ' Default to top grade
While (studentGrade = "A") And (gradeLevel < maxGradeLevel)
If studentScore < rangeLimit(gradeLevel) Then
studentGrade = grade(gradeLevel)
End If
gradeLevel = gradeLevel + 1
Wend
Subtleties:
- Watch endpoints - make sure top of each range is covered
- Be careful with < vs <=
- Consider binary search for large lists
- Consider indexed access for speed (trade space for time)
External Table Data
When to externalize:
- Data changes without code changes needed
- Customer-configurable behavior
- A/B testing, feature flags
- Localization data
How: Store table data in external file (JSON, YAML, config), read at runtime.
Tradeoff: Adds I/O and parsing overhead. Use for genuinely volatile data.
Chain
| After | Next |
|---|---|
| Table implemented | cc-routine-and-class-design (CHECKER) |
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.