มาทำความรู้จักกับ Feature Toggle กันเถอะ

เราอาจจะเคยได้ยินคำว่า Feature Toggle / Feature Flags / Flipper / Experiment กันมาบ้างแล้ว แต่ว่าวันนี้พี่หมีจะพามารู้จักกับแนวคิดเบื้องหลังการทำ Feature Toggle กันนะครับ สำหรับการพัฒนาระบบในปัจจุบันนั้น เรามักจะ Release Feature ด้วยการ Deploy Code แต่เพื่อคุณภาพชีวิตที่ดี และเพื่อเวลานอนอันศักดิ์สิทธิ์นั้น เราควรแยกการ Release Feature ออกจากการ Deploy Code ให้ได้นะครับ ซึ่งอันนี้เทคนิค Feature Toggle น่าจะช่วยเราได้แน่ๆ แต่ก่อนอื่นขอซัมมอนโควทของ Martin Fowler มาเพื่อเป็นขวัญและกำลังใจก่อนนะ

Feature toggles are a powerful technique, allowing teams to modify system behavior without changing code. They fall into various usage categories, and it’s important to take that categorization into account when implementing and managing toggles. Toggles introduce complexity. We can keep that complexity in check by using smart toggle implementation practices and appropriate tools to manage our toggle configuration, but we should also aim to constrain the number of toggles in our system.

ปกติแล้วเมื่อจะมีการเพิ่ม Feature ใหม่ๆลงใน Software นั้น ตามแนวนิยมเราจะสร้าง branch ใหม่ขึ้นมาใน version control ซึ่งที่นิยมแพร่หลายก็คงจะเป็น Git นั่นเอง ซึ่งเมื่อเราพัฒนา Feature นั้นๆเสร็จแล้ว เราก็จะทำการรวม(merge) ตัว Feature branch นั้นกลับเข้ามาใน Master เพื่อทำการ Deploy ต่อไป (อย่าลืมเทสต์ด้วยนะตะเองงงง)

1_t4CZZHmlTJSJgaixI4VzWg

picture from https://buddy.works/blog/5-types-of-git-workflows
แต่สิ่งหนึ่งที่ Feature Branch นั้นแตกต่างออกไปจาก Feature Toggle คือ Feature Branch นั้นเป็นการควบคุมในระดับของ Version Control และไม่ได้หมายความว่า Feature นั้นจะถูกควบคุมด้วยการ เปิดและปิด (Toggle) นะครับ

ในการเปิดและปิด Feature ด้วย Feature Toggle นั้นคือการทำให้ Feature นั้นๆสามารถถูกเปิดและปิดได้ในเงื่อนไขที่เหมาะสม และ กรณีศึกษาของเงื่อนไขหนึ่งที่โด่งดังมากจนกลายเป็น Talk of the Town ในช่วงปีที่ผ่านๆมานั่นก็คือการทำ A/B Test นั่นเอง

1_YCbnJM2ZzTbNPVgiDFYZgw

picture : https://dzone.com/articles/is-it-a-feature-flag-or-a-feature-toggle
สำหรับวิธีในการสร้าง Feature Toggle นั้นมีความยากง่ายแตกต่างกันไปตามโครงสร้างของแอพพลิเคชัน และความต้องการของการทดสอบ Feature ของเรา โดยโครงสร้างหลักๆของ Feature Toggle มักจะแบ่งเป็นส่วนหลักๆประมาณนี้

1_zbflz4jhcH9CjnnHlQYprw

Common Feature Toggle Approach
ส่วนแรกที่มักจะมีก็คือ Feature Database ซึ่งมักจะมาพร้อมกันกับ Feature Toggle Control ซึ่งมีเอาไว้สำหรับทำการเปิด/ปิด Feature นั่นเอง ในส่วนนี้เราอาจไม่จำเป็นต้องมีก็ได้นะครับ เราสามารถใช้ REST Client อ่านเอาจาก URL ที่เรา upload json ไว้ก็ได้ หรือจะใช้ Firebase เป็น Feature Database ยังได้เลย LOLz และในส่วนที่สองคือส่วนที่ใช้ในการตัดสินใจ Execution Path ของ A/B นั่นเอง ในส่วนนี้จริงๆแล้ว Logic หลักๆของมันคือ If-Else นี่เอง จากใน blog ของปรมาจารย์ Martin Fowler ได้ยกตัวอย่างไว้หลายแบบดังนี้

เริ่มแรกก็ใช้ If-Else แบบง่ายๆเลย เรียกว่านี่เป็นต้นแบบของ Feature Toggle ละกัน

function reticulateSplines(){
    var useNewAlgorithm = false;
    // useNewAlgorithm = true; // UNCOMMENT IF YOU ARE WORKING ON THE NEW SR ALGORITHM
  
    if( useNewAlgorithm ){
      return enhancedSplineReticulation();
    }else{
      return oldFashionedSplineReticulation();
    }
  }
  
  function oldFashionedSplineReticulation(){
    // current implementation lives here
  }
  
  function enhancedSplineReticulation(){
    // TODO: implement better SR algorithm
  }

ส่วนอีกตัวอย่างนึงเป็นการใช้ Feature Toggle ที่มีความยืดหยุ่นมากขึ้นระดับนึง สมมติว่าเราสร้าง module ที่ชื่อว่า feature-toggles ขึ้นมา และทำการ load flags เพื่อนำไปใช้ในการตัดสินใจในการเลือก Code path ที่จะใช้ในการทำงานได้ (module นี้ มีอยู่จริงที่ https://www.npmjs.com/package/feature-toggles )

var toggles = {
  foo: true, 
  bar: false
};

// load them into the module 
var featureToggles = require('feature-toggles');
featureToggles.load(toggles);


// Sample for feature on/off
if (featureToggles.isFeatureEnabled('foo')) {
  // Feature On PATH
}


// Sample for A/B Testing
if (featureToggles.isFeatureEnabled('foo')) {
  // Path B AKA Variant
}
else
{
  // Path A
}

ซึ่งจะเห็นได้ว่าด้วยเงื่อนไขของ toggles จะทำให้ Execution path เปลี่ยนไป หนึ่งมนสิ่งที่เรานิยมในการนำ Feature Toggles มาใช้ก็คือ การทดสอบ Feature นั่นเอง เช่น Facebook นั้นก็มีระบบ Feature Toggle ที่ชื่อว่า gatekeeper ที่จะทำให้การทำงานของ Facebook เปลี่ยนไปตามกลุ่มผู้ใช้งานนั่นเอง

1_33boViysDmkIKfC0kYBPpg

picture : http://blog.launchdarkly.com/category/continuous_delivery/
ในการที่จะใช้ Feature Toggle เพื่อทำ A/B Test นั้นมีเรื่องหนึ่งที่ต้องให้ความสนใจครับ นั่นคือเรื่องของ Marketing และ Statistics นั่นเอง (แอบๆมี Data Mining หน่อยๆ ด้วยนะ)ในการที่เราจะให้ Feature Toggle ทำงานเพื่อทำ Test นั้น เราต้องนึกถึงข้อมูลของผู้ใช้ทางด้านการตลาดว่า เราควรจะแบ่ง (Clustering ผู้ใช้ว่าอยู่ใน demographic กลุ่มไหน แล้วแบ่งออกไปเท่าๆกัน เพื่อดูว่า conversion ของแบบไหนดีกว่ากัน

1_gmos-3_SEccCV4w_vMpU0w

picture : https://vwo.com/features/
วิธีการประยุกต์ใช้งาน Feature Toggle

จาก Blog ของ MF (ผมเป็นแฟนบอย) เค้าสรุปการใช้งาน Toggle ไว้ด้วยกัน 4 แบบดังนี้

1_cxtnPENEQVgm-5A4uFmfRA

picture : https://martinfowler.com/articles/feature-toggles.html

  • Release Toggle เทคนิคนี้อาจจะดูขัดใจคุณแม่นิดหน่อย เพราะเป็นช่วยให้เราสามารถเอา Feature ที่ยังไม่เสร็จ และ(อาจจะ)ยังไม่ได้เทส merge รวมเข้า master ได้เลยครับ ใช่แล้ว อ่านไม่ผิดครับ เราสามารถเอาของที่ยังทำไม่เสร็จใส่ลงไปใน master ได้ แล้วด้วย Release Toggle จะทำให้ Code ส่วนนี้ไม่เคยถูกรันบน production สิ่งนี้เป็นสิ่งที่สำคัญมากในการทำให้เราแยกการ Release Feature ออกจากการ Deploy Code ได้
  • A/B Test (Experiment Toggles) อันนี้ก็เขียนมาเยอะละ ผ่านๆๆ
  • Ops Toggle (Operation Toggles) เทคนิคนี้เป็นอีกอันนึงที่เรามักจะใช้สลับๆกันกับ Release Toggle และ Experiment Toggle เพราะตัว Ops Toggle หรือ Kill Switch เป็น Mechanism เพื่อให้ระบบสามารถมีชีวิติยู่ต่อไปได้ เช่น ช่วงลดราคามหาโหด Black friday บาง feature ถูกระบุไว้ใน Design Review ว่า อาจจะทำให้ระบบมีปัญหาในด้าน Performance เมื่อถึงเวลา Ops สามารถใช้ Kill Switch เพื่อทำให้ feature นั้นๆ หยุดทำงาน/เริ่มทำงานเพื่อให้ระบบสามารถทำงานต่อไปได้เป็นต้น แต่วัตถุประสงค์จะต่างกันกับ Release Toggle และ Experiment Toggle อย่างชัดเจน และ Ops Toggle นี้ปกติมักจะสร้างขึ้นมาคู่กันกับ Feature ที่เราไม่มั่นใจในผลกระทบต่อประสิทธิภาพของระบบ และเราไม่ควรให้มันอยู่ใน code base นานนัก เมื่อเรามั่นใจมากพอเราควรจะ retire ตัว Ops Toggle นี้ทันที
  • Privilege Toggle อันนี้อธิบายง่ายๆก็ประมาณ In-App Purchase ที่เมื่อเราจ่ายเงิน ระบบจะทำให้เราสามารถทำอะไรเพิ่มขึ้นได้นั่นเอง
    ข้อแนะนำสำหรับคนที่อยากทำ Feature Toggle

ข้อแรก ในการทำ Feature Toggle / Feature Flag นั้นพี่หมีมีข้อแนะนำข้อแรกคือ merge Feature Toggle เข้าไปใน master branch .ให้เร็วที่สุด และ เอา Feature flag ออกจาก codebase ให้เร็วที่สุด เพราะว่า Feature Toggle จัดว่าเป็น Technical Debt อย่างนึงนะครับ เพราะเราเพิ่ม Complexity เข้าไป เมื่อเราตัดสินผลแล้วว่าได้ไปต่อไหม เราควรจัดการกับ Feature Toggle ซะ อย่าให้เหลือ

ข้อที่สอง ในการทำ Feature Toggle นั้น จะทำให้มี Execution Path ของ code base ที่แยกออกไปสองทาง ดังนั้น เทสต์ของเราควรจะเทสทั้งสองทางด้วยนะ

1_AEXebGAsxAU5g7Py6in6qw-1

picture: https://martinfowler.com/articles/feature-toggles.html
ข้อที่สาม การสร้าง Feature Toggle แบบ A/B Test ไม่ควรซ้อนทับกันใน Code path จุดเดียวกันเพราะจะทำให้เกิดความผิดพลาดทางสถิติได้ เช่น ชุดโค้ดตัวอย่างด้านล่างนี้

// define toggles 
var toggles = {
  foo: true, 
  bar: false
};
 
// load them into the module 
var featureToggles = require('feature-toggles');
featureToggles.load(toggles);
 
// A/B test here
if (featureToggles.isFeatureEnabled('foo')) {
  // Path B
  
  // WTF another A/B test inside A/B Test
  if (featureToggles.isFeatureEnabled('foo')) {
    // Path B-2
  }
  else
  {
    // Path A-2
  }
} 
} 
else
{
  // Path A
}

จะเห็นว่าการทำ Feature Toggle นั้นเป็นงานด้าน Software Engineering ที่สำคัญมากๆในการออกแบบโครงสร้างทางสถาปัตยกรรมของ Software อย่างหนึ่งเลยทีเดียว พร้อมแล้วก็ไปลุยกันเลยครับ Happy Coding

References: