Gitflow vs Trunk Based Development vs GitHub flow
ต่อจาก ตอนที่แล้ว ที่ Tech Giant เจ้าใหญ่ๆ ใช้ Monorepo และ Trunk Based Development คราวที่แล้วเราคุยเรื่อง Monorepo ไปแล้ว คราวนี้ถึงตอนของ Trunk Based Development แต่ผมขอดึง workflow แบบอื่นๆ มาคุยด้วยเลยแล้วกัน
Gitflow นี่แทบจะเป็น standard workflow ของหลายๆ ที่ เลย จุดเด่นของ Gitflow มีดังนี้
- Parallel Development ทีมงานสามารถทำหลายๆ feature พร้อมกัน โดยงานใหม่จะแยกจาก develop เป็น feature branch และจะ merge กลับ develop เมื่องานเสร็จ
- Sandbox งานใน feature branch นึงจะไม่ไปกวนงานในอีก feature branch นึง
- Clean ใน develop จะมี code ล่าสุดที่พร้อมขึ้น production เสมอ feature ไหนยังไม่พร้อมก็ไม่ต้อง merge (เช่น business ยังไม่อยาก release) เมื่อจะทำ staging ก็แยกออกเป็น release branch และเมื่อขึ้น production ก็เอาเข้า master branch
ฟังแล้วก็ดูดี แต่ Gitflow ก็มีข้อเสียดังนี้
- Merge Conflict เพราะ code ใน feature branch บางทีอาจจะใหญ่เกินไป พอมารวมกันใน develop ทำให้เกิดโอกาส conflict มากขึ้น
- Slow Feedback บางทีงานใน branch นึงอาจจะมี side effect กับอีก branch นึง หากแยกกันนานเกินไป เมื่อพบปัญหาอาจจะช้าเกินไป และการมี feature branch เป็นการปิดโอกาสในการทดลอง code ให้ไปอยู่ใน environment อื่นๆ รวมถึง production ซึ่งบางที feature ที่เสร็จแค่บางส่วน เราสามารถเอาไปทดลองกับผู้ใช้ได้
- Refactoring การมี feature branch ทำให้ refactoring ทำได้ยากขึ้น เพราะมีโอกาสสูงที่ทำให้เกิด merge conflict
ตามแนวทางของ Trunk Based Development เราจะมี branch หลักอันเดียว อาจจะเรียกว่า trunk หรือ master ก็ได้ หลักการคือ master, release, hotfix, develop และ feature branch ต่างๆ จะอยู่รวมกันแค่ branch เดียว
ไม่ใช่ว่า Trunk Based Development จะไม่ยอมให้มี branch แต่เราสามารถแยกเป็น release branch เพื่อเป็น version ของ production และในยุคหลังจากมี pull request เราเริ่มจะนิยมทำ short-lived feature branch ที่เป็นงานเล็กๆ ทำแค่คนเดียว ระยะเวลาแค่ 1–2 วัน ได้ แล้วทำ pull request เพื่อเช็ค code quality
ทีนี้เราอาจจะมีคำถามว่าทีนี้งานที่ยังไม่เสร็จล่ะจะทำอย่างไร? แนวทางของ Trunk Based Development แนะนำดังนี้
- Feature Toggles หลักการคือมี switch เปิดปิด feature ถ้ายังไม่เสร็จ ก็ยังไม่ต้องเปิด Feature Toggles เป็น practice ที่ดี เพราะเมื่องานบน production มีปัญหา เราก็สามารถปิด feature นั้นได้ทันที
- Branch by Abstraction ใช้สำหรับการ upgrade ระบบ โดยการเขียน abstraction layer มาคั่น implementation เอาไว้ เมื่อ implementation ตัวใหม่เสร็จ ก็ชี้ไปที่ตัวใหม่ ซึ่งก็ถือว่าเป็น practice ที่ดี เพราะจะทำให้ระบบเรา decouple มากขึ้น
- Strangler Application ใช้สำหรับการ upgrade ระบบ ในกรณีระบบใหม่เป็นคนละ process กับระบบเก่า หลักการก็คือใช้ router เป็นตัวกำหนดว่าคำสั่งไหนไประบบเก่า อันไหนไประบบใหม่ วิธีนี้คล้ายๆ กับ Branch by Abstraction แต่อยู่ใน level ของ process
ยังไงก็แล้วแต่ Trunk Based Development ก็มี Challenge
- Code Health เพราะว่ามีแค่ branch เดียว ดังนั้นมีโอกาสสูง ที่จะมี dev ทำ build พัง หรือทำให้ code run ไม่ได้ และจะกระทบกับทุกคน ซึ่ง Unit tests, Code review, และ CI สำหรับ pull request สำคัญมาก
- Development Cost เทคนิคด้านต้น เช่น Feature Switch และ Branch by Abstraction ไม่ได้มาฟรีๆ ซึ่งก็มี effort ในการ handle เหมือนกัน
- Big changes บางทีการแก้ code แล้วให้เสร็จ 1–2 วันอาจจะเป็นไปได้ยาก แล้วเทคนิค Branch by Abstraction ก็ไม่ได้ตอบโจทย์ทุกสถานการณ์ ทำให้เสียเวลาวางแผนมากกว่าแบบ Feature branch
GitHub flow นี่เป็น simplified version ของ Gitflow แต่ดันไป compatible กับ Trunk Based Development ซะด้วย GitHub flow มองว่าถ้าเราทำ CI/CD เราสามารถยุบ develop กับ master รวมเป็น master อันเดียว และงานต่างๆ ทำที่ feature branch เหมือนเดิม (feature branch จะถือเป็น release branch ด้วย) ซึ่งถ้าสังเกตุ รูปแบบแทบจะเป็นแบบเดียวกันกับ Trunk Based Development ที่มี pull request
GitHub flow ไม่ได้กำหนดว่า feature branch จะมีอายุแค่ไหน เป็นหน้าที่ของทีมตัดสินใจกันเอง โดยมากเราก็จะเน้น short-lived feature branch เพราะว่า review ง่ายและ conflict น้อย แต่ถ้างานใหญ่ๆ ก็ค่อนข้างยืดหยุ่น เช่น งานที่ทำประมาณ 3–5 วัน อาจจะไม่ต้องทำ Feature Toggles ก็ได้ ทำให้จำนวน toggle ลดลงไปเยอะ
เลือก workflow แบบไหนดี?
ถามผม ผมว่า workflow แบบไหนก็ไม่สำคัญครับ เพียงแต่เราเข้าใจว่า workflow ที่ดีประกอบด้วยอะไรบ้าง เช่น
- Short-lived feature branch เราควรแตก task ให้เล็กที่สุด ใช้เวลาทำแค่ 1–2 วัน ซึ่งก็เข้ากับ concept ของ Agile
- Pull request การเช็คคุณภาพก่อน merge เข้า upstream เป็นสิ่งที่สำคัญมาก และทางที่ดีคุณต้องมี CI บน pull request ด้วยว่าถ้า merge ไป build จะพังหรือไม่ unit tests จะผ่านหมดหรือไม่?
- Big changes อันนี้เป็นข้อแตกต่างหลักใน 3 workflow ว่ายอมให้มี big changes มากแค่ไหน แต่หลักการคือ เราควรพยายามแตก big changes ให้ได้ ซึ่งอาจจะใช้ 3 เทคนิคด้านต้น (Feature Toggles, Branch by Abstraction, Strangler Application) เพื่อลดเวลาของ task ใหญ่ให้มากที่สุด
ส่วน detail ที่เหลือ เช่น release จาก branch ไหน fix bugs ที่ branch ไหน ทำ hotfix ที่ branch ไหน อันนี้ผมว่ามันแล้วแต่ project เลยครับ ถ้าต้อง handle หลาย version ก็ Gitflow ถ้า release ถี่ๆ ก็ GitHub flow หรือไม่ก็ Trunk Based Development ก็ได้
จบแล้วครับ หวังว่ามีประโยชน์ลองเอาไปปรับใช้กันได้ครับ