Monthly Archives: January 2012

เริ่มต้นกับ Ruby และ Rails ยังไงดี

Blog นี้ผมเข้าเนื้อหาเลยนะครับ ใครอยากอ่านที่ ผมเกริ่น ตามไปอ่านกันได้

Blog นี้เหมาะสำหรับคนที่พร้อมหรือพยายามศึกษาด้วยเอกสารภาษาอังกฤษนะครับ มันเป็นวิธีที่ผมใช้ ใครไม่ค่อยถนัด ลองพยายามหน่อยนะครับ ภาษาอังกฤษมันจะเป็นสำหรับสาขาเราจริงๆ

เริ่มต้นที่ตัวติดตั้ง Ruby ครับ ผมแนะนำ RVM ถ้าใช้ตัวนี้คุณจะติดตั้ง Ruby ได้ง่ายๆ จะเปลี่ยน Ruby version ได้ง่ายๆ เปลี่ยนไปใช้ Ruby บน VM อื่นๆ เช่น JRuby ก็ง่ายเช่นกัน แถมสามารถสร้าง gemset ต่างๆ กันต่อโปรเจ็คได้ด้วย

จากนั้นก็ไปทำความรู้จักกับ basic Ruby จากสถานที่ต่างๆ ตามอัตถยาศัยครับ อันนี้ไม่มี recommend แต่อย่าลืมทำความรู้จักกับ irb เพื่อนยากไว้ด้วย

สิ่งที่ต้องรู้จักต่อมาคือ gem มันคือ library package manager ที่กลายเป็นมาตรฐานของ Ruby ไปแล้ว หนึ่งในความสนุกของ Ruby อยู่ตรงนี้หละครับ เพราะ ณ วันนี้มี gem ให้เล่นเยอะเหลือเกิน ถ้าติดตามข่าวดีๆ ทำความรู้จักกับเหล่า gem ไว้ จะทำให้เราประหยัดเวลาในการทำอะไร ด้วยการไปใช้ของที่คนอื่นทำไว้ให้แล้ว ไปได้เยอะมาก เช่น ทำหน้า CRUD สำหรับ Admin ได้อย่างรวดเร็วด้วย Active Admin หรือระบบ user management พื้นฐานด้วย Devise และอื่นๆอีกมากมาย

มาถึง​ Rails กันครับ มันก็อยู่ในรูป gemๆ หนึ่งเท่านั้นแหละ ก็ install มันเข้าไป เอกสารพื้นฐานของตัว Rails ผมก็ไม่มีอันไหนแนะนำเป็นพิเศษเหมือนกัน

โดยพื้นฐานก็ 2 ลิงค์นี้ น่าจะพอครับ http://ruby.railstutorial.org/ กับ http://guides.rubyonrails.org/index.html

แต่ผมมี screencast แนะนำอยู่อันนึง The Intro to Rails Screencast I Wish I Had

พอเล่นกับ Rails ซักพัก ก็คงอยาก deploy ขึ้นบน server จริง อันนี้แนะนำ Heroku ครับ สำหรับผู้เริ่มต้น ฟรี ครับ แต่จะจำกันให้แค่ 1 dyno ต่อประมาณหนึ่งเดือน หมายความว่าเราจะรับได้แค่ไม่กี่ concurrent user และห้ามมี background job ครับ

อีกยี่ห้อนึงที่ดังๆ คือ Engine Yard แต่ผมไม่เคยใช้เหมือนกันคิดว่าคงไม่ต่างกันมากมั้ง

ถ้าเราเลือกใช้ Heroku สิ่งที่ต้องเตรียมตัวคือ มันบังคับให้เราใช้ PostgreSQL เป็น database ครับ เพราะฉะนั้นตอนเริ่มเล่น Rails ใครไม่อยากเสียเวลาก็เริ่มที่ Postges ซะเลย

