DDD

Sat. Jun 20th, 2026 10:56 PM6 mins read
DDD
Source: Ideogram - Domain Driven Development

Domain Driven Design (DDD) adalah sebuah filosofi pengembangan software yang berpusat pada logic bisnis yang disebut sebagai “Domain”. Filosofi ini diperkenalkan oleh Eric Evans di tahun 2003. Walaupun udah lebih dari 20 tahun yang lalu tapi filosofi ini masih tetap relevan di jaman sekarang. DDD menyelaraskan antara code dengan realita bisnis, bukan sebaliknya. Fokus saat develop aplikasi adalah bisnisnya, bukan teknologinya. DDD memiliki beberapa komponen seperti Ubiquitous Language, Bounded Context, Context Mapping, Entity Object, Value Object, Aggregate Object, Domain Service, dan Repository.

Ubiquitous Language

Ubiquitous Language artinya adalah istilah yang dipakai di dalam bisnis harus seragam dengan istilah yang digunakan pada code. Misalnya pada dunia marketing ada istilah “Canvassing” untuk penjualan barang secara langsung, maka pada code kita juga harus menggunakan istilah ini seperti pada objek “SalesCanvassing”, bukan “SalesDoorToDoor” atau “SalesFaceToFace”. Contoh lainnya adalah “Invoice” untuk istilah faktur pembelian. Jika orang-orang bisnis menggunakan istilah itu maka di dalam code kita juga harus menggunakan istilah yang sama, bukan menggunakan istilah lain seperti “Billing”. Meskipun keduanya bermakna sama, tapi apa yang didevelop harus selaras dengan istilah yang sering digunakan oleh orang-orang bisnis. Berlaku juga untuk beberapa istilah lain yang bermakna mirip seperti “Product” dengan “Item”, “Sales” dengan “Revenue”, “Delivery” dengan “Shipment”, atau istilah lainnya.

Bounded Context

Bounded Context adalah batasan istilah yang disepakati. Meskipun kita telah menyepakati sebuah istilah yang akan digunakan, kadang istilah yang sama digunakan untuk beberapa konteks berbeda. Di sini kita harus batasi penggunaan istilahnya sesuai konteks. Misalnya istilah “Item”, di dalam konteks penjualan “Item” maknanya adalah barang yang dijual. Di dalam konteks pergudangan “Item” adalah barang yang disimpan. Di dalam konteks pengiriman “Item” adalah barang yang dikirim. Artinya harus dibedakan 3 objek “Item” untuk tiap konteks seperti “SalesItem” untuk barang yang dijual, “StockItem” untuk barang yang disimpan, dan “DeliveryItem” untuk barang yang dikirim. Batasan konteks ini harus jelas. Jangan sampai hanya karena istilahnya sama kita hanya bikin satu objek doang yang dipakai untuk semua konteks🫣. Kita harus memahami kapan konteks tersebut berbeda. Misalnya pada konteks penjualan “SalesItem” mengandung informasi kode barang, jumlah barang yang dipesan, dan jumlah barang yang dikonfirmasi. Sedangkan pada konteks pergudangan “StockItem” mengandung informasi kode barang, jumlah barang yang tersedia, jumlah barang yang dipesan, dan jumlah barang yang diretur.

Context Mapping

Context Mapping adalah strategi untuk memetakan konteks tentang bagaimana konteks tersebut berkomunikasi. Ada beberapa strategi Context Mapping:

Customer-Supplier

Ini sama kayak analogi Customer-Supplier, yaitu ketergantungan antara Customer dan Supplier. Contohnya kayak fitur Ordering dengan Promo. Keduanya memiliki konteks berbeda tapi saling bergantung. Keduanya harus saling kooperatif. Saat develop tiap tim dari kedua fitur harus saling bernegosiasi terkait istilah yang akan dipakai. Misalnya ketika develop kalkulasi promo pada fitur penjualan, maka harus ada kesepakatan seperti istilah yang akan digunakan, format properti apa yang dibutuhkan, dan sebagainya. Jangan sampai fitur Ordering butuhnya “VoucherCode”, tapi di fitur Promo adanya “Coupon”🥴.

Anti-Corruption Layer

Strategi ini terjadi ketika ada perbedaan istilah dengan sistem luar. Ini yang bikin pusing kepala karena istilah yang biasa kita pakai bentrok saat integrasi dengan sistem luar. Misalnya kita menggunakan istilah “Sku” sebagai kode unik barang. Aplikasi kita terintegrasi dengan API pihak luar yang menggunakan istilah “ProductCode” sebagai kode unik barang🥴. Untuk mengatasinya dengan strategi ini adalah kita perlu bikin logic mapping istilah “ProductCode” ini dengan “Sku” sebelum diproses lebih lanjut di dalam code kita. Jadi istilah “ProductCode” ini hanya terisolasi di satu tempat di bagian integrasinya aja, sedangkan di codebase kita secara umum masih menggunakan istilah “Sku”. Ini salah satu strategi yang umum pada project yang sering berintegrasi dengan sistem luar.

Conformist

Ini kebalikan dari Anti-Corruption Layer. Sesuai namanya, di sini kita pasrah saat terjadi perbedaan istilah🤷. Biasanya ini dilakukan ketika ada istilah dari sistem luar yang berbeda tapi ga banyak digunakan di sistem kita. Misalkan kita bikin aplikasi trading saham, tapi di dalamnya ada fitur beli paket internet yang terintegrasi dengan API luar. Di dalam code kita menggunakan istilah “Credit”, sedangkan pada API integrasi menggunakan istilah “Quota”. Daripada repot-repot bikin logic mapping mending pasrah aja dengan risiko istilah di codebase kita ada yang ga konsisten karena itu bukan fitur utama kita dan ga banyak tersebar codenya.

Shared Kernel

Strategi ini adalah dengan cara menggunakan data yang sama pada konteks berbeda. Ini bertolak-belakang dengan Bounded Context di mana kita harus memisahkannya tiap konteks. Tapi memang ada kalanya ini bisa dipakai karena memang mirip sehingga ga worth it untuk dipisah. Contohnya “Currency” dan “Country” yang sama-sama memiliki properti “Language”. Walaupun konteksnya beda, tapi keduanya memiliki properti “Language” yang bisa dipakai bersama-sama.

Copy
public record Language(String name, String code){
}

public record Country(String name, Language language){
}

public record Currency(String name, Language language){
}

Tapi yang kayak gini jarang terjadi dan ga bisa dijadiin strategi default karena bisa bikin pusing kalau ternyata strategi ini kurang tepat pada kasus tertentu🥴.

Entity Object

Entity Object adalah objek yang memiliki identitas unik. Sebuah Entity yang memiliki identitas unik sama meskipun data lainnya berubah tetaplah objek yang sama. Di Java kita bisa menggunakan override method equals() & hashcode() dan tulis logicnya untuk properti yang dijadikan Id. Kalau pakai Lombok kita bisa menggunakan anotasi @EqualsAndHashCode dan menulis properti yang dijadikan Id. Contohnya pada Entity User dengan username sebagai identitas unik:

Entity User
Copy
@EqualsAndHashCode(of = "username")
public static class UserEntity{
	String username;
	String password;
	LocalDate birthDate;
}

Dengan begini dua objek User dengan username yang sama adalah objek yang sama.

Value Object

Value Object adalah objek untuk menyimpan data immutable dan ga harus punya identitas unik. Sebuah Value yang memiliki data yang sama dengan objek Value lainnya adalah objek yang sama. Di Java kita bisa menggunakan override method equals() & hashcode() dan tulis logicnya untuk semua property. Kalau pakai Lombok kita bisa menggunakan anotasi @Value, nanti otomatis dibuatin implementasinya menggunakan semua properti. Atau kalau pakai Java versi modern, kita bisa menggunakan record. Contohnya pada Value yang menyimpan alamat user.

Record UserAddress
Copy
public record UserAddress(String street, String city, String country){
}

Karena objeknya immutable, maka saat objeknya berubah kita harus bikin objek baru.

Aggregate Object

Aggregate Object adalah Entity Object atau Value Object yang berisi kumpulan Entity Object atau Value Object lainnya dalam satu kesatuan data. Misalnya User sebagai Aggregate Object dengan value UserAddresses.

Record User
Copy
public record User(String username, List<UserAddress> addresses){
}

Tanpa objek User, objek UserAddresses ga akan ada artinya karena satu kesatuan data.

Domain Service

Ini merupakan bagian layer terdalam di Clean Architecture. Domain Service adalah objek inti yang berisi logic bisnis. Bedanya dengan Entity, Value, dan Aggregate Object adalah di sini ga cuma nyimpan data, tapi juga ada logicnya. Misalnya perubahan state, validasi bisnis, atau logic bisnis lainnya. Contohnya pada objek Password yang menyimpan value password beserta validasi bisnisnya:

Record Password
Copy
public record Password(String value) {

	public Password {
		if (value == null || value.isBlank()) {
			throw new WeakPasswordException("Password must not be blank");
		}
		if (value.length() < 8) {
			throw new WeakPasswordException("Password must be at least 8 characters");
		}
		if (!value.matches(".*[a-zA-Z].*") || !value.matches(".*\\d.*")) {
			throw new WeakPasswordException("Password must contain at least one letter and one number");
		}
	}

}

Konsep ini menentang penggunaan Anemic Data Model yang sering digunakan. Anemic Data Model adalah objek yang logic bisnisnya dipisah di objek berbeda. Contohnya kayak gini:

Record Password
Copy
public record Password(String value) {
}
Class PasswordValidator
Copy
public class PasswordValidator {

	public void validate(Password password) {
		String value = password.value();
		if (value == null || value.isBlank()) {
			throw new WeakPasswordException("Password must not be blank");
		}
		if (value.length() < 8) {
			throw new WeakPasswordException("Password must be at least 8 characters");
		}
		if (!value.matches(".*[a-zA-Z].*") || !value.matches(".*\\d.*")) {
			throw new WeakPasswordException("Password must contain at least one letter and one number");
		}
	}

}

Dengan pendekatan seperti itu objek Password disebut kayak kurang darah😅. Pendekatan seperti itu ditentang oleh filosofi ini dan dinilai anti-pattern OOP. Manipulasi data dilakukan di luar objek dan dianggap lebih berorientasi prosedural daripada berorientasi objek. Domain Service ini mengangkat marwah objek inti🫡.

Repository

Repository adalah interface untuk mekanisme penyimpanan dan pengambilan data ke database. Objek-objek sebelumnya tugasnya menyimpan data ke objek secara bisnis, nah yang ini tugasnya lebih ke arah teknis untuk menyimpan data ke database.

Interface Repository
Copy
public interface UserRepository {
	void save(UserEntity user);
	boolean existsByUsername(String username);
	Optional<UserEntity> findByUsername(String username);
}

Verdict

DDD mendorong kita untuk berpikir tentang aturan bisnis terlebih dulu dibanding berpikir teknis. Logic bisnis ditempatkan sebagai pusat utama. Setelah itu baru diterjemahkan ke dalam teknis. DDD cocok digunakan pada project besar yang sangat kompleks dan maintainability tinggi. Keuntungan terbesarnya adalah code benar-benar merepresentasikan bisnis, bukan teknologi.

© 2026 · Ferry Suhandri