Agent skill
40-04-ts-domain-logic-separation
TS/React: Business logic lives in pure modules. Not in React hooks. Not in closures. Not in callbacks. Prevents untestable, unreasonable code.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/40-04-ts-domain-logic-separation
SKILL.md
40.04 Domain Logic Separation (TypeScript / React)
Business logic lives in pure modules that can be tested with plain function calls. The view layer visualizes. Stores hold state. Pure functions compute.
The Problem
Logic in the wrong place:
// WRONG — logic in React hook
function useWarpSpeed() {
const [speed, setSpeed] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSpeed(prev => {
if (prev > maxSpeed) return maxSpeed; // business rule buried in React
return prev + acceleration * dt; // physics in a useEffect
});
}, 16);
return () => clearInterval(interval);
}, []);
}
// WRONG — logic in closure callback
conn.db.shipComponent.onInsert((_, row) => {
// 50 lines of entity creation, ECS component setup, visual sync...
// untestable without mocking the entire subscription system
});
The Rule
| Layer | Responsibility | Tests with |
|---|---|---|
| Pure functions | Compute, transform, decide | Plain unit tests — expect(fn(input)).toBe(output) |
| Stores / shared state | Hold state, expose reads | Store tests — set state, assert reads |
| Domain modules | Orchestrate: read state → compute → write state | Integration tests against shared state |
| React components | Visualize state, dispatch actions | Visual tests (Playwright, Storybook) |
| Callbacks / handlers | Thin glue — call into domain modules | Don't test these directly — test the domain module |
How to Apply
1. Extract the logic
When you find logic inside React, a callback, or a closure:
// Before: logic in callback
conn.db.shipComponent.onInsert((_, row) => {
const eid = addEntity(world);
addComponent(world, Position, eid);
Position.x[eid] = row.x;
// ... 40 more lines
});
// After: thin callback → domain function
conn.db.shipComponent.onInsert((_, row) => upsertShip(row.entityId));
// Domain function — testable, readable, reusable
export const upsertShip = (entityId: string) => {
const position = positions.get(entityId);
if (!position) return;
const eid = addEntity(bridge.world!);
// ...
};
2. Keep callbacks thin
Callbacks are glue. They translate events into domain function calls. A callback longer than 5 lines probably contains domain logic that should be extracted.
3. React components read and dispatch
// Component reads from store, dispatches actions
function WarpButton() {
const isWarping = useSpacetimeStore(s => s.isWarping);
return <Button onClick={() => travelActions.engageWarp(targetId)} />;
}
The component doesn't know how warp works. It knows the state and the action.
The Test
Can I test this logic with a plain function call and an
expect()?
If no — the logic is in the wrong place. Extract it.
Relationship to Other Principles
- 40.01 State Ownership — domain logic reads from owned state, writes to owned state
- 40.02 Module Boundaries — domain modules are the natural extraction unit
- 40.03 Dependency Direction — domain logic sits in the middle layer, importing state, imported by UI
- 40.05 Singleton Patterns (TS) — domain modules read from singleton refs, not injected deps
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?