# Backend Code Quality SOLID principles, design patterns, clean code practices, and refactoring strategies (2025). ## SOLID Principles ### Single Responsibility Principle (SRP) **Concept:** Class/module should have one reason to change **Bad:** ```typescript class User { saveToDatabase() { /* ... */ } sendWelcomeEmail() { /* ... */ } generateReport() { /* ... */ } validateInput() { /* ... */ } } ``` **Good:** ```typescript class User { constructor(public id: string, public email: string, public name: string) {} } class UserRepository { async save(user: User) { /* ... */ } async findById(id: string) { /* ... */ } } class EmailService { async sendWelcomeEmail(user: User) { /* ... */ } } class UserValidator { validate(userData: any) { /* ... */ } } class ReportGenerator { generateUserReport(user: User) { /* ... */ } } ``` ### Open/Closed Principle (OCP) **Concept:** Open for extension, closed for modification **Bad:** ```typescript class PaymentProcessor { process(amount: number, method: string) { if (method === 'stripe') { // Stripe logic } else if (method === 'paypal') { // PayPal logic } // Adding new payment method requires modifying this class } } ``` **Good (Strategy Pattern):** ```typescript interface PaymentStrategy { process(amount: number): Promise; } class StripePayment implements PaymentStrategy { async process(amount: number) { // Stripe-specific logic return { success: true, transactionId: '...' }; } } class PayPalPayment implements PaymentStrategy { async process(amount: number) { // PayPal-specific logic return { success: true, transactionId: '...' }; } } class PaymentProcessor { constructor(private strategy: PaymentStrategy) {} async process(amount: number) { return this.strategy.process(amount); } } // Usage const processor = new PaymentProcessor(new StripePayment()); await processor.process(100); ``` ### Liskov Substitution Principle (LSP) **Concept:** Subtypes must be substitutable for base types **Bad:** ```typescript class Bird { fly() { /* ... */ } } class Penguin extends Bird { fly() { throw new Error('Penguins cannot fly!'); } } // Violates LSP - Penguin breaks Bird contract ``` **Good:** ```typescript interface Bird { move(): void; } class FlyingBird implements Bird { move() { this.fly(); } private fly() { /* ... */ } } class Penguin implements Bird { move() { this.swim(); } private swim() { /* ... */ } } ``` ### Interface Segregation Principle (ISP) **Concept:** Clients shouldn't depend on interfaces they don't use **Bad:** ```typescript interface Worker { work(): void; eat(): void; sleep(): void; } class Robot implements Worker { work() { /* ... */ } eat() { throw new Error('Robots don't eat'); } sleep() { throw new Error('Robots don't sleep'); } } ``` **Good:** ```typescript interface Workable { work(): void; } interface Eatable { eat(): void; } interface Sleepable { sleep(): void; } class Human implements Workable, Eatable, Sleepable { work() { /* ... */ } eat() { /* ... */ } sleep() { /* ... */ } } class Robot implements Workable { work() { /* ... */ } } ``` ### Dependency Inversion Principle (DIP) **Concept:** Depend on abstractions, not concretions **Bad:** ```typescript class MySQLDatabase { query(sql: string) { /* ... */ } } class UserService { private db = new MySQLDatabase(); // Tight coupling async getUser(id: string) { return this.db.query(`SELECT * FROM users WHERE id = ${id}`); } } ``` **Good (Dependency Injection):** ```typescript interface Database { query(sql: string, params: any[]): Promise; } class MySQLDatabase implements Database { async query(sql: string, params: any[]) { /* ... */ } } class PostgreSQLDatabase implements Database { async query(sql: string, params: any[]) { /* ... */ } } class UserService { constructor(private db: Database) {} // Injected dependency async getUser(id: string) { return this.db.query('SELECT * FROM users WHERE id = $1', [id]); } } // Usage const db = new PostgreSQLDatabase(); const userService = new UserService(db); ``` ## Design Patterns ### Repository Pattern **Concept:** Abstraction layer between business logic and data access ```typescript // Domain entity class User { constructor( public id: string, public email: string, public name: string, ) {} } // Repository interface interface UserRepository { findById(id: string): Promise; findByEmail(email: string): Promise; save(user: User): Promise; delete(id: string): Promise; } // Implementation class PostgresUserRepository implements UserRepository { constructor(private db: Database) {} async findById(id: string): Promise { const row = await this.db.query('SELECT * FROM users WHERE id = $1', [id]); return row ? new User(row.id, row.email, row.name) : null; } async save(user: User): Promise { await this.db.query( 'INSERT INTO users (id, email, name) VALUES ($1, $2, $3)', [user.id, user.email, user.name] ); } // Other methods... } // Service layer uses repository class UserService { constructor(private userRepo: UserRepository) {} async getUser(id: string) { return this.userRepo.findById(id); } } ``` ### Factory Pattern **Concept:** Create objects without specifying exact class ```typescript interface Notification { send(message: string): Promise; } class EmailNotification implements Notification { async send(message: string) { console.log(`Email sent: ${message}`); } } class SMSNotification implements Notification { async send(message: string) { console.log(`SMS sent: ${message}`); } } class PushNotification implements Notification { async send(message: string) { console.log(`Push notification sent: ${message}`); } } class NotificationFactory { static create(type: 'email' | 'sms' | 'push'): Notification { switch (type) { case 'email': return new EmailNotification(); case 'sms': return new SMSNotification(); case 'push': return new PushNotification(); default: throw new Error(`Unknown notification type: ${type}`); } } } // Usage const notification = NotificationFactory.create('email'); await notification.send('Hello!'); ``` ### Decorator Pattern **Concept:** Add behavior to objects dynamically ```typescript interface Coffee { cost(): number; description(): string; } class SimpleCoffee implements Coffee { cost() { return 10; } description() { return 'Simple coffee'; } } class MilkDecorator implements Coffee { constructor(private coffee: Coffee) {} cost() { return this.coffee.cost() + 2; } description() { return `${this.coffee.description()}, milk`; } } class SugarDecorator implements Coffee { constructor(private coffee: Coffee) {} cost() { return this.coffee.cost() + 1; } description() { return `${this.coffee.description()}, sugar`; } } // Usage let coffee: Coffee = new SimpleCoffee(); coffee = new MilkDecorator(coffee); coffee = new SugarDecorator(coffee); console.log(coffee.description()); // "Simple coffee, milk, sugar" console.log(coffee.cost()); // 13 ``` ### Observer Pattern (Pub/Sub) **Concept:** Notify multiple objects about state changes ```typescript interface Observer { update(event: any): void; } class EventEmitter { private observers: Map = new Map(); subscribe(event: string, observer: Observer) { if (!this.observers.has(event)) { this.observers.set(event, []); } this.observers.get(event)!.push(observer); } emit(event: string, data: any) { const observers = this.observers.get(event) || []; observers.forEach(observer => observer.update(data)); } } // Observers class EmailNotifier implements Observer { update(event: any) { console.log(`Sending email about: ${event.type}`); } } class LoggerObserver implements Observer { update(event: any) { console.log(`Logging event: ${JSON.stringify(event)}`); } } // Usage const eventEmitter = new EventEmitter(); eventEmitter.subscribe('user.created', new EmailNotifier()); eventEmitter.subscribe('user.created', new LoggerObserver()); eventEmitter.emit('user.created', { type: 'user.created', userId: '123' }); ``` ## Clean Code Practices ### Meaningful Names **Bad:** ```typescript function d(a: number, b: number) { return a * b * 0.0254; } ``` **Good:** ```typescript function calculateAreaInMeters(widthInInches: number, heightInInches: number) { const INCHES_TO_METERS = 0.0254; return widthInInches * heightInInches * INCHES_TO_METERS; } ``` ### Small Functions **Bad:** ```typescript async function processOrder(orderId: string) { // 200 lines of code doing everything // - validate order // - check inventory // - process payment // - update database // - send notifications // - generate invoice } ``` **Good:** ```typescript async function processOrder(orderId: string) { const order = await validateOrder(orderId); await checkInventory(order); const payment = await processPayment(order); await updateOrderStatus(orderId, 'paid'); await sendConfirmationEmail(order); await generateInvoice(order, payment); } ``` ### Avoid Magic Numbers **Bad:** ```typescript if (user.age < 18) { throw new Error('Too young'); } setTimeout(fetchData, 86400000); ``` **Good:** ```typescript const MINIMUM_AGE = 18; if (user.age < MINIMUM_AGE) { throw new Error('Too young'); } const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000; setTimeout(fetchData, ONE_DAY_IN_MS); ``` ### Error Handling **Bad:** ```typescript try { const user = await db.findUser(id); return user; } catch (e) { console.log(e); return null; } ``` **Good:** ```typescript try { const user = await db.findUser(id); if (!user) { throw new UserNotFoundError(id); } return user; } catch (error) { logger.error('Failed to fetch user', { userId: id, error: error.message, stack: error.stack, }); throw new DatabaseError('User fetch failed', { cause: error }); } ``` ### Don't Repeat Yourself (DRY) **Bad:** ```typescript app.post('/api/users', async (req, res) => { if (!req.body.email || !req.body.email.includes('@')) { return res.status(400).json({ error: 'Invalid email' }); } // ... }); app.put('/api/users/:id', async (req, res) => { if (!req.body.email || !req.body.email.includes('@')) { return res.status(400).json({ error: 'Invalid email' }); } // ... }); ``` **Good:** ```typescript function validateEmail(email: string) { if (!email || !email.includes('@')) { throw new ValidationError('Invalid email'); } } app.post('/api/users', async (req, res) => { validateEmail(req.body.email); // ... }); app.put('/api/users/:id', async (req, res) => { validateEmail(req.body.email); // ... }); ``` ## Code Refactoring Techniques ### Extract Method **Before:** ```typescript function renderOrder(order: Order) { console.log('Order Details:'); console.log(`ID: ${order.id}`); console.log(`Total: $${order.total}`); console.log('Items:'); order.items.forEach(item => { console.log(`- ${item.name}: $${item.price}`); }); } ``` **After:** ```typescript function renderOrder(order: Order) { printOrderHeader(order); printOrderItems(order.items); } function printOrderHeader(order: Order) { console.log('Order Details:'); console.log(`ID: ${order.id}`); console.log(`Total: $${order.total}`); } function printOrderItems(items: OrderItem[]) { console.log('Items:'); items.forEach(item => { console.log(`- ${item.name}: $${item.price}`); }); } ``` ### Replace Conditional with Polymorphism **Before:** ```typescript function getShippingCost(order: Order) { if (order.shippingMethod === 'standard') { return 5; } else if (order.shippingMethod === 'express') { return 15; } else if (order.shippingMethod === 'overnight') { return 30; } } ``` **After:** ```typescript interface ShippingMethod { getCost(): number; } class StandardShipping implements ShippingMethod { getCost() { return 5; } } class ExpressShipping implements ShippingMethod { getCost() { return 15; } } class OvernightShipping implements ShippingMethod { getCost() { return 30; } } ``` ## Code Quality Checklist - [ ] SOLID principles applied - [ ] Functions are small (< 20 lines ideal) - [ ] Meaningful variable/function names - [ ] No magic numbers (use constants) - [ ] Proper error handling (no silent failures) - [ ] DRY (no code duplication) - [ ] Comments explain "why", not "what" - [ ] Design patterns used appropriately - [ ] Dependency injection for testability - [ ] Code is readable (readable > clever) ## Resources - **Clean Code (Book):** Robert C. Martin - **Refactoring (Book):** Martin Fowler - **Design Patterns:** https://refactoring.guru/design-patterns - **SOLID Principles:** https://en.wikipedia.org/wiki/SOLID