점진적 소프트웨어 출시 전략: 단순한 If/Else를 넘어 Feature Flags
Source: Dev.to
Feature Toggles란?
우주 로켓(당연히 여러분의 소프트웨어)을 만든다고 상상해 보세요! 새로운 섹션이 여러 개 있습니다: 공간 왜곡 엔진, 홀로그램 엔터테인먼트 시스템, 그리고 로봇 어시스턴트. 모든 것을 한 번에 테스트 없이 발사하고 싶지는 않겠죠? 만약 공간 왜곡 엔진에 문제가 생기면, 로켓을 착륙시키고 부품을 교체하지 않고도 빠르게 끌어낼 수 있기를 원합니다.
Feature Toggles는 바로 그 역할을 하는 코드 내 제어 스위치입니다. 실행 시점에 특정 기능을 켜거나 끌 수 있게 해 줍니다. 이 스위치는 deploy와 기능 출시를 분리합니다. 즉, 새로운 코드를 (기능이 꺼진 상태로) 프로덕션에 배포하고, 준비가 되면 원하는 사용자에게 혹은 특정 조건에서만 기능을 활성화할 수 있습니다.
Pete Hodgson은 Feature Toggles를 수명과 동적 특성에 따라 분류합니다. 이러한 카테고리를 이해하는 것은 토글을 효과적으로 사용하고, 오래된 토글이 초래하는 두려운 “기술 부채”를 피하는 데 필수적입니다.
Feature Toggles 카테고리
| 카테고리 | 지속 기간 | 역동성 | 주요 목적 | 사용 예시 | 관리 |
|---|---|---|---|---|---|
| Release Toggles | 짧음 (일/주) | 낮음 | 불완전한 기능이나 조정된 출시를 위해 기능을 활성화/비활성화. | 특정 날짜에 모든 고객에게 새로운 사용자 인터페이스를 출시. | 전체 출시 후 제거. |
| Experiment Toggles | 중간 (주) | 높음 | A/B 테스트, 다변량 테스트. | 서로 다른 사용자 그룹에 구매 버튼의 두 버전을 보여주어 어느 것이 더 전환되는지 확인. | 실험 및 결정 후 제거. |
| Ops Toggles | 짧음/길음 | 높음 | 운영 제어, “킬 스위치”. | 트래픽 급증 시 높은 리소스를 소비하는 기능을 비활성화. | 필수 “킬 스위치”는 유지하고, 안정화 후 다른 스위치는 제거. |
| Permissioning Toggles | 길음 (개월/년) | 높음 | 특정 사용자/그룹을 위한 맞춤형 경험. | 구독자를 위한 “프리미엄” 기능, 베타 테스터를 위한 사전 접근. | 영구적일 수 있으며 비즈니스 로직의 일부. |
Source: …
실용 예제: FastAPI + Feature Toggles
간단한 시나리오를 만들어 보겠습니다: FastAPI API에 최적화된 배송비 계산이라는 새로운 기능이 있습니다. 코드를 배포하고 싶지만, 이 기능은 선택된 사용자 그룹에게만 혹은 특정 시점에만 활성화하고자 합니다.
1. Poetry를 사용해 FastAPI 프로젝트 만들기
poetry new feature-toggle-app
cd feature-toggle-app
poetry add fastapi uvicorn
2. main.py 파일
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def hello_world():
return {"status": "ok"}
3. 토글 관리 (feature_flags.py 파일)
단순화를 위해 딕셔너리를 사용합니다. 실제 환경에서는 외부 서비스(LaunchDarkly, Unleash, 데이터베이스, config server 등)에서 가져올 수 있습니다.
# feature_flags.py
FEATURE_TOGGLES = {
"OTIMIZED_SHIPPING": False, # 우리의 Release Toggle
"NEW_DASHBOARD_BETA": False, # Permissioning/Experiment Toggle 예시
}
def is_feature_enabled(feature_name: str) -> bool:
"""토글이 활성화돼 있으면 True를 반환합니다."""
return FEATURE_TOGGLES.get(feature_name, False)
4. API에서 토글 사용하기 (main.py 업데이트)
# main.py
from fastapi import FastAPI, HTTPException
from feature_flags import is_feature_enabled
app = FastAPI()
@app.get("/")
async def hello_world():
return {"status": "ok"}
@app.get("/shipping_cost/{item_id}")
async def get_shipping_cost(item_id: int):
"""
배송비를 계산합니다.
- OTIMIZED_SHIPPING이 활성화돼 있으면 → 최적화된 계산.
- 그렇지 않으면 → 기존 계산.
"""
if is_feature_enabled("OTIMIZED_SHIPPING"):
# 새로운 최적화된 배송비 계산 로직
cost = item_id * 0.5 # 예시: 더 저렴한 계산
method = "optimized"
else:
# 기존 배송비 계산 로직
cost = item_id * 1.0 # 예시: 기본 계산
method = "standard"
return {"item_id": item_id, "cost": cost, "method": method}
# 토글이 활성화돼 있을 때만 나타나는 엔드포인트
@app.get("/admin/new_dashboard")
async def new_admin_dashboard():
if not is_feature_enabled("NEW_DASHBOARD_BETA"):
raise HTTPException(status_code=404, detail="New dashboard not available")
return {"message": "베타 새 관리 대시보드에 오신 것을 환영합니다!"}
5. 애플리케이션 실행
poetry run uvicorn main:app --reload
6. 토글 테스트하기
-
http://127.0.0.1:8000/shipping_cost/10에 접속합니다.- “standard” 메서드가 표시됩니다.
-
feature_flags.py에서OTIMIZED_SHIPPING을True로 바꾸고 저장합니다.uvicorn이 자동으로 재시작됩니다. -
다시
http://127.0.0.1:8000/shipping_cost/10에 접속합니다.- 이제 “optimized” 메서드가 표시됩니다!
이것이 Release Toggle이 실제로 동작하는 모습입니다! 코드를 비활성화된 상태로 배포하고, 필요할 때 언제든 새 기능을 활성화할 수 있으며, 새로운 배포가 필요하지 않습니다.
모범 사례와 함정
- 토글을 잘 이름 짓기:
OTIMIZED_SHIPPING같은 명확한 이름이FEATURE_A보다 좋습니다. 이름은 기능의 목적을 나타내야 합니다. - 분류 체계 유지: 카테고리(Release, Experiment, Ops, Permissioning)를 사용하여 장기성과 관리에 안내하십시오.
- 구식 토글 제거: Release 및 Experiment 토글은 목적을 달성하면 즉시 제거해야 합니다. 이는 기술 부채입니다! 제거 일정을 잡으세요.
- 과도한 “if‑else” 피하기: 조건문이 많은 코드는 유지하기 어려운 얽힌 구조가 될 수 있습니다. 더 깔끔한 API를 제공하는 추상화나 피처 플래그 라이브러리를 고려하세요.
- 각 토글 문서화: 누가 만들었는지, 왜 만들었는지, 언제 제거해야 하는지, 책임자는 누구인지 기록하세요.
참고문헌
코드 격리
- 목표: 토글 뒤에 있는 기능의 코드를 격리해 보세요.
- 팁:
if is_feature_enabled(...)를 코드베이스 전체에 퍼뜨리는 것을 피하세요.
테스트
- 두 경로 모두 테스트하십시오 (토글 켜짐 및 꺼짐).
- 테스트는 모든 변형을 포함해야 합니다.
관리 도구
대규모 프로젝트의 경우 LaunchDarkly, Unleash, Split.io와 같은 전용 도구 사용을 고려하세요. 이들은 다음을 제공합니다:
- 대시보드
- 사용자 세분화
- 중앙 집중식 관리
Feature Toggle 유형 및 권장 사항
| Toggle 유형 | 제거 / 유지 시점 | 비고 |
|---|---|---|
| Release Toggle | 기능이 완전히 출시되고 안정화되면 즉시 제거하십시오. | if와 오래된 코드를 제거하도록 리팩터링하십시오. |
| Experiment Toggle | 실험이 종료되고 기능을 유지할지 폐기할지 결정된 후 제거하십시오. | |
| Ops Toggle | 필수적인 “킬 스위치”만 유지하십시오. | 정기적으로 검토하십시오. |
| Permissioning Toggle | 장기간 사용할 수 있지만, 잘 문서화하고 비즈니스 로직의 일부로 다루어야 합니다. |
Note: Feature Toggle의 가장 큰 도전은 관리입니다. 코드에 오래 남아 있는 Release Toggle은 실수로 Permissioning 또는 Ops Toggle이 되어 불필요한 복잡성을 추가합니다.
Feature Toggles의 장점
- 배포 위험 감소
- 프로덕션에서 A/B 테스트 및 실험 용이
- 사용자 하위 집합에 기능을 제공 가능
- 프로덕션 문제에 신속히 대응 가능
이 기술을 현명하게 도입하면 소프트웨어 품질은 물론 팀의 신뢰와 속도도 향상됩니다.
참고문헌
- Fowler, Martin. Feature Toggles (aka Feature Flags). MartinFowler.com, 2017. Disponível em: .