3 poin oleh GN⁺ 2024-07-05 | 1 komentar | Bagikan ke WhatsApp
  • Di Firezone, Rust digunakan untuk membangun akses jarak jauh yang aman dan dapat diskalakan di ponsel Android, komputer macOS, atau server Linux
  • Menggunakan library koneksi bernama connlib untuk mengelola koneksi jaringan dan tunnel WireGuard
  • Setelah melalui banyak iterasi, mereka sampai pada desain sans-IO yang memberikan pengujian yang cepat dan menyeluruh, kustomisasi mendalam, serta keandalan tinggi

connlib ditulis dalam Rust dan mengikuti desain sans-IO

  • Cocok untuk membangun layanan jaringan berkat kecepatan dan keamanan memori Rust
  • Menggunakan runtime tokio, WebSocket tungstenite, implementasi WireGuard boringtun, enkripsi trafik API rustls, dan lainnya
  • Desain sans-IO mengimplementasikan protokol sebagai state machine murni alih-alih mengirim dan menerima byte melalui socket di banyak tempat

Model asinkron Rust dan perdebatan "function coloring"

  • Fungsi asinkron hanya dapat dipanggil dari fungsi asinkron lain
  • Jika sebuah fungsi berada jauh di dalam rantai fungsi asinkron, maka semua fungsi yang memanggilnya juga harus menjadi fungsi asinkron
  • Hal ini bisa menjadi masalah bagi orang yang ingin menulis kode yang tidak peduli apakah dependensinya asinkron atau tidak

Pengenalan sans-IO

  • Ide inti sans-IO mirip dengan prinsip inversi dependensi di dunia OOP
  • Kebijakan (apa yang harus dilakukan) tidak boleh bergantung pada detail implementasi (bagaimana melakukannya)
  • Alih-alih mengirim data menggunakan struct Transmit, ia akan memancarkan Transmit

Menerapkan inversi dependensi

  • Alih-alih mengirim data menggunakan struct Transmit, ia akan memancarkan Transmit
  • Event loop mengimplementasikan efek samping dan benar-benar memanggil UdpSocket::send

State machine

  • Diagram state machine untuk permintaan binding STUN memiliki dua state: Sent dan Received
  • State machine diimplementasikan dengan mendefinisikan struct StunBinding dan fungsi-fungsi terkait

Event loop

  • Event loop menggerakkan state machine dan memproses data menggunakan poll_transmit dan handle_input

Abstraksi waktu

  • Menangani kebutuhan berbasis waktu menggunakan API poll_timeout dan handle_timeout

Premis sans-IO

  • Desain sans-IO menyerahkan keputusan tentang apakah dependensi bersifat asinkron kepada aplikasi
  • Desain sans-IO mudah dikomposisikan, menyediakan API yang fleksibel, mudah diuji, dan sangat cocok dengan kemampuan Rust

Komposisi yang mudah

  • API StunBinding dapat diterapkan pada sebagian besar protokol jaringan
  • Library snownet milik Firezone menggabungkan ICE dan WireGuard untuk menyediakan tunnel IP "ajaib" yang bekerja terlepas dari konfigurasi jaringan

API yang fleksibel

  • Menulis event loop sendiri memungkinkan penyetelan kode dan mempermudah pemeliharaan

Pengujian cepat

  • Kode sans-IO tidak memiliki efek samping sehingga sangat mudah diuji
  • Di Firezone, mereka mengimplementasikan state machine referensi dan menjalankan pengujian yang membandingkannya dengan state aktual connlib

Edge case dan kegagalan IO

  • Desain sans-IO memisahkan implementasi protokol dari efek samping IO nyata sehingga edge case dan penanganan kesalahan menjadi lebih mudah

Rust + sans-IO: pasangan serasi?

  • Rust memodelkan kepemilikan dan mutabilitas secara eksplisit sehingga sangat cocok dengan desain sans-IO
  • Desain sans-IO dengan leluasa menggunakan &mut untuk mengekspresikan perubahan state, dan tidak seperti Rust async, hanya menggunakan API sinkron

Kekurangan

  • Menulis event loop sendiri dapat menimbulkan bug yang sulit dideteksi
  • Workflow sekuensial bisa membutuhkan lebih banyak kode
  • Di komunitas Rust, desain sans-IO masih belum digunakan secara luas

Penutup

  • Kode sans-IO awalnya terasa asing, tetapi menjadi sangat menyenangkan setelah terbiasa
  • Rust menyediakan alat yang luar biasa untuk memodelkan state machine
  • Desain sans-IO terasa seperti cara yang tepat untuk menulis kode jaringan karena memaksa penanganan kesalahan menjadi bagian dari pemrosesan input

Pendapat GN⁺

  • Desain sans-IO sangat cocok dengan model kepemilikan Rust sehingga sangat sesuai untuk implementasi protokol jaringan
  • Menulis event loop sendiri meningkatkan fleksibilitas kode dan mempermudah pemeliharaan
  • Kemudahan pengujian sangat membantu dalam menulis kode yang andal
  • Namun, karena belum banyak digunakan di komunitas Rust, library terkait mungkin masih kurang
  • Saat mengadopsi teknologi baru, kurva pembelajaran dan dukungan komunitas perlu dipertimbangkan

1 komentar

 
GN⁺ 2024-07-05
Opini Hacker News
  • Sebelum sintaks async/await diperkenalkan di Rust, mesin status diimplementasikan secara manual

    • Berkat sintaks async/await Rust, produktivitas meningkat secara signifikan
    • Async di Rust diubah menjadi mesin status otomatis dan menyimpan nilai pada titik I/O
  • Saat menulis library VT100, penulis menyadari adanya masalah pada pola enkapsulasi Rust

    • Terlalu terobsesi dengan enkapsulasi justru menimbulkan masalah
    • Mengingatkan kembali bahwa komputer adalah mesin yang melakukan input, transformasi data, dan output
  • Dibandingkan dengan desain yang mengirim data menggunakan channel

    • Kode menjadi lebih kompleks
    • Tipe pesan harus diimplementasikan secara manual
    • Pengirim harus disediakan secara eksplisit
    • Jika transmisi jaringan gagal, hasil tidak akan diperoleh
    • Namun, ada juga sisi yang praktis
  • Di ekosistem Haskell ada gagasan untuk memisahkan logika dan eksekusi

    • Tidak disebutkan bagaimana pemanggilan tokio::select! dienkapsulasi
    • Ada ketertarikan pada implementasi fungsi yang dienkapsulasi dengan gaya sans-IO
  • Fungsi async Rust dikompilasi menjadi mesin status

    • Penasaran apakah pernah ada upaya menggabungkan sans-io dan async
    • Masalah utamanya adalah kegunaan dan penanganan Pin
  • Dengan mengekspos status, fungsi async bisa menjadi 'murni'

    • Pernah mencoba melakukan binding OpenSSL ke async Rust
  • Firezone adalah alat yang luar biasa

    • Menemukan pola yang mirip dengan Rust-libp2p
  • Akan bagus jika compiler bisa secara otomatis mengubah kode async menjadi sans io

    • Konversi manual rentan menimbulkan kesalahan
  • Setelah membaca artikel dan komentarnya, rasanya seperti menemukan kembali gaya arsitektur hexagonal atau ports/adapters

  • Penasaran apakah lalu lintas nyata melewati gateway, atau hanya digunakan untuk penyiapan koneksi