Use when adding new error messages to React, or seeing "unknown error code" warnings.
0
0
# Install this skill:
npx skills add iceflower/opencode-agents-and-skills --skill "code-quality"
Install specific skill from multi-skill repository
# Description
>-
# SKILL.md
name: code-quality
description: >-
Code quality and design principles.
Use when writing, reviewing, or refactoring code.
Code Quality and Design Principles
1. Code Quality Pillars
Every piece of code should satisfy these six qualities:
- Readable: Other developers must understand the intent immediately
- Predictable: Code behaves as callers expect with no hidden surprises
- Hard to misuse: The API makes incorrect usage difficult or impossible
- Modular: Each unit has a single, well-defined responsibility
with minimal coupling - Reusable and generalizable: Code avoids unnecessary assumptions
and can be adapted without modification - Testable: Code can be verified through automated tests
without excessive setup
2. Abstraction Layers
Layer Separation
- Each layer of code should solve one well-defined problem
and provide a clean API to the layer above - Implementation details must not leak through the public API
- If a function or class operates at mixed abstraction levels,
split it
API Design
- Public APIs define the contract β
they must be minimal, clear, and stable - Functions should do one thing at one level of abstraction
- Classes should encapsulate a single coherent concept
- Interfaces should define the minimal set of operations
a caller needs
Null Values and Pseudo-Code Contracts
- Prefer explicit types (Optional, sealed class, Result)
over null to represent absence - When null is unavoidable, document the contract clearly
3. Code Contracts with Other Developers
Your Code vs Others' Code
- Assume your public API will be called by developers
who haven't read your implementation - Design APIs so that correct usage is obvious
and incorrect usage fails fast
Checks and Assertions
- Precondition checks: Validate inputs at public API boundaries
and fail immediately with clear messages - Assertions: Use for internal invariants that should never
be violated β these signal bugs, not user errors - Do NOT silently swallow invalid states β
make violations visible
Immutable Objects
- Prefer immutable objects by default β
they eliminate accidental mutation bugs - If mutability is needed, limit the scope of mutable state
- Immutable objects are inherently thread-safe
and easier to reason about
4. Error Handling
Recoverability
- Classify errors by whether the caller can reasonably recover:
- Recoverable: invalid user input, network timeout,
missing optional resource β signal to caller - Unrecoverable: programming bugs,
corrupted state β fail fast
Robustness vs Fail-Fast
- Fail fast for programming errors β
hiding bugs causes worse failures later - Be robust at system boundaries (user input, external APIs)
β validate and handle gracefully - Never silently ignore errors β
either handle them or propagate them explicitly
Error Signaling Strategy
| Strategy | When to use |
|---|---|
| Checked exception | Caller MUST handle this error |
| Unchecked exception | Programming bug, should not occur |
| Result/Either type | Functional error handling |
| Optional/nullable return | Absence is a normal outcome |
- Be consistent within a codebase β
do not mix strategies arbitrarily - Make error information specific enough
to diagnose the problem
Compiler Warnings
- Never ignore compiler warnings β treat them as errors
- Warnings often indicate latent bugs that will surface later
5. Readability
Descriptive Naming
- Names should describe WHAT, not HOW
- Avoid abbreviations that aren't universally understood
- Use names that distinguish the purpose from similar concepts
Comments
- β Do NOT comment WHAT the code does β
the code itself should be clear - β
Comment WHY β
the reasoning, constraints, or non-obvious decisions - Remove outdated comments immediately β
misleading comments are worse than none
Avoid Deep Nesting
- Deep nesting (3+ levels) severely harms readability
- Use early returns, guard clauses, or extract functions
to flatten structure - Each nesting level adds cognitive load
Eliminate Magic Numbers
- Replace literal values with named constants
- The name should explain the meaning, not just the value
- Configuration values should be externalized,
not embedded in code
Function Calls as Documentation
- Function and method calls should read like
a description of the operation - Avoid boolean parameters β they obscure intent
at the call site. Prefer enums or separate methods
6. Predictable Code
Minimize Side Effects
- Functions should primarily communicate
through their return values - Side effects (modifying external state, I/O, logging)
should be explicit and documented - Avoid functions that silently modify their arguments
Null Safety
- Never return null when the caller expects a value β
use Optional or throw - Never accept null as a parameter
unless explicitly documented - Prefer the type system to enforce null safety
over runtime checks
Clear Inputs and Outputs
- Function signatures should make the data flow obvious
- Avoid using mutable shared state
as an implicit input/output channel - If a function needs many inputs,
consider grouping them into a dedicated parameter object
Beware of Unexpected Side Effects
- A getter should never modify state
- A validation method should never fix the data
- Name functions honestly β
if it has side effects, the name must reflect them
7. Hard to Misuse
Immutable by Default
- Make fields
final/val/readonly
unless mutation is explicitly required - Return unmodifiable collections from public APIs
- Use copy-on-write or defensive copying
when exposing internal state
Use Enums Over Constants
- When a value belongs to a fixed set,
use an enum β not string/int constants - Enums enable exhaustive matching
and prevent invalid values at compile time
Access Restriction
- Expose the minimum visibility necessary
(private>internal>public) - Package-private/internal visibility is preferable
to public for implementation classes - Avoid making things public "just in case" β
expanding visibility is easy, restricting it is hard
Make Temporal Dependencies Explicit
- If operations must occur in a specific order,
enforce it through the API design
(e.g., builder pattern, state machine) - Do not rely on documentation alone
to communicate ordering requirements
8. Modularity
Single Responsibility
- Each class/module should have exactly one reason to change
- If a class description requires "and",
it likely has multiple responsibilities β split it
Dependency Injection
- Do not hard-code dependencies β
accept them through constructors - DI improves testability, flexibility,
and makes dependencies visible - Combine static factory methods with constructor injection
for production convenience
Composition Over Inheritance
- Prefer composition (
has-a) over inheritance (is-a) - Inheritance creates tight coupling and fragile hierarchies
- Use inheritance only when there is a genuine
"is-a" relationship AND the superclass
is designed for extension
Interface Segregation
- Clients should not depend on methods they don't use
- Split large interfaces into smaller, focused ones
- A class can implement multiple small interfaces
Minimize Inter-Module Dependencies
- Depend on abstractions, not concrete implementations
- Keep the dependency graph shallow and acyclic
- If two modules are tightly coupled,
consider merging them or extracting a shared abstraction
9. Reusability and Generalization
Minimize Assumptions
- Do not assume the caller's context β
design for the general case - Avoid embedding business rules in utility code
- Parameterize behavior instead of hard-coding decisions
Return Type Flexibility
- Return the most general type
that provides the needed functionality - Returning
Listinstead ofArrayList
allows implementation changes without breaking callers - For collections, consider returning immutable views
Global State
- Avoid global mutable state β
it creates hidden dependencies and makes testing difficult - If shared state is necessary,
encapsulate it behind a clear interface - Prefer explicit parameter passing over ambient context
Keep Reuse Pragmatic
- Do not prematurely generalize β
extract common code only when duplication actually occurs - Three occurrences is a reasonable threshold
for extraction (Rule of Three) - Over-abstraction is as harmful as duplication
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Amp
Antigravity
Claude Code
Clawdbot
Codex
Cursor
Droid
Gemini CLI
GitHub Copilot
Goose
Kilo Code
Kiro CLI
OpenCode
Roo Code
Trae
Windsurf
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.