Untitled

Anonymous
markdown
10/19/2026 12:17 PM
38.1 KB
4
Indexable

Metadata name refactoring-clean-code description Refactor and improve code quality while preserving behavior. Use when asked to clean up, simplify, restructure, make code more readable or maintainable, remove code smells, or review refactoring opportunities. Refactoring and Clean Code Improve the code's clarity, correctness, and maintainability while preserving its intended behavior. Prefer small, verifiable changes over broad rewrites. Clean code is code that is easy to understand and change safely—not code that mechanically follows every rule or uses the fewest lines.

Use this skill when the user asks to refactor code, clean up a project, improve readability or maintainability, remove code smells, simplify logic, or conduct a clean-code review.

Operating rules Preserve behavior by default. Do not intentionally change business rules, public APIs, user-visible behavior, data formats, persistence semantics, or error contracts unless the user explicitly requests it or a defect must be fixed to complete the task. Call out any unavoidable behavior change. Follow the repository. Read applicable CLAUDE.md files and nearby project documentation first. Follow the existing language version, architecture, naming, formatting, testing, and dependency conventions unless they are clearly harmful or the user asks to change them. Protect existing work. Inspect git status and relevant diffs before editing. Never overwrite or discard user changes. Avoid resetting, cleaning, force-checking-out, or otherwise destructive Git operations. Understand before editing. Trace the relevant call sites, data flow, side effects, interfaces, and tests. Do not refactor code based only on a short snippet when repository context is available. Keep scope proportional. Make the smallest coherent set of changes that achieves the goal. Do not reformat unrelated files, rewrite whole modules, introduce dependencies, or redesign architecture without a concrete need. Prefer clarity over cleverness. Use straightforward control flow and explicit intent. Do not sacrifice readability to reduce line count. Avoid speculative design. Apply abstractions, design patterns, interfaces, and indirection only when they solve an existing problem. Do not generalize for hypothetical future requirements. Do not silently conceal uncertainty. If behavior is unclear, use tests, types, call sites, docs, and history where available. If it remains uncertain, make the safest behavior-preserving choice and report the uncertainty. Do the work when asked to refactor. Make and validate edits rather than only listing recommendations. If the user asks for review or advice only, do not modify files. Never claim validation that did not happen. Report the exact checks run, checks skipped, and any failures or pre-existing problems. Workflow

  1. Establish context and baseline Read applicable CLAUDE.md, README, contribution instructions, and relevant local documentation. Check the working tree and inspect the relevant diff before editing. Identify the language/framework versions and existing formatter, linter, type checker, test runner, and build commands. Locate the target code, its callers, related implementations, contracts, and tests. Run a focused baseline test or check when feasible. If it already fails, distinguish that failure from changes made by this refactor.
  2. Identify the actual problem Find concrete sources of complexity, such as unclear names, duplicated business rules, excessive nesting, long functions with multiple responsibilities, hidden side effects, tight coupling, unsafe error handling, unnecessary state, or obsolete code.

Do not change code merely because its style differs from your personal preference. Separate genuine maintainability issues from subjective stylistic choices. If the request is broad, prioritize high-impact improvements in the relevant area and avoid an uncontrolled whole-repository cleanup.

  1. Plan a behavior-preserving change State the intended outcome internally before editing. Choose a small, coherent refactor that can be checked independently. Preserve interfaces and observable behavior unless a change is authorized. Add or adjust tests first when needed to characterize fragile or poorly documented behavior. Keep structural refactoring separate from feature changes where practical.
  2. Refactor using these rules Names and readability Use descriptive, precise, searchable names that communicate intent. Name booleans as conditions where appropriate (is_valid, has_access, can_retry). Use consistent terms for the same concept; avoid vague names, unexplained abbreviations, and misleading names. Keep expressions simple. Introduce a well-named intermediate variable when it makes a complex expression easier to understand. Avoid clever one-liners, deep ternaries, confusing double negatives, and reliance on implicit coercion. Follow the repository's formatter and style guide; do not create formatting churn unrelated to the task. Functions and control flow Give each function one coherent responsibility and one clear abstraction level. Keep inputs, outputs, side effects, and dependencies understandable. Prefer guard clauses or early returns when they reduce nesting and clarify exceptional cases. Avoid long parameter lists, hidden mutations, global mutable state, and boolean flags that select unrelated behaviors. Do not split functions mechanically just to make them shorter. Extract a helper when it gives a meaningful name to a concept or isolates a distinct responsibility. Make loop termination, branching, null handling, and failure paths explicit. Modules and architecture Keep related behavior together and unrelated responsibilities separate. Reduce unnecessary coupling and avoid circular dependencies. Keep module interfaces small and deliberate; expose only what callers need. Prefer composition when it simplifies design; avoid deep inheritance and god objects/modules. Separate domain logic from I/O, framework code, persistence, and presentation when doing so improves testability or reduces coupling. Do not add abstraction layers, interfaces, factories, classes, or design patterns without a concrete benefit. Duplication and abstractions Remove duplicated knowledge and business rules when they should have one authoritative implementation. Do not unify fragments merely because they look similar; they may represent different concepts or evolve for different reasons. Follow DRY, but do not create a generic framework to eliminate trivial repetition. Apply YAGNI: implement current requirements, not speculative future possibilities. Prefer the simplest design that makes the current change clear and safe. Data and types Keep variable scope narrow and declare values close to their use. Prefer immutable values when mutation is not needed. Avoid reusing variables for unrelated meanings, unnecessary data duplication, and unexplained magic values. Use meaningful constants for domain concepts and shared configuration. Handle optional, missing, null, and invalid data deliberately. Use precise types and data structures when supported; avoid unsafe casts and broad types that obscure contracts. Make ownership and mutation of shared data clear. Errors and side effects Never swallow errors or use empty catch/exception handlers to make failures disappear. Handle errors at the layer with enough context to respond appropriately. Preserve error causes when wrapping errors and provide actionable context without exposing secrets. Do not catch and rethrow unchanged errors unless adding context or changing the contract. Avoid unexpected side effects in functions that appear to be simple queries. Make resource cleanup reliable on success and failure paths. Treat external input, network responses, file paths, and persisted data as untrusted where appropriate. Do not broaden retry behavior without confirming that the operation can be safely retried. Tests and verification Test observable behavior and contracts rather than private implementation details. Cover normal paths, edge cases, invalid inputs, and failures that matter to the change. Keep tests deterministic, focused, and independent. Add regression tests for bugs and tests before risky refactors when existing coverage is insufficient. Avoid over-mocking internal details or changing assertions just to make tests pass. Do not use code coverage percentage as the sole evidence of correctness. Security, performance, and dependencies Do not weaken validation, authorization, escaping, parameterized queries, secret handling, or other security controls while refactoring. Never move secrets into source code or logs. Do not optimize based only on intuition. Preserve correctness and measure meaningful bottlenecks before performance-driven changes. Watch for N+1 calls, redundant work, unbounded processing, resource leaks, and unsafe shared state when relevant. Avoid adding dependencies for trivial functionality. Remove dependencies only when they are genuinely unused and removal is within scope. Comments and documentation Prefer clear code over comments that merely paraphrase it. Keep comments that explain why a non-obvious choice exists, including constraints, invariants, trade-offs, or workarounds. Remove obsolete or misleading comments and commented-out code when safe; version control preserves history. Update relevant documentation when interfaces or important behavior change. Do not invent rationale for code when the reason cannot be established.
  3. Validate incrementally After editing:

Review the exact diff, including whitespace and generated changes. Run the project's formatter or formatter check for touched files, if available. Run focused tests for the affected behavior. Run relevant linting, type checking, and build checks when practical. Run broader tests only when justified by the scope, cost, and risk. Inspect failures and determine whether they were introduced by the refactor, already existed, or are unrelated. Search relevant call sites and public interfaces for accidental behavior or compatibility changes. Remove temporary debugging code, unused imports, dead variables, and accidental files introduced by the work. Never make unrelated formatting changes just to obtain a clean formatter result across the whole repository. If a command is unavailable, too expensive, or blocked, say so clearly instead of implying it passed.

  1. Final review Before finishing, confirm:

The code still implements the intended behavior. Names and control flow make intent easier to understand. Each changed function/module has a coherent responsibility. No unnecessary abstraction, dependency, or indirection was added. Error handling, security checks, and resource cleanup were preserved. Tests and checks provide reasonable confidence for the scope. The diff contains only changes related to the task, aside from explicitly justified adjacent fixes. Any remaining trade-offs, risks, or known failures are understood and can be reported. 7. Report results Give a concise completion summary:

Changed: the main structural or readability improvements. Behavior: state whether behavior was intended to remain unchanged; call out any deliberate behavior changes. Validation: list the exact tests, formatter, linter, type checker, or build commands run and their results. Limitations: mention relevant checks not run, pre-existing failures, and any remaining risk. Do not dump every internal step or list generic clean-code advice unless the user asks for it.

Prioritization when rules conflict Use this order of priority:

Correctness and preservation of required behavior. Security and data integrity. Clarity and maintainability. Consistency with established project conventions. Performance requirements supported by evidence. Personal stylistic preferences. These guidelines are not absolute laws. Optimize for code that a competent developer can understand, test, and change safely. Use the comprehensive checklist below during large refactors or explicit code-quality reviews. Apply only the items relevant to the language, architecture, and scope; the checklist is a guide, not a mandate to rewrite acceptable code.

Example requests “Refactor this function without changing behavior.” “Clean up this module and remove the code smells.” “Review this package for maintainability issues and fix the highest-impact ones.” “Simplify this logic, add regression tests, and verify the result.” “Review only; do not edit files.” Comprehensive Clean Code Checklist Use this during larger refactors, code reviews, or when the user explicitly asks for a thorough cleanup. Do not blindly apply every item to every change. A rule is useful only when it improves correctness, clarity, safety, or maintainability in the current context.

  1. Naming Names communicate intent and are easy to search. Names are precise, pronounceable, and use consistent domain terminology. Booleans read like conditions, such as is_valid, has_access, or can_retry. Collections use plural names when that improves clarity. Vague names, unnecessary abbreviations, misleading names, and arbitrary suffixes are avoided. Variables, functions, classes, and modules follow the project's naming conventions. The same term is used for the same concept across the codebase. Names do not promise behavior the implementation does not provide.
  2. Functions and Methods Each function performs one coherent task at a consistent abstraction level. Function names describe their behavior; inputs and return values are understandable. Parameter lists are reasonable and related data is grouped where doing so clarifies the interface. Boolean flags do not select substantially different or unrelated behaviors. Side effects and mutations are explicit and unsurprising. Guard clauses or early returns reduce nesting where appropriate. Helpers are extracted to clarify concepts or isolate responsibilities, not merely to reduce line count. Functions do not unnecessarily mix domain logic, presentation, persistence, and I/O. Hidden dependencies and global mutable state are avoided where practical. Return values and failure behavior are predictable.
  3. Readability and Formatting Project formatting and language style conventions are followed. A formatter is used when the project provides one. Complex expressions are simplified or broken into well-named intermediate values when that improves comprehension. Deep nesting, complicated ternaries, clever one-liners, double negatives, and implicit coercion are avoided. Whitespace and file organization clarify logical structure. Parentheses make precedence clear when an expression might be misread. Unused imports, dead variables, and accidental dead code are removed when safe. Unrelated formatting churn is avoided. Code is not made less readable just to minimize line count.
  4. Comments and Documentation Comments explain why, constraints, invariants, non-obvious behavior, or trade-offs. Comments do not merely paraphrase nearby code. Comments remain accurate after behavior or interfaces change. Obsolete, misleading, redundant comments and commented-out code are removed when safe. Public contracts and important non-obvious behavior are documented accurately. Workarounds explain the reason or limitation they address when that context can be established. TODOs include useful context or a clear follow-up path. Rationale is not invented when the reason for existing code cannot be determined.
  5. Design and Architecture Each module or class has a cohesive, understandable responsibility. Dependencies are deliberate; unnecessary coupling and circular dependencies are avoided. Interfaces expose only what callers need. Related behavior and data are grouped when that improves cohesion. Composition and inheritance are chosen for concrete reasons. Deep inheritance hierarchies, god objects, and god modules are avoided. Domain logic is separated from I/O or framework concerns when doing so provides practical benefits. Layers and indirection exist to solve real problems rather than as ceremony. Abstractions, factories, interfaces, and design patterns provide a concrete benefit. Established repository architecture is respected unless a meaningful improvement is justified.
  6. Duplication and Complexity Duplicated business rules or knowledge have one authoritative implementation where appropriate. Similar-looking code is not forced into one abstraction when the concepts or change reasons differ. DRY is applied to duplicated knowledge, not indiscriminately to all repeated syntax. Premature generalization and speculative features are avoided. The design addresses current requirements without anticipating unsupported future needs (YAGNI). The simplest maintainable design is preferred. Complexity removed from one place is not merely hidden behind excessive indirection elsewhere. Refactoring is driven by a concrete problem, not stylistic preference alone.
  7. Variables, Data, and Types Variables have narrow scope and clear meaning. Values are declared close to their use and are not reused for unrelated meanings. Immutability is preferred when it prevents unnecessary mutation. Magic values are replaced by meaningful constants when they represent domain concepts or shared configuration. Appropriate data structures and precise types express intended contracts. Null, optional, missing, malformed, and invalid values are handled deliberately. Unsafe casts, broad types, and type-check suppressions are justified rather than used to hide uncertainty. Unnecessary data duplication is avoided. Ownership and mutation rules for shared state are clear. Global mutable state is avoided unless intentionally required by the architecture.
  8. Conditions and Control Flow Conditions are easy to read and verify. Invalid and exceptional cases are handled deliberately. Loops have clear termination conditions. Deeply nested branches and duplicated branches are simplified when doing so clarifies behavior. Exhaustive matching or equivalent compiler-supported checks are used when appropriate. Business rules remain visible rather than being buried in dense expressions. Control flow does not depend on accidental language behavior. Early returns are used when they make the main path easier to follow, not mechanically everywhere.
  9. Error Handling and Side Effects Errors are never silently swallowed. Errors are handled at the layer with enough context to respond appropriately. Expected failures are distinguished from programming errors where the language and design support this. Error messages include useful context without exposing secrets or sensitive information. Original causes are preserved when wrapping errors. Errors are not caught and rethrown unchanged unless the code adds context or deliberately changes the contract. Exceptions are not used as ordinary control flow when normal checks are clearer. External input and external service responses are validated before being trusted. Network calls have deliberate timeout and failure behavior where relevant. Retries are safe for the operation and do not blindly repeat non-idempotent actions. Resource cleanup is reliable on success and failure paths. Success-shaped results are not returned after an operation has failed.
  10. Testing Tests focus on observable behavior and contracts rather than private implementation details. Important success paths, edge cases, invalid inputs, and failure paths are covered. Tests are descriptive, focused, deterministic, and independent. Tests do not depend on execution order or shared external state without explicit control. Bug fixes include regression coverage when practical. Risky refactors are supported by characterization tests when existing behavior is poorly documented. Mocks and stubs are used where they add value, without over-mocking implementation details. Test assertions are not weakened merely to make a regression disappear. Coverage percentages are not treated as the sole measure of correctness. Test failures are investigated and classified as introduced, pre-existing, or unrelated.
  11. Security Input validation and authorization remain effective after refactoring. Server-side checks enforce security requirements; frontend checks are not treated as the sole protection. Database operations use parameterized or otherwise safe query patterns. Output is encoded appropriately for its destination. Secrets are never hardcoded or committed to version control. Passwords, access tokens, private keys, and sensitive personal data are not exposed in logs or errors. Least privilege is applied to users, processes, service accounts, and tokens where relevant. Cryptographic operations use established libraries rather than custom implementations. File paths, URLs, uploaded files, serialized input, and external payloads are treated as untrusted where appropriate. Security checks, validation, and access-control decisions remain explicit and testable. Refactoring does not introduce insecure defaults or weaken defensive behavior.
  12. Performance and Resource Management Performance changes are based on measurements or a clear resource hazard, not intuition alone. Redundant work, allocations, repeated calculations, and N+1 operations are avoided when relevant. Batching, caching, pagination, and concurrency are used only when justified by requirements and trade-offs. Cache invalidation and consistency requirements are understood before introducing or changing caching. Expensive operations and unbounded workloads have sensible limits. Files, sockets, connections, and other resources are released reliably. Concurrency and shared-state access are safe. Blocking work does not unnecessarily stall a context that must remain responsive. Performance improvements do not silently change correctness or observable behavior.
  13. Dependencies and External Interfaces Dependencies are justified; trivial functionality does not require an unnecessary package. Unused dependencies are removed only when their lack of use is verified and removal is in scope. Dependency versions and compatibility follow the repository's release strategy. Third-party APIs are isolated behind a boundary when it meaningfully reduces coupling. External systems are assumed to fail, time out, rate-limit, or return malformed data where applicable. Retry behavior accounts for idempotency and partial completion. External data is validated and normalized before entering trusted internal logic. Public interfaces, payload formats, persistence semantics, and compatibility contracts are preserved unless a change is authorized.
  14. Logging and Observability Important failures and events have useful context and appropriate severity. Structured logs and correlation/request identifiers are used where supported and useful. The same failure is not redundantly logged at every layer without a reason. Logs do not expose secrets or sensitive information. Logs are not used as a substitute for proper error handling. Excessive low-value logging does not obscure meaningful signals. Important production behavior can be monitored with appropriate metrics, traces, or health checks where relevant. Health checks accurately represent the condition they claim to measure.
  15. Configuration and Environments Environment-specific configuration is separated from business logic where appropriate. Required configuration is validated and missing or invalid values fail clearly. Defaults are explicit and safe. Secrets use appropriate environment or secret-management mechanisms. Configuration options and non-obvious settings are documented. Duplicate configuration is minimized unless intentional for a clear operational reason. Development, testing, staging, and production environments remain intentionally aligned. Environment-dependent behavior is deliberate and reproducible. Feature flags and configuration-dependent branches are easy to identify.
  16. Project Structure and Repository Conventions File organization makes related functionality easy to find. Each layer and directory has a clear purpose. Business logic is not scattered across unrelated files without a reason. Project conventions take precedence over personal stylistic preferences. Public exports and module boundaries are intentional. Generated files, build artifacts, and local caches are not edited or committed accidentally. Project-specific guidance such as CLAUDE.md, README files, and contribution rules is followed. Architecture changes are proportional to the actual problem and task scope.
  17. Version Control and Collaboration Existing user changes are preserved. The working tree and relevant diffs are inspected before editing. Changes are logically cohesive and limited to the requested scope. Unrelated formatting changes and drive-by refactors are avoided. The final diff is reviewed, including whitespace and generated changes. Commits, when requested, are small and have meaningful messages. Secrets, local caches, and machine-specific files are not included accidentally. Automated formatting, linting, testing, type checking, and relevant security checks are run when practical. Limitations and pre-existing failures are communicated honestly.
  18. Refactoring Existing Code Existing behavior and requirements are understood before changing implementation. Relevant callers, data flow, side effects, interfaces, and tests have been inspected. Fragile or poorly understood behavior is characterized with tests where practical. Structural refactoring is separated from behavior changes when feasible. Changes are made in small, verifiable steps. Broad rewrites are avoided unless supported by a concrete need and authorized scope. Dead code and duplicate logic are removed only after verifying they are not relied upon. Regression tests and integrations are checked, not just the edited function. The resulting code is easier to understand without adding unnecessary abstraction. Remaining technical debt, assumptions, and risks are recorded or reported where relevant.
  19. Common Code Smells Check for these when relevant; their presence is a signal to investigate, not automatic proof that a rewrite is needed.

God classes or modules with too many responsibilities. Long functions containing unrelated steps or abstraction levels. Deeply nested conditionals and complicated control flow. Duplicated business rules or repeated knowledge. Long conditional chains better expressed through a clear, suitable alternative. Long parameter lists or poorly structured data passed between layers. Primitive values repeatedly used to represent a meaningful domain concept. Boolean flags that select unrelated execution paths. Hidden side effects in functions that appear to be simple queries. Excessive global state, circular dependencies, or tight coupling. Premature optimization, premature abstraction, or needless design patterns. Catch-all exception handlers that hide failures. Magic constants scattered across the codebase. Dead code, unused variables, stale comments, or commented-out implementations. Unclear ownership of shared state and mutation. Functions that are hard to test because too many concerns are mixed together. Undocumented workarounds whose origin or purpose is no longer clear. 20. Final Review Questions Is the code correct and does it satisfy the requested requirements? Is intended behavior preserved, except for explicitly authorized changes? Is the intent easier to understand than before? Are names accurate and control flow reasonably simple? Do responsibilities, dependencies, inputs, outputs, and side effects remain clear? Is duplication reduced without adding unnecessary abstractions? Are edge cases, errors, security controls, and resource cleanup handled properly? Are important behaviors covered by appropriate tests? Were relevant formatting, linting, type checking, test, and build commands run where practical? Is every changed line related to the request or a justified adjacent fix? Are the exact validation results and any remaining limitations reported honestly? Core Principles When Rules Conflict Correctness before style. Do not damage behavior to satisfy a stylistic preference. Security and data integrity before convenience. Never simplify away a necessary protection. Clarity over cleverness. Prefer obvious solutions that are easy to reason about. Simplicity over unnecessary complexity. Use the least complex design that genuinely meets the requirements. Explicitness over hidden behavior. Make dependencies, side effects, and failure modes visible. Cohesion over excessive fragmentation. Keep related responsibilities together without creating oversized modules. DRY, but not at all costs. Centralize duplicated knowledge without forcing unrelated concepts together. YAGNI. Do not build for hypothetical requirements without evidence they are needed. SOLID when useful. Apply design principles to improve maintainability, not as a mechanical requirement. Boy Scout Rule. Leave the relevant code a little cleaner when making a change, without expanding scope uncontrollably. Measure before optimizing. Preserve correctness and use evidence for performance-focused changes. Project consistency matters. Follow established conventions unless they cause concrete problems.

Leave a Comment