Dalam pengembangan perangkat lunak, sering terjadi permasalahan dependency hell. Semakin besar sistem yang dibuat dan semakin banyak modul yang digunakan sistem kita, semakin sering permasalahan ini akan terjadi.
Dalam sistem yang saling terkait, merilis versi baru bisa menjadi mimpi buruk. Jika spesifikasi dependensi sistem terlalu ketat, bisa jadi sistem kita tidak bisa dikembangkan lagi. Jika spesifikasi dependensi sistem terlalu bebas, semakin sulit untuk berasumsi versi mana yang bisa digunakan dengan versi yang lain. Dependency hell adalah saat Anda berada pada satu atau dua masalah ini, yang menahan Anda untuk bergerak maju dengan aman dan mudah.
Sebagai solusi permasalahan ini, saya mengusulkan seperangkat aturan dan persayaratan sederhana yang menentukan bagaimana nomor versi diberikan dan bertambah. Agar sistem ini dapat bekerja, Anda harus mengumumkan API publik terlebih dahulu. Ini dapat terdiri dari dokumentasi atau diberlakukan oleh kode itu sendiri. Apapun itu, API ini harus jelas dan tepat. Setelah Anda mengidentifikasi API publik Anda, Anda mengomunikasikan perubahan pada API tersebut dengan penambahan spesifik pada nomor versi Anda. Pertimbangkan format versi X.Y.Z (Major.Minor.Patch). Perbaikan bug yang tidak memengaruhi API tersebut akan menambah versi patch, penambahan/perubahan API yang kompatibel dengan versi sebelumnya akan menambah versi minor, dan perubahan API yang tidak kompatibel dengan versi sebelumnya akan menambah versi major.
Standar ini bernama “Pemversian Semantik”. Dengan skema ini, setiap orang yang melihat angka versi bisa tahu secara umum apa yang berubah dengan sistem tersebut.
Kata/frasa “HARUS” (“MUST”), “TIDAK BOLEH” (“MUST NOT”), “DIBUTUHKAN” (“REQUIRED”), “SEHARUSNYA” (“SHALL”), “JANGAN SAMPAI” (“SHALL NOT”), “SEBAIKNYA” (“SHOULD”), “SEBAIKNYA TIDAK” (“SHOULD NOT”), “DIREKOMENDASIKAN” (“RECOMMENDED”), “BISA” (“MAY”) , dan “OPSIONAL” di dokumen ini sesuai dengan RFC 2119.
Perangkat lunak dengan Pemversian Semantik HARUS menentukan API public. Bisa dijelaskan dengan kode, atau ditulis di dokumentasi saja. Apapun itu harus ditulis dengan jelas dan akurat.
Versi normal HARUS ditulis dalam bentuk X.Y.Z, dengan X, Y, dan Z adalah bilangan bulat. X adalah versi major, Y adalah minor, dan Z adalah patch. Setiap elemen HARUS bertambah secara numerik dengan kenaikan sebesar satu. Contohnya: 1.9.0 -> 1.10.0 -> 1.11.0
Ketika nomor versi major bertambah, versi minor dan patch versi HARUS diatur ulang ke nol. Ketika nomor versi minor bertambah, nomor versi patch HARUS disetel ulang ke nol. Misalnya: 1.1.3 -> 2.0.0 dan 2.1.7 -> 2.2.0.
Versi prarilis BISA ditulis dengan menambahkan titik dan rangkaian pengenal dengan pemisah titik tepat setelah versi patch. Pengenal ini HARUS terdiri dari hanya alfanumerik ASCII dan tanda pisah [0-9A-Za-z] dan HARUS mulai dengan sebuah huruf [A-Za-z]. Versi prarilis diperbolehkan, namun memiliki presendens yang lebih rendah dibandingkan dengan versi normal. Presedens SEBAIKNYA ditentukan dari urutan leksikografik ASCII. Contoh: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
Setelah sebuah paket berversi dirilis, isi dari versi tersebut TIDAK BOLEH diubah. Setiap perubahan harus dirilis sebagai versi baru.
Versi major 0 (0.y.z) adalah untuk pengembangan awal. Apapun bisa bisa berubah kapanpun. API publik sebaiknya dianggap tidak stabil di versi ini.
Versi 1.0.0 adalah titik awal API publik. Cara nomor versi ini dinaikkan setelah rilis ini adalah tergantung dengan API publik ini dan bagaimana ia berubah.
Versi patch Z (x.y.Z | x > 0) HARUS dinaikkan jika ada perbaikan bug yang kompatibel dengan versi lama. Sebuah perbaikan bug didefinisikan sebagai perubahan internal yang memperbaiki perilaku yang salah.
Versi minor Y (x.Y.z | x > 0) HARUS dinaikkan jika ada fitur baru yang kompatibel dengan versi lama dalam API publik. Ini BISA dinaikkan jika ada tambahan fungsionalitas substansial atau terjadi peningkatan di dalam kode privat. Ini BISA diubah bersama dengan perubahan tingkat patch.
Versi major X (X.y.z | X > 0) HARUS dinaikkan jika ada perubahan yang membuat versi baru tidak kompatibel dengan versi lama pada API publik. Ini BISA diubah bersama dengan perubahan tingkat patch dan minor.
Subspesifikasi ini SEBAIKNYA digunakan jika Anda menggunakan sistem kontrol versi (Git, Mercurial, SVN, dll) untuk menyimpan kode Anda. Dengan menggunaakan sistem ini, alat otomatis dapat memeriksa paket Anda dan menentukan kepatuhan SemVer dan versi yang dirilis.
Saat menandai rilis dalam sistem kontrol versi, tag untuk sebuah versi HARUS “vX.Y.Z”, seperti “v3.1.0”.
Revisi pertama yang memperkenalkan kepatuhan SemVer SEBAIKNYA diberi tag “semver”. Hal ini memungkinkan proyek yang sudah ada sebelumnya untuk mengasumsikan kepatuhan pada suatu titik dan agar alat otomatis tahu tentang hal ini.
Ini bukanlah ide baru yang revolusioner. Faktanya, kalian mungkin sudah menggunakan standar ini, hanya saja tidak terlalu ketat. Masalahnya, “tidak teralu ketat” saja tidak cukup bagus. Tanpa kepatuhan terhadap beberapa jenis spesifikasi formal, nomor versi adalah pada dasarnya tidak berguna untuk manajemen dependensi. Dengan memberikan nama dan definisi yang jelas definisi yang jelas untuk ide-ide tersebut, mengkomunikasikan maksud Anda kepada pengguna perangkat lunak Anda menjadi lebih mudah. Setelah maksud ini jelas, spesifikasi ketergantungan yang fleksibel (tetapi tidak terlalu fleksibel) akhirnya dapat dibuat.
Contoh sederhana ini menunjukkan manfaat Pemversian Semantik untuk menghilangkan “dependency hell.” Misalkan ada sebuah modul bernama “MobilPemadamKebakaran”. Modul “MobilPemadamKebakaran” membutuhkan modul lain bernama “Tangga”. Pada waktu “MobilPemadamKebakaran” dibuat, “Tangga” memiliki versi 3.1.0. Dengan menggunakan Pemversian Semantik, “MobilPemadamKebakaran” bisa dengan yakin menggunakan modul “Tangga” selama modul tersebut mempunyai versi antara 3.1.0 sampai dengan sebelum versi 4.0.0.
Sebagai pengembang yang bertanggung jawab, tentu saja Anda ingin memverifikasi bahwa peningkatan paket berfungsi seperti yang diiklankan. Dunia nyata tidaklah pasti; tidak ada yang bisa kita lakukan selain waspada. Yang bisa Anda lakukan adalah membiarkan Pemversian Semantik memberi Anda cara yang masuk akal untuk merilis dan memutakhirkan paket tanpa harus menggulirkan versi baru dari paket dependen, membuat Anda menghemat waktu dan kerumitan.
Jika menurut kalian aturan ini bagus, cara untuk memulai menggunakan pemversian semantik adalah dengan menautkan situs ini dalam README kalian supaya orang lain bisa tahu mengenai aturan ini dan mulai menggunakannya juga.
Jika perangkat lunak Anda digunakan dalam produksi, mungkin perangkat lunak Anda sudah versi 1.0.0. Jika Anda memiliki API yang stabil yang menjadi andalan pengguna, Anda harusnya sudah pada 1.0.0. Jika Anda sangat mengkhawatirkan kompatibilitas versi lama, Anda mungkin sudah pada 1.0.0.
Versi major nol adalah tentang pengembangan yang cepat. Jika Anda mengubah API setiap hari, Anda harus tetap berada di versi 0.x.x atau di pengembangan terpisah yang bekerja pada versi major berikutnya.
Ini adalah pertanyaan tentang pengembangan yang bertanggung jawab dan pandangan ke depan. Perubahan yang tidak kompatibel tidak boleh diperkenalkan dengan mudah ke perangkat lunak yang memiliki banyak kode dependen. Biaya yang harus dikeluarkan untuk meng-upgrade bisa sangat besar. Kewajiban mengganti versi major untuk merilis perubahan yang tidak kompatibel seharusnya membuat Anda memikirkan dampak dari perubahan Anda, dan mengevaluasi perbandingan biaya dan manfaat yang terkait.
Sudah tanggung jawab Anda sebagai pengembang profesional untuk mendokumentasikan perangkat lunak untuk digunakan oleh orang lain dengan benar. Mengelola kompleksitas perangkat lunak adalah bagian yang sangat penting dalam menjaga proyek tetap efisien, dan itu sulit dilakukan jika tidak ada yang tahu cara menggunakan perangkat lunak Anda, atau metode apa yang aman untuk dihubungi. Dalam jangka panjang, Pemversian Semantik, dan desakan pada API publik yang terdefinisi dengan baik dapat membuat semua orang dan segala sesuatu berjalan dengan lancar.
Setelah Anda menyadari bahwa Anda telah melanggar spesifikasi Pemversian Semantik, perbaiki dan rilis versi minor baru yang memperbaiki masalah dan mengembalikan kompatibilitas versi lama. Ingat, memodifikasi rilis yang telah diberi versi adalah dilarang, bahkan dalam kondisi ini. Jika mau, dokumentasikan versi yang bermasalah dan memberi tahu pengguna Anda tentang masalah tersebut sehingga mereka mengetahui versi yang bermasalah.
Hal tersebut dianggap kompatibel karena tidak mempengaruhi API publik. Perangkat lunak yang secara eksplisit bergantung pada dependensi yang sama dengan paket Anda harus memiliki spesifikasi dependensi mereka sendiri dan pembuatnya akan memberi tahu konflik yang ada. Menentukan apakah perubahan tersebut merupakan tingkat patch atau tingkat minor tergantung pada apakah Anda memperbarui dependensi untuk memperbaiki bug atau memperkenalkan fungsionalitas baru. Saya biasanya mengharapkan kode tambahan untuk contoh yang kedua, yang dalam hal ini jelas merupakan kenaikan tingkat minor.
Gunakan kebijakan terbaik Anda. Jika Anda memiliki audiens yang sangat besar yang akan terpengaruh secara drastis dengan apa yang dimaksudkan oleh API publik, maka lebih baik melakukan rilis versi major, meskipun perbaikannya dapat sangat dianggap sebagai rilis patch. Ingat, Pemversian Semantik adalah segalanya tentang menyampaikan makna melalui perubahan nomor versi. Jika perubahan ini perubahan ini penting bagi pengguna Anda, gunakan nomor versi itu untuk memberi tahu mereka.
Spesifikasi Pemversian Semantik dibuat oleh Tom Preston-Werner, pembuat Gravatars dan cofounder dari GitHub.
Terjemahan Bahasa Indonesia ditulis oleh Aditya Purwa, Christian B. Wibowo, dan Hans5958.
Untuk saran dan kritik, silahkan buka issue di GitHub.