Mengapa Perlu Sistem Build?

Halaman ini membahas apa yang dimaksud dengan sistem build, fungsinya, alasan Anda harus menggunakan sistem build, dan alasan compiler serta skrip build bukan pilihan terbaik saat organisasi Anda mulai melakukan penskalaan. Halaman ini ditujukan untuk developer yang tidak memiliki banyak pengalaman dengan sistem build.

Apa yang dimaksud dengan sistem build?

Pada dasarnya, semua sistem build memiliki tujuan yang jelas: 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 oleh manusia; sistem ini juga memungkinkan mesin membuat build secara otomatis, baik untuk pengujian maupun untuk rilis ke produksi. Di organisasi dengan ribuan engineer, biasanya sebagian besar build dipicu secara otomatis, bukan langsung oleh engineer.

Bisakah saya hanya menggunakan compiler?

Kebutuhan akan sistem build mungkin tidak langsung terlihat. Sebagian besar engineer tidak menggunakan sistem build saat belajar coding: sebagian besar mulai 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

Perintah ini menginstruksikan compiler Java untuk mengambil setiap file sumber Java di direktori saat ini dan mengubahnya menjadi file class biner. Dalam kasus yang paling sederhana, hanya ini yang Anda butuhkan.

Namun, begitu kode diperluas, komplikasi akan dimulai. javac cukup cerdas untuk mencari kode yang akan diimpor di subdirektori direktori saat ini. Namun, `javac` tidak dapat menemukan kode yang disimpan di bagian lain dari sistem file (mungkin library yang dibagikan oleh beberapa project). Selain itu, `javac` hanya tahu cara mem-build kode Java. Sistem besar sering kali melibatkan berbagai bagian yang ditulis dalam berbagai bahasa pemrograman dengan jaringan dependensi di antara bagian-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, mem-build kode tidak lagi menjadi proses satu langkah. Sekarang Anda harus mengevaluasi dependensi kode dan mem-build bagian-bagian tersebut dalam urutan yang benar, yang 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 tidak berlaku lagi. Untuk codebase dengan ukuran sedang, proses ini akan dengan cepat menjadi membosankan dan rentan error.

Compiler juga tidak mengetahui cara menangani dependensi eksternal, seperti file JAR pihak ketiga di Java. Tanpa sistem build, Anda dapat mengelola hal ini dengan mendownload dependensi dari internet, menempelkannya di folder lib di hard drive, dan mengonfigurasi compiler untuk membaca library dari direktori tersebut. Seiring waktu, akan sulit untuk mempertahankan update, versi, dan sumber dependensi eksternal ini.

Bagaimana dengan skrip shell?

Misalkan project hobi Anda dimulai dengan cukup sederhana sehingga Anda dapat mem-build-nya hanya menggunakan compiler, tetapi Anda mulai mengalami beberapa masalah yang dijelaskan sebelumnya. Mungkin Anda masih berpikir bahwa Anda tidak memerlukan sistem build dan dapat mengotomatiskan bagian yang membosankan menggunakan beberapa skrip shell sederhana yang menangani build dalam urutan yang benar. Hal ini akan membantu untuk sementara waktu, tetapi Anda akan segera mulai mengalami lebih banyak masalah:

  • Prosesnya menjadi membosankan. Saat sistem Anda menjadi lebih kompleks, Anda mulai menghabiskan hampir waktu yang sama untuk mengerjakan skrip build seperti pada kode sebenarnya. Proses debug skrip shell sangat menyakitkan, dengan semakin banyak hack yang ditumpuk satu sama lain.

  • Prosesnya lambat. Untuk memastikan Anda tidak secara tidak sengaja mengandalkan library yang tidak berlaku lagi, Anda memiliki skrip build yang mem-build setiap dependensi secara berurutan setiap kali Anda menjalankannya. Anda berpikir untuk menambahkan beberapa logika untuk mendeteksi bagian mana yang perlu di-build ulang, tetapi hal itu terdengar sangat kompleks dan rentan error untuk skrip. Atau, Anda berpikir untuk menentukan bagian mana yang perlu di-build ulang setiap kali, tetapi kemudian Anda kembali ke awal.

  • Kabar baik: saatnya rilis! Sebaiknya cari tahu semua argumen yang perlu Anda teruskan ke perintah jar untuk membuat build akhir. Dan ingat cara mengupload dan mengirimkannya ke repositori pusat. Serta build dan kirimkan update dokumentasi, dan kirimkan notifikasi kepada pengguna. Hmm, mungkin ini memerlukan skrip lain...

  • Bencana! Hard drive Anda rusak, 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 menemukan semuanya lagi dan memastikan bahwa library tersebut memiliki versi yang sama seperti saat Anda mendownloadnya pertama kali? Skrip Anda mungkin bergantung pada alat tertentu yang diinstal di tempat tertentu—dapatkah Anda memulihkan lingkungan yang sama sehingga skrip dapat berfungsi lagi? Bagaimana dengan semua variabel lingkungan yang Anda tetapkan sejak lama agar compiler berfungsi dengan benar, lalu Anda lupakan?

  • Terlepas dari masalah tersebut, project Anda cukup berhasil sehingga Anda dapat mulai merekrut lebih banyak engineer. Sekarang Anda menyadari bahwa tidak perlu terjadi bencana agar masalah sebelumnya muncul—Anda harus melalui proses bootstrapping yang menyakitkan yang sama setiap kali developer baru bergabung dengan tim Anda. Dan meskipun Anda telah melakukan upaya terbaik, masih ada sedikit perbedaan dalam sistem setiap orang. Sering kali, hal yang berfungsi di mesin satu orang tidak berfungsi di mesin orang lain, dan setiap kali perlu beberapa jam untuk men-debug jalur alat atau versi library untuk mengetahui letak 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 perlu melalui proses penyiapan yang menyakitkan, tetapi sekarang Anda tidak memiliki manfaat dari otak manusia yang dapat mendeteksi dan menyelesaikan masalah kecil. Sekarang, setiap pagi saat Anda masuk, Anda melihat bahwa build tadi malam gagal karena kemarin seorang developer melakukan perubahan yang berfungsi di sistemnya, tetapi tidak berfungsi di sistem build otomatis. Setiap kali ada perbaikan sederhana, tetapi hal ini sering terjadi sehingga Anda menghabiskan banyak waktu setiap hari untuk menemukan dan menerapkan perbaikan sederhana ini.

  • Build menjadi semakin lambat seiring pertumbuhan project. Suatu hari, saat menunggu build selesai, Anda menatap dengan sedih desktop rekan kerja yang sedang berlibur dan berharap ada cara untuk memanfaatkan semua daya komputasi yang terbuang.

Anda telah mengalami masalah skala klasik. Untuk satu developer yang mengerjakan paling banyak beberapa ratus baris kode selama paling banyak satu atau dua minggu (yang mungkin merupakan seluruh pengalaman sejauh ini dari developer junior yang baru lulus dari universitas), compiler adalah semua yang Anda butuhkan. Skrip mungkin dapat membawa Anda sedikit lebih jauh. Namun, begitu Anda perlu berkoordinasi dengan beberapa developer dan mesin mereka, bahkan skrip build yang sempurna pun tidak cukup karena akan sangat sulit untuk memperhitungkan perbedaan kecil di mesin tersebut. Pada titik ini, pendekatan sederhana ini akan rusak dan saatnya berinvestasi dalam sistem build yang sebenarnya.