Dari Kode Sumber ke Sesuatu yang Benar-Benar Bisa Dijalankan
Kamu baru saja selesai menulis kode di laptop. Kode itu berjalan sempurna. Semua fitur berfungsi. Tidak ada error. Kamu merasa puas. Sekarang kamu ingin menunjukkannya ke tim atau pengguna. Kamu menyalin folder proyek ke komputer lain dan mencoba menjalankannya. Tiba-tiba, tidak ada yang berfungsi. Muncul error yang belum pernah kamu lihat sebelumnya. Atau mungkin aplikasinya berjalan, tapi tampilannya sangat berbeda.
Kode yang sama. Hasil yang berbeda.
Inilah momen ketika banyak developer menyadari sesuatu yang penting: kode sumber bukanlah sesuatu yang bisa langsung dijalankan di mana saja. Kode sumber adalah bahan mentah. Ia adalah kumpulan file teks yang berisi instruksi program. Sebelum server mana pun, komputer pengguna mana pun, atau lingkungan produksi mana pun bisa menggunakannya, kode sumber itu perlu diubah menjadi sesuatu yang bisa dieksekusi.
Proses transformasi itu disebut build.
Mengapa Kode Sumber Tidak Bisa Langsung ke Produksi
Ada beberapa alasan mengapa kode sumber mentah belum siap dijalankan di luar laptop kamu.
Pertama, sebagian besar bahasa pemrograman membutuhkan penerjemahan. Java, Kotlin, Go, Rust, dan C# harus dikompilasi menjadi file biner atau bytecode. Bahasa seperti JavaScript, Python, atau Ruby tidak memerlukan kompilasi dengan cara yang sama, tetapi mereka tetap membutuhkan dependensi dan paket yang diatur dengan benar agar bisa bekerja di lingkungan yang berbeda.
Kedua, aplikasi modern hampir selalu bergantung pada library atau framework eksternal. Library ini perlu diunduh, ditempatkan di lokasi yang tepat, dan terkadang dikonfigurasi untuk setiap lingkungan. Kode kamu saja tidak berguna tanpa mereka.
Ketiga, aplikasi seringkali membutuhkan sumber daya seperti file konfigurasi, aset statis, template, atau gambar. Semua ini harus dikemas bersama dengan kode secara konsisten.
Semua pekerjaan ini — menerjemahkan kode, mengunduh dependensi, mengatur file, dan menghasilkan output yang siap dijalankan — inilah yang kita sebut build. Hasil dari sebuah build disebut artifact.
Seperti Apa Bentuk Artifact
Artifact hadir dalam berbagai bentuk tergantung pada tumpukan teknologi yang kamu gunakan.
Untuk aplikasi Java, artifact biasanya berupa file JAR atau WAR. Untuk aplikasi Go, artifact-nya adalah satu file biner. Untuk frontend web, artifact bisa berupa folder berisi file HTML, CSS, dan JavaScript yang sudah diminifikasi. Untuk aplikasi Python, bisa berupa paket yang berisi semua dependensi yang digabungkan.
Format spesifik tidak terlalu penting dibandingkan dengan apa yang diwakili oleh artifact: satu paket mandiri yang siap dijalankan. Artifact inilah yang dikirim ke server, ditempatkan di lingkungan staging, atau di-deploy ke produksi. Kode sumber itu sendiri tidak pernah langsung dikirim ke server. Yang dikirim selalu artifact.
Sebagai contoh, sebuah Dockerfile mendefinisikan langkah-langkah build yang mengubah kode sumber kamu menjadi image kontainer — format artifact yang umum:
FROM node:18-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
Anggap saja seperti memasak. Kode sumber adalah bahan-bahan kamu — tepung, telur, gula, mentega. Proses build adalah tindakan mencampur, memanggang, dan menyajikan. Artifact adalah kue yang sudah jadi. Kamu tidak mengirim bahan mentah ke meja makan restoran. Kamu mengirim kuenya.
Masalah dengan Banyak Build
Setelah kamu memahami bahwa build menghasilkan artifact, muncul pertanyaan baru. Kamu akan melakukan build aplikasi berkali-kali. Setiap perubahan kode, setiap perbaikan bug, setiap fitur baru memicu build baru. Bagaimana cara membedakan satu artifact dari yang lain?
Tanpa cara untuk membedakannya, kamu tidak akan tahu artifact mana yang sudah diuji, mana yang berjalan di produksi, dan mana yang baru. Ini menjadi kritis ketika terjadi kesalahan. Jika produksi rusak, kamu harus tahu persis artifact mana yang di-deploy di sana dan versi kode apa yang menghasilkannya.
Di sinilah identifikasi artifact menjadi penting. Setiap output build membutuhkan identitas unik. Identitas ini memungkinkan kamu melacak artifact apa pun kembali ke kode sumber, konfigurasi build, dan lingkungan yang tepat yang membuatnya.
Apa yang Terjadi Selama Build
Proses build yang khas melibatkan beberapa langkah, meskipun urutan pastinya tergantung pada teknologi yang kamu gunakan.
Diagram alir berikut menunjukkan urutan langkah-langkah tipikal yang mengubah kode sumber menjadi artifact yang dapat di-deploy:
Langkah pertama biasanya mengambil kode sumber terbaru dari sistem kontrol versi kamu. Ini memastikan kamu melakukan build persis seperti apa yang ada di repositori, bukan modifikasi lokal yang lupa kamu commit.
Berikutnya adalah resolusi dependensi. Alat build mengunduh semua library dan framework yang diperlukan. Langkah ini bisa lambat pada kali pertama, tetapi build berikutnya seringkali menyimpan cache dependensi untuk menghemat waktu.
Kemudian, kompilasi atau transformasi yang sebenarnya terjadi. Kode dikompilasi, aset diminifikasi, template diproses. Alat build menerapkan transformasi apa pun yang ditentukan dalam konfigurasi build kamu.
Setelah itu, sumber daya dirakit. File konfigurasi, file statis, dan aset lainnya dikumpulkan dan ditempatkan di lokasi yang benar dalam struktur output.
Terakhir, alat build mengemas semuanya ke dalam format artifact yang sesuai untuk aplikasi kamu. Ini bisa berupa arsip terkompresi, file biner, atau image kontainer.
Lingkungan Build Itu Penting
Satu detail kritis yang sering luput dari banyak tim: build harus dilakukan di lingkungan yang konsisten. Jika kamu melakukan build di laptop, hasilnya mungkin berbeda dengan build di mesin rekan kerja atau di server build. Sistem operasi yang berbeda, versi alat yang berbeda, library terinstal yang berbeda — semua ini dapat menghasilkan artifact yang berbeda dari kode sumber yang sama.
Inilah sebabnya tim profesional menggunakan server build khusus atau kontainer build. Lingkungan build distandarisasi dan dikendalikan. Setiap build berjalan dalam kondisi yang sama, menghasilkan artifact yang dapat direproduksi. Laptop kamu bukanlah server build, tidak peduli seberapa hati-hati kamu mengaturnya.
Artifact yang Di-deploy
Inilah prinsip yang terdengar jelas tetapi sering dilanggar: artifact yang kamu uji di staging harus persis sama dengan artifact yang kamu deploy ke produksi. Bukan di-build ulang dari kode yang sama. Bukan konfigurasi yang sedikit berbeda. File yang persis sama.
Jika kamu melakukan build ulang untuk produksi, kamu memperkenalkan risiko. Mungkin server build memiliki status yang berbeda. Mungkin versi dependensi berubah di antara build. Mungkin alat build berperilaku berbeda. Satu-satunya cara untuk memastikan bahwa apa yang kamu uji adalah apa yang berjalan di produksi adalah dengan menggunakan artifact yang identik.
Ini berarti proses build kamu harus menghasilkan satu artifact per versi kode kamu. Artifact itu dipromosikan melalui lingkungan — dari pengembangan ke pengujian ke staging ke produksi — tanpa di-build ulang. Artifact membawa identitasnya, dan kamu selalu bisa melacak dari mana asalnya.
Daftar Periksa Praktis untuk Proses Build Kamu
- Tentukan format artifact apa yang dihasilkan aplikasi kamu (JAR, biner, image kontainer, dll.)
- Siapkan lingkungan build khusus yang konsisten di semua build
- Konfigurasikan alat build kamu untuk menghasilkan pengidentifikasi versi unik untuk setiap build
- Simpan setiap artifact di repositori pusat yang bisa diambil kembali nanti
- Jangan pernah melakukan build ulang kode yang sama untuk lingkungan yang berbeda — promosikan artifact yang sama
- Dokumentasikan langkah-langkah dalam proses build kamu sehingga siapa pun di tim dapat memahaminya
Apa Artinya Ini untuk Pekerjaan Sehari-hari Kamu
Lain kali ketika kamu menjalankan aplikasi di laptop dan berhasil, ingatlah bahwa ini hanyalah awal. Kode itu perlu melalui proses build sebelum bisa dijalankan di tempat lain. Build mengubah kode sumber mentah kamu menjadi artifact — sebuah paket yang siap dijalankan di lingkungan mana pun yang dikonfigurasi dengan benar.
Memahami perbedaan antara kode sumber dan artifact mengubah cara kamu berpikir tentang pengiriman. Kode sumber adalah apa yang kamu tulis. Artifact adalah apa yang kamu deploy. Mereka bukanlah hal yang sama, dan memperlakukan mereka sebagai hal yang dapat dipertukarkan akan menyebabkan masalah "berfungsi di mesin saya" yang membuang waktu berjam-jam untuk debugging.
Bangun artifact kamu secara konsisten. Identifikasi mereka dengan jelas. Promosikan mereka melalui lingkungan tanpa melakukan build ulang. Disiplin sederhana ini menghilangkan seluruh kategori masalah deployment sebelum mereka mencapai produksi.