개발/Spring Boot

Spring Boot 고급 시리즈 9편 – API 버전 없이 유연한 기능 확장: Feature Flag와 조건 분기 전략

B컷개발자 2025. 4. 22. 21:30

Spring Boot에서 Feature Flag와 조건 분기 전략을 활용해 API 버전 없이 기능을 점진적으로 확장하는 방법을 설명합니다. 실무 예제와 설계 원칙 포함.


Spring Boot 고급 시리즈 9편 – API 버전 없이 유연한 기능 확장: Feature Flag와 조건 분기 전략

API 기능을 개선하거나 새로운 기능을 추가할 때,
기존에는 /v1, /v2와 같이 버전을 나누는 방식이 일반적이었습니다.
그러나 모든 변경이 반드시 새로운 버전을 의미하진 않습니다.

이번 글에서는 버전을 늘리지 않고도 유연하게 기능을 제어할 수 있는
Feature Flag(기능 플래그) 전략과 조건 기반 분기 처리 방법을 다룹니다.


📌 1. 왜 버전 없이 기능을 분기해야 할까?

  • API 경로 변경 없이 유지보수성 향상
  • A/B 테스트, 점진적 기능 배포, 환경별 기능 제어 가능
  • 운영 중에도 릴리즈 관리와 롤백이 빠름
  • 클라이언트별로 유연한 기능 적용 로직 설계

🔧 2. Feature Flag란?

Feature Flag는 코드 내 특정 기능을 동적으로 켜고 끌 수 있는 스위치입니다.

✅ 주요 활용 사례

  • 신규 기능 점진적 적용 (rollout)
  • 특정 고객 그룹 대상 A/B 테스트
  • 베타 기능 제공
  • 긴급 상황에서 기능 빠른 비활성화

✅ 3. 조건 기반 분기 설계 전략

1️⃣ Controller 또는 Service 내 조건 분기 예시

@RestController
@RequiredArgsConstructor
public class RecommendationController {

    private final RecommendationService recommendationService;
    private final FeatureToggleService featureToggleService;

    @GetMapping("/api/v1/recommend")
    public ResponseEntity<?> getRecommendations(@RequestParam Long userId) {

        if (featureToggleService.isEnabled("new-algo")) {
            return ResponseEntity.ok(recommendationService.newAlgorithm(userId));
        }

        return ResponseEntity.ok(recommendationService.oldAlgorithm(userId));
    }
}

✅ 단점 보완 전략

  • 분기가 많아지면 서비스 코드가 오염됨
  • FeatureEvaluator, Strategy 패턴, Aspect를 통해 책임 분리 가능

🛠️ 4. Feature Toggle 구현 방법

1️⃣ application.yml 기반 구성 (간단)

features:
  new-algo: true
  beta-mode: false
@Component
@ConfigurationProperties(prefix = "features")
@Getter
@Setter
public class FeatureToggleConfig {
    private Map<String, Boolean> toggles = new HashMap<>();

    public boolean isEnabled(String key) {
        return toggles.getOrDefault(key, false);
    }
}
  • 코드 변경 없이 YAML 수정만으로 기능 제어 가능
  • 배포 자동화 시스템(CI/CD)와 연계하면 실시간 기능 토글 가능

2️⃣ DB 기반 플래그 관리 (운영 중 실시간 변경 가능)

@Entity
public class FeatureFlag {
    @Id
    private String name;
    private boolean enabled;
}
public interface FeatureFlagRepository extends JpaRepository<FeatureFlag, String> {}
@Service
@RequiredArgsConstructor
public class FeatureToggleService {

    private final FeatureFlagRepository repository;

    public boolean isEnabled(String featureName) {
        return repository.findById(featureName)
                         .map(FeatureFlag::isEnabled)
                         .orElse(false);
    }
}
  • 관리자 페이지에서 UI로 실시간 제어 가능
  • 동시 다발적인 A/B 테스트 및 퍼센트 롤아웃 가능

🧠 실무 팁 – 클린한 기능 분기 설계

전략 설명

Strategy 패턴 기능 구현을 각각의 클래스로 분리 후 런타임 선택
AOP 기반 제어 기능 실행 전후 동작을 공통화
컨텍스트 분리 기능 조건을 FeatureContext로 캡슐화
조건 캐싱 Redis 등에 캐싱하여 트래픽 대응 성능 확보
테스트 분리 각 분기별 테스트 케이스를 명확히 분리

🧪 예시: Feature Flag + Strategy 조합

public interface RecommendStrategy {
    List<Product> recommend(Long userId);
}

@Component("new")
public class NewRecommendStrategy implements RecommendStrategy {
    public List<Product> recommend(Long userId) {
        return List.of(); // 신 알고리즘
    }
}

@Component("old")
public class OldRecommendStrategy implements RecommendStrategy {
    public List<Product> recommend(Long userId) {
        return List.of(); // 기존 방식
    }
}
@Service
@RequiredArgsConstructor
public class RecommendationService {

    private final FeatureToggleService toggleService;
    private final Map<String, RecommendStrategy> strategyMap;

    public List<Product> recommend(Long userId) {
        String key = toggleService.isEnabled("new-algo") ? "new" : "old";
        return strategyMap.get(key).recommend(userId);
    }
}
  • 전략은 Bean으로 관리, Feature Flag는 key 결정만 담당
  • 각 전략은 독립 테스트 가능

✅ 마무리 요약

항목 요약

목적 API 버전 없이 유연하게 기능 제어
기술 @Value, ConfigurationProperties, DB 기반 플래그, Strategy 패턴
추천 방식 YAML 초기 구성 → 운영 중 DB/관리자 UI 기반 확장
설계 팁 Controller 분기 지양, 서비스/전략 객체로 분리, 테스트 가능성 확보
사용 시점 실험적 기능, 단계적 배포, 긴급 대응

📌 다음 편 예고

Spring Boot 고급 시리즈 10편: 멀티 모듈 구조로 서비스 분리 – 실전 프로젝트 아키텍처 설계 전략

 

LIST