การเปลี่ยนมาใช้ Elixir
(leemeichin.com)- หลังจากนักพัฒนาแบ็กเอนด์ Ruby เข้าร่วมบริษัทที่ ใช้ Elixir เป็นภาษาหลัก ก็สามารถปรับตัวได้ค่อนข้างเร็วแม้ไม่มีประสบการณ์กับ Elixir/Erlang มาก่อน เพราะไวยากรณ์ได้รับอิทธิพลจาก Ruby
- Elixir มอบทั้งความสนุกด้านไวยากรณ์และความเป็นมิตรต่อ DSL แบบ Ruby แต่ใช้ โมเดลฟังก์ชันเชิงประกอบที่ไม่เปลี่ยนแปลงค่า ซึ่งไม่มีคลาส·อินสแตนซ์·การสืบทอด จึงลดภาระในการจัดการสถานะ
- ขณะที่ Ruby DSL พึ่งพาการนิยามอ็อบเจ็กต์และเมธอดแบบไดนามิกในรันไทม์นั้น Elixir DSL ใช้ แมโครในช่วงคอมไพล์ เพื่อสร้างโค้ดรันไทม์ ทำให้พบข้อผิดพลาดได้เร็วกว่า
- ไวยากรณ์แบบ pipeline, นิพจน์
withและ Result tuple ในรูปแบบ{:ok, result}มีประโยชน์ในการแยกเส้นทางปกติออกจากการจัดการข้อผิดพลาดที่กู้คืนได้ - เมื่อเทียบกับแนวทางใน Ruby ที่พึ่งพา exception,
nil/falseและสถานะข้อผิดพลาดภายในอ็อบเจ็กต์แล้ว การคืนค่าok/errorอย่างชัดเจนของ Elixir ให้ความรู้สึกน่าพอใจกว่า และแม้ใช้มา 3 เดือนก็ยังรู้สึกสนุกกับการเขียนอยู่
วิธีที่คนมีประสบการณ์ Ruby ปรับตัวกับ Elixir
- ที่ทำงานใหม่ใช้ Elixir เป็นภาษาหลักของแบ็กเอนด์ และก่อนเริ่มงานก็ไม่เคยเขียนโค้ด Elixir หรือ Erlang มาก่อน
- Erlang ไม่ได้รู้สึกแปลกนักเพราะเคยแตะ Prolog มาบ้าง และ Elixir ก็เรียนรู้ได้เร็วเพราะไวยากรณ์ได้รับอิทธิพลจาก Ruby อย่างชัดเจน
- แม้ยังไม่เชี่ยวชาญแนวปฏิบัติที่ดี สถาปัตยกรรม หรือแนวคิด Erlang ระดับล่างกว่านี้ แต่สิ่งเหล่านี้ก็ไม่ได้ขัดขวางการเริ่มต้นกับ Elixir
- Elixir ถูกมองว่าเป็นภาษาที่คงความสนุกในการเขียนโปรแกรมแบบที่ Ruby มอบให้ไว้ ขณะเดียวกันก็ลดกับดักเรื่องสถานะที่พบบ่อยในภาษา OOP
- ไม่มีคลาส, อินสแตนซ์, การสืบทอด
- ยึดตาม immutability และสไตล์เชิงฟังก์ชัน
- ไม่ถูกผูกมัดด้วยระบบชนิดข้อมูลแบบสแตติก
- โค้ดที่มีสถานะเปลี่ยนแปลงได้มักดูแลรักษายากกว่ามาก และก็ไม่ชัดเจนเสมอไปว่าสถานะนั้นอยู่ในขอบเขตของฟังก์ชัน อินสแตนซ์ หรือคลาส
- ใน Ruby ทุกอย่างคืออ็อบเจ็กต์ ทำให้อ็อบเจ็กต์แต่ละตัวมีสถานะได้ และระหว่างพยายามสร้าง DSL ที่ใช้งานได้อย่างเป็นธรรมชาติ ก็มักทำให้สถานะระดับฟังก์ชัน·อินสแตนซ์·คลาสปะปนกันได้ง่าย
- Eigenclass ของ Ruby คือแนวคิดคล้ายคลาสของคลาส และอินสแตนซ์หนึ่งตัวสามารถแก้ไข eigenclass จนส่งผลต่อสถานะของอินสแตนซ์อื่นได้
ความต่างของ DSL กับแมโครในช่วงคอมไพล์
- Elixir รองรับ DSL และมีไวยากรณ์คุ้นเคยแบบ Ruby เช่นกัน แต่ความต่างสำคัญอยู่ที่ช่วงเวลาที่ DSL ถูกสร้างขึ้น
- Elixir DSL คือ แมโครในช่วงคอมไพล์ ที่สร้างโค้ดสำหรับรันไทม์
- Ruby DSL พึ่งพาการแก้ไขรันไทม์เพื่อกำหนดอ็อบเจ็กต์และเมธอดแบบไดนามิก
- หากใช้แมโครของ Elixir ผิดพลาด อาจเกิดข้อผิดพลาดในไลบรารี และหากโค้ดแมโครที่สร้างขึ้นผิดก็จะเจอ compiler error
- เพราะข้อผิดพลาดเหล่านี้ปรากฏตั้งแต่ช่วงคอมไพล์ การทดสอบจึงโฟกัสกับ logic ของแอปพลิเคชันจริงได้มากกว่า
การไหลของงานที่เกิดจาก pipeline และ with
- ตัวดำเนินการ pipeline
|>ของ Elixir มีประโยชน์ แต่ตัวดำเนินการ threading ของ Clojure ก็มีข้อดีของมันเช่นกัน->ของ Clojure จะส่งผลลัพธ์จากนิพจน์ก่อนหน้าเข้าเป็นอาร์กิวเมนต์ตัวแรกของฟังก์ชันถัดไป เหมือน|>ของ Elixir->>ของ Clojure จะส่งผลลัพธ์ก่อนหน้าเข้าเป็น อาร์กิวเมนต์ตัวสุดท้าย ของฟังก์ชันถัดไป- ความต่างนี้ดูเหมือนเล็กน้อย แต่มีประโยชน์เมื่อเขียนโค้ดเชื่อมต่อร่วมกันโดยไม่ต้องใช้อะนอนิมัสฟังก์ชัน
- นิพจน์
withของ Elixir ชวนให้นึกถึงletใน Haskell·Lisp และทำงานเหมือนมีotherwiseในตัว- มันช่วยแยกฟังก์ชันที่ซับซ้อนออกเป็นเส้นทางปกติด้านบน กับการจัดการข้อผิดพลาดด้านล่าง
- หากไม่สามารถทำ pattern matching กับ
{:ok, result}ได้ ก็สามารถมองเป็นข้อผิดพลาดที่กู้คืนได้ จึงเข้ากันได้ดีกับ Result tuple
ข้อดีของการคืนค่าข้อผิดพลาดอย่างชัดเจน
- ใน Ruby การใช้ exception เพื่อควบคุม flow เป็นเรื่องที่พบได้บ่อย และแทนที่จะมีชนิดข้อผิดพลาดแบบชัดเจน ก็มักพึ่งพาผลลัพธ์เมื่อสำเร็จ,
nil,falseหรือสถานะข้อผิดพลาดภายในอ็อบเจ็กต์- ตัวอย่างเช่น
model.update(params)จะคืนค่าfalseเมื่อไม่สำเร็จ และเก็บสาเหตุของความล้มเหลวไว้ในmodel.errors - สิ่งนี้พากลับไปสู่ปัญหาเรื่อง สถานะที่เปลี่ยนแปลงได้ อีกครั้ง
- ตัวอย่างเช่น
- แนวทางแบบ
Result/Eithermonad ที่ระบุok/errorหรือleft/rightอย่างชัดเจนในค่าที่คืนกลับ ให้ความรู้สึกน่าพอใจกว่าการไหลของข้อยกเว้นแบบ Ruby - แม้หลังจากใช้ Elixir มา 3 เดือน Elixir ก็ยังเป็นภาษาที่สืบทอดความรู้สึกว่า “การเขียนโปรแกรมคือเรื่องสนุก” แบบที่ Ruby เคยมอบให้
1 ความคิดเห็น
ความเห็นจาก Hacker News
ช่วงหลายสัปดาห์ที่ผ่านมาแทบดู วิดีโอ Elixir บน YouTube ทุกวัน
เหมือนเมื่อไม่นานมานี้จะมีงานคอนเฟอเรนซ์ Elixir พอดี และพอดูไปไม่กี่อัน YouTube ก็แนะนำคอนเทนต์ Elixir ต่อเนื่องให้เรื่อยๆ
ผมชอบแนวคิดของ Erlang แต่ตอนก่อนที่เคยจับพวกแชตเซิร์ฟเวอร์อย่าง ejabberd มันรู้สึกแปลกมากเกินไป
ทุกครั้งที่ดูวิดีโอของ Joe Armstrong ก็ยิ่งรู้สึกว่าเขาเป็นอัจฉริยะที่ถูกประเมินต่ำไป และเรื่องโปรเซสที่แยกจากกันกับการส่งข้อความ หรือก็คือ actor model ดูเป็นตัวเลือกที่ดีสำหรับอนาคตของการเขียนโปรแกรมแบบกระจาย
แม้แต่วิดีโอภาษา Misty ใหม่ของ Crockford https://www.youtube.com/watch?v=R2idkNdKqpQ ก็ยังน่าสนใจตรงที่คำถามถูกพาไปทาง Elixir/Erlang
แต่พอเห็น “เวทมนตร์” ของ LiveView กับ LiveBook ก็ยังไม่มั่นใจเต็ม 100% ของที่ดูดีเกินไปมักมีหลุมพราง และคำศัพท์แปลกๆ อย่าง GenServer รวมถึงความรู้เฉพาะแพลตฟอร์มก็ดูเหมือนประตูทางเดียว ไม่แน่ใจว่าเป็นความรู้ที่ย้ายไปใช้ที่อื่นได้ไหม
ในเมื่อ Go เองก็มีเรื่องเล่าด้าน concurrency ที่ดีพอตัว ภาษาและแพลตฟอร์มที่ชุมชนเล็กกว่าก็มีความเสี่ยงด้านการจ้างงาน ไลบรารี และเอกสารอยู่มาก ถึงอย่างนั้น สิ่งที่ชุมชน Elixir ทำได้ก็ยังน่าประทับใจมาก และก็น่าติดตามว่าระบบ type จะออกมาเป็นอย่างไร
sendทำงานอย่างไรก็พอGenServer ก็แค่การสรุปรูปแบบที่คุณต้องเขียนเองซ้ำแล้วซ้ำอีกให้เป็นนามธรรมที่เป็นธรรมชาติ และความรู้เรื่อง actor ก็เอาไปใช้ที่อื่นได้
ใน Go ก็มีไลบรารีที่ทำ actor abstraction เหมือนกัน และ mailbox ของโปรเซสก็มองเป็น message queue คล้าย channel ของ Go ได้ ความต่างอยู่ที่อินเทอร์พรีเตอร์กับการยอมคืนเวลาให้โปรเซสเซอร์ทำงานอย่างไร
ส่วน LiveView นั้นดูเหมือนเวทมนตร์จริง มีชิ้นส่วนที่เคลื่อนไหวหลายอย่างทำงานร่วมกัน และเป็นผลจากงานที่หลายคอมมูนิตี้สะสมกันมาตลอด 10 ปีที่ผ่านมา ดังนั้นถึงจะมี abstraction เยอะ แต่ไอเดียตัวมันเองถือว่าสุกงอมแล้ว
ของอย่าง Riak นั้นมาก่อนกาล และเกือบจะมีแนวคิดครบแล้วว่าคุณสามารถสร้างระบบ distributed ที่แข็งแกร่งได้เหมือนกับการสร้าง GenServer
ทั้ง Chris และ José ต่างก็พยายามเพิ่มการมองเห็นนอกวง Elixir ยุคแรกกันมาก และคนในคอมมูนิตี้เองก็ทำสิ่งเดียวกันในระดับของตัวเอง
เรื่องการจ้างงานไม่ได้ซับซ้อนอย่างที่คิด มีคนจำนวนไม่น้อยที่อยากทำงานด้วยภาษานี้ และนักพัฒนาที่เก่งก็ตามทันได้ค่อนข้างเร็ว
ถึงอย่างนั้นความเป็น ภาษาเฉพาะกลุ่ม ก็ยังเป็นเรื่องที่ต้องรับมือ สำหรับตัวภาษาเองมันคือความเสี่ยง แต่ในระยะสั้นมันก็อาจกลายเป็นผลตอบแทนจากการเชี่ยวชาญเทคโนโลยีเฉพาะทางได้เหมือนกัน
ส่วนใหญ่คุณดูออกว่าอะไรทำอะไรและอ่านโค้ดเข้าใจได้ แต่ JavaScript มักไม่เป็นแบบนั้น
เรื่องหาคนกับหาบทสอนยากนั้นจริง ตัวอย่างเช่น การหาคนที่เคยทำสิ่งที่ผมอยากทำใน Elixir มาก่อนยากกว่า JavaScript มาก
ไลบรารีไม่ใช่ปัญหาใหญ่และก็มีเยอะพอสมควร เวลาใช้ API บางทีมีไคลเอนต์ไลบรารีสำหรับ JavaScript หรือ Python แต่ไม่มีของ Elixir ซึ่งโดยทั่วไปก็ไม่ได้ยากนักที่จะใช้ API ด้วยแค่ HTTP client
ตอนนี้ใช้ Node.js ไม่ใช่เพราะอยากใช้ แต่เพราะจำเป็นต้องใช้ ลองใช้แล้วก็คิดว่าคงไม่เริ่มโปรเจ็กต์ใหม่ด้วย Node.js อีกแน่นอน
เรื่อง การควบคุม concurrency, scalability และเครื่องมือด้าน reliability/observability ของ Node.js ตามหลัง ecosystem ของ BEAM อยู่มาก
ผมคิดว่าที่คนรู้สึกเชื่อยากเพราะคนชอบ Elixir กันมาก อาจเป็นเพราะคุ้นกับแพลตฟอร์มที่ไม่ได้ถูกออกแบบมาเพื่อความยืดหยุ่นทนทานมากเกินไป
LiveBook ถ้าไม่นับรายละเอียดเป๊ะๆ ของการคำนวณ diff หรือการบีบอัดข้อมูล ก็สร้าง mental model ที่ถูกต้องได้ค่อนข้างง่าย ถ้าจำเป็นจริงๆ จะเปิดดูข้อความ WebSocket ก็ยังพอเข้าใจได้ว่าเกิดอะไรขึ้น
LiveView นั้นเข้าใจได้ตรงไปตรงมาจนน่าประหลาดใจ
เสน่ห์ใหญ่ของ Elixir/Erlang คือในบริบทเว็บเซิร์ฟเวอร์มันทำ งานเบื้องหลัง ได้ง่ายมาก และไม่ต้องกังวลว่า blocking I/O จะทำให้ทั้งเซิร์ฟเวอร์หยุดไป
ที่ทำงานเก่าผมเคยต้องยิง HTTP request จำนวนมากในตัวจัดการ webhook และถ้าเกิดพร้อมกันเยอะพอ โปรเซสของระบบปฏิบัติการจะยุ่งจนทั้งเว็บล่ม
ตอนนั้นคิดจริงๆ ว่าถ้าเป็น Elixir แค่ปล่อย Task ขึ้นมาหนึ่งตัวแล้วไปต่อก็คงจบ
แนวคิดเรื่องการแชร์ออบเจ็กต์ระหว่างโปรเซส async ของ Tokio รู้สึกยากกว่าเมื่อเทียบกับความสามารถระดับ first-class ของ Elixir ไม่ใช่ว่าทำไม่ได้หรือยากโดยเนื้อแท้ แต่ดูจะทำให้ถูกต้องได้ยากกว่า
ผมอยากให้งานเบื้องหลังอยู่บน กำลังประมวลผล ที่แยกจาก HTTP request เพราะรูปแบบการใช้ทรัพยากรต่างกัน และผมอยากมี state หรือ queue อยู่ข้างหน้าเพื่อให้เรื่อง retry, การจัดการข้อผิดพลาด และ backpressure ชัดเจน
แน่นอนว่าคงดีถ้าไม่มีความซับซ้อนพวกนี้และเฟรมเวิร์กเดียวจัดการทั้งหมดให้ได้ แต่ผมมองว่ายากที่ภาษาหรือ runtime เพียงอย่างเดียวจะพาไปถึงจุดนั้นได้ ต้องมีทั้ง monitoring และกระบวนการปฏิบัติการเป็นส่วนหนึ่งของคำตอบด้วย
งานบรรยาย The Soul of Erlang and Elixir ของ Sasa Juric แสดงให้เห็นได้ดีว่าภาษานี้ทรงพลังได้แค่ไหน
https://www.youtube.com/watch?v=JvBT4XBdoUE&t=4
ถ้าคุณเคยได้ยินคำว่า “ปล่อยให้มันล้มเหลว” หรือ “BEAM ทำ concurrency ได้ถูกต้อง” แต่ยังไม่ค่อยเห็นภาพ ขอแนะนำอย่างยิ่ง งานบรรยายนี้ยอดเยี่ยมจริงๆ
ตั้งแต่ปี 1991 ก็เขียนโปรแกรมด้วย Erlang ทุกวัน และเดิมก็ตั้งใจว่าจะทำแบบนั้นต่อไป
ระหว่างทางก็ได้ลอง Haskell, Rust, Elixir และตัวอื่น ๆ มาด้วย ประเภทข้อมูลที่เข้มงวดมีคุณค่ามาก แต่สุดท้ายก็ลงเอยที่ว่าเราสนุกกับอะไรที่สุด
Erlang คือภาษาการเขียนโปรแกรมที่ให้ความสนุกมากที่สุด และอย่างน้อยก็ตั้งใจจะยังแฮ็ก Erlang ต่อไปจนกว่าจะเกษียณในอีกไม่กี่ปีข้างหน้า
รู้จัก Elixir มาได้ปีกว่า ๆ แล้ว และการเรียนรู้พร้อมทั้งค่อย ๆ ใส่มันเข้าไปในองค์ประกอบต่าง ๆ ก็ค่อนข้างสนุกมาก
ความสนุกที่ใหญ่ที่สุดมาจากการที่มีหลายอย่างให้มาเป็นพื้นฐานอยู่แล้วด้วย BEAM/OTP เพียงอย่างเดียว
เคยมีคนในทีมที่ทำงานด้วยกันบอกว่า “BEAM/OTP ก็เหมือน k8s ที่ตัดส่วนซับซ้อนออกไป”
แม้จะเรียน Elixir มาหลายปี แต่ช่วงหลังข้อดีนี้ก็ถูกลดทอนไปบ้าง เพราะการย้ายระบบ OpenShift หรือก็คือ k8s ที่ฉันออกแบบเอง
ถ้าไม่มี k8s มันคงเป็นข้อเสนอที่น่าดึงดูดกว่านี้มาก แต่สุดท้ายก็เลือกคงสแตกพัฒนาเดิมไว้ และใช้แนวคิดของ k8s เพื่อทำสิ่งที่เดิมจะทำด้วย OTP แน่นอนว่า trade-off ก็ต่างกัน
“Elixir ให้ความสนุกแบบภาษาอย่าง Ruby แต่ตัดกับดักเรื่อง state ของภาษาสาย object-oriented ออกไป ไม่มีทั้งคลาส อินสแตนซ์ และการสืบทอด แถมยังเป็นแบบ immutable/functional และไม่ถูกผูกมัดด้วยระบบชนิดข้อมูลแบบ static”
ฉันก็อยากได้แบบนี้ แต่ก็อยากให้มี type ด้วย เชื่อมั่นว่ากับโค้ดเบสขนาดใหญ่ ประเภทข้อมูลที่เข้มงวดนั้นเหมาะสมกว่า เพราะช่วยเปิดเผยเวทมนตร์ที่ซ่อนอยู่หลายอย่างและทำให้ reasoning ได้ง่ายขึ้น
ด้วย pattern matching/unification ของฟังก์ชัน จึงพอจะรู้ได้ค่อนข้างดีว่าข้อมูลมีรูปทรงแบบไหนเมื่อไหลไปมา ถ้ายังกังวลก็ยังมี Dialyzer
Dialyzer คือเครื่องมือวิเคราะห์แบบ static สำหรับ Erlang/Elixir รวมอยู่ใน Erlang release มาตรฐาน และเป็นตัวย่อของ “DIscrepancy AnaLYZer for ERlang programs”
มันตรวจหาความไม่สอดคล้อง เช่น type error, dead code, และการทดสอบที่ไม่จำเป็น ใน Erlang module เดี่ยวหรือชุดของแอปพลิเคชัน โดยจะอนุมาน type จากโปรแกรมที่ถูกต้อง และแม้ type annotation จะไม่จำเป็น แต่ถ้ามีก็จะให้คำเตือนที่ดีขึ้น
https://fly.io/phoenix-files/adding-dialyzer-without-the-pai...
https://elixir-lang.org/blog/2023/06/22/type-system-updates-...
GenServer ใกล้เคียงกับอ็อบเจ็กต์ และไม่ได้เป็นแค่ struct ที่มีฟังก์ชันเกี่ยวข้องติดมาด้วย แต่โต้ตอบกันผ่านข้อความ
ถ้ามีเทมเพลตพื้นฐานสำหรับสิ่งอย่างการลงทะเบียนร่วมกัน การตั้งค่าหน่วยความจำ และ logging ใน GenServer ของโปรเจกต์ แล้วสามารถทำให้เฉพาะทางตามงานของสามรูปแบบย่อยได้ก็คงดี
Elixir อุดช่องว่างของปัญหานี้ด้วยการสร้างโค้ดผ่าน macro แต่ก็ไม่ได้ดีนัก GenServer ของฉันเต็มไปด้วยการทำซ้ำเล็ก ๆ น้อย ๆ
ฉันมองว่าคำพูดที่ว่า “ใน Ruby การใช้ exception กับ control flow เป็นเรื่องปกติ” นั้นผิดไปเลย
ตัวอย่างหลังย่อหน้านั้นคือเมธอด
updateของ Rails แต่ในตัวอย่าง Rails มาตรฐานและโค้ดที่ generator สร้างให้ มักใช้updateแบบที่ไม่โยน exceptionไลบรารีหรือแอปพลิเคชันที่มีขนาดสักระดับหนึ่ง เมื่อซับซ้อนมากพอ ก็มักเปลี่ยนไปใช้คลาสข้อผิดพลาดที่อธิบายได้ชัดเจน เพราะการจัดการข้อผิดพลาดแบบอิงสถานะอย่างใน ActiveRecord นั้นทรมาน
ตอนนี้ Ruby ก็มี pattern matching อยู่พอสมควรแล้ว เลยคิดว่าน่าจะใช้แทน exception สำหรับ control flow ได้ แทนที่จะ throw exception ก็คืนคลาสนั้นกลับมาแล้วค่อย match กับมัน
gem จำนวนมากใช้ exception กับ control flow และในแอปกับไลบรารีที่ฉันเขียนหรือดูแลรักษาก็พบได้บ่อย
ใน Rails มีเมธอด
bang!จำนวนมากที่โยน exception เมื่อเกิดข้อผิดพลาด แต่โดยทั่วไปแล้วใน Ruby การใช้ exception กับ control flow นั้นพบได้บ่อยจริง เหมือนกับใน Pythonมาจาก F# และเคยลองจับ Elixir แค่นิดหน่อย แต่ภาษานี้น่าเสียดายที่ค่อนข้างชวนสับสนเล็กน้อย
ตัวอย่างเช่น ซิกเนเจอร์ของฟังก์ชันแสดงแค่ชื่อกับจำนวนพารามิเตอร์ แต่ไม่ได้แสดงชนิดข้อมูล ทำให้ในไลบรารีขนาดใหญ่ค่อนข้างยากที่จะทำความเข้าใจในหัวว่าอะไรถูกส่งไปที่ไหน
ก็มักจะเพิ่งเห็นว่าใส่พารามิเตอร์ผิดหลังจากรันโค้ดและดีบักแล้วเท่านั้น ในภาษาที่มีระบบ type เข้มงวดอย่าง F# ปัญหาแบบนี้ถูกจับได้ระหว่างเขียนโค้ดทันที จึงช่วยประหยัดเวลาและแรงไปได้มาก
เพราะอย่างนั้น นอกจาก ecosystem ของ Erlang แล้วก็เลยสงสัยว่าเสน่ห์หลักของ Elixir คืออะไรกันแน่
https://elixir-lang.org/blog/2023/09/20/strong-arrows-gradua...
ตอนนี้มันยังเป็นภาษาแบบ dynamic อยู่จริง ดังนั้นจึงยังไม่ได้ข้อมูลด้าน type จากตัวภาษาเองมากนัก และยังไม่ใช่ภาษาที่มี static type
แต่สิ่งที่ทำให้ฉันยก Elixir เหนือกว่าภาษาอื่นที่เคยใช้จริง ๆ คือ BEAM/OTP
จากประสบการณ์ของฉัน ฟีเจอร์จำนวนมากที่ในภาษาอื่นต้องดึงมาเป็นไลบรารี กลับมีมาให้ในตัวอยู่แล้ว และไลบรารีเหล่านั้นก็มักเพิ่มความซับซ้อนอย่างมาก บางครั้งยังมี learning curve สูงด้วย ฟีเจอร์ด้าน async เป็นตัวอย่างที่ดี
พอใช้ Elixir ไปสักระยะและได้เรียนรู้เครื่องมือกับ abstraction ที่มีมาให้เหล่านี้ ก็จะเริ่มเข้าใจพลังของ ecosystem ทั้งหมด
เสน่ห์หลักน่าจะเป็นการที่มันรันบน BEAM พร้อมไวยากรณ์ที่ให้ความรู้สึกแบบ Ruby ซึ่งฉันมองว่า BEAM เป็นข้อได้เปรียบที่ใหญ่มาก
มันเทียบกับระบบ type ของ F# ได้ไม่ค่อยตรงนัก แต่ก็ใช้ typespec ได้: https://hexdocs.pm/elixir/1.15.7/typespecs.html
ตัวอย่างเช่น มีแนวทางที่ machine learning ถูกผสานรวมอย่างเป็นธรรมชาติร่วมกับ Axon, Nx, BumbleBee และยังคอมไพล์ลง GPU ได้ด้วย: https://www.youtube.com/watch?v=HK38-HIK6NA
ชุมชนก็ผลักดันด้านนี้อย่างจริงจัง
วิธีการทำงานของ LiveView ก็น่าสนใจเช่นกัน แม้ว่าใน .NET จะมี Blazor อยู่แล้ว
Elixir ใช้ได้ในบริบทที่หลากหลาย เช่น Nerves สำหรับ embedded หรือการทำ scripting เป็นต้น เท่าที่ทราบ F# ก็ใช้ทำ scripting ได้เหมือนกัน
โดยรวมแล้ว BEAM และโครงสร้างที่เกี่ยวข้องคือจุดแข็ง และ package manager อย่าง Hex ก็ดีมากจริง ๆ แน่นอนว่า .NET เองก็มีเครื่องมือที่ดี
จะประคองไปด้วย typespec, pattern matching และ guard ก็ได้ แต่ค่อนข้างจุกจิก และอย่างน้อยในปลั๊กอิน JetBrains ที่ชุมชนทำกันเอง มันก็ไม่ค่อยเป็นมิตรกับ IDE/IntelliSense
ไม่ใช่ตอนเริ่มต้น แต่ควรมาเขียนหลังจาก ใช้มาแล้ว 2 ปี มากกว่า
ของใหม่ตอนแรกมักจะดูเหมือนเป็นวิธีแก้ปัญหาครบจักรวาลที่แวววาวไร้ที่ติอยู่เสมอ
ความประทับใจแรกก็มีที่ทางของมัน และนั่นคือสิ่งที่ฉันกำลังนำเสนอ เพราะกลุ่มเป้าหมายไม่ใช่ผู้เชี่ยวชาญ Elixir/Erlang แต่เป็นผู้เชี่ยวชาญ Ruby
Elixir เป็นอัญมณีทั้งในตอนนั้นและตอนนี้ มันไม่สมบูรณ์แบบ แต่รับมือการใช้งานได้ดีอย่างน่าทึ่ง
ฉันใช้ Ruby มาตั้งแต่ราว ๆ ปี 2007
ทุกครั้งที่พยายามย้ายไปใช้สิ่ง “เจ๋ง ๆ” ตัวถัดไป สุดท้ายก็มักกลับมาที่ Ruby เพราะฉันชอบ Ruby ทำงานได้เร็วที่สุดด้วย Ruby และแค่นั้นก็พอแล้ว
แต่ช่วงนี้เห็นคนพูดถึง Elixir มากขึ้นมาก และฉันก็ชอบหน้าตาและความรู้สึกของมัน กำลังจะเริ่ม side project ใหม่เร็ว ๆ นี้ เลยคิดว่าน่าจะลองใช้ดูสักครั้ง