[บันทึกการอ่าน] Continuous Integration

KakyKad
4 min readDec 17, 2019

--

ห่างหายจากการเขียนไปนาน ได้มีโอกาสได้อ่าน Continuous Integration ของ Martinfowler ที่เขียนเอาไว้ (โดย assign ให้อ่านมาอีกที 555) โดยแบ่งเนื้อหาออกเป็นดังนี้

อ่านและแปลคร่าวๆ ตามความเข้าใจของคนเขียนนะฮะ ^^

Continuous Integration คือ

การที่สมาชิกในทีม (developer) มีการ integrate ร่วมกันบ่อยๆ แต่ละคนต้อง integrate กันวันละอย่างน้อย 1 ครั้ง (พยายามทำให้เกิดหลายครั้งต่อวัน) ซึ่งในการทำ integrate แต่ละครั้งจะต้องถูก verify ด้วย automate build และ test และถ้าเจอปัญหาให้ทำการแก้ไขโดยทันที

Martin ได้เล่าถึงประสบการณ์ของเขาว่าโปรเจคที่ทำการ integrate กันช้า จะทำให้ใช้เวลานานและคาดเดาไม่ได้ในการทำ integrate ในแต่ละครั้ง

ดังนั้นจึงควรเปลี่ยนการ integrate จากกิจกรรมให้เป็น “ทุกครั้ง” ที่ developer ทำงานเสร็จจะต้องรวมงานกัน เพื่อจะได้ใช้เวลาไม่นานในการรวมโค้ดและการพบปัญหาที่เกิดขึ้นระหว่างการ integrate ตั้งแต่ตอนทำงาน ซึ่งควรจะฝึกฝนให้ทุกคนในทีมรวมงานกันบ่อยๆ กับ repository ตรงกลาง อย่างน้อยวันละครั้ง

Building a Feature with Continuous Integration

วิธีง่ายที่สุดที่จะทำความเข้าใจว่า Continuous Integration คืออะไร?

ให้นึกถึงเวลา develop นั้นจะต้องทำ

  1. Pull code ลงมาที่เครื่องของตัวเอง (local environment) ผ่านทาง source code management system
  2. ทำงานตาม task ของตัวเอง (แก้ไข source code และเพิ่ม/เปลี่ยน code และชุด test)
  3. เมื่อทำเสร็จให้ build source code ตัวเองและ run test จะต้อง pass 100% “บนเครื่อง local” [compile > execute > run automated test] และถ้าเกิด run test แล้วเกิดพังให้แก้ไขทันทีก่อนที่จะ commit code ของเราขึ้นไป
  4. เมื่อ build และ test ไม่มี errors เป็นสัญญาณที่บอกว่างานของตัวเองนั้นเสร็จแล้ว
  5. Commit สิ่งที่ทำไปให้ชัดเจนใน repository ของ project นั้น

ในบางครั้งอาจจะมีคนอื่นทำการเปลี่ยนแปลง mainline ไปก่อนแล้ว เราต้องทำการ update กับ source code ปัจจุบัน และทำกระบวนการ automated build ใหม่อีกครั้ง เพื่อเช็คว่าของที่คนอื่นแก้รวมกับของเราแล้วไม่พัง หากเกิด failure ขึ้นภายในเครื่องตัวเองเป็นหน้าที่ของเราที่ต้องแก้ไขให้ผ่าน

6. หลังจากที่ build ล่าสุดของเราเป็นปัจจุบันแล้ว จึง commit ขึ้นไปยัง mainline (repository)

เราอาจจะทำการ build อีกครั้งด้วย build server เพื่อให้มั่นใจว่าสิ่งที่แก้ไปนั้นเสร็จสิ้น เป็นการเช็คอีกครั้งว่าเราไม่มีอะไรที่ยังไม่ได้เอาขึ้น repository ซึ่ง build server อาจจะเป็น manual หรือ automated ก็ได้

Practices of Continuous Integration

Maintain a Single Source Repository

ใน Software ประกอบไปด้วย file จำนวนมากที่ทำงานร่วมกัน การติดตามการแก้ไขของแต่ละ file จึงเป็นเรื่องสำคัญ ทั้งนี้เราจะใช้เครื่องมืออะไรก็ได้ ขอแค่ในเครื่องมือนั้นทำให้มั่นใจได้ว่ามีที่เก็บที่ทุกคนสามารถเข้าถึงได้และจัดการ source code และพัฒนาภายใต้ repository หลักเพียงอันเดียว โดยรวมไปถึง source code management ด้วย ยกตัวอย่าง ภายในทีมสามารถหาที่อยู่ของโค้ดฟังก์ชั่นใดฟังก์ชั่นหนึ่งโดยที่ไม่ต้องถามและสามารถช่วยลดค่าใช้จ่ายที่ไม่จำเป็นออกไป

แต่ก็มีไม่น้อยที่บางทีมจะใช้ repository แบบผิดๆ ไม่เอาทุกอย่างขึ้น repository เช่น test scripts, properties files, database schema, install scripts, 3rd library รวมถึง IDE config ไว้สำหรับเป็น convention ของทีม

กฎง่ายๆ ที่ควรจะเป็นคือ หากมีคนใหม่เข้ามาทำงาน จะต้องสามารถ clone ลงมาที่เครื่อง และสามารถ build ในเครื่องได้เลย

ในท่ีน้ีสามารถแบ่งแยก Branche ออกมาเพื่อการพัฒนาท่ีมีแนวทางแตกต่างกันได้ เช่น แก้ bug, ทำการทดลองต่างๆ เป็นต้น แต่ควรมีให้น้อย ภายใต้ Mainline (Single Branch) โดยทุกคนใช้ทำงานร่วมกัน

Automate the build

การแปลงจาก source code เป็น running system อาจมีความซับซ้อน มีหลายขั้นตอนที่ต้องทำ จะทำอย่างไรให้เราสามารถทำให้มันเป็น automated ได้ และไม่ควรจะมีใครต้องพิมพ์หรือกดอะไรให้เสียเวลา โดยสามารถนำมารวมกันเป็น script ชุดเดียวที่รวมทุกคำสั่งและเวลาใช้งานก็พิมพ์แค่ command เดียว

ทุกคนต้องสามารถ pull code ลงมาในเครื่องและรัน 1 command เพื่อให้เกิด running system บนเครื่อง local ได้ ซึ่ง build script ที่เขียนก็สามารถเป็นอะไรก็ได้ แล้วแต่ platform

Make your Build Self-Testing

การ build หมายถึง การ compiling ทั้งหมดที่จำเป็นสำหรับการเรียกใช้โปรแกรม (โปรแกรมอาจจะทำงาน แต่ไม่ได้หมายความว่าทำงานถูกต้องเสมอไป)

วิธีที่จะตรวจจับ bugs ได้อย่างมีประสิทธิภาพและรวดเร็วคือ ใส่ automated tests ไปใน build process

การ test นั้นไม่ได้มาเพื่อช่วยหา bug ทั้งหมด แต่มันก็ช่วยได้เป็นอย่างมาก ซึ่งการใช้ Extreme Programming (XP) และ Test Driven Development (TDD) ช่วยในการพัฒนาตั้งแต่การออกแบบลงมา ส่งผลให้คนเห็น value ของการทำ Self-Testing มากขึ้น

การทำ self-testing จะต้องมี automate test ที่สามารถตรวจสอบ code base เพื่อหา bugs จากการ test ได้ ซึ่ง tests จะต้องสามารถทำงานได้ด้วยจาก command เดียวและเช็คได้ด้วยตัวมันเอง (self-checking) และเมื่อผลของการ run test suite พบว่ามี test ใด test หนึ่ง failed จะถือว่า build นั้น fail

การมี test ไม่ได้การันตีว่าจะไม่มี bugs เราไม่สามารถคาดหวังกับ test ทั้งหมดที่พบได้ แต่การมี test รันบ่อยๆ ย่อมดีกว่าการไม่เขียนเทสอยู่แล้ว การเริ่มมี unit test นับว่าเป็นการเริ่มต้นที่ดี แต่ต้องดูส่วนอื่นๆ ด้วย เช่น end-to-end-testing

Everyone Commits To the Mainline Every Day

การทำ Continuous Integration นั้นเป็นเรื่องเกี่ยวกับการสื่อสาร การ integrate ช่วยให้ development คุยกันในทีมถึงการเปลี่ยนแปลงที่เกิดขึ้น (การสื่อสารเป็นประจำทำให้ทุกคนรู้ได้เร็วเมื่อมีการเปลี่ยนแปลง)

ซึ่งก่อนที่จะ commit ขึ้น mainline (อย่างน้อยวันละครั้ง) นั้นจะต้อง run test ก่อนทุกครั้งว่ายังทำงานได้ถูกต้อง หากผ่านแล้วถึงจะเอางานขึ้นไปที่ mainline และยิ่งทำบ่อยๆ จะทำให้คนในทีมเจอปัญหาและแก้ conflict ได้อย่างรวดเร็ว

การ commit บ่อยๆ ก่อให้เกิดการ break down งานออกมาเป็นชิ้นเล็กๆ ที่ใช้เวลาไม่กี่ชั่วโมงในการทำ และช่วยให้ track process ได้ง่าย และสามารถประเมินได้อีกว่างานจะเสร็จภายในไม่กี่ชั่วโมงได้

Every Commit Should Build the Mainline on an Integration Machine

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

ดังนั้นการมี integration machine จะช่วยให้คุณตรวจสอบได้ว่า build ไม่มีปัญหาเวลามีคน commit ขึ้น ซึ่งเป็นหน้าที่ของ developer คนที่ commit ขึ้นไปในการดู mainline ว่า build ผ่านหรือไม่ ถ้ามัน fail ก็ต้องยอมรับผลของมันและรับผิดชอบแก้ไขให้มันผ่าน (คุณไม่ควรกลับบ้านจนกว่า machine build นั้นจะผ่าน)

ซึ่งเราสามารถทำได้ 2 วิธี คือ แบบ manual กับ automate build

  1. แบบ Manual developer ไปที่เครื่อง integration แล้วสั่ง checkout code ลงมาแล้วสั่ง build ดูจนกว่า build นั้นจะเสร็จสิ้น
  2. แบบ Automate build จะทำการ monitor ของใน repository ทุกครั้งที่มีการ commit มาที่ repository ให้อัตโนมัติและแจ้งเตือน development

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

Fix Broken Builds Immediately

ส่วนสำคัญในการทำ Continuous Build คือ ถ้า machine build fail จะต้องแก้ไขทันที

nobody has a higher priority task than fixing the build — Kent Beck

บ่อยครั้งวิธีที่เร็วที่สุดในการแก้ไข คือ revert กลับไปที่ commit ที่ mainline ล่าสุดเพื่อให้ระบบกลับไปใช้งานได้ และไป debug ปัญหาในเครื่อง local ของตัวเอง

Keep the Build Fast

จุดประสงค์หลักของการทำ Continuous Integration คือ Rapid feedback การ build ที่นานทำให้ได้ feedback ที่ช้า ซึ่งคอขวดที่เกิดขึ้นส่วนใหญ่จะอยู่ที่ testing โดยเฉพาะ ที่ต้องไปเชื่อมกับ external service เช่น database

Step ที่สำคัญอย่างหนึ่งคือ การ set up deployment pipeline คือ การทำ multiple builds done in sequence ซึ่งมี 2 stage ได้แก่

  1. run test (unit test + test double) run เสร็จได้ใน 10 minutes
  2. run service + real database แล้ว run different suite of tests ที่มีรายละเอียดของ end-to-end behavior ซึ่งควรจะเสร็จได้ใน 1–2 ชั่วโมงในการรัน

แต่ถ้าเกิดการ fail ที่ stage ที่ 1 ให้หยุดและแก้ไขทันทีไม่ต้องไปต่อที่ stage ที่ 2

Test in a Clone of the Production Environment

วัตถุประสงค์ของการทำ test ก็คือเพื่อลดปัญหาที่จะเกิดขึ้นที่ production หาก environment ที่เราทดสอบไม่เหมือนกับ production อาจมีความเสี่ยงที่สิ่งที่ทดสอบ ดังนั้นจึง set up test environment ให้เหมือน production environment ให้เหมือนมากที่สุด รวมถึง IP, port และ hardware

Make it Easy for Anyone to Get the Latest Executable

การจัดเก็บ software version ล่าสุด เพื่อให้ทุกคนที่เกี่ยวข้องสามารถมาเอา version ล่าสุดมาใช้งานได้ (ดึง latest version ที่ผ่าน test แล้ว)

Everyone can see what’s happening

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

สิ่งสำคัญของการทำ state ของ mainline build คือ จะต้องรู้ว่าสถานะสุดของ mainline ว่าคืออะไร เช่น สีแดงสำหรับ fail และเขียวสำหรับ success

Automate Deployment

ในการทำ Continuous Integration จำเป็นต้องมีหลาย environment สำหรับ run & test หากสามารถทำให้เกิด executable แต่ละ environments ได้หลายครั้งต่อวัน script เป็นสิ่งที่ช่วยได้และสามารถ deploy application ไปที่ environment ไหนก็ได้และหากได้ script ในการ deploy production แล้ว อาจจะไม่ต้อง deploy บน production ทุกวันและยังช่วยเพิ่มความเร็วและลด errors ที่เกิดขึ้นได้

สิ่งที่ต้องคำนึงหลังจากทำ automate deploy คือ automated rollback เพื่อลดความยากในการ deploy ลงและเพิ่มความกล้าในการ deploy ให้กับทีมมากขึ้นในการ deploy บ่อยๆ

Benefits of Continuous Integration

ถ้าทำ integrate กันช้า อาจจะทำให้เกิดความยุ่งเหยิงและเกิดข้อบกพร่องของ software การทำ Continuous Integration ไม่ได้แค่กำจัดข้อผิดพลาดอย่างเดียว แต่ทำให้ง่ายต่อการค้นหาและแก้ไขข้อผิดพลาดและสามารถ debug ด้วยการ diff version ก่อนหน้าและปัจจุบันได้

Introducing Continuous Integration

  • การเริ่มทำ CI ไม่จำเป็นต้องเริ่มทำทุก practices พร้อมกัน หยิบไปทำทีละอย่างก็ได้ (ไม่มีสูตรสำเร็จ)
  • เริ่มทำ automate build และ automate testing
  • ลดระยะเวลา build ซึ่งควรจะจบการ build ภายใน 1–2 ชั่วโมง แต่ถ้าเป็นไปได้ควรจะภายใน 10 นาที
  • ถ้าเริ่มโปรเจ็คใหม่ ให้เริ่มใส่ CI ไปตั้งแต่เริ่ม และคอยดูระยะเวลาที่ใช้ในการ build ไม่ให้เกิด 10 นาที

Reference : https://martinfowler.com/articles/continuousIntegration.html

Credit ร่วมกันแปล : SEAL Team

--

--

KakyKad
KakyKad

Written by KakyKad

เขียนไปเรื่อย

Responses (1)