7 poin oleh GN⁺ 2025-05-10 | 3 komentar | Bagikan ke WhatsApp
  • Sistem manajemen dependensi Rust memang memudahkan pengembangan, tetapi jumlah dan kualitas dependensi menjadi kekhawatiran
  • Bahkan crate yang umum dipakai pun belum tentu selalu mutakhir, sehingga kadang lebih baik mengimplementasikannya sendiri
  • Setelah menambahkan crate populer seperti Axum dan Tokio, total jumlah baris kode termasuk dependensi mencapai 3,6 juta sehingga sulit ditangani
  • Kode yang benar-benar saya tulis hanya sekitar 1.000 baris, tetapi kode di sekitarnya praktis tidak mungkin saya telaah dan audit
  • Belum ada solusi yang jelas soal apakah pustaka standar Rust perlu diperluas dan bagaimana infrastruktur inti sebaiknya diimplementasikan; komunitas secara keseluruhan perlu memikirkan keseimbangan antara performa, keamanan, dan pemeliharaan bersama-sama

Gambaran umum masalah dependensi Rust

  • Rust adalah bahasa favorit saya, dan komunitas serta kemudahan penggunaan bahasanya sangat unggul
  • Produktivitas pengembangan tinggi, tetapi belakangan saya mulai khawatir dari sisi manajemen dependensi

Kelebihan crate Rust dan Cargo

  • Dengan Cargo, manajemen paket dan otomatisasi proses build bisa dilakukan sehingga produktivitas meningkat pesat
  • Perpindahan antar berbagai sistem operasi dan arsitektur menjadi mudah, dan kita tidak perlu terlalu memikirkan pengelolaan file manual atau konfigurasi alat build
  • Kita bisa langsung menulis kode tanpa perlu banyak memikirkan manajemen paket terpisah

Kekurangan pengelolaan crate Rust

  • Karena jadi lebih jarang memikirkan manajemen paket, kita bisa lengah terhadap stabilitas
  • Misalnya, saya memakai crate dotenv, lalu mengetahui lewat Security Advisory bahwa pemeliharaannya telah dihentikan
  • Sambil mempertimbangkan crate pengganti (dotenvy), pada akhirnya saya hanya mengimplementasikan sendiri bagian yang benar-benar dibutuhkan dalam sekitar 35 baris
  • Masalah paket yang tidak lagi dipelihara sering terjadi di banyak bahasa, jadi inti persoalannya adalah situasi ketika dependensi tidak bisa dihindari

Ledakan jumlah kode akibat dependensi

  • Saya menggunakan paket penting dan berkualitas tinggi dalam ekosistem Rust seperti Tokio dan Axum
  • Sebagai dependensi, saya menambahkan Axum, Reqwest, ripunzip, serde, serde_json, tokio, tower-http, tracing, dan tracing-subscriber
  • Tujuan utamanya hanya web server, ekstraksi file terkompresi, dan logging, jadi proyeknya sendiri sederhana
  • Saya memanfaatkan fitur Cargo vendor untuk mengunduh semua crate dependensi secara lokal
  • Setelah menganalisis jumlah baris kode dengan tokei, totalnya mencapai sekitar 3,6 juta baris termasuk dependensi (sekitar 11.136 baris jika crate yang di-vendor tidak dihitung)
  • Sebagai perbandingan, keseluruhan kernel Linux diketahui sekitar 27,8 juta baris, jadi proyek kecil saya setara sekitar sepertujuh jumlah itu
  • Kode yang benar-benar saya tulis sendiri hanya sekitar 1.000 baris
  • Mengawasi dan melakukan audit terhadap kode dependensi sebanyak itu pada praktiknya hampir mustahil

Mencari solusi

  • Untuk saat ini, belum ada solusi yang benar-benar jelas
  • Sebagian orang berpendapat pustaka standar perlu diperluas seperti Go, tetapi itu juga menimbulkan masalah baru seperti beban pemeliharaan
  • Rust mengejar performa tinggi, keamanan, dan modularitas, serta menargetkan persaingan di ranah embedded dan C++, jadi perluasan pustaka standarnya harus dipertimbangkan dengan hati-hati
  • Misalnya, runtime canggih seperti Tokio juga dikelola sangat aktif di Github dan Discord
  • Secara realistis, mengimplementasikan sendiri infrastruktur inti seperti runtime asinkron atau web server terlalu berat bagi pengembang individu
  • Bahkan layanan besar seperti Cloudflare juga menggunakan dependensi tokio dan crates.io apa adanya, dan tidak jelas seberapa sering mereka melakukan audit
  • Clickhouse juga menyinggung masalah ukuran biner dan jumlah crate
  • Dengan Cargo, sulit untuk mengidentifikasi secara tepat baris kode mana yang benar-benar masuk ke biner akhir, dan ada keterbatasan karena kode yang tidak diperlukan untuk platform tertentu pun ikut tercakup
  • Pada akhirnya, kenyataannya kita hanya bisa meminta jawaban dari komunitas secara keseluruhan

3 komentar

 
codemasterkimc 2025-05-11

Kalau dijalankan dengan Trivy, dibandingkan js NPM atau Java Maven, jumlah temuan high atau critical jauh lebih sedikit dan lebih aman. Jadi, tulisan ini sebenarnya ingin menyampaikan apa dengan membawa-bawa Rust?

 
GN⁺ 2025-05-10
Komentar Hacker News
  • Menurut saya, sistem yang memudahkan penambahan dependensi tanpa penalti ukuran atau biaya pada akhirnya akan berujung pada masalah dependensi. Jika melihat cara distribusi perangkat lunak selama 40 tahun terakhir, pada era 80-an pustaka dibeli dengan uang, lalu hanya bagian yang benar-benar dibutuhkan yang dipilih agar sesuai dengan lingkungan yang serba terbatas. Sekarang, pustaka ditumpuk di atas pustaka lain tanpa henti. Cukup tulis satu baris import foolib, dan tak ada yang peduli apa isi di dalamnya. Di setiap lapisan mungkin kita hanya butuh sekitar 5% fungsinya, tetapi makin dalam pohon dependensinya, makin banyak kode tak berguna yang ikut menumpuk. Akhirnya satu biner sederhana bisa jadi 500MiB, dan bahkan untuk memformat angka saja kita malah menarik sebuah dependensi. Go dan Rust mendorong semuanya dimasukkan ke satu berkas, jadi kalau hanya ingin memakai sebagian kecil saja situasinya jadi serba tanggung. Dalam jangka panjang, solusi sebenarnya tampaknya adalah pelacakan simbol/dependensi yang sangat rinci, sehingga setiap fungsi/tipe menyatakan dengan tepat elemen yang dibutuhkan, lalu hanya kode itu yang dipakai dan sisanya dibuang. Saya pribadi tidak terlalu suka ide ini, tetapi saya juga belum melihat cara lain untuk memperbaiki sistem saat ini yang menyeret seluruh alam semesta dari pohon dependensi
    • Mungkin karena masih mahasiswa jadi belum tahu, tetapi kompiler Rust sudah bisa mendeteksi kode, variabel, fungsi, dan sebagainya yang tidak dipakai. IDE juga bisa melakukannya di kebanyakan bahasa. Jadi bukankah cukup hapus bagian seperti itu saja? Kode yang tidak digunakan tidak akan dikompilasi
    • Saya sendiri pernah mencoba memangkas dependensi dengan feature flag saat mengerjakan pustaka Rust dengan pohon dependensi yang cukup berat (Xilem), dan hampir semuanya memang harus dipertahankan sesuai fitur yang dibutuhkan (vulkan, decoding PNG, unicode shaping, dan sebagainya). Dependensi yang benar-benar tidak perlu kebanyakan justru kecil-kecil, dan hanya serde_json yang bisa saya lepaskan dengan sedikit modifikasi. Dependensi yang lebih besar (winit/wgpu dan lain-lain) butuh perubahan arsitektur sehingga tidak mudah dilepas
    • Go dan C# (.NET) adalah contoh tandingan yang bagus. Keduanya punya manajemen paket dan ekosistem yang sama efektifnya dengan Rust atau JS (Node), tetapi relatif tidak mengalami dependency hell. Alasannya karena standard library mereka luar biasa bagus. Keluasan standard library seperti itu pada dasarnya hanya bisa didanai perusahaan besar seperti Google dan Microsoft
    • Kalau begitu, mengapa kompiler saat ini tidak menghapus kode yang tidak digunakan?
    • Dulu, tiap fungsi dibuatkan berkas .o tersendiri lalu dibundel ke dalam arsip .a, dan linker hanya mengambil fungsi yang memang diperlukan. Namespacing pun dilakukan dengan gaya seperti foolib_do_thing(). Sekarang polanya lebih mirip god object, di mana objek top-level memegang semua fungsi, jadi begitu foolib di-import, semuanya ikut tertarik. Dalam keadaan seperti itu, linker sulit menentukan fungsi mana yang benar-benar wajib. Sebaliknya, Go sangat bagus dalam menghapus dead code, jadi bagian yang tak dipakai akan dipotong dari hasil kompilasi
    • Kompiler dan linker modern sebenarnya sudah melakukan ekstraksi simbol dan penghapusan dead code, dan Rust juga mendukung ini lewat proyek seperti min-sized-rust
    • Dulu kami mengelola semua pustaka dengan memasukkannya langsung ke proyek lalu mengintegrasikannya sendiri ke berkas build. Memang merepotkan dan butuh usaha besar, tetapi membuat kita memahami dependensinya jauh lebih dalam dibanding hanya menambah satu baris ke berkas deps
    • Go sebenarnya tidak fanatik pada satu berkas saja; secara logis ia juga mendukung pemisahan ke banyak berkas dengan mudah. Itu salah satu hal yang sangat saya sukai
    • Dotnet sudah mewujudkan ide ini lewat Trimming dan Ahead Of Time Compilation. Bahasa lain bisa belajar dari Dotnet
    • Dari sudut pandang ukuran biner, masalah ini sebenarnya sudah selesai sepenuhnya dengan LTO (Link Time Optimization). Bagian yang tidak dipakai dibuang lewat optimisasi. Yang masih mahal hanyalah waktu build
    • Menurut saya, masalah utamanya bukan pustaka itu sendiri, melainkan kurangnya visibilitas setelah dependensi ditambahkan: kita tidak tahu apa yang dipakai di dalamnya dan seberapa besar porsinya. Yang dibutuhkan adalah lingkungan yang bisa memberi umpan balik dengan mudah soal performa tiap paket, rasio kode sisa saat build, dan semacamnya
    • Bahasa bernama Unison mengadopsi pendekatan yang sebagian mirip ide ini. Tiap fungsi didefinisikan menurut struktur AST, lalu dimuat dan digunakan ulang dari registry global berbasis hash
    • Dibanding pemeliharaan terpecah seperti isEven, isOdd, leftpad di npm yang terdiri dari banyak potongan pustaka kecil, pustaka umum yang besar dan dikelola tim federatif jauh lebih menjamin masa depan dan kesinambungan
    • Daripada mengejar simbol/dependensi yang ultra-rinci, ide lain adalah membuat modul yang sangat halus dan memanfaatkan sistem tree-shaking yang sudah ada
    • Cara Go mengelola dependensi di dunia nyata sebenarnya cukup dekat dengan gambaran ideal di tulisan asli. Modul adalah kumpulan paket, dan saat vendoring yang disertakan hanya paket dan simbol yang benar-benar dipakai (saya tidak yakin apakah betul sampai ke tingkat simbol)
    • Sistem modul JS memang mendukung manajemen simbol yang sangat rinci seperti itu serta tree shaking
    • Ide dependensi ultra-rinci yang awalnya diajukan sebenarnya sudah ditangani di Rust dengan section splitting seperti --gc-sections
    • Rust adalah bahasa yang sangat bagus untuk import yang rinci lewat pemisahan API menggunakan crate feature. Berbeda dengan Go
    • Tergantung arsitekturnya, misalnya thick client yang berpusat pada lokal, ukuran instalasi awal 800MB pun bukan masalah jika saat pemakaian nyata komunikasinya di jaringan sangat terbatas. Dependensi besar yang berulang demi kolaborasi di UI juga masih bisa diterima
    • Dependensi seperti inilah justru cara terbaik untuk melakukan reuse kode. Optimalkan hanya di bagian yang benar-benar perlu
    • Pada era 80-an, konsep komponen perangkat lunak yang bisa dipakai ulang sebenarnya sudah diwujudkan lewat bahasa seperti Objective-C. Salah satu keberhasilan besar Rust adalah membawa model komponen perangkat lunak semacam ini agar luas dipakai bahkan di bahasa pemrograman sistem
    • Dengan tree shaking, masalah ukuran dan penggelembungan kode bisa diatasi sampai tingkat tertentu (dan di server bahkan sering tidak dipedulikan). Masalah yang jauh lebih serius adalah risiko supply chain dependensi dan keamanan. Makin besar perusahaan, makin umum ada proses persetujuan untuk penggunaan open source. Menaikkan granularity saja tidak ada artinya secara keamanan jika 1000 fitur itu datang dari 1000 penulis NPM yang berbeda
    • Jika pada setiap lapisan abstraksi paket tingkat pemakaiannya hanya 50%, maka ukuran total tiap lapisan menjadi dua kali kebutuhan sebenarnya. Dalam 3 lapisan, 88% kodenya tidak berguna. Contohnya: kalkulator Windows 11 ikut membawa pustaka yang tidak perlu sampai alat pemulihan akun. Ini contoh ketika kemudahan menambah fitur berujung pada naiknya kompleksitas
    • Saya setuju bahwa akumulasi dependensi adalah masalah. Saat ini pertahanan terbaik adalah mengelola dependensi sistem dengan sangat ketat. Untuk satu fungsi 10 baris, saya kadang lebih memilih menyalin kodenya sendiri daripada menarik pustaka eksternal. Ekosistem pustaka yang benar-benar sehat itu pengecualian. Saya sering langsung menahan engineer junior agar tidak sembarang menambah dependensi
    • Sudah lama rasanya saya tidak melihat orang yang bicara setegas ini padahal bahkan tidak paham dasar-dasar Rust
    • Berkat penghapusan dead code, pada bahasa terkompilasi seperti Rust, pohon dependensi yang besar tidak otomatis menyebabkan biner membengkak
  • Masalah yang saya rasakan di ekosistem npm adalah banyak pengembang mengambil dependensi tanpa memikirkan desain. Misalnya pustaka glob seharusnya hanya fungsi globbing sederhana, tetapi penulisnya juga membundel alat command line sehingga dependensinya ikut menarik parser besar. Ini menyebabkan peringatan dependency out-of-date muncul terus-menerus. Selain itu, ruang lingkup tanggung jawab pustaka glob sendiri juga masih bisa diperdebatkan. Hanya melakukan pencocokan pola string sebenarnya desain yang lebih fleksibel, misalnya untuk testing atau abstraksi filesystem. Banyak pengguna memang ingin pustaka serba bisa yang "melakukan semuanya", tetapi makin begitu makin besar pula efek sampingnya. Saya rasa Rust pun tidak jauh berbeda
    • Selera desain memang penting, dan bahasa yang bagus tidak terlalu mendukung atau menghalangi preferensi pengembang seperti ini. Rust, Zig, C, dan sebagainya adalah contoh. Secara statistik masalahnya lebih jarang muncul. Ketika "kerumunan" pengembang berkumpul, muncullah model "bazaar" di mana siapa pun bebas menumpuk crate. Pada akhirnya saya berharap Rust juga punya standard library resmi yang lebih lengkap, misalnya stdlib::data_structures::automata::weighted_finite_state_transducer, dengan namespace yang rapi dan pendekatan "batteries included". Karena bahasanya sendiri sudah menanamkan versioning dan kompatibilitas mundur, saya optimistis masih bisa berkembang ke arah sana
    • Fungsi glob POSIX memang benar-benar menelusuri filesystem. Untuk pencocokan string ada fnmatch. Idealnya fnmatch dipisah jadi modul tersendiri lalu menjadi dependensi dari glob. Kalau mencoba mengimplementasikan glob langsung, ternyata cukup sulit karena ada kebutuhan kompleks seperti struktur direktori dan brace expansion, jadi memang perlu kombinasi fungsi yang dirancang dengan baik
    • Di Rust, borrow checker selama ini berfungsi seperti semacam tameng terhadap pengembang yang insting desainnya lemah. Pengaruh itu akan bertahan sampai kapan masih belum jelas
    • Salah satu keunggulan besar Rust adalah para pengembangnya rata-rata cukup kompeten, dan kualitas crate-nya juga cenderung tinggi
    • Bun juga sudah menyertakan fitur glob
  • Tidak perlu mengkhususkan pada Rust; masalah dependensi dan serangan supply chain itu sudah nyata di mana-mana. Kalau mendesain bahasa baru, kita perlu capability system bawaan agar seluruh pohon pustaka bisa diisolasi dengan aman. Misalnya saat merancang pustaka pemuat gambar, ia tidak menerima file langsung melainkan hanya stream, atau secara eksplisit diberi batasan "tidak punya izin membuka file", sehingga penggunaan fungsi berbahaya bisa diblokir pada waktu kompilasi. Di ekosistem yang sudah ada ini memang tidak mudah, tetapi jika dilakukan dengan benar, permukaan serangan bisa diperkecil semaksimal mungkin. Budaya meminimalkan dependensi pun sulit menjadi solusi mendasar, dan bahasa seperti Go juga tidak kebal dari serangan supply chain
    • Budaya Sans-IO, yaitu desain yang membuat dependensi tidak melakukan IO secara langsung, perlu disebarkan lebih aktif. Saat pustaka baru diumumkan, perlu ada budaya untuk menegur jika ia mengimplementasikan IO sendiri. Tentu peninjauan publik saja tidak akan cukup, tetapi akan bagus jika prinsip Sans-IO makin meluas
    • Sebagai contoh ada bahasa tujuan khusus bernama WUFFS. Ia bahkan tidak bisa mencetak Hello world dan tidak punya tipe string. Sebagai gantinya, ia dikhususkan untuk parsing format berkas yang tidak tepercaya. Kita butuh lebih banyak bahasa tujuan khusus seperti ini. Cepat, aman, dan karena minim risiko banyak pemeriksaan yang tidak perlu bisa dihilangkan
    • Java dan .NET Framework sebenarnya sudah punya fitur partial trust/capabilities beberapa dekade lalu, tetapi tidak banyak dipakai dan akhirnya ditinggalkan
    • Di Rust ada sedikit kecenderungan serupa. Dengan #![deny(unsafe_code)], penggunaan kode unsafe bisa diblokir sebagai error kompilasi dan fakta itu bisa diinformasikan ke pengguna. Namun ini bukan pemeriksaan paksa total, karena unsafe tetap bisa dipakai jika secara khusus diizinkan. Bisa dibayangkan capability system yang seperti feature flag, yang mengendalikan kemampuan standard library secara transitif
    • Saya sendiri ingin membuat ide seperti ini, dan berharap suatu hari bisa terwujud. Di Rust, pelacakan capability sebagian bisa dilakukan lewat linter. Masalah unsoundness di kompiler tetap perlu dibereskan
    • Sulit memperkenalkan penegakan statis yang sempurna ke bahasa atau ekosistem yang sudah ada, tetapi validasi saat runtime saja pun sudah memberi sebagian besar manfaat. Jika kode pustaka dikompilasi dari source, kita bisa membungkus setiap system call dengan pemeriksaan izin. Jika melanggar, buat panic, lalu siapkan dan distribusikan capability profile untuk tiap pustaka. Hal serupa pada dasarnya sudah terbukti di TypeScript
    • Haskell sebagian mewujudkan pendekatan ini lewat IO monad. Fungsi yang tidak boleh melakukan IO dibatasi lewat type signature
    • Menurut saya, untuk sistem seperti ini kita mungkin perlu mengubah total cara berkomunikasi dengan OS. Bahkan tindakan membaca stream pun pada kenyataannya bisa menggunakan system call pembacaan file
    • Ada proyek bernama Capslock yang di Go bekerja cukup dekat dengan pendekatan ini
    • Jika sejak program entry kita membatasi pustaka agar tidak bisa mengimpor API sistem, capability dapat diteruskan hanya lewat dependency injection. Secara desain ini mungkin dilakukan bahkan di bahasa yang ada sekarang, tetapi dalam praktik masalah besarnya adalah kompatibilitas dengan pustaka lama akan rusak
    • Saya penasaran apakah pernah ada sesuatu yang mirip ide ini yang sudah diimplementasikan. Di bahasa saat ini tampaknya memang sangat sulit diterapkan
    • Satu bahasa saja tidak cukup; yang dibutuhkan adalah ekosistem multibahasa
    • Di ekosistem TypeScript, misalnya, bila lingkungan tidak memiliki kelas untuk operasi file, kompilasi akan gagal sehingga pembatasan itu berlaku secara alami
  • Ini masalah umum dalam pengembangan perangkat lunak modern. Ambang masuk rendah, dan pemanfaatan kode yang ada makin luas. Dependensi pada akhirnya tetaplah kode yang tidak bisa sepenuhnya dipercaya. Jika tidak ada solusi teknis, maka harus selalu ada orang yang meninjau kode, merawatnya, serta menjaga sistem kepercayaan sosial dan hukum. Kalau semuanya ditarik masuk ke Rust stdlib, tim inti harus ikut bertanggung jawab atas seluruh kode itu, sehingga beban pengelolaannya besar
    • Tingkat keparahan yang tampak memang berbeda menurut bahasa. Bahasa dengan standard library kuat lebih diuntungkan karena banyak hal bisa dilakukan dengan minim dependensi eksternal. Bahasa seperti JS/Node yang fitur bawaannya sedikit menjadikan dependensi eksternal sebagai hal default. "Ringan" tidak selalu berarti baik
    • Saya rasa Rust perlu lebih banyak integrasi ke standard library. Go punya standard library yang hebat, sementara di Rust bahkan hal-hal dasar seperti web, tls, x509, base64, dan sebagainya masih menyakitkan karena harus memilih dan mengelola pustaka sendiri
    • Gilad Bracha pernah mengusulkan pendekatan menarik untuk sandboxing pustaka pihak ketiga: hilangkan import, lalu jadikan semuanya dependency injection. Jika subsistem IO tidak disuntikkan, kode pihak ketiga tidak akan pernah bisa mengaksesnya. Jika hanya ingin memberi kemampuan baca, maka cukup bungkus dan suntikkan kemampuan baca saja. Namun di wilayah pemrograman sistem ada keterbatasannya, misalnya karena unsafe code
    • Ada juga usulan untuk menjalankan semua pustaka dalam lingkungan terisolasi seperti QubesOS: kode kita sendiri di dom0, tiap pustaka di template VM terpisah, dan komunikasi memakai network namespace. Untuk industri sensitif, ini cukup praktis
    • Menurut pengamatan saya, bukan berarti kita sekarang melakukan hal yang lebih rumit; kita hanya melakukan hal yang sama dengan cara yang lebih rumit. Tujuannya sendiri tidak menjadi lebih sulit
    • Sebenarnya situasi tiap bahasa berbeda. Di C/C++, menambah dependensi itu sulit, dan kalau ingin mendukung lintas platform jauh lebih merepotkan lagi, jadi masalah serupa tidak terlalu muncul
    • Kompleksitas itu sendiri adalah penggelembungan kode yang tidak perlu. Hampir semua proyek dipenuhi kompleksitas yang tidak perlu dan overengineering. Itulah masalah industri ini
  • blessed.rs merekomendasikan daftar pustaka berguna yang sulit dimasukkan ke standard library. Saya suka sistem ini karena membuat sebagian besar paket tetap dibatasi untuk tujuan tertentu dan lebih mudah dikelola
    • cargo-vet juga layak direkomendasikan. Ia bisa melacak dan mendefinisikan paket yang dipercaya, misalnya dari paket yang wajib diaudit pakar sebelum diimpor sampai kebijakan semi-YOLO seperti "paket yang dikelola maintainer tokio anggap saja tepercaya". Pendekatannya lebih formal daripada blessed.rs, dan bagus sebagai sarana berbagi daftar kuasi-standar resmi di dalam tim
    • Andai ada sistem seperti ini juga di Python, pasti bagus sekali
    • Setelah saya lihat, ini benar-benar proyek rekomendasi yang bagus
  • Setelah insiden leftpad, citra package manager masih menyisakan kesan negatif. Hal seperti tokio pada dasarnya sudah setara fitur tingkat bahasa, jadi kalau OP menganggap seluruh Go atau bahkan V8 di Node juga harus diaudit langsung, itu tidak realistis
    • Faktanya, tokio juga memang terus diaudit oleh seseorang. Memang bukan banyak orang, tetapi tetap ada yang melakukannya
    • Fenomena cargo yang memasukkan dua versi sekaligus saat dua dependensi memakai versi berbeda adalah dukungan yang cukup unik dari cargo
  • Feature flag pada paket cargo benar-benar salah satu hal terbaik. Saya sering mengirim PR untuk menyembunyikan dependensi yang tidak perlu di balik flag ini. Dengan cargo tree, pohon dependensi juga sangat mudah dilihat. Tampilan jumlah baris kode yang benar-benar masuk ke biner sebenarnya kurang bermakna, karena kalau fungsi di-inline, sebagian besar akhirnya menyatu ke main
    • Sayang sekali npm tidak punya feature flag. Saya penasaran apakah ada package manager lain yang sudah mendukungnya. Saya ingin mengisolasi kode dependensi framework tertentu di pustaka internal agar bisa dikembangkan lebih fleksibel
  • Saya juga merasakan hal yang sama. Menambah dependensi dengan Cargo terlalu mudah, jadi walaupun saya sendiri berhati-hati, beberapa penambahan kecil saja bisa menarik puluhan dependensi transitif. Tetapi mengatakan "ya sudah jangan dipakai" juga tidak realistis. Di C++ fenomena seperti ini lebih jarang. Di Rust, pemecahan menjadi paket-paket kecil begitu umum sampai rasanya seperti mengambil kode acak dari internet. Saya suka Rust-nya, tetapi tidak suka strukturnya yang seperti ini
    • Dalam tulisan yang ditautkan di subreddit Rust, dijelaskan bahwa alasan dependensi C++ tampak kurang terlihat adalah karena kebanyakan disediakan sebagai dynamic library. Bahkan ketergantungan pada kemampuan manajemen stabilitas/keamanan dari package manager OS itu sendiri juga bisa dianggap kelebihan. Akan bagus jika Rust setidaknya punya konsep perluasan standard library
    • Menurut saya dependensi C++ jauh lebih rumit dan sistem build-nya kacau, jadi dependensi ala Rust yang kurang stabil justru masih lebih baik. Dependensi transitif C++ yang sebenarnya malah lebih tidak terlihat karena datang dalam bentuk yang sudah precompiled
    • Di Rust, pemecahan menjadi paket-paket kecil bukan semata-mata "filosofi", melainkan karena kecepatan build. Saat proyek membesar, orang akhirnya membelah proyek menjadi crate-crate. Itu bukan demi abstraksi, tetapi restrukturisasi yang nyaris dipaksakan oleh performa build
    • Kita tidak harus langsung menyetujui logika "kalau begitu jangan dipakai saja". Ini masih perlu dipikirkan lebih dalam
    • C++ dan CMake begitu sulit sampai dalam praktiknya banyak perangkat lunak justru jadi tidak digunakan
  • Saya biasanya memakai pustaka open source untuk fungsi inti, lalu untuk fitur kecil saya meniru contoh dari open source dan menempelkan kodenya langsung ke basis kode sendiri. Kode memang jadi agak membesar tanpa perlu, tetapi beban review kode eksternal dan paparan supply chain bisa berkurang. Pustaka besar tetap jadi masalah, tentu saja, tetapi tidak mungkin menulis semuanya sendiri. Ini bukan masalah Rust saja, melainkan masalah umum
  • Dulu, untuk sistem penting di bahasa lain, saya pernah menetapkan kebijakan meminimalkan modul/paket, lalu semua paket yang dipakai dipindahkan ke repositori internal perusahaan agar bisa diaudit per branch dan per pembaruan. Untuk area seperti frontend, pengelolaan seketat itu secara realistis tidak mungkin. Belakangan, alat dan model AI open source yang heboh itu juga menimbulkan kekhawatiran serupa soal manajemen dependensi. Bahkan saat mengerjakan proyek pribadi dengan Rust, ledakan dependensi pustaka UI/async adalah hal yang paling membuat saya tidak nyaman. Begitu salah satunya rentan, semuanya bisa ditembus; ini cuma soal waktu
    • Cara yang realistis adalah menghubungkan sistem CI/CD hanya ke repositori internal resmi. Pengembang boleh memasang apa saja secara lokal, tetapi commit yang tidak sah akan diblokir oleh server build
    • Ada RFC yang mencoba menyelesaikan risiko keamanan ini, tetapi mungkin karena alasan budaya, tidak ada perubahan drastis
    • Salah satu hal keren dari Rust adalah async pun bisa diimplementasikan sendiri dengan cara yang kita inginkan. Tidak harus terikat pada implementasi tertentu
 
iolothebard 2025-05-11

Ini bukan masalah yang hanya dimiliki Rust.
Semua bahasa yang punya pengelola paket dengan repositori paket publik dan mendukung dependensi transitif memiliki keunggulan sekaligus potensi masalah yang sama.
Pada akhirnya, orang yang memakainya harus menggunakannya dengan benar…
Meski sudah ada insiden leftpad di Node&npm, tidak ada yang berubah.