From design
Refactor and reorganize codebases using SOLID principles, clean architecture, strict naming conventions, and defensive programming. Trigger with "refactor this codebase", "reorganize the code", "clean up the project structure", "fix the naming", "audit the codebase", "code organization", or when someone needs help restructuring, renaming, deduplicating, or improving code quality across a project.
How this skill is triggered — by the user, by Claude, or both
Slash command
/design:codebase-organizationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A complete methodology for auditing, refactoring, and reorganizing codebases. Every decision must be filtered through the principles below - they are constraints, not suggestions. When two principles conflict, the order listed here represents priority.
A complete methodology for auditing, refactoring, and reorganizing codebases. Every decision must be filtered through the principles below - they are constraints, not suggestions. When two principles conflict, the order listed here represents priority.
any, object, untyped function signatures.const, readonly, frozen data structures by default. Mutate only with clear justification, contained to the smallest scope.Names must describe what something IS, not how it compares to something that came before. Names are read thousands of times by developers with no knowledge of history. The name must stand entirely on its own.
These are strictly prohibited in file names, folder names, function names, class names, variable names, component names, and any other identifier. If any exist, they must be renamed.
| Banned Pattern | Why It's Harmful | Correct Alternative |
|---|---|---|
EnhancedWidget / ImprovedWidget | Implies a non-enhanced version exists. Enhanced compared to what? | Name for what it does: WidgetWithValidation |
NewUserService / OldUserService | "New" is only new today. Which one is active? | UserService. For migrations: UserServiceV1 + UserServiceV2 with deprecation timeline |
BetterParser / FastParser / SmartParser | Subjective, relative, unverifiable | Name the mechanism: StreamingParser, BatchParser, RecursiveDescentParser |
utils2.js / helpers_new.py / styles_final.css | Versioned filenames signal fear of replacing the original | One file, one name. utils.js. Delete or merge the old one |
handleClickNew() / processDataV2() | Creates ghost references developers hunt for | handleClick(). Or name the behavioral difference: processDataInBatches() |
temp_, test_ (non-test), my_, foo, bar, xxx | Non-descriptive placeholders in production | Name for what it does: extractInvoiceLineItems() |
data, info, item, thing, stuff, obj, val, result (standalone) | Semantically empty - every variable holds data | Name the domain concept: invoice, userProfile, authToken |
doProcess() / handleStuff() / manageThings() | Vague verbs + vague nouns | calculatePortfolioReturn(), syncMeetingTranscript() |
IUserInterface / AbstractBaseUser | Hungarian notation encodes type system info into names | User for the interface. Let the language's type system communicate the construct type |
_backup, _copy, _orig, _fixed, _patched, _updated, _refactored | Suffixes narrate the changelog inside the name | Strip the suffix. Git provides the history |
UserService not RefactoredUserServicegetActiveUsers() not queryDatabaseForNonDeletedUsers()filterByExpirationDate() not getRelevantItems()rebalancePortfolio()emailAddress not email. retryDelayMs not delay. maxLoginAttempts not maxisAuthenticated, hasPermission, shouldRetry, canEditusers is an array, user is one element, usersByEmail is a mapon[Event] or handle[Event] - onSubmit, handleFileUploadUPPER_SNAKE_CASE describing meaning - MAX_RETRY_ATTEMPTS = 3, DEFAULT_TIMEOUT_MS = 5000HttpClient, parseJson, userId, apiUrl - not HTTPClient, parseJSONThe same concept must use the same noun everywhere: backend, frontend, database, API, types, docs. Maintain a domain glossary at docs/glossary.md mapping business terms to canonical code names.
Reorganize into a clear, predictable layout:
project-root/
+-- frontend/ # All client-side code
+-- backend/ # All server-side code
+-- shared/ # Types, constants, utilities shared across sides
+-- scripts/ # Build, deploy, migration, maintenance scripts
+-- docs/ # Architecture decisions, API docs, glossary, guides
| +-- decisions/ # Architecture Decision Records (ADRs)
| +-- glossary.md # Domain term -> code name mapping
+-- .github/ # CI/CD workflows, PR templates, issue templates
+-- docker/ # Dockerfiles, compose files (if applicable)
+-- README.md
Rules:
frontend/ or backend/, it belongs in shared/ or scripts/features/auth/ containing its components, hooks, services, and tests over separate top-level components/, hooks/, services/ folders| Concept | Frontend Path | Backend Path |
|---|---|---|
| User auth | frontend/src/features/auth/ | backend/src/features/auth/ |
| API client / route | frontend/src/api/users.ts | backend/src/routes/users.py |
| Type definitions | frontend/src/types/user.ts | backend/src/schemas/user.py |
| Validation logic | frontend/src/validation/user.ts | backend/src/validation/user.py |
| Shared constants | shared/constants/roles.ts | shared/constants/roles.py |
File naming: lowercase-kebab-case for non-Python, lowercase_snake_case for Python, PascalCase for components.
For every instance of duplicated or near-duplicated logic:
utils/, hooks/, or services/ within that sideshared/Shared types between frontend and backend must live in shared/types/. Pure utility functions belong in shared/utils/.
Every async operation must be resilient and observable. Silent failures are unacceptable.
async function performOperation():
try:
result = await riskyOperation()
return { success: true, data: result }
catch (error):
// 1. LOG with full context (operation, inputs, stack trace)
logger.error("performOperation failed", { error, context })
// 2. CLASSIFY (transient vs permanent)
if isTransient(error):
// 3. RETRY with exponential backoff
return await retryWithBackoff(riskyOperation, maxRetries=3)
// 4. FALLBACK to degraded behavior
fallbackResult = getCachedOrDefault()
if fallbackResult:
return { success: true, data: fallbackResult, degraded: true }
// 5. PROPAGATE with meaningful error (never swallow)
throw new ApplicationError("Operation failed", { cause: error })
try/catch that swallows errors. Every catch must: log + rethrow, log + return fallback, or log + return typed errorcatch (e) {} - this is a silent failureResult<T, E> or {success, data, error} objects for expected failure modes. Reserve exceptions for truly unexpected failures// TODO(jerry, 2025-02-24): Replace with batch APIdocs/decisions/ with context, alternatives, and rationaledocs/glossary.md, align canonical names before renamingAt every step: run tests, verify builds, confirm no regressions before proceeding.
Before considering the refactoring complete:
frontend/, backend/, or shared/docs/glossary.md exists mapping every domain concept to its canonical code nameany, no untyped parameters, no implicit nullnpx claudepluginhub p/henssler-financial-design-plugins-designGuides collaborative design exploration before implementation: explores context, asks clarifying questions, proposes approaches, and writes a design doc for user approval.
Creates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.
Provides Slack GIF creation utilities with dimension/FPS/color constraints and Python PIL-based frame generation. Use for animated Slack emoji or message GIFs.