หรือใครจะอยากไม่อยากใช้ SQL ก็ไม่ว่ากันครับ แต่ไม่แน่ใจเหมือนกันว่า Heroku มี add-ons ของพวก NoSQL ให้เล่นฟรีๆ แค่ไหน แต่ถ้าไม่ใช้ NoSQL ก็จะไม่ได้เล่นกับ ActiveRecord ที่ถือเป็นของขึ้นชื่อของ Rails พอควร

พอเล่นไปได้ซักพัก ใครที่สนใจเรื่อง test เหมือนผม แนะนำ เล่มนี้ครับ The RSpec Book 

RSpec คือ ชื่อ test framework ยี่ห้อนึง ประมาณ xUnit แหละครับ แต่ส่วนตัวผมชอบมาก เล่มนี้ไม่ได้สอน RSpec อย่างเดียว แต่สอนถึง TDD และวิธีการพัฒนาแบบ Outside-in ด้วย และพอเป็น outside-in แน่นอนต้องพูดถึง Cucumber ด้วย

ปัญหาอย่างนึงที่ผมเจอตอนไต่ learning curve ของ Rails มาคือ document มันไม่ค่อยน่าพอใจเท่าไหร่ มันก็มีเยอะพอสมควรแต่รู้สึกไม่พอใจยังไงไม่รู้

ผมพอจะสันนิษฐานได้ว่า เกิดจากความที่มันเป็น open source แล้วมันเปลี่ยนแปลงบ่อยมาก ทำให้มีอะไรใหม่ๆ เรื่อยๆ ข้อมูลหลายๆ อย่างก็ตกยุคอย่างรวดเร็ว รวมไปถึงพวก blog post และ mailing list ต่างๆ ด้วย

ไม่นานมานี้ ผมมักจะมีปัญหาว่า จะทำสิ่งๆหนึ่ง ทำยังไงดี หรือจะทำสิ่งๆหนึ่ง รู้สึกว่าเปลืองเวลา และน่าจะมีคนทำแล้ว พอไปค้น gem ดูเจอหลายตัว เอ๊ะ เค้านิยมใช้ตัวไหนกันว่ะ

วิธีแก้ปัญหาที่ผมเลือกใช้แก้ปัญหานี้ คือ เปิดรับข่าวสารครับ ผมคิดว่าสิ่งที่ต่างสำหรับคนที่เข้าไปใน platform ใหม่ๆ กับคนที่อยู่มานานแล้ว อย่างนึงคือ คือ ความรู้ในสิ่งที่เคยเป็นที่พูดถึงกันในอดีต พอรู้แบบนี้ผมเลยช่างมันกับเรื่องเก่าๆ ครับ แต่ข่าวใหม่ๆ ผมต้องไม่พลาด

ผมติดตามๆ สิ่งต่างๆ เหล่านี้ http://railscasts.com/, http://rubyshow.com/, http://ruby5.envylabs.com/, http://www.rubyinside.com/, http://www.planetrubyonrails.com/ ที่มีการอัพเดตอยู่ทุกวัน, ทุกอาทิตย์ๆ ผม follow twitter account ของคนเขียนหนังสือ และคนเขียน library ต่างๆ และผลที่ผ่านมารู้สึกเป็นไปได้ด้วยดีครับ เริ่มรู้อะไรขึ้นเรื่อยๆ

สำหรับเบื้องต้น ก็คงประมาณนี้หละครับ ใครมีปัญหาอะไรก็ถามมาได้ ทางไหนก็ได้ตามสะดวกครับ

ขอให้มีความสุขครับ 🙂

เกริ่นกับ Ruby และ Rails สำหรับ blog ถัดไป

พอดีเพื่อนที่บริษัทเก่ากำลังจะเริ่มศึกษา Rails แล้วมาถามข้อมูลเบื้องต้น เลยฉุกคิดได้ว่าน่าจะ blog ไว้หน่อย ไหนๆ ก็อยู่ในจุดที่กำลังจะผ่านช่วง beginner ไต่ leaning curve ไปแล้ว

เริ่มต้น ต้องเข้าใจก่อนว่า Ruby และ Rails มันช้านะครับ เช่น แค่เวลารัน command ต่างๆ จะรู้สึกได้ว่ามันอืดๆ นิดๆ (เทียบกับเวลาใช้พวก shell command) และจะเห็นได้ว่าอยู่อันดับท้ายๆ ของทุกๆ benchmark ถ้าใครรู้สึกไม่โอเคกับตรงนี้ก็เตรียมตัวหา platform อื่นได้เลย น่าจะมีที่ถูกใจกว่า

Web framework แต่ละตัวของแต่ละ platform ไม่ว่าจะเป็น Python, PHP, Java, C# หรือ Javascript หลักๆ มันก็คล้ายๆ กันแหละ แต่ละตัวโดดเด่นตามช่วงเวลา เปลี่ยนแปลงคุณสมบัติ และความนิยม ไปเรื่อยๆ ตามปกติของโลก technology เพราะฉะนั้นอยากเขียนภาษาอะไร หรือมีพันธะบังคับต้องไปเชื่อมต่อกับภาษาไหน ก็เลือกได้ตามสะดวก

ถึงตรงนี้คงเกิดคำขึ้นว่าทำไมผมถึงเลือก platform Ruby มี 2 เหตุผลหลักๆ ครับ

  1. ผมพยายามจะเป็นโปรแกรมเมอร์ที่ happy ทำให้ผมซื้อแนวคิดของคนสร้างภาษาที่ focus ความ happy ของโปรแกรมเมอร์เลยคิดว่าภาษานี้น่าจะพัฒนาไปในทิศทางที่ถูกใจ
  2. ผมรู้สึกว่า Ruby เป็น platform ที่คนจาก Agile community สนใจมากที่สุด (ด้วยเหตุผลอะไรก็ไม่รู้) เป็นผลให้เกิด tools, library หลายๆ อย่างที่ support Agile และ testing เหมาะสำหรับไอ้บ้า test แบบผม จากเหตุผลดังกล่าวผมสังเกตได้ว่า testing tools (สำหรับระดับ developer) ตอนนี้บน Ruby platform จะล้ำๆ platform อื่นอยู่นิดหน่อย

ส่วนเรื่อง performance เป็นประเด็นรองๆ ลงไปสำหรับผม ไว้ถึงวันที่ผมทำระบบที่มีคนเข้าเยอะมากจน server และ topology ที่ผมใช้รับไม่ไหว วันนั้นผมก็คงมาพูดอีกแบบหนึ่ง (แต่ก็ยังแอบคิดว่าถึงวันนั้น ผมคงแก้ที่ persistent layer ก่อนอยู่ดี)

โอเค เกริ่นพอละ พบกับ blog การเริ่มต้นศึกษา Ruby และ Rails ฉบับผมได้เลยครับ

Trunk Based Development

จริงๆ แล้วเรื่องนี้เป็นส่วนหนึ่งของ Continuous Integration ที่เคยเขียนถึงไปแล้ว แต่วันนี้จะลงรายละเอียดไปอีกหน่อย

การจะทำ CI ให้ประสบความสำเร็จนั้น ทีมพัฒนาจำเป็นจะต้องมีวินัยด้วย ไม่ใช่ว่าแค่ตั้ง CI server, Jenkins(Hudson) หรือ CruiseControl ขึ้นมาแล้วจะบอกว่าตัวเองทำ CI แล้ว ระเบียบวินัยที่ว่านี้มีหลายด้าน วันนี้จะมาว่าด้วยเรื่องของ source code version control ครับ

Trunk Based Development คือ อะไร?

มันคือ สไตล์การจัดการ source code version control ที่เอื้อให้เกิดการรวม code ตั้งแต่ช่วงเริ่มต้น และตลอดการพัฒนา โดยวิธีการคือ นักพัฒนาทุกคน ไม่ว่าจะทีมใหญ่แค่ไหน อยู่ที่เดียวกัน หรืออยู่ต่างจังหวัด ต่างประเทศกันก็ตาม ทุกคนต้อง commit code เข้าที่ branch เดียวเสมอๆ (และบ่อยๆ)

