Git branching strategies vs trunk base development ตอนที่ 4

Trunk-Based Development

Chokchai Phatharamalai
odds.team
3 min readFeb 7, 2022

--

Photo by Sebastian Pichler on Unsplash

Trunk-Based Development (TBD) เป็นกลยุทธ์การแตก branch ที่ทุกคนในทีม integrate งานตัวเองเข้าไปใน trunk ที่ทุกคนแชร์กันทุก ๆ วัน โดยที่ trunk จะพร้อม release ตลอดเวลา

ไม่ว่าคนในทีมจะแก้ไขอะไรลงไปใน repository บนเครื่องตัวเองก็ตาม อย่างน้อยต้อง itegrate กลับไปที่ trunk วันละครั้ง การทำแบบนี้บังคับให้ทุกคนในทีมคอยดูและปรับเปลี่ยนตามโค้ดที่เพื่อน ๆ แก้มาอย่างสม่ำเสมอ ซึ่งมักจะนำไปสู่ความร่วมมือในการดูแลทั้งคุณภาพและสภาพของโค้ดปัจจุบันให้อยู่ในรูปแบบที่ทุกคนในทีมโอเคอยู่เสมอ

ใน TBD สามารถแตก branch ได้นะ เช่น release branch อายุสั้น ๆ ที่ใช้ release product หรือสมาชิกของทีมอาจจะสร้าง feature branch บนเครื่องตัวเองก็ไม่ได้ผิดอะไร

พอหลาย ๆ ทีมให้ความสำคัญกับ Continuous Delivery และ DevOps มากขึ้นเรื่อย ๆ จนบางทีมนับว่า practice เหล่านี้เป็นสิ่งที่ขาดไม่ได้ในการพัฒนาเลยด้วยซ้ำ ทำให้ TBD ที่ถูกออกแบบล้อมาตาม practice เหล่านี้ได้รับความนิยมตามไปด้วย จริง ๆ ต้องบอกว่า TBD เป็นสิ่งจำเป็นในการทำ Continuous Integration และ Continuous Develivery ด้วยซ้ำ

ต่อไปเรามาดูประโยชน์ของ TBD ที่ feature branch ไม่มีกัน

เป็น continuous integration ที่แท้ทรู

TBD ออกแบบกระบวนการพัฒนาโดยมี Continuous Integration เป็นแก่นและให้ความสำคัญกับมันก่อนเรื่องใด ๆ ถ้าทีมไหนเลือกทำ TBD เรียกว่าไม่สามารถหลีกเลี่ยง Continuous Integration ได้เลย ถ้าไม่ฉีกข้อตกลงของการทำ TBD

เพียงแค่คิดว่าจะต้อง integrate โค้ดทุกวัน ก็ทำให้เราต้องเปลี่ยนวิธีคิด วิธีทำงานร่วมกันกับคนในทีมใหม่แล้ว และการ integrate กันอย่างสม่ำเสมอก็เป็นจุดเริ่มต้นของการพัฒนาในจังหวะที่รวดเร็วขึ้น

change ขนาดเล็ก

การจะ integrate ทุกวันได้นั้น มันทำให้เราต้องเดินก้าวเล็ก ๆ การจะรื้อทั้งระบบ แก้ทีละหลาย ๆ ไฟล์ก็ทำไม่ได้อีกต่อไป มันบังคับให้เราแบ่งงานที่เราทำเป็นขั้นตอนเล็ก ๆ หลาย ๆ ขั้น และแต่ละขั้นจะต้องทำให้ product ของเรายังอยู่ในสภาพที่พร้อม release เช่นเดิม ซึ่ง change เล็ก ๆ เหล่านี้มีโอกาสที่จะทำ production ไฟลุกน้อยกว่า

แตก branch ด้วย abstraction

แม้ว่าหลายคนจะเห็นด้วยกับประโยชน์ 2 ข้อบนแบบไม่มีข้อโต้แย้ง แต่ในชีวิตจริง บางครั้งเราก็เจอความเปลี่ยนแปลงที่มันทำแบบ 2 วิธีบนไม่ได้ เพราะมันต้องแก้กันเกิน 1 วัน ณ ตอนนั้นเราจะเจอตอว่า มัน integrate ทุกวันไม่ไหวจริง ๆ ในโลกของ TBD เราจะใช้เทคนิค branch ด้วย abstraction ซึ่งจะช่วยให้เราสามารถ integrate โค้ดกันทุกวันได้ แม้ว่า feature นั้นตอนแก้กันหลาย ๆ วัน

ใน TBD เราจะเริ่มจากหาจุดที่เราต้องแก้ไข แล้วเราจะหารอยต่อที่เราสามารถ toggle logic ได้ (if-else นั่นแหละ) แล้วเราก็จะเพิ่ม interface หรือ component ใหม่เข้าไปตรงรอยต่อนี้ หลังจากนี้เราก็จะ integrate โค้ดที่เราแก้ไขเข้าไปใน trunk ได้ (เอาไป deploy ได้ด้วยนะ) เพียงแต่ว่าโค้ดที่เราเพิ่มเข้าไปจะยังไม่ถูกใช้งาน พอเราทำงานเสร็จ เราก็แก้ toggle ให้มาใช้โค้ดใหม่ของเรา แล้วก็ลบของเก่าทิ้ง เทคนิคนี้เรียกว่าแตก branch ด้วย abstraction (เราใช้หลักการ abstraction มาแตก branch ของโค้ด แทนที่จะใช้ branching ใน Git)

Feature flags

พอเราใช้ท่า branch ด้วย abstraction จนคล่องแล้ว เราก็เริ่มเห็นโอกาสว่าบางครั้งเราอยากให้มีโค้ดที่ถูก deploy ขึ้นไปด้วย เช่น ใน test environment แต่ยังไม่แสดงผลใน production environment หรือ อาจจะให้ user กลุ่มเล็ก ๆ บน production เห็นก่อน (บางทีเรียกว่า canary release) ส่วน user ที่เหลือยังไม่เห็น ซึ่งเราสามารถใช้ท่า branch ด้วย abstraction ได้ แต่การ config environment เหล่านี้ใน source code มันยุ่งยากและไม่ยืดหยุ่นเลย

แทนที่จะทำแบบนั้น เราก็ใช้ท่า feature flag ซึ่งเป็นการย้ายการควบคุมตัวแปรเหล่านี้นอก source code เช่น ใน config file, ใน database หรือ service เป็นต้น การทำแบบนี้ทำให้แยกการ release ออกจาก code base ของเราได้ เราสามารถ deploy code ขึ้นไปบน production แต่ปิดไว้ก่อน ยังไม่ให้ user เห็นได้ การทำ feature flag เลยลดความเสี่ยงตอนทำ Trunk-Base Development ได้

เดี๋ยวเรามาดูกันว่ารูปแบบที่เค้าใช้ Feature flags มีเสริม Trunk-Based Development นั้นมีแบบไหนบ้าง

Flag สำหรับ Development เท่านั้น

วิธีใช้ feature flag ที่เห็นบ่อยสุดคือใส่ flag ให้มันแสดงผลใน development environment เท่านั้นเพื่อให้การทดสอบง่ายขึ้น แต่ปิด feature เหล่านี้บน production

จากกฎของ TBD ที่บอกว่า trunk ต้องอยู่ในสภาพที่พร้อม deploy ขึ้น production อยู่เสมอ อย่างไรก็ดี เราต้องแยก deploy (เอาโค้ดของ feature ใหม่ขึ้นไปวาง) กับ release (เปิด feature ใหม่ให้ user ใช้งานเห็น) ออกจากกัน ท่าที่เราเห็นคนทำบ่อย ๆ คือแตก branch ด้วย abstraction ก่อน แล้วให้ build system เป็นคนกำหนด toggle ว่าจะ release อะไรบ้างบน non-production environment และปิดมันบน production

พอใช้ build system ทำแบบนี้เราก็จะมั่นใจได้ว่าเราจะไม่หลุดปล่อยของไปบน production ก่อนเวลา

ใช้ flag ทำ deployment gatling

พอใช้ feature flags แยกของที่จะปล่อยบน non-production environment กับ production environment จนชำนาญแล้ว ขั้นต่อไปคือใช้เทคนิคนี้ค่อย ๆ ปล่อยของบน production ทีละนิด ๆ

ยกตัวอย่างเช่นการทำ canary release ซึ่งคือการ release ให้คนภายใน หรือว่ากลุ่ม pilot หรือกลุ่ม user ในบางพื้นที่ลองเล่น version ใหม่ก่อน ถ้าทุกอย่างราบรื่นดี ก็ค่อยเปิดให้ user กลุ่มอื่น ๆ ได้เล่นบ้างจนกระทั้ง user ทั้งหมดได้เล่น version ใหม่

ความยากคือการค่อย ๆ เปิด feature flag เพื่อให้คนเห็นทีละนิด และการจะจัดการกับ flag เหล่านี้แบบไม่ถึกมากนี่แหละ การมานั่งแก้ build system ให้เปิด/ปิด feature ตามต้องการน่าจะเหนื่อยมาก และแม้บางทีมจะคิดว่าตัวเองพัฒนา feature flag system ไหว แต่เค้าก็ไม่ควรทำ เพราะมันทำให้เค้าหลุดโฟกัสไปจากความชำนาญในโดเมนหลักของงานพวกเค้า คำแนะนำคือถ้าทีมอยากใช้ feature flag system ให้ระดับ advance เบอร์นี้ ให้เลือกหาเครื่องมือที่มี feature flag system as a service มาใช้

LaunchDarkly (ขายของ)

ย่อหน้าสุดท้ายนี้ผมสรุปว่าเป็นย่อหน้าขายของจากบทความต้นฉบับเลย แต่เพราะผมเห็นแก่ที่บทความต้นฉบับให้ความรู้ที่เป็นประโยชน์กับผม ผมจะแปลท่อนนี้ให้ด้วยแม้จะไม่ได้ค่าคอมฯก็ตาม :P

LaunchDarkly เป็นให้บริการเรื่อง feature flag management ซึ่งทำให้คุณสามารถทำ TBD และใช้ feature flag ได้ในทุกแบบที่คุณต้องการ

LaunchDarkly รองรับหลาย ๆ องค์ประกอบที่จำเป็นในการ release ของในระดับองค์กร เช่น ตั้ง schedule ในการ release, ตั้งให้มีการ approve release ได้, ตั้งให้ feature flags สามารถปรับเปลี่ยนได้ตามปัจจัยภายนอกหรือเงื่อนไขเหตุการณ์ต่าง ๆ เป็นต้น สรุปแล้ว LaunchDarkly ช่วยให้คุณพลิกแพลงการใช้ feature flag ได้อย่างพลิกแพลงหลากหลาย ถือเป็นเครื่องมือสำคัญในการขับเคลื่อน TBD เลยก็ว่าได้

สรุป

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

Trunk-based development เป็นวิธีที่ดีที่สุดที่ช่วยเพิ่มคุณภาพโค้ดผ่านความร่วมมือกันภายในทีมและ continuous integration ที่แท้ทรู

LaunchDarkly ยกระดับ TBD ไปอีกเวลด้วย dynamic release ทำให้มองไม่เห็นรอยต่อระหว่างของที่กำลังพัฒนาและของที่เสร็จสมบูรณ์แล้ว

บทความที่เกี่ยวข้อง

--

--