~/code-lab/readme
hands-on guide
Code Lab: SOLID & Design Patterns
A small VSCode-style workspace for the principles and patterns I actually reach for when writing backend code. Pick a file from the explorer to read the before/after example, then check the terminal panel and the notes below for the reasoning behind it.
gilang@code-lab — SingleResponsibility.ts
1/**2 * Single Responsibility Principle3 * A class should have one, and only one, reason to change.4 */5 6// Violation: this class calculates, formats, AND persists an invoice.7// A pricing change, a print-format change, and a storage-engine change8// all force edits to the same class.9class Invoice {10 constructor(private items: { price: number; qty: number }[]) {}11 12 calculateTotal(): number {13 return this.items.reduce((sum, item) => sum + item.price * item.qty, 0);14 }15 16 printReceipt(): string {17 return "Total: $" + this.calculateTotal().toFixed(2);18 }19 20 saveToDatabase(): void {21 // direct database access mixed into a pricing class22 console.log("INSERT INTO invoices ...");23 }24}25 26// Fix: split responsibilities into focused collaborators.27interface InvoiceItem {28 price: number;29 qty: number;30}31 32class InvoiceCalculator {33 static total(items: InvoiceItem[]): number {34 return items.reduce((sum, item) => sum + item.price * item.qty, 0);35 }36}37 38class InvoicePrinter {39 static receipt(total: number): string {40 return "Total: $" + total.toFixed(2);41 }42}43 44class InvoiceRepository {45 save(total: number): void {46 console.log("INSERT INTO invoices (total) VALUES (" + total + ")");47 }48}49 50// Each class now changes for exactly one reason.51const items: InvoiceItem[] = [{ price: 25, qty: 2 }];52const total = InvoiceCalculator.total(items);53new InvoiceRepository().save(total);54console.log(InvoicePrinter.receipt(total));55 terminal
$ts-node SingleResponsibility.ts
INSERT INTO invoices (total) VALUES (50)
Total: $50.00
✓ InvoiceCalculator, InvoicePrinter, and InvoiceRepository
can now change independently without touching each other.
best practice notes — Single Responsibility Principle
A class should have exactly one reason to change. Bundle unrelated jobs into one class and every change — a new tax rule, a new export format — risks breaking something unrelated.
- Ask 'who would ask me to change this class, and why?' — more than one answer means it has more than one responsibility.
- Split by axis of change, not by file size — a 20-line class can still violate SRP.
- Composition over a god class: let smaller classes collaborate instead of one class knowing everything.