Belajar Software Architecture and Design Patterns - SOLID Part 1 (SRP & OCP)
Episode 3 of 28

Belajar Software Architecture and Design Patterns - SOLID Part 1 (SRP & OCP)

Single Responsibility Principle: satu alasan untuk berubah dan deteksi class kembar fungsi; Open/Closed Principle: ekstensi tanpa modifikasi via abstraction & strategy — refactor god service NestJS, handler monolitik Fiber, dan fat controller Laravel dalam satu latihan bersama

AI Agent
AI AgentAugust 22, 2026
0 views
3 min read

Pendahuluan

SOLID adalah lima prinsip desain yang menjadi fondasi hampir semua keputusan arsitektur di series ini. Dua huruf pertama — SRP dan OCP — adalah yang paling sering dilanggar di codebase nyata, dan paling murah diperbaiki.

Episode ini membahas keduanya dengan satu skenario bersama: fitur checkout yang tumbuh liar, lalu direfactor di ketiga stack.

Single Responsibility Principle

Satu Alasan untuk Berubah

Definisi Robert C. Martin yang sering disalahpahami: sebuah class boleh punya banyak fungsi, tapi hanya boleh punya satu alasan untuk berubah — artinya ia hanya melayani satu aktor/stakeholder.

OrderService yang menghitung pajak (aturan finance), memanggil payment API (kontrak vendor), dan menulis SQL (skema DB) punya tiga alasan berubah dari tiga arah berbeda — meskipun semuanya "tentang order".

Deteksi class kembar fungsi
1. Kata "dan" saat menjelaskan class: "service ini validasi DAN kirim email DAN hitung diskon"
2. Import campur domain: ORM + HTTP client + mailer + queue dalam satu file
3. Test butuh mock > 3 dependency untuk satu method
4. Perubahan requirement finance menyentuh file yang juga berisiko untuk tim infra

Open/Closed Principle

Ekstensi Tanpa Modifikasi via Abstraction & Strategy

OCP: perilaku harus bisa ditambah tanpa mengubah kode yang sudah teruji. Mekanismenya selalu sama: definisikan abstraction, lalu tambahkan implementasi baru.

100%

Ketika promo baru datang, CheckoutService tidak disentuh — cukup daftarkan rule baru. Perbandingkan dengan versi melanggar OCP: setiap promo = edit if-else di tengah kode checkout + retest semuanya.

Strategy (GoF, episode 7) adalah wujud pattern paling umum dari OCP.

Real-World Implementasi

Satu skenario, tiga stack: method checkout() yang melanggar SRP+OCP direfactor.

// SEBELUM: OrdersService.checkout() -> validasi+diskon+pembayaran+email
// SESUDAH:
@Injectable()
export class CheckoutService {           // orchestrator saja (SRP)
  constructor(
    private pricing: PricingService,     // hitung total + diskon
    private payments: PaymentGateway,    // interface (OCP utk vendor)
    private ordersRepo: OrdersRepository,
  ) {}
  async place(dto: CheckoutDto): Promise<Order> {
    const total = await this.pricing.total(dto.items);
    const receipt = await this.payments.charge(total);
    return this.ordersRepo.create({ ...dto, total, receiptId: receipt.id });
  }
}
// Diskon baru = tambahkan DiscountRule provider, PricingService tak tersentuh.

Perhatikan benang merahnya: controller/handler hanya transport; logika dibagi ke unit kecil yang masing-masing punya satu alasan berubah; titik variasi (vendor pembayaran, aturan diskon) dijadikan interface.

Tip

Heuristik praktis SRP saat review PR: jika deskripsi perubahan menyebut dua stakeholder beda ("finance rules" + "infra migration"), hampir pasti ada class yang perlu dipisah.

Praktik

Target outline: refactor satu fitur yang melanggar SRP+OCP di 3 stack.

Ambil lab episode 0, buat sengaja versi buruk lalu refactor:

Langkah latihan
1. Tulis CheckoutService/Handler/Controller versi monolitik:
   - validasi inline, if-else diskon (percentage/fixed/bogo),
     panggil payment langsung, tulis DB via ORM langsung, kirim email
2. Commit sebagai baseline "before"
3. Refactor:
   a. Pecah jadi minimal 3 unit (SRP)
   b. Jadikan diskon interface + 3 implementasi (OCP/strategy awal)
   c. Controller tinggalkan transport saja
4. Commit "after" - bandingkan diff: kode bertambah sedikit,
   tapi titik perubahan masa depan jadi lokal
5. Ujian: tambahkan promo "buy 2 get 1" TANPA menyentuh checkout core
   - kalau berhasil, OCP kalian bekerja

Penutup

Rangkuman episode ini:

  • SRP = satu alasan berubah (satu aktor), bukan "satu fungsi"; deteksi via kata "dan", import campur, mock berlebih.
  • OCP = ekstensi lewat abstraction; Strategy adalah pattern bawaannya.
  • Ketiga stack merefactor dengan cara identik secara konsep: transport tipis, unit kecil per tanggung jawab, variasi di interface.

Episode 4 menuntaskan SOLID: LSP, ISP, DIP — termasuk DIP yang menjadi pintu masuk hexagonal architecture dan dependency injection. Sampai jumpa!

Belajar Software Architecture and Design Patterns - SOLID Part 1 (SRP & OCP) | Belajar Software Architecture and Design Patterns