สรุปสิ่งที่ได้จากการอ่านและพูดคุยกับพี่ปุ๋ยเรื่อง Continuous Integration

สรุปสิ่งที่ได้จากการอ่านและพูดคุยกับพี่ปุ๋ยเรื่อง Continuous Integration

เนื้อหาต่อไปนี้คือสิ่งที่ได้จากการอ่านจากหนังสือ Continuous Integration: Improving Software Quality and Reducing Risk และการพูดคุยกับพี่ปุ๋ยครับ

ทุกอย่างต้องมาด้วยสาเหตุก่อนครับ เคยไหมครับที่เราต้องเจอสถานการแบบนี้ในโลกของการพัฒนาซอฟแวร์

  • โปรแกรมที่เราเขียนมา ทดสอบของเราเรียบร้อยแล้ว แต่พอไปรวมกับคนอื่นไหงมันพัง?
  • เขียนโค๊ดเสร็จแล้วไม่กล้า merge เพราะกลัวพัง ดังนั้นเราก็ต้องมีเผื่อเวลาช่วงท้ายไว้ในการรวมโค๊ดซิ…
  • บนเครื่องเราก็ใช้ได้ แต่ทำไมพอ deploy ขึ้นแล้วมันพัง?

นี่คือปัญหาคลาสสิคที่แทบทุกคนต้องเคยเจออย่างน้อย 1 ข้อ ปัญหามันจะไม่เกิดถ้าเรา… รวมโค๊ดกันแต่เนิ่น ๆ (Early) และ บ่อยขึ้น (Often) เพื่อที่ทำให้เรา รู้ผลเร็วขึ้น (Fast feedback) ว่ามันทำงานได้ไหม พยายามหาวิธีในการ ลดความเสี่ยง (Reduce risks) ของขั้นตอนการ deploy

เมื่อพูดถึงความเสี่ยงแล้ว ต่อไปนี้คือความเสี่ยงที่มักเกิดขึ้นในการพัฒนาซอฟแวร์

  1. Lack of deployable software — ปัญหาที่ไม่สามารถจัดการให้ซอฟแวร์ของเราพร้อมในการนำไป deploy ได้โดยรวดเร็ว, ง่าย และ ถูกต้อง ผลที่ตามมาคือจะเกิดปัญหา อาทิ ซอฟแวร์ชุดนี้สามารถทำงานบนเครื่องนักพัฒนาได้แต่มีปัญหาบน production จริง, ข้อมูลแสดงผลไม่ตรงกันในแต่ละ environment ทำให้ตรวจสอบความถูกต้องไม่ได้, เกิดความผิดพลาดจากขั้นตอนของการติดตั้งของผู้ติดตั้งเอง เช่น ลืมวิธีการ ทำให้ข้ามขั้นตอนไป
  2. Late discovery of defects — พบปัญหาต่าง ๆ ช้า กว่าจะเจออาจจะไปถึง production แล้ว ซึ่งอาจจะทำให้เกิดผลกระทบที่รุนแรงตามมาได้
  3. Project visibility — ทีมพัฒนาส่วนใหญ่ไม่ทราบว่าตอนนี้ภาพรวมของระบบสถานการณ์เป็นเช่นไร ดี หรือ แย่ มีจุดไหนต้องแก้ไขปรับปรุงให้ดีขึ้นไหม เพราะไม่มีการถูกนำเอาออกมา visualize ให้คนที่เกี่ยวข้องเข้าถึงได้ง่าย
  4. Low quality software — สามารถเปรียบเสมือนสุขภาพของเราที่ไม่ผ่านการตรวจอย่างเป็นประจำ เมื่อคุณภาพของซอฟแวร์ไม่ถูกหยิบยกมาดูอย่างสม่ำเสมอ ขาดผู้ที่จะมาสนใจในเรื่องนี้ซึ่งจะส่งผลให้เกิดปัญหาในอนาคตได้

