Episode ini membahas modular programming dan arsitektur project Java: Java Platform Module System, modularisasi aplikasi dengan module-info.java dan dependency encapsulation, clean architecture, package-by-feature, dan arsitektur layered, serta pola desain penting builder, factory, strategy, dan observer.

Semakin besar aplikasi, semakin penting arsitekturnya. Episode 18 membahas modular programming dan project architecture — dari Java Platform Module System hingga pola desain yang menjadi bahasa bersama para pengembang Java. Kalian akan belajar menyusun aplikasi yang mudah dipelihara dan berkembang.
Arsitektur yang baik membuat perubahan kecil tetap aman dan terisolasi. Episode ini membekali kalian alat untuk membangun fondasi tersebut: modul, lapisan, dan pola desain yang teruji.
JPMS, diperkenalkan Java 9, menambahkan sistem modul ke platform. Modul mengekspos package tertentu dan mendeklarasikan dependency secara eksplisit — memberikan enkapsulasi yang jauh lebih kuat daripada classpath.
Modul dideklarasikan dalam file module-info.java di root source:
module com.aplikasi.core {
requires java.sql;
requires com.fasterxml.jackson.databind;
exports com.aplikasi.core.model;
exports com.aplikasi.core.service;
}requires mendeklarasikan dependency, dan exports menentukan package mana yang bisa diakses modul lain. Package lain tetap tersembunyi.
Kompilasi dan jalankan dengan flag module:
javac -d out --module-source-path src $(find src -name "*.java")
java --module-path out -m com.aplikasi.main/com.aplikasi.main.Main--module-path menggantikan classpath, dan -m menentukan modul serta class utama.
Pecah aplikasi besar menjadi modul fungsional: core, service, web, dan persistence. Setiap modul hanya bergantung pada apa yang dibutuhkannya, dan hanya mengekspos apa yang diperlukan.
Dependency encapsulation mencegah akses tidak disengaja ke package internal. Ini membuat batasan arsitektur diterapkan oleh compiler, bukan hanya oleh disiplin tim.
Clean architecture memisahkan lapisan: domain (inti bisnis), use case, dan adapters (web, database). Aturan utamanya: dependency mengarah ke dalam — lapisan dalam tidak bergantung pada lapisan luar.
domain <- use case <- adapters (web, persistence, external)Package-by-feature mengelompokkan kode berdasarkan fitur, misalnya order, payment, dan produk. Arsitektur layered mengelompokkan berdasarkan fungsi teknis: controller, service, repository. Package-by-feature lebih cocok untuk aplikasi besar karena perubahan terlokalisasi per fitur.
com.aplikasi.order -> OrderController, OrderService, OrderRepository
com.aplikasi.payment -> PaymentController, PaymentServiceBuilder menyederhanakan pembuatan objek dengan banyak parameter, terutama untuk immutable object:
public class Pengguna {
private final String nama;
private final int umur;
private Pengguna(Builder b) {
this.nama = b.nama;
this.umur = b.umur;
}
public static class Builder {
private String nama;
private int umur;
public Builder nama(String nama) { this.nama = nama; return this; }
public Builder umur(int umur) { this.umur = umur; return this; }
public Pengguna build() {
return new Pengguna(this);
}
}
}Factory memusatkan pembuatan objek dan menyembunyikan logika instantiasi:
public interface Pembayaran {
void proses(double jumlah);
}
public class PembayaranFactory {
public static Pembayaran buat(String tipe) {
return switch (tipe) {
case "kartu" -> new PembayaranKartu();
case "transfer" -> new PembayaranTransfer();
default -> throw new IllegalArgumentException("Tipe tidak dikenal");
};
}
}Strategy memungkinkan algoritma dipertukarkan saat runtime:
public interface StrategiDiskon {
double hitung(double harga);
}
public class DiskonLebaran implements StrategiDiskon {
public double hitung(double harga) {
return harga * 0.8;
}
}Observer membuat objek memberi tahu dependennya saat terjadi perubahan — dipakai luas di event system:
import java.util.concurrent.*;
public class DemoObserver {
public static void main(String[] args) {
SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>();
publisher.subscribe(new Flow.Subscriber<Integer>() {
public void onSubscribe(Flow.Subscription s) { s.request(Long.MAX_VALUE); }
public void onNext(Integer item) { System.out.println("Nilai: " + item); }
public void onError(Throwable t) {}
public void onComplete() {}
});
publisher.submit(42);
publisher.close();
}
}Episode 18 membahas modular programming dan arsitektur: JPMS dengan module-info.java dan dependency encapsulation, clean architecture, package-by-feature, arsitektur layered, serta pola desain builder, factory, strategy, dan observer.
Inti yang harus dibawa pulang:
requires dan exports mendefinisikan kontrak antar modul.Di episode 19 selanjutnya kita akan membahas tooling modern dan build automation — Maven versus Gradle Kotlin DSL, dependency management, plugin modern, build lifecycle, code formatting, linting, quality gates otomatis, skrip build reproducible, dan multi-module project. Saatnya mengotomasi build!