Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 47 — Feature Flag & Trunk-Based Development

Technical BA Masterclass Bài 47/60

Mở đầu — vì sao bài này quan trọng

Hãy hình dung một tình huống quen thuộc: đội phát triển vừa hoàn thành tính năng "thanh toán bằng ví điện tử" sau ba tuần làm việc. Code đã merge, đã test, sẵn sàng lên production. Nhưng khối Marketing lại muốn ra mắt tính năng đúng 0 giờ ngày mùng 1 để trùng với chiến dịch khuyến mãi. Theo cách làm truyền thống, đội kỹ thuật phải chờ tới đúng đêm đó mới deploy — nghĩa là cả nhóm thức trắng, hồi hộp xem có lỗi gì phát sinh không, và nếu hỏng thì gần như không kịp xử lý.

Có một cách làm thông minh hơn: deploy code lên production từ tuần trước, nhưng để tính năng ở trạng thái tắt. Đến đúng 0 giờ mùng 1, một người chỉ cần bật một công tắc trong dashboard — không deploy lại, không thức đêm, không rủi ro hạ tầng. Công tắc đó chính là Feature Flag (cờ tính năng).

Là một Technical BA, bạn không phải người viết code bật/tắt flag, nhưng bạn là người viết spec quyết định: tính năng này có cần flag không? Bật cho ai trước? Rollout theo phần trăm nào? Khi nào tắt? Ai có quyền bật? Đây là những quyết định nghiệp vụ trá hình dưới lớp áo kỹ thuật — và nếu spec sai, hậu quả có thể là một sự cố production hoặc một chiến dịch ra mắt thất bại. Bài này giúp bạn hiểu sâu Feature Flag và mô hình Trunk-Based Development đi kèm, để bạn viết spec đúng và phối hợp hiệu quả với đội kỹ thuật.

Khái niệm cốt lõi

Deploy không bằng Release

Đây là tư tưởng nền tảng của cả bài. Trong cách làm cũ, hai khái niệm này dính chặt vào nhau: hễ đẩy code lên production là tính năng tự động xuất hiện với người dùng. Feature Flag tách bạch chúng:

  • Deploy (triển khai): hành động kỹ thuật, đưa code lên môi trường production. Code đã ở đó nhưng có thể đang "ngủ".
  • Release (phát hành): hành động nghiệp vụ, cho người dùng thực sự nhìn thấy và dùng được tính năng. Chỉ là một thao tác bật flag.
Sự tách bạch này thay đổi căn bản cách quản lý rủi ro. Đội kỹ thuật có thể deploy nhiều lần mỗi ngày một cách bình thản, vì code mới luôn ẩn sau flag tắt. Còn việc release thì do business quyết định thời điểm, độc lập với lịch deploy.

Feature Flag là gì về bản chất

Về bản chất, Feature Flag chỉ là một câu lệnh điều kiện trong code:

if (flagService.isEnabled("vi-dien-tu", user)) {
    // hiển thị luồng thanh toán ví điện tử mới
} else {
    // giữ luồng thanh toán cũ
}

Giá trị của flag (true/false) không nằm cứng trong code mà được điều khiển từ bên ngoài — qua một dashboard quản lý (như LaunchDarkly, Unleash, hoặc một bảng cấu hình tự xây). Người vận hành thay đổi giá trị này theo thời gian thực mà không cần đụng tới code hay deploy lại.

Bốn loại Feature Flag theo mục đích

Đây là phần quan trọng nhất với BA, vì mỗi loại flag phục vụ một mục tiêu nghiệp vụ khác nhau và có vòng đời khác nhau:

1. Release Flag (cờ phát hành): Tách deploy khỏi release như ví dụ đầu bài. Vòng đời ngắn — bật xong, ổn định rồi thì gỡ flag khỏi code. Ví dụ: tính năng ví điện tử bật đúng 0 giờ mùng 1.

2. Experiment Flag / A/B Test (cờ thử nghiệm): Chia người dùng thành nhóm để so sánh. Ví dụ 50% người dùng thấy nút "Mua ngay" màu cam, 50% thấy màu xanh, rồi đo tỉ lệ chuyển đổi. Vòng đời bằng thời gian chạy thí nghiệm.

3. Operational Flag / Kill Switch (cờ vận hành / công tắc khẩn cấp): Cho phép tắt nhanh một tính năng đang gây sự cố mà không cần rollback toàn bộ. Nếu tính năng gợi ý sản phẩm bằng AI làm chậm cả website, ops chỉ cần tắt flag đó, website trở lại bình thường ngay. Loại này thường sống lâu, là "phanh khẩn cấp" của hệ thống.

4. Permission Flag (cờ phân quyền): Bật tính năng cho một nhóm người dùng cụ thể — ví dụ chỉ khách hàng VIP hoặc nhân viên nội bộ mới thấy tính năng beta. Loại này có thể tồn tại vĩnh viễn như một phần của mô hình phân quyền.

Gradual Rollout — phát hành dần dần

Thay vì bật tính năng cho 100% người dùng một lúc, ta bật dần: 1% → 5% → 25% → 50% → 100%. Mỗi bước, đội theo dõi log lỗi, tốc độ, phản hồi. Nếu 1% đầu tiên gặp lỗi, chỉ 1% người dùng bị ảnh hưởng thay vì toàn bộ. Đây gọi là canary release (phát hành kiểu "chim hoàng yến trong mỏ than" — nhóm nhỏ cảnh báo nguy hiểm trước).

Trunk-Based Development

Mô hình nhánh code này gắn liền với Feature Flag. Trong cách làm cũ (GitFlow), mỗi tính năng có một nhánh riêng sống nhiều tuần, rồi merge một lần — gây ra "địa ngục merge" khi nhiều nhánh xung đột. Trunk-Based Development thì ngược lại: mọi lập trình viên merge code vào nhánh chính (main/trunk) hàng ngày, mỗi lần một mẩu nhỏ.

Câu hỏi đặt ra: nếu merge code chưa hoàn thiện vào nhánh chính, chẳng phải sẽ làm hỏng sản phẩm? Đây chính là lúc Feature Flag vào cuộc. Code chưa xong được merge nhưng ẩn sau một flag đang tắt — nó nằm trên production mà không ai thấy, cho tới khi hoàn thiện và sẵn sàng bật. Feature Flag là thứ khiến Trunk-Based Development khả thi.

Tình huống thực tế

Tình huống 1 — Sàn TMĐT bật tính năng "mua trước trả sau" cho ngày đôi

Một sàn thương mại điện tử lớn tại Việt Nam (gọi là sàn X) muốn ra mắt tính năng "mua trước trả sau" (BNPL) đúng dịp 11/11. Áp lực rất lớn: nếu lỗi vào ngày sale, thiệt hại doanh thu có thể lên tới hàng tỉ đồng mỗi giờ.

Bối cảnh: Đội kỹ thuật hoàn thành code trước ngày sale một tuần và deploy lên production, nhưng để flag bnpl ở trạng thái tắt. BA viết spec rollout như sau: 0h ngày 11/11 bật cho 5% người dùng ở TP.HCM; sau 30 phút nếu tỉ lệ lỗi dưới 0,5% thì nâng lên 25%; sau 1 giờ nâng lên 100% toàn quốc. Đồng thời spec ghi rõ một kill switch: nếu đối tác cấp tín dụng (bên thứ ba) trả lỗi quá 5%, tự động tắt flag và quay về luồng thanh toán cũ.

Diễn giải: Đúng 0h, flag bật cho 5%. Hệ thống đối tác tín dụng quá tải, trả lỗi 8%. Kill switch kích hoạt, tính năng tắt, người dùng chuyển về thanh toán thường mà không hề thấy màn hình lỗi. Đội xử lý với đối tác trong 40 phút, rồi bật lại. Kết quả: sự cố chỉ ảnh hưởng 5% người dùng trong 40 phút, không ai phải rollback toàn bộ hệ thống giữa đêm sale.

Bài học: Spec rollout có ngưỡng số cụ thể (0,5%, 5%, 25%) và kill switch tự động là khác biệt giữa một sự cố nhỏ và một thảm họa. BA không cần biết code, nhưng phải biết đặt ra các ngưỡng nghiệp vụ này.

Tình huống 2 — Fintech A/B test màn hình onboarding

Một công ty fintech ở Singapore mở rộng sang Việt Nam, muốn biết quy trình mở tài khoản (onboarding) nào hiệu quả hơn: bản 5 bước chi tiết hay bản 3 bước rút gọn.

Bối cảnh: Thay vì tranh cãi dựa trên cảm tính trong phòng họp, đội dùng Experiment Flag chia ngẫu nhiên người dùng mới thành hai nhóm 50/50. BA định nghĩa chỉ số thành công rõ ràng trong spec: tỉ lệ hoàn tất mở tài khoản và tỉ lệ nạp tiền lần đầu trong 7 ngày. Thí nghiệm chạy hai tuần trên khoảng 8.000 người dùng mới.

Diễn giải: Kết quả bất ngờ. Bản 3 bước rút gọn có tỉ lệ hoàn tất cao hơn (72% so với 61%), nhưng tỉ lệ nạp tiền lần đầu lại thấp hơn (vì người dùng đăng ký vội mà chưa thực sự cam kết). Nhờ đo cả hai chỉ số, đội nhận ra rút gọn quá mức không phải lúc nào cũng tốt, và chọn một phương án lai (4 bước).

Bài học: Vai trò của BA trong A/B test không phải là bật flag, mà là định nghĩa chỉ số đo lường đúng. Nếu chỉ đo "tỉ lệ hoàn tất", đội đã chọn nhầm phương án. Một chỉ số phù phiếm (vanity metric) có thể dẫn tới quyết định sai.

Tình huống 3 — Ngân hàng số dọn dẹp flag bị bỏ quên

Một ngân hàng số tại Việt Nam dùng Feature Flag rộng rãi, nhưng sau hai năm tích lũy hơn 300 flag trong code, nhiều flag đã bật 100% từ lâu mà không ai gỡ.

Bối cảnh: Một flag cũ tên new-transfer-limit (giới hạn chuyển khoản mới) lẽ ra đã bật vĩnh viễn, nhưng do lỗi cấu hình trong một lần triển khai môi trường mới, nó vô tình về trạng thái tắt. Hậu quả: hạn mức chuyển khoản quay về giá trị cũ thấp hơn, hàng loạt khách hàng doanh nghiệp không chuyển được khoản lớn, tổng đài quá tải.

Diễn giải: Mất nửa ngày để truy ra nguyên nhân vì không ai nhớ flag này còn tồn tại và làm gì. Sau sự cố, đội lập quy trình: mỗi Release Flag phải có ngày hết hạn trong spec, và BA phối hợp rà soát hàng quý để gỡ flag đã ổn định.

Bài học: Flag không được dọn dẹp trở thành "nợ kỹ thuật" (technical debt) và là nguồn rủi ro tiềm ẩn. BA nên đưa "vòng đời và điều kiện gỡ flag" vào spec ngay từ đầu, không để flag sống mãi.

Hướng dẫn từng bước

Khi bạn là BA viết spec cho một tính năng dùng Feature Flag, hãy đi theo các bước sau:

Bước 1 — Xác định tính năng có cần flag không. Không phải mọi thứ đều cần. Một sửa lỗi chính tả nhỏ thì không. Cần flag khi: tính năng rủi ro cao, cần ra mắt theo thời điểm, cần A/B test, hoặc cần khả năng tắt khẩn cấp.

Bước 2 — Chọn loại flag. Đây là Release Flag, Experiment Flag, Operational Flag hay Permission Flag? Việc này quyết định vòng đời và cách viết spec phần sau.

Bước 3 — Đặt tên flag rõ ràng và quy ước nhất quán. Ví dụ payment-bnpl-2026q4 tốt hơn flag1 hay tinh-nang-moi. Tên nên gợi ý mục đích, nhóm tính năng và thời điểm.

Bước 4 — Viết chiến lược rollout với ngưỡng số cụ thể. Ghi rõ phần trăm từng bước, đối tượng (theo vùng, theo nhóm khách hàng), và điều kiện để chuyển bước (ví dụ: "nâng lên bước tiếp theo nếu tỉ lệ lỗi dưới 0,5% sau 30 phút").

Bước 5 — Định nghĩa kill switch và điều kiện kích hoạt. Với tính năng quan trọng, nêu rõ điều kiện tự động tắt và hành vi dự phòng (fallback) — người dùng sẽ thấy gì khi flag tắt giữa chừng.

Bước 6 — Định nghĩa chỉ số đo lường (đặc biệt với Experiment Flag). Chỉ số chính, chỉ số phụ, ngưỡng để kết luận thắng/thua, thời gian chạy tối thiểu.

Bước 7 — Quy định quyền bật/tắt. Ai được phép thay đổi flag này? Production thường cần quyền cao hơn môi trường thử nghiệm.

Bước 8 — Ghi điều kiện và thời hạn gỡ flag. Khi nào tính năng được coi là ổn định và flag được gỡ khỏi code? Đặt ngày rà soát.

Lỗi thường gặp & mẹo

Lỗi 1 — Để flag sống mãi. Như tình huống ngân hàng, flag không gỡ tích tụ thành nợ kỹ thuật và rủi ro. Mẹo: mỗi Release Flag phải có ngày hết hạn trong spec.

Lỗi 2 — Quên định nghĩa hành vi fallback. Spec chỉ tả "khi bật thì làm gì" mà quên "khi tắt thì người dùng thấy gì". Khi kill switch kích hoạt mà fallback không rõ, người dùng có thể gặp màn hình trắng. Mẹo: luôn viết cả hai nhánh if/else trong spec.

Lỗi 3 — Flag lồng nhau quá phức tạp. Khi flag A phụ thuộc flag B phụ thuộc flag C, không ai hiểu nổi trạng thái cuối là gì. Mẹo: giữ logic flag phẳng, tránh phụ thuộc chéo.

Lỗi 4 — Nhầm tưởng deploy là release với business. BA cần truyền đạt rõ cho các bên: code đã lên không có nghĩa khách hàng đã thấy. Tránh hiểu lầm khi báo cáo tiến độ. Mẹo: trong báo cáo, tách rõ "đã deploy" và "đã release".

Lỗi 5 — A/B test dừng quá sớm. Thấy một bên nhỉnh hơn sau hai ngày là vội kết luận, trong khi số liệu chưa đủ tin cậy. Mẹo: định nghĩa trước thời gian chạy và cỡ mẫu tối thiểu, không dừng sớm vì sốt ruột.

Mẹo phối hợp: Khi làm việc với đội kỹ thuật, hãy hỏi sớm: "Tính năng này có nên đặt sau flag không?" Đặt câu hỏi này lúc viết spec, không phải lúc sắp deploy — vì gắn flag vào code sau khi đã viết xong rất tốn công.

Bài tập thực hành

Bài 1 — Phân loại flag. Cho bốn tình huống, hãy xác định mỗi cái dùng loại flag nào: (a) ra mắt tính năng quà tặng đúng dịp Tết; (b) thử hai cách hiển thị giá để xem cái nào bán tốt hơn; (c) tắt nhanh tính năng livestream khi server quá tải; (d) chỉ cho nhân viên nội bộ dùng thử bản beta. Giải thích lựa chọn.

Bài 2 — Viết chiến lược rollout. Bạn là BA cho tính năng "đăng nhập bằng sinh trắc học" của một ứng dụng ngân hàng có 2 triệu người dùng. Hãy viết kế hoạch rollout theo bước với phần trăm cụ thể, đối tượng từng bước, và ít nhất một điều kiện kill switch. Nêu rõ chỉ số bạn sẽ theo dõi ở mỗi bước.

Bài 3 — Thiết kế A/B test. Một sàn TMĐT muốn biết nút "Thêm vào giỏ" nên đặt trên hay dưới phần mô tả sản phẩm. Hãy định nghĩa: chỉ số chính, chỉ số phụ, tỉ lệ chia nhóm, thời gian chạy tối thiểu, và điều kiện kết luận.

Bài 4 — Phản biện. Một đồng nghiệp nói: "Cứ deploy thẳng tính năng, cần gì flag cho phức tạp." Hãy viết ba lập luận thuyết phục họ rằng flag đáng giá cho tính năng rủi ro cao, kèm một tình huống thực tế.

Tóm tắt

Feature Flag tách bạch hai việc vốn bị gộp chung: deploy (đưa code lên — việc kỹ thuật) và release (cho người dùng thấy — việc nghiệp vụ). Sự tách bạch này mở ra khả năng ra mắt theo thời điểm, A/B test, phát hành dần dần (gradual rollout/canary), và tắt khẩn cấp (kill switch). Có bốn loại flag chính theo mục đích — release, experiment, operational, permission — mỗi loại có vòng đời riêng. Feature Flag cũng là nền tảng khiến Trunk-Based Development khả thi: code chưa hoàn thiện được merge vào nhánh chính hàng ngày nhưng ẩn sau flag tắt, tránh "địa ngục merge".

Là Technical BA, vai trò của bạn không phải bật/tắt flag mà là viết spec quyết định: loại flag, chiến lược rollout với ngưỡng số cụ thể, kill switch và fallback, chỉ số đo lường, quyền hạn, và điều kiện gỡ flag. Ba sai lầm tốn kém nhất cần tránh là: để flag sống mãi thành nợ kỹ thuật, quên định nghĩa hành vi fallback, và kết luận A/B test quá sớm. Nắm vững những điều này, bạn sẽ giúp đội phát triển ra mắt tính năng an toàn, đo lường được, và bình tĩnh trước rủi ro.