Feature Toggles(หรือที่มักเรียกกันว่า Feature Flags) เป็นเทคนิคที่ทรงพลังซึ่งช่วยให้ทีมสามารถปรับเปลี่ยนพฤติกรรมของระบบได้โดยไม่ต้องแก้ไข code เทคนิคนี้แบ่งออกได้เป็นหลายประเภทตามลักษณะการใช้งาน ซึ่งการเข้าใจประเภทเหล่านี้เป็นสิ่งสำคัญมากในการนำไปปรับใช้และจัดการ Toggles นำมาซึ่งความซับซ้อน แต่เราสามารถควบคุมมันได้ด้วยการเลือกวิธีระบุตัวแปร (implementation) ที่ชาญฉลาดและการใช้เครื่องมือที่เหมาะสมในการจัดการการตั้งค่า (configuration) นอกจากนี้ เราควรพยายามจำกัดจำนวน Toggles ในระบบให้เหลือน้อยที่สุดเท่าที่จะเป็นไปได้

09 ตุลาคม 2017

Pete Hodgson

Pete Hodgson เป็นที่ปรึกษาอิสระด้านการส่งมอบ software ที่อาศัยอยู่ในแถบ Pacific Northwest เขาเชี่ยวชาญในการช่วยทีมวิศวกรรมของสตาร์ทอัพปรับปรุงแนวปฏิบัติทางวิศวกรรมและสถาปัตยกรรมทางเทคนิค

ก่อนหน้านี้ Pete ใช้เวลาหกปีเป็นที่ปรึกษาที่ Thoughtworks โดยเป็นผู้นำด้านแนวปฏิบัติทางเทคนิคสำหรับธุรกิจในฝั่ง West Coast และเขายังเคยดำรงตำแหน่ง Tech Lead ในสตาร์ทอัพหลายแห่งในซานฟรานซิสโก


"Feature Toggling" เป็นชุดของรูปแบบ (patterns) ที่ช่วยให้ทีมส่งมอบ function ใหม่ๆ ให้กับผู้ใช้ได้อย่างรวดเร็วแต่ปลอดภัย ในบทความเรื่อง Feature Toggling นี้ เราจะเริ่มด้วยเรื่องราวสั้นๆ เพื่อแสดงสถานการณ์ทั่วไปที่ Feature Toggles มีประโยชน์ จากนั้นเราจะเจาะลึกรายละเอียดเกี่ยวกับรูปแบบและแนวปฏิบัติเฉพาะที่จะช่วยให้ทีมประสบความสำเร็จในการใช้ Feature Toggles

Feature Toggles ยังถูกเรียกในชื่ออื่นๆ เช่น Feature Flags,Feature Bits หรือ Feature Flippers ซึ่งทั้งหมดนี้เป็นคำพ้องความหมายสำหรับเทคนิคชุดเดียวกัน ในบทความนี้ผมจะใช้คำว่า feature toggles และ feature flags สลับกันไปมา

3222a074-5dde-4be1-8ffe-f3d48d960c75

𝐀 𝐓𝐎𝐆𝐆𝐋𝐈𝐍𝐆 𝐓𝐀𝐋𝐄 (ตำนานแห่งการสลับ feature)

ลองจินตนาการดู: คุณอยู่ในหนึ่งในหลายๆ ทีมที่กำลังพัฒนาเกมจำลองการวางผังเมืองที่ซับซ้อน ทีมของคุณรับผิดชอบส่วนของเอนจินจำลองหลัก และได้รับมอบหมายให้เพิ่มประสิทธิภาพของ algorithm Spline Reticulation คุณรู้ดีว่านี่เป็นงานใหญ่ที่ต้องยกเครื่อง code เดิมและอาจใช้เวลาหลายสัปดาห์ ในขณะเดียวกัน สมาชิกคนอื่นๆ ในทีมก็ยังต้องทำงานในส่วนที่เกี่ยวข้องใน codebase เดิมต่อไป

คุณต้องการหลีกเลี่ยงการแยกกิ่ง (branching) สำหรับงานนี้ให้ได้มากที่สุด เพราะเคยมีประสบการณ์ที่เจ็บปวดจากการรวมกิ่งที่ค้างไว้นานๆ ในอดีต แทนที่จะทำแบบนั้น คุณตัดสินใจว่าทั้งทีมจะทำงานบน trunk ต่อไป แต่เหล่านักพัฒนาที่ทำเรื่องการปรับปรุง Spline Reticulation จะใช้ Feature Toggle เพื่อป้องกันไม่ให้งานของพวกเขาส่งผลกระทบต่อคนอื่นๆ ในทีม หรือทำให้ codebase ไม่เสถียร

จุดกำเนิดของ Feature Flag

นี่คือการเปลี่ยนแปลงครั้งแรกที่ทีม algorithm นำมาใช้:

ก่อน (Before)

function reticulateSplines(){
 //`code` เดิมอยู่ที่นี่
}

หลัง (After)

function reticulateSplines(){
 var useNewAlgorithm = false;
 // useNewAlgorithm = true; // เอาคอมเมนต์ออกถ้าคุณกำลังทำ `algorithm` ใหม่

 if( useNewAlgorithm ){
 return enhancedSplineReticulation();
 }else{
 return oldFashionedSplineReticulation();
 }
}

function oldFashionedSplineReticulation(){
 //`code` เดิมย้ายมาอยู่ที่นี่
}

function enhancedSplineReticulation(){
 // TODO: เขียน `algorithm` ใหม่ที่ดีกว่าเดิม
}

ทีมงานได้ย้าย algorithm เดิมไปไว้ใน function oldFashionedSplineReticulation และเปลี่ยน reticulateSplines ให้กลายเป็น Toggle Point(จุดสลับ) คราวนี้ถ้าใครกำลังทำ algorithm ใหม่อยู่ ก็แค่เอาคอมเมนต์หน้าบรรทัด useNewAlgorithm = true ออกเพื่อเปิดใช้งาน feature ใหม่

Making a flag dynamic (การทำให้ Flag ทำงานแบบไดนามิก)

เวลาผ่านไปไม่กี่ชั่วโมง และทีมงานพร้อมที่จะรัน algorithm ใหม่ผ่าน integration tests บางส่วนของเอนจินจำลอง พวกเขายังต้องการทดสอบ algorithm เดิมในการรันการทดสอบรอบเดียวกันด้วย พวกเขาจึงจำเป็นต้องเปิดหรือปิด feature นี้ได้แบบไดนามิก ซึ่งหมายความว่าถึงเวลาที่จะต้องก้าวข้ามกลไกที่ยุ่งยากในการต้องคอยมานั่งคอมเมนต์บรรทัด useNewAlgorithm = true แล้ว:

function reticulateSplines(){
 if( featureIsEnabled("use-new-SR-algorithm") ){
 return enhancedSplineReticulation();
 }else{
 return oldFashionedSplineReticulation();
 }
}

ตอนนี้เราได้นำ function featureIsEnabled มาใช้ ซึ่งก็คือ Toggle Router (ตัวเลือกเส้นทาง Toggle) ที่สามารถใช้ควบคุมแบบไดนามิกว่าเส้นทาง code ไหนจะทำงาน มีหลายวิธีในการสร้าง Toggle Router ตั้งแต่ที่เก็บข้อมูลในหน่วยความจำ (in-memory store) แบบง่ายๆ ไปจนถึงระบบกระจายตัวที่ซับซ้อนพร้อมหน้าจอ UI สวยงาม สำหรับตอนนี้เราเริ่มจากระบบที่ง่ายมากก่อน:

function createToggleRouter(featureConfig){
 return {
 setFeature(featureName,isEnabled){
 featureConfig[featureName] = isEnabled;
 },
 featureIsEnabled(featureName){
 return featureConfig[featureName];
 }
 };
}

เราสามารถสร้าง toggle router ใหม่ตามการตั้งค่าเริ่มต้นบางอย่าง (เช่น อ่านจากไฟล์ config) แต่เรายังสามารถสลับเปิดหรือปิด feature ได้แบบไดนามิกด้วย วิธีนี้ช่วยให้การทดสอบอัตโนมัติ (automated tests) สามารถตรวจสอบได้ทั้งสองฝั่งของ feature ที่ถูกสลับ:

describe( 'spline reticulation', function(){
 let toggleRouter;
 let simulationEngine;

 beforeEach(function(){
 toggleRouter = createToggleRouter();
 simulationEngine = createSimulationEngine({toggleRouter:toggleRouter});
 });

 it('ทำงานได้อย่างถูกต้องกับ `algorithm` เดิม', function(){
 // Given
 toggleRouter.setFeature("use-new-SR-algorithm",false);

 // When
 const result = simulationEngine.doSomethingWhichInvolvesSplineReticulation();

 // Then
 verifySplineReticulation(result);
 });

 it('ทำงานได้อย่างถูกต้องกับ `algorithm` ใหม่', function(){
 // Given
 toggleRouter.setFeature("use-new-SR-algorithm",true);

 // When
 const result = simulationEngine.doSomethingWhichInvolvesSplineReticulation();

 // Then
 verifySplineReticulation(result);
 });
});

Getting ready to release (การเตรียมตัวสำหรับการเปิดตัว)

เวลาผ่านไปและทีมเชื่อว่า algorithm ใหม่ของพวกเขามี feature ครบถ้วนแล้ว เพื่อยืนยันสิ่งนี้พวกเขาได้แก้ไขการทดสอบอัตโนมัติระดับสูงเพื่อให้ทดสอบระบบทั้งแบบที่ปิดและเปิด feature ทีมยังต้องการทำ manual exploratory testing เพื่อให้แน่ใจว่าทุกอย่างทำงานตามที่คาดหวัง เพราะท้ายที่สุดแล้ว Spline Reticulation เป็นส่วนสำคัญอย่างยิ่งต่อพฤติกรรมของระบบ

ในการทดสอบ feature ที่ยังไม่ได้รับการรับรองว่าพร้อมสำหรับการใช้งานทั่วไปด้วยตนเอง เราต้องสามารถปิด feature นั้นไว้สำหรับฐานผู้ใช้ทั่วไปในโปรดักชัน แต่สามารถเปิดให้ผู้ใช้ภายในทีมใช้งานได้ มีแนวทางที่แตกต่างกันมากมายในการบรรลุเป้าหมายนี้:

  • ให้ Toggle Router ตัดสินใจตาม Toggle Configuration และทำให้การตั้งค่านี้ขึ้นอยู่กับสภาพแวดล้อม (environment-specific) โดยเปิด feature ใหม่เฉพาะในสภาพแวดล้อมก่อนโปรดักชัน (pre-production) เท่านั้น
  • อนุญาตให้แก้ไข Toggle Configuration ได้ที่ runtime ผ่านทาง admin UI บางรูปแบบ และใช้ admin UI นั้นเพื่อเปิด feature ใหม่ในสภาพแวดล้อมทดสอบ
  • สอนให้ Toggle Router รู้วิธีทำการตัดสินใจแบบไดนามิกต่อหนึ่ง request โดยการตัดสินใจเหล่านี้จะพิจารณาจาก Toggle Context เช่น การมองหา cookie พิเศษหรือ HTTP header โดยปกติแล้ว Toggle Context จะถูกใช้เป็นตัวแทนในการระบุตัวตนของผู้ใช้ที่ส่ง request เข้ามา

ทีมตัดสินใจเลือกใช้ per-request Toggle Router เนื่องจากมันให้ความยืดหยุ่นสูง ทีมชื่นชอบเป็นพิเศษตรงที่วิธีนี้ช่วยให้พวกเขาสามารถทดสอบ algorithm ใหม่ได้โดยไม่จำเป็นต้องมีสภาพแวดล้อมการทดสอบแยกต่างหาก แต่พวกเขาสามารถเปิด algorithm ในสภาพแวดล้อมโปรดักชันได้โดยตรง แต่เปิดให้เฉพาะผู้ใช้ภายในเท่านั้น (ซึ่งตรวจพบผ่าน cookie พิเศษ) ตอนนี้ทีมสามารถเปิดใช้ cookie นั้นสำหรับตัวพวกเขาเองและยืนยันว่า feature ใหม่ทำงานได้ตามที่คาดหวัง

Canary releasing (การเปิดตัวแบบนกคานารี)

algorithm Spline Reticulation ใหม่ดูดีจากการทดสอบเบื้องต้นที่ทำไปแล้ว อย่างไรก็ตาม เนื่องจากมันเป็นส่วนที่สำคัญมากของเอนจินจำลองเกม จึงยังมีความลังเลที่จะเปิด feature นี้ให้กับผู้ใช้ทุกคน ทีมจึงตัดสินใจใช้โครงสร้างพื้นฐาน Feature Flag ของพวกเขาเพื่อทำ Canary Release โดยเปิด feature ใหม่ให้กับผู้ใช้เพียงเปอร์เซ็นต์เล็กน้อยจากฐานผู้ใช้ทั้งหมด ซึ่งก็คือกลุ่ม "นกคานารี" (canary cohort)

ทีมปรับปรุง Toggle Router โดยสอนให้มันรู้จักแนวคิดของกลุ่มผู้ใช้ (user cohorts) ซึ่งเป็นกลุ่มของผู้ใช้ที่ได้รับประสบการณ์จาก feature ว่าเปิดหรือปิดอย่างสม่ำเสมอ กลุ่มผู้ใช้คานารีถูกสร้างขึ้นผ่านการสุ่มตัวอย่าง 1% ของฐานผู้ใช้ เช่น การใช้เศษเหลือ (modulo) จาก user ID กลุ่มคานารีนี้จะมี feature เปิดใช้งานอยู่เสมอ ในขณะที่ผู้ใช้อีก 99% ที่เหลือยังคงใช้ algorithm เดิม ตัวชี้วัดทางธุรกิจที่สำคัญ (การมีส่วนร่วมของผู้ใช้, รายได้รวม ฯลฯ) จะถูกตรวจสอบสำหรับทั้งสองกลุ่มเพื่อสร้างความมั่นใจว่า algorithm ใหม่ไม่ส่งผลกระทบเชิงลบต่อพฤติกรรมผู้ใช้ เมื่อทีมมั่นใจว่า feature ใหม่ไม่มีผลเสีย พวกเขาจะแก้ไข Toggle Configuration เพื่อเปิดใช้งานให้กับฐานผู้ใช้ทั้งหมด

A/B testing

ผู้จัดการผลิตภัณฑ์ของทีมทราบเรื่องแนวทางนี้และรู้สึกตื่นเต้นมาก เธอเสนอให้ทีมใช้กลไกที่คล้ายกันเพื่อทำ A/B testing มีการถกเถียงกันมานานว่าการแก้ไข algorithm อัตราอาชญากรรมให้พิจารณาระดับมลพิษด้วยนั้นจะช่วยเพิ่มหรือลดความน่าเล่นของเกม ตอนนี้พวกเขามีความสามารถในการยุติการโต้เถียงนี้โดยใช้ข้อมูล พวกเขาวางแผนที่จะรันการทำงานแบบง่ายๆ ที่เก็บใจความสำคัญของแนวคิดนี้ โดยควบคุมด้วย Feature Flag พวกเขาจะเปิด feature นี้ให้กับกลุ่มผู้ใช้ที่มีขนาดใหญ่พอสมควร จากนั้นศึกษาพฤติกรรมของผู้ใช้เหล่านั้นเปรียบเทียบกับกลุ่ม "ควบคุม" (control cohort) แนวทางนี้จะช่วยให้ทีมสามารถคลี่คลายข้อพิพาทเรื่องผลิตภัณฑ์ที่รุนแรงได้โดยใช้ข้อมูล แทนที่จะใช้ HiPPO (ความเห็นของบุคคลที่ได้รับค่าตอบแทนสูงสุด)

𝐂𝐀𝐓𝐄𝐆𝐎𝐑𝐈𝐄𝐒 𝐎𝐅 𝐓𝐎𝐆𝐆𝐋𝐄𝐒 (ประเภทของ Toggles)

เราแบ่ง Feature Toggles ออกได้เป็น 2 มิติหลัก: ความยาวนาน (longevity) และ ความไดนามิกในการตัดสินใจ (dynamism)

Release Toggles (Toggle สำหรับการเปิดตัว)

Release Toggles อนุญาตให้เส้นทาง code ที่ยังไม่สมบูรณ์และยังไม่ได้รับการทดสอบถูกส่งไปยังโปรดักชันในฐานะ latent code ซึ่งอาจจะไม่ถูกเปิดใช้งานเลยก็ได้

สิ่งเหล่านี้คือ feature flags ที่ใช้เพื่อสนับสนุนการพัฒนาแบบ trunk-based สำหรับทีมที่ฝึกฝน Continuous Delivery พวกเขาอนุญาตให้ feature ที่กำลังพัฒนาอยู่สามารถตรวจสอบ (check-in) เข้าไปยังสาขาการรวม code ที่แชร์กัน (เช่น master หรือ trunk) ในขณะที่ยังคงอนุญาตให้สาขานั้นถูก deploy ไปยังโปรดักชันได้ทุกเมื่อ

11752bad-4536-438e-a95a-04de874e2594

ผู้จัดการผลิตภัณฑ์อาจใช้แนวทางเดียวกันนี้ในเวอร์ชันที่เน้นผลิตภัณฑ์เพื่อป้องกันไม่ให้ feature ของผลิตภัณฑ์ที่ทำเสร็จเพียงครึ่งเดียวปรากฏต่อผู้ใช้ปลายทาง ตัวอย่างเช่น ผู้จัดการผลิตภัณฑ์ของไซต์อีคอมเมิร์ซอาจไม่ต้องการให้ผู้ใช้เห็น feature วันที่จัดส่งโดยประมาณ (Estimated Shipping Date) ใหม่ที่ทำงานได้เฉพาะกับคู่ค้าขนส่งรายเดียวของไซต์ โดยเลือกที่จะรอจนกว่า feature นั้นจะได้รับการพัฒนาสำหรับคู่ค้าขนส่งทุกราย

Experiment Toggles (Toggle สำหรับการทดลอง)

Experiment Toggles ใช้สำหรับการทำ multivariate testing หรือ A/B testing ผู้ใช้แต่ละคนจะถูกจัดอยู่ในกลุ่มทดสอบ (cohort) และที่ runtime ตัว Toggle Router จะส่งผู้ใช้คนนั้นไปยังเส้นทาง code เดิมหรือใหม่ตามกลุ่มที่เขาอยู่ การติดตามพฤติกรรมโดยรวมของกลุ่มต่างๆ ช่วยให้เราเปรียบเทียบผลกระทบของเส้นทาง code ที่แตกต่างกันได้

e9f69ef7-0846-4654-8c28-5628bfbc9180

Ops Toggles (Toggle สำหรับการปฏิบัติการ)

Flags เหล่านี้ใช้ควบคุมแง่มุมด้านการปฏิบัติการของระบบ เราอาจนำ Ops Toggle มาใช้เมื่อเปิดตัว feature ใหม่ที่ยังไม่แน่ใจเรื่องผลกระทบด้านประสิทธิภาพ เพื่อให้ผู้ดูแลระบบสามารถปิดการใช้งานหรือลดระดับ feature นั้นในโปรดักชันได้อย่างรวดเร็วหากจำเป็น

57d752bf-9ea8-45f7-b612-053d23fe3519

Permissioning Toggles (Toggle สำหรับการจัดการสิทธิ์)

Flags เหล่านี้ใช้เพื่อเปลี่ยน feature หรือประสบการณ์การใช้งานผลิตภัณฑ์ที่ผู้ใช้บางกลุ่มได้รับ เช่น เราอาจมีชุด feature"premium" ที่เราเปิดให้เฉพาะลูกค้าที่จ่ายเงินเท่านั้น หรือชุด feature"alpha" ที่เปิดให้เฉพาะผู้ใช้ภายในบริษัท

159bab91-9686-4f16-9611-f6806088ed47


𝐌𝐚𝐧𝐚𝐠𝐢𝐧𝐠 𝐝𝐢𝐟𝐟𝐞𝐫𝐞𝐧𝐭 𝐜𝐚𝐭𝐞𝐠𝐨𝐫𝐢𝐞𝐬 𝐨𝐟 𝐭𝐨𝐠𝐠𝐥𝐞𝐬

เมื่อเรามีโครงสร้างการแบ่งประเภทแล้ว เราสามารถพูดคุยกันได้ว่ามิติเรื่องความไดนามิกและความยาวนานส่งผลต่อการทำงานกับ feature flags ในแต่ละหมวดหมู่อย่างไร

8c2a950e-08d4-4311-8d66-829da65cb5c5 4beba83c-421f-42b5-a91c-e6c4b4682324

Static vs Dynamic Toggles

Toggles ที่ทำหน้าที่เลือกเส้นทางแบบ runtime จำเป็นต้องมี Toggle Router ที่ซับซ้อนขึ้น พร้อมกับการตั้งค่าที่ละเอียดขึ้น

สำหรับการตัดสินใจเลือกเส้นทางแบบคงที่ (static) การตั้งค่า toggle อาจเป็นเพียงแค่สถานะเปิด (On) หรือปิด (Off) อย่างง่ายสำหรับแต่ละ feature โดยมี toggle router ที่ทำหน้าที่ส่งต่อสถานะนั้นไปยัง Toggle Point แต่สำหรับหมวดหมู่อื่นๆ ที่มีความไดนามิกมากกว่า เช่น Experiment Toggle การตัดสินใจจะเกิดขึ้นแบบไดนามิกสำหรับผู้ใช้แต่ละราย โดยอาจใช้ algorithm การจัดกลุ่มที่เสถียรตาม user ID

Long-lived Toggles vs Transient Toggles

เรายังสามารถแบ่ง toggle ออกเป็นกลุ่มที่มีลักษณะชั่วคราว (transient) กับกลุ่มที่มีอายุยืนนาน (long-lived) ซึ่งอาจจะอยู่ในระบบเป็นปีๆ ความแตกต่างนี้ควรส่งผลต่อวิธีการเขียน code ที่ Toggle Point อย่างมาก หากเรากำลังเพิ่ม Release Toggle ที่จะถูกลบออกในอีกไม่กี่วัน เราอาจจะใช้เพียงการตรวจสอบ if/else ง่ายๆ บน Toggle Router แต่หากเรากำลังสร้าง Permissioning Toggle ที่คาดว่าจะอยู่อีกนาน เราย่อมไม่ต้องการให้มี code if/else กระจัดกระจายอยู่ทั่วไป เราจำเป็นต้องใช้เทคนิคการระบุตัวแปร (implementation) ที่บำรุงรักษาได้ง่ายกว่านั้น

𝐈𝐌𝐏𝐋𝐄𝐌𝐄𝐍𝐓𝐀𝐓𝐈𝐎𝐍 𝐓𝐄𝐂𝐇𝐍𝐈𝐐𝐔𝐄𝐒 (เทคนิคการเขียน code)

การใช้ Feature Flags มักทำให้ code ที่ Toggle Point ดูยุ่งเหยิงและกระจายไปทั่ว codebase นี่คือแนวทางเพื่อลดปัญหาดังกล่าว:

1. แยกจุดตัดสินใจออกจากตรรกะการตัดสินใจ (De-coupling Decision Points from Decision Logic)

ความผิดพลาดทั่วไปคือการผูกจุดที่ตัดสินใจ (Toggle Point) เข้ากับตรรกะเบื้องหลังการตัดสินใจ (Toggle Router) โดยตรง

invoiceEmailer.js (ก่อนปรับปรุง)

const features = fetchFeatureTogglesFromSomewhere();

function generateInvoiceEmail(){
 const baseEmail = buildEmailForInvoice(this.invoice);
 if( features.isEnabled("next-gen-ecomm") ){ 
 return addOrderCancellationContentToEmail(baseEmail);
 }else{
 return baseEmail;
 }
}

แนวทางนี้เปราะบางมาก เพราะหากต้องการเปลี่ยนเงื่อนไขการเปิดปิด feature เราจะต้องตามแก้ในทุกจุดที่ใช้ next-gen-ecomm วิธีที่ดีกว่าคือการเพิ่มเลเยอร์ของการอ้างอิงทางอ้อม (indirection):

featureDecisions.js

function createFeatureDecisions(features){
 return {
 includeOrderCancellationInEmail(){
 return features.isEnabled("next-gen-ecomm");
 }
 };
}

invoiceEmailer.js (หลังปรับปรุง)

const features = fetchFeatureTogglesFromSomewhere();
const featureDecisions = createFeatureDecisions(features);

function generateInvoiceEmail(){
 const baseEmail = buildEmailForInvoice(this.invoice);
 if( featureDecisions.includeOrderCancellationInEmail() ){
 return addOrderCancellationContentToEmail(baseEmail);
 }else{
 return baseEmail;
 }
}

2. การกลับทิศทางการตัดสินใจ (Inversion of Decision)

เราสามารถใช้ Inversion of Control เพื่อลดการผึ่งพากันระหว่าง module ได้ โดยส่งการตัดสินใจเข้าไปผ่านทาง configobject ในขณะสร้าง object(Dependency Injection)

3. หลีกเลี่ยงการใช้ Conditionals (Avoiding Conditionals)

แทนที่จะใช้ if/else เราสามารถใช้ Strategy Pattern เพื่อเลือกชุดของพฤติกรรม (Strategy) ตั้งแต่ตอนเริ่มต้นได้ ซึ่งจะช่วยให้ code สะอาดและบำรุงรักษาได้ง่ายกว่าในระยะยาว

𝐓𝐎𝐆𝐆𝐋𝐄 𝐂𝐎𝐍𝐅𝐈𝐆𝐔𝐑𝐀𝐓𝐈𝐎𝐍 (การตั้งค่า Toggle)

Dynamic routing vs dynamic configuration

มีความแตกต่างระหว่าง toggles ที่การตัดสินใจเปลี่ยนไปตาม request(เช่น Experiment Toggle) กับ toggles ที่เปลี่ยนจากการตั้งค่าใหม่ (เช่น Ops Toggle) บางประเภทอาจมีความไดนามิกในการตัดสินใจสูงมากแต่มีการตั้งค่าที่ค่อนข้างคงที่

Prefer static configuration (เน้นการตั้งค่าแบบคงที่)

การจัดการการตั้งค่า toggle ผ่าน source control และการ re-deployment เป็นสิ่งที่น่าปรารถนาที่สุดหากลักษณะของ feature เอื้ออำนวย เพราะจะช่วยให้เราได้รับประโยชน์เต็มที่จาก Continuous Delivery pipeline ที่ตรวจสอบได้และทำซ้ำได้

𝐖𝐎𝐑𝐊𝐈𝐍𝐆 𝐖𝐈𝐓𝐇 𝐅𝐄𝐀𝐓𝐔𝐑𝐄-𝐅𝐋𝐀𝐆𝐆𝐄𝐃 𝐒𝐘𝐒𝐓𝐄𝐌𝐒

Feature Toggles introduce validation complexity

ในระบบที่มี Feature Flags กระบวนการ Continuous Delivery จะซับซ้อนขึ้น โดยเฉพาะในส่วนของการทดสอบ เราจำเป็นต้องทดสอบเส้นทาง code หลายสายสำหรับอาร์ติแฟกต์เดียวกัน

3513ddc8-1049-4cb0-82f2-e8905cd1508f

คำแนะนำที่ดีคือ: เปิดใช้พฤติกรรมเดิมเมื่อ Feature Flag ปิด และเปิดใช้พฤติกรรมใหม่เมื่อมันเปิด

ทีมควรทดสอบการตั้งค่า toggle ที่คาดว่าจะถูกใช้จริงในโปรดักชัน และควรทดสอบกรณีที่ feature ถูกปิดไว้ (fall-back configuration) เพื่อความปลอดภัย

Managing the carrying cost of Feature Toggles

Feature Flags มีแนวโน้มที่จะเพิ่มขึ้นอย่างรวดเร็ว แต่มันมาพร้อมกับต้นทุนในการแบกรับ (carrying cost) ทั้งความซับซ้อนใน code และภาระในการทดสอบ ทีมที่เก่งจะมองว่า Feature Toggles คือสินค้าคงคลัง (inventory) ที่ต้องพยายามรักษาไว้ให้ต่ำที่สุด

แนวทางปฏิบัติที่ดีคือ:

  • กำหนดภารกิจในการลบ toggle ทันทีที่มันไม่จำเป็นแล้ว
  • ใส่ "ระเบิดเวลา" (time bombs) หรือวันหมดอายุให้กับ toggle
  • จำกัดจำนวน toggle สูงสุดที่อนุญาตให้มีได้ในระบบในเวลาเดียวกัน

บทสรุป

Feature Toggles เป็นเครื่องมือที่ยอดเยี่ยมสำหรับการส่งมอบ software ที่รวดเร็วและปลอดภัย แต่การจัดการความซับซ้อนที่ตามมาเป็นหน้าที่สำคัญของทีมวิศวกรรม การแยกประเภทที่ชัดเจนและการใช้เทคนิคการเขียน code ที่เหมาะสมจะช่วยให้ระบบของคุณยืดหยุ่นและบำรุงรักษาได้ง่ายในระยะยาว

References