- Ruby อาจไม่ใช่ภาษาที่เร็วที่สุดหรือกำลังเป็นกระแสที่สุด แต่แม้จะผ่านการใช้งานมาหลายภาษาตลอดกว่า 15 ปี ก็ยังคงเป็นภาษาที่ถูกเลือกกลับมาใช้อีกครั้งเมื่ออยากทำงานอย่างมีความสุข
- refinements, Forwardable, SimpleDelegator,
Object#then,Kernel#tapและ numbered parameters มอบความสะดวกทางไวยากรณ์เล็กๆ พร้อมลำดับการอ่านที่เข้าใจง่าย Thread::Queue,json,csvใน standard library รวมถึง RuboCop และ Ruby LSP ช่วยให้คงสภาพแวดล้อมการพัฒนาที่ใช้งานได้จริงโดยไม่ต้องพึ่ง gem ย่อยมากมายหรือการตั้งค่าที่ซับซ้อน- YJIT ใน Ruby 3.x และ ZJIT ใน 4.x กำลังลดช่องว่างในงานที่ใช้ CPU หนักลง และในการเปรียบเทียบ Fibonacci แบบง่าย Ruby with ZJIT อยู่ห่างจาก Go เพียงราว 2–3 เท่า
- แม้ Rust·Go·Python จะเหมาะกว่าในบางด้าน แต่สำหรับเว็บแอป งานเบื้องหลัง และเครื่องมือภายใน จุดแข็งของ Ruby ก็ยังอยู่ที่ ความสุขของนักพัฒนา และความเร็วในการทำซ้ำ
เหตุผลทางภาษาที่ทำให้ Ruby ใช้งานแล้วรู้สึกสบาย
- Ruby อาจไม่ใช่ ภาษาที่เร็วที่สุดหรือเป็นกระแสที่สุด แต่แม้จะสลับไปมาระหว่างหลายภาษาตลอดกว่า 15 ปี ก็ยังเป็นภาษาที่ทำให้เลือกกลับมาใช้เมื่ออยากสนุกกับการทำงานจริงๆ
- refinements เปิดคลาสได้เฉพาะในขอบเขตจำกัด จึงเพิ่มความสะดวกทางไวยากรณ์เล็กๆ ภายในไฟล์หรือบล็อกได้โดยไม่ทำให้ namespace ทั้งหมดปนเปื้อน
- เหมาะกับ test helper หรือ internal DSL ในโค้ดเบสขนาดใหญ่
- สามารถใช้เมธอดอย่าง
"hello".quoteได้เฉพาะตำแหน่งที่เรียกusing QuotingRefinement
- Forwardable และ
SimpleDelegatorใน standard library ช่วยให้ทำ delegation ได้อย่างสะอาด โดยไม่ต้องเขียน wrapper method เองหรือดึง gem เพิ่มเข้ามา- ถ้าใช้ Rails อยู่แล้ว
delegateของ Active Support อาจสะดวกกว่า แต่เวอร์ชัน Ruby แกนหลักช่วยให้สคริปต์ทั่วไปยังคงเบา
- ถ้าใช้ Rails อยู่แล้ว
Object#thenและKernel#tapช่วยเชื่อมงานต่อกันเป็น chain ที่อ่านจากบนลงล่างได้ โดยไม่ต้องสร้างตัวแปรกลาง- สามารถเขียนลำดับการสร้าง บันทึก log ทำ normalization และบันทึกข้อมูลต่อเนื่องได้ เช่น
User.new(params).tap { ... }.then { ... }.save
- สามารถเขียนลำดับการสร้าง บันทึก log ทำ normalization และบันทึกข้อมูลต่อเนื่องได้ เช่น
- numbered parameters ตั้งแต่ Ruby 2.7 ช่วยลดความรกใน callback สั้นๆ
- ไม่จำเป็นต้องประกาศ block argument อย่างชัดเจน เช่น
items.map { _1.price * 1.1 }
- ไม่จำเป็นต้องประกาศ block argument อย่างชัดเจน เช่น
- fiber scheduler ทำให้เขียนโค้ด concurrency ที่หน้าตาเหมือนโค้ดแบบลำดับได้เมื่อเชื่อมกับ event loop
- ใช้รูปแบบ
Fiber.schedule do ... endเพื่อแสดงโค้ดที่ทำงานร่วมกับ fiber อื่น
- ใช้รูปแบบ
ภาพปัจจุบันของเครื่องมือ ประสิทธิภาพ และ ecosystem
- Ruby LSP ของ Shopify ให้การทำงานร่วมกับ editor ด้วยการตั้งค่าน้อยมาก และทำงานร่วมกับ Steep หรือ RBS สำหรับการเพิ่ม type แบบค่อยเป็นค่อยไปได้ดี
- RuboCop ช่วยรักษาความสม่ำเสมอของสไตล์ได้โดยไม่ต้องผ่านพิธีกรรมที่เป็นทางการเหมือนใน ecosystem อื่น
- standard library ยังคงเป็นจุดแข็งเงียบๆ ที่ช่วยให้ไม่ต้องเพิ่ม gem ย่อยจำนวนมากสำหรับงานทั่วไป
- ถ้าต้องการคิว สามารถใช้
Thread::Queueได้ - การ parse JSON หรือ CSV ก็มี
jsonและcsvที่รองรับกรณีใช้งานจริงส่วนใหญ่ได้โดยไม่ต้องมีขั้นตอนมาก
- ถ้าต้องการคิว สามารถใช้
- ต่อจาก YJIT ใน Ruby 3.x ตอนนี้ซีรีส์ 4.x กำลังนำ ZJIT เข้ามา
- ZJIT เป็น JIT ที่ทำงานเชิงรุกมากขึ้นบนฐานเดียวกัน และคอมไพล์เส้นทางการทำงานที่ร้อนจัดได้อย่างมีประสิทธิภาพกว่า
- จากตัวเลขเบื้องต้น ช่องว่างระหว่าง Ruby กับภาษาที่เคยทิ้งห่างมากในงานที่ใช้ CPU หนักลดลงอย่างมีนัยสำคัญ
- CRuby ZJIT กำลังพัฒนาอยู่ใน repository หลักของ Ruby
- ใน benchmark แบบง่ายที่เปรียบเทียบการทำ Fibonacci แบบ recursive บนเครื่องเดียวกัน Ruby with ZJIT อยู่ห่างจาก Go เพียงราว 2–3 เท่า และในกรณีนั้นก็ไม่ได้ห่างจาก Rust ที่ปรับแต่งมาอย่างดีมากนัก ขณะที่ Python with pypy ตามหลัง
- แม้ microbenchmark จะมีข้อจำกัด แต่ในเส้นทางโค้ดที่อุ่นแล้วและมีเวลาให้ JIT ปรับแต่ง แอปพลิเคชันจริงก็อาจได้ประโยชน์มากกว่า
- เมื่อเทียบกับ Rust แล้ว Ruby เด่นกว่าในเรื่อง ความเร็วในการวนซ้ำของ business logic
- ใน Rust อาจต้องใช้เวลาไปกับการต่อสู้กับ borrow checker แม้ในเรื่องที่ชัดเจนอยู่แล้วตอนรันจริง
- Go มีพื้นฐานด้าน concurrency ที่ยอดเยี่ยม แต่จนไม่นานมานี้ยังไม่มี generics และการจัดการข้อผิดพลาดที่ค่อนข้างแข็งทื่ออาจทำให้สคริปต์ง่ายๆ หนักเกินความจำเป็น
- Python เป็นญาติทางความคิดที่ใกล้ที่สุด แต่ต้องใช้ boilerplate มากกว่าในการแสดงแนวคิดระดับสูงแบบเดียวกัน โดยเฉพาะรอบๆ class และ decorator
- เมื่อใส่โค้ดลงในโมเดล ประสิทธิภาพต่อโทเค็น ก็เป็นข้อได้เปรียบจริงของ Ruby
- สามารถใช้
do/endหรือวงเล็บปีกกาเพื่อแทน block และแทบไม่ต้องใส่วงเล็บใน method call หากยังอ่านง่าย - hash และ keyword argument เป็นฟีเจอร์หลักที่กระชับ จึงใส่ logic จริงลงใน context window เดียวกันได้มากกว่าภาษาที่มีโครงสร้างรกกว่า
- สามารถใช้
- utility ด้าน metaprogramming ของ Ruby เหมาะกับการสร้าง API ที่เล็กและอ่านง่าย
- ฟีเจอร์อย่าง
define_method,class_evalและการดักจับ missing method ช่วยสร้าง API ที่แสดงพลังได้มากโดยไม่ต้องมีขั้นตอนสร้างโค้ด - ไลบรารีอย่าง
dry-rbหรือaasmใช้ความสามารถนี้อย่างพอดีเพื่อให้ได้ state machine และชั้น validation ที่สะอาด
- ฟีเจอร์อย่าง
- เครื่องมือของชุมชนและกระบวนการ deploy ก็สุกงอมขึ้นมากแล้ว
- byebug และ
pryให้ความรู้สึกยืดหยุ่นกว่าดีบักเกอร์หลายตัวที่เคยใช้ในที่อื่น - สำหรับงาน background job นั้น
solid_queueและgood_jobเรียบง่ายพอที่คนคนหนึ่งจะทำความเข้าใจการทำงานทั้งระบบได้ภายในบ่ายเดียว - Kamal เข้ามาแทนขั้นตอนแบบ capistrano รุ่นเก่าสำหรับหลายคน และให้ความรู้สึกเหมือนเป็นเครื่องมือที่สร้างโดยคนที่ดูแลทีมเล็กจริงๆ
- byebug และ
- ทั้งหมดนี้ไม่ได้หมายความว่า Ruby จะชนะ Rust หรือ Go ในทุกงาน และก็ยังมีหลายด้านที่ Rust หรือ Go เหมาะกว่า
- แต่ในพื้นที่ตรงกลางอันกว้างของเว็บแอป การประมวลผลงานเบื้องหลัง และเครื่องมือภายใน Ruby ยังคงมอบ ความสุขของนักพัฒนา ได้อย่างต่อเนื่องโดยไม่ต้องมีพิธีรีตองมากเกินไปหรือสลับบริบทบ่อย
- ความสะดวกเล็กๆ น้อยๆ และสัมผัสโดยรวมของภาษา ยังคงเป็นสิ่งที่ทำให้คนเอื้อมมือไปหา Ruby ก่อนแม้เวลาจะผ่านไปเกินสิบปี และงานด้าน JIT ใหม่ๆ รวมถึงการพัฒนาภาษาอย่างต่อเนื่องก็ยิ่งตอกย้ำเหตุผลนั้น
1 ความคิดเห็น
ความคิดเห็นจาก Lobste.rs
รู้สึกว่าเห็นด้วยกับคำว่า “no ceremony RuboCop” ได้ยาก
RuboCop มีขั้นตอนให้ถกกันพอสมควรว่าจะเลือกและปรับ cop ตัวไหนบ้าง และจะเปิด cop ใหม่ที่เพิ่มมาในอัปเดตล่าสุดหรือไม่
StandardRB ใกล้เคียงกับแนวทางที่ไร้พิธีรีตองกว่ามาก แต่สุดท้ายก็ยังต้องเลือกมันอยู่ดี
ภาษาที่มี lint ฝังมาในตัวนั้นยุ่งยากน้อยกว่า Ruby มาก และมีข้อถกเถียงเรื่องสไตล์เล็ก ๆ น้อย ๆ น้อยกว่าด้วย
ข้อจำกัดกลับให้เสรีภาพ
โดยทั่วไปผมค่อนข้างไม่ชอบการตั้งค่า linter และอยากปล่อยให้การตัดสินใจแบบนี้เป็นหน้าที่ของ ค่าเริ่มต้นจากชุมชน
ด้านหนึ่ง ผมคิดว่าค่าเริ่มต้นของ RuboCop ก็ดีพออยู่แล้ว จึงควรยึดตามและค่อย ๆ พัฒนาไปด้วยกัน มากกว่าจะไปแยกย่อยสไตล์การเขียนโค้ดเพิ่ม
แต่อีกด้านหนึ่ง บางครั้งมันก็มีความเห็นจัดเกินไป จนดูเหมือนว่าจำเป็นต้องมีอะไรอย่าง standard.rb
ผมเขียนจากมุมมองที่ว่า ถ้าใครจะเริ่มเรียน Ruby หรือกลับมาใช้ใหม่ เขาควรเขียนโค้ดได้อย่างราบรื่นโดยไม่ต้องไปรับมือกับ gem จำนวนมหาศาล
ตอนที่ Go ออกมา ผมคิดว่าการมีระบบจัดรูปแบบอย่างเป็นทางการเพียงหนึ่งเดียวนั้นเป็นสิ่งที่ทำได้ดีมาก
สมองเป็นเครื่องจักรจับแพตเทิร์น พอคุ้นแล้วมันก็จะมองข้ามไปเอง แต่ถ้ามีตัวเลือก เราจะรู้สึกไม่สบายใจ และทุกคนก็จะถูกดึงไปคนละทาง
ปัญหาคือทั้ง RuboCop และ Standard ต่างก็ไม่มีทางมีสถานะความชอบธรรมแบบนั้นใน Ruby ได้
ความชอบธรรมนั้นต้องมาจาก ทีม core แต่คงไม่เกิดขึ้นเพราะขัดกับปรัชญาของ Ruby
ในโปรเจกต์ของผม ผมปิด RuboCop cop ทั้งหมดแล้วเปิดใช้แค่บางตัว
single quote ดีที่สุด 😀
ดูเหมือนอีกบทความหนึ่งก็พูดถึงประเด็นนี้ไว้: https://caio.ca/blog/coding/my-complicated-relationship - “The Wild West of Code Formatting”
ประมาณว่า “มันไม่ใช่วิธีแก้แบบเรียบง่ายที่ฝังมาในตัว แต่เป็น cop ที่ตั้งค่าได้หลายร้อยตัว ซึ่งนำไปสู่การถกเถียงไม่รู้จบว่าจะเปิดกฎไหนบ้าง”
โดยรวมเห็นด้วย แต่ค่อนข้างเสียดายที่ยก refinements เป็นตัวอย่างแรก
ผมเข้าใจว่าทำไมถึงชอบมัน แต่ก็ใกล้เคียงกับสิ่งที่ไม่รู้วิธีทำไส้กรอกน่าจะดีกว่า
semantics ของมันซับซ้อนมาก จนแม้จะผ่านมากว่า 10 ปีหลังการเปิดตัว ก็ยังเจอบั๊กชวนปวดหัวใน MRI อยู่เรื่อย ๆ
อย่างเช่นในช่วง 2 สัปดาห์ล่าสุดก็มี https://bugs.ruby-lang.org/issues/22071 และ https://bugs.ruby-lang.org/issues/22058
ในแง่ประสิทธิภาพ มันก็ทำให้การทำ optimization หลายอย่างยากขึ้น และตอนนี้สิ่งคล้ายกันก็กำลังเกิดขึ้นอีกกับ boxes
แม้ในระดับ implementation เอง ก็น่าจะยังมีบั๊กซ่อนอยู่อีกมาก และฝั่งไลบรารีก็คงเช่นกัน
ตอนนี้ผมไม่ได้ใช้ Ruby มากแล้ว แต่ก็อยากรู้ว่ามันจะลงเอยอย่างไร
ดูน่าสนุกดี
บทความนี้ทับซ้อนกับประสบการณ์ของผมในบทความ “Returning to Rails” [1] มากเหมือนกัน
อาจเป็น confirmation bias ก็ได้ แต่ดูเหมือนจะมีคนมากขึ้นที่กลับมาค้นพบหรืออย่างน้อยก็ยอมรับความงามของโค้ด Rails อีกครั้ง
อย่างไรก็ตาม มันก็ทำให้นึกถึงปรากฏการณ์ที่รสนิยมทางดนตรีหรือศิลปะมักจะตกผลึกในช่วงปลายวัยรุ่นถึงวัย 20 ต้น ๆ
คนที่ได้รู้จัก Ruby ครั้งแรกใน “ยุคทอง” ของ Rails อาจกำลังมองย้อนกลับไปยังยุคของ Rails 3 และ Capistrano ผ่าน แว่นสีชมพู อยู่หรือเปล่า
ตอนนั้นผมจมลึกอยู่ในโลก Ruby “shop” และรอบตัวก็มีแต่คนพัฒนา Rails เลยรู้สึกเหมือน Ruby อยู่ทุกที่
แต่เมื่อเห็นความเห็นในเธรด lobste.rs [2] ว่า Ruby จริง ๆ แล้วเป็นภาษานิชมาตลอด ก็อาจเป็นอิทธิพลจากตรงนั้นด้วย
ถึงอย่างนั้น Ruby ก็ยังให้ความรู้สึกเหมือนบ้าน และดูเหมือนทำงานตรงกับวิธีคิดในหัวของผม
แทบไม่ต้องมีขั้นตอนแปลความ ไม่มีอะไรให้แปลกใจ และให้ความรู้สึกเหมือนคุยกับเพื่อนมากกว่ากำลังเขียนบทความเชิงวิชาการอย่างเป็นทางการ
ผมยังไม่เจอภาษาอื่นที่เข้ากับตัวเองได้ขนาดนี้ และไม่คิดว่ามันเป็นเพียงความคิดแบบ “เด็กสมัยนี้นี่นะ” เท่านั้น
ยังไงก็ตาม ผมดีใจที่มันยังอยู่รอดมาได้ยาวนานขนาดนี้
และขอบคุณที่แนะนำ chain แบบ “tap / new”
โครงสร้างนั้นสวยและมีประโยชน์มากจนผมต้องหยุดดูอยู่พักหนึ่ง และน่าจะได้ลองใช้แน่ ๆ
PS - แม้จะไม่เกี่ยวกับหัวข้อโดยตรง แต่ AI avatar บนหน้าโฮมเพจน่าขนลุกนิดหน่อย
มันให้ความรู้สึก uncanny valley แบบแรง ๆ ว่า “บทความนี้บอตเป็นคนเขียนหรือเปล่า?”
ทุกครั้งที่เห็นอะไรแบบนั้น ผมจะเผลอสงสัยอยู่ชั่วครู่ว่ากำลังคุยกับมนุษย์จริงหรือเปล่า
[1]=https://www.markround.com/blog/2026/03/05/returning-to-rails-in-2026/
[2]=https://lobste.rs/s/jreqtw/returning_rails_2026
แค่ไม่อยากเปิดเผยรูปจริงของตัวเอง และ avatar นั้นก็คล้ายพอที่คนที่รู้จักผมจริงจะจำได้
Ruby 3.4 เพิ่ม พารามิเตอร์บล็อก
itเข้ามา และสามารถใช้แทน_1ในตัวอย่างได้https://rubyreferences.github.io/rubychanges/3.4.html/…
itไปมันเป็นฟีเจอร์ที่ค่อนข้างใหม่ เลยยังไม่ชินมือที่จะพิมพ์
itใน iterator เอาเสียเลยผมชอบการเขียนโค้ดด้วย Ruby มากจริง ๆ แต่ ภาระเรื่องการทดสอบ มันหนักเกินไปแล้ว
ผมคิดว่าการเพิ่ม type safety ให้ภาษาอีกสักหน่อยน่าจะช่วยได้ แต่ใน
#{last_job}พอเราใส่ Sorbet ลงในโค้ดเบส แรงส่งและความสนุกในการเขียนโค้ดก็หายไปหมดอาจเป็นความเห็นที่ไม่เป็นที่นิยม แต่ผมมองว่าการที่มีสิ่งอย่าง Sorbet อยู่ได้ตั้งแต่แรกนั้น เป็นเหมือนกลิ่นไม่ดีของ Ruby มากกว่า
ตัว Ruby เองเป็นภาษาที่ทรงพลังและสนุก แต่คนเริ่มเอามันไปใช้กับงานที่เดิมทีไม่ได้ออกแบบมาเพื่อรองรับ และในกระบวนการนั้นก็เริ่มเสริมเครื่องมือต่าง ๆ เพื่อกลบ anti-feature ของภาษา
ตอนนี้ทุกบรรทัดให้ความรู้สึกเหมือนงานน่าเบื่อชวนทรมาน และผมใช้เวลารอเครื่องมือ build, test, lint ต่าง ๆ มากกว่าที่ได้เขียนโค้ดจริงเสียอีก
พอรวมกับกระบวนการ build และ deploy ที่ออกแบบเกินความจำเป็นเข้าไปอีก แม้แต่งานพื้นฐานก็ใช้เวลานานและทำงานอย่างทุกข์ทรมาน
ผมคิดถึงโลกของ Ruby ราวปี 2012 มาก
มองย้อนกลับไป มันเป็นช่วงเวลาที่ดีจริง ๆ
ผมเข้าใจว่าสิ่งที่เรียกว่า “งานที่เดิมทีไม่ได้ออกแบบมาเพื่อรองรับ” หมายถึงแอปพลิเคชัน Rails ขนาดใหญ่
ผมกลับมาใช้ Ruby อีกครั้งหลังผ่านไป 10 ปี และในยุค “AI” การที่เราสามารถเข้าใจโค้ดที่ไหลผ่านตาไปอย่างรวดเร็วได้จริง และควบคุมหรือหยุด LLM ได้ ก็เป็นข้อดีมาก
ในภาษาที่เยิ่นเย้อกว่านี้ มันทำได้ยากกว่า
ผมคิดถึง Ruby และยิ่งไปกว่านั้น ผมคิดถึงการมีอยู่ของภาษาลักษณะนั้นในงานโปรดักชันประจำวันด้วย
มันคือความหวัง หรือไม่ก็ เป็นตัวความหวังเอง
อย่างน้อยสำหรับผม มันเป็นแบบนั้นมาอยู่นาน
อ่านแล้วเหมือนบทความที่ AI ปั่นแบบลวก ๆ
บล็อกโพสต์อื่น ๆ ช่วงหลังก็คล้ายกัน
มีเบาะแสอะไรที่ทำให้คุณคิดแบบนั้น?
การชี้ว่ามีบทความ AI คุณภาพต่ำในเว็บนี้เป็นเรื่องที่ดี แต่ก็ควรหลีกเลี่ยง false positive และบอกให้ชัดด้วยว่าคิดอย่างนั้นเพราะอะไร
ทำไมคุณถึงคิดอย่างนั้น?
ผมชอบการเตือนแบบนี้นะ แต่จะชอบมากกว่าถ้ามีเหตุผลแนบมาด้วย
ผมมีความทรงจำที่ดีจากการทำงานกับ Ruby ในช่วงต้นอาชีพ
Ruby มีบางอย่างที่ให้ความรู้สึกดีจริง ๆ
แต่ตอนที่ผมน่าจะได้ใช้ Ruby ล่าสุดเล็กน้อยเมื่อปีที่แล้ว ผมรู้สึกว่าเอกสาร standard library แบบเว็บนั้นค้นดูยาก
หรือมีแค่ผมคนเดียว? มีทางเลือกอื่นแทนเอกสารบน ruby-lang.org ไหม?
[1] https://rubyapi.org
[2] https://devdocs.io/ruby/
บทความนี้ให้ความรู้สึกแปลก ๆ นิดหน่อย
ผมเคยมีโอกาสเขียนโปรเจกต์หนึ่งกับ SDK อีกตัวหนึ่งด้วย Ruby และมันทำให้ผมไม่อยากใช้ Ruby อีกเลย