A

ภาคผนวก A: วงจรชีวิตโปรเจกต์ Ruby

th/appendix_a_project_lifecycle

merged appendix page

วงจรชีวิตของโปรเจกต์ Ruby และเครื่องมือแกนกลาง

ทำไมภาคผนวกนี้จึงมีอยู่

ผู้เรียนอาจเข้าใจไวยากรณ์ของ Ruby แล้ว แต่ยังรู้สึกหลงเมื่อต้องทำงานกับโปรเจกต์จริง สิ่งที่ขาดอยู่มักไม่ใช่ "ฟีเจอร์ของภาษาเพิ่มอีกนิด" แต่มันคือกระบวนการรอบ ๆ ภาษา:

  • คำสั่งไหนควรรันก่อน
  • จะรู้ได้อย่างไรว่าเรากำลังใช้ Ruby เวอร์ชันไหน
  • จะติดตั้ง dependencies อย่างปลอดภัยได้อย่างไร
  • ทำไมบางโปรเจกต์ถึงใช้ bundle exec แทบทุกครั้ง
  • จะเปิดดู documentation โดยไม่ต้องออกไปเปิด browser ได้อย่างไร
  • เมื่อไรควรเริ่มสนใจ document generators, linters, task runners และ debuggers

ภาคผนวกนี้จึงสอนเครื่องมือของ Ruby ผ่านเรื่องเล่าของวงจรชีวิตโปรเจกต์จริง ตั้งแต่ "ผมมี แค่โฟลเดอร์ว่าง" ไปจนถึง "ตอนนี้ผมกำลังทำงานซ้ำเป็น sprint บน codebase ที่ดูแลได้"

สิ่งที่ผมอยากให้คุณทำได้เมื่อจบภาคผนวกนี้

เมื่อจบภาคผนวกนี้ คุณควรจะ:

  • อธิบายบทบาทของ ruby, gem, bundle, ri และ rbenv ได้
  • เริ่มต้นโปรเจกต์ Ruby แบบที่ทำซ้ำได้
  • เข้าใจว่าเมื่อไรควรใช้ gem install และเมื่อไรควรใช้ bundle add
  • รันโค้ด Ruby จาก command line และเช็กไวยากรณ์ได้เร็ว
  • ใช้ ri เปิดดู API แบบ local ระหว่างพัฒนาได้
  • เข้าใจว่า rake, rubocop, rdoc, yard และ rdbg เข้ามามีบทบาทตรงไหนในชีวิตของโปรเจกต์
  • แก้ปัญหาสภาพแวดล้อมที่พบบ่อยได้ โดยไม่เดาสุ่ม

แนวคิดการสอนของภาคผนวกนี้

ภาคผนวกนี้ ไม่ได้ สอนเครื่องมือแบบเรียงตามตัวอักษร

ผมสอนมันตามลำดับที่นักพัฒนามักต้องใช้จริง:

  1. เลือก Ruby version
  2. ยืนยันว่า interpreter ใช้งานได้
  3. สร้างโปรเจกต์
  4. เพิ่ม dependencies
  5. เริ่มวงจร test
  6. เปิด docs ระหว่างเขียนโค้ด
  7. ทำงานที่ซ้ำบ่อยให้เป็นงานอัตโนมัติ
  8. รักษา style และ docs ให้สม่ำเสมอ
  9. debug พฤติกรรมตอน runtime
  10. แก้ปัญหา environment drift

ลำดับนี้สำคัญ เพราะเมื่อผู้เรียนรู้จักเครื่องมือตามลำดับของโปรเจกต์ จุดประสงค์ของแต่ละ ตัวจะชัดเอง

ไฟล์ที่อยู่ในภาคผนวกนี้

  • story.md: เรื่องเล่าแบบละเอียดของวงจรชีวิตโปรเจกต์
  • cheatsheet.md: ชุดคำสั่งตามลำดับที่มักใช้จริง
  • sprint_flow.md: เครื่องมือเหล่านี้เข้ากับงานประจำวันแบบ sprint อย่างไร
  • troubleshooting.md: ปัญหาที่พบบ่อยและลำดับการวินิจฉัย
  • addons.md: เครื่องมือที่มีประโยชน์ในระยะต่อมา หลังจากพื้นฐานเริ่มนิ่งแล้ว

ภาคผนวกนี้ไม่ใช่อะไร

มันไม่ใช่:

  • คู่มือ RubyGems แบบเต็ม
  • คู่มือ Bundler ครบทุกคำสั่ง
  • บทเรียน shell
  • ตัวแทนของเอกสารทางการ

มันคือคู่มือเอาตัวรอดแบบใช้งานจริง สำหรับผู้เรียนที่กำลังขยับจาก "ผมเขียน Ruby ได้" ไปสู่ "ผมทำงานในโปรเจกต์ Ruby ได้อย่างรับผิดชอบ"

เรื่องเล่าวงจรชีวิตของโปรเจกต์ Ruby

Stage 0: ก่อนที่โปรเจกต์จะมีอยู่จริง

ก่อนที่โปรเจกต์ Ruby จะมีโค้ด มันก็มี dependency ที่มองไม่เห็นอยู่แล้วหนึ่งตัว นั่นคือ Ruby interpreter เอง

ถ้า Ruby version ที่เปิดใช้อยู่ผิด ทุกขั้นตอนหลังจากนั้นจะเริ่มไม่เสถียร:

  • gems อาจถูกติดตั้งไปผิดที่
  • native extensions อาจ build ไม่ผ่าน
  • scripts อาจมีพฤติกรรมไม่เหมือนกัน
  • เครื่องของคุณอาจไม่ตรงกับ environment ที่โปรเจกต์ตั้งใจไว้

เพราะอย่างนี้ วงจรชีวิตของโปรเจกต์จึงต้องเริ่มที่ runtime ไม่ใช่เริ่มที่ source files

เครื่องมือที่เริ่มแนะนำตรงนี้

  • ruby
  • which
  • rbenv

คำสั่ง

ruby -v
which ruby
rbenv versions
rbenv local 3.4.8
rbenv which ruby
story.md
bash

แต่ละคำสั่งกำลังบอกอะไร

ruby -v

  • บอก Ruby version ที่กำลังใช้งานอยู่
  • ใช้เช็กทุกครั้งเมื่อโปรเจกต์คาดหวัง version เฉพาะ

which ruby

  • บอกว่า shell ของคุณจะรัน executable ตัวไหนจริง
  • สำคัญมากเมื่อมี version manager เข้ามาเกี่ยวข้อง

rbenv versions

  • แสดง versions ที่ติดตั้งไว้ และชี้ว่าอันไหนกำลัง active

rbenv local 3.4.8

  • เขียน version ที่โปรเจกต์นี้จะใช้ไว้ในระดับ local
  • ความหมายคือ "เมื่อผมอยู่ในไดเรกทอรีนี้ ให้ใช้ Ruby 3.4.8"

rbenv which ruby

  • บอก path ของ Ruby binary ที่ rbenv resolve ออกมาจริง

สถานการณ์จริง

คุณ clone โปรเจกต์ Ruby มา แล้ว bundle install fail ด้วย error แปลก ๆ จาก native extension บ่อยครั้งตัวต้นเหตุไม่ได้อยู่ที่ gem เลย แต่เกิดจาก shell ของคุณกำลังใช้ Ruby ผิดเวอร์ชัน

เพราะฉะนั้นคำถามแรกเวลา debug ไม่ควรเป็น:

  • "ทำไม Bundler พัง"

แต่ควรเป็น:

  • "ตอนนี้ผมกำลังใช้ Ruby ตัวไหนกันแน่"

นี่คือเหตุผลที่เรื่อง version management ต้องมาก่อน

Stage 1: ลอง Ruby ก่อนสร้างโปรเจกต์

ก่อนจะสร้าง project skeleton ให้ยืนยันก่อนว่า interpreter กับวิธีทำงานผ่าน shell ใช้งาน ได้จริง วิธีนี้ช่วยแยกปัญหาของ environment ออกจากปัญหาของโปรเจกต์

เครื่องมือที่เริ่มแนะนำตรงนี้

  • ruby
  • irb

คำสั่ง

ruby -e 'puts "hello from ruby"'
ruby -e 'puts [1, 2, 3].map { |n| n * 2 }.inspect'
irb
story.md
bash

ทำไมช่วงนี้จึงสำคัญ

ruby -e เป็น smoke test ที่เร็วมาก:

  • interpreter ทำงานได้
  • การ quote ใน shell ทำงานได้
  • คุณลองประเมิน expression สั้น ๆ ได้ทันที

irb คือ scratchpad ของ Ruby แบบสด ๆ:

  • ลอง expression
  • ดูว่า method ทำงานอย่างไร
  • ทดลองก่อนกลับไปแก้ไฟล์จริง

สถานการณ์จริง

คุณไม่แน่ใจว่า String#gsub หรือ Array#zip ทำงานแบบที่จำได้หรือเปล่า แทนที่จะเดา หรือแก้โค้ดจริงแบบสุ่ม ๆ คุณใช้ irb เช็กได้ทันที

ตัวอย่าง:

irb
irb(main):001> %w[Ana Bob].zip([88, 76])
=> [["Ana", 88], ["Bob", 76]]
story.md
ruby

นี่คือวิธีทำงานที่ใช้กันจริงทุกวัน ไม่ใช่แค่ทริกสำหรับผู้เริ่มต้น

Stage 2: สร้างโปรเจกต์

ตอนนี้ Ruby เองทำงานแล้ว ขั้นต่อไปคือสร้างไดเรกทอรีของโปรเจกต์ และเริ่ม dependency management ให้ถูกตั้งแต่วันแรก

เครื่องมือที่เริ่มแนะนำตรงนี้

  • bundle

คำสั่ง

mkdir my_ruby_project
cd my_ruby_project
bundle init
story.md
bash

สิ่งที่เกิดขึ้นตรงนี้

bundle init

  • สร้าง Gemfile
  • ทำเครื่องหมายว่าโปรเจกต์นี้จะจัดการ dependencies แบบเป็นระบบ

นี่คือนิสัยที่สำคัญมากในงาน Ruby:

  • อย่าเริ่มด้วยการติดตั้ง gems แบบ global ไปเรื่อย ๆ แล้วค่อยหวังว่าโปรเจกต์จะใช้ได้ทีหลัง
  • ให้เริ่มจากการประกาศ dependencies ของโปรเจกต์ก่อน

สถานการณ์จริง

ถ้าคุณข้าม Bundler ไปแล้วรันแค่ gem install rspec เครื่องของคุณอาจใช้ได้ แต่เครื่องของ เพื่อนร่วมทีมอาจใช้ไม่ได้ Bundler คือสิ่งที่เปลี่ยนจาก "เครื่องของผม" ให้กลายเป็น "environment ของโปรเจกต์"

Stage 3: รันไฟล์และเช็กไวยากรณ์

เมื่อโปรเจกต์เริ่มมีอยู่แล้ว คุณต้องมีคำสั่งพื้นฐานสักชุดหนึ่งสำหรับการรันไฟล์ตรง ๆ และ รับ feedback แบบเร็ว

คำสั่ง

ruby app.rb
ruby -c app.rb
ruby -Ilib script.rb
story.md
bash

ทำไมคำสั่งพวกนี้จึงสำคัญ

ruby app.rb

  • ใช้รันไฟล์ Ruby ตรง ๆ

ruby -c app.rb

  • ใช้เช็กไวยากรณ์โดยไม่รันโปรแกรม
  • มีประโยชน์มากเวลาต้อง debug ปัญหาไวยากรณ์แบบเร็ว ๆ

ruby -Ilib script.rb

  • ใช้เพิ่มไดเรกทอรีเข้า load path
  • เหมาะกับ scripts เล็ก ๆ ที่อยากให้ require หาไฟล์ในโปรเจกต์เจอ

สถานการณ์จริง

ผู้เรียนแก้หลาย method แล้วเจอ error ทางไวยากรณ์ ตอนนี้เขาไม่จำเป็นต้องรอทั้ง test suite เพื่อ รู้ว่าโค้ดมีปัญหาที่ไวยากรณ์หรือไม่ ruby -c ให้คำตอบที่เร็วกว่า ก่อนจะไปทดสอบเชิงลึก

Stage 4: เพิ่ม dependencies แบบที่โปรเจกต์ต้องการ

ตอนนี้โปรเจกต์เริ่มต้องใช้ libraries

เครื่องมือที่เริ่มแนะนำตรงนี้

  • gem
  • bundle

แก่นของเรื่อง

มีเรื่องที่ต้องแยกให้ออกอยู่สองชั้น:

  1. ระบบ gems ระดับเครื่อง
  2. ชุด dependencies ที่โปรเจกต์ประกาศไว้

ผู้เรียนต้องเข้าใจว่ามันไม่ใช่เรื่องเดียวกัน

คำสั่งระดับเครื่อง

gem -v
gem list
gem env
gem which rake
story.md
bash

คำสั่งเหล่านี้ช่วยให้คุณมองเห็นสภาพแวดล้อมของ RubyGems บนเครื่อง

คำสั่งระดับโปรเจกต์

bundle add rspec
bundle install
bundle info rspec
story.md
bash

ความหมายของคำสั่งเหล่านี้

bundle add rspec

  • เพิ่ม gem ลงใน Gemfile ของโปรเจกต์
  • ดีกว่าการติดตั้งแบบ global แบบสุ่ม ๆ เมื่อมันเป็น dependency ของโปรเจกต์

bundle install

  • resolve และติดตั้ง dependencies สำหรับโปรเจกต์ปัจจุบัน

bundle info rspec

  • บอกว่า Bundler resolve gem นี้มาจากไหน

สถานการณ์จริง

สมมติว่า csv ใช้ได้ในเครื่องหนึ่ง แต่ใช้ไม่ได้ในอีกเครื่องหนึ่ง ผู้เรียนอาจคิดว่า:

  • "Ruby มันไม่สม่ำเสมอ"

แต่คำถามที่ถูกกว่าคือ:

  • "csv ถูกประกาศไว้ในโปรเจกต์หรือยัง หรือมันมีอยู่แค่ในเครื่องบางเครื่อง"

นี่แหละคือความสับสนที่ Bundler ถูกสร้างขึ้นมาเพื่อกันไว้

Stage 5: เริ่มวงจร test ครั้งแรก

ตรงนี้คือจุดที่โปรเจกต์กลายเป็นงานพัฒนาจริง

คำสั่ง

bundle exec rspec
bundle exec rspec spec/my_spec.rb
bundle exec rspec spec/my_spec.rb:12
story.md
bash

ทำไม bundle exec จึงสำคัญ

bundle exec

  • บังคับให้คำสั่งนี้รันในบริบทของ dependencies ของโปรเจกต์
  • ช่วยไม่ให้เผลอไปใช้ gem version จากข้างนอกโปรเจกต์

ผู้เรียนมักรู้สึกต้าน bundle exec ในช่วงแรก เพราะมันดูพิมพ์ยาวและซ้ำ แต่ผมคิดว่าควร สอนตั้งแต่ต้น เพราะมันแก้ปัญหาจริงของโปรเจกต์

สถานการณ์จริง

คุณมี RSpec หลายเวอร์ชันอยู่ในหลายโปรเจกต์ ถ้ารัน rspec ตรง ๆ อาจได้ executable ผิดตัว แต่ถ้ารัน bundle exec rspec คุณจะได้ dependency resolution ตามที่โปรเจกต์ ประกาศไว้

นี่ไม่ใช่เรื่องรสนิยม แต่มันคือความถูกต้องของ environment

Stage 6: ใช้ documentation ระหว่างเขียนโค้ด

เมื่อเริ่มทำงานเป็น sprint ผู้เรียนต้องมีวิธีเปิดดู Ruby APIs ให้เร็ว

เครื่องมือที่เริ่มแนะนำตรงนี้

  • ri

คำสั่ง

ri Array#map
ri Enumerable#reduce
ri String#gsub
ri File
story.md
bash

ทำไม ri จึงสำคัญ

ri คือ local documentation reader สำหรับ Ruby APIs

มันมีประโยชน์เพราะ:

  • เร็ว
  • ไม่ต้องเปิด browser
  • ช่วยฝึกนิสัยการเปิดดูพฤติกรรมของ method อย่างแม่นยำ

สถานการณ์จริง

ผู้เรียนรู้ว่า map มีอยู่ แต่ลืมว่า reduce ต้องมี initial value หรือไม่ หรือ String#gsub คืนค่าอะไร ri ให้คำตอบได้ระหว่างที่กำลังลงมือเขียนอยู่ ซึ่งนี่คือวิธีใช้ docs ของนักพัฒนาจริง

Stage 7: เปลี่ยนคำสั่งที่ทำซ้ำให้เป็นงานของโปรเจกต์

เมื่อโปรเจกต์เริ่มมีวิธีทำงานที่ทำซ้ำ คำสั่ง shell ดิบ ๆ อย่างเดียวจะเริ่มไม่พอ

เครื่องมือที่เริ่มแนะนำตรงนี้

  • rake

คำสั่ง

bundle exec rake -T
bundle exec rake
story.md
bash

ทำไม rake จึงสำคัญ

rake คือ task runner แบบดั้งเดิมของ Ruby

มันเหมาะเมื่อโปรเจกต์มีงานที่ต้องทำซ้ำ เช่น:

  • รัน test suites
  • สร้าง docs
  • ล้าง build artifacts
  • seed ข้อมูลในเครื่อง
  • รันงานเฉพาะของโปรเจกต์

สถานการณ์จริง

ถ้าทีมต้องบอกกันอยู่บ่อย ๆ ว่า:

  • "รันสี่คำสั่งนี้ตามลำดับนี้นะ"

นั่นมักเป็นสัญญาณว่าโปรเจกต์กำลังอยากได้ task runner

Stage 8: รักษา style ให้สม่ำเสมอ

เมื่อ codebase โตขึ้น ความอ่านง่ายและความสม่ำเสมอควรถูกช่วยด้วย automation

เครื่องมือที่เริ่มแนะนำตรงนี้

  • rubocop

คำสั่ง

bundle exec rubocop
bundle exec rubocop -A
story.md
bash

ทำไม rubocop จึงสำคัญ

rubocop ช่วยทีม:

  • ทำให้ style สม่ำเสมอ
  • จับ smell ง่าย ๆ บางอย่างได้
  • ลดเสียงรบกวนใน code review ที่เป็นเรื่อง formatting

มันไม่ได้มาแทน design review แต่มีประโยชน์เพราะมันช่วยทำ feedback ที่ซ้ำ ๆ ให้เป็น อัตโนมัติ

สถานการณ์จริง

ถ้าไม่มี formatter/linter code review มักเต็มไปด้วย:

  • การจัด spacing
  • การเถียงกันเรื่อง quote style
  • การเถียงกันเรื่อง layout

ซึ่งทำให้พลังของมนุษย์ถูกใช้ไปกับเรื่องที่เครื่องควรจัดการได้

Stage 9: ทำเอกสารให้มนุษย์อ่าน

เมื่อโค้ดเริ่มถูกใช้ร่วมกัน คนอื่นต้องการมากกว่า test ที่ผ่าน พวกเขาต้องการ API docs ที่อ่านออก

เครื่องมือที่เริ่มแนะนำตรงนี้

  • rdoc
  • yard

คำสั่ง

rdoc
yard doc
yard server --reload
yard stats --list-undoc
story.md
bash

ความต่างระหว่าง ri, rdoc และ yard

ri

  • ใช้อ่านเอกสาร Ruby แบบ local

rdoc

  • สร้าง documentation จาก comments ใน source code ของ Ruby

yard

  • เป็นเครื่องมือ documentation ของ Ruby ที่ใช้กันแพร่หลาย และรองรับวิธีทำงานด้านเอกสารของโปรเจกต์ได้ดีกว่า

ทำไมช่วงนี้จึงมาทีหลัง

ผู้เรียนควรเข้าใจก่อนว่า:

  • จะเขียนโค้ดอย่างไร
  • จะรัน tests อย่างไร
  • จะใช้ docs อย่างไร

เมื่อสามอย่างนี้เริ่มนิ่งแล้ว จึงค่อยสมเหตุสมผลที่จะให้ผู้เรียนสร้าง docs สำหรับคนอื่น

สถานการณ์จริง

service object ตัวหนึ่งเริ่มถูกใช้ร่วมกันหลาย scripts tests ที่ผ่านช่วยยืนยันว่ามันทำงาน ได้ก็จริง แต่ไม่ได้อธิบาย:

  • input ที่คาดหวังมีรูปแบบอย่างไร
  • โครงของค่าที่คืนกลับมาเป็นอย่างไร
  • มี side effects อะไรหรือไม่

นี่คือจุดที่เครื่องมือด้าน documentation เริ่มมีความหมายจริง

Stage 10: debug การทำงาน ไม่ใช่ดูแค่ source code

เมื่อโปรเจกต์โตขึ้น การ puts อย่างเดียวเริ่มไม่พอ

เครื่องมือที่เริ่มแนะนำตรงนี้

  • rdbg

คำสั่ง

rdbg app.rb
rdbg -c -- bundle exec rspec
story.md
bash

ทำไม rdbg จึงสำคัญ

debugger ช่วยเมื่อ:

  • recursion มีพฤติกรรมแปลก
  • state ในฐานข้อมูลไม่ตรงกับที่คิด
  • closure จับค่าผิด
  • test ส่งข้อมูลผ่านหลายชั้นเกินกว่าจะดูด้วย puts ได้ง่าย

สถานการณ์จริง

recursive traversal ตัวหนึ่งทำ path ซ้ำเฉพาะ edge case แบบหนึ่ง ถ้าคุณใส่ print statements ไว้เต็มไปหมด โค้ดจะเริ่มรก debugger ช่วยให้คุณเปิดดู call stack กับค่าปัจจุบัน ได้อย่างแม่นยำกว่า

Stage 11: เครื่องมือเสริมของโปรเจกต์ที่เริ่มโตแล้ว

เมื่อวงจรหลักของโปรเจกต์เริ่มนิ่ง ผู้เรียนอาจเจอเครื่องมือเสริมอย่าง:

  • simplecov
  • bundler-audit
  • ruby-lsp
  • solargraph

ทั้งหมดนี้สำคัญ แต่ยังไม่ใช่เครื่องมือชุดแรกที่ผู้เรียนควรรู้

มันควรเข้ามาหลังจากที่ผู้เรียนเข้าใจวงจรหลักของโปรเจกต์แล้ว

Sprint Flow: เครื่องมือเหล่านี้เข้ากับงานประจำวันอย่างไร

วงจรที่เกิดซ้ำ

เมื่อโปรเจกต์ Ruby เริ่มมีชีวิต วงจรประจำวันมักหน้าตาแบบนี้:

  1. เช็ก environment
  2. ติดตั้งหรือ sync dependencies ถ้าจำเป็น
  3. รัน test หนึ่งตัวหรือ spec file หนึ่งไฟล์
  4. แก้โค้ด
  5. รัน tests ซ้ำ
  6. เปิดดูพฤติกรรมของ Ruby ถ้ายังไม่แน่ใจ
  7. lint หรือจัด style ก่อนถือว่างานจบ

วงจรนี้คือจุดที่เครื่องมือเลิกเป็น "คำสั่งที่ต้องท่อง" แล้วกลายเป็นส่วนหนึ่งของการทำงาน จริง

ตัวอย่าง sprint ที่สมจริง

ลองนึกว่าคุณกำลังทำแบบฝึกหัดในหัวข้อหนึ่ง หรือกำลังเพิ่มฟีเจอร์ใหม่ในโปรเจกต์

Step 1: ยืนยัน runtime

ruby -v
which ruby
sprint_flow.md
bash

เหตุผล:

  • ป้องกันการทำงานอยู่ยี่สิบนาทีก่อนจะรู้ว่าคุณใช้ Ruby คนละเวอร์ชัน

Step 2: sync dependencies

bundle install
sprint_flow.md
bash

เหตุผล:

  • ทำให้ dependencies ในโปรเจกต์ตรงกับ Gemfile และ lockfile

Step 3: รันเฉพาะ tests ที่เกี่ยวข้อง

bundle exec rspec spec/my_spec.rb
sprint_flow.md
bash

เหตุผล:

  • ได้ feedback เร็วกว่า
  • โฟกัสกับปัญหาทีละก้อนได้ง่ายกว่า

Step 4: เปิด docs ระหว่างลงมือเขียน

ri Enumerable#filter_map
sprint_flow.md
bash

เหตุผล:

  • ช่วยตอบคำถามเฉพาะจุด โดยไม่ต้องหลุดออกจาก flow

Step 5: เช็กไวยากรณ์ให้ไวเมื่อจำเป็น

ruby -c lib/my_class.rb
sprint_flow.md
bash

เหตุผล:

  • มีประโยชน์เมื่อความล้มเหลวดูเหมือนเป็นเรื่องไวยากรณ์ มากกว่าจะเป็นเรื่อง logic

Step 6: รัน linter ก่อนถือว่างานเสร็จ

bundle exec rubocop
sprint_flow.md
bash

เหตุผล:

  • ช่วยลด review comments ที่เลี่ยงได้

เมื่อไร rake เข้ามาอยู่ใน sprint loop

ถ้าโปรเจกต์เริ่มมีวิธีทำงานที่ต้องทำซ้ำ ทีมมักเลิกเขียนคำสั่งดิบ ๆ ไว้ใน README แล้วเริ่ม ทำให้มันเป็น tasks อย่างเป็นทางการ

ตัวอย่าง:

  • bundle exec rake test
  • bundle exec rake docs
  • bundle exec rake setup

นี่เป็นสัญญาณว่าโปรเจกต์เริ่มโตขึ้นในเชิงการปฏิบัติการ

เมื่อไร rdbg เข้ามาอยู่ใน sprint loop

ใช้ debugger เมื่อ:

  • state ที่ fail อยู่ลึกใน recursion
  • คุณต้องดูค่าระหว่างทาง
  • การ debug ด้วย puts เริ่มรก
  • query result, block หรือ lambda มีพฤติกรรมแปลกกว่าที่คิด

ในสถานการณ์แบบนี้ rdbg ไม่ใช่ของตกแต่งระดับสูง แต่มันคือเครื่องมือดูภายในที่ช่วย ประหยัดเวลา

โพยสั้น: วงจรชีวิตของโปรเจกต์

1. เช็ก runtime ก่อน

ruby -v
which ruby
rbenv versions
rbenv local 3.4.8
rbenv which ruby
cheatsheet.md
bash

2. ลอง Ruby ให้ไว

ruby -e 'puts "hello"'
ruby -e 'puts [1, 2, 3].map { |n| n * 2 }.inspect'
irb
cheatsheet.md
bash

3. สร้างโปรเจกต์

mkdir my_ruby_project
cd my_ruby_project
bundle init
cheatsheet.md
bash

4. รันไฟล์และเช็กไวยากรณ์

ruby app.rb
ruby -c app.rb
ruby -Ilib script.rb
cheatsheet.md
bash

5. เพิ่ม dependencies

bundle add rspec
bundle install
bundle info rspec
cheatsheet.md
bash

6. ดูสภาพแวดล้อมของ gems

gem -v
gem list
gem env
gem which rake
cheatsheet.md
bash

7. เริ่มวงจร test

bundle exec rspec
bundle exec rspec spec/my_spec.rb
bundle exec rspec spec/my_spec.rb:12
cheatsheet.md
bash

8. อ่าน docs ระหว่างเขียนโค้ด

ri Array#map
ri Enumerable#reduce
ri String#gsub
ri File
cheatsheet.md
bash

9. ใช้ project tasks

bundle exec rake -T
bundle exec rake
cheatsheet.md
bash

10. รักษา style ให้สม่ำเสมอ

bundle exec rubocop
bundle exec rubocop -A
cheatsheet.md
bash

11. สร้าง docs

rdoc
yard doc
yard server --reload
yard stats --list-undoc
cheatsheet.md
bash

12. debug พฤติกรรมตอน runtime

rdbg app.rb
rdbg -c -- bundle exec rspec
cheatsheet.md
bash

คู่มือแก้ปัญหา

กฎที่สำคัญที่สุด

อย่าเดาสุ่ม

ให้ตรวจ environment ตามลำดับเดิมทุกครั้ง

ลำดับการวินิจฉัย

  1. ตอนนี้ Ruby ตัวไหนกำลัง active
  2. shell กำลังใช้ executable ตัวไหนจริง
  3. dependency นี้ถูกประกาศไว้ในโปรเจกต์หรือยัง
  4. คุณรันคำสั่งผ่าน Bundler แล้วหรือยัง
  5. gem ถูกติดตั้งแล้วแต่ executable ยังไม่อยู่บน PATH หรือไม่
  6. มีปัญหาเรื่อง native extension หรือ default-gem packaging หรือไม่

ปัญหา: ใช้ Ruby ผิดเวอร์ชัน

อาการ:

  • path ที่ติดตั้ง gems ดูแปลก
  • native gems พังแบบไม่คาดคิด
  • โปรเจกต์ใช้ได้ใน terminal tab หนึ่ง แต่อีก tab กลับใช้ไม่ได้

ให้เช็ก:

ruby -v
which ruby
rbenv versions
rbenv which ruby
troubleshooting.md
bash

การตีความ:

  • ถ้า ruby -v ไม่ตรงกับที่โปรเจกต์คาดไว้ ให้แก้เรื่องเวอร์ชันก่อน

ปัญหา: คำสั่ง gem ใช้ได้ แต่คำสั่งของโปรเจกต์ใช้ไม่ได้

อาการ:

  • gem list rspec เห็นว่า RSpec มีอยู่
  • แต่ bundle exec rspec ยัง fail

ให้เช็ก:

bundle info rspec
bundle install
troubleshooting.md
bash

การตีความ:

  • gem นั้นอาจมีอยู่ในระดับ global แต่ไม่ได้ถูก resolve ให้โปรเจกต์นี้

ปัญหา: หา executable ไม่เจอ

อาการ:

  • bundle หรือ rubocop หรือ yard ขึ้นว่า "not found"

ให้เช็ก:

which bundle
gem env
troubleshooting.md
bash

การตีความ:

  • gem อาจถูกติดตั้งแล้ว แต่ไดเรกทอรีของ executable ไม่ได้อยู่บน PATH
  • หรือ shell integration ของ version manager ยังไม่สมบูรณ์

ปัญหา: Ruby บอกว่าฟีเจอร์ใน standard library หายไป

อาการ:

  • cannot load such file -- csv
  • cannot load such file -- erb

การตีความ:

Ruby เวอร์ชันใหม่อาจแยกบางส่วนที่เคยติดมากับภาษาออกมาเป็น gems ที่ต้องติดตั้งแยก

สิ่งที่ควรทำ:

  • เพิ่ม dependency นั้นลงใน Gemfile ของโปรเจกต์
  • ติดตั้งผ่าน Bundler หรือผ่านขั้น bootstrap ของโปรเจกต์

ปัญหา: build native extension ไม่ผ่าน

อาการ:

  • gems อย่าง sqlite3 build ไม่ผ่าน
  • มี compiler หรือ header errors โผล่ขึ้นมา

ให้เช็ก:

gem env
ruby -v
pkg-config --modversion sqlite3
troubleshooting.md
bash

การตีความ:

  • มักเกิดจาก system headers ที่ขาดหาย หรือใช้ Ruby environment ไม่ตรงกัน

ปัญหา: คำสั่งใช้ได้ข้างนอกโปรเจกต์ แต่ใช้ไม่ได้ในโปรเจกต์

อาการ:

  • ruby -e ใช้ได้
  • แต่ scripts ของโปรเจกต์ fail

การตีความ:

  • ปัญหานี้มักอยู่ที่ dependency resolution ของโปรเจกต์ ไม่ใช่ที่ตัว interpreter

ให้เช็ก:

bundle install
bundle exec rspec
troubleshooting.md
bash

ปัญหา: คำสั่งดู docs ให้ผลไม่ตรงอย่างที่คิด

อาการ:

  • ri ดูข้อมูลน้อยกว่าที่คิด
  • yard docs ไม่ครบ

การตีความ:

  • ri อ่าน docs ที่ติดตั้งมากับ Ruby/core APIs
  • yard พึ่งคุณภาพของ comments ในโปรเจกต์

พูดอีกแบบคือ:

  • ri ใช้อ่าน docs
  • yard ใช้สร้าง docs ให้คนอื่นอ่าน

เครื่องมือเสริม และเหตุผลที่มันควรมาทีหลัง

เครื่องมือชุดนี้มีประโยชน์จริง แต่ยังไม่ใช่ของชิ้นแรกที่ผู้เริ่มต้นควรถูกโยนใส่ ผู้เรียนควร ได้เจอเครื่องมือเหล่านี้หลังจากวงจรพื้นฐานของโปรเจกต์ Ruby เริ่มคุ้นมือแล้ว

simplecov

ใช้เมื่อ:

  • ทีมต้องการรายงาน test coverage

เหตุผลที่มีประโยชน์:

  • ช่วยชี้ให้เห็นส่วนที่ยังไม่มีชุดทดสอบรองรับ

เหตุผลที่ควรมาทีหลัง:

  • coverage จะมีประโยชน์ก็ต่อเมื่อผู้เรียนรันและเชื่อใจชุดทดสอบได้แล้ว

bundler-audit

ใช้เมื่อ:

  • โปรเจกต์ต้องการตรวจช่องโหว่ของ dependencies

เหตุผลที่มีประโยชน์:

  • ทำให้เรื่องความปลอดภัยของ dependencies กลายเป็นส่วนหนึ่งของการดูแลโปรเจกต์จริง

เหตุผลที่ควรมาทีหลัง:

  • ผู้เรียนควรเข้าใจการจัดการ dependencies แบบปกติก่อน

ruby-lsp หรือ solargraph

ใช้เมื่อ:

  • การทำงานร่วมกับ editor เริ่มสำคัญขึ้น
  • ผู้เรียนอยากได้ hover docs, completion และ navigation ใน editor

เหตุผลที่มีประโยชน์:

  • ช่วยให้ประสบการณ์แก้ไขโค้ดในแต่ละวันสะดวกขึ้น

เหตุผลที่ควรมาทีหลัง:

  • เครื่องมือใน editor ควรช่วยเสริมความเข้าใจ ไม่ใช่เข้ามาแทนมัน

reek

ใช้เมื่อ:

  • ทีมอยากได้ feedback เรื่อง smell ที่ลึกกว่า formatting

เหตุผลที่มีประโยชน์:

  • ช่วยเปิดบทสนทนาเรื่องการออกแบบ

เหตุผลที่ควรมาทีหลัง:

  • ผู้เรียนควรรู้ภาษาและวงจรของโปรเจกต์ก่อนจะไปต่อที่ศัพท์เรื่อง smell

brakeman

ใช้เมื่อ:

  • โปรเจกต์ใช้ Rails

เหตุผลที่มีประโยชน์:

  • ใช้สแกนเรื่องความปลอดภัยใน Rails applications

เหตุผลที่ควรมาทีหลัง:

  • มันไม่ได้เกี่ยวกับทุกโปรเจกต์ Ruby

บทเรียนที่กว้างกว่านั้น

โปรเจกต์ Ruby มักโตเป็นชั้น ๆ:

  1. runtime
  2. การตั้งต้นโปรเจกต์
  3. dependencies
  4. tests
  5. docs และ style
  6. debugging
  7. เครื่องมือเสริมของ ecosystem

ผู้เรียนควรรู้ว่า add-ons พวกนี้มีอยู่ แต่ไม่ควรถูกกลบด้วยเครื่องมือมากเกินไป ก่อนที่ วิธีทำงานแกนกลางจะเริ่มเป็นธรรมชาติ