ได้ยินแบบนี้หลายท่านอาจจะรู้สึกขัดใจ เพราะตามที่เราเข้าใจกันมา ทีมระดับเทพ และโปรเจ็คที่มีความใหญ่ประมาณหนึ่งขึ้นไปควรจะมีการจัดการ branch ที่ดี อาจจะแบ่งตามเวอร์ชั่น แบ่งตามฟีเจอร์ แบ่งตามนักพัฒนาก็ว่ากันไป มีโปรเซสในการรวม code ที่ดี และการตรวจสอบเทสบั๊ก จากการรวม code เข้ามาตรวจจับและวิเคราะห์หาบั๊กและปัญหาต่างๆ และแก้ได้ถูก branch เป็นการจำกัดขอบเขตความเสียหาย และหาจุดบกพร่องได้ง่ายขึ้น

“ไอ่ที่มี SVN branch เดียว ทุกคน commit ไปรวมกันหมด ชิบหายมานักต่อนักแล้ว มันเอาไว้ให้โปรเจ็คเล็กๆ ง่ายๆ พัฒนาคนเดียว หรือไม่่กี่คนเค้าใช้กัน”

ข้างบนนี้คือ ความคิดแวบแรกของผมที่ได้ยินคอนเซปนี้เลยครับ แต่พอได้รู้ถึงเหตุผล และผลเสียของการแตก branch ผมก็เริ่มเข้าใจมากขึ้น

  • ลองคิดถึงเวลาต้อง merge code ที่ไม่ได้ merge กันมาเป็นเวลานาน มันยากขนาดไหน ต้องใช้เวลานานขนาดไหน ส่วนตัวผมเคยถึงขั้น ไม่สามารถ merge กันได้ ต้องแยกกันไปเลยก็มี
  • เคยมั้ยที่คุณไม่กล้าแก้ refactor code ให้ดีขึ้นเพราะกลัวจะ merge กับเพื่อนแล้วมีปัญหา
  • เคยมั้ยที่เรากำลังจะทำงานๆ หนึ่ง แล้วมันต้องใช้ code ที่เพื่อนร่วมทีมของคุณทำไปแล้ว แต่ไม่ได้ merge เข้ามา หรือยัง merge เข้ามาไม่ได้
  • ฯลฯ

ปัญหาเหล่านี้หละครับ เป็นส่วนหนึ่งที่ทำให้เกิดความล่าช้า และความซับซ้อนในการพัฒนาโดยไม่จำเป็น

ตามคำกล่าวที่ว่า “if it hurts, do it more often” ถ้ามันยากนักก็ทำมันบ่อยๆ ซะ มันก็จะง่ายขึึ้นเอง ถ้าการ merge code ทำให้ชีวิตเราลำบาก ทำไมเราไม่ merge มันบ่อยๆ หละ

อยากให้ลองกันดูครับ ไม่ยากอะไร แค่ กำหนดให้นักพัฒนาทุกคนที่พัฒนาบน source code ชุดเดียวกัน อย่างน้อยคนละครั้งต่อวัน แล้วสิ่งดีๆ จะตามมา

ถ้าบริษัทที่มีนักพัฒนาเยอะระดับ Google เค้าทำได้ เราก็ต้องทำได้ครับ

 

FAQ

แล้ว ถ้า code คนอื่นมาทำทั้งโปรเจ็คพังไปหมดจะทำไงหละ?

– การป้องกันการพังด้วยการ ไม่เอา code มารวมกัน มันเป็นการแก้ปัญหาที่ไม่ตรงจุดนะครับ กรณีนี้ผมก็คงต้องแนะนำให้นักพัฒนาทุกคน มีความรับผิดชอบต่อ code ตัวเอง(อีกวินัยหนึ่งที่จำเป็นต่อ CI) ด้วยการเขียน test อย่างครอบคลุมครับ

แล้วถ้า feature ที่ทำอยู่มันทำงานร่วมกับ feature ปัจจุบันไม่ได้เลยหละ จะทำยังไง?

– เรื่องนี้ผมรู้ว่ามี 2 เทคนิคที่เอามาช่วยแก้ปัญหานี้ได้ครับ อันนึงคือ Feature toggle (Feature bit) อีกอันนึงคือ Branch by abstraction ถ้ามีโอกาส (และความอยาก) จะมาเล่า 2 เรื่องนี้ให้ฟังครับ

อย่างงี้ DVCS เท่ๆ ของเราทั้ง Git ทั้ง Mecurial ก็หมดความหมายไปเลยสิ?

– จริงๆ แล้วประเด็นของวิธีนี้ ไม่ได้กำหนดว่าห้ามสร้าง branch ครับ แต่ต้องมีวินัยนำกลับมา trunk เร็วที่สุด ตัว DVCS ยังให้ประโยชน์แก่เราในกรณีอื่นๆ อีกมากมาย ไม่ใช่แค่สร้าง branch ได้ cheap เพียงอย่างเดียวครับ DVCS ของเรายังเท่อยู่ครับ

I have a method. object.tap!!!

งานวันนี้ต้องมีการทำ operation กับ hash นิดหน่อย รับ input เป็น hash จากนั้น ทำอะไรบางอย่างกับ value แล้ว return เป็น hash กลับออกมาอีกครั้ง

แรกสุดเลยผมและคู่ pair ทำ version แรกออกมาแบบง่ายและ make sense แก่ชาว dev ที่เกิดบนยุค for loop ที่สุดหน้าตาเป็นดังนี้

1
2
3
4
5
def do_each(hash)
  result = {}
  hash.each { |key, value| result[key] = do_something(value) }
  result
end

แต่พวกเราไม่พอใจ จากที่ Ruby ไม่ต้องมี return เพราะมันจับค่าที่ return จาก expression สุดท้าย เป็นค่า return ของ method ให้เอง เราจึงมองว่า result ตัวสุดท้ายมันเกะกะ (result ตัวแรกก็แอบเกะกะด้วย)

พอเกิดปัญหานี้ เราก็มักจะเปลี่ยนมันเป็น inject ซะ ได้ว่า

1
2
3
def do_inject(hash)
  hash.inject({}) { |result, pair| result[pair.first] = do_something(pair.last); result }
end

แต่ result ตัวสุดท้ายใน block ก็ยังเกะกะอยู่

จากนั้นคู่ pair ของผม นึก method ที่เราต้องการออก มันคือ instance method “tap” คอนเซปก็คือ เราทำอะไรกับมันก็ได้ใน block แล้วมันจะถูก return ออกไป code จึงเปลี่ยนไปเป็นแบบนี้

1
2
3
4
5
def do_tap(hash)
  {}.tap do |result|
    hash.each { |key, value| result[key] = do_something(value) }
  end
end

เหอะๆ ไม่รู้จัก method นี้มากก่อนเลย ตอนนี้บน version control เลยเป็นอันนี้อยู่

ตอนเย็น ระหว่างเดินไปขึ้นรถบัสไปงาน Agile meetup นึกขึ้นได้อีกท่านึง ดูจะสั้นกว่าด้วย

1
2
3
def do_map(hash)
  Hash[hash.map { |key, value| [key, do_something(value)] }]
end

สนุกดีนะครับ 555

 

ประสบการณ์ Pair Programming

เริ่มทำงานที่ปัจจุบันมาได้เดือนกว่าๆ ได้มีโอกาสทำ Pair Programming ตลอดเวลา เลยมีประเด็นต่างๆ ที่สังเกตได้มาเล่าให้ฟังครับ

เริ่มจากตัว pair programming เองก่อน

  • มันบังคับให้เรา concentrate กับงานได้ 8 ชั่วโมงเต็มๆ จริงๆ ลืมไปได้เลย social networks, blogs ข่าวต่างๆ หรือแม้กระทั่งเวลานั่งง่วง เหม่อ
  • ทำให้เราต้องมีเหตุผลในการทำสิ่งต่างๆ มากขึ้น ความผิดพลาดจากการลืมทำบางอย่าง หรือพิมพ์ผิด น้อยลงมาก เพราะมีคนคอยจ้องเราพิมพ์ตลอดเวลา
  • ได้เรียนรู้นิสัย วิธีคิดของเพื่อนร่วมงานอย่างรวดเร็ว เพราะต้องคุยกันตลอด
  • เรียนรู้สิ่งใหม่ๆ ได้เร็วขึ้น เช่น ภาษาใหม่, framework ใหม่, domain knowledge ใหม่, codebase ของบริษัท
  • ได้ศึกษา tips หรือ technique ในการเขียนโปรแกรมของคนอื่น มาปรับใช้กับตัวเอง เช่น short-key, สไตล์การ debug, สไตล์การ organize code
  • ลดโอกาสการเรียนรู้บางอย่างในเวลางาน พวกทักษะที่ต้องใช้เวลาในการเรียนรู้ ไม่ใช่เห็นแล้วจำได้ทันที จะไม่มีเวลาได้ทดลองหัด เพราะจะโดน pair แย่งทำอย่างรวดเร็ว ส่วนตัวที่เจอคือ RegEx กับ SQL ต้องกลับมาทำการบ้านทดแทน

ส่วนพฤติกรรมของ pair ที่สังเกตได้มีดังนี้

  • พฤติกรรมการเคาะ keyboard (Esc, Ctrl-C)แรงๆหลายๆที เวลาเครื่องแฮงค์/ตอบสนองช้า เป็นพฤติกรรมที่ไม่ค่อยหน้าอยู่ใกล้เลย รู้สึกมันทำให้บรรยากาศดูเครียด ส่วนตัวคิดว่าตัวเองก็ทำอยู่บ้าง ต่อไปจะพยายามไม่ทำ
  • การหลุด focus ขณะที่เราทำ task หนึ่งๆอยู่ บางครั้งเราจะหลุดไปทำอย่างอื่น เช่น เห็น code หรือ CSS เน่า(ที่ส่วนอื่น)แวะผ่านตาก็แวบไป clean มัน การหลุด focus แบบนี้ส่งผลมากกว่าที่คิด นอกจากจะทำให้ task ที่ทำอยู่เสร็จช้าลงแล้ว บางทีอาจพบปัญหา code พังโดยไม่รู้ว่าผิดที่การแก้ไขตรงไหน, ทำให้ commit ของเราไม่ clean กลายเป็น commit ที่ทำหลายอย่างไป และหลายๆครั้งที่สิ่งที่หลุดไปแก้มันยากเกินที่จะทำให้เสร็จในเวลาอันสั้น กลายเป็นครึ่งๆ กลางๆ ไม่สามารถถอยกลับได้ และถ้าไม่ระวังตัวให้ดีจะเกิดซ้อนๆๆๆ กันยิ่งยุ่งไปใหญ่
  • คนที่รู้ว่าควรทำอะไร แต่ไม่ทำหรือไม่เห็นความสำคัญที่จะทำ พูดด้วยยากกว่าคนที่ไม่รู้เยอะ
  • คนชอบทำเผื่อ “เดี๋ยวก็ได้ใช้”, “มันจะได้ยืดหยุ่น” ก็พูดด้วยยากเหมือนกัน
  • คนที่ชอบเขียน production code ก่อน test code เมื่ออยากรู้ functionality ใดๆ ก็จะไปเปิด code ดูก่อนเสมอ ทำให้ไม่เห็นความสำคัญของการเขียน test code ให้อ่านรู้เรื่อง เราควรเขียน test code ให้เราอยากอ่านเวลาต้องการรู้ functionality มากกว่า production code

แถมสิ่งอื่นๆ ที่ได้ ระหว่างการ pair

  • เราควร give point ให้ task เมื่อรู้แล้วเท่านั้นว่าต้องทำอย่างไร ให้ task นี้เสร็จ ถ้าไม่สามารถรู้ได้ อาจจะเป็นสัญญาณบอกว่า task นั้นใหญ่เกินไปต้องหาทางหั่นลงมาอีก
  • การเขียน test code หลัง production code มักทำให้เกิด production code ที่ทำงานเกินความต้องการเสมอ