~/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 Principle
3 * 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 change
8// 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 class
22 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.