2 poin oleh GN⁺ 2023-11-11 | 1 komentar | Bagikan ke WhatsApp
  • Setelah seorang developer backend Ruby bergabung dengan perusahaan yang menggunakan Elixir sebagai bahasa utama, ia bisa beradaptasi relatif cepat meski belum berpengalaman dengan Elixir/Erlang, berkat sintaks yang dipengaruhi Ruby
  • Elixir menawarkan kesenangan sintaksis dan ramah DSL seperti Ruby, tetapi dengan model fungsional immutable tanpa class, instance, dan inheritance, sehingga mengurangi beban manajemen state
  • Jika DSL Ruby bergantung pada pendefinisian object dan method secara dinamis saat runtime, DSL Elixir menghasilkan kode runtime melalui macro compile-time, sehingga error muncul lebih awal
  • Sintaks pipeline, ekspresi with, dan tuple Result berbentuk {:ok, result} berguna untuk memisahkan alur normal dari penanganan error yang dapat dipulihkan
  • Dibandingkan pendekatan Ruby yang bergantung pada exception, nil/false, dan status error internal object, pengembalian ok/error yang eksplisit di Elixir terasa lebih memuaskan, dan setelah 3 bulan penggunaan pengalaman menulisnya tetap menyenangkan

Cara developer berpengalaman Ruby beradaptasi dengan Elixir

  • Tempat kerja baru menggunakan Elixir sebagai bahasa utama backend, dan sebelum mulai ia belum pernah menulis kode Elixir maupun Erlang
  • Erlang tidak terasa asing karena pernah sedikit menggunakan Prolog, dan Elixir bisa dipelajari cepat berkat sintaks yang sangat dipengaruhi Ruby
  • Ia belum ahli dalam best practice, arsitektur, maupun konsep Erlang level lebih rendah, tetapi hal-hal ini tidak menghalangi masuk ke Elixir
  • Elixir dipandang sebagai bahasa yang mempertahankan kesenangan pemrograman dari Ruby sekaligus mengurangi jebakan terkait state yang umum di bahasa OOP
    • Tidak ada class, instance, maupun inheritance
    • Berbasis immutability dan gaya fungsional
    • Tidak terikat pada sistem tipe statis
  • Kode dengan mutable state jauh lebih sulit dipelihara, dan tidak selalu jelas apakah state itu lokal ke fungsi, milik instance, atau milik class
  • Di Ruby, semuanya adalah object sehingga setiap object bisa memiliki state, dan dalam proses membuat DSL yang intuitif, state di level fungsi, instance, dan class mudah bercampur
  • Eigenclass di Ruby adalah konsep seperti class dari sebuah class, dan satu instance dapat memodifikasi eigenclass sehingga turut memengaruhi state instance lain

Perbedaan DSL dan macro compile-time

  • Elixir juga mendukung DSL seperti Ruby dan sintaksnya terasa familier, tetapi perbedaan utamanya ada pada kapan DSL dibuat
    • DSL Elixir adalah macro compile-time dan menghasilkan kode runtime
    • DSL Ruby bergantung pada cara memodifikasi runtime untuk mendefinisikan object dan method secara dinamis
  • Jika macro Elixir digunakan secara keliru, error terjadi di library, dan jika kode macro yang dihasilkan salah, compiler error akan muncul
    • Karena error seperti ini terlihat saat compile-time, pengujian bisa lebih berfokus pada logika aplikasi yang sebenarnya

Alur yang dibentuk oleh pipeline dan with

  • Operator pipeline Elixir |> berguna, tetapi operator threading Clojure juga punya keunggulan
    • -> di Clojure memasukkan hasil ekspresi sebelumnya sebagai argumen pertama fungsi berikutnya, seperti |> di Elixir
    • ->> di Clojure memasukkan hasil sebelumnya sebagai argumen terakhir fungsi berikutnya
    • Perbedaan ini tampak kecil, tetapi berguna saat menulis kode interoperabilitas tanpa memakai fungsi anonim
  • Ekspresi with di Elixir mengingatkan pada let di Haskell/Lisp dan bekerja seolah memiliki otherwise bawaan
    • Fungsi yang kompleks bisa dibagi menjadi jalur normal di bagian atas dan penanganan error di bagian bawah
    • Jika tidak bisa melakukan pattern matching pada {:ok, result}, hal itu dapat diperlakukan sebagai error yang dapat dipulihkan, sehingga cocok dengan tuple Result

Keunggulan pengembalian error yang eksplisit

  • Di Ruby, exception sering digunakan untuk alur kontrol, dan alih-alih tipe error eksplisit, kode sering bergantung pada hasil sukses, nil, false, atau status error internal object
    • Misalnya, model.update(params) mengembalikan false saat gagal dan menyimpan alasan kegagalan di model.errors
    • Ini kembali mengarah pada masalah mutable state
  • Cara yang menjadikan ok/error atau left/right sebagai nilai return secara eksplisit, seperti monad Result / Either, terasa lebih memuaskan daripada alur exception ala Ruby
  • Setelah menggunakan Elixir selama 3 bulan, Elixir tetap terasa sebagai bahasa yang meneruskan sensasi Ruby bahwa “pemrograman itu menyenangkan”

1 komentar

 
GN⁺ 2023-11-11
Pendapat Hacker News
  • Dalam beberapa minggu terakhir, hampir setiap hari saya menonton video YouTube tentang Elixir
    Sepertinya belum lama ini ada konferensi Elixir, dan setelah menonton beberapa video, YouTube terus merekomendasikan konten Elixir
    Saya suka ide-ide Erlang, tetapi dulu saat menangani hal seperti server chat ejabberd, rasanya terlalu unik
    Setiap kali menonton video Joe Armstrong, saya berpikir bahwa ia adalah genius yang kurang diapresiasi, dan proses yang terisolasi serta pengiriman pesan, yaitu model aktor, terlihat sebagai kandidat yang bagus untuk masa depan pemrograman terdistribusi
    Di video bahasa baru Misty dari Crockford https://www.youtube.com/watch?v=R2idkNdKqpQ juga menarik bahwa pertanyaannya mengarah ke Elixir/Erlang
    Namun, melihat “keajaiban” LiveView dan LiveBook, saya belum 100% yakin. Hal yang terlihat terlalu bagus biasanya punya jebakan, dan istilah asing seperti GenServer serta pengetahuan khusus platform terasa seperti masuk ke portal satu arah, jadi saya tidak tahu apakah pengetahuan itu bisa dipindahkan ke tempat lain
    Di saat Go juga punya cerita konkurensi yang cukup bagus, bahasa dan platform dengan komunitas kecil punya risiko besar dalam hal perekrutan, library, dan materi. Meski begitu, pencapaian komunitas Elixir benar-benar mengesankan, dan saya juga menantikan bagaimana implementasi sistem tipenya nanti

    • Untuk bagian konkurensi, sepertinya kekhawatirannya agak berlebihan. Cukup lihat apa itu proses dan bagaimana send bekerja
      GenServer adalah generalisasi alami dari pola yang akan sangat sering Anda tulis sendiri, dan pengetahuan tentang aktor juga bisa dibawa ke tempat lain
      Di Go juga ada library yang mengimplementasikan abstraksi aktor, dan kotak surat proses bisa dianggap sebagai antrean pesan seperti channel di Go. Perbedaannya ada pada bagaimana interpreter dan penyerahan jatah prosesor bekerja
      Sebaliknya, LiveView memang terlihat seperti sihir. Pada kenyataannya banyak komponen bergerak yang saling terkait, dan karena ini adalah hasil kerja yang dibangun oleh berbagai komunitas selama 10 tahun terakhir, meski abstraksinya banyak, idenya sendiri sudah matang
      Hal seperti Riak melampaui zamannya, dan hampir sudah memiliki gagasan bahwa Anda bisa membangun sistem terdistribusi yang kokoh seperti membuat GenServer
    • Ada kebutuhan nyata untuk mendorong Elixir keluar dari komunitas awalnya, dan saya merasa sekarang itu sudah mulai terjadi sampai tingkat tertentu
      Baik Chris maupun José banyak bergerak untuk meningkatkan eksposur di luar lingkaran awal Elixir, dan orang-orang di komunitas juga melakukan hal yang sama pada level masing-masing
      Perekrutan tidak serumit yang dibayangkan. Ada cukup banyak orang yang ingin bekerja dengan bahasa ini, dan developer yang bagus bisa mengejar ketertinggalan cukup cepat
      Meski begitu, sisi sebagai bahasa niche tetap harus dijinakkan. Itu adalah risiko bagi bahasanya sendiri, tetapi dalam jangka pendek juga bisa menjadi imbalan karena mahir dalam teknologi niche
    • Saya justru merasa sebaliknya. Setelah dipelajari, Elixir menjadi kurang terasa seperti sihir
      Sebagian besar hal bisa dilihat, dipahami, dan kodenya bisa dibaca. JavaScript sering kali tidak demikian
      Memang benar perekrutan dan mencari tutorial itu sulit. Misalnya, menemukan orang yang sudah pernah melakukan hal yang ingin saya lakukan dengan Elixir jauh lebih sulit dibandingkan JavaScript
      Library bukan masalah besar, jumlahnya cukup banyak. Saat berurusan dengan API, kadang ada library klien untuk JavaScript atau Python tetapi tidak ada untuk Elixir, namun biasanya memakai API hanya dengan HTTP client tidak terlalu sulit
    • Saya pernah dari Ruby ke Elixir, lalu kembali ke Node.js
      Sekarang saya memakai Node.js bukan karena ingin, tetapi karena harus. Setelah mencobanya, saya berpikir tidak akan pernah memulai proyek baru dengan Node.js
      Kontrol konkurensi, skalabilitas, serta alat reliabilitas dan observabilitas Node.js tertinggal jauh dibandingkan ekosistem BEAM
      Menurut saya, ketika orang merasa Elixir terlalu bagus sampai sulit dipercaya, itu kadang karena mereka sudah terlalu terbiasa dengan platform yang tidak dirancang untuk resiliensi
    • Saya tidak begitu paham apa yang dimaksud dengan keajaiban LiveView dan LiveBook
      Untuk LiveBook, selain detail persis perhitungan diff atau kompresi data, cukup mudah memiliki model mental yang benar. Kalau mendesak, dengan melihat pesan WebSocket pun Anda bisa cukup memahami apa yang terjadi
      LiveView ternyata sangat intuitif
  • Daya tarik besar Elixir/Erlang adalah dalam konteks web server, menjalankan pekerjaan latar belakang benar-benar mudah, dan tidak perlu khawatir I/O yang blocking menghentikan seluruh server
    Di pekerjaan sebelumnya, saya harus melakukan banyak request HTTP di dalam handler webhook, dan jika terjadi cukup banyak secara bersamaan, semua proses sistem operasi menjadi sibuk sehingga seluruh situs sering mati
    Saat itu saya benar-benar berpikir, seandainya memakai Elixir, saya bisa tinggal menjalankan satu Task lalu lanjut

    • Baru-baru ini kami beralih dari Rust ke Elixir untuk layanan baru, dan hal ini menjadi salah satu alasan yang cukup besar
      Gagasan berbagi objek di antara proses asinkron Tokio terasa sulit dibandingkan fitur kelas satu di Elixir. Bukan berarti mustahil atau secara inheren sulit, tetapi tampaknya lebih sulit untuk dibuat dengan benar
    • Saya tidak terlalu menginginkan pekerjaan latar belakang menjadi mudah dengan cara seperti itu
      Saya ingin menaruh pekerjaan latar belakang di atas kapasitas komputasi yang berbeda dari request HTTP. Karena pola penggunaan sumber dayanya berbeda, dan saya ingin menaruh state atau antrean di depan agar retry, penanganan error, dan backpressure menjadi jelas
      Tentu akan bagus jika kompleksitas seperti ini tidak ada dan framework yang sama menangani semuanya, tetapi saya rasa bahasa pemrograman atau runtime saja sulit mencapai sejauh itu. Monitoring dan prosedur operasional juga harus menjadi bagian dari solusinya
  • Presentasi Sasa Juric, The Soul of Erlang and Elixir, menunjukkan dengan baik betapa kuatnya bahasa ini
    https://www.youtube.com/watch?v=JvBT4XBdoUE&t=4

    • Karena penasaran dengan Elixir, saya menonton presentasi ini awal minggu ini
      Sangat saya rekomendasikan untuk orang yang pernah mendengar “biarkan gagal” atau “BEAM menangani konkurensi dengan benar” tetapi belum benar-benar mendapat gambarannya. Presentasi ini benar-benar luar biasa
  • Sejak 1991, saya memprogram dengan Erlang setiap hari, dan berniat terus begitu
    Selama itu saya juga mencoba Haskell, Rust, Elixir, dan lainnya. Tipe yang kuat memang sangat berharga, tetapi pada akhirnya semuanya kembali ke di mana kita paling merasa senang
    Erlang adalah bahasa pemrograman yang memberi saya kesenangan terbesar, dan setidaknya sampai saya pensiun beberapa tahun lagi, saya berencana terus mengutak-atik Erlang

    • Saya penasaran proyek seperti apa yang paling menyenangkan untuk dikerjakan
  • Saya mengenal Elixir sedikit lebih dari setahun yang lalu, dan proses mempelajarinya serta memasukkannya ke berbagai komponen cukup menyenangkan
    Kesenangan terbesar datang dari banyaknya hal yang sudah tersedia secara bawaan hanya dengan BEAM/OTP
    Seseorang di tim tempat saya bekerja pernah berkata, “BEAM/OTP itu seperti k8s tanpa bagian-bagian yang rumit”

    • Saya menjelaskannya begitu kepada tim ketika penjelasan lain tidak mempan
      Saya mempelajari Elixir selama beberapa tahun, tetapi migrasi OpenShift, yaitu k8s, yang baru-baru ini saya rancang membuat manfaat itu agak berkurang
      Tanpa k8s, ini akan menjadi tawaran yang jauh lebih menarik. Sebagai gantinya, kami mempertahankan stack pengembangan yang ada, dan mencapai hal-hal yang tadinya akan dilakukan dengan OTP lewat konsep k8s. Tentu saja trade-off-nya berbeda
  • “Elixir memberi Anda bahasa yang menyenangkan seperti Ruby, sambil menyingkirkan ranjau terkait state dalam bahasa berorientasi objek. Tidak ada class, instance, maupun inheritance; sifatnya immutable dan fungsional, serta tidak terikat pada sistem tipe statis”
    Saya menginginkan ini, tetapi juga ingin ada tipe. Untuk codebase besar, saya yakin tipe yang kuat adalah pilihan yang benar. Karena itu menyingkap banyak magic dan membuatnya lebih mudah ditalar

    • Di Elixir, masalah ini lebih kecil dibanding bahasa dinamis lain seperti Ruby atau Python, atau bahasa statis yang memiliki mutabilitas
      Berkat pattern matching/unification pada fungsi, kita bisa cukup tahu bentuk data saat keluar-masuk. Kalau masih khawatir, ada Dialyzer
      Dialyzer adalah alat analisis statis untuk Erlang/Elixir. Alat ini disertakan dalam rilis standar Erlang, dan merupakan singkatan dari “DIscrepancy AnaLYZer for ERlang programs”
      Pada satu modul Erlang atau sekumpulan aplikasi, alat ini menemukan diskrepansi seperti kesalahan tipe, kode mati, dan pengujian yang tidak perlu. Ia menyimpulkan tipe berdasarkan program yang benar, dan anotasi tipe tidak wajib, tetapi jika ada akan memberikan peringatan yang lebih baik
      https://fly.io/phoenix-files/adding-dialyzer-without-the-pai...
    • Tipe sedang datang. Semoga tidak terlalu jauh lagi
      https://elixir-lang.org/blog/2023/06/22/type-system-updates-...
    • Saya justru berada di posisi berlawanan di sini. Saya benar-benar berharap GenServer di Elixir punya inheritance
      GenServer lebih mirip objek, dan bukan sekadar struct dengan fungsi-fungsi terkait; ia berinteraksi lewat pesan
      Akan bagus jika GenServer dalam proyek memiliki template dasar untuk registrasi umum, pengaturan memori, logging, dan semacamnya, lalu bisa dikhususkan untuk tiga variasi pekerjaan tertentu
      Elixir menambal masalah ini dengan pembuatan kode lewat macro, tetapi hasilnya tidak terlalu bagus. GenServer saya penuh dengan repetisi sepele
    • Kalau begitu, Gleam mungkin cocok untuk Anda. Sepertinya punya nuansa yang mirip
  • Menurut saya pernyataan “di Ruby, umum menggunakan exception untuk control flow” itu keliru
    Contoh setelah paragraf itu adalah metode update di Rails, padahal cara yang dipakai dalam contoh dan generator Rails standar adalah versi update yang tidak memakai exception

    • Contoh itu menunjukkan cara sederhana yang membatasi kompleksitas, terutama bagi orang yang sedang belajar
      Library atau aplikasi dengan skala tertentu, begitu cukup kompleks, akan beralih ke class error yang deskriptif. Karena penanganan error berbasis state seperti ActiveRecord itu menyakitkan
      Karena Ruby sekarang sudah punya pattern matching sampai tingkat tertentu, saya rasa itu bisa menggantikan exception untuk control flow. Alih-alih melempar exception, kembalikan class itu sendiri lalu lakukan matching terhadapnya
    • Sebagai orang yang memakai Ruby sejak 2004, saya sama sekali tidak merasa itu keliru
      Banyak gem memakai exception untuk control flow, dan itu juga umum di aplikasi serta library yang saya tulis atau pelihara
    • Ruby dan Rails tidak sama
      Rails memiliki banyak metode bang! yang melempar exception saat error. Namun secara umum, Ruby seperti Python: penggunaan exception untuk control flow memang umum dalam praktiknya
  • Saya berasal dari F# dan baru sedikit mencoba Elixir, tetapi sayangnya bahasanya terasa agak membingungkan
    Misalnya, signature fungsi hanya menunjukkan nama dan jumlah parameter, bukan tipenya, jadi di library besar cukup sulit untuk memahami di kepala apa yang masuk ke mana
    Fakta bahwa kita memasukkan parameter yang salah pun sering baru terlihat setelah menjalankan kode dan melakukan debugging. Dalam bahasa bertipe ketat seperti F#, masalah seperti ini langsung tertangkap saat coding, sehingga sangat menghemat waktu dan usaha
    Jadi selain lingkungan Erlang, saya penasaran apa daya tarik utama Elixir

    • Static typing di Elixir sedang aktif dikembangkan
      https://elixir-lang.org/blog/2023/09/20/strong-arrows-gradua...
      Saat ini memang masih bahasa dinamis, jadi kita tidak mendapat banyak informasi tipe dari bahasanya sendiri. Belum menjadi bahasa dengan static typing
    • Di Elixir sendiri juga banyak hal yang bisa disukai. Seperti disebutkan di artikel, sintaks yang terinspirasi Ruby enak dilihat dan mudah dipelajari
      Namun yang benar-benar membuat Elixir lebih unggul dibanding bahasa lain yang pernah saya pakai adalah BEAM/OTP
      Dari pengalaman saya, banyak fitur yang di bahasa lain harus dibawa lewat library sudah tersedia secara bawaan. Library semacam itu sangat menambah kompleksitas dan kadang juga memiliki kurva belajar yang besar. Fitur terkait async adalah contoh yang bagus
      Menurut saya, setelah memakai Elixir beberapa waktu dan mempelajari tool serta abstraksi bawaan seperti ini, kita akan memahami kekuatan seluruh ekosistemnya
    • Kalau hanya dilihat sebagai bahasa, saya tidak akan menyebutnya upgrade dari F#. Subjektif memang
      Daya tarik utamanya mungkin adalah ia berjalan di atas BEAM dengan sintaks bernuansa Ruby. Saya melihat BEAM sebagai keunggulan yang cukup besar
      Memang tidak sebanding dengan tipe di F#, tetapi typespec bisa dipakai: https://hexdocs.pm/elixir/1.15.7/typespecs.html
    • Saya cukup banyak memakai .NET dan hanya sesekali memakai F#, tetapi ada beberapa daya tarik Elixir
      Misalnya ada alur yang mengintegrasikan machine learning secara native bersama Axon, Nx, BumbleBee, bahkan memungkinkan kompilasi GPU: https://www.youtube.com/watch?v=HK38-HIK6NA
      Komunitas benar-benar mendorong bidang ini dengan kuat
      Cara kerja LiveView juga menarik. Meski begitu, .NET punya Blazor
      Elixir bisa dipakai dalam berbagai konteks seperti Nerves untuk embedded atau scripting. Sejauh yang saya tahu, F# juga bisa dipakai untuk scripting
      Secara keseluruhan, BEAM dan struktur terkaitnya adalah kekuatan utama, dan package manager Hex juga benar-benar bagus. Tentu saja tool di .NET juga bagus
    • Tidak adanya type hint pada parameter fungsi adalah hal yang paling memukul produktivitas di Elixir
      Kita bisa bertahan dengan typespec, pattern matching, dan guard, tetapi itu cukup merepotkan, dan setidaknya pada plugin JetBrains yang digerakkan komunitas, tidak ramah IDE/IntelliSense
  • Akan lebih baik kalau menulisnya setelah memakai 2 tahun, bukan saat baru mulai
    Hal baru pada awalnya selalu tampak seperti solusi serba bisa yang berkilau tanpa cela

    • Saya penulisnya, dan saya paham konsep masa honeymoon
      Kesan pertama juga punya tempatnya sendiri, dan itulah yang saya berikan. Sasarannya bukan para pakar Elixir/Erlang, melainkan para pakar Ruby
    • Saya pernah bekerja secara profesional sebagai developer Elixir lebih lama dari itu sebelum memulai program doktoral
      Elixir dulu maupun sekarang tetap seperti permata. Tidak sempurna, tetapi luar biasa tangguh
  • Saya sudah memakai Ruby sejak sekitar 2007
    Setiap kali mencoba beralih ke hal “keren” berikutnya, akhirnya saya selalu kembali ke Ruby, karena saya menyukai Ruby, bisa bekerja paling cepat dengan Ruby, dan hanya itu yang penting
    Namun belakangan saya melihat jauh lebih banyak pembahasan tentang Elixir, dan saya suka tampilan serta feel-nya. Sepertinya saya harus mencobanya lewat side project baru dalam waktu dekat