it

Feature Flags คืออะไร? สอน Progressive Delivery และ Feature Toggle สำหรับ DevOps 2026

Feature Flags คืออะไร? สอน Progressive Delivery และ Feature Toggle สำหรับ DevOps 2026

Feature Flags (หรือ Feature Toggles) เป็นเทคนิคที่ทรงพลังที่สุดอย่างหนึ่งใน Modern Software Delivery ช่วยให้คุณ Deploy code ขึ้น Production ได้ทุกวัน โดยไม่ต้องเปิดฟีเจอร์ให้ User ทุกคนเห็นทันที ทำให้สามารถ Release อย่างปลอดภัย ทดสอบกับ User จริง และ Rollback ได้ทันทีโดยไม่ต้อง Redeploy

บทความนี้จะสอน Feature Flags ครบทุกเรื่อง ตั้งแต่แนวคิดพื้นฐาน, Progressive Delivery, A/B Testing, Platform ยอดนิยม ไปจนถึง Best Practices สำหรับทีม DevOps

อ่านเพิ่ม: Error Handling คืออะไร? Resilience Patterns สำหรับ Backend ท · อ่านเพิ่ม: SRE คืออะไร? Site Reliability Engineering แนวคิดจาก Google ส · อ่านเพิ่ม: Zero-Downtime Deployment คืออะไร? กลยุทธ์ Deploy แบบไม่มี Do

Feature Flags คืออะไร?

Feature Flags คืออะไร? สอน Progressive Delivery และ Feature Toggle สำหรับ DevOps 2026

Feature Flags (Feature Toggles) คือเทคนิคที่ใช้ Configuration เพื่อควบคุมว่า Feature ใดจะเปิดหรือปิดใน Runtime โดยไม่ต้องแก้ Code หรือ Deploy ใหม่ เปรียบเหมือน "สวิตช์" ที่เปิด-ปิดฟีเจอร์ได้ทันที

// ตัวอย่างพื้นฐาน

if (featureFlags.isEnabled('new-checkout')) {

  showNewCheckout()

} else {

  showOldCheckout()

}

ประเภทของ Feature Flags

ประเภทวัตถุประสงค์อายุตัวอย่าง
Release Flagซ่อนฟีเจอร์ที่ยังไม่เสร็จสั้น (days-weeks)new-dashboard, v2-api
Experiment FlagA/B Testingปานกลาง (weeks)checkout-variant-b, pricing-test
Ops Flagควบคุม operational behaviorยาว (permanent)enable-cache, rate-limit-mode
Permission Flagจำกัดสิทธิ์การเข้าถึงยาว (permanent)beta-access, premium-feature

Progressive Delivery คืออะไร?

Progressive Delivery คือแนวทางการ Release ซอฟต์แวร์แบบค่อยๆ เปิดให้ User เข้าถึง แทนที่จะ Release ทีเดียวให้ทุกคน (Big Bang Release) ประกอบด้วยเทคนิค:

เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง Wireless Site Survey Clean Architecture

  • Canary Release — ปล่อยให้ User กลุ่มเล็กก่อน (เช่น 1%) แล้วค่อยขยาย
  • Percentage Rollout — ค่อยๆ เพิ่มเปอร์เซ็นต์ (1% → 10% → 50% → 100%)
  • Ring Deployment — Release ทีละกลุ่ม (Internal → Beta → GA)
  • A/B Testing — ทดสอบ 2 versions กับ User จริง วัดผลลัพธ์
ทำไมต้อง Progressive Delivery? ลดความเสี่ยงจากการ Release, ค้นหา Bug ก่อนกระทบ User ทั้งหมด, ทดสอบ Performance กับ Traffic จริง, และ Rollback ได้ทันทีเมื่อเจอปัญหา

Canary Release กับ Feature Flags

// Canary: เปิดให้ 5% ของ User ก่อน

const flag = {

  name: 'new-payment-flow',

  enabled: true,

  rolloutPercentage: 5,  // 5% ของ users

  targetGroups: ['internal-testers']

}



function shouldShowFeature(userId, flag) {

  // 1. เช็ก target groups ก่อน

  if (flag.targetGroups.includes(getUserGroup(userId))) {

    return true

  }

  // 2. เช็ก percentage rollout

  const hash = hashUserId(userId) % 100

  return hash < flag.rolloutPercentage

}

A/B Testing กับ Feature Flags

// A/B Test: ทดสอบ 2 variants

const experiment = {

  name: 'checkout-redesign',

  variants: [

    { key: 'control', weight: 50 },     // A: แบบเดิม

    { key: 'treatment', weight: 50 }     // B: แบบใหม่

  ]

}



function getVariant(userId, experiment) {

  const hash = hashUserId(userId) % 100

  let cumulative = 0

  for (const variant of experiment.variants) {

    cumulative += variant.weight

    if (hash < cumulative) return variant.key

  }

  return experiment.variants[0].key

}



// ใช้งาน

const variant = getVariant(userId, experiment)

if (variant === 'treatment') {

  renderNewCheckout()

  trackEvent('checkout_view', { variant: 'treatment' })

} else {

  renderOldCheckout()

  trackEvent('checkout_view', { variant: 'control' })

}

User Targeting

// Target by attribute

const flag = {

  name: 'beta-feature',

  rules: [

    // เปิดให้ทุก internal users

    { attribute: 'email', operator: 'endsWith', value: '@company.com', enabled: true },

    // เปิดให้ users ในประเทศไทย

    { attribute: 'country', operator: 'equals', value: 'TH', enabled: true },

    // เปิดให้ premium users

    { attribute: 'plan', operator: 'in', value: ['pro', 'enterprise'], enabled: true },

    // เปิดให้ specific users

    { attribute: 'userId', operator: 'in', value: ['user-123', 'user-456'], enabled: true }

  ],

  defaultValue: false  // ปิดสำหรับ users ที่ไม่ตรง rules

}

Feature Flag Platforms เปรียบเทียบ

Platformประเภทราคาจุดเด่น
LaunchDarklySaaSเริ่ม $10/moEnterprise-grade, SDK ครบ, Experimentation
UnleashOpen Source / SaaSFree (OSS)Self-hosted, Open Source, ยืดหยุ่น
FlagsmithOpen Source / SaaSFree (OSS)Remote Config + Flags, Edge support
ConfigCatSaaSFree tierSimple, ราคาถูก, Config management
PostHogOpen Source / SaaSFree tierFeature Flags + Analytics + Session Replay
StatsigSaaSFree tierExperimentation platform + Auto metrics

Implementing Feature Flags — React

// React + LaunchDarkly

import { useFlags, useLDClient } from 'launchdarkly-react-client-sdk'



function CheckoutPage() {

  const { newCheckout, showPromoBar } = useFlags()



  return (

    <div>

      {showPromoBar && <PromoBanner />}

      {newCheckout ? <NewCheckout /> : <OldCheckout />}

    </div>

  )

}
// React + Custom Hook (ไม่ใช้ platform)

import { createContext, useContext, useState, useEffect } from 'react'



const FlagContext = createContext({})



export function FlagProvider({ children }) {

  const [flags, setFlags] = useState({})



  useEffect(() => {

    fetch('/api/flags')

      .then(r => r.json())

      .then(setFlags)

  }, [])



  return (

    <FlagContext.Provider value={flags}>

      {children}

    </FlagContext.Provider>

  )

}



export function useFlag(flagName) {

  const flags = useContext(FlagContext)

  return flags[flagName] ?? false

}



// ใช้งาน

function MyComponent() {

  const showNewUI = useFlag('new-ui')

  return showNewUI ? <NewUI /> : <OldUI />

}

Implementing Feature Flags — Node.js

// Node.js + Unleash

import { initialize } from 'unleash-client'



const unleash = initialize({

  url: 'https://unleash.example.com/api',

  appName: 'my-api',

  customHeaders: { Authorization: process.env.UNLEASH_TOKEN }

})



// Express middleware

function featureFlag(flagName) {

  return (req, res, next) => {

    const context = {

      userId: req.user?.id,

      properties: {

        email: req.user?.email,

        country: req.headers['x-country']

      }

    }

    req.flagEnabled = unleash.isEnabled(flagName, context)

    next()

  }

}



// ใช้งาน

app.get('/api/dashboard',

  featureFlag('new-dashboard'),

  (req, res) => {

    if (req.flagEnabled) {

      return res.json(getNewDashboardData())

    }

    return res.json(getOldDashboardData())

  }

)

Implementing Feature Flags — Python

# Python + Custom implementation

import hashlib

import json

from functools import wraps



class FeatureFlagService:

    def __init__(self, config_path='flags.json'):

        with open(config_path) as f:

            self.flags = json.load(f)



    def is_enabled(self, flag_name, user_id=None, attributes=None):

        flag = self.flags.get(flag_name)

        if not flag or not flag.get('enabled'):

            return False



        # Global kill switch

        if flag.get('kill_switch'):

            return False



        # Percentage rollout

        if user_id and 'percentage' in flag:

            hash_val = int(hashlib.md5(

                f"{flag_name}:{user_id}".encode()

            ).hexdigest(), 16) % 100

            return hash_val < flag['percentage']



        return True



# Flask decorator

flags = FeatureFlagService()



def feature_required(flag_name):

    def decorator(f):

        @wraps(f)

        def wrapper(*args, **kwargs):

            if not flags.is_enabled(flag_name, user_id=g.user_id):

                abort(404)

            return f(*args, **kwargs)

        return wrapper

    return decorator



@app.route('/new-feature')

@feature_required('new-feature')

def new_feature():

    return render_template('new_feature.html')

Feature Flags ใน Microservices

Feature Flags คืออะไร? สอน Progressive Delivery และ Feature Toggle สำหรับ DevOps 2026
// Centralized Flag Service Architecture

//

// [Flag Service] ← Admin Dashboard

//       ↓ (SDK / API)

//  ┌────┼────┐

//  ↓    ↓    ↓

// [Web] [API] [Worker]

//

// ทุก Service ใช้ flag state เดียวกัน



// Flag evaluation ใน API Gateway

async function apiGatewayMiddleware(req, res, next) {

  const flags = await flagService.getAllFlags({

    userId: req.user?.id,

    service: req.params.service

  })



  // Inject flags เข้า request header ส่งต่อไป downstream services

  req.headers['x-feature-flags'] = JSON.stringify(flags)

  next()

}



// Downstream service อ่าน flags จาก header

function getFlags(req) {

  return JSON.parse(req.headers['x-feature-flags'] || '{}')

}

Flag Lifecycle Management

Feature Flags มี Lifecycle ที่ต้องจัดการ ไม่เช่นนั้นจะกลายเป็น Technical Debt:

  1. Creation — สร้าง Flag พร้อม description, owner, expiry date
  2. Development — ใช้ Flag wrap ฟีเจอร์ใหม่ในระหว่าง development
  3. Testing — ทดสอบทั้ง flag on/off
  4. Rollout — ค่อยๆ เปิด (Canary → Percentage → Full)
  5. Full Release — เปิด 100%
  6. Cleanup — ลบ Flag code ออก (สำคัญมาก!)
// ตัวอย่าง Flag metadata

{

  "new-checkout": {

    "enabled": true,

    "percentage": 100,

    "owner": "team-checkout",

    "created": "2026-03-01",

    "expires": "2026-05-01",

    "description": "New checkout flow with Apple Pay",

    "jira": "PROJ-1234",

    "status": "full-rollout",    // ready-for-cleanup

    "stale_after_days": 30

  }

}
Technical Debt Warning: Feature Flags ที่ไม่ลบออกจะสะสมเป็น Technical Debt อย่างรวดเร็ว ตั้งกฎว่า Flag ที่ rollout 100% แล้ว ต้อง cleanup ภายใน 2 สัปดาห์ ใช้ automated alerts เตือน stale flags

Kill Switches สำหรับ Incidents

// Kill Switch — ปิดฟีเจอร์ทันทีเมื่อเกิดปัญหา

const KILL_SWITCHES = {

  'external-payment': true,    // ปิด external payment เมื่อ gateway ล่ม

  'ai-recommendations': true,  // ปิด AI เมื่อ model service มีปัญหา

  'search-service': true,      // ปิด search เมื่อ Elasticsearch ล่ม

}



// ใน code

async function processPayment(order) {

  if (!flagService.isEnabled('external-payment')) {

    // Fallback: queue สำหรับ retry ภายหลัง

    await paymentQueue.add(order)

    return { status: 'queued', message: 'Payment will be processed shortly' }

  }

  return await paymentGateway.charge(order)

}

Trunk-based Development + Feature Flags

Feature Flags ช่วยให้ทีมใช้ Trunk-based Development ได้อย่างมั่นใจ:

  • ทุกคน commit เข้า main (trunk) ทุกวัน
  • ฟีเจอร์ที่ยังไม่เสร็จซ่อนด้วย Feature Flag
  • ไม่ต้องใช้ Long-lived Feature Branches
  • Deploy main ไป production ทุกวัน (Continuous Deployment)
  • เปิด/ปิดฟีเจอร์ผ่าน Flag โดยไม่ต้อง deploy ใหม่

Workflow

แนะนำเพิ่มเติม — iCafeForex

1. Developer สร้าง flag "new-search"

2. เขียน code wrap ด้วย flag

เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: Python SQLAlchemy SSL TLS Certificate

3. Commit เข้า main → Deploy to production (flag ปิด)

4. ทดสอบใน production กับ internal users (flag เปิดเฉพาะ internal)

5. Canary release 5% → 25% → 50% → 100%

6. ลบ flag code → commit → deploy

แนะนำเพิ่มเติม — คู่มือเทรดจาก SiamCafeBook

ข้อดี:

  • ไม่มี merge conflicts จาก long-lived branches
  • ทุก commit ผ่าน CI/CD ทันที
  • ฟีเจอร์ถูก test กับ production traffic จริง

Testing กับ Feature Flags

// ทดสอบทั้ง flag on และ off

describe('Checkout', () => {

  it('shows new checkout when flag is ON', () => {

    // Mock flag service

    jest.spyOn(flagService, 'isEnabled')

      .mockReturnValue(true)



    render(<CheckoutPage />)

    expect(screen.getByTestId('new-checkout')).toBeInTheDocument()

  })



  it('shows old checkout when flag is OFF', () => {

    jest.spyOn(flagService, 'isEnabled')

      .mockReturnValue(false)



    render(<CheckoutPage />)

    expect(screen.getByTestId('old-checkout')).toBeInTheDocument()

  })

})



// Integration test matrix

// ทดสอบ combinations ของ flags ที่อาจกระทบกัน

const flagCombinations = [

  { 'new-checkout': true, 'promo-bar': true },

  { 'new-checkout': true, 'promo-bar': false },

  { 'new-checkout': false, 'promo-bar': true },

  { 'new-checkout': false, 'promo-bar': false },

]

Monitoring Feature Flag Impact

// วัดผลกระทบของ flag ต่อ metrics

function trackFlagImpact(flagName, variant, metrics) {

  analytics.track('flag_evaluation', {

    flag: flagName,

    variant: variant,

    // Business metrics

    conversion_rate: metrics.conversion,

    revenue: metrics.revenue,

    // Technical metrics

    latency_p99: metrics.latencyP99,

    error_rate: metrics.errorRate,

    // User experience

    page_load_time: metrics.pageLoadTime,

    bounce_rate: metrics.bounceRate

  })

}



// Dashboard queries

// - เปรียบเทียบ conversion rate ระหว่าง control vs treatment

// - ดู error rate ก่อน/หลังเปิด flag

// - ดู latency impact ของ flag

// - ดู user engagement metrics

Best Practices

DoDon't
ตั้ง expiry date ให้ทุก flagปล่อย flag ค้างไว้ไม่มีกำหนด
ใช้ naming convention ชัดเจนตั้งชื่อ flag แบบ "flag1", "test123"
ทดสอบทั้ง on/off pathsทดสอบแค่ happy path
มี kill switch สำหรับ critical featuresไม่มีทางปิด feature ได้ทันที
Cleanup flags ที่ rollout 100% แล้วสะสม stale flags เป็นร้อยๆ
ใช้ centralized flag serviceกระจาย flag config ไปทั่ว codebase
Log flag evaluations สำหรับ debuggingไม่มี visibility ว่า flag ไหนเปิดอยู่
ใช้ server-side evaluation สำหรับ sensitive flagsส่ง flag logic ไปฝั่ง client ทั้งหมด

Anti-patterns ที่ต้องระวัง

  • Flag Explosion — มี flags มากเกินไป (>100) โดยไม่ cleanup ทำให้ codebase ซับซ้อน
  • Nested Flags — Flag ที่ depend กับ flag อื่น (if flag A && flag B && flag C) ยากต่อการ test
  • Permanent Release Flags — ใช้ Release Flag แบบ permanent แทนที่จะ cleanup
  • Flag-based Architecture — ออกแบบ architecture ทั้งหมดรอบ flags แทนที่จะใช้ proper abstraction
  • Missing Default — ไม่มี default value เมื่อ flag service ล่ม

Flag-driven Development Workflow

Step-by-step workflow สำหรับทีม

เนื้อหาเกี่ยวข้อง — อ่านต่อ: GitLab CI Include Consensus Algorithm

1. Product: สร้าง feature flag ใน dashboard

  • ตั้งชื่อ, description, owner, expiry

2. Dev: เขียน code wrap ด้วย flag

  • commit เข้า main ทุกวัน

3. QA: ทดสอบ flag on/off ใน staging

  • ทดสอบ edge cases, combinations

4. Release Manager: เปิด flag ให้ internal users

  • Dogfooding ภายใน 1-2 วัน

5. Gradual Rollout: 5% → 25% → 50% → 100%

เนื้อหาเกี่ยวข้อง — AWS Fargate Developer Experience DX

  • Monitor metrics ทุก stage

6. Cleanup: ลบ flag code + config

  • PR review + merge ภายใน 2 สัปดาห์

สรุป

Feature Flags เป็นเครื่องมือสำคัญสำหรับ Modern Software Delivery ช่วยให้ทีม Deploy ได้บ่อยขึ้น Release อย่างปลอดภัย และ Rollback ได้ทันทีเมื่อเกิดปัญหา เมื่อรวมกับ Progressive Delivery ทำให้สามารถ Release ฟีเจอร์ใหม่ให้ User กลุ่มเล็กก่อน ทดสอบกับ Traffic จริง แล้วค่อยขยายไปทั้งระบบ

เริ่มต้นง่ายๆ: เลือก Platform ที่เหมาะกับทีม (Unleash สำหรับ self-hosted, LaunchDarkly สำหรับ enterprise, PostHog สำหรับ flags + analytics) สร้าง flag แรก wrap ฟีเจอร์ใหม่ แล้วลอง rollout ทีละ 10% — คุณจะเข้าใจทันทีว่าทำไม Feature Flags ถึงเปลี่ยนวิธีที่เรา deliver software

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง