Halaman ini membahas definisi sistem build, fungsinya, alasan Anda harus menggunakan sistem build, dan alasan compiler dan skrip build bukan pilihan terbaik saat organisasi Anda mulai diskalakan. Panduan ini ditujukan bagi developer yang tidak memiliki banyak pengalaman dengan sistem build.
Apa yang dimaksud dengan sistem build?
Pada dasarnya, semua sistem build memiliki tujuan yang sederhana: sistem tersebut mengubah kode sumber yang ditulis oleh engineer menjadi biner yang dapat dieksekusi dan dapat dibaca oleh mesin. Sistem build tidak hanya untuk kode yang ditulis manusia; sistem ini juga memungkinkan komputer membuat build secara otomatis, baik untuk pengujian maupun untuk rilis ke produksi. Di organisasi dengan ribuan engineer, umumnya sebagian besar build dipicu secara otomatis, bukan langsung oleh engineer.
Tidak bisakah saya menggunakan compiler saja?
Kebutuhan akan sistem build mungkin tidak langsung terlihat. Sebagian besar engineer
tidak menggunakan sistem build saat belajar membuat kode: sebagian besar memulai dengan memanggil alat
seperti gcc
atau javac
langsung dari command line, atau yang setara di
lingkungan pengembangan terintegrasi (IDE). Selama semua kode sumber berada di
direktori yang sama, perintah seperti ini akan berfungsi dengan baik:
javac *.java
Tindakan ini akan menginstruksikan compiler Java untuk mengambil setiap file sumber Java di direktori saat ini dan mengubahnya menjadi file class biner. Dalam kasus paling sederhana, ini adalah yang Anda butuhkan.
Namun, begitu kode diperluas, komplikasi akan dimulai. javac
cukup pintar
untuk mencari di subdirektori direktori saat ini guna menemukan kode yang
akan diimpor. Namun, tidak ada cara untuk menemukan kode yang disimpan di bagian lain
sistem file (mungkin library yang digunakan bersama oleh beberapa project). Alat ini juga hanya mengetahui
cara mem-build kode Java. Sistem besar sering kali melibatkan berbagai bagian yang ditulis dalam
berbagai bahasa pemrograman dengan jaringan dependensi di antara bagian tersebut,
yang berarti tidak ada compiler untuk satu bahasa yang dapat mem-build seluruh sistem.
Setelah Anda menangani kode dari beberapa bahasa atau beberapa unit kompilasi, proses build tidak lagi menjadi proses satu langkah. Sekarang Anda harus mengevaluasi apa saja yang menjadi dependensi kode Anda dan mem-build bagian-bagian tersebut dalam urutan yang tepat, mungkin menggunakan kumpulan alat yang berbeda untuk setiap bagian. Jika ada dependensi yang berubah, Anda harus mengulangi proses ini untuk menghindari dependensi pada biner yang sudah tidak berlaku. Untuk codebase dengan ukuran sedang, proses ini dengan cepat menjadi membosankan dan rentan error.
Compiler juga tidak tahu apa pun tentang cara menangani dependensi
eksternal, seperti file JAR
pihak ketiga di Java. Tanpa sistem build,
Anda dapat mengelolanya dengan mendownload dependensi dari internet, menyimpannya
di folder lib
di hard drive, dan mengonfigurasi compiler untuk membaca
library dari direktori tersebut. Seiring waktu, sulit untuk mempertahankan
update, versi, dan sumber dependensi eksternal ini.
Bagaimana dengan skrip shell?
Misalkan project hobi Anda dimulai cukup sederhana sehingga Anda dapat mem-build-nya hanya menggunakan compiler, tetapi Anda mulai mengalami beberapa masalah yang dijelaskan sebelumnya. Mungkin Anda masih merasa tidak memerlukan sistem build dan dapat mengotomatiskan bagian yang membosankan menggunakan beberapa skrip shell sederhana yang menangani pembuatan dalam urutan yang benar. Hal ini membantu untuk sementara, tetapi tidak lama lagi Anda akan mulai mengalami lebih banyak masalah:
Hal ini menjadi merepotkan. Seiring sistem menjadi lebih kompleks, Anda mulai menghabiskan hampir sama banyak waktu untuk mengerjakan skrip build seperti kode sebenarnya. Proses debug skrip shell sangat merepotkan, dengan semakin banyak hack yang ditumpuk satu sama lain.
Lambat. Untuk memastikan Anda tidak sengaja mengandalkan library yang sudah tidak berlaku, Anda harus membuat skrip build membuat setiap dependensi secara berurutan setiap kali menjalankannya. Anda berpikir untuk menambahkan beberapa logika guna mendeteksi bagian mana yang perlu dibangun ulang, tetapi hal itu terdengar sangat rumit dan rentan error untuk skrip. Atau, Anda berpikir untuk menentukan bagian mana yang perlu dibuat ulang setiap kali, tetapi Anda kembali ke awal.
Kabar baik: sekarang waktunya merilis. Sebaiknya cari tahu semua argumen yang perlu Anda teruskan ke perintah jar untuk membuat build akhir. Dan ingat cara menguploadnya dan mengirimkannya ke repositori pusat. Kemudian, build dan dorong update dokumentasi, serta kirim notifikasi kepada pengguna. Hmm, mungkin ini memerlukan skrip lain...
Bencana! Hard drive Anda mengalami error, dan sekarang Anda perlu membuat ulang seluruh sistem. Anda cukup cerdas untuk menyimpan semua file sumber dalam kontrol versi, tetapi bagaimana dengan library yang Anda download? Dapatkah Anda menemukannya lagi dan memastikan versinya sama seperti saat pertama kali mendownloadnya? Skrip Anda mungkin bergantung pada alat tertentu yang diinstal di tempat tertentu—dapatkah Anda memulihkan lingkungan yang sama sehingga skrip berfungsi kembali? Bagaimana dengan semua variabel lingkungan yang Anda tetapkan jauh-jauh hari agar compiler berfungsi dengan baik, lalu Anda lupa?
Meskipun ada masalah, project Anda cukup berhasil sehingga Anda dapat mulai mempekerjakan lebih banyak engineer. Sekarang Anda menyadari bahwa tidak perlu terjadi bencana agar masalah sebelumnya muncul—Anda harus melalui proses bootstraping yang merepotkan yang sama setiap kali developer baru bergabung dengan tim Anda. Dan meskipun Anda sudah berupaya sebaik mungkin, masih ada perbedaan kecil di sistem setiap orang. Sering kali, hal yang berfungsi di komputer satu orang tidak berfungsi di komputer orang lain, dan setiap kali diperlukan waktu beberapa jam untuk men-debug jalur alat atau versi library untuk mengetahui perbedaannya.
Anda memutuskan bahwa Anda perlu mengotomatiskan sistem build. Secara teori, hal ini sesederhana mendapatkan komputer baru dan menyiapkannya untuk menjalankan skrip build setiap malam menggunakan cron. Anda masih harus melalui proses penyiapan yang merepotkan, tetapi sekarang Anda tidak memiliki manfaat otak manusia yang dapat mendeteksi dan menyelesaikan masalah kecil. Sekarang, setiap pagi saat Anda masuk, Anda melihat bahwa build tadi malam gagal karena kemarin developer membuat perubahan yang berfungsi di sistem mereka, tetapi tidak berfungsi di sistem build otomatis. Setiap kali terjadi, Anda dapat memperbaikinya dengan mudah, tetapi hal ini sering terjadi sehingga Anda harus menghabiskan banyak waktu setiap hari untuk menemukan dan menerapkan perbaikan sederhana ini.
Build menjadi semakin lambat seiring berkembangnya project. Suatu hari, sambil menunggu build selesai, Anda menatap dengan sedih desktop rekan kerja yang tidak ada aktivitasnya, yang sedang berlibur, dan berharap ada cara untuk memanfaatkan semua daya komputasi yang terbuang sia-sia.
Anda mengalami masalah skala klasik. Untuk satu developer yang mengerjakan maksimal beberapa ratus baris kode selama maksimal satu atau dua minggu (yang mungkin merupakan seluruh pengalaman sejauh ini dari developer junior yang baru saja lulus universitas), compiler adalah satu-satunya yang Anda butuhkan. Skrip mungkin dapat membawa Anda sedikit lebih jauh. Namun, begitu Anda perlu berkoordinasi di beberapa developer dan komputer mereka, bahkan skrip build yang sempurna pun tidak cukup karena menjadi sangat sulit untuk memperhitungkan perbedaan kecil di komputer tersebut. Pada tahap ini, pendekatan sederhana ini akan gagal dan saatnya berinvestasi dalam sistem build yang sebenarnya.