- Beberapa proyek perangkat lunak bersifat berdarah panas, yang hanya bisa bertahan jika ada aktivitas pengembangan berkelanjutan; jika aktivitas sempat terhenti tetapi masih bisa dilanjutkan lagi, proyek itu lebih dekat ke tipe berdarah dingin
- Proyek berdarah dingin memilih teknologi yang membosankan agar build dan test tidak rusak meski lama berhenti, serta menghindari ketergantungan pada layanan eksternal yang bisa berubah atau hilang
- Akuisisi atau penutupan layanan yang diandalkan, upgrade compiler, dan dihentikannya dukungan paket akan kembali sebagai biaya pemeliharaan saat proyek yang jarang aktif ingin dimulai lagi
- Kode seperti proyek pribadi yang tidak disentuh selama 1, 2, atau 3 tahun sulit menghasilkan panas secara terus-menerus, sehingga harus dirancang sejak awal dengan asumsi tingkat perubahan rendah
- Generator situs statis untuk blog ini, sejak commit pertamanya pada 2012, terus berjalan hampir tanpa perubahan hanya dengan Python 2, 4 modul pihak ketiga yang disertakan di repositori, eksekusi lokal, dan deployment
rsyncoverssh
Cara mempertahankan proyek dilihat dari analogi hewan berdarah dingin
- Dalam kuliah sejarah alam tahun 2004, seorang profesor meletakkan anak painted turtle yang baru diambil dari freezer di bawah kamera sambil melanjutkan kuliah
- Anak painted turtle adalah salah satu dari sedikit spesies yang bisa bertahan hidup meski dalam keadaan membeku
- Selama satu jam, kura-kura itu mulai dari gerakan yang nyaris tak terlihat, lalu pada akhirnya berpindah sekitar setengah layar
- Hewan berdarah panas harus menjaga suhu tubuh dalam rentang sempit, dan manusia akan bermasalah jika keluar dari sekitar 37°C
- Hewan berdarah dingin menyesuaikan metabolisme dengan suhu sekitar; mereka aktif saat hangat, dan bergerak makin lambat ketika tubuh serta lingkungannya makin dingin
- Proyek perangkat lunak juga bisa dibagi dengan cara serupa
- Perangkat lunak berdarah panas berjalan baik ketika ada pergerakan dan panas yang terus-menerus di dalam proyek
- Jika dibiarkan berhenti selama 6 bulan, saat dikeluarkan lagi proyek itu bisa tampak seperti sudah mati
Syarat dan contoh perangkat lunak berdarah dingin
- Alasan proyek berdarah panas menjadi sulit dimulai lagi adalah karena perubahan eksternal terus menumpuk
- Layanan yang diandalkan CI bisa diakuisisi atau kehabisan dana lalu berhenti berfungsi
- Saat ingin menambah dependensi baru, bisa jadi perlu upgrade compiler
- Paket lain mungkin sudah tidak didukung lagi sehingga tidak berjalan dengan compiler terbaru
- Proyek yang dikerjakan sendirian, hanya diubah saat ada inspirasi, lalu tidak disentuh lagi selama lebih dari setahun sulit dijalankan sebagai proyek berdarah panas
- Proyek berdarah dingin harus bisa dimulai lagi dari titik berhenti yang sama setahun kemudian, seperti anak painted turtle yang membeku
- Untuk itu, proyek memakai teknologi yang membosankan dan tidak bergantung pada layanan eksternal tempat script build dan test bisa berubah, rusak, atau hilang sepenuhnya
- Dependensi disertakan di dalam repositori proyek seperti pada pendekatan vendored dependencies
- Perangkat lunak yang menjalankan blog ini adalah contoh proyek berdarah dingin
- Commit pertamanya pada 8 Januari 2012, dan awalnya merupakan generator situs statis kecil untuk menggantikan instalasi Wordpress lama
- Ditulis dengan Python 2, bergantung pada 4 modul pihak ketiga, dan semuanya di-commit ke repositori proyek
- Semua proses dijalankan secara lokal, dan hasilnya dideploy dengan
rsyncoverssh - Selain beberapa perbaikan kecil, perangkat lunak ini terus berjalan tanpa perubahan, dan diharapkan masih akan terus berjalan 12 tahun lagi
1 komentar
Pendapat Hacker News
Express, framework web dalam ekosistem Node dan JavaScript, saat ini masih mempertahankan versi mayor 4.x.x selama lebih dari 10 tahun https://www.npmjs.com/package/express?activeTab=versions
Meski begitu, framework ini masih sangat banyak dipakai hingga diunduh lebih dari 17 juta kali per minggu https://www.npmjs.com/package/express, dan walaupun fiturnya tidak lengkap atau performanya bukan yang terbaik https://fastify.dev/benchmarks/, hal baiknya adalah ia memungkinkan pengembangan yang cepat dan stabil serta perencanaan jangka panjang
Kita tidak perlu khawatir soal penghentian patch keamanan untuk versi lama atau perubahan API yang drastis, dan Go bahkan lebih stabil karena berkat standard library yang luas serta janji kompatibilitasnya, program berusia lebih dari 10 tahun pun masih bisa dijalankan https://go.dev/doc/go1compat
Saat pertama muncul, hanya karena ditulis dengan JavaScript, ia sering diperlakukan seperti sampah untuk programmer palsu yang amatiran, tetapi setelah itu Express membantu berbagai perusahaan membangun layanan keren yang benar-benar menghasilkan uang, dan sekarang pasti sedang menangani jumlah request yang sangat besar
Sekarang saya juga banyak menulis dengan Go, tetapi saya masih sepenuhnya puas membangun layanan dengan Express, dan secara keseluruhan menganggapnya software yang bagus
Bukan berarti benar-benar membencinya, tetapi rasanya saya tidak akan memilihnya karena roda hamster upgrade versi yang tak ada habisnya
Python adalah contoh yang sangat buruk untuk software berdarah dingin
Ada breaking changes terus-menerus, baik di runtime maupun tooling, dan penulisnya juga berada dalam situasi harus tetap memakai Python 2 yang dukungannya sudah berakhir sejak lama
Contoh yang lebih baik adalah bahasa seperti Go atau Java, di mana kode berusia 10 tahun masih berjalan baik dengan tooling modern; atau lebih ekstrem lagi, Perl, di mana kode berusia 30 tahun pun masih berjalan dengan baik
Saat membuat software, kita bisa saja membuat kesalahan yang memungkinkan pengguna melakukan sesuatu dengan cara yang tidak kita maksudkan; di dunia Java, masalah seperti ini diselesaikan dengan menambahkan fitur yang lebih baru, lebih aman, dan lebih jelas maksudnya, lalu mendorong pengguna untuk bermigrasi
Python juga mirip, tetapi ditambah dengan “dan sebentar lagi fitur lama akan dimatikan”, sedangkan Java tidak begitu
Misalnya, metode
equalspadajava.net.URLdikenal sebagai desain yang rusak dan sangat tidak disarankan, tetapi tetap didukung selama lebih dari 20 tahunDi Python Airflow, operator kosong sempat mendukung nama
DummyOperator, tetapi karena “dummy” pernah dipakai sebagai istilah peyoratif secara historis dan budaya, maintainer mengubahnya agar memakaiEmptyOperatordan merusak nama lamaSetelah upgrade, kode akan error saat proses load sampai nama referensinya diganti, dan secara pribadi saya rasa saya tidak akan merusak pengguna dengan cara seperti ini
Di dunia Java, perubahan nama semacam itu cukup bisa ditangani dengan penggantian teks, jadi kemungkinan akan terus didukung sampai ada alasan yang benar-benar membuatnya tidak bisa dipertahankan
Karena itu, secara keseluruhan menurut saya Java dan dependensi library Java bisa di-upgrade jauh lebih bebas dibanding Python
Jika memakai versi Java LTS dan memilih dependensi yang bagus, kita bisa membuatnya bisa dijalankan ulang kapan saja
Di Python, saat kelas machine learning, pernah ada satu dependensi yang memasukkan perubahan API yang merusak dalam semalam, dan instrukturnya tidak menyadarinya karena masih memakai versi terbaru dari beberapa minggu sebelumnya ketika ia mulai menyiapkan kelas
Peralihan dari Python 2 ke 3 memang breaking change, tetapi itu satu kali perubahan, bukan “breaking changes yang terus-menerus”
Jika tetap berada di versi mayor yang sama, kode lama tidak akan rusak di versi minor baru; misalnya kode 2.x lama berjalan baik di 2.7 dan kode 3.x lama juga berjalan baik di 3.12
Perubahan versi minor memang bisa menambahkan fitur baru, tetapi kode 3.x lama tidak akan rusak hanya karena tidak memakai keyword
asyncatau type hintIni salah satu alasan saya menghindari Python jika memungkinkan
Saya merasa kecil kemungkinannya kode Python yang ditulis hari ini masih akan berjalan beberapa tahun kemudian, dan menurut saya itu masalah yang cukup besar
Bahkan ketika mencoba menjalankan kode Java berusia 3 tahun dengan SDK baru, selalu saja ada sesuatu yang rusak
Saya bekerja di mainframe IBM (z/OS), dan dalam hal menjaga kompatibilitas mundur, saya hampir tidak pernah melihat yang sedekat IBM
Menurut saya Microsoft Windows berada di posisi kedua, dan ABI kernel Linux mungkin sekitar posisi ketiga, tetapi jika dilihat dari keseluruhan ekosistem Linux itu hanya bagian kecil
Sebagian besar lainnya lebih dekat ke churn, dan di open source tampaknya jarang ada orang yang ingin meluangkan waktu untuk kompatibilitas mundur sebagai hobi
Secara ekonomi ini terlihat seperti dilema tahanan: semua orang melempar biaya menjaga kompatibilitas kepada orang lain, dan akibatnya semua orang malah menciptakan lebih banyak pekerjaan yang tidak berguna bagi semua pihak
Misalnya, jika melihat komunitas retro computing, tidak jarang orang menulis driver agar hardware baru bisa berjalan di sistem operasi lama
Kalau tidak ada bayaran, pada akhirnya bergantung pada seberapa besar kita menyayangi platform yang kita buat, dan karena komitmen yang terbukti terhadap stabilitas ABI, saya memutuskan menargetkan kernel Linux secara langsung melalui system call
Sebaliknya, untuk bahasa pemrograman yang saya buat sendiri, saya ingin membuatnya se“sempurna” mungkin sehingga terus muncul keinginan untuk memperbaikinya
Karena khawatir ada orang yang nekat memakainya secara serius, saya menaruh pemberitahuan di README bahwa proyek ini masih tahap pengembangan awal dan belum stabil
Saya kira orang-orang yang membuat Ruby atau Python juga merasakan hal serupa; karena bahasa itu terasa seperti anak sendiri dan mereka ingin bahasa itu sukses, mereka bisa merasa bahwa kesalahan seperti ketika
printdulu berupa keyword memang harus diperbaikiBahkan bagian yang dibuat demi kompatibilitas mundur pun sering rusak
Di pekerjaan sebelumnya, kami membuat aplikasi Node yang dikontainerisasi, dan CI membangun image dari source Node; deployment layanan-layanan yang tidak disentuh selama beberapa waktu tiba-tiba mulai gagal
Ternyata Dockerfile-nya berbasis image Ubuntu yang masa dukungannya sudah berakhir, dan repository update-nya dipindahkan ke archive repository, sehingga image tidak bisa dibangun tanpa memperbaiki Dockerfile
Itu contoh software yang tidak disentuh tapi tetap rusak, dan karena itulah saya menyukai Go dan single binary
Jika sudah dipaketkan sebagai release, tidak perlu dibangun ulang, dan image Docker Distroless tidak punya dependensi selain binary saya
Saya sudah lama memakai Go, tetapi belum pernah mengalami masalah software yang rusak seiring bertambahnya usia; berbagai jenis masalah yang saya rasakan saat memakai Node atau PHP pun hilang
Masalah terbesar kedua di sisi Node adalah pola-pola indireksi pada framework, dan yang pertama adalah manajemen paket
Masalah peer dependency seperti “saya memasang versi X, tetapi modul Y membutuhkan versi Z” terus muncul
Banyak engineer saat mencari library di GitHub memeriksa waktu commit terakhir
Ada kecenderungan menganggap commit yang lebih baru berarti library tersebut lebih didukung
Namun jika sebuah proyek yang sudah diarsipkan melakukan persis apa yang dibutuhkan, memiliki 0 bug, dan stabil selama bertahun-tahun, itu seperti menemukan permata tersembunyi di toko barang bekas
Sekarang banyak engineer otomatis membuang library yang tidak “terus-menerus” diperbarui, dan tampaknya mereka menganggap itu hal yang baik
Lingkungan pengembangan software modern sering kali tidak seperti itu, dan frontend web adalah contoh khas yang sering berubah
Jika library benar-benar independen, tidak adanya update bisa saja tidak masalah, tetapi library yang bergantung pada framework frontend web akan menimbulkan masalah jika tidak diperbarui mengikuti perubahan ekosistem
Saya tidak tahu angka pastinya, tetapi menurut saya dalam mayoritas besar kasus, tidak adanya aktivitas terbaru berarti “ditinggalkan”, bukan “sudah selesai dan bebas bug”
Ada bahasa yang menjadi hampir berbeda sama sekali dari versi 1.0, dan ada bahasa yang mempertahankan sebagian besar kode yang sudah ditulis lalu hanya menambahkan di atasnya
Pada akhirnya, kecenderungan itu tampaknya juga tercermin pada komunitas dan ekosistemnya
Seingat saya Clojure berada di peringkat atas karena hampir tidak pernah membuat perubahan yang merusak, dan library yang terakhir berubah 5 tahun lalu pun berjalan sempurna pada versi bahasa saat ini
Fakta bahwa ia berasal dari keluarga Lisp, sehingga inti bahasa bisa diperluas tanpa perubahan upstream, tampaknya juga membantu, meski tentu itu punya cacatnya sendiri
Namun saya suka karena itu membuat saya berhenti menganggap “segar” sama dengan “bagus”
Belakangan ini saya lebih sering memakai library yang hampir tidak berubah sejak beberapa tahun lalu daripada library yang baru dibuat tahun lalu, dan tidak ada masalah besar
Ada bahasa yang rilis setiap 1–2 tahun dan banyak dipakai, sambil menambahkan sintaks baru yang elegan atau tipe data abstrak di standard library untuk menggantikan pola yang sering dipakai tetapi terasa canggung
Komunitas bahasa tersebut hampir langsung menganggap sintaks baru itu “idiomatis”, dan menilai kode yang ditulis dengan cara lama yang lamban perlu diperbaiki
Alasan untuk mengubah codebase tertentu biasanya adalah bahwa dibanding sintaks baru, cara lama lebih tidak jelas dan membuat maintenance serta code review lebih sulit
Logikanya, jika sintaks baru itu sudah ada sejak awal, tidak ada yang akan menganggap cara lama sebagai kode yang baik; jadi kode harus diperbarui demi meningkatkan keterbacaan bagi developer baru dan menurunkan hambatan untuk berkontribusi
Jika library yang diimplementasikan dengan bahasa seperti ini tidak diperbarui selama lebih dari 3 tahun, itu sering menjadi sinyal buruk
Itu bisa berarti developernya tidak cukup terhubung dengan komunitas untuk menjaga kode tetap idiomatis dan mudah dibaca oleh developer lain yang mempelajari bentuk terbaru bahasa tersebut, dan mungkin juga tidak berminat menerima PR eksternal
Bisa saja proyek itu ditandai sebagai ditinggalkan sehingga tidak ada yang melaporkan, padahal mungkin ada kerentanan keamanan
Perangkat lunak yang bisa bertahan tanpa pembaruan hanyalah perangkat lunak yang sejak awal dibuat dengan benar
Kalau perangkat lunak itu hanya untuk diri sendiri, ini relatif mudah: kemungkinan besar selera tidak banyak berubah bahkan setelah 10 tahun, dan karena
nkecil, masalah kecil seperti memakai fungsiO(n^2)meski ada fungsiO(n)bisa diabaikanNamun jika perangkat lunak itu akan dipakai orang lain, persyaratannya berbeda, dan pada
Nyang cukup besar masalah muncul—misalnya fungsiO(n)menjadi bernilaiBaik dipakai untuk diri sendiri maupun untuk orang lain, masalah yang tak terduga bisa saja muncul
Misalnya, aplikasi crash saat memproses file lebih dari 1GB, tetapi selama ini tidak dipedulikan karena biasanya hanya memakai file di bawah 100KB; lalu saat hendak diperbaiki, ternyata separuhnya harus ditulis ulang
Di sinilah sanggahan terbesar terhadap gagasan bahwa perangkat lunak yang tidak berubah secara inheren lebih baik daripada perangkat lunak yang sering berubah
Perangkat lunak yang tidak berubah mungkin memang sempurna sejak awal, tetapi bisa juga ada kengerian yang bersembunyi di kedalaman, dan sulit membedakannya sebelumnya
Ini juga bukan berarti perangkat lunak yang cepat diperbarui secara inheren lebih baik daripada yang lambat diperbarui; selain kecepatan pembaruan, ada banyak faktor lain
Jika persyaratan berubah, tentu perangkat lunak juga harus berubah
Namun dalam 10 tahun, banyak hal bisa terjadi yang tidak terkait dengan perubahan persyaratan
Proyek open source bisa ditinggalkan atau berubah arah, perangkat lunak komersial bisa dihentikan, perusahaan bisa diakuisisi, aturan App Store atau Play Store bisa berubah, API bisa menghilang atau harganya berubah sehingga kelayakan ekonomi proyek runtuh
Toolchain, framework, bahasa pemrograman, paradigma, dan best practice juga berubah
Menurut saya intinya adalah mencegah perubahan eksternal yang tidak terkait dengan persyaratan memaksa kita untuk berubah
Itu prinsip yang baik, tetapi seperti biasa ada kompromi
Stabil dan menjadi usang itu berbeda, dan perbedaannya sering kali ditentukan oleh keamanan
Bagaimana jika memenuhi persyaratan baru yang penting sebenarnya mudah, tetapi kita harus menaikkan vendored library sebanyak 7 versi mayor, dan akibatnya muncul banyak kerusakan yang tidak terkait
Bagaimana jika orang-orang yang akrab dengan toolset yang seolah berhenti di waktu tertentu tidak lagi cukup jumlahnya dan tidak ada yang mau mempelajarinya
Memilih dependensi dengan hati-hati dan konservatif itu baik, tetapi menurut saya tidak mengikuti bahkan perubahan dependensi yang sudah dijaga sekecil itu adalah satu langkah terlalu jauh
Saya bersimpati dengan nuansa tulisan ini
Saya benar-benar tidak suka bahwa aplikasi mobile yang dibuat baru beberapa tahun lalu pun kini butuh puluhan jam hanya untuk dipatch dan mengirimkan pembaruan
Bagian akhir, ketika penulis menyebut static site generator miliknya sebagai perangkat lunak berdarah dingin dan mengatakan bahwa itu berjalan di Python 2, juga menarik
Python 2 sekarang makin sulit dipasang, dan pada akhirnya proyek itu juga akan menjadi proyek berdarah panas
Setiap kali meng-upgrade Xcode, saya harus memperbaiki hal-hal kecil agar proyek bisa dikompilasi bersih dan berjalan; ini benar-benar menyebalkan dan seharusnya sama sekali tidak bisa diterima
Belakangan ini pesan riwayat git semuanya variasi dari “perbaiki agar berjalan di Xcode terbaru”
Jika perubahan SDK atau OS tingkat bawah seperti ini diperlukan karena ancaman keamanan, saya masih bisa memahaminya sampai batas tertentu, tetapi hampir tidak pernah begitu
Sebagian besar hanyalah perubahan bodoh seperti mendeprekasi API, menambahkan peringatan default, atau sekarang harus memakai framework ini alih-alih framework itu
Platform dan framework harus berhenti sengaja menjadi target bergerak, apalagi jika kini sudah menjadi sistem operasi yang sangat stabil dan andal
Proyek berusia 10 tahun seharusnya bisa dikeluarkan dari freezer dan tetap dikompilasi bersih serta berjalan seperti 10 tahun lalu
Vendor sistem operasi ini adalah perusahaan bernilai triliunan, jadi saya tidak mau mendengar alasan bahwa kompatibilitas mundur membutuhkan banyak upaya engineering
Saya terus memelihara proyek sampingan pribadi
Dimulai 12–13 tahun lalu dengan PHP murni, lalu kemudian ditulis ulang dengan Laravel, dan sekitar 2017 ditulis ulang lagi dengan Symfony
Ada masa ketika saya hanya membuat 2–3 commit sangat kecil selama 6–18 bulan karena tidak punya energi akibat bekerja full-time sebagai freelancer, tetapi ketika ada waktu saya menambahkan fitur, melakukan upgrade, bereksperimen, dan belajar
Ini sangat berguna untuk belajar cara memelihara proyek dalam jangka panjang
Saya belajar hal-hal seperti memperbarui dependensi, menghapus yang tidak perlu, memeriksa pembaruan keamanan, mencari peluang penyederhanaan (dari Vagrant ke Docker, dari Vue + Axios + Webpack dan semacamnya ke Htmx), serta hal-hal yang sebaiknya dihindari
Secara pribadi, saya jadi menghindari dependensi yang baru saja dikembangkan, microservices, dan infrastruktur kompleks seperti Kubernetes
Belakangan ini saya membuat beberapa fitur dan menaikkannya ke PHP 8.2 dan Symfony 7, serta mengintegrasikan fitur berbasis ChatGPT, jadi rasanya kalau mau saya bisa beristirahat sekitar 1–3 tahun
Dalam 4–5 tahun terakhir, proyek ini menghasilkan pendapatan yang kira-kira setara dengan pendapatan satu tahun freelancer rata-rata, jadi ini juga bukan proyek sampingan anonim yang tertidur
Setelah tidak memakainya selama beberapa tahun lalu kembali, fungsi-fungsi manipulasi gambar yang mengerikan itu masih tetap ada persis seperti saat saya meninggalkannya 8 tahun lalu
Selain hal-hal yang disebutkan dalam tulisan, model ancaman yang secara inheren aman juga penting
Misalnya, seluruh situs web harus terus berhadapan dengan penyerang dan bot spam, sehingga secara inheren lebih dekat ke berdarah panas
Sebaliknya, halaman statis seperti TiddlyWiki bisa saja tidak diunggah ke web sama sekali, dan browser adalah platform yang luar biasa stabil, jadi itu jauh lebih baik
Perbedaan preferensi antara proyek berdarah dingin dan proyek berdarah panas tampaknya berkaitan dengan Buxton Index yang dibahas di https://www.cs.utexas.edu/users/EWD/transcriptions/EWD11xx/EWD1175.html
Toko kelontong kecil di lingkungan sekitar sekitar 0,5 tahun, seorang Kristen sejati tak terbatas, rata-rata politisi yang mengincar terpilih kembali sekitar 4 tahun, sebagian besar industri sedikit lebih panjang dari itu, dan para manajer yang harus menulis laporan triwulanan jauh lebih pendek, kira-kira begitu
Alasan Buxton Index penting adalah karena kerja sama erat antara pelaku yang memiliki Buxton Index yang sangat berbeda pasti gagal dan berujung pada kecaman moral
Pihak yang jangka waktunya pendek dituduh dangkal dan rabun jauh, sementara pihak yang jangka waktunya panjang dituduh lalai dalam tugas, menghindari tanggung jawab, atau menumpang gratis
Mereka juga akan saling menganggap bodoh
Kelebihan Buxton Index adalah karena ia berupa konsep angka yang sederhana, ia netral secara moral dan mengangkat perbedaan di atas perdebatan moral
Ini sangat penting terutama saat memikirkan kerja sama antara akademia dan industri
Nama ini benar-benar kurang bagus
Hewan berdarah dingin sangat bergantung pada lingkungan, sedangkan hewan berdarah panas mengurangi ketergantungan pada suhu eksternal melalui metabolisme
Bagaimanapun, istilah ini tidak perlu dibuat ambigu
Kalau cukup disebut “software yang tidak memiliki ketergantungan eksternal”, paragraf penjelasan yang panjang itu bisa dihilangkan
Saya juga tidak suka tulisan pengembangan software yang melompat ke kesimpulan dangkal dengan analogi yang tidak tepat dari alam, tetapi saya lebih tidak suka lagi tulisan yang melakukannya sambil sepenuhnya salah memahami fenomena alam yang dijadikan analogi itu sendiri
Beberapa spesies, termasuk kura-kura painted turtle, dapat bertahan hidup meski membeku bukan karena sifat berdarah dingin, melainkan berkat protein antibeku khusus
Kadal atau hewan berdarah dingin lain akan mengalami jaringan tubuhnya robek saat dicairkan
https://lobste.rs/s/hitos3/cold_blooded_software#c_mxjzwh