Kenapa Rebuild untuk Production Lebih Berisiko dari yang Terlihat

Kamu punya green build di staging. Semua tes lulus. Tim siap rilis. Lalu seseorang berkata, "Gampang, kita checkout tag yang sama, rebuild, lalu deploy ke production. Nggak perlu repot nyimpen artifact lama."

Kedengarannya efisien. Tidak perlu kelola penyimpanan artifact. Tidak perlu cari-cari build lama. Tinggal jalankan build lagi dan kirim. Tapi jalan pintas yang tampak praktis ini membawa dua masalah yang diam-diam menggerogoti apa yang ingin kamu capai dengan delivery pipeline: kamu kehilangan traceability dan reproducibility.

Masalah Traceability

Saat kamu rebuild untuk production, artifact yang berjalan di production BUKAN artifact yang sama yang lulus tes di staging. Kamu membangun dari source code yang sama, tapi proses build menghasilkan artifact baru dengan identitas baru. Checksum-nya berbeda, timestamp build-nya berbeda, dan metadata yang tertanam di dalamnya pun bisa berbeda.

Jika terjadi masalah di production, kamu tidak bisa menunjuk hasil staging dan berkata "artifact persis inilah yang sudah dites." Kamu harus percaya bahwa build kedua menghasilkan output yang identik. Tanpa verifikasi, kepercayaan itu buta.

Diagram alir berikut membandingkan kedua jalur:

flowchart TD A[Source Code yang Sama] --> B[Build Kedua] B --> C[Artifact Baru] C --> D[Checksum & Timestamp Berbeda] D --> E[Deploy ke Production] E --> F[Traceability Hilang] G[Satu Kali Build] --> H[Artifact dengan Identitas Tetap] H --> I[Promote ke Staging] I --> J[Promote ke Production] J --> K[Traceability Terjaga]

Traceability bukan soal dokumen. Ini soal kemampuan menjawab pertanyaan sederhana: "Apa yang sebenarnya berjalan di production sekarang, dan bagaimana saya tahu itu cocok dengan yang sudah dites?" Saat kamu rebuild, pertanyaan itu jadi sulit dijawab dengan yakin.

Masalah Reproducibility

Bahkan jika kamu checkout commit yang persis sama, proses build tidak selalu menghasilkan output yang sama. Banyak faktor yang bisa mengubah hasil antara dua build:

Dependency drift. Build pertama hari Senin menarik library open source versi 1.2.3. Hari Rabu, maintainer merilis versi 1.2.4. Build kedua menarik versi baru secara otomatis. Tidak ada source code yang berubah, tapi perilaku aplikasi bisa berubah. Patch minor bisa memperbaiki bug yang kamu andalkan, atau malah memperkenalkan regresi. Bisa juga diam-diam menarik celah keamanan.

Pembaruan base image. Jika build kamu menggunakan Docker base image dengan tag latest atau bahkan versi minor tertentu yang mendapat patch, build kedua mungkin menggunakan lapisan sistem operasi yang berbeda. Kode aplikasi sama, tapi lingkungan runtime-nya bergeser.

Perbedaan lingkungan build. CI runner yang membangun staging mungkin memiliki versi JDK, Node.js runtime, atau library sistem yang sedikit berbeda. Mungkin build cache kedaluwarsa di antara dua eksekusi, menyebabkan kompilasi ulang penuh yang menghasilkan bytecode berbeda. Perbedaan ini jarang terlihat saat development, tapi bisa menyebabkan kegagalan halus di production.

Timestamp dan metadata. Banyak build tools menyematkan timestamp, nomor build, atau commit hash ke dalam artifact. Meskipun kode fungsionalnya identik, metadata artifact-nya berbeda. Ini mempersulit debugging saat kamu perlu menghubungkan perilaku production dengan build tertentu.

Dampak di Dunia Nyata

Masalah-masalah ini bukan teori. Tim pernah mengirim rebuild ke production hanya untuk menemukan bahwa dependency yang diperbarui otomatis membawa celah keamanan. Tim lain melihat perubahan perilaku aplikasi karena update level patch di library mengubah cara kerja suatu fungsi. Dalam beberapa kasus, rebuild menghasilkan artifact yang berfungsi baik di development tapi gagal di production karena lingkungan build memiliki versi compiler yang berbeda.

Bagian terburuknya: masalah ini sulit dideteksi. Pipeline menunjukkan hijau. Commit hash cocok. Semuanya terlihat baik-baik saja sampai seseorang menyadari ada yang tidak beres di production, dan saat itu, melacak akar masalah menjadi investigasi forensik.

Prinsipnya: Build Sekali, Promote Berkali-kali

Inilah kenapa prinsip "build once, promote many" ada. Kamu membangun artifact sekali, memverifikasinya, lalu mempromosikan artifact yang persis sama melalui setiap environment: development, staging, production. Tidak ada rebuild. Tidak ada kesempatan kedua.

Dengan pendekatan ini, artifact di production secara fisik identik dengan artifact yang lulus semua tes. Checksum-nya cocok. Metadata yang tertanam cocok. Kamu tahu persis apa yang dites dan apa yang dikirim. Traceability sudah built-in karena setiap artifact memiliki pengenal unik yang terhubung ke commit, konfigurasi build, dan timestamp-nya. Reproducibility tidak perlu dikhawatirkan karena kamu tidak mereproduksi apa pun - kamu menggunakan binary yang sama.

Kapan Rebuild Tidak Terhindarkan

Ada kasus sah di mana rebuild diperlukan. Artifact lama mungkin tidak kompatibel dengan upgrade infrastruktur production. Patch keamanan kritis di base image mungkin memaksa rebuild. Persyaratan kepatuhan mungkin menuntut artifact production dibangun dari lingkungan hardened tertentu.

Situasi ini ada, tapi harus menjadi pengecualian, bukan default. Setiap kali tim kamu memutuskan rebuild untuk production, kamu harus secara eksplisit mengakui risikonya: kamu memutus traceability, dan kamu bertaruh bahwa build tersebut reproducible. Dokumentasikan keputusan itu, verifikasi output terhadap build asli, dan jadikan sebagai kesempatan review insiden untuk mencegah rebuild di masa depan.

Checklist Praktis Sebelum Rebuild untuk Production

  • Dapatkah kamu memverifikasi bahwa artifact hasil rebuild secara fungsional identik dengan artifact yang sudah dites?
  • Apakah semua versi dependency, termasuk transitive dependency, sudah di-pin?
  • Apakah lingkungan build (compiler, runtime, system libraries) identik dengan build asli?
  • Apakah base image di-pin ke digest spesifik, bukan tag?
  • Apakah kamu punya alasan terdokumentasi mengapa promosi artifact asli tidak memungkinkan?
  • Apakah tim sudah setuju untuk memperlakukan ini sebagai pengecualian, bukan praktik standar?

Intinya

Setiap rebuild untuk production memasukkan ketidakpastian ke dalam delivery pipeline kamu. Kamu kehilangan kemampuan untuk mengatakan dengan yakin bahwa artifact yang berjalan di production adalah yang sama dengan yang lulus pengujian. Penghematan penyimpanan artifact atau kemudahan jarang sebanding dengan biaya debugging saat terjadi masalah. Build sekali. Promosikan artifact yang sama ke mana-mana. Biarkan rebuild menjadi pengecualian yang membutuhkan justifikasi eksplisit, bukan jalur default menuju production.