Alasan Jepsen Ditulis dengan Clojure
(aphyr.com)- Jepsen adalah alat untuk memverifikasi sistem konkurensi seperti database, sehingga model konkurensi dan dukungan thread nyata pada bahasa implementasinya juga menjadi kriteria pemilihan yang penting
- Struktur data immutable dan persisten milik Clojure serta alat konkurensi JVM membantu mengurangi kemungkinan kesalahan pada kode pengujian, dan juga cocok dengan klien database berbasis Java
- Pekerjaan Jepsen lebih dekat ke eksperimen dan eksplorasi daripada pengembangan produk yang sudah ditetapkan, sehingga fitur Clojure seperti REPL, makro, threading macro, dan EDN menguntungkan untuk pemrosesan data yang kompleks
- Performanya memang bukan yang teratas, tetapi Clojure idiomatis biasanya hanya lebih lambat dari Java dalam kisaran satu hingga dua digit, dan titik yang perlu dapat ditangani dengan optimisasi serta alat profiling JVM
- Ada kelemahan seperti komunitas yang kecil, tidak adanya sistem tipe statis yang diterima luas dan terbukti sukses, penanganan primitive yang kurang nyaman, serta pesan kesalahan, tetapi bagi Jepsen yang dipelihara dan digunakan oleh 1–3 orang, itu adalah kompromi yang masih layak diterima
Syarat bahasa yang cocok untuk alat uji konkurensi
- Jepsen dibuat untuk menguji sistem konkurensi, dan target pengujiannya sebagian besar adalah database
- Clojure memenuhi dengan baik syarat dasar yang dibutuhkan untuk menulis kode pengujian konkurensi
- Struktur data immutable dan persisten menurunkan kemungkinan kesalahan pada kode yang menangani state bersama
- Dapat menggunakan thread nyata, promise, future, atom, lock, queue, cyclic barrier,
java.util.concurrent, dan lain-lain - Bahasa yang lebih ketat dalam mengendalikan efek samping seperti Haskell juga sempat dipertimbangkan, tetapi pendekatan Clojure yang tidak terlalu dogmatis lebih cocok untuk Jepsen
- Pengujian database membutuhkan koneksi dengan berbagai klien
- Hampir semua database biasanya menyediakan klien JVM yang ditulis dengan Java
- Clojure memiliki interoperabilitas Java yang baik sehingga mudah memanfaatkan klien-klien tersebut
Fitur Clojure yang menguntungkan untuk eksperimen dan eksplorasi data
- Pengujian Jepsen adalah pekerjaan eksperimental, jadi dibutuhkan bahasa yang ringkas, mudah diubah, dan cocok untuk prototyping
- Sintaks Clojure yang ringkas dan sistem makro sangat cocok untuk cara kerja seperti ini
- Threading macro membuat transformasi berantai lebih mudah dibaca
- Makro memudahkan implementasi penanganan error yang dapat digunakan ulang dan pengendalian cakupan resource
- REPL Clojure berguna untuk menjelajahi data hasil eksekusi pengujian secara langsung
- Dalam proses pengujian, perlu merepresentasikan, mentransformasikan, dan memeriksa struktur data yang kompleks dan bertingkat
- Struktur data Clojure dan fungsi pustaka standarnya kuat untuk pekerjaan ini
- Saat banyak mencetak data terstruktur ke konsol dan file, sintaks data EDN sangat cocok
Kompromi antara performa dan pemeliharaan jangka panjang
- Jepsen bukan sistem yang sangat besar, tetapi tetap menangani jumlah data yang lumayan sehingga membutuhkan performa yang “cukup baik”
- Clojure bukan bahasa yang paling cepat
- Clojure idiomatis biasanya memiliki selisih performa terhadap Java yang masih dalam kisaran satu hingga dua digit
- Pada bottleneck penting, selisih itu bisa dikurangi
- Alat profiling JVM bekerja dengan baik untuk Clojure
- Jepsen adalah proyek berusia sekitar 10 tahun, jadi inti yang matang dan stabilitas itu penting
- Clojure stabil baik dari sisi target JVM maupun dari sisi bahasanya sendiri
- Pustakanya tidak cepat “membusuk” seperti Scala atau Ruby
Kelemahan Clojure yang harus diterima
- Clojure punya kekurangan yang masih bisa ditangani pada skala Jepsen, tetapi bisa menjadi beban untuk tim yang lebih besar
- Komunitas engineering-nya kecil
- Tidak ada sistem tipe statis yang diterima luas dan sukses
- Jepsen hanya dipelihara dan digunakan oleh 1–3 orang pada satu waktu, sehingga batasan ini tidak terlalu besar dampaknya
- Saat menangani JVM primitive, bisa terasa menyulitkan jika tidak turun ke Java, dan memang kadang Java dipakai
- Sebagian sistem polimorfismenya kurang memadai, tetapi bisa diakali dengan pustaka, dan pesan kesalahannya juga tidak bagus
- Jepsen sempat dibuat prototipenya dalam beberapa bahasa sebelum akhirnya diputuskan memakai Clojure, dan bahkan setelah 10 tahun, itu masih menjadi kompromi yang cukup baik
1 komentar
Komentar Hacker News
Dari sudut pandang saya yang sudah mengoperasikan SaaS dengan Clojure/ClojureScript selama sekitar 10 tahun, saya sepenuhnya setuju dengan tulisan Kyle
Hal lain yang sangat bernilai adalah fakta bahwa sebagian besar kode domain bisa ditempatkan di file cljc sehingga dapat dikompilasi untuk server maupun klien, bahwa transducer dan pipeline transducer masih diremehkan dari sisi performa, komposabilitas, dan reusabilitas, serta bahwa, sebagaimana layaknya bahasa yang dirancang Rich Hickey, stabilitas dan kompatibilitas jangka panjangnya sangat baik
Kompatibilitas ke belakang sangat penting, sehingga kita bisa fokus pada aplikasi alih-alih terseret oleh alat yang terus berubah; menurut saya bukan kebetulan juga bahwa rata-rata programmer Clojure memiliki pengalaman lebih dari 12 tahun dan mendapat kompensasi kuartil teratas
Hampir tidak pernah rusak dan upgrade juga mudah. Berkat HMR, REPL, dan file cljc, pengalaman developernya juga luar biasa, dan menulis kode Clojure itu menyenangkan
Orang bilang tidak apa-apa membuat bahasa dan sistem sampai “melengkung ke belakang” demi tidak merusak hal yang sudah bekerja, tapi saya tidak mengerti kenapa terhadap dua bahasa yang menopang sebagian besar software yang benar-benar berjalan, orang justru berharap mereka memutus masa lalu dan masa kini yang gemilang
Masalah terbesar Clojure jelas adalah ekosistem
Kalau melihat distribusi alat yang bisa diakses dan layak dipakai, pilihannya terlalu berada di ujung kiri—alat yang buruk sekali tetapi mudah diakses—atau terlalu di ujung kanan, dengan README berisi kutipan Lord of the Rings, semuanya adalah data sampai orde ke-n, dan hanya naga yang bisa menulis plugin Emacs sambil ditutup matanya dan digantung terbalik yang bisa mengaksesnya
Bahasanya sendiri luar biasa, dan interoperabilitas Java juga jauh lebih baik daripada yang dikatakan Aphyr, tetapi seandainya Clojure punya sesuatu seperti Rails atau Django, atau lebih baik lagi Phoenix, bahasa ini akan jauh lebih mudah meyakinkan orang dan akan dipakai lebih luas
Terutama ketika ingin meyakinkan tim untuk pindah dari bahasa imperatif keluarga Algol ke Lisp, manfaat yang didapat harus lebih besar daripada kerepotannya, sementara saat ini hampir setiap proyek harus menemukan ulang roda, kecuali untuk elemen dasar seperti routing HTTP
Meski begitu, kemampuan memakai paket Maven apa pun dan dikompilasi menjadi jar adalah keunggulan besar; di mana pun jar bisa berjalan, Clojure juga bisa berjalan
https://calva.io
Clojure punya beberapa bentuk; yang terutama dipakai adalah Clojure dan ClojureScript, ada juga Babashka, Scittle, dan lain-lain, tetapi semuanya diturunkan dari clj atau cljs
Alat pengembangan bergantung pada platform dan preferensi IDE, jadi Emacs, Neovim, VSCode, dan IntelliJ masing-masing punya alat berbeda, dan sistem build juga berbeda sesuai kebutuhan
Di clj, deps.edn saat ini yang paling banyak dipakai, disusul leiningen; untuk cljs, selain shadow-cljs ada beberapa opsi lain
Bagi orang yang baru mengenalnya ini bisa terasa berlebihan, tetapi komunitasnya baik dan selalu membantu. Saya sudah bekerja sebagai programmer profesional dengan berbagai bahasa, tetapi Clojure jelas yang paling saya sukai
Saya sudah memakai Clojure sejak sekitar 2013 dan tidak terpikir alat seperti itu. Sebagian besar library populer sangat bagus, dan dalam hal stabilitas, kompatibilitas ke belakang, serta kesederhanaan, ekosistemnya jauh di depan kebanyakan ekosistem yang saya kenal
Berkat file sumber .cljc yang dapat dibagikan antara Clojure dan ClojureScript, kode Clojure yang sama bisa dijalankan di frontend maupun backend
Seperti yang dikatakan Rich Hickey, bukan hanya JVM yang “dijangkau”, JavaScript juga dijangkau
Saya sudah lama memakai Emacs dan pada akhirnya bisa mengonfigurasinya sesuai keinginan atau membuat kode elisp yang diperlukan, tetapi saya sama sekali tidak bisa bilang saya mahir elisp
Saya mengakui bahwa bagi orang yang belum pernah belajar dialek Lisp sama sekali, mempelajari Emacs, elisp, dan Clojure sekaligus itu sulit dan sangat susah diyakinkan
Sekarang ada Clojure LSP server dan ia bekerja tidak hanya di Emacs tetapi juga di IDE lain, jadi meskipun banyak developer Clojure memakai Emacs, Emacs bukanlah syarat untuk pengembangan Clojure
Selama 7 tahun saya hanya memakai Clojure dan aktif menangani codebase Clojure + ClojureScript lebih dari 500 ribu baris, dan keluhan terbesar saya adalah tidak adanya sistem tipe yang kokoh
Saya setuju bahwa Clojure ekspresif, memungkinkan bergerak cepat, dan tidak menghalangi, tetapi ia juga membiarkan error runtime yang berantakan, sulit direproduksi, dan sulit di-debug
Seandainya ada sistem tipe statis yang diterima luas dan sukses, Clojure akan luar biasa. Saat ini, menurut saya Clojure cukup bagus jika kamu menyukai Ruby atau Python tetapi menginginkan sesuatu yang lebih kuat, dan sekarang saya jadi mempertimbangkan apakah Go adalah jalan yang tepat
Saya sepenuhnya setuju bahwa Clojure(Script) benar-benar seperti berkah, dan merupakan pilihan yang sangat baik untuk banyak proyek, baik kecil maupun besar
Setelah sedikit memakai C, Python, PowerShell, Java, Bash, dan SQL untuk tugas kuliah, administrasi sistem, analisis traffic dump, dan sebagainya, bahasa pertama yang saya pakai untuk pemrograman profesional adalah Clojure
Saya sedang membuat OrgPad dengan Clojure+ClojureScript, dan meski kodenya sudah melampaui 100 ribu baris, saya tetap menganggap itu keputusan yang baik
Mudah didekati, dan setelah menulis sedikit kode, saya cukup yakin bahwa ia akan berjalan seperti yang saya bayangkan. Di Python, PowerShell, dan Bash pun tidak sampai seperti ini; rasanya benar-benar beda kelas
Alur kerja REPL juga sangat bagus, dan rekan saya membuat video terkait: https://www.youtube.com/watch?v=4igO7Qbyj9o
Sekarang, fungsi, tugas singkat, dan proyek kecil yang mungkin membuat kita mempertimbangkan pindah dari Bash ke Python juga bisa ditangani dengan Babashka/nbb
Dulu ketika saya mencoba menulis beberapa ribu baris Clojure dan ClojureScript, masalah terbesarnya adalah sebagian besar tooling memiliki kondisi error yang cukup berantakan
Python juga punya sisi serupa, sehingga kalau sebagian besar program Python dihentikan dengan Ctrl+C akan muncul stack trace berisi hal-hal yang tidak jelas, tetapi bagi orang yang baru mulai, ini membuat sulit untuk maju
Saya pikir bahasa dan ekosistemnya memuat banyak ide inovatif dan menarik. Setidaknya, membaca makalah sejarah Clojure dan menginternalisasi sebagian besar pelajarannya layak dilakukan
Mungkin terdengar sesat bagi semua orang, tetapi saya pikir ada ruang ekosistem kecil untuk sebuah bahasa scripting yang sama seriusnya dengan Clojure soal performa dan ergonomi penulisan kode, tetapi tanpa tanda kurung
Kebiasaan memperlakukan nil secara khusus juga sebaiknya tidak perlu ada, tetapi setidaknya di sana ada sedikit landasan
Saya tahu
(f x y)lebih baik daripadaf(x, y), tetapi masalah saya lebih dekat pada kasus ketika form let menyebabkan indentasi. Menurut saya, untuk memberi nama pada sebuah nilai, kita tidak perlu membayar biaya indentasi dan tanda kurung sekaligusKalau datang dari bahasa seperti Python yang memakai indentasi yang memang akan kita tulis di kode sebagai informasi, hal-hal seperti ini kadang terasa seperti noise saja
Dalam gaya fungsional, sering kali tidak perlu memberi nama pada argumen antara yang diteruskan antar-fungsi
Biasanya argumen diteruskan secara implisit ke fungsi berikutnya dengan threading macro
->,->>, atau transformasi itu sendiri didefinisikan sebagai fungsi murni dan diletakkan di level teratasNamun saya mengerti bahwa pada sebagian kode interoperabilitas, let memang banyak dibutuhkan. Terutama library Java JWT yang mengubah argumen dalam rantai prosedural
Misalnya setelah lama debugging, baru sadar bahwa belum melakukan reload atau reinitialization
Saya merasa kebanyakan orang akan menambahkannya ke daftar hal yang harus dicek dalam situasi “ini tidak mungkin terjadi”. Misalnya, “mari tambahkan output debug untuk memastikan perubahan kode saya benar-benar dipanggil”
Tentu saja ini hanya jaring pengaman, dan biasanya kita mencoba menghindari situasi seperti itu dengan kebiasaan kerja REPL yang lain
(+ clojure clojurescript)Clojure melakukan banyak hal dengan benar, dan karena itu saya sangat menyukainya
Menurut saya, satu hal yang memperlambat tim nyata ketika membangun pekerjaan web nyata dengan Clojure adalah dorongan yang hampir dogmatis untuk merangkai semuanya dengan menggabungkan banyak library yang masing-masing punya caranya sendiri
Jika selain pendekatan yang ada saat ini komunitas juga memiliki web framework yang aktif dipelihara, batteries included, dan secara umum layak dipakai, saya rasa Clojure akan jauh lebih populer dan menyenangkan digunakan. Saya penasaran apakah Biff adalah jawabannya
Akan bagus kalau ada jalur alternatif bagi orang yang menyukai bahasanya tetapi tidak menyukai cara merakit monster sendiri
Ini juga karena saya sudah terbiasa dengan Ruby on Rails
Seperti ceramah Rich Hickey yang terkenal, pendekatannya adalah jangan complect, tetapi compose: (https://github.com/matthiasn/talk-transcripts/blob/master/Hi...)
Belajar Clojure, graph database, dan kadang HTMX juga, itu cukup banyak. Meski begitu, banyak konfigurasi sudah disiapkan, autentikasinya teliti dan mudah, dan komentar pada file konfigurasi server juga bagus
Ada juga skrip deployment untuk menyiapkan server Linux dan masuk ke production REPL lewat SSH. Jika ingin memakai XTDB, cara Biff mengatur validasi dokumen benar-benar bagus
Secara pribadi, saya lebih menyukai ini daripada aplikasi yang berjalan dengan ClojureScript. Ada banyak wrapper ClojureScript untuk React dan itu hampir menjadi meme, tetapi sebagai developer React, saya tidak merasa satu pun di antaranya lebih mudah daripada React
Justru terasa rumit dan tidak pas di tangan. Sebaliknya, HTMX/Hyperscript sangat cocok dengan Clojure karena sintaks HTML hanyalah array dan objek yang mudah dimanipulasi
Pepatah “kode adalah data” yang terus diulang para penggemar Clojure untuk pertama kalinya terasa nyata
Dulu saya beberapa kali mencoba memakai OCaml sedikit-sedikit, tetapi saya tidak menyukai sistem tipenya yang terlalu ketat
Waktu yang saya habiskan untuk memuaskan compiler lebih banyak daripada waktu menulis kode. Di Clojure, Common Lisp, dan C, saya punya kebebasan lebih besar untuk membengkokkan compiler atau sistem tipe ke arah yang saya inginkan
Tentu ada plus-minusnya, tetapi saya tidak ingin terganggu saat menulis kode. Bisa saja ini gaya saya, tetapi saya bertemu banyak orang yang berpikiran sama
Saya percaya sistem tipe statis adalah soal selera, dan kubu seberang berpikir berbeda. Meski begitu, adanya kubu yang saling berlawanan itu bagus karena kita bisa banyak belajar satu sama lain
Rich Hickey berkali-kali mengatakan bahwa Clojure adalah bahasa host, jadi tidak masalah turun ke Java atau JavaScript saat diperlukan
Secara pribadi, saya melihat ini sebagai salah satu fitur terkuat dalam ekosistem Clojure, karena jauh lebih pragmatis
Saya sering melihat upaya mengimplementasikan ulang hal yang sama dalam bahasa yang disukai hanya karena tidak mau menyentuh “library yang ditulis dengan bahasa lain yang kotor itu”. Alasannya beragam: lambat, tidak aman, tidak fleksibel, dan sebagainya
Hal seperti ini sering terjadi, dulu maupun sekarang, di Common Lisp dan juga di komunitas Rust
SBCL menjamin deklarasi itu semaksimal mungkin, dan mungkin menghemat beberapa menit sakit kepala di tiap proyek
Dan CL sangat pragmatis; misalnya, tidak ada yang merasa terusik hanya karena woo berbasis library C
Semua masalah operasional terkait dengan isu-isu kecil dan halus. Misalnya, urutan key JSON berubah karena upgrade runtime sehingga client lama yang mem-parsing JSON secara manual menjadi rusak, atau library jauh di dalam stack mulai mengembalikan kode HTTP sebagai integer alih-alih string sehingga parsing error rusak
Pada skala operasi kami, bahkan jika hanya sebagian kecil pelanggan yang terdampak, itu berarti ratusan laporan masalah masuk, jadi setiap gangguan adalah perkara besar
Sekarang saya bekerja di startup kecil dan situasinya benar-benar berbeda. Kami memilih bahasa statis karena itulah arah yang menarik perhatian dan orang, tetapi saya merindukan masa bekerja dengan bahasa dinamis
Karena harus merilis cepat, kualitas kode benar-benar memburuk. Karena keterbatasan waktu, alih-alih berurusan dengan sistem tipe dan melakukan refactor bersih, kami menyalin beberapa struktur objek yang hampir sama tetapi sedikit berbeda dan memakainya di berbagai tempat
Karena bentuk tipe membuat generalisasi sulit, alih-alih memisahkan fitur lalu merujuknya dari banyak tempat, kami copy/paste logika yang sama ke 10 tempat
Saya pikir solusi yang tepat bergantung pada domain masalahnya. Jika bug yang halus bisa membuat Anda dipanggil tengah malam, tipe statis yang ketat kemungkinan besar tepat
Jika Anda perlu beriterasi cepat dan masalah bisa diselesaikan dengan satu email atau pesan Slack, tipe dinamis bisa lebih baik
Kuncinya adalah tidak menumpuk terlalu banyak utang dalam paradigma dinamis, agar siap saat tumbuh dan harus berpindah ke paradigma statis
Sayangnya, bahasa yang punya banyak penggemar fanatik tampaknya mudah tergelincir ke sikap “saya tidak mau memakai library bahasa lain”
Clojure sejauh ini adalah bahasa favorit saya dan terasa alami
Namun dua hal yang benar-benar saya rindukan dari bahasa lain adalah pesan error yang bisa dipahami dan type hint
Di perusahaan, saya harus me-refactor codebase besar, dan itu menyakitkan. Sulit mengetahui fungsi mana yang akan melempar exception atau sekadar mengembalikan nil, dan sulit juga mengetahui apakah fungsi inti akan mengembalikan vector, sequence, atau collection lain
Ada proyek-proyek yang mencoba menyelesaikan ini seperti spec, malli, dan typed clojure, tetapi bagi saya belum terasa seperti pengganti yang mendekati tipe di Python atau TypeScript
Bahasa yang tidak bisa memberi tahu apa yang masuk dan apa yang keluar dari sebuah fungsi terasa hampir tidak bernilai untuk codebase yang lebih dari beberapa file
Mencoba menyimpulkan tipe dengan melihat apa yang tampaknya bisa dilakukan kode saat ini terhadap sebuah objek adalah cara menyiksa diri sendiri
Jika baru pertama kali mengenal Clojure, ada baiknya mencoba tutorial interaktif ini: https://tryclojure.org
Ini adalah kumpulan pembelajaran interaktif yang lebih baik, dari level mudah ke menengah hingga sulit
Clojure itu menyenangkan
Rails mendominasi pengembangan web pada 2010-an, dan banyak startup yang sangat sukses dibangun di atasnya
Banyak engineer mencibir bahwa orang “bermain dengan mainan”, tetapi cukup banyak hal baik yang kita miliki sekarang dulunya pernah berupa mainan. Linux juga contoh yang bagus
Hal rumit dari bahasa yang sangat “menyenangkan” adalah kita jadi berasumsi semua hal bisa diselesaikan dengan bahasa itu
Pada akhirnya kita menulis banyak kode, padahal jika dilihat belakangan, tidak menulis kode mungkin sudah menjadi solusi yang cukup baik
[1] https://franz.hamburg/writing/clojure-makes-happy.html