พักเรื่องความเสี่ยงไว้ก่อนครับเดี๋ยวเราค่อยมาดูกันว่า CI มาช่วยลดความเสี่ยงเหล่านี้ยังไงบ้าง

คำว่า CI นั้นย่อมาจาก Continuous Intregation ถ้าแปลตรงตัวคือ การนำเอาของมารวมกันอย่าง เรื่อย ๆ และ สม่ำเสมอ

ถ้าเราลองดูจากรูปด้านซ้ายประกอบน่ะครับ นี่คือการยกตัวอย่างการทำงานทั่วไปของทีมพัฒนา เริ่มเต้นการพัฒนานั้นก็ต้องเกิดจากการที่

  • นักพัฒนาดึงโค๊ดมาจากตรงส่วนกลางที่นักพัฒนาคนอื่น ๆ ใช้ร่วมกัน
  • ทันทีที่ได้พัฒนาเรื่องนั้นเสร็จแล้ว นักพัฒนาคนนี้ก็ทำการนำเอาโค๊ดขึ้นมารวมไว้ตรงกลาง (commit & push)
  • ตรงนี้ล่ะครับ ให้ลองนึกภาพว่าจะมีหุ่นยนต์คอยตรวจสอบว่าโค๊ดที่อยู่ตรงกลางมีการเปลี่ยนแปลงไหม ก็จะทำการดึงมาตรวจสอบ
  • จากนั้นก็ทำกระบวนการสร้างแพคเกจซอฟแวร์ออกมา อาจจะประกอบด้วยรายงานสรุปผลการทำงาน เพื่อที่จะทำการแจ้งผล (Feedback) กลับไปหาทีมพัฒนาว่าเรียบร้อยแล้ว หรือ ไม่สำเร็จเพราะเหตุผลอะไร

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

ดังนั้นหัวใจหลักของ CI คือ แนวคิดของการนำเอางานที่ทีมพัฒนาทำมารวมกันอย่าง เรื่อย ๆ และ สม่ำเสมอ เพื่อนำมาตรวจสอบทำให้ได้ Feedback ที่รวดเร็ว

ตอนนี้เราน่าจะพอเห็นภาพคร่าว ๆ แล้วน่ะครับว่า CI คืออะไร เราลองมาดูต่อไปที่คุณค่า (Value) ที่จะเกิดขึ้นเมื่อเรานำเอาแนวคิด CI มาใช้ ซึ่งมีดังนี้

  • ลดความเสี่ยงที่กล่าวมาข้างต้น เนื่องจากมีการนำเอาซอฟแวร์มารวมกันสม่ำเสมอ ทำให้สามารถตรวจสอบได้ ทราบผลได้ไว แก้ปัญหาได้เร็วไม่ต้องรอลุ้นหวยออกตอนท้าย ๆ เรียกว่าเจ็บบ่อย ๆ และเจ็บเนิ่น ๆ จากแต่ก่อนที่จะไปเจ็บหนักตอนท้าย อีกทั้งในทุกการเปลี่ยนแปลงเราสามารถติดตามได้ ทำให้ทราบที่มาที่ไปว่าเกิดจากอะไร ทำให้ทราบสถานการณ์ของภาพใหญ่ด้วยว่าตอนนี้ซอฟแวร์ของเราสุขภาพเป็นอย่างไร ดังนั้นสิ่งสำคัญที่เกิดขึ้นคือทุกขั้นตอนถูกนำเอาออกมาแสดงผลให้ทุกคนสามารถจับต้องได้ ช่วยลดปัญหาการเกิดมโน (assumption) ซึ่งนั่นมักทำให้ปัญหารุนแรงอย่างมาก เช่น ถ้าเราตั้งสมมติฐานเอาเองว่าซอฟแวร์ของเราไม่น่ามีปัญหา เราก็จะหย่อนยานที่จะทดสอบความถูกต้อง
  • ลดการทำงานที่ซ้ำซากจำเจ เนื่องจากแนวคิดของ CI มีการนำเอาหุ่นยนต์เข้ามาช่วยเรากับงานที่ต้องทำซ้ำ ๆ ทำให้เรามีเวลาในการพัฒนาสิ่งต่าง ๆ ให้ดีขึ้นกว่าเดิม
  • เชื่อมั่นใน Product ทุกคนมีความเชื่อมั่นเพราะทุกอย่างมีการตรวจสอบและถูกแสดงผลออกมา เช่น ทีมพัฒนาที่มีความกล้าจะรวมโค๊ดบ่อยขึ้น เพราะถ้ามีปัญหาก็ทราบผลได้และแก้ไขได้ทันท่วงที
  • จัดการซอฟแวร์ให้พร้อม deploy ได้ มีการกำหนดขั้นตอนที่ชัดเจน ทำให้ไม่พลาด และ สามารถเลือกได้ว่าจะนำเอาการเปลี่ยนแปลงใดไปใช้งาน
  • เกิดความโปร่งใส่ เห็นสถานการณ์ปัจจุบัน และ อดีต เพื่อนำเอามาวิเคราะห์หาแนวโน้มมาปรับปรุงให้ซอฟแวร์ดีขึ้นได้

จากการที่เราได้เห็นคุณค่า (Value) นี้ ถ้าลองอ่านดูจะพบว่ามันไม่มีพูดถึงเรื่องของเครื่องมือเลย ดังนั้นสิ่งที่ต้องทำให้เกิดคือต้องเกิดการปฏิบัติ (Practice) ที่จะต้องมีการเปลี่ยนแปลงจากการทำงานในรูปแบบเดิมด้วย ดังต่อไปนี้

  • ทีมพัฒนาต้อง commit code ขึ้นตรงกลางอย่างสม่ำเสมอ อย่างน้อยควรเป็น 1 ครั้งต่อวันให้ได้
  • ทีมพัฒนาต้องไม่ commit code ที่เสียขึ้นไป ซึ่งต้องผ่านขั้นตอนการทดสอบให้เรียบร้อยแล้ว ซึ่งเกิดจากการเขียน automate test script นั่นเอง ยกตัวอย่างเช่น unit test ต้องผ่าน 100% ก่อนถึงนำเอาขึ้นได้
  • ทีมพัฒนาทำการแก้ไขปัญหาทันทีหากเกิดปัญหากับซอฟแวร์ตรงกลาง
  • การเก็บโค๊ดต้องเก็บในที่เดียวที่ทุกคนในทีมสามารถเข้าถึงได้ เพื่อให้ตรวจสอบการเปลี่ยนแปลงได้ทุกการเปลี่ยนแปลง ต้องไม่อยู่กระจัดกระจาย เพราะเราต้องมีการรวมโค๊ด และ นำมาทดสอบกันได้บ่อย ๆ ซึ่งภายในโค๊ดต้องประกอบไปด้วย โค๊ดของซอฟแวร์, Build script และ Database

โดยทั่วไป Build script นี้จะประกอบไปด้วย 6 ขั้นตอนด้วยกัน นั่นคือ เคลียร์ค่าต่าง ๆ ให้พร้อมใช้งานในขั้นตอนถัด ๆ ไป, ขั้นตอนการ Compile, การจัดการเรื่องข้อมูล, ขั้นตอนการ Test, ขั้นตอนการนำเอาโค๊ดมาวิเคราะห์ และ การนำเอาไป deploy

Build = ขั้นตอนของการ Compile / Test / Analysis / Development

สำหรับ Build script นี้ต้องไม่ขึ้นกับเครื่องมือสำหรับพัฒนา (IDE) เช่น eclipse, vscode เป็นต้น เพราะจะเกิดปัญหาตามมาคือ IDE บางตัวอาจจะไม่สามารถนำไปใช้กันกับทุกเครื่องได้ ทำให้ไม่สามารถสั่ง Build script ได้สำเร็จ

  • ทีมพัฒนาต้องออกแบบซอฟแวร์ให้รองรับการแก้ไขค่าต่าง ๆ ของ environtment ต่าง ๆ เนื่องจากปัจจุบันขั้นตอนการพัฒนา จะมี environment หลายขั้น เช่น Development, UAT, Production แต่ละขั้นอาจจะมีการเชื่อมต่อ database คนละที่กัน สิ่งที่ต้องทำให้ได้คือการแยกเอาค่าเหล่านั้นออกมาจากโค๊ดเพื่อให้ง่ายต่อการรองรับการทำงานในรูปแบบนี้ และ Build script ต้องสามารถทำงานได้โดยไม่จำเป็นต้องให้คนเข้ามาเกี่ยวข้องในแต่ละขั้นตอน สำหรับข้อมูลที่น่าสนใจนี้สามารถศึกษาเพิ่มเติมได้จาก https://12factor.net/
  • ทีมพัฒนาต้องร่วมออกแบบและดูแล CI ด้วยตนเอง เพื่อให้สามารถแก้ไขให้ดีขึ้นได้ในอนาคต เพราะ คนที่จะสามารถดูแลได้ดีที่สุดคือคนที่ต้องใช้งานมันอย่างสม่ำเสมอ เพื่อจะได้ทราบจุดที่ควรปรับปรุงต่อไป
  • ทีมพัฒนาต้องให้ความสนใจข้อมูลที่ผ่านการ analysis โดยเครื่องมือ เช่น การนำเอาสิ่งที่ได้จาก report มาวิเคราะห์และปรับปรุงสุขภาพซอฟแวร์ที่ดีขึ้น

เมื่อเราลองมาดูรูปด้านซ้าย นี่คือสิ่งที่เกิดขึ้นเมื่อมีการ commit & push โค๊ดขึ้นตรงกลาง (Single source point) ก็มี CI Server คอยดูว่ามีโค๊ดที่เปลี่ยนแปลงไหม เพื่อนำมาสั่ง Build ตาม build script ที่กล่าวไปข้างต้นจะเห็นได้ว่าเราจะสามารถติดตามได้ว่า Build ชิ้นนี้มาจาก โค๊ดเวอร์ชั่นไหนเพื่อให้ง่ายต่อการจัดการ จากนั้น CI Server จะทำการแจ้ง Feedback กลับไปหาทีมพัฒนาต่อไป

สิ่งที่อยู่ในโค๊ดนั้นไม่ได้มีแค่โค๊ดของซอฟแวร์แต่จะต้องมีครบทุกอย่าง ที่ทำให้ทุกคนสามารถนำเอาไป Build ได้ บนเครื่องต่าง ๆ โดยไม่ต้องมีคนมาเกี่ยวข้องในแต่ละขั้นตอน

สิ่งสำคัญของ CI อีกอันไม่ควรมองข้ามนั้น คือ Feedback ที่ต้องสามารถให้ข้อมูลอย่าง ถูกต้อง และ รวดเร็ว เพื่อเป็นสิ่งที่จะทำให้ทีมพัฒนานำเอาข้อมูลที่มีประโยชน์นี้มาใช้ประกอบการทำงานต่อไป โดยข้อมูลที่ได้มาก็ต้องเกิดจากการที่ทีมพัฒนากำหนดร่วมกันว่าสิ่งที่ถูกต้อง นั้นคืออะไร เช่น การเขียน automate test script และ การที่ทำให้ซอฟแวร์ของเราดีขึ้นนั้นควรเป็นอย่างไรผ่านการ Review code, Pair programming และมีการหยิบเอาผลจากการที่เราได้จากการวิเคราะห์โค๊ด เพื่อให้ลดเวลายิ่งขึ้น อาทิ การตรวจสอบ Coding standard, Naming convention และ การหาจุดที่เสี่ยงจะเกิด Technical debt ในอนาคต (เราควรลดงานพวกนี้จะได้ไม่เสียเวลามากนัก โดยให้มีการ ทำ automate reviewed มาช่วยในส่วนนี้)

ถ้าเราอยากใช้แนวคิด CI มาใช้กับงานแล้ว… ควรต้องเริ่มอย่างไร? ต่อไปนี้คือ 4 ขั้นตอนที่จะทำให้เกิดได้

  1. Identify — หาให้ได้ว่าตอนนี้เรามีขั้นตอนการทำงานอย่างไร งานในสามารถทำแบบอัติโนมัติได้
  2. Build — ลองวางขั้นตอนต่าง ๆ มาให้อยู่ในรูปแบบที่ทำงานได้โดยอัติโนมัติ ไม่มีคนมาเกี่ยวข้องในแต่ละขั้นตอน
  3. Share — ทุกอย่างที่เรานำมาใช้ หรือ ตั้งขึ้นมา ทุกคนที่เกี่ยวข้องต้องรับรู้ และ สามารถนำเอามาใช้ประโยชน์กันได้
  4. Continuous — ทดลองทำ ไม่ต้องสนใจว่ามันจะต้องเป็นแบบนี้ตลอดไป ถ้าสิ่งไหนลองแล้วเจอปัญหา ลองปรับปรุงประยุกต์ให้มันดีขึ้นเรื่อย

CI = Continuous Integration หรือ ถ้าตีความอีกอันนั่นคือ Continuous Improvement

เมื่อนำเอา CI ไปใช้สิ่งที่จะลดทอนมันไม่ให้สามารถอยู่ได้อย่างยั่งยืนมีดังนี้

  • ต้องมีงานที่ต้องดูแล CI Server / System เกิดขึ้น
  • เกิดการเปลี่ยนแปลงหลายอย่างดังจะเห็นจากการที่ทีมพัฒนาต้องรับผิดชอบมากขึ้นจากเดิม จึงทำให้เกิด CI ได้ ดังนั้นต้องค่อย ๆ ปรับและเปลี่ยนทีละเล็กทีละน้อย
  • มีความผิดพลาดเกิดขึ้นเยอะ ถ้าทีมพัฒนาไม่มีการทดสอบตามที่ตกลงกัน ผลที่ตามมาคือคนอื่น ๆ จะเจอปัญหามากมายตามมา เพราะ ระบบไม่มีใครสนใจที่จะแก้ไขให้มันถูกต้อง
  • มีค่าใช้จ่ายเพิ่มในการตั้ง CI Server / System แต่ค่าใช้จ่ายตรงนี้พร้อมไหมถ้าจะแลกกับการที่ต้องเสียไปในตอนท้ายเพื่อมาแก้ไขปัญหาทีหลัง
  • ทีมพัฒนาต้องรับหน้าที่นี้ หากเกิดความไม่เข้าใจ และ ไม่ยอมทำตามที่ตกลงกันก็จะไม่สามารถเกิดสิ่งเหล่านี้ได้เลย

สรุป

CI ไม่ใช่การมุ่งไปที่หาเครื่องมือ แต่คือการที่เรา ทีมพัฒนาต้องพูดคุยกันเพื่อมาดูว่าตอนนี้เรามี work flow การทำงานอย่างไรอยู่ จะเอาเครื่องมือเข้ามาช่วยตรงจุดไหนได้บ้าง วิธีไหนที่จะทำให้เราได้รับ Feedback ที่เร็วขึ้น เพื่อที่เราจะได้มีการแก้ไขปรับปรุงให้ดีขึ้นได้

ระวังการเกิดเหตุการณ์ที่ คนทำไม่ได้ใช้ คนใช้ไม่ได้ทำ ผลสุดท้ายแล้ว คุณค่าของ CI จะค่อย ๆ ถูกบั่นทอนลงทีละเล็กทีละน้อยจากคนที่ไม่ได้ทำ แต่เป็นคนที่ใช้

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