Belajar NestJS - Architecture & Design Patterns
Episode 18 of 24

Belajar NestJS - Architecture & Design Patterns

Episode ini membahas arsitektur dan pola desain di NestJS: modular architecture dan feature modules, domain-driven design dan hexagonal architecture, event-driven architecture dengan CQRS dan event sourcing, serta shared modules dan inter-module boundaries.

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

Pendahuluan

Saat aplikasi dan tim bertumbuh, cara kita menyusun kode menentukan keberhasilan jangka panjang. Episode 18 membahas arsitektur dan pola desain yang membuat codebase tetap sehat: modular architecture, DDD, hexagonal architecture, dan event-driven architecture.

Kalian akan belajar pola-pola yang dipakai proyek NestJS skala enterprise di dunia nyata.

Modular Architecture dan Feature Modules

Feature Modules

Feature module mengelompokkan kode berdasarkan domain fitur — controller, service, entity, dan DTO milik fitur yang sama berada dalam satu module.

Struktur feature modules
src/
  modules/
    users/
      users.module.ts
      users.controller.ts
      users.service.ts
      user.entity.ts
    orders/
      orders.module.ts
      orders.controller.ts
      orders.service.ts
      order.entity.ts

Struktur ini membuat kode mudah dinavigasi dan memungkinkan beberapa developer mengerjakan fitur berbeda tanpa bentrok.

Prinsip Single Responsibility

Setiap module punya satu tanggung jawab. Jika sebuah module terlalu besar, pecah menjadi submodule. Pola ini menjaga tiap bagian aplikasi tetap fokus dan mudah diuji.

Domain-Driven Design

Ubiquitous Language dan Bounded Context

DDD berfokus pada pemodelan domain bisnis. Konsep kuncinya adalah bounded context — batas di mana satu model domain berlaku — dan ubiquitous language — istilah yang sama dipakai developer dan domain expert.

JSEntity domain dengan logika bisnis
import { Entity } from "typeorm";
 
@Entity()
export class Order {
  id: number;
  status: string;
  items: OrderItem[];
 
  addItem(item: OrderItem): void {
    if (this.status === "completed") {
      throw new Error("Order sudah selesai");
    }
    this.items.push(item);
  }
}

Entity domain menyimpan logika bisnis (invariant) — bukan sekadar data pasif.

Layer Arsitektur

DDD memisahkan layer: domain (logika bisnis), application (use case), infrastructure (database, HTTP), dan presentation (controller). NestJS cocok dengan pola ini karena module dan provider memetakan layer dengan rapi.

Hexagonal Architecture

Port dan Adapter

Hexagonal architecture (ports and adapters) memisahkan inti aplikasi dari dunia luar. Inti aplikasi tidak bergantung pada database atau HTTP — ia berkomunikasi lewat port, dan adapter mengimplementasikan port tersebut.

JSPort repository
export interface UserRepository {
  findById(id: number): Promise<User>;
  save(user: User): Promise<void>;
}

Adapter TypeORM mengimplementasikan port ini:

JSAdapter repository TypeORM
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { User } from "../domain/user.entity";
 
@Injectable()
export class TypeOrmUserRepository implements UserRepository {
  constructor(
    @InjectRepository(User)
    private readonly repo: Repository<User>,
  ) {}
 
  async findById(id: number): Promise<User> {
    return this.repo.findOneBy({ id });
  }
 
  async save(user: User): Promise<void> {
    await this.repo.save(user);
  }
}

Inti aplikasi tetap murni — mengganti database tidak menyentuh logika bisnis.

Event-Driven Architecture dengan CQRS

CQRS Module

CQRS memisahkan operasi baca (query) dan tulis (command). NestJS memiliki module @nestjs/cqrs yang dipasang lewat npm install @nestjs/cqrs:

Install @nestjs/cqrs
npm install @nestjs/cqrs
JSCommand dan command handler
import { CommandHandler, ICommand, ICommandHandler } from "@nestjs/cqrs";
 
export class CreateOrderCommand implements ICommand {
  constructor(public readonly productId: number) {}
}
 
@CommandHandler(CreateOrderCommand)
export class CreateOrderHandler implements ICommandHandler<CreateOrderCommand> {
  async execute(command: CreateOrderCommand): Promise<void> {
    // logika membuat order
  }
}

Event Sourcing

Event sourcing menyimpan perubahan state sebagai urutan event, bukan hanya state final. Setiap aksi menghasilkan event yang bisa dipakai untuk rekonstruksi state, audit trail, dan replikasi antar service. Kombinasi CQRS dan event sourcing adalah fondasi banyak sistem event-driven berskala besar.

Shared Modules, Global Modules, dan Boundaries

Shared dan Global Modules

Shared module mengekspor provider untuk dipakai module lain. Global module (ditandai @Global()) tersedia di seluruh aplikasi tanpa perlu diimpor ulang — cocok untuk cross-cutting concern seperti logging dan konfigurasi.

Inter-Module Boundaries

Batasan antar module menjaga agar dependensi tetap jelas: module hanya boleh bergantung pada yang diimpor secara eksplisit. Hindari global module berlebihan karena menyembunyikan dependensi dan membuat graph module sulit dipahami.

Penutup

Episode 18 memetakan arsitektur tingkat lanjut: feature modules, DDD, hexagonal architecture, event-driven dengan CQRS dan event sourcing, serta boundary antar module.

Inti yang harus dibawa pulang:

  • Feature module mengelompokkan kode berdasarkan domain fitur.
  • DDD memodelkan domain dengan bounded context dan ubiquitous language.
  • Hexagonal architecture memisahkan inti aplikasi dari dunia luar via port-adapter.
  • CQRS memisahkan operasi baca dan tulis.
  • Event sourcing menyimpan state sebagai urutan event.
  • Batas antar module dijaga dengan impor eksplisit.

Di episode 19 selanjutnya kita akan membahas tooling modern dan build automation — Nest CLI, TypeScript compiler, dan ts-node; build pipeline dengan npm dan Docker; static analysis, linting, dan formatting; serta reproducible builds dan multi-environment setup.

Belajar NestJS - Architecture & Design Patterns | Belajar NestJS