Nguyen Le PhongNguyen Le Phong

Feature flag để deploy an toàn hơn

Một bài nhìn thực tế về feature flag: cách chúng tách deploy khỏi release, hỗ trợ rollout từ từ và kill switch, đồng thời những việc team phải làm để tránh flag debt, hidden complexity và observability yếu.

Cuộc release call khá bình tĩnh cho đến khi một nghi ngại nhỏ xuất hiện. Code đã merge. Test đã pass. Deployment window đã mở. Nhưng checkout flow mới chạm vào payment, email, inventory và một promotion rule từng khá mong manh. Theo nhịp cũ, team hoặc ship hết rồi hy vọng, hoặc delay hết rồi giải thích. Với feature flag, có lựa chọn thứ ba: deploy code, giữ feature tắt, và chọn thời điểm release cẩn thận hơn.

Sự tách rời đó là giá trị chính của feature flag. Deployment là đưa code vào environment. Release là mở behavior cho user. Khi hai việc này buộc chặt với nhau, mỗi deploy có cảm giác lớn hơn cần thiết. Khi chúng được tách ra, team có thể ship code change nhỏ hơn, test trong điều kiện gần production hơn, bật feature cho internal user, rollout từ từ, và tắt behavior mà không cần redeploy ngay.

Một feature flag có hình dạng rất đơn giản: nếu condition này đúng, dùng path mới; nếu không, dùng path cũ. Condition có thể nhắm tới internal staff, một tenant, một quốc gia, một phần trăm traffic, beta group, hoặc tất cả trừ một segment rủi ro. Đằng sau nhánh nhỏ đó là một cách làm việc khác. Team giảm blast radius của thay đổi. Thay vì hỏi feature có an toàn cho cả thế giới không, team hỏi nó có an toàn cho nhóm nhỏ tiếp theo không.

Điều này đặc biệt hữu ích khi production reality quan trọng. Một số bug chỉ xuất hiện với traffic thật, data shape thật, tổ hợp browser thật, network timing thật, hoặc hành vi user thật. Staging quan trọng, nhưng staging không phải thế giới. Feature flag cho team học từ production mà không biến mọi user thành cùng một experiment trong cùng một lúc. Rollout cẩn thận có thể bắt đầu với team, rồi một account thân thiện, rồi năm phần trăm, rồi rộng hơn khi metric vẫn khỏe.

Kill switch là một lợi ích yên tĩnh khác. Nếu recommendation panel mới làm trang chậm, checkout experiment gây nhầm lẫn, hoặc third-party integration hành xử khác dự kiến, team có thể disable feature nhanh. Kill switch tốt không thay thế rollback, test hay incident response. Nó cho team thêm một mặt điều khiển. Đôi khi tắt một behavior an toàn hơn rollback toàn bộ deploy có chứa cả những fix không liên quan.

Feature flag cũng cải thiện collaboration khi work chưa hoàn tất. Team có thể merge backend change, rồi UI change, rồi analytics, rồi copy, tất cả đứng sau một flag đang tắt. Việc này giảm long-lived branch và merge conflict đau đầu. Code được integrate sớm trong khi behavior vẫn ẩn. Với team đang thực hành continuous integration, flag làm main branch bớt đáng sợ hơn vì work chưa xong không cần bị cô lập tới phút cuối.

Nhưng flag không miễn phí. Mỗi flag thêm một phiên bản reality có thể tồn tại. Path cũ và path mới đều phải hợp lý. Test có thể cần cover cả hai. Support cần biết customer nào thấy behavior nào. Analytics phải phân biệt experience cũ và mới. Nếu team thêm flag quá dễ dãi, codebase trở thành một hành lang đầy cửa hé mở. Không ai nhớ cửa nào còn quan trọng, và mọi thay đổi chậm lại vì các tổ hợp ẩn có thể vỡ.

Flag debt là technical debt thật. Một release flag thường nên có owner, purpose, creation date và removal plan. Nếu flag chỉ để rollout, hãy remove sau khi rollout xong. Nếu flag trở thành product setting lâu dài, hãy đối xử khác: document nó, test nó, expose nó có chủ đích, và đảm bảo business hiểu các variant nó tạo ra. Temporary flag không nên âm thầm trở thành permanent architecture.

Observability quyết định feature flag tạo confidence hay chỉ tạo thêm nút bấm. Khi flag được bật cho một nhóm, team nên thấy error rate, latency, conversion, support signal và business metric của nhóm đó so với path control khi phù hợp. Nếu feedback duy nhất là có vẻ ổn, flag chưa làm đủ việc. Progressive delivery cần progressive evidence.

Cũng có vấn đề về data và migration. Một số thay đổi không thể ẩn an toàn chỉ bằng một nhánh trong UI. Feature mới có thể cần database column, background job, permission model mới, hoặc event contract đã đổi. Khi đó team cần cách expand-and-contract: deploy data change backward-compatible, write cả hai format nếu cần, read cả hai an toàn, bật behavior từ từ, rồi remove path cũ sau. Flag chỉ là một phần của migration discipline.

Feature flag practice tốt thường khá nhàm theo nghĩa tốt. Tên rõ. Default an toàn. Ownership nhìn thấy được. Rollout rule dễ hiểu. Flag được review như code. Flag cũ được dọn. Dashboard cho thấy khác biệt giữa path enabled và disabled. Support biết customer đã thấy experience nào. Product có thể chọn tốc độ rollout mà không cần nhờ engineering redeploy cho mỗi thay đổi phần trăm nhỏ.

Feature flag làm deployment an toàn hơn vì chúng làm thay đổi dễ đảo ngược hơn, từ từ hơn và quan sát được hơn. Chúng không xóa nhu cầu design, testing, communication hay cleanup. Chúng cho team một cách bình tĩnh hơn để đưa thay đổi ra gặp reality. Lần tới khi một release có vẻ quá lớn, câu hỏi hữu ích có thể không phải delay hay rush. Có thể là team có làm change nhỏ hơn, đặt sau một flag rõ ràng, và học từ lát cắt đầu tiên trước khi mời tất cả user vào không?

Bạn thấy bài viết thế nào?