1. 개요

이 기사에서는 기능 플래그를 간략하게 정의하고 Spring Boot 애플리케이션에서이를 구현하기위한 독단적이고 실용적인 접근 방식을 제안합니다. 그런 다음 다양한 Spring Boot 기능을 활용하여 더 정교한 반복을 파헤칩니다.

기능 플래그 지정이 필요할 수있는 다양한 시나리오에 대해 논의하고 가능한 솔루션에 대해 이야기합니다. Bitcoin Miner 예제 애플리케이션을 사용하여이를 수행합니다.

2. 기능 플래그

기능 토글이라고도하는 기능 플래그는 코드를 수정하거나 앱을 재배포하지 않고도 애플리케이션의 특정 기능을 활성화 또는 비활성화 할 수있는 메커니즘입니다.

특정 기능 플래그에 필요한 역학에 따라 전역 적으로, 앱 인스턴스별로 또는 더 세부적으로 (아마도 사용자 또는 요청별로) 구성해야 할 수 있습니다.

소프트웨어 엔지니어링의 많은 상황과 마찬가지로 불필요한 복잡성을 추가하지 않고 당면한 문제를 해결하는 가장 간단한 접근 방식을 사용하는 것이 중요합니다.

기능 플래그는 현명하게 사용하면 시스템에 안정성과 안정성을 제공 할 수있는 강력한 도구입니다. 그러나 잘못 사용되거나 유지 관리가 부족하면 신속하게 복잡성과 골치 아픈 원인이 될 수 있습니다.

기능 플래그가 유용 할 수있는 많은 시나리오가 있습니다.

트렁크 기반 개발 및 중요하지 않은 기능

트렁크 기반 개발에서, 특히 자주 통합하려는 경우 특정 기능을 출시 할 준비가되어 있지 않을 수 있습니다. 기능 플래그를 사용하면 완료 될 때까지 변경 사항을 적용하지 않고도 계속 릴리스 할 수 있습니다.

환경 별 구성

E2E 테스트 환경을 위해 DB를 재설정하려면 특정 기능이 필요할 수 있습니다.

또는 프로덕션 환경에서 사용되는 것과 비 프로덕션 환경에 대해 다른 Security 구성을 사용해야 할 수도 있습니다.

따라서 기능 플래그를 활용하여 올바른 환경에서 올바른 설정을 전환 할 수 있습니다.

A / B 테스트

동일한 문제에 대한 여러 솔루션을 출시하고 영향을 측정하는 것은 기능 플래그를 사용하여 구현할 수있는 강력한 기술입니다.

카나리아 출시

새로운 기능을 배포 할 때 소규모 사용자 그룹부터 시작하여 동작의 정확성을 검증 할 때 채택을 확대하는 등 점진적으로 수행하기로 결정할 수 있습니다. 기능 플래그를 통해이를 달성 할 수 있습니다.

다음 섹션에서는 위에서 언급 한 시나리오를 해결하기위한 실용적인 접근 방식을 제공하려고합니다.

가장 간단한 시나리오부터 시작하여 더 세분화되고 복잡한 설정으로 이동하는 기능 플래그 지정에 대한 다양한 전략을 분석해 보겠습니다.

3. 애플리케이션 레벨 기능 플래그

처음 두 사용 사례 중 하나를 해결해야하는 경우 애플리케이션 수준 기능 플래그는 작업을 수행하는 간단한 방법입니다.

간단한 기능 플래그는 일반적으로 속성 및 해당 속성의 값을 기반으로하는 일부 구성을 포함합니다.

3.1. Spring 프로파일을 사용하는 기능 플래그

Spring에서는 프로필을 활용할있습니다 . 편리하게도 프로파일을 통해 특정 빈을 선택적으로 구성 할 수 있습니다. 주변에 몇 가지 구성을 사용하면 애플리케이션 수준 기능 플래그를위한 간단하고 우아한 솔루션을 신속하게 만들 수 있습니다.

우리가 BitCoin 채굴 시스템을 구축하고 있다고 가정 해 봅시다. 우리의 소프트웨어는 이미 생산 중이며 실험적이고 개선 된 채굴 알고리즘을 만들어야합니다.

우리에 JavaConfig 우리는 우리의 구성 요소를 프로파일 링 할 수 :

@Configuration
public class ProfiledMiningConfig {

    @Bean
    @Profile("!experimental-miner")
    public BitcoinMiner defaultMiner() {
        return new DefaultBitcoinMiner();
    }

    @Bean
    @Profile("experimental-miner")
    public BitcoinMiner experimentalMiner() {
        return new ExperimentalBitcoinMiner();
    }
}

그런 다음 이전 구성에서 새 기능에 대한 옵트 인을 위해 프로필을 포함하기 만하면됩니다. 거기 우리의 응용 프로그램을 구성하는 방법의 톤 일반과 특히 프로파일을 가능가 . 마찬가지로 우리의 삶을 더 쉽게 만들어주는 테스트 유틸리티 가 있습니다.

시스템이 충분히 단순하다면 환경 기반 구성을 만들어 적용 할 기능 플래그와 무시할 기능을 결정할 수 있습니다.

이전 실험용 채굴 기와 함께 테이블 대신 카드를 기반으로하는 새로운 UI가 있다고 가정 해 봅시다.

수락 환경 (UAT)에서 두 기능을 모두 활성화하려고합니다. application.yml 파일 에 다음 프로필 그룹을 만들 수 있습니다 .

spring:
  profiles:
    group:
      uat: experimental-miner,ui-cards

이전 속성을 제자리에두고 원하는 기능 집합을 얻으려면 UAT 환경에서 UAT 프로필을 활성화하면됩니다. 물론 프로젝트에 application-uat.yml 파일을 추가하여 환경 설정을위한 추가 속성을 포함 할 수도 있습니다 .

우리의 경우 uat 프로필에 실험 채굴 자UI 카드 도 포함 되기를 원합니다 .

참고 : 2.4.0 이전의 Spring Boot 버전을 사용하는 경우 UAT 프로필 관련 문서에서 spring.profiles.include 속성을 사용하여 추가 프로필을 구성합니다. spring.profiles.active에 비해 전자는 추가 방식으로 프로파일을 포함 할 수 있습니다.

3.2. 사용자 지정 속성을 사용하는 기능 플래그

프로필은 작업을 완료하는 훌륭하고 간단한 방법입니다. 그러나 다른 목적으로 프로필이 필요할 수 있습니다. 또는 더 구조화 된 기능 플래그 인프라를 구축하고 싶을 수도 있습니다.

이러한 시나리오의 경우 사용자 지정 속성이 바람직한 옵션 일 수 있습니다.

@ConditionalOnProperty 및 네임 스페이스 를 활용하여 이전 예제를 다시 작성해 보겠습니다 .

@Configuration
public class CustomPropsMiningConfig {

    @Bean
    @ConditionalOnProperty(
      name = "features.miner.experimental", 
      matchIfMissing = true)
    public BitcoinMiner defaultMiner() {
        return new DefaultBitcoinMiner();
    }

    @Bean
    @ConditionalOnProperty(
      name = "features.miner.experimental")
    public BitcoinMiner experimentalMiner() {
        return new ExperimentalBitcoinMiner();
    }
}

이전 예제는 Spring Boot의 조건부 구성을 기반으로 빌드하고 속성이 true 또는 false로 설정되었는지 (또는 완전히 생략 되었는지)에 따라 하나 또는 다른 구성 요소를 구성합니다 .

결과는 3.1의 결과와 매우 유사하지만 이제 네임 스페이스가 있습니다. 네임 스페이스가 있으면 의미있는 YAML / 속성 파일을 만들 수 있습니다.

#[...] Some Spring config

features:
  miner:
    experimental: true
  ui:
    cards: true
    
#[...] Other feature flags

또한이 새로운 설정을 통해 기능 접두사를 사용할 수 있습니다 .이 경우 기능 접두사를 사용합니다 .

작은 세부 사항처럼 보일 수 있지만 애플리케이션이 성장하고 복잡성이 증가함에 따라이 간단한 반복은 기능 플래그를 제어하는 ​​데 도움이 될 것입니다.

이 접근 방식의 다른 이점에 대해 이야기 해 보겠습니다.

3.3. @ ConfigurationProperties 사용

접두사가 붙은 속성 집합을 얻는 즉시 @ConfigurationProperties장식 된 POJO를 만들어 코드에서 프로그래밍 방식 핸들을 얻을 수 있습니다.

진행중인 예를 따르십시오.

@Component
@ConfigurationProperties(prefix = "features")
public class ConfigProperties {

    private MinerProperties miner;
    private UIProperties ui;

    // standard getters and setters

    public static class MinerProperties {
        private boolean experimental;
        // standard getters and setters
    }

    public static class UIProperties {
        private boolean cards;
        // standard getters and setters
    }
}

기능 플래그의 상태를 일관된 단위에 배치함으로써 새로운 가능성을 열어 해당 정보를 UI와 같은 시스템의 다른 부분이나 다운 스트림 시스템에 쉽게 노출 할 수 있습니다.

3.4. 기능 구성 노출

비트 코인 채굴 시스템은 아직 완전히 준비되지 않은 UI 업그레이드를 받았습니다. 그래서 우리는 그것을 특징 짓기로 결정했습니다. React, Angular 또는 Vue를 사용하는 단일 페이지 앱이있을 수 있습니다.

기술에 관계없이 페이지를 적절하게 렌더링하려면 어떤 기능이 활성화되어 있는지 알아야합니다.

필요한 경우 UI가 백엔드를 쿼리 할 수 ​​있도록 구성을 제공하는 간단한 엔드 포인트를 만들어 보겠습니다.

@RestController
public class FeaturesConfigController {

    private ConfigProperties properties;

    // constructor

    @GetMapping("/feature-flags")
    public ConfigProperties getProperties() {
        return properties;
    }
}

커스텀 액추에이터 엔드 포인트 생성 과 같이이 정보를 제공하는 더 정교한 방법이있을 수 있습니다 . 그러나이 사용방법(예제)에서는 컨트롤러 엔드 포인트가 충분한 솔루션으로 느껴집니다.

3.5. 캠프 청결 유지

당연하게 들릴지 모르지만 일단 기능 플래그를 신중하게 구현 한 후에는 더 이상 필요하지 않게되면 제거하는 데 규칙을 유지하는 것도 똑같이 중요합니다.

첫 번째 사용 사례 (트렁크 기반 개발 및 중요하지 않은 기능)의 기능 플래그는 일반적으로 수명이 짧습니다 . , ConfigProperties, Java 구성 및 YAML 파일이 깨끗하고 최신 상태로 유지 되는지 확인해야합니다 .

4. 더 세분화 된 기능 플래그

때때로 우리는 더 복잡한 시나리오에 처해 있습니다. A / B 테스트 또는 카나리아 릴리스의 경우 이전 접근 방식으로는 충분하지 않습니다.

보다 세부적인 수준에서 기능 플래그를 얻으려면 솔루션을 만들어야 할 수 있습니다. 여기에는 기능별 정보를 포함하도록 사용자 엔터티를 사용자 지정하거나 웹 프레임 워크를 확장하는 작업이 포함될 수 있습니다.

기능 플래그로 사용자를 오염시키는 것은 모든 사람에게 매력적인 아이디어가 아닐 수 있지만 다른 솔루션이 있습니다.

대안 으로 Togglz와 같은 내장 도구를 활용할 수 있습니다 . 이 도구는 약간의 복잡성을 추가하지만 뛰어난 기본 솔루션을 제공하고 Spring Boot와의 최고 수준의 통합을 제공합니다 .

Togglz는 다양한 활성화 전략을 지원합니다 .

  1. 사용자 이름 : 특정 사용자와 관련된 플래그
  2. 점진적 롤아웃 : 사용자 기반의 백분율에 대해 활성화 된 플래그입니다. 예를 들어 기능의 동작을 확인하려는 경우 Canary 릴리스에 유용합니다.
  3. 출시 날짜 : 특정 날짜와 시간에 활성화되도록 플래그를 예약 할 수 있습니다. 이는 제품 출시, 조정 된 릴리스 또는 제안 및 할인에 유용 할 수 있습니다.
  4. 클라이언트 IP : 클라이언트 IP를 기반으로 플래그가 지정된 기능입니다. 고정 IP가있는 특정 고객에게 특정 구성을 적용 할 때 유용 할 수 있습니다.
  5. 서버 IP : 이 경우 서버의 IP를 사용하여 기능을 활성화할지 여부를 결정합니다. 이는 인스턴스에서 성능 영향을 평가하려는 경우와 같이 점진적 롤아웃과 약간 다른 접근 방식을 사용하는 카나리아 릴리스에도 유용 할 수 있습니다.
  6. ScriptEngine : 랜덤의 스크립트를 기반으로 기능 플래그를 활성화 할 수 있습니다 . 이것은 틀림없이 가장 유연한 옵션입니다.
  7. 시스템 속성 : 특정 시스템 속성을 설정하여 기능 플래그의 상태를 확인할 수 있습니다. 이것은 우리가 가장 간단한 접근 방식으로 달성 한 것과 매우 유사합니다.

5. 요약

이 기사에서 우리는 기능 플래그에 대해 이야기 할 기회가있었습니다. 또한 새로운 라이브러리를 추가하지 않고도 Spring이이 기능의 일부를 달성하는 데 어떻게 도움이되는지 논의했습니다.

이 패턴이 몇 가지 일반적인 사용 사례를 통해 우리를 어떻게 도울 수 있는지 정의하는 것으로 시작했습니다.

다음으로, Spring 및 Spring Boot 기본 도구를 사용하여 몇 가지 간단한 솔루션을 구축했습니다. 이를 통해 간단하면서도 강력한 기능 플래그 지정 구조를 생각해 냈습니다.

아래에서 몇 가지 대안을 비교했습니다. 더 간단하고 덜 유연한 솔루션에서 더 복잡하지만 더 복잡한 패턴으로 이동합니다.

마지막으로보다 강력한 솔루션을 구축하기위한 몇 가지 지침을 간략하게 제공했습니다. 이는 더 높은 수준의 세분성이 필요할 때 유용합니다.