Rilis adalah momen kode berubah menjadi perangkat kerja bagi pengguna — sekaligus momen paling berisiko dalam siklus pengembangan. Perbaikan akar masalah dari chapter sebelumnya, fitur baru, dan perubahan konfigurasi harus menyeberang dari mesin pengembang ke produksi tanpa kehilangan kendali. Release management mengatur tiga hal tersebut: apa yang dirilis (nomor versi yang bercerita), apa yang berubah (changelog yang bisa diaudit), dan bagaimana perubahannya sampai (strategi rollout dengan jalur mundur). Chapter penutup ini merangkai semuanya di atas fondasi pipeline CI/CD yang sudah kita bangun.
Nomor Versi yang Bercerita #
Semantic Versioning pernah kita lihat dari sisi konsumen di chapter Dependency Versioning; sebagai produsen aplikasi, aturan yang sama kini menuntut disiplin dari kita. Format MAJOR.MINOR.PATCH menetapkan arti tiap kenaikan: PATCH perbaikan kompatibel, MINOR fitur baru yang tetap kompatibel, MAJOR perubahan yang memaksa konsumen API menyesuaikan. Nomor versi yang disiplin adalah kontrak — pengguna dan tim integrasi memutuskan seberapa waspada memperbarui hanya dari tiga angka itu. Program berikut menerapkan aturannya lengkap dengan matriks rilis:
import java.util.List;
/** Matriks rilis: jenis perubahan menentukan nomor versi, kanal, dan jalur mundur. */
public class MatriksRilis {
/** Jenis perubahan sejak rilis terakhir — bahasa Semantic Versioning. */
enum Jenis { PATCH, MINOR, MAJOR }
/** Satu perubahan masuk rilis berikutnya. */
record Perubahan(Jenis jenis, String contoh) {}
/** Naikkan versi sesuai jenis perubahan: patch +1, minor +1 & patch reset, major +1 & sisanya reset. */
static String versiBerikutnya(String versi, Jenis jenis) {
String[] angka = versi.split("\\.");
int mayor = Integer.parseInt(angka[0]);
int minor = Integer.parseInt(angka[1]);
int patch = Integer.parseInt(angka[2]);
return switch (jenis) {
case PATCH -> mayor + "." + minor + "." + (patch + 1);
case MINOR -> mayor + "." + (minor + 1) + ".0";
case MAJOR -> (mayor + 1) + ".0.0";
};
}
/** Satu lingkungan dalam rantai promosi: nama dan peran pemeriksaannya. */
record Lingkungan(String nama, String gerbang) {}
public static void main(String[] args) {
String versiKini = "2.1.0";
List<Perubahan> perubahan = List.of(
new Perubahan(Jenis.PATCH, "perbaiki kwitansi terpotong"),
new Perubahan(Jenis.MINOR, "laporan penjualan harian"),
new Perubahan(Jenis.MAJOR, "API pesanan berubah bentuk"));
System.out.println("== Matriks versi dari " + versiKini + " ==");
System.out.printf("%-7s %-30s %-10s %s%n", "jenis", "contoh perubahan", "versi", "arti bagi pengguna");
for (Perubahan p : perubahan) {
String arti = switch (p.jenis()) {
case PATCH -> "aman diperbarui (bugfix)";
case MINOR -> "aman; fitur baru tersedia";
case MAJOR -> "perlu penyesuaian konsumen API";
};
System.out.printf("%-7s %-30s %-10s %s%n",
p.jenis(), p.contoh(), versiBerikutnya(versiKini, p.jenis()), arti);
}
System.out.println();
List<Perubahan> rilisBerikut = List.of(
new Perubahan(Jenis.MINOR, "laporan penjualan harian"),
new Perubahan(Jenis.PATCH, "perbaiki kwitansi terpotong"));
String target = versiBerikutnya(versiKini, rilisBerikut.get(0).jenis());
System.out.println("== Rilis berikutnya: v" + target + " ==");
for (Perubahan p : rilisBerikut) {
System.out.println(" perubahan: [" + p.jenis() + "] " + p.contoh());
}
System.out.println(" nomor versi ditetapkan dari jenis terbesar: " + target);
System.out.println();
System.out.println("== Promosi artefak yang sama lintas lingkungan ==");
String cerna = "sha256:7f3c19ab"; // sidik jari artefak — identik di seluruh lingkungan
List<Lingkungan> rantai = List.of(
new Lingkungan("ci", "pengujian otomatis lulus"),
new Lingkungan("staging", "pemeriksaan manual + uji beban"),
new Lingkungan("produksi", "metrik sehat pasca rollout"));
for (Lingkungan l : rantai) {
System.out.printf(" %-9s %s %s%n", l.nama(), cerna, "(" + l.gerbang() + ")");
}
System.out.println();
System.out.println("== Strategi rollout dan jalur mundur ==");
System.out.printf("%-12s %-22s %s%n", "strategi", "cakupan awal", "jalur mundur");
System.out.printf("%-12s %-22s %s%n", "big-bang", "100% seketika", "redeploy versi lama");
System.out.printf("%-12s %-22s %s%n", "rolling", "pod bergantian", "pulihkan pod lama bertahap");
System.out.printf("%-12s %-22s %s%n", "blue-green", "saklar penuh ke hijau", "alihkan balik ke biru");
System.out.printf("%-12s %-22s %s%n", "canary", "1-5% trafik", "hentikan canary, trafik tetap di stabil");
}
}Output yang Dihasilkan:
== Matriks versi dari 2.1.0 ==
jenis contoh perubahan versi arti bagi pengguna
PATCH perbaiki kwitansi terpotong 2.1.1 aman diperbarui (bugfix)
MINOR laporan penjualan harian 2.2.0 aman; fitur baru tersedia
MAJOR API pesanan berubah bentuk 3.0.0 perlu penyesuaian konsumen API
== Rilis berikutnya: v2.2.0 ==
perubahan: [MINOR] laporan penjualan harian
perubahan: [PATCH] perbaiki kwitansi terpotong
nomor versi ditetapkan dari jenis terbesar: 2.2.0
== Promosi artefak yang sama lintas lingkungan ==
ci sha256:7f3c19ab (pengujian otomatis lulus)
staging sha256:7f3c19ab (pemeriksaan manual + uji beban)
produksi sha256:7f3c19ab (metrik sehat pasca rollout)
== Strategi rollout dan jalur mundur ==
strategi cakupan awal jalur mundur
big-bang 100% seketika redeploy versi lama
rolling pod bergantian pulihkan pod lama bertahap
blue-green saklar penuh ke hijau alihkan balik ke biru
canary 1-5% trafik hentikan canary, trafik tetap di stabilMari kita bedah matriksnya:
versiBerikutnya(versi, jenis): aturan kenaikan Semantic Versioning dalam satuswitch—PATCHmenambah angka terakhir,MINORmenaikkan angka tengah dan me-reset patch,MAJORmenaikkan angka pertama dan me-reset keduanya. Tiga bariscaseitu adalah seluruh spesifikasinya.- Rilis berikutnya
2.2.0: daftar berisi satuMINORdan satuPATCH, tetapi versi ditetapkan dari jenis terbesar — cukup satuMINORuntuk menjadikan seluruh rilis berversi minor. Angka mengikuti jenis perubahan paling berdampak. - Kolom arti bagi pengguna:
2.2.0memberi tahu pengguna bahwa pembaruan aman,3.0.0memberi tahu konsumen API untuk bersiap menyesuaikan kode. Nomor yang melompat tanpa alasan merusak kepercayaan pada kontrak ini. - Rantai promosi: sidik jari
sha256:7f3c19abidentik di tiga lingkungan — aplikasi tidak dibangun ulang untuk produksi, melainkan dipromosikan. Build once, deploy many dari chapter CI/CD menjadi baris yang bisa diperiksa: bandingkan cerna artefak antar lingkungan.
Changelog yang Bisa Diaudit #
Nomor versi menjawab “seberapa besar berubahnya”; changelog menjawab “apa persisnya yang berubah”. Format Keep a Changelog mengelompokkan perubahan per kategori dengan tanggal rilis beku:
## [2.2.0] - 2026-01-15
### Added
- Laporan penjualan harian dengan ekspor CSV.
### Fixed
- Kwitansi terpotong pada printer 58 mm.
## [2.1.1] - 2026-01-08
### Fixed
- Zona waktu laporan harian kini mengikuti Asia/Jakarta.Setiap rilis menjadi satu bagian ## [versi] - tanggal yang dikelompokkan per kategori (Added, Changed, Fixed, Removed), ditutup tautan pembanding antar tag.
Changelog seperti ini ditulis dari commit yang rapi — dan tag v2.2.0 yang dipendorong memicu workflow rilis dari chapter GitHub Actions: pipeline membangun artefak sekali, menempel versi sebagai tag image, lalu mengunggah GitHub Release berisi JAR dan catatan rilisnya. Nomor versi, tag git, tag image, dan changelog merujuk satu momen yang sama.
Strategi Rollout dan Jalur Mundur #
Rilis yang sehat punya rencana mundur sebelum digulirkan. Empat strategi menawarkan kompromi yang berbeda antara kecepatan dan pengamanan:
| Strategi | Cakupan awal | Kebutuhan infrastruktur | Cocok untuk |
|---|---|---|---|
| Big-bang | seluruh trafik seketika | paling sederhana | aplikasi internal berdampak kecil |
| Rolling | pod bergantian sedikit demi sedikit | replika lebih dari satu | layanan tanpa downtime |
| Blue-green | versi baru utuh diuji sebelum saklar | kapasitas dua kali lipat + saklar trafik | rilis besar yang butuh putar balik cepat |
| Canary | 1-5% trafik ke versi baru | pemisahan trafik + metrik per versi | layanan dengan jumlah pengguna besar |
Canary adalah bentuk paling hati-hati: sebagian kecil trafik sungguhan menguji rilis baru sementara metrik latensi, error, dan bisnis dipantau per versi — keputusan melanjutkan atau mundur diambil dari angka. Kubernetes Deployment menjalankan rolling secara bawaan; blue-green dan canary memakai service mesh atau alat rollout khusus.
Section ini menuntaskan perjalanan aplikasi Java dari ratusan berkas .class menjadi rilis bernomor versi yang teruji, terkontainerisasi, terobservasi, dan punya jalur mundur. Peralatan berikutnya di course ini menggeser fokus dari menyala dan terkendali menjadi berjalan cepat: section berikutnya membahas performance dan optimasi JVM secara mendalam.
Referensi #
- Semantic Versioning 2.0.0
- Keep a Changelog 1.1.0
- GitHub: About Releases
- Kubernetes: Deployments — strategi rolling update
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
MatriksRilis.java
Unduh berkasimport java.util.List;
/** Matriks rilis: jenis perubahan menentukan nomor versi, kanal, dan jalur mundur. */
public class MatriksRilis {
/** Jenis perubahan sejak rilis terakhir — bahasa Semantic Versioning. */
enum Jenis { PATCH, MINOR, MAJOR }
/** Satu perubahan masuk rilis berikutnya. */
record Perubahan(Jenis jenis, String contoh) {}
/** Naikkan versi sesuai jenis perubahan: patch +1, minor +1 & patch reset, major +1 & sisanya reset. */
static String versiBerikutnya(String versi, Jenis jenis) {
String[] angka = versi.split("\\.");
int mayor = Integer.parseInt(angka[0]);
int minor = Integer.parseInt(angka[1]);
int patch = Integer.parseInt(angka[2]);
return switch (jenis) {
case PATCH -> mayor + "." + minor + "." + (patch + 1);
case MINOR -> mayor + "." + (minor + 1) + ".0";
case MAJOR -> (mayor + 1) + ".0.0";
};
}
/** Satu lingkungan dalam rantai promosi: nama dan peran pemeriksaannya. */
record Lingkungan(String nama, String gerbang) {}
public static void main(String[] args) {
String versiKini = "2.1.0";
List<Perubahan> perubahan = List.of(
new Perubahan(Jenis.PATCH, "perbaiki kwitansi terpotong"),
new Perubahan(Jenis.MINOR, "laporan penjualan harian"),
new Perubahan(Jenis.MAJOR, "API pesanan berubah bentuk"));
System.out.println("== Matriks versi dari " + versiKini + " ==");
System.out.printf("%-7s %-30s %-10s %s%n", "jenis", "contoh perubahan", "versi", "arti bagi pengguna");
for (Perubahan p : perubahan) {
String arti = switch (p.jenis()) {
case PATCH -> "aman diperbarui (bugfix)";
case MINOR -> "aman; fitur baru tersedia";
case MAJOR -> "perlu penyesuaian konsumen API";
};
System.out.printf("%-7s %-30s %-10s %s%n",
p.jenis(), p.contoh(), versiBerikutnya(versiKini, p.jenis()), arti);
}
System.out.println();
List<Perubahan> rilisBerikut = List.of(
new Perubahan(Jenis.MINOR, "laporan penjualan harian"),
new Perubahan(Jenis.PATCH, "perbaiki kwitansi terpotong"));
String target = versiBerikutnya(versiKini, rilisBerikut.get(0).jenis());
System.out.println("== Rilis berikutnya: v" + target + " ==");
for (Perubahan p : rilisBerikut) {
System.out.println(" perubahan: [" + p.jenis() + "] " + p.contoh());
}
System.out.println(" nomor versi ditetapkan dari jenis terbesar: " + target);
System.out.println();
System.out.println("== Promosi artefak yang sama lintas lingkungan ==");
String cerna = "sha256:7f3c19ab"; // sidik jari artefak — identik di seluruh lingkungan
List<Lingkungan> rantai = List.of(
new Lingkungan("ci", "pengujian otomatis lulus"),
new Lingkungan("staging", "pemeriksaan manual + uji beban"),
new Lingkungan("produksi", "metrik sehat pasca rollout"));
for (Lingkungan l : rantai) {
System.out.printf(" %-9s %s %s%n", l.nama(), cerna, "(" + l.gerbang() + ")");
}
System.out.println();
System.out.println("== Strategi rollout dan jalur mundur ==");
System.out.printf("%-12s %-22s %s%n", "strategi", "cakupan awal", "jalur mundur");
System.out.printf("%-12s %-22s %s%n", "big-bang", "100% seketika", "redeploy versi lama");
System.out.printf("%-12s %-22s %s%n", "rolling", "pod bergantian", "pulihkan pod lama bertahap");
System.out.printf("%-12s %-22s %s%n", "blue-green", "saklar penuh ke hijau", "alihkan balik ke biru");
System.out.printf("%-12s %-22s %s%n", "canary", "1-5% trafik", "hentikan canary, trafik tetap di stabil");
}
}