| name | coding-standards |
| description | Guide for writing clean, maintainable code following industry best practices and design principles like DRY, SOLID, and composition patterns. Use when writing any code to ensure consistency, readability, and long-term maintainability across all programming languages. |
| license | MIT |
| compatibility | Works with Claude Code and OpenAI Codex. Language-agnostic with specific guidance for Python, TypeScript, Java, Go, Rust. |
| metadata | [object Object] |
Coding Standards & Design Principles Guide
Overview
This skill ensures you write high-quality, maintainable code that follows industry best practices. Use this whenever you're writing code, reviewing code, or refactoring existing implementations. The principles here apply across all programming languages, with specific considerations for different contexts.
Core Philosophy:
- Clarity over cleverness - Code is read more often than written
- Practical pragmatism - Apply patterns when they add value, not dogmatically
- Evolution-friendly - Design for change and future extension
- Team-oriented - Write code others (including future you) can understand
Process
🚀 High-Level Workflow
Writing quality code involves three main phases:
Phase 1: Planning and Design
1.1 Understand Core Design Principles
Before writing code, internalize these fundamental principles:
DRY (Don't Repeat Yourself):
- Extract duplicated logic when the same code appears 3+ times
- Create reusable functions/methods/classes for shared behavior
- BUT: Don't abstract prematurely - two instances might just be coincidence
- Balance: Readability > DRY for simple, self-explanatory code
- Example: If you see identical validation logic in 3 endpoints, extract it
SOLID Principles:
S - Single Responsibility Principle (SRP):
- Each class/function should do one thing and do it well
- If you can't describe what it does in one sentence without "and", it's doing too much
- Red flag: Functions with names like
processAndValidateAndSaveUser() - Good: Separate
validateUser(),processUser(),saveUser()
O - Open/Closed Principle:
- Open for extension, closed for modification
- Use interfaces, abstract classes, or composition to allow new behavior without changing existing code
- Example: Plugin architecture instead of giant switch statements
L - Liskov Substitution Principle:
- Subclasses should be substitutable for their base classes
- Don't break contracts - if parent returns non-null, child shouldn't return null
- Red flag: Subclass that throws NotImplementedException for parent methods
I - Interface Segregation Principle:
- Many specific interfaces are better than one general-purpose interface
- Clients shouldn't depend on methods they don't use
- Example:
IReadableandIWritableinstead ofIFileOperationswith unused methods
D - Dependency Inversion Principle:
- Depend on abstractions, not concrete implementations
- High-level modules shouldn't depend on low-level modules
- Use: Dependency injection, interface-based design
Composition Over Inheritance:
- Favor "has-a" relationships over "is-a"
- Inheritance creates tight coupling; composition provides flexibility
- Example: Use strategy pattern instead of inheritance hierarchies
- Guideline: More than 2-3 inheritance levels is usually a smell
YAGNI (You Aren't Gonna Need It):
- Don't build features "just in case" or "for the future"
- Add complexity only when actually needed
- Balance: Don't over-engineer, but leave sensible extension points
KISS (Keep It Simple, Stupid):
- Simple solutions are easier to understand, test, and maintain
- If a junior developer can't understand it, it's probably too complex
- Question: "Is there a simpler way to achieve the same goal?"
1.2 Plan Your Approach
Before writing code, ask yourself:
Functionality:
- What is the single responsibility of this code?
- What are the inputs, outputs, and side effects?
- What are the error cases and how should they be handled?
Reusability:
- Is there existing code that does something similar?
- Will this logic be needed elsewhere?
- What's the right level of abstraction?
Dependencies:
- What external dependencies does this need?
- Can dependencies be injected rather than hard-coded?
- Are we depending on abstractions or concrete implementations?
Testing:
- How will this be tested?
- Are we writing testable code (pure functions, dependency injection)?
- What are the edge cases?
1.3 Design the Interface First
Before implementation, design the public interface:
- What will consumers of this code need?
- What parameters are required vs optional?
- What does success look like? What about failure?
- How will this be documented?
Consider:
- Function/method signatures
- Class constructors and public methods
- Return types and error handling strategy
- Naming conventions
Phase 2: Implementation
2.1 Code Organization
File Structure:
- One class per file (for OOP languages)
- Group related functionality in modules/packages
- Keep files under 300-500 lines (guideline, not rule)
- Organize imports: stdlib → third-party → local
Function/Method Length:
- Aim for 20-30 lines max per function
- If longer, can you extract helper functions?
- Exception: Sometimes a long, linear function is clearer than over-decomposition
Class Length:
- Aim for under 200-300 lines per class
- If larger, consider if it has multiple responsibilities
- Extract inner classes or create new classes
2.2 Naming Conventions
Critical Rules:
- Names should reveal intent:
getUserById()notget() - Avoid abbreviations unless universally known:
HTTPis fine,usrLstis not - Be consistent within the codebase
- Use domain language that business stakeholders understand
Specific Guidelines:
Variables:
- Use nouns:
userCount,activeConnections,databasePool - Boolean: Prefix with
is,has,can:isValid,hasAccess,canDelete - Avoid single letters except for:
i, j, k(loop indices),x, y(coordinates),e(exceptions)
Functions/Methods:
- Use verbs:
calculateTotal(),fetchUser(),validateEmail() - Predicates return boolean:
isEmpty(),hasPermission() - Commands vs Queries: Separate functions that change state from those that return data
Classes:
- Use nouns:
UserRepository,EmailValidator,PaymentProcessor - Avoid "Manager", "Helper", "Utility" names - they hide responsibility
- If you need them, be specific:
DatabaseConnectionManagernotManager
Constants:
- All caps with underscores:
MAX_RETRY_ATTEMPTS,DEFAULT_TIMEOUT - Group related constants in enums or dedicated modules
2.3 Function Design
Parameters:
- Ideal: 0-2 parameters
- Acceptable: 3 parameters
- Avoid: 4+ parameters (use parameter objects/configs)
- Example: Instead of
createUser(name, email, age, country, preferences, settings), usecreateUser(UserCreateRequest request)
Return Values:
- Be consistent: Don't mix null, undefined, empty arrays, and exceptions for "no data"
- Prefer explicit error handling over null: Result types, Option types, or exceptions
- Return early to avoid deep nesting
Side Effects:
- Document all side effects in function documentation
- Separate query operations (read) from command operations (write)
- Minimize hidden side effects (global state, file I/O, etc.)
Pure Functions When Possible:
- Same inputs always produce same outputs
- No side effects
- Easier to test, reason about, and parallelize
- Example:
calculateTax(amount, rate)is pure;updateUserInDatabase(user)is not
2.4 Error Handling
General Principles:
- Fail fast: Validate inputs early
- Provide actionable error messages
- Don't swallow exceptions silently
- Use specific exception types
Error Handling Strategies:
Exceptions (for exceptional situations):
- Use for truly exceptional conditions, not control flow
- Provide context: What failed, why, and what to do about it
- Clean up resources (use try-finally or context managers)
Return Values (for expected failures):
- Use Result/Option types for operations that commonly fail
- Example:
findUser()returnsOption<User>orResult<User, NotFoundError> - Avoid null/undefined when possible
Validation:
- Validate at system boundaries (API endpoints, database queries)
- Use type systems and schema validation
- Return structured validation errors
Logging:
- Log actionable information
- Include context: user ID, request ID, timestamp
- Use appropriate levels: ERROR for failures, WARN for degraded state, INFO for significant events
2.5 Comments and Documentation
When to Comment:
- WHY, not WHAT: Explain the reasoning, not the obvious
- ❌
// Increment counter by 1 - ✅
// Skip first item as it contains headers
- ❌
- Complex algorithms: Explain the approach
- Non-obvious business rules
- TODO/FIXME with context and owner
When NOT to Comment:
- Self-explanatory code (use better names instead)
- Commented-out code (use version control)
- Obvious statements
Documentation (Doc Comments):
- Public APIs: Always document
- Complex internal functions: Document
- Simple, self-explanatory functions: Optional
Include:
- Purpose and behavior
- Parameter descriptions with types and constraints
- Return value description
- Exceptions/errors that can be thrown
- Usage examples for complex APIs
2.6 Code Quality Practices
Avoid Deep Nesting:
- Maximum 3 levels of indentation
- Use early returns/guards
- Extract complex conditions into well-named functions
Example:
// ❌ BAD:
if (user !== null) {
if (user.isActive) {
if (user.hasPermission("write")) {
// do something
}
}
}
// ✅ GOOD:
if (user === null) return;
if (!user.isActive) return;
if (!user.hasPermission("write")) return;
// do something
Avoid Long Parameter Lists:
- Use parameter objects/configs for 4+ parameters
- Consider builder pattern for objects with many optional parameters
Avoid Magic Numbers:
- Define constants with descriptive names
- ❌
if (status === 404) - ✅
if (status === HTTP_NOT_FOUND)
Consistent Formatting:
- Use automated formatters (Prettier, Black, gofmt)
- Follow language-specific style guides
- Be consistent within the project
Minimize Global State:
- Prefer dependency injection over global singletons
- Use function parameters instead of accessing global variables
- Make mutability explicit and minimal
Phase 3: Review and Refine
3.1 Self-Review Checklist
Before considering code complete, verify:
Design Principles:
- Each function/class has a single, clear responsibility
- No code duplication (DRY applied where it adds value)
- Dependencies are injected, not hard-coded
- Code is open for extension, closed for modification
- Abstractions don't leak implementation details
Code Quality:
- Names clearly express intent
- Functions are short and focused (< 30 lines typically)
- No deep nesting (< 3 levels)
- No magic numbers or strings
- Consistent formatting and style
Error Handling:
- Input validation at boundaries
- Meaningful error messages
- Resources properly cleaned up
- No swallowed exceptions
Testing:
- Code is testable (minimal dependencies, pure functions where possible)
- Edge cases identified
- Test coverage for critical paths
Documentation:
- Public APIs documented
- Complex logic has explanatory comments
- Non-obvious decisions explained
Performance:
- No obvious inefficiencies (N+1 queries, unnecessary loops)
- Appropriate data structures chosen
- No premature optimization
Security:
- Input sanitized/validated
- Sensitive data not logged
- Authentication/authorization checked
3.2 Refactoring Opportunities
Code Smells to Watch For:
Long Functions/Methods:
- Extract smaller, well-named functions
- Each function should do one thing
Large Classes:
- Consider if class has multiple responsibilities
- Extract collaborating classes
Long Parameter Lists:
- Use parameter objects or builder pattern
- Consider if function is doing too much
Primitive Obsession:
- Create domain objects instead of passing primitives
- Example:
Emailclass instead of raw strings
Feature Envy:
- Method uses another class's data more than its own
- Move method to the class whose data it uses
Data Clumps:
- Same group of parameters appears together repeatedly
- Extract into a dedicated object
Switch Statements:
- Consider polymorphism or strategy pattern
- Especially if same switch appears in multiple places
Comments:
- If you need a comment to explain what code does, consider better naming
- If explaining why, the comment is valuable
For language-specific best practices and examples, see references/LANGUAGE-SPECIFICS.md.
For detailed code examples demonstrating these principles, see references/EXAMPLES.md.
Quick Reference
When to Apply Each Principle
Use DRY when:
- Same logic appears 3+ times
- The abstraction is clear and natural
- Changes to the logic should affect all uses
Don't use DRY when:
- Two similar pieces of code serve different purposes
- The abstraction would be more complex than duplication
- Code is unlikely to change together
Use SRP when:
- Class/function is hard to name without "and"
- Changes for one reason affect unrelated functionality
- Testing requires mocking many dependencies
Use Dependency Injection when:
- Testing with mock dependencies
- Supporting multiple implementations
- Configuration needs to vary by environment
Use Composition when:
- Multiple inheritance creates diamond problem
- Behavior needs to be mixed and matched
- Inheritance depth exceeds 2-3 levels
Keep It Simple when:
- Always - start simple, add complexity only when needed
- You're tempted to use advanced patterns
- Junior developers will maintain the code
Common Anti-Patterns to Avoid
- God Objects: Classes that do everything
- Shotgun Surgery: One change requires editing many files
- Spaghetti Code: No clear structure, everything connected
- Copy-Paste Programming: Duplicating code instead of abstracting
- Golden Hammer: Using favorite pattern everywhere
- Premature Optimization: Optimizing before measuring
- Not Invented Here: Reimplementing existing solutions
- Analysis Paralysis: Over-planning without implementing
Final Notes
Remember:
- These are guidelines, not laws - apply them with judgment
- Consistency within a codebase matters more than perfect adherence
- Write code for humans first, machines second
- When in doubt, favor simplicity and clarity
- Refactor continuously - don't let technical debt accumulate
The Goal: Write code that is:
- Easy to understand
- Easy to change
- Easy to test
- Easy to debug
- Easy to extend
If your code achieves these goals, you're on the right track.