From code-foundations
Guides OOP class and routine design: enforces LSP checks, prefers containment over inheritance, limits parameters >7, evaluates cohesion. For reviews and refactoring.
npx claudepluginhub ryanthedev/code-foundationsThis skill uses the workspace's default tool permissions.
| Check | Time | Why Non-Negotiable |
Reviews and refactors object-oriented code for SOLID compliance in PHP, Java, Python, TypeScript, C++. Detects violations of SRP, OCP, LSP, ISP, DIP and suggests fixes with examples.
Elevates code to senior-engineer quality using SOLID principles, TDD, and clean code practices for writing, refactoring, architecture planning, reviews, and debugging.
Applies Uncle Bob's Clean Code, Architecture, Coder, Agile principles for code reviews, refactoring, architecture evaluation, and professional practices.
Share bugs, ideas, or general feedback.
| Check | Time | Why Non-Negotiable |
|---|---|---|
| LSP Test - "Is 'A is a B' literally true?" | 30 sec | Wrong inheritance creates debugging hell |
| Containment Default - If LSP feels wrong, use containment | 30 sec | Containment is fixable; inheritance requires architecture changes |
| Parameter Count - If >7 parameters, interface is wrong | 15 sec | High parameter count predicts interface errors |
This skill assumes:
For functional programming, prototype-based inheritance, or heavily concurrent code, adapt principles rather than applying literally. See "Pattern-Specific Guidance" section.
These checks are NON-NEGOTIABLE regardless of deadline pressure:
| Check | Time | Why Non-Negotiable |
|---|---|---|
| LSP Test - "Is 'A is a B' literally true?" | 30 sec | Wrong inheritance creates debugging hell that costs MORE time than it saves |
| Containment Default - If LSP feels like "purity theater," use containment | 30 sec | Containment problems are fixable; inheritance problems require architecture changes |
| Parameter Count - If >7 parameters, interface is wrong | 15 sec | High parameter count predicts interface errors |
Why these three? Violations create problems that CANNOT be easily fixed post-crisis. They require architectural changes, not patches.
Design fixes deferred are rarely completed. Technical debt from wrong inheritance is architectural, not patchable.
Purpose: Execute design checklists against routines and classes Triggers:
Severity Classification Rubric:
| Severity | Criteria | Example |
|---|---|---|
| VIOLATION | Explicitly fails checklist item | 12 parameters (> 7 limit) |
| VIOLATION | Breaks LSP/encapsulation | Empty override, protected base data |
| WARNING | Near limit, needs justification | 8 parameters, 3-level inheritance |
| WARNING | Subjective concern | Questionable abstraction consistency |
| PASS | Meets or exceeds requirement | Clear cohesion, ≤7 parameters |
Note: Test suite status is IRRELEVANT to checker results. A class can pass all tests and still have VIOLATION-level design issues that predict future maintenance problems.
Purpose: Guide class interface design, inheritance decisions, and routine creation Triggers:
Threshold Table:
| Count | Status | Action |
|---|---|---|
| 1-5 | PASS | No action needed |
| 6-7 | PASS | Minor concern, document if unusual |
| 8-9 | WARNING | Justify in code review OR redesign |
| 10+ | VIOLATION | Must redesign - use Parameter Object or split responsibilities |
"About 7" means: 7 is the limit. 8 is over. Count ALL parameters including optional ones with defaults. Variadic args (*args/...) count as 1.
Ordering convention (implies data flow sequence - ORDER MATTERS):
If A inherits from B, then everywhere code uses B, you can substitute A without breaking anything.
Test: Does calling every method on the base class make sense for the derived class?
Inheritance requires BOTH:
If EITHER fails: use containment instead.
Routine performs one and only one operation.
Name Test: If you need "and" or "then" in the name to describe what the routine does, it has multiple operations.
ValidateUserInput(), CalculateTotalPrice(), SendWelcomeEmail()ValidateAndSaveUser(), ReadFileThenParseJSON(), InitializeAndConnect()Scope: "One operation" means one action at the routine's declared abstraction level.
CreateUser() is ONE operation (user creation) even though it involves validation, hashing, insertionQuestion order rationale: Data-only sharing → containment (simplest). Behavior-only sharing → interface/protocol. Both data and behavior → requires full LSP verification before inheriting.
digraph inheritance_decision {
rankdir=TB;
START [label="How should A relate to B?" shape=doublecircle];
q1 [label="Shares ONLY data?" shape=diamond];
q2 [label="Shares ONLY behavior\n(method signatures)?" shape=diamond];
q3 [label="Shares BOTH data\nand behavior?" shape=diamond];
q4 [label="Is 'A is a B' literally true?\n(LSP: A substitutes for B\neverywhere)" shape=diamond];
contain1 [label="CONTAIN\ncommon object" shape=box];
interface1 [label="USE INTERFACE/PROTOCOL\n(not inheritance)" shape=box];
inherit2 [label="INHERIT" shape=box];
contain2 [label="CONTAIN" shape=box];
none [label="NO RELATION\n(reconsider if relationship needed)" shape=box];
START -> q1;
q1 -> contain1 [label="yes"];
q1 -> q2 [label="no"];
q2 -> interface1 [label="yes"];
q2 -> q3 [label="no"];
q3 -> q4 [label="yes"];
q3 -> none [label="no"];
q4 -> inherit2 [label="yes"];
q4 -> contain2 [label="no"];
}
FINAL CHECK (apply AFTER flowchart determines INHERIT, BEFORE committing to inheritance):
If ANY answer is NO → use CONTAIN instead.
Classification algorithm: Questions test for highest-quality cohesion first. Stop at first YES answer - that's your classification. This prevents under-classifying (e.g., calling functional cohesion "sequential").
Target: Functional cohesion - routine performs one and only one operation.
digraph cohesion_classification {
rankdir=TB;
START [label="Classify routine cohesion" shape=doublecircle];
q1 [label="Single operation?\n(Name Test passes)" shape=diamond];
q2 [label="Ordered operations\nsharing data step-to-step?" shape=diamond];
q3 [label="Operations share\ndata only?" shape=diamond];
q4 [label="Same-time operations\n(startup/shutdown)?" shape=diamond];
q5 [label="Orchestrates calls\n(not direct work)?" shape=diamond];
q6 [label="Order from external\nrequirement (UI)?" shape=diamond];
q7 [label="Control flag selects\noperation?" shape=diamond];
functional [label="FUNCTIONAL\n[ACCEPT]" shape=box style=filled fillcolor=lightgreen];
sequential [label="SEQUENTIAL\n[ACCEPT w/caution]" shape=box style=filled fillcolor=lightyellow];
communicational [label="COMMUNICATIONAL\n[ACCEPT w/caution]" shape=box style=filled fillcolor=lightyellow];
temporal_ok [label="TEMPORAL\n[ACCEPT]" shape=box style=filled fillcolor=lightgreen];
temporal_fix [label="TEMPORAL\n[FIX: orchestrate]" shape=box style=filled fillcolor=orange];
procedural [label="PROCEDURAL\n[REJECT]" shape=box style=filled fillcolor=lightcoral];
logical [label="LOGICAL\n[REJECT]" shape=box style=filled fillcolor=lightcoral];
coincidental [label="COINCIDENTAL\n[REDESIGN]" shape=box style=filled fillcolor=red fontcolor=white];
START -> q1;
q1 -> functional [label="yes"];
q1 -> q2 [label="no"];
q2 -> sequential [label="yes"];
q2 -> q3 [label="no"];
q3 -> communicational [label="yes"];
q3 -> q4 [label="no"];
q4 -> q5 [label="yes"];
q4 -> q6 [label="no"];
q5 -> temporal_ok [label="yes"];
q5 -> temporal_fix [label="no"];
q6 -> procedural [label="yes"];
q6 -> q7 [label="no"];
q7 -> logical [label="yes"];
q7 -> coincidental [label="no"];
}
Evidence: 50% of highly cohesive routines fault-free vs 18% low cohesion [Card et al. 1986, N=450 routines]. This is MAINTENANCE data, not shipping data - the 50% vs 18% gap appears during modifications.
Types listed from BEST (top) to WORST (bottom) quality - ORDER MATTERS:
| Type | Definition | Status | Code Example |
|---|---|---|---|
| Functional | Routine performs one and only one operation | ACCEPT | calculateTax(amount) - returns tax |
| Sequential | Operations share data step-to-step in required order, but don't form complete function | ACCEPT w/caution | parse(input) -> validate(parsed) -> transform(validated) |
| Communicational | Operations use same data but aren't otherwise related | ACCEPT w/caution | printReport(data); emailReport(data) - both use reportData |
| Temporal | Operations combined because done at same time (startup, shutdown) | ACCEPT if orchestrates | startup() calls initDB(), initCache(), initLogger() |
| Procedural | Operations ordered by external requirement (UI flow), not logical relationship | REJECT | showPage1() -> showPage2() -> showPage3() - wizard steps |
| Logical | Control flag selects one of several unrelated operations in big if/case | REJECT | process(mode) with switch between Parse, Validate, Format |
| Coincidental | Operations have no discernible relationship ("chaotic cohesion") | REDESIGN | doStuff() logs, validates, emails, calculates tax |
"ACCEPT w/caution" means:
"Caution" is not permission to ignore - it's permission with accountability.
If description uses these verbs, likely ORCHESTRATION (temporal cohesion OK):
If description uses these verbs, likely DIRECT WORK (check cohesion type):
Orchestration Example (GOOD):
def startup():
load_config() # calls another routine
init_database() # calls another routine
start_server() # calls another routine
log_startup_complete()
Direct Work Example (FIX by extracting):
def startup():
config = json.load(open('config.json')) # direct work - extract
db = Database(config['db_url']) # direct work - extract
db.connect() # direct work - extract
server.start(config['port']) # acceptable call
| Type | Improvement Steps |
|---|---|
| Sequential | 1) Split into separate routines per operation 2) Have dependent routine call what it depends on 3) Both achieve functional cohesion |
| Communicational | 1) Identify operations related only by same data 2) Split into individual routines 3) Reinitialize data close to creation 4) Call both from higher-level routine |
| Temporal | 1) Make routine an organizer, not doer 2) Call other routines to perform activities 3) Name at right abstraction level (e.g., Startup() not ReadConfigInitScratchEtc()) |
| Logical | 1) Create separate routine for each distinct operation 2) Move shared code/data to lower-level routine 3) Package routines into a class |
Builders exhibit intentional method chaining (fluent interface). Evaluate cohesion at the class level, not individual methods.
this are acceptableMixins add behavior without "is-a" claims. Evaluate differently:
Apply extra scrutiny:
Cohesion evaluation differs for event-driven patterns:
awaitWhen full checklist review is impractical, these 7 items are MANDATORY:
| # | Check | Time |
|---|---|---|
| 1 | LSP test for any inheritance | 30 sec |
| 2 | Inheritance depth < 3 levels | 15 sec |
| 3 | No empty overrides | 30 sec |
| 4 | Parameter count ≤ 7 | 15 sec |
| 5 | Routine name describes everything it does | 30 sec |
| 6 | Class presents consistent abstraction level | 1 min |
| 7 | Implementation details hidden | 1 min |
Total: ~4 minutes - This is the floor, not the ceiling.
Skipped items require: Technical debt ticket with specific follow-up date.
Why These Rules Apply Even After Success:
| Claim | Evidence | Limitation |
|---|---|---|
| High cohesion = fewer faults | 50% fault-free vs 18% [Card et al. 1986] | N=450 routines, single study |
| Deep inheritance = more faults | Significantly associated [Basili 1996] | Correlation, not causation |
| Information hiding reduces faults | Factor of 4 reduction [Korson/Vaishnavi 1986] | Varies by context |
| High coupling = more errors | 7x errors, 20x fix cost [Selby 1991] | Coupling-to-cohesion ratio |
| Cognitive limit ~7 items | Miller 1956 | Original study was about memory chunks, application to parameters is heuristic |
Critical insight: This is MAINTENANCE data, not shipping data. All code "works" on day 1. The 50% vs 18% gap appears during modifications, extensions, and bug fixes. Code passing tests on first commit does not predict maintenance quality.
| After | Next |
|---|---|
| Design verified | cc-defensive-programming (CHECKER) |