advance-minimax-m3-cursor-rules / rules
madebyaris/advance-minimax-m3-cursor-rules/.cursor/rules/language-agnostic-patterns.mdc
Language-agnostic programming patterns: SOLID, design patterns, clean code, and architecture. Load when refactoring, designing abstractions, or reviewing structure — not for everyday syntax.
Cursor rule125 starsChanged 4 months ago
---
description: "Language-agnostic programming patterns: SOLID, design patterns, clean code, and architecture. Load when refactoring, designing abstractions, or reviewing structure — not for everyday syntax."
alwaysApply: false
---
# Language-Agnostic Programming Patterns
Universal principles for structure, naming, architecture, and testing — applicable across all languages.
Load this rule when refactoring modules, designing abstractions, reviewing architecture, or choosing patterns. For day-to-day coding workflow (read-before-edit, CI discovery, minimal diff, verification), the always-on core **Code Discipline** section is canonical — do not duplicate it here. For the judgment layer — root-cause method, simplicity taste, test integrity — load `fable5-coding-craft` alongside this rule.
---
## Pattern Judgment (Read First)
Everything below is vocabulary, not a checklist. Frontier-quality code applies patterns *reactively* — when the code's actual pain demands them — never proactively because a situation pattern-matches a textbook example.
- Every pattern has a cost: indirection, a new concept for readers, more files to trace through. Apply one only when the pain it removes is already present, not predicted.
- The strongest signal for an abstraction is the **third occurrence** of real duplication with identical reasons to change. Two similar blocks that change for different reasons are not duplication — unifying them couples things that must stay free.
- SOLID violations matter when they cause observed friction (a class you cannot test, a switch you keep re-editing). A small concrete class that "violates SRP" but has never needed to change is fine code — leave it alone.
- The best architecture for most changes is the one the repo already has. Pattern fluency is mostly for *reading* existing designs and for naming the structure a refactor is already growing toward.
- When reviewing, flag pattern *overuse* with the same severity as pattern absence: a Strategy with one strategy, a Factory with one product, or an interface with one implementation is indirection without payoff.
---
## Change Discipline
- Solve the requested problem with the smallest vertical slice; expand only after it works.
- Prefer extending existing modules over creating parallel implementations.
- When adding a dependency, confirm the repo does not already solve the same need.
- Keep public surfaces stable unless the task explicitly requires a breaking change.
- Leave the codebase in a compilable, testable state after each meaningful step.
---
## SOLID Principles
### Single Responsibility Principle (SRP)
A class/module should have only one reason to change.
**Apply when:**
- A function does multiple unrelated things
- A class has too many dependencies
- Changes in one area affect unrelated code
**Example Pattern:**
```
Bad: UserService handles auth, profile, notifications, and billing
Good: AuthService, ProfileService, NotificationService, BillingService
```
### Open/Closed Principle (OCP)
Open for extension, closed for modification.
**Apply when:**
- Adding new features requires modifying existing code
- Switch statements grow with each new type
- Core logic changes for edge cases
**Example Pattern:**
```
Bad: if type == "email" ... elif type == "sms" ... elif type == "push" ...
Good: NotificationStrategy interface with EmailStrategy, SMSStrategy, PushStrategy
```
### Liskov Substitution Principle (LSP)
Subtypes must be substitutable for their base types.
**Apply when:**
- Derived classes override behavior in unexpected ways
- Code checks for specific types before operating
- Inheritance creates illogical hierarchies
**Example Pattern:**
```
Bad: Square extends Rectangle but can't independently set width/height
Good: Both Square and Rectangle implement Shape interface
```
### Interface Segregation Principle (ISP)
Clients shouldn't depend on interfaces they don't use.
**Apply when:**
- Classes implement methods they don't need
- Interfaces have too many methods
- Changes affect many unrelated implementations
**Example Pattern:**
```
Bad: Animal interface with fly(), swim(), walk() - Penguin can't fly
Good: Flyable, Swimmable, Walkable interfaces
```
### Dependency Inversion Principle (DIP)
Depend on abstractions, not concretions.
**Apply when:**
- High-level modules import low-level modules directly
- Changing database/service requires code changes
- Testing requires real dependencies
**Example Pattern:**
```
Bad: UserService directly imports MySQLDatabase
Good: UserService depends on DatabaseInterface, injected at runtime
```
## Common Design Patterns
### Creational Patterns
#### Factory Pattern
Use when object creation logic is complex or needs to be centralized.
```
When to use:
- Multiple similar objects with different configurations
- Object creation depends on runtime conditions
- Hiding complex initialization logic
```
#### Builder Pattern
Use for constructing complex objects step by step.
```
When to use:
- Objects with many optional parameters
- Complex configuration requirements
- Need for immutable objects with many fields
```
#### Singleton Pattern
Use sparingly for truly global, single-instance resources.
```
When to use:
- Configuration managers
- Connection pools
- Logger instances
Avoid when:
- It's just for convenience (use DI instead)
- Testing would be difficult
- Multiple instances might be needed later
```
### Structural Patterns
#### Adapter Pattern
Convert one interface to another that clients expect.
```
When to use:
- Integrating third-party libraries
- Working with legacy code
- Unifying different data sources
```
#### Decorator Pattern
Add behavior to objects dynamically.
```
When to use:
- Adding features without subclassing
- Composable behaviors
- Middleware-like patterns
```
#### Facade Pattern
Provide a simplified interface to a complex subsystem.
```
When to use:
- Simplifying complex library usage
- Creating API boundaries
- Reducing coupling between layers
```
### Behavioral Patterns
#### Strategy Pattern
Define a family of interchangeable algorithms.
```
When to use:
- Multiple algorithms for the same task
- Runtime algorithm selection
- Avoiding complex conditionals
```
#### Observer Pattern
Notify dependents of state changes.
```
When to use:
- Event-driven systems
- Pub/sub messaging
- Reactive data flows
```
#### Command Pattern
Encapsulate requests as objects.
```
When to use:
- Undo/redo functionality
- Queueing operations
- Macro recording
```
## Clean Code Principles
### Naming Conventions
#### Variables and Functions
- Use intention-revealing names
- Avoid abbreviations unless universally understood
- Be consistent with terminology
```
Bad: d, tmp, data, info, process()
Good: elapsedTimeInDays, userProfile, activeConnections, validatePayment()
```
#### Booleans
- Use positive names (avoid double negatives)
- Start with is/has/can/should
```
Bad: notDisabled, flag, status
Good: isEnabled, hasPermission, canEdit, shouldRefresh
```
#### Functions
- Use verbs for actions
- Be specific about what they do
```
Bad: handle(), process(), manage()
Good: validateUserInput(), calculateTotalPrice(), sendConfirmationEmail()
```
### Function Design
#### Keep Functions Small
- Do one thing well
- 5-20 lines is ideal
- If you can't name it well, it's probably doing too much
#### Limit Parameters
- 0-3 parameters is ideal
- Use objects for more
- Consider builder pattern for complex initialization
#### Avoid Side Effects
- Functions should be predictable
- Clearly document mutations
- Prefer pure functions when possible
### Comments
#### When to Comment
- Explain WHY, not WHAT
- Document public APIs
- Warn about non-obvious behavior
- Link to external resources/tickets
#### When NOT to Comment
- Explaining what code does (make code clearer instead)
- Commented-out code (delete it)
- Redundant descriptions
- TODOs without tickets
```
Bad: // increment counter by 1
counter += 1;
Good: // Retry limit based on SLA requirements (see JIRA-1234)
MAX_RETRIES = 3;
```
### Error Handling
Match the repo's existing error style (exceptions, `Result`/`error`, error codes, etc.) before introducing a new pattern.
#### Fail Fast
- Validate inputs early
- Throw exceptions for unexpected states
- Don't swallow errors silently
#### Error Messages
- Include context (what was being done)
- Include relevant values
- Suggest remediation when possible
```
Bad: "Error occurred"
Good: "Failed to connect to database 'users' at localhost:5432: Connection refused. Check if PostgreSQL is running."
```
#### Error Categories
1. **Recoverable**: Retry, fallback, or prompt user
2. **Validation**: Return clear error to caller
3. **Programming**: Fail fast, fix the bug
4. **System**: Log, alert, graceful degradation
## Architecture Patterns
### Layered Architecture
```
Presentation → Business Logic → Data Access → Database
```
- Each layer only talks to adjacent layers
- Dependencies flow downward
### Clean Architecture
```
Entities → Use Cases → Controllers → Frameworks
```
- Business rules at the center
- Frameworks/DB at the edges
- Dependency rule: inward only
### Hexagonal Architecture (Ports & Adapters)
```
[Adapters] → [Ports] → [Core Domain] ← [Ports] ← [Adapters]
```
- Core domain is isolated
- Ports define interfaces
- Adapters implement external concerns
### When to Choose What
- **Layered**: Simple CRUD apps, rapid development
- **Clean**: Complex business logic, long-lived systems
- **Hexagonal**: Multiple interfaces, testability focus
## Testing Principles
### Test Pyramid
```
/\
/ \ E2E Tests (few)
/----\ Integration Tests (some)
/------\ Unit Tests (many)
```
### Unit Tests
- Test one thing in isolation
- Fast and deterministic
- Mock external dependencies
### Integration Tests
- Test component interactions
- Use real (or realistic) dependencies
- Focus on boundaries
### End-to-End Tests
- Test complete user flows
- Slowest and most brittle
- Use for critical paths only
### Test Quality
- Tests are documentation
- One assertion per test when possible
- Arrange-Act-Assert pattern
- Test behavior, not implementation
## Performance Principles
### Measure First
- Don't optimize prematurely
- Profile before changing
- Set performance budgets
### Common Optimizations
- **Caching**: Memoization, HTTP caching, query caching
- **Batching**: Combine multiple operations
- **Lazy Loading**: Defer until needed
- **Pagination**: Don't load everything at once
### Database Performance
- Index frequently queried columns
- Avoid N+1 queries
- Use connection pooling
- Consider read replicas for scale
## Security Best Practices
### Input Validation
- Validate all external input
- Whitelist, don't blacklist
- Sanitize before use
### Authentication
- Use established libraries
- Hash passwords with strong algorithms
- Implement rate limiting
- Use HTTPS everywhere
### Authorization
- Check permissions on every request
- Fail closed (deny by default)
- Log access attempts
### Data Protection
- Encrypt sensitive data at rest
- Use parameterized queries
- Don't log sensitive information
- Implement proper session management
## Code Organization
### Module Structure
```
Feature-based (preferred for larger apps):
/features
/auth
- service
- controller
- repository
/products
- service
- controller
- repository
Layer-based (simpler for smaller apps):
/controllers
/services
/repositories
```
### File Naming
- Consistent conventions across project
- Reflect content purpose
- Include type suffix when helpful (e.g., `.service`, `.controller`)
### Import Organization
1. Standard library
2. Third-party packages
3. Local modules
4. Relative imports
---
## Code Review Heuristics
Use when reviewing diffs, PRs, or your own work before closeout. Complements core **Code Discipline** and the always-on verification contract.
### Correctness
- Does the change solve the stated problem, or only a symptom?
- Are edge cases handled the way this repo handles them (null/empty, auth, timeouts)?
- Do error paths propagate or log usefully — no silent swallowing?
- If behavior changed, are callers, tests, and docs updated?
### Scope & maintainability
- Is the diff the smallest honest fix? Any unrelated refactors or drive-by renames?
- Does new code match naming, layering, and error style of surrounding files?
- New abstraction justified by reuse, or premature?
- New dependency necessary, or does the repo already cover the need?
### Tests & verification
- Is there a test or check proportional to the risk? If not, is that gap called out as `unverified`?
- Do tests assert behavior, not implementation details?
- Would CI scripts in this repo catch a regression from this change?
### Security & data
- User/external input validated and parameterized (SQL, shell, HTML)?
- Secrets, tokens, or PII absent from logs, commits, and client bundles?
- AuthZ checked on the server for every sensitive action — not only UI gating?
### Performance (when relevant)
- N+1 queries, unbounded loops, or loading entire datasets into memory?
- Caching added only where measured or clearly hot-path?
### Review output shape
Keep feedback actionable: **issue → impact → suggested fix**. Separate blocking concerns from nits. Prefer pointing to existing repo patterns over generic style opinions.
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

