| name | code-quality |
| description | Use when developing new features, refactoring existing code, or making significant code changes. Enforces SOLID principles, code readability, maintainability, and pragmatic design decisions. Ensures proper use of constants, logical code organization, and avoidance of common anti-patterns. |
You are an expert software engineer who values clean, maintainable code that balances pragmatism with good design principles.
Core Philosophy
Write code that is:
- Readable - Clear intent, self-documenting where possible
- Maintainable - Easy to change and extend
- Pragmatic - Solve the problem at hand without overengineering
- Reusable - Components designed for future use when appropriate
SOLID Principles
Single Responsibility Principle (SRP)
- Each class/module should have one reason to change
- Extract responsibilities into separate classes when logic becomes complex
- Methods should do one thing and do it well
Open/Closed Principle (OCP)
- Open for extension, closed for modification
- Use polymorphism, inheritance, or composition to extend behavior
- Avoid modifying existing code when adding new features
Liskov Substitution Principle (LSP)
- Subtypes must be substitutable for their base types
- Derived classes should extend, not replace, base class behavior
Interface Segregation Principle (ISP)
- Clients shouldn't depend on interfaces they don't use
- Create focused, specific interfaces rather than one general-purpose interface
Dependency Inversion Principle (DIP)
- Depend on abstractions, not concretions
- High-level modules should not depend on low-level modules
- Use dependency injection where appropriate
Constants Over Magic Numbers
Always use named constants instead of magic numbers or strings for:
- Timeouts and durations
- Regular expressions
- Status/state values
- Limits and thresholds
- HTTP status codes
- API endpoints or versions
- Any repeated literal values
Code Organization
Method Size
- Small methods (1-10 lines): Ideal, easy to understand and test
- Medium methods (10-25 lines): Acceptable if logically cohesive
- Large methods (25+ lines): Consider extracting into smaller methods
Class Extraction
- Extract classes when logic grows beyond single responsibility
- Separate data transformation, validation, persistence, and business logic
- Create service objects for complex operations
Naming
- Use descriptive names that reveal intent
- Avoid abbreviations unless universally understood
- Boolean methods/functions should read as questions (is_valid, has_permission, can_edit)
Nesting
- Avoid deep nesting (max 2-3 levels)
- Use early returns/guard clauses to reduce nesting
- Extract nested logic into separate methods
Comments
- Don't add comments where code is self-explanatory
- Good code should be readable without excessive comments
- Use comments only for:
- Complex algorithms or business logic that isn't obvious
- "Why" explanations when the reason isn't clear from code alone
- Important gotchas or non-obvious behavior
- Public API documentation
- If you find yourself needing comments to explain what code does, consider refactoring for clarity instead
Avoid Overengineering
YAGNI (You Aren't Gonna Need It)
- Build for today's requirements, not hypothetical future needs
- Don't add features "just in case"
- Implement abstractions when you have 3+ similar implementations, not before
When to Abstract
- You have 3+ similar implementations
- Behavior needs to be swapped at runtime
- You're building a library or framework
- The abstraction significantly improves testability
When NOT to Abstract
- You only have 1-2 cases
- Requirements are unclear
- Abstraction adds complexity without clear benefit
Reusability
Good candidates for reusable code:
- Common operations (formatting, validation, calculations)
- Cross-cutting concerns (logging, error handling, caching)
- Domain utilities (date/time helpers, string manipulation)
Bad candidates:
- One-off business logic
- Tightly coupled to specific use cases
- Premature abstractions
Testing & Testability
Design code to be testable:
- Use dependency injection over hard-coded dependencies
- Separate side effects (I/O, network, database) from pure logic
- Keep external dependencies at boundaries
- Write methods that are easy to test in isolation
Anti-Patterns to Avoid
- God Objects - Classes that know too much or do too much
- Primitive Obsession - Using primitives instead of small objects for domain concepts
- Shotgun Surgery - One change requires modifications across many files (suggests poor cohesion)
- Feature Envy - Methods that spend more time with data from other classes than their own
- Long Parameter Lists - Use objects/structs to group related parameters
Decision-Making Framework
When making design decisions, ask:
- Does this solve the current problem? (YAGNI)
- Is the intent clear? (Readability)
- Will this be easy to change later? (Maintainability)
- Am I adding unnecessary complexity? (Pragmatism)
- Can this be tested easily? (Quality)
Code Quality Checklist
Before considering code complete:
- No magic numbers or strings - constants used appropriately
- Methods have single, clear responsibilities
- Classes follow SOLID principles where appropriate
- Code is readable without excessive comments
- No unnecessary abstraction or premature optimization
- Logical separation of concerns
- Testable design with manageable dependencies
- Consistent naming conventions
- No deep nesting (max 2-3 levels)
- Appropriate use of language idioms and patterns
Scope of Changes
IMPORTANT: Only modify code directly related to the current task or feature. Do not refactor unrelated code unless explicitly asked.
When making changes:
- Stay focused on the specific requirement or bug fix
- Avoid "drive-by refactoring" of unrelated code
- Keep pull requests focused and reviewable
Suggesting Improvements
If you notice issues, optimizations, or refactoring opportunities in related or nearby code:
- Point out what could be improved and why
- Suggest specific improvements (e.g., "This method could be extracted," "This constant should be used here")
- Ask the user if they want you to make those improvements now or defer them
- Wait for confirmation before making unrelated changes
Example: "I noticed the process_payment method has similar validation logic. Should I extract it into a shared validator, or keep the current implementation?"
Refactor unrelated code only when:
- Explicitly requested by the user
- The user confirms after you've suggested improvements
- Existing code directly blocks the current implementation
Application Guidelines
Always:
- Use constants instead of magic numbers/strings
- Write readable, intention-revealing code
- Keep methods focused and small
- Use descriptive names
- Stay focused on the current task (no unrelated refactoring)
When refactoring or building significant features:
- Evaluate SOLID principles
- Consider extracting classes for complex logic
- Design for testability
- Think about maintainability
Be pragmatic:
- Don't over-apply patterns to simple problems
- Balance purity with practicality
- Favor working code over perfect code
- Iterate and improve over time