It’s got SOLID principles, clean code practices, and JavaScript tweaks.
# SOLID Design Principles - JavaScript Coding Assistant Guidelines
When generating, reviewing, or modifying JavaScript code, follow these guidelines to
ensure adherence to SOLID principles:
## 1. Single Responsibility Principle (SRP)
- Each module or function must have only one reason to change.
- Limit module scope to a single functional area or abstraction level.
- When a module exceeds 100-150 lines, consider if it has multiple responsibilities.
- Separate cross-cutting concerns (logging, validation, error handling) from business logic using dedicated functions or modules.
- Create separate files for distinct operations like data access, business rules, and UI logic.
- Function names should clearly indicate their singular purpose.
- If a function description requires "and" or "or", it likely violates SRP.
- Prioritize composition over inheritance using JavaScript objects or higher-order functions.
## 2. Open/Closed Principle (OCP)
- Design modules to be extended without modification.
- Use interfaces (via object shapes or abstract-like contracts) to define stable contracts.
- Implement extension points with callbacks or plugin systems for anticipated variations.
- Favor strategy patterns using functions or classes over conditional logic.
- Use configuration objects and dependency injection with module exports/imports.
- Avoid switch/if-else chains based on type checking; use polymorphism instead.
- Provide hooks for customization in libraries or Node.js apps (e.g., middleware-like patterns).
- Design with JavaScript’s prototypal inheritance or composition for extending functionality.
## 3. Liskov Substitution Principle (LSP)
- Ensure derived classes or objects are fully substitutable for their base counterparts.
- Maintain all invariants of the base object in derived implementations.
- Never throw unexpected exceptions from methods not specified in base contracts.
- Don’t strengthen preconditions in subclasses or extended objects.
- Don’t weaken postconditions in subclasses or extended objects.
- Avoid overriding methods with implementations that do nothing or throw exceptions.
- Avoid type checking or downcasting, which may indicate LSP violations.
- Prefer composition (e.g., object mixing) over inheritance when substitutability is tricky.
## 4. Interface Segregation Principle (ISP)
- Create focused, minimal object shapes with cohesive methods.
- Split large object contracts into smaller, more specific ones.
- Design contracts around client needs, not implementation convenience.
- Avoid "fat" interfaces that force clients to depend on methods they don’t use.
- Use role-based object shapes representing behaviors rather than object types.
- Implement multiple small object contracts rather than a single general-purpose one.
- Consider object composition to build complex behaviors.
- Remove any methods from contracts that are only used by a subset of implementing objects.
## 5. Dependency Inversion Principle (DIP)
- High-level modules should depend on abstractions (e.g., object shapes), not concrete implementations.
- Make all dependencies explicit, ideally through function parameters or module imports.
- Use dependency injection with module systems (e.g., passing dependencies via arguments).
- Program to object shapes or interfaces, not concrete classes or functions.
- Place abstractions in separate modules from implementations.
- Avoid direct instantiation of service functions with `new` or inline calls in business logic.
- Create abstraction boundaries at module or architecture layer transitions.
- Define contracts owned by the client, not the implementation.
## Implementation Guidelines
- When starting a new module, explicitly identify its single responsibility.
- Document extension points and expected behavior for composition.
- Write object contracts with clear expectations and invariants.
- Question any module that depends on many concrete implementations.
- Use module exports, factory functions, or dependency injection to manage dependencies.
- Review object hierarchies to ensure LSP compliance.
- Regularly refactor toward SOLID, especially when extending functionality.
- Use design patterns (Strategy, Decorator, Factory, Observer, etc.) to facilitate SOLID adherence.
## Warning Signs
- "God" modules that handle everything.
- Functions with boolean parameters that radically change behavior.
- Deep prototype chains.
- Modules that know implementation details of their dependencies.
- Circular dependencies between modules.
- High coupling between unrelated components.
- Modules that grow rapidly in size with new features.
- Functions with many parameters.