hacomono TECH BLOG

フィットネスクラブやスクールなどの顧客管理・予約・決済を行う、業界特化型SaaS「hacomono」を提供する会社のテックブログです!

hacomonoにおけるRelease Toggles 実践編

この記事は hacomono Advent Calendar 2024 3日目の記事です。

年の瀬も迫ってまいりましたアドベントカレンダー、読者の皆様におかれましてはいかがお過ごしでしょうか。
リーアキテクチャ&イネーブルメント部に所属しているさいもん(野崎)です。
年々、一年を短く感じるようになり、ついこの間年始だったのになと思うばかりであります。

現在は、既存コードの改善やリアーキテクチャタスクなどに取り組んでおり、テックブログにも以下のような記事を投稿しております。

また、年に1, 2回程度ですがイベントで発表する活動も行っています。


さて、本記事はhacomono Advent Calendar 2024 2日目の後編ということで、フィーチャーフラグ利用者目線での振り返りや今後の展開について私見を述べるものであります。
フィーチャーフラグは実際どのように活用されるのか、すでに使っているけど他事例も知りたいという方にご参考いただければ幸いです。

なお、本記事とあわせて、前編も参照いただけますと立体的に理解いただけるかと思います。

おさらい: hacomonoにおけるフィーチャーフラグ

前編でも書いてくださったとおりですが、hacomonoにおけるフィーチャーフラグはいわゆるRelease Togglesで、アプリケーション上では極めてシンプルなインターフェースで実装されています。
以下のようにしてフラグのON/OFFが切り替えられるようになっており、直感的で使いやすいものとなっています。

if FeatureFlag.on? 'use-feature-flag'
  # ONのときの動作
else
  # OFFのときの動作
end


活用例紹介: リファクタリングを安全にリリースする

筆者は「複雑だが事故を起こせないリファクタリング」のプロジェクトに取り組んでおりました。
リファクタリングの内容自体については、過去に公開しました別記事にて詳しく触れておりますのでそちらをご参考ください。
リアーキテクチャ&イネーブルメント部を立ち上げました/リファクタリング取り組み事例紹介

プロジェクトアウトラインとReleaseTogglesの活用

リファクタリングプロジェクトの概略を簡単に示します。
対象となるクラスは、もともと800行くらいあって1メソッド100行強、しかも改善しようにもテストコードもない状況でした。
また、共通クラスで、呼び出し元が10箇所以上あるので変更リスク・コストも極めて高かったです。
ですから、リファクタリングはもちろん、まず既存の挙動からユニットテストを書き起こし、テストコードを書きながら仕様を担保する、王道のリファクタリング作業を進めていきました。

リファクタリング前にユニットテストを書けるだけ書いたので、正直テストコードにもリファクタリング後の挙動が破壊されていないことには手応えはありました。しかし、新規クラスとして内部実装を書き換えていたので、他の呼び出し元と正しく協調できるか、全く安全かと言われると100%断言も難しかった。

したがって、リファクタリングのリリースに際しては先述のように、フィーチャーフラグをRelease Togglesとして利用し、呼び出し元を段階的に書き換える戦略で進めていきました。
呼び出し元クラスへのフィーチャーフラグ埋め込みは至って単純で、簡単な分岐を呼び出し先に追加したのみです。

class PurchaseController < ApplicationController
  def calculate
    if FeatureFlag.on? 'v2-service'
      # リファクタリング後のクラスを使う
      V2::CalculateService.call
    else
      # 環境を指定して旧版を維持
      CalculateService.call
    end
  end
end

※コード例はイメージです

ここまで来ると少しやりすぎな感も否めませんが… 同じようにして、テストコードに対してもフィーチャーフラグの分岐を入れ、旧版と新版で挙動に変化がないことも確認しました。

[true, false].each do |feature_flag|
  before do
    allow(FeatureFlag).to receive(:on?).with('v2-service').and_return feature_flag
  end
  describe '#call' do
    context 'なにか条件のとき' do
      # ... snip ...
    end
  end
end
やってみての所感

大きな課題感なく進められ、安全かつ効率的にリファクタリングを導入できたように思います。

良かった点は主に2つほどで、1つ目は、リファクタリング対象の事故リスクに見合ったリリース戦略であったこと。もう一つは、やりたいことに対して現在の単純な分岐実装が「呼び出し先クラスの分岐」というユースケースにフィットしていたことです。
Release Togglesとしてフィーチャーフラグを使う場合、製品にどう組み込むかによって利便性や課題感に幅が出てくるような感覚でした。

もっとうまくやれた点をもしあげるとすれば、さらにリリース速度を上げる意味で、フラグを使わずリリースしても良い判断も部分的にあったかもしれません。結果的に無事故で完遂できたので、この所感は結果から見た振り返りではあります。

未来にむけて

hacomonoでは、内部品質やリリースによるトラブルの削減に注力して施策に取り組んでいます。
フィーチャーフラグ、Release Toggles はリリースとデプロイを分離して管理するのに有用なツールですので、社内でも利用を推進しています。
多くのプロジェクトで使ってもらうにあたり、いくつか課題も感じられるため、アプローチに触れていきます。

フロントエンドにおけるフィーチャーフラグの実装

筆者が取り組んでいた事例では、バックエンドだけでフラグの分岐が完結するものでした。
しかし、他のプロジェクトでも積極的に活用するとなると、プロダクトのあらゆる(?)箇所にフィーチャーフラグを埋め込みたいはずです。
目下、フロントエンドでもフィーチャーフラグで分岐したり、バックエンドに追従して適時更新する管理機能の開発をしています。

フィーチャーフラグをアプリケーションで参照できるようになるまでの流れを簡単におさらいです。
hacomonoは、フロントエンドをNuxt、サーバサイドをRuby on Railsを使って書かれているウェブアプリケーションです。
フィーチャーフラグの名前、true/falseはデータベースに入っており、別のサービスからAPIを通じて更新されるようになっています。



フロントエンドでフィーチャーフラグを参照する際には、フラグが配信された日時を任意の処理を介して随時確認します。
配信日時をフロントエンドでも常に保持しながら、バックエンドのそれと定期的に突合することで、小さい誤差でフラグ情報に追従できるようにしています。




上記の管理機能はアプリ基盤として実装されており、製品開発においては、分岐にフォーカスして利用できます。

<script lang="ts">
export default defineComponent({
  created() {
    this.$featured('use-feature-flag') {
      // フィーチャーフラグ有効時の実装
    }
  }
})
</script>
<template>
  <p>
    Text
    <template v-if="$featured('use-feature-flag')">
      <!-- フィーチャーフラグ有効時の表示 -->
    </template>
  </p>
</template>


記事執筆時点では実利用しているプロジェクトはまだないのですが、今後積極的に活用いただき、改良・改善していきたいと思います。

フィーチャーフラグの管理ルール

hacomonoのフィーチャーフラグは、DBにあるフラグの実態をアプリケーションで参照する仕組みを取っています。
今までは利用シーンが限られていて単純な使われ方だけでしたが、複数のプロジェクトで使うとなるとフラグ同士の依存関係が生まれないか?は気になるところです。
例えば、次のようにクラスの依存関係に分岐が埋め込まれてしまうと、かえって管理コストが跳ね上がってしまいます。

class PurchaseController < ApplicationController
  def calculate
    if FeatureFlag.on? 'v2-service'
      V2::CalculateService.call
    else
      CalculateService.call
    end
  end
end
def CalculateService
  def call
    if FeatureFlag.on? 'use-new-feature'
      # 新機能の分岐
    else
      # 旧機能維持
    end
  end
end

メソッド内には分岐しない・呼び出し先を分岐する、などルール作りで担保できないかを現在模索しています。

その他、記事作成時点で具体的なアイデアはありませんが、今後フラグの配信のみならず参照や、利用箇所の可視化、アドホックにフラグをスイッチできるような管理機能が必要になるかもしれないと見立てています。

おわりに

本記事では、hacomonoにおけるフィーチャーフラグの活用および今後に向けたフロントエンドへの実装事例をご紹介しました。
前編でも触れられているように、hacomonoではフィーチャーフラグの実装をSaaSなどを使わず、シンプルな構成で実現しています。手動での配信、シンプルな分岐の実装であるがゆえの制約もなくはないですが、明示的で管理コストは低いとも感じます。

本記事が、フィーチャーフラグ・Release Togglesの導入や活用を検討している方のご参考になれば幸いです。


株式会社hacomonoでは一緒に働く仲間を募集しています。
エンジニア採用サイトや採用ウィッシュリストもぜひご覧ください!