ภาคผนวก 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เข้ามามีบทบาทตรงไหนในชีวิตของโปรเจกต์ - แก้ปัญหาสภาพแวดล้อมที่พบบ่อยได้ โดยไม่เดาสุ่ม
แนวคิดการสอนของภาคผนวกนี้
ภาคผนวกนี้ ไม่ได้ สอนเครื่องมือแบบเรียงตามตัวอักษร
ผมสอนมันตามลำดับที่นักพัฒนามักต้องใช้จริง:
- เลือก Ruby version
- ยืนยันว่า interpreter ใช้งานได้
- สร้างโปรเจกต์
- เพิ่ม dependencies
- เริ่มวงจร test
- เปิด docs ระหว่างเขียนโค้ด
- ทำงานที่ซ้ำบ่อยให้เป็นงานอัตโนมัติ
- รักษา style และ docs ให้สม่ำเสมอ
- debug พฤติกรรมตอน runtime
- แก้ปัญหา 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
เครื่องมือที่เริ่มแนะนำตรงนี้
rubywhichrbenv
คำสั่ง
ruby -v
which ruby
rbenv versions
rbenv local 3.4.8
rbenv which rubybash
แต่ละคำสั่งกำลังบอกอะไร
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 ที่
rbenvresolve ออกมาจริง
สถานการณ์จริง
คุณ clone โปรเจกต์ Ruby มา แล้ว bundle install fail ด้วย error แปลก ๆ จาก native extension บ่อยครั้งตัวต้นเหตุไม่ได้อยู่ที่ gem เลย แต่เกิดจาก shell ของคุณกำลังใช้ Ruby ผิดเวอร์ชัน
เพราะฉะนั้นคำถามแรกเวลา debug ไม่ควรเป็น:
- "ทำไม Bundler พัง"
แต่ควรเป็น:
- "ตอนนี้ผมกำลังใช้ Ruby ตัวไหนกันแน่"
นี่คือเหตุผลที่เรื่อง version management ต้องมาก่อน
Stage 1: ลอง Ruby ก่อนสร้างโปรเจกต์
ก่อนจะสร้าง project skeleton ให้ยืนยันก่อนว่า interpreter กับวิธีทำงานผ่าน shell ใช้งาน ได้จริง วิธีนี้ช่วยแยกปัญหาของ environment ออกจากปัญหาของโปรเจกต์
เครื่องมือที่เริ่มแนะนำตรงนี้
rubyirb
คำสั่ง
ruby -e 'puts "hello from ruby"'
ruby -e 'puts [1, 2, 3].map { |n| n * 2 }.inspect'
irbbash
ทำไมช่วงนี้จึงสำคัญ
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]]ruby
นี่คือวิธีทำงานที่ใช้กันจริงทุกวัน ไม่ใช่แค่ทริกสำหรับผู้เริ่มต้น
Stage 2: สร้างโปรเจกต์
ตอนนี้ Ruby เองทำงานแล้ว ขั้นต่อไปคือสร้างไดเรกทอรีของโปรเจกต์ และเริ่ม dependency management ให้ถูกตั้งแต่วันแรก
เครื่องมือที่เริ่มแนะนำตรงนี้
bundle
คำสั่ง
mkdir my_ruby_project
cd my_ruby_project
bundle initbash
สิ่งที่เกิดขึ้นตรงนี้
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.rbbash
ทำไมคำสั่งพวกนี้จึงสำคัญ
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
เครื่องมือที่เริ่มแนะนำตรงนี้
gembundle
แก่นของเรื่อง
มีเรื่องที่ต้องแยกให้ออกอยู่สองชั้น:
- ระบบ gems ระดับเครื่อง
- ชุด dependencies ที่โปรเจกต์ประกาศไว้
ผู้เรียนต้องเข้าใจว่ามันไม่ใช่เรื่องเดียวกัน
คำสั่งระดับเครื่อง
gem -v
gem list
gem env
gem which rakebash
คำสั่งเหล่านี้ช่วยให้คุณมองเห็นสภาพแวดล้อมของ RubyGems บนเครื่อง
คำสั่งระดับโปรเจกต์
bundle add rspec
bundle install
bundle info rspecbash
ความหมายของคำสั่งเหล่านี้
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:12bash
ทำไม 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 Filebash
ทำไม 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 rakebash
ทำไม 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 -Abash
ทำไม rubocop จึงสำคัญ
rubocop ช่วยทีม:
- ทำให้ style สม่ำเสมอ
- จับ smell ง่าย ๆ บางอย่างได้
- ลดเสียงรบกวนใน code review ที่เป็นเรื่อง formatting
มันไม่ได้มาแทน design review แต่มีประโยชน์เพราะมันช่วยทำ feedback ที่ซ้ำ ๆ ให้เป็น อัตโนมัติ
สถานการณ์จริง
ถ้าไม่มี formatter/linter code review มักเต็มไปด้วย:
- การจัด spacing
- การเถียงกันเรื่อง quote style
- การเถียงกันเรื่อง layout
ซึ่งทำให้พลังของมนุษย์ถูกใช้ไปกับเรื่องที่เครื่องควรจัดการได้
Stage 9: ทำเอกสารให้มนุษย์อ่าน
เมื่อโค้ดเริ่มถูกใช้ร่วมกัน คนอื่นต้องการมากกว่า test ที่ผ่าน พวกเขาต้องการ API docs ที่อ่านออก
เครื่องมือที่เริ่มแนะนำตรงนี้
rdocyard
คำสั่ง
rdoc
yard doc
yard server --reload
yard stats --list-undocbash
ความต่างระหว่าง 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 rspecbash
ทำไม rdbg จึงสำคัญ
debugger ช่วยเมื่อ:
- recursion มีพฤติกรรมแปลก
- state ในฐานข้อมูลไม่ตรงกับที่คิด
- closure จับค่าผิด
- test ส่งข้อมูลผ่านหลายชั้นเกินกว่าจะดูด้วย
putsได้ง่าย
สถานการณ์จริง
recursive traversal ตัวหนึ่งทำ path ซ้ำเฉพาะ edge case แบบหนึ่ง ถ้าคุณใส่ print statements ไว้เต็มไปหมด โค้ดจะเริ่มรก debugger ช่วยให้คุณเปิดดู call stack กับค่าปัจจุบัน ได้อย่างแม่นยำกว่า
Stage 11: เครื่องมือเสริมของโปรเจกต์ที่เริ่มโตแล้ว
เมื่อวงจรหลักของโปรเจกต์เริ่มนิ่ง ผู้เรียนอาจเจอเครื่องมือเสริมอย่าง:
simplecovbundler-auditruby-lspsolargraph
ทั้งหมดนี้สำคัญ แต่ยังไม่ใช่เครื่องมือชุดแรกที่ผู้เรียนควรรู้
มันควรเข้ามาหลังจากที่ผู้เรียนเข้าใจวงจรหลักของโปรเจกต์แล้ว
Sprint Flow: เครื่องมือเหล่านี้เข้ากับงานประจำวันอย่างไร
วงจรที่เกิดซ้ำ
เมื่อโปรเจกต์ Ruby เริ่มมีชีวิต วงจรประจำวันมักหน้าตาแบบนี้:
- เช็ก environment
- ติดตั้งหรือ sync dependencies ถ้าจำเป็น
- รัน test หนึ่งตัวหรือ spec file หนึ่งไฟล์
- แก้โค้ด
- รัน tests ซ้ำ
- เปิดดูพฤติกรรมของ Ruby ถ้ายังไม่แน่ใจ
- lint หรือจัด style ก่อนถือว่างานจบ
วงจรนี้คือจุดที่เครื่องมือเลิกเป็น "คำสั่งที่ต้องท่อง" แล้วกลายเป็นส่วนหนึ่งของการทำงาน จริง
ตัวอย่าง sprint ที่สมจริง
ลองนึกว่าคุณกำลังทำแบบฝึกหัดในหัวข้อหนึ่ง หรือกำลังเพิ่มฟีเจอร์ใหม่ในโปรเจกต์
Step 1: ยืนยัน runtime
ruby -v
which rubybash
เหตุผล:
- ป้องกันการทำงานอยู่ยี่สิบนาทีก่อนจะรู้ว่าคุณใช้ Ruby คนละเวอร์ชัน
Step 2: sync dependencies
bundle installbash
เหตุผล:
- ทำให้ dependencies ในโปรเจกต์ตรงกับ
Gemfileและ lockfile
Step 3: รันเฉพาะ tests ที่เกี่ยวข้อง
bundle exec rspec spec/my_spec.rbbash
เหตุผล:
- ได้ feedback เร็วกว่า
- โฟกัสกับปัญหาทีละก้อนได้ง่ายกว่า
Step 4: เปิด docs ระหว่างลงมือเขียน
ri Enumerable#filter_mapbash
เหตุผล:
- ช่วยตอบคำถามเฉพาะจุด โดยไม่ต้องหลุดออกจาก flow
Step 5: เช็กไวยากรณ์ให้ไวเมื่อจำเป็น
ruby -c lib/my_class.rbbash
เหตุผล:
- มีประโยชน์เมื่อความล้มเหลวดูเหมือนเป็นเรื่องไวยากรณ์ มากกว่าจะเป็นเรื่อง logic
Step 6: รัน linter ก่อนถือว่างานเสร็จ
bundle exec rubocopbash
เหตุผล:
- ช่วยลด review comments ที่เลี่ยงได้
เมื่อไร rake เข้ามาอยู่ใน sprint loop
ถ้าโปรเจกต์เริ่มมีวิธีทำงานที่ต้องทำซ้ำ ทีมมักเลิกเขียนคำสั่งดิบ ๆ ไว้ใน README แล้วเริ่ม ทำให้มันเป็น tasks อย่างเป็นทางการ
ตัวอย่าง:
bundle exec rake testbundle exec rake docsbundle 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 rubybash
2. ลอง Ruby ให้ไว
ruby -e 'puts "hello"'
ruby -e 'puts [1, 2, 3].map { |n| n * 2 }.inspect'
irbbash
3. สร้างโปรเจกต์
mkdir my_ruby_project
cd my_ruby_project
bundle initbash
4. รันไฟล์และเช็กไวยากรณ์
ruby app.rb
ruby -c app.rb
ruby -Ilib script.rbbash
5. เพิ่ม dependencies
bundle add rspec
bundle install
bundle info rspecbash
6. ดูสภาพแวดล้อมของ gems
gem -v
gem list
gem env
gem which rakebash
7. เริ่มวงจร test
bundle exec rspec
bundle exec rspec spec/my_spec.rb
bundle exec rspec spec/my_spec.rb:12bash
8. อ่าน docs ระหว่างเขียนโค้ด
ri Array#map
ri Enumerable#reduce
ri String#gsub
ri Filebash
9. ใช้ project tasks
bundle exec rake -T
bundle exec rakebash
10. รักษา style ให้สม่ำเสมอ
bundle exec rubocop
bundle exec rubocop -Abash
11. สร้าง docs
rdoc
yard doc
yard server --reload
yard stats --list-undocbash
12. debug พฤติกรรมตอน runtime
rdbg app.rb
rdbg -c -- bundle exec rspecbash
คู่มือแก้ปัญหา
กฎที่สำคัญที่สุด
อย่าเดาสุ่ม
ให้ตรวจ environment ตามลำดับเดิมทุกครั้ง
ลำดับการวินิจฉัย
- ตอนนี้ Ruby ตัวไหนกำลัง active
- shell กำลังใช้ executable ตัวไหนจริง
- dependency นี้ถูกประกาศไว้ในโปรเจกต์หรือยัง
- คุณรันคำสั่งผ่าน Bundler แล้วหรือยัง
- gem ถูกติดตั้งแล้วแต่ executable ยังไม่อยู่บน
PATHหรือไม่ - มีปัญหาเรื่อง native extension หรือ default-gem packaging หรือไม่
ปัญหา: ใช้ Ruby ผิดเวอร์ชัน
อาการ:
- path ที่ติดตั้ง gems ดูแปลก
- native gems พังแบบไม่คาดคิด
- โปรเจกต์ใช้ได้ใน terminal tab หนึ่ง แต่อีก tab กลับใช้ไม่ได้
ให้เช็ก:
ruby -v
which ruby
rbenv versions
rbenv which rubybash
การตีความ:
- ถ้า
ruby -vไม่ตรงกับที่โปรเจกต์คาดไว้ ให้แก้เรื่องเวอร์ชันก่อน
ปัญหา: คำสั่ง gem ใช้ได้ แต่คำสั่งของโปรเจกต์ใช้ไม่ได้
อาการ:
gem list rspecเห็นว่า RSpec มีอยู่- แต่
bundle exec rspecยัง fail
ให้เช็ก:
bundle info rspec
bundle installbash
การตีความ:
- gem นั้นอาจมีอยู่ในระดับ global แต่ไม่ได้ถูก resolve ให้โปรเจกต์นี้
ปัญหา: หา executable ไม่เจอ
อาการ:
bundleหรือrubocopหรือyardขึ้นว่า "not found"
ให้เช็ก:
which bundle
gem envbash
การตีความ:
- gem อาจถูกติดตั้งแล้ว แต่ไดเรกทอรีของ executable ไม่ได้อยู่บน
PATH - หรือ shell integration ของ version manager ยังไม่สมบูรณ์
ปัญหา: Ruby บอกว่าฟีเจอร์ใน standard library หายไป
อาการ:
cannot load such file -- csvcannot load such file -- erb
การตีความ:
Ruby เวอร์ชันใหม่อาจแยกบางส่วนที่เคยติดมากับภาษาออกมาเป็น gems ที่ต้องติดตั้งแยก
สิ่งที่ควรทำ:
- เพิ่ม dependency นั้นลงใน
Gemfileของโปรเจกต์ - ติดตั้งผ่าน Bundler หรือผ่านขั้น bootstrap ของโปรเจกต์
ปัญหา: build native extension ไม่ผ่าน
อาการ:
- gems อย่าง
sqlite3build ไม่ผ่าน - มี compiler หรือ header errors โผล่ขึ้นมา
ให้เช็ก:
gem env
ruby -v
pkg-config --modversion sqlite3bash
การตีความ:
- มักเกิดจาก system headers ที่ขาดหาย หรือใช้ Ruby environment ไม่ตรงกัน
ปัญหา: คำสั่งใช้ได้ข้างนอกโปรเจกต์ แต่ใช้ไม่ได้ในโปรเจกต์
อาการ:
ruby -eใช้ได้- แต่ scripts ของโปรเจกต์ fail
การตีความ:
- ปัญหานี้มักอยู่ที่ dependency resolution ของโปรเจกต์ ไม่ใช่ที่ตัว interpreter
ให้เช็ก:
bundle install
bundle exec rspecbash
ปัญหา: คำสั่งดู docs ให้ผลไม่ตรงอย่างที่คิด
อาการ:
riดูข้อมูลน้อยกว่าที่คิดyarddocs ไม่ครบ
การตีความ:
riอ่าน docs ที่ติดตั้งมากับ Ruby/core APIsyardพึ่งคุณภาพของ comments ในโปรเจกต์
พูดอีกแบบคือ:
riใช้อ่าน docsyardใช้สร้าง 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 มักโตเป็นชั้น ๆ:
- runtime
- การตั้งต้นโปรเจกต์
- dependencies
- tests
- docs และ style
- debugging
- เครื่องมือเสริมของ ecosystem
ผู้เรียนควรรู้ว่า add-ons พวกนี้มีอยู่ แต่ไม่ควรถูกกลบด้วยเครื่องมือมากเกินไป ก่อนที่ วิธีทำงานแกนกลางจะเริ่มเป็นธรรมชาติ