| name | code-quality |
| description | Code quality principles including SOLID, clean code, design patterns, and code smells. Use when refactoring code, reviewing code quality, or when implementing design patterns in any language. |
Code Quality Best Practices
This skill provides code quality principles, design patterns, and practices for writing maintainable, clean code across multiple programming languages.
SOLID Principles
S - Single Responsibility Principle
A class/function should have only one reason to change.
class User {
save() { }
sendEmail() { }
validate() { }
}
class User {
validate() { }
}
class UserRepository {
save(user: User) { }
}
class EmailService {
sendEmail(user: User) { }
}
O - Open/Closed Principle
Open for extension, closed for modification.
interface PaymentProcessor {
process(amount: number): Promise<PaymentResult>;
}
class CreditCardProcessor implements PaymentProcessor {
async process(amount: number) { }
}
class PayPalProcessor implements PaymentProcessor {
async process(amount: number) { }
}
L - Liskov Substitution Principle
Subtypes must be substitutable for their base types.
class Bird {
move() { }
}
class Sparrow extends Bird {
move() { this.fly(); }
}
class Penguin extends Bird {
move() { this.walk(); }
}
I - Interface Segregation Principle
Clients shouldn't depend on interfaces they don't use.
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
interface Sleepable {
sleep(): void;
}
D - Dependency Inversion Principle
Depend on abstractions, not concretions.
class OrderService {
private emailService = new EmailService();
}
class OrderService {
constructor(private emailService: IEmailService) {}
}
Clean Code Principles
Meaningful Names
- Use descriptive names that reveal intent
- Avoid abbreviations and single-letter variables
- Use searchable names
- Use consistent naming conventions
const d = new Date();
const u = getUserById(i);
const currentDate = new Date();
const user = getUserById(userId);
Functions
- Small and focused (single responsibility)
- Do one thing well
- Descriptive names
- Few parameters (3 or fewer ideally)
function processOrder(order) {
validate(order);
calculateTotal(order);
applyDiscount(order);
chargePayment(order);
sendEmail(order);
updateInventory(order);
logActivity(order);
}
function processOrder(order: Order) {
const validatedOrder = validateOrder(order);
const orderWithTotal = calculateOrderTotal(validatedOrder);
return chargeAndFulfill(orderWithTotal);
}
Comments
- Code should be self-documenting
- Comments should explain "why", not "what"
- Remove commented-out code
- Use comments for complex business logic
counter++;
counter++;
Code Smells
Long Method
Problem: Method is too long and does too much.
Solution: Extract methods, break into smaller functions.
Large Class
Problem: Class has too many responsibilities.
Solution: Split into multiple classes following SRP.
Duplicate Code
Problem: Same code appears in multiple places.
Solution: Extract to shared function/class.
Long Parameter List
Problem: Function has too many parameters.
Solution: Use parameter objects or configuration objects.
function createUser(name, email, age, address, phone, role) {}
function createUser(userData: CreateUserRequest) {}
Feature Envy
Problem: Method uses more features of another class than its own.
Solution: Move method to the class it's most interested in.
Data Clumps
Problem: Same group of data appears together frequently.
Solution: Extract to a class or data structure.
Design Patterns
Strategy Pattern
Define a family of algorithms, encapsulate each, and make them interchangeable.
interface PaymentStrategy {
pay(amount: number): Promise<PaymentResult>;
}
class CreditCardStrategy implements PaymentStrategy {
async pay(amount: number) { }
}
class PayPalStrategy implements PaymentStrategy {
async pay(amount: number) { }
}
class PaymentProcessor {
constructor(private strategy: PaymentStrategy) {}
processPayment(amount: number) {
return this.strategy.pay(amount);
}
}
Factory Pattern
Create objects without specifying the exact class.
interface Logger {
log(message: string): void;
}
class ConsoleLogger implements Logger {
log(message: string) { console.log(message); }
}
class FileLogger implements Logger {
log(message: string) { }
}
class LoggerFactory {
static create(type: 'console' | 'file'): Logger {
switch (type) {
case 'console': return new ConsoleLogger();
case 'file': return new FileLogger();
default: throw new Error('Unknown logger type');
}
}
}
Repository Pattern
Abstract data access logic.
interface IRepository<T> {
findById(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
save(entity: T): Promise<T>;
delete(id: string): Promise<void>;
}
class UserRepository implements IRepository<User> {
async findById(id: string) { }
async findAll() { }
async save(user: User) { }
async delete(id: string) { }
}
Key Principles
- Readability: Code should be easy to read and understand
- Maintainability: Code should be easy to modify and extend
- Testability: Code should be easy to test
- DRY (Don't Repeat Yourself): Avoid duplication
- KISS (Keep It Simple, Stupid): Prefer simple solutions
- YAGNI (You Aren't Gonna Need It): Don't add functionality until needed