Description = “System Coding Practices: Refactor code into highly cohesive, loosely coupled modules adhering to Clean Code and hyper-modularity principles.”
Role: You are an expert software architect executing the /MODULARIZE command. Your objective is to refactor the provided code into highly cohesive, loosely coupled modules based on strict hyper-modularity rules.
Read the project’s configuration files (e.g., `.gemini/settings.json`, `.eslintrc`, or `tsconfig.json`) for any environment-specific constants or style enforcements.
Sub-Task: {{args}}
Execution Steps:
1. Analyze Responsibilities: Identify all distinct responsibilities, behaviors, and UI concerns within the provided code block.
2. Extract Functions: Break down large functions into bite-sized units. Ensure each function does exactly one thing, does it well, and does it only.
3. Extract Classes: Group cohesive variables and the functions that manipulate them into separate classes. Ensure each class has only one reason to change, adhering strictly to the Single Responsibility Principle.
4. Rename for Clarity: Rename variables, functions, and classes to be explicitly intention-revealing, pronounceable, and strictly bound to the problem or solution domain.
5. Eliminate Duplication: Ruthlessly apply the DRY (Don’t Repeat Yourself) principle across all newly extracted modules.
Output: Provide the fully refactored code followed by a brief bulleted summary of the newly created architectural boundaries.
Best Practices for Complete Modular Clean Code
Shrink Functions: The first rule of functions is that they should be small, and the second rule is that they should be smaller than that. Functions should do one thing, do it well, and do it only.
Shrink Classes by Responsibility: The first rule of classes is that they should be small, which is measured by counting responsibilities. A class or module should have one, and only one, reason to change.
Maximize Cohesion: Classes should have a small number of instance variables, and each of the methods of a class should manipulate one or more of those variables. Breaking large functions into smaller ones naturally creates new, highly cohesive classes.
Eliminate Duplication: Duplication is the root of all evil in software. Use composition, abstraction, and pure subroutines to centralize repeated logic.
Create Clean Boundaries: Code at the boundaries needs clear separation and tests that define expectations. Encapsulate external APIs or side-effects using adapters to isolate the core system from external changes.
—
HYPER-MODULAR CODEBASE — Architecture Guide
How this codebase is organized, and the rules to follow when adding to it.
The organizing principle is **hyper-modularity: one structural unit (function, component, or class) per file.**
1. The Core Rule
**One exported unit per file. The file is named exactly after its export.**
src/domain/feature/calculateMetric.ts → export function calculateMetric(…)
src/model/entity/updateState.ts → export function updateState(entity, …)
src/components/layout/SubmitButton.tsx → export function SubmitButton()
Corollaries:
A folder is a module. A directory holds everything required for a specific feature, with one file per operational step.
No index.ts barrels. Import the exact file you need: import { doAction } from ‘../feature/doAction’;. Barrels obscure the module graph and artificially recreate the monoliths this structure is designed to destroy.
File name === export name, including case. UI components and Classes are PascalCase; standard pure functions are camelCase.
Where Types Live
Types are not logic, so they do not automatically get their own file by default:
A type that describes one function’s parameters or return value lives in that function’s file.
A type shared across a specific module gets a PascalCase file of its own within that module directory.
Cross-cutting domain types stay in src/core/types.ts (or equivalent).
Never put DataType.ts next to dataType.ts. It breaks on case-insensitive file systems (macOS/Windows). Types live with the functions that produce/consume them.
Constants
Small, tightly related constants may share one file if they are meaningless apart. A constant used by exactly one function belongs inline within that function’s file.
2. Classes are State Facades (The Delegation Pattern)
If the architecture uses classes for state management or complex entities, they should act solely as facades. They hold mutable state, but contain minimal logic.
Each method should be a one-line delegator to a separate file that holds the actual implementation as a free, pure function.
TypeScript
// src/model/EntityStore.ts — the facade
processPayload(payload: PayloadType): boolean {
return processPayload(this, payload);
}
// src/model/store/processPayload.ts — the implementation
export function processPayload(store: EntityStore, payload: PayloadType): boolean {
// … actual logic here
}
Because call sites still use standard class methods (store.processPayload()), the public API remains stable and ergonomic, while the implementation stays highly modular and independently testable. Internal fields accessed by these modular functions should be exposed but clearly documented (e.g., /** @internal */).
3. Directory Map & Dependency Direction
Maintain a strict separation of concerns utilizing common architectural layers.
src/
core/ Types, constants, and pure helpers (e.g., parsers, math). No side effects.
domain/ Pure business logic. No application state, no UI, no external APIs.
model/ Data structures and application state operations.
services/ I/O, database adapters, network requests, browser storage.
state/ Global store (e.g., Redux, Zustand) and state actions.
components/ UI Layer. One component per file. Highly nested by layout and feature.
Strict Dependency Direction
components → state → services → model → domain → core.
Lower layers must never import from higher layers (e.g., domain/ code cannot import from components/ or state/).
4. UI Structure & Composition
Avoid monolithic UI components. If a UI view is complex, it should be broken down into semantic parts.
Layouts own state, children render it: A parent layout component should track high-level UI state (e.g., “is the modal open?”) and pass data down.
One component per file: A row, a button, a divider, and a panel all get their own files.
Decoupled Features: If adding a new tool, menu, or command to the application, implement its logic, state, and UI in isolated files, then register it in a central registry rather than hardcoding it into shared layout files.
5. Style & Context
Comments explain WHY, not WHAT. Only comment when the business reason for the code isn’t obvious. The code structure itself should explain the what.
Naming Context: Name variables so their context is obvious (domainCoordinates vs viewCoordinates, dbId vs uiId).
Strict Imports: Keep imports explicit and grouped. Unused imports should be treated as build errors. Use type-only imports wherever applicable.
6. Verifying Changes
Type-checking and unit testing are not proof that a full system integration works.
Static: Pass the type-checker and linter strictly (noEmit, strict mode).
Unit: Pure functions in core and domain must pass headless tests.
Integration: Boot the local development environment and physically verify UI, side effects, and state interactions.


















































































