1. 概要

この記事では、機能フラグを簡単に定義し、Spring Bootアプリケーションでそれらを実装するための意見があり実用的なアプローチを提案します。 次に、さまざまなSpring Boot機能を利用して、より洗練されたイテレーションを掘り下げます。

機能のフラグ付けが必要になる可能性のあるさまざまなシナリオについて説明し、考えられる解決策について説明します。 これは、ビットコインマイナーのサンプルアプリケーションを使用して行います。

2. 機能フラグ

機能フラグ(機能トグルと呼ばれることもあります)は、コードを変更したり、理想的にはアプリを再デプロイしたりすることなく、アプリケーションの特定の機能を有効または無効にできるメカニズムです。

特定の機能フラグに必要なダイナミクスに応じて、グローバルに、アプリインスタンスごとに、またはより細かく、おそらくユーザーまたはリクエストごとに構成する必要がある場合があります。

ソフトウェアエンジニアリングの多くの状況と同様に、不必要な複雑さを追加することなく、目前の問題に取り組む最も簡単なアプローチを使用することを試みることが重要です。

機能フラグは、賢明に使用すると、システムに信頼性と安定性をもたらすことができる強力なツールです。 ただし、誤用したり、メンテナンスが不十分だったりすると、すぐに複雑さと頭痛の種になる可能性があります。

機能フラグが役立つシナリオはたくさんあります。

トランクベースの開発と重要な機能

トランクベースの開発では、特に頻繁に統合を続けたい場合、特定の機能をリリースする準備ができていないことに気付く場合があります。 機能フラグは、変更が完了するまで変更を有効にせずにリリースを継続できるようにするために役立ちます。

環境固有の構成

E2Eテスト環境用にDBをリセットするには、特定の機能が必要になる場合があります。

または、非実稼働環境で実稼働環境で使用されているものとは異なるセキュリティ構成を使用する必要がある場合があります。

したがって、機能フラグを利用して、適切な環境で適切なセットアップを切り替えることができます。

A/Bテスト

同じ問題に対して複数のソリューションをリリースし、影響を測定することは、機能フラグを使用して実装できる説得力のある手法です。

カナリア解放

新しい機能を導入する場合、少数のユーザーグループから始めて、その動作の正確さを検証するにつれて採用を拡大することで、段階的に導入することを決定する場合があります。 機能フラグを使用すると、これを実現できます。

次のセクションでは、上記のシナリオに取り組むための実用的なアプローチを提供しようとします。

最も単純なシナリオから始めて、よりきめ細かくより複雑な設定に移行することから、機能のフラグ付けにさまざまな戦略を分解してみましょう。

3. アプリケーションレベルの機能フラグ

最初の2つのユースケースのいずれかに取り組む必要がある場合、アプリケーションレベルの機能フラグは物事を機能させるための簡単な方法です。

単純な機能フラグには、通常、プロパティと、そのプロパティの値に基づく構成が含まれます。

3.1. Springプロファイルを使用した機能フラグ

春には、プロファイルを利用できます。 便利なことに、プロファイルを使用すると、特定のBeanを選択的に構成できます。 それらの周りにいくつかの構造があれば、アプリケーションレベルの機能フラグのためのシンプルでエレガントなソリューションをすばやく作成できます。

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プロファイルにexperimental-minerおよびui-cardsも含める必要があります。

注: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に設定されている(または完全に省略されている)かどうかに応じて、1つのコンポーネントまたは別のコンポーネントを構成します。

結果は3.1の結果と非常に似ていますが、名前空間ができました。 名前空間があると、意味のあるYAML/プロパティファイルを作成できます。

#[...] Some Spring config

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

また、この新しい設定により、機能フラグにプレフィックスを付けることができます。この場合、featuresプレフィックスを使用します。

細かい部分のように見えるかもしれませんが、アプリケーションが大きくなり、複雑さが増すにつれて、この単純な反復により、機能フラグを制御できるようになります。

このアプローチの他の利点について話しましょう。

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テストまたはカナリアリリースの場合、以前のアプローチでは不十分です。

より詳細なレベルで機能フラグを取得するには、ソリューションを作成する必要がある場合があります。 これには、機能固有の情報を含めるようにユーザーエンティティをカスタマイズすることや、Webフレームワークを拡張することが含まれる場合があります。

機能フラグでユーザーを汚染することは、誰にとっても魅力的なアイデアではないかもしれませんが、他の解決策もあります。

別の方法として、Togglzなどのいくつかの組み込みツールを利用することもできます。 このツールは複雑さを増しますが、すぐに使える優れたソリューションを提供し、はSpringBootとのファーストクラスの統合を提供します。

Togglzは、さまざまなアクティベーション戦略をサポートしています。

  1. ユーザー名:特定のユーザーに関連付けられたフラグ
  2. 段階的なロールアウト:ユーザーベースのパーセンテージに対して有効になっているフラグ。 これは、Canaryのリリースで役立ちます。たとえば、機能の動作を検証する場合などです。
  3. リリース日:特定の日時にフラグを有効にするようにスケジュールできます。 これは、製品の発売、調整されたリリース、またはオファーと割引に役立つ場合があります
  4. クライアントIP:クライアントIPに基づいてフラグが立てられた機能。 これらは、静的IPを使用している場合、特定の構成を特定の顧客に適用するときに役立つ場合があります。
  5. サーバーIP:この場合、サーバーのIPは、機能を有効にするかどうかを決定するために使用されます。 これはカナリアのリリースにも役立つ可能性があります。段階的な展開とは少し異なるアプローチです。たとえば、インスタンスのパフォーマンスへの影響を評価する場合などです。
  6. ScriptEngine:任意のスクリプトに基づいて機能フラグを有効にできます。 これは間違いなく最も柔軟なオプションです
  7. システムプロパティ:特定のシステムプロパティを設定して、機能フラグの状態を判別できます。 これは、最も簡単なアプローチで達成したものと非常によく似ています。

5. 概要

この記事では、機能フラグについて話す機会がありました。 さらに、Springが、新しいライブラリを追加せずにこの機能の一部を実現するのにどのように役立つかについても説明しました。

このパターンがいくつかの一般的なユースケースでどのように役立つかを定義することから始めました。

次に、SpringおよびSpringBootのすぐに使用できるツールを使用していくつかの簡単なソリューションを構築しました。 それで、シンプルでありながら強力な機能フラグ付け構造を思いつきました。

以下では、いくつかの選択肢を比較しました。 より単純で柔軟性の低いソリューションから、より複雑ではあるがより洗練されたパターンへの移行。

最後に、より堅牢なソリューションを構築するためのガイドラインをいくつか簡単に説明しました。 これは、より高度な粒度が必要な場合に役立ちます。