はじめに
ENECHANGE株式会社でSREを担当している杉田(@Mnbvc124)です。
本記事では、環境価値管理サービス「eValue Platform」のリアーキテクチャにおける設計判断についてお話しします。
要件が不確定な中で、どのようにアーキテクチャを決めたのか。
その意思決定プロセスを共有します。
eValue Platformとは
eValue Platformは、電力会社向けの環境価値管理サービスです。
再エネ需要の高まりを背景に、複雑化する環境価値業務を一元管理し、事業者様の再エネメニュー拡大を支援しています。
詳細は以下をご参照ください。
リアーキを決断した背景
運用の限界
これまでeValue Platformは、新規クライアントが増えるたびに以下の運用をしていました。
- ベースリポジトリから新規リポジトリを作成
- クライアント向けにカスタマイズ開発
- インフラも新規構築
この運用では、新規クライアントのたびにインフラ構築の工数が発生していたこと、また同じ修正を複数のリポジトリに適用する必要があり運用負荷が増大していたことから、スケールしにくい状況となっていました。
アプリ負債の蓄積
運用の限界に加え、アプリケーション側にも負債が蓄積していました。
- DB設計の問題 : 適切にリレーションが組まれておらずパフォーマンスが悪い、使われていないテーブルやカラムが散乱
- バリデーション不備 : 入力時点でバリデーションが整っておらず、後続処理でエラー多発
これらの課題から、一から再構築してスケール可能な設計に変更することになりました
ビジネス側からの要望
リアーキテクチャにあたり、ビジネス側から以下の要望がありました。
要望1: 柔軟な設計
「各社の要望に柔軟に応えられる設計にしてほしい」
eValue Platformは顧客ごとに要件が異なります。マルチテナントで一律の機能を提供するのは難しく、各社のカスタマイズ要件に対応する必要がありました。
一方で、運用の課題から1リポジトリで全顧客向けに開発し、運用負荷を下げるという方針になりました。
要望2: インフラ分離
「セキュリティの関係上、インフラを各社ごとに用意する」
セキュリティ要件として、インフラは顧客ごとに分離することが必須でした。
悩んだポイント
最大の悩みは、どのような設計が適切なのか、その正解が見えないことでした。
具体的な要件が定まっていない上に、将来どのようなカスタマイズ要望が生まれるかも予測できません。また、「柔軟に対応してほしい」という要望はあるものの、どこまでを共通化し、どこからを個別最適とするべきかの判断も難しい状況でした。
不確実性が高い中でアーキテクチャを決める必要がある点が今回のリアーキテクチャの難しさでした。
これらの悩みに対し、以下の方針を取りました。
どう意思決定したか
不確実性が高い状況において、共通化と個別最適の境界を初期段階で固定することは適切ではないと判断しました。
そこで、まずは機能差異を制御可能な状態を作ることを優先しました。
その上で、実際の要望や運用状況を観測しながら、段階的に調整していく方針としました。
全体の方針
- アプリ: 1リポジトリで開発し、機能差異を制御可能な設計とする
- インフラ: セキュリティ要件により分離を前提としつつ、構築効率を最大化する
アプリ:Feature Flagを採用
機能差異を実行時に制御する仕組みとして、Feature Flag を採用しました。
Feature Flag を利用することで、クライアント単位で機能の有効/無効を切り替えることができます。
これにより、単一のコードベースを維持しながら複数クライアントの機能差異を吸収できます。
利用ライブラリは Flipper を採用することにしました。 https://github.com/flippercloud/flipper
1リポジトリで複数クライアントの開発を並行して行う場合、コード競合や影響範囲の管理が課題となります。
その対策としてモジュラモノリスの採用も検討しましたが、以下の理由により現時点では導入を見送る判断としました。
- 明確なモジュール境界の設計が前提となる
- 境界設計の誤りが将来的な再設計コスト増大につながる
- 現時点では要件変動が大きく、境界を固定するタイミングとして適切ではない
インフラ:Terraform Modulesで効率化
インフラはセキュリティ要件でクライアントごとに分離が必須なので、Terraform Modulesを使い、AWSリソースの構築を標準化・効率化する方針としました。
モジュールはAWSサービス単位で以下のように分割する方針にしました。
- vpc-baseモジュール: ネットワーク基盤(サブネット、セキュリティグループ等)
- commonモジュール: ECRコンテナイメージのレジストリ管理等
- ecs-serviceモジュール: コンテナ実行環境(タスク定義、サービス設定等)
- cloudfront-s3モジュール : CloudFront、S3等の静的配信基盤
- codepipeline-ecsモジュール: CI/CDパイプライン
ディレクトリ構成は以下のとおりです。
networkディレクトリでvpc-baseモジュールを呼び出し、serviceディレクトリでecs-service等のモジュールを呼び出す構成にしています。
├── evalue-platform │ ├── 事業者A │ │ ├── network │ │ └── service │ │ ├── common │ │ └── production │ │ ├── backend │ │ └── frontend │ ├── modules │ │ ├── codepipeline-ecs │ │ ├── ecs-service │ │ ├── cloudfront-s3 │ │ ├── common │ │ └── vpc-base
今後について
Feature Flagによるアプローチは、今回の要件には適切な選択だと考えています。
一方で、Feature Flagの運用には以下のようなリスクも存在します。
- フラグの肥大化: クライアントが増えるにつれてフラグが増加し、コードの見通しが悪くなる可能性
- テストの複雑化: フラグの組み合わせが増えると、テストケースが増大する
- 不要フラグの残存: 役目を終えたフラグが削除されず、技術的負債となる可能性
これらのリスクも踏まえ、各事業者の要望や運用実態を観測しながら、必要に応じてモジュラモノリス等の他のアプローチへの移行も検討していく予定です。