トレタ開発者ブログ

飲食店向け予約/顧客台帳サービス「トレタ」、モバイルオーダー「トレタO/X」などを運営するトレタの開発メンバーによるブログです。

フロントエンドチームのリリースサイクルとブランチ運用

こんにちは、トレタ VPoEの北川です。

カジュアル面談などでよく聞かれる質問として「開発プロセスはアジャイルですか?」という質問とあわせて「リリースサイクルはどれくらいですか?」という質問を受けることがあります。

そこで今回は弊社のフロントエンドチームでのリリースサイクルとそれに対応するブランチ運用を例にして紹介しようと思います。

リリーストレインによる定期リリースサイクル

弊社のモバイルオーダー・トレタO/Xのオーダーアプリチームのリリースサイクルは週1回となっています。毎週水曜日の定期リリースという形でいわゆるリリーストレイン(ReleaseTrain)の手法となっています。

背景としては、リリース前に必ずQAによる動作確認・品質確認を行なっているという点があります。また、リリース前には利用店へのリリース内容の告知準備などもあります。そのため、開発してすぐにリリースではなくリリース日までに一定のリードタイムを設けています。関係する人が複数いるため、リリースの曜日が固定されているとでコミュニケーションは円滑になります。

ブランチ運用としては以下の図のようになります。

エンジニアは随時開発した機能はdevelopブランチへマージしていきます。毎週水曜にコードフリーズを行い、そこまでのdevelpブランチに入っている差分をpreviewブランチにマージします。previewブランチは主にQA作業を行うブランチです。ここでQAを行い問題がなければ次の水曜日にpreviewブランチをmainブランチへマージしてリリースします。

リリーストレインのデメリット

この運用におけるデメリットは、開発完了したものがリリースされるまでに1週間以上空くという点で、単純にデリバリーが遅くなります。そのため、機能追加や運用がある程度落ちついて開発が安定しているフェーズに向いています。

もう一つデメリットとしては緊急のバグ修正(Hotfix)が多いとブランチが煩雑になるという点です。リリースサイクルが短ければHotfixとせずに次のリリースタイミングに含めればよいものが、上記の周期では修正したものがリリースされるまでに最低でも1週間以上かかるため、mainブランチからHotfixブランチを切るケースが多くなってしまいます。

大規模な機能追加などを行なった後などに起こりがちで、その場合はリリースサイクルは保ちつつコードフリーズ期間を縮めるといった調整を行うことで対応しています。

トランクベースによる不定期サイクル

上記のオーダーアプリのブランチはいわゆるGitflowの手法ですが、同じトレタO/Xの開発チームの中でも管理画面アプリのチームはトランクベースでの開発プロセスをとっているのでそちらも紹介します。

トランクベースでのリリースプロセス

トランクベースの場合はエンジニアは常にmainブランチに対してマージしていきます。ただし上記の背景にもある通り、リリース前にQAを行うためmainブランチにマージされたタイミングではリリースは行われずにリリースタグを打った時点でリリースを行うようにしています。

弊社のフロントエンドのアプリケーションはVercelでホスティングをしているため、こちらもmainブランチでの自動デプロイはせずにPromoteを使ってデプロイを行っています。

QAを行う環境としてはstagingブランチを使い検証環境を用意しています。こちらはmainブランチにマージが行われたタイミングでstagingブランチにも自動で差分を取り込むようにしているため、常にmainとstagingのコードベースは同じ状態になっています。

リリースサイクルとしては不定期です。数日おきにリリースする時もあれば数週間空く場合もあり、その時の開発している機能の粒度に依存します。

トランクベース採用の背景

トランクベースにしている理由としては、オーダーアプリチームに比べてエンジニアが多かったため、featureブランチからdevelopブランチへマージする際にコンフリクトが多発していたことです。業務委託のエンジニアの出入りも多く運用ルールとして保つのも困難であったため、各自でfeatureブランチは作らずに常にmainブランチにマージし続けるという運用に切り替えました。

常にmainブランチに入れていくとリリースタイミングをずらしたい場合も発生するので、その際にはFeatureFlagを設けてリリースはするが機能は公開しない制御を行なっています。FeatureFlagの実装面についてはこちらの記事をご参照ください。

さいごに

今回2つのチームのリリースサイクルとブランチ運用を紹介しましたが、わりと流動的に変更しています。その時のプロダクトのフェーズやチームの体制に適した運用を常に模索して、少しずつ調整したり時にはガラッと変えたりしています。今回紹介したパターンが読者の参考になれば幸いです。

FeatureFlagの運用パターン -トレタのテックトーク

こんにちは、トレタ VPoEの北川です。 9月に入りましたが残暑が厳しすぎます…

テックトークとは

隔週に一回開催し、当番の発表者が最近の気になる技術情報であったり、業務する中での技術的な学びを社内に発信する場です。 全体30分の前半はLT(ライトニングトーク)、後半はその内容について参加者内で議論、という形式で行なっています。

今回のテックトーク

今回の発表は自分、北川の担当でした。

先日行なったエンジニアイベントでの質問の中にFeatureFlagをどう運用しているのか、という質問をいくつかいただいたので、今回の発表では弊社内でのFeatureFlagの使い方について発表しました。

FeatureFlagと一口にいってもその用途・使い方は様々なので、まずはそれらを整理しながら社内のいろいろなプロジェクト内での使われ方を分類して紹介しています。

FeatureFlagとは

まずFeatureFlag(フィーチャーフラグ)とは、特定の機能を動的にオン・オフするための仕組みです。アジャイル開発や継続的デリバリー(Continuous Delivery)のプラクティスとして、頻繁に機能をリリースしながらシステムの安定性を保つために、Facebook、Googleなどの企業で利用されてきた手法です。

FeatureFlagを使うユースケース

FeatureFlagを使う目的は様々です。いろいろなユースケース、目的を達成するための手段としてFeatureFlagが利用されます。一般的な利用目的を以下にまとめてみました。

  • 段階的リリース(Gradual Rollout) 新機能を一部のユーザーにのみ提供し、問題がないことを確認しながら徐々に全ユーザーに展開する。これにより、システムの安定性を保ちつつ、フィードバックを受けて調整することが可能です。

  • A/Bテスト 異なるバージョンの機能をユーザーごとに切り替えて提供し、どちらがより効果的かを比較するテストに利用できます。例えば、異なるUIデザインを一部のユーザーに試し、コンバージョン率を測定する場合などです。

  • カナリアリリース(Canary Release) 新機能をまず小規模なユーザーグループに提供し、そのパフォーマンスや安定性を観察して問題がないことを確認した後、全ユーザーにリリースする手法です。

  • リスク軽減 重要な機能を導入する際に、万が一不具合が発生した場合でも、即座にその機能を無効化できるようにして、システム全体に悪影響を与えるリスクを軽減します。

  • 特定のユーザー層への限定機能提供 プレミアムユーザーやベータテスターなど、特定のユーザー層だけに新しい機能を提供することができます。これにより、ユーザーに応じたカスタマイズされた体験を提供できます。

  • デプロイとリリースの分離 新機能のコードをあらかじめデプロイしておき、特定のタイミングで機能を有効化することで、デプロイとリリースを分離し、リリースのタイミングをより柔軟に管理することができます。

FeatureFlagの導入パターン

次に、特定の目的にFeatureFlagを使って解決しようとした際に、FeatureFlagの導入パターンも複数あります。こちらも一般的なパターンを以下にまとめてみました。

それぞれのパターンにはPros&Consがあり、どのパターンが適しているかは目的やサービスの規模、システムの非機能要件などによって変わってきます。

1. コード埋め込みパターン

概要

FeatureFlagのロジックをコード内に直接埋め込むパターンです。条件分岐を使用して、特定の機能を有効化または無効化します。

特徴

  • シンプルで導入が容易。
  • 開発者が直接コード内でフラグを制御できる。
  • 設定の変更にはコードの修正と再デプロイが必要。
  • 設定はコード内にあるため、外部依存がない。
  • 大規模なシステムではフラグが増えると管理が複雑になる。

ユースケース

  • 小規模なプロジェクトや、一度しか使用しない一時的なフラグ。

2. 環境変数パターン

概要

FeatureFlagの状態を環境変数として管理するパターンです。環境ごとに異なる値を設定でき、コードから環境変数を参照して機能を制御します。

特徴

  • デプロイ時に設定を変更可能。
  • 環境ごとに異なる設定を簡単に持てる(開発環境、本番環境など)。
  • 一時的なフラグなら良いが、長期間のフラグ管理には向いていない。

ユースケース

  • デプロイごとに簡単に設定を変更する必要がある場合。
  • 環境に応じて異なる設定を適用したい場合。

3. データベース連携パターン

概要

FeatureFlagの状態をデータベースに保存し、アプリケーションがその情報を参照してフラグを評価するパターンです。フラグの状態はデータベースから動的に取得されます。

特徴

  • フラグの状態を永続化できる。
  • フラグの状態変更が即座に反映され、アプリケーションの再デプロイが不要。
  • データベースに保存するため、設定変更の柔軟性が高い。
  • フラグの変更履歴や状態の追跡が可能。
  • 高度なフィーチャーフラグの管理が可能(例: ユーザーごとのカスタマイズ)。
  • データベースのパフォーマンスに依存するため、アクセス頻度が高い場合は最適化が必要。

ユースケース

  • ユーザーごとの個別設定や、複雑なフラグ管理が必要な大規模なアプリケーション。
  • フィーチャーフラグの状態や履歴を保持したい場合。

4. 分離パターン

概要

FeatureFlagを管理するコンポーネントを、アプリケーションコードとは別に管理するパターンです。設定ファイルや専用のコンフィグ管理システムを使ってフラグを管理します。

特徴

  • 設定ファイルを用いてフラグの状態を管理。
  • フラグはアプリケーションの外部に保存され、アプリケーションはその状態を参照して機能を制御。
  • コードベースから設定を切り離せるため、変更が柔軟。
  • 変更が即座に反映される。
  • 複数のアプリケーションやサービス間で統一したフラグ管理が可能。
  • 外部設定を管理するためのインフラが必要。
  • 複雑な設定管理が必要になることがある。

ユースケース

  • 大規模なシステムで、複数のアプリケーションやサービス間で統一的なFeatureFlag管理が必要な場合。
  • 設定変更を頻繁に行いたいが、アプリケーションの再デプロイを避けたい場合。

5. 外部サービスパターン

概要

FeatureFlag管理の外部サービス(LaunchDarkly、Flagsmith、Split.ioなど)を利用するパターンです。フラグの状態は外部サービス上で管理され、アプリケーションはAPIを通じてその状態を取得します。

特徴

  • 外部サービスがFeatureFlagの状態を一元管理。
  • 各種プラットフォームでフラグを統合管理可能。
  • フラグ管理に特化したツールを使用するため、スケーラビリティが高い。
  • リアルタイムでフラグの変更が反映され、ユーザーごとの柔軟な制御が可能。
  • 分析ツールやA/Bテスト機能が組み込まれていることが多い。
  • 外部サービスへの依存が生じ、サービス障害や遅延が発生するリスクがある。
  • コストがかかる(特に大規模なアプリケーションでは料金が高くなることがある)。

ユースケース

  • 大規模なマイクロサービスアーキテクチャや、複数のプラットフォームでFeatureFlagを統一的に管理する必要がある場合。
  • FeatureFlagの運用管理や分析を外部に委託したい場合

トレタでのFeatureFlagを使っている実例

さて、弊社でのFeatureFlagの導入事例についての紹介です。

上記でまとめたパターンごとに紹介していきます。

コード埋め込みパターンの例

{
  "USE_CALENDAR": true,
  "IS_FULLSCREEN": false,
}

弊社では設定画面のプロダクトにてコード埋め込みパターンでのFeatureFlag運用を行っています。 FeatureFlagを使う目的としては、クライアントアプリ向けのAPIとのその設定画面のリリースタイミングをずらすために利用しています。

新機能を出す際に、まずはAPIを先行してリリースし、利用するクライアントアプリ側が対応の後に設定画面をリリース、という流れとなります。 切り替えを行うのはデプロイを伴っても構わないため、一番簡易な手段としてコード埋め込みでFeatureFlagを扱っています。

環境変数パターンの例

export const isExtraColorPattern = (organizationId: OrganizationId): boolean => {
  const organizationIdsEnv = process.env.EXTRA_COLOR_PATTERN_ORGANIZATION_IDS;
  if (!organizationIdsEnv) {
    throw new ProcessEnvNotFoundError(500, "EXTRA_COLOR_PATTERN environment not set");
  }
  const organizationIds = organizationIdsEnv.split(",");
  return organizationIds.includes(organizationId);
};

上記のコードは、組織が特定のIDの場合にのみ特別なカラーパターンを利用できるようにするための判定式です。 利用可能な組織IDをEXTRA_COLOR_PATTERN_ORGANIZATION_IDS というkeyの環境変数に設定しています。 環境変数なので文字列しか設定できないため、カンマ区切りで配列を表現しています。

PoCであったり個社向けの対応に利用する用途なので、値の変更頻度は高くないため値の変更時にデプロイが必要になっても問題にはなりません。

データベース連携型の例

type Item {
  id: ID!
  name: Name!
  createdAt: Timestamp!
  updatedAt: Timestamp!
  ...
  metadata: KV  
}

データベースにFeatureFlagを設定する場合にはmetadata といったようなプロパティ名のKey-Value型のフィールドを用意して利用しています。 metadata のkeyの定義はDBスキーマ上は行っていないので必要応じてFeatureFlagのkeyと値を自由に追加・削除できます。

こちらは値の変更時にデプロイが不要なため、上記の環境変数パターンに比べて変更頻度が高い場合に利用しています

分離型の例

{
  "organiaztionIds": [
    "clilazd3oidfx0mm2akbmf1dj3",
    "cl3d3jpoklpx9jlkmlass31smpo"
 }

こちらは分離型として、静的ファイルに分離するという手法を取りました。

Githubで専用リポジトリを作り、/public にjsonファイルを配置しており、Vercelでプロジェクトを配信することで運用しています。 構成としてはあまり手間がかからないのと、Githubで管理されているため変更履歴が残るのとブランチを切り替えることで本番用と開発用で分けられるのが良いところです。

用途としては、リプレイスを行なったシステムに対しての移行をフラグ管理しています。 移行が終わっていない組織のIDをリストに入れておき、該当する組織は各アプリケーションではリプレイス前のシステムを利用します。 移行が済んだ組織はリストから外していき、リストが空になったらこの仕組みごと削除する、という流れになります。

複数のアプリケーションがその組織の移行状況を確認する必要があったため特定のアプリケーションではない場所で管理したかったのと、 最終的には不要になるため削除する時に後が残らず、また一覧性もあることが望ましかったため、この手法を取りました。

FeatureFlagを消すタイミング

FeatureFlagがそもそも永続化されるか一時的なものかは、パターンとあわせて利用するユースケースによります。 コード埋め込みパターンや環境変数パターンは比較的に短期利用で採用することが多いため、基本的には不要になった時点で削除を行います。

ただ、実際のところでゆうと消し忘れることは多いです。 フラグをオンにするタイミングで消すといいのですが、大体のケースはオンにして様子見てから消す、とするとそのまま放置されることが多いです。 この辺は運用ルールとして定めても守れらないと意味がないので、自動的に守られるような仕組みが必要ですが今のところそこまで至っていないのが現状です。

まとめ

長くなったので上記の内容のまとめです。 私見でのマトリクスを作ったので、FeatureFlagを使う際の判断の参考にぜひご活用ください。

  • FeatureFlagには、複数のユースケースやそれに適したアプローチがある。
  • どのアプローチでFeatureFlagを実装するかはユースケースに応じて、以下の観点で選択するとよい。
    • 外部依存度
      • レイテンシ
      • 障害点
    • 変更容易性
      • 変更にデプロイが必要でも問題ないか
    • 設定柔軟性
      • 環境にごとに切り替えたいか
      • 特定の店舗への設定か
    • 管理のしやすさ
      • 一覧性
      • 消しやすさ
コード埋め込み 環境変数型 データベース連携 分離 外部サービス
外部依存度 × ×
変更容易性 × ×
環境ごとの切り替え
設定柔軟性 ×
管理のしやすさ × ×
コスト ×

TORETA TECH UPDATE #1 イベント後記

こんにちは、トレタ VPoEの北川です。

先日、トレタ主催のエンジニアイベント「TORETA TECH UPDATE #1 -飲食を支えるフロントエンド」を開催しました。 ご参加いただいた皆様、大変ありがとうございました。 また、台風の影響によりオフラインの開催からオンラインの開催へ急遽切り替えさせていただき、参加予定だった方にはご迷惑をおかけして大変申し訳ございませんでした。

toreta.connpass.com

今回のイベントはトレタとしてコロナ禍以降にイベントを行う機会が減って、約5年振りのイベント開催でした。 自分としてもイベントを企画するのは今回が初めてだったので、今回のイベントを振り返りつつ、イベント開催をしてみようと考えている方向けに参考になりそうなことを書き記しておこうと思います。

集客の悩み

企画が動き始めたのは約3ヶ月前の6月頃で、経緯としてはこちらの記事で書いております。 当日までの準備で一番苦労した点は集客でした。

今回は採用につなげたいという目的もあったので、オフライン開催として開催の1ヶ月前にConnpassにイベント掲載をしました。 その日に登録いただいた参加者は5名程度。 イベント開催をよくやっている方からいただいたアドバイスとしては、参加者が集まるピークはイベント掲載時とまで言われていました。 弊社はまだまだ知名度も低いので集客力がないのは承知でしたが、正直これはまずい…ということで掲載内容を知り合いなどに見てもらい改善点を検討しました。

タイトルのキャッチーさ

今回のタイトルは「TORETA TECH UPDATE #1 - 飲食を支えるフロントエンド」ですが、たしかに指摘されてから見ると何のイベントかわからないのと興味も引きづらいです。 フロントエンドという部分で大まかなターゲットは分かりますが、どういうテーマかが見えてこません。 「飲食」という部分もエンジニアの興味を引くワードとしては厳しいです。 なのでこのタイトルではConnpassで見かけてくれた人をアトラクトすることはできず、実際に掲載日に応募いただいた方の経路はSNS経由でした。

改善点としては例えば、「Next.jsでのリアーキテクト」など、具体的な内容、技術要素、日頃抱えている課題に直結するなど、タイトルを見てわかるのが良いのかと痛感しました。 タイトルを途中から変えるのは憚られたので今回はそのままにしましたが、次回以降は改善しようと思います。

オフライン勉強会文化の移り変わり

これは20代の若い方からの意見としていただきましたが、オフラインのみしかない勉強会やイベントは人を誘ってでないと1人では行きづらい、とのことでした。

これについては自分の感覚と大きくギャップを感じましたが、コロナ禍以前を知らない人たちからするとオフラインでの勉強会は参加者目線ではハードルが高く、オフラインの場合でも同時にオンライン参加がないとハードルが高くて参加しづらいとのことでした。

弊社も勤務はフルリモートな環境なので、この為に外出するのは腰が重い、業務都合で時間が取れなそうならオンライン参加にしたい、という気持ちはたしかにわかります。 今回は思いがけず台風10号の影響でオンライン開催に途中で急遽切り替えましたが、おかげでオンライン参加でたくさん応募いただくことができ、最終的には35名の参加まで募ることができました。

当日の振り返り

当日は2名のトークと、その後にQ&Aという構成で行いました。

フロントエンドエンジニアの武市さんの登壇資料 speakerdeck.com

クレスウェア株式会社の奥野さんの登壇資料 speakerdeck.com

Q&AにはSli.doを利用したところ、登壇中に20件の質問をいただくことができQ&Aが非常に盛り上がりました。 いただいた質問をいくつかピックアップして紹介します。これらいただいた質問に関してはこのブログ内で順次回答していこうと思います。

  • AppRouter移行の作業にはどれくらいかかりましたか?
  • AppRouter移行後の効果はどれほどありましたか?
  • PagerRouter時代のコンポーネントとAppRouter移行後のRSCとが混在している状態での認知負荷などはありますか?
  • FeatureFlagの管理方法はどうしていますか?利用しなくなったら消しますか?
  • フロントエンドのテストはどの粒度でやていますか?ツールは何を使っていますか?
  • Next.jsのデプロイ先の構成やサーバーコストを知りたいです
  • リリースサイクルやQA体制はどうしていますか?

やはり実際にやってみてどうだったか、運用してみてどうだったか、といった事例の詳細に関心をいただけたかと思います。 ウチはこうやってるけどヨソではどうしてます?というのは私達もよく気になることなので、これからもウチではこうやってるよ!というのを今後も発信し続けていこうと思います。

次回の開催

今回のタイトルを「TORETA TECH UPDATE #1」としたので、「#2」も近々やりたいと考えています。テーマはまだ何も決まっていませんが、「フロントエンド x 〇〇」をテーマに何かできないか検討中です。いただいた質問やアンケート回答を見ていると「テスト」であったり「プロジェクト進行」みたいな部分をもっと知りたいという声をいただいたので検討させていただこうと思います。

ぜひ次回開催時の際にも沢山のご参加をお待ちしております。

© Toreta, Inc.

Powered by Hatena Blog