DMM プラットフォーム事業本部フロントエンドグループのokpです。
この記事では DMM プラットフォーム事業本部におけるフロントエンドグループの発足背景や仕事内容について紹介します。
プラットトフォーム事業本部について
DMM プラットフォーム事業本部では以下の領域を扱っており、所属するエンジニア数だけでも100名を超える規模です。
- 認証認可
- 決済
- 不正対策
- 会員
- ポイント
- ポイントクラブ
- カスタマーサポート
ドメイン知識が要求される領域も多く組織規模も大きいため、バックエンドのシステムではマイクロサービスアーキテクチャを採用して開発をしています。詳細は Microservices Architect in DMM Platform を御覧ください。
プラットフォーム事業本部におけるフロントエンドの課題
プラットフォーム事業本部におけるフロントエンドの課題として、以下がありました。
- 変更容易性の低さ
- 開発効率の悪さ
- 拡張性の低さ
変更容易性の低さ
プラットフォームという性質上、バックエンドのシステムを「API」として提供することが多いですが、もちろんフロントエンドも様々な形で提供しています(ログイン、決済、ヘルプページなど)。多くは URL からアクセスできるいわゆる Web フロントエンドですが、UIを部分的に組み込むために、API や scripts として提供することもあります。DMM では従来よりマイクロサービスとして各チーム・アプリケーションが独立して開発しており、フロントエンドも同じように独立して開発されていました。
プラットフォーム事業本部では歴史的にPHPなどのMPAでフロントエンドをつくることが多く、 HTML / CSS のコーディングだけを別部署に依頼し、バックエンドのエンジニアが保守をするというのが主な体制となっていました。
一部のアプリケーションでは React や Vue を使い始めたりしていましたが、フロントエンド専業のエンジニアがなかなかおらず、技術選定やアーキテクチャなどをプラットフォーム事業本部の中だけで独自に実装されていたことが多いです。また、システムとしても歴史の長いものが多いため、簡単にはリファクタリングできないアプリケーションも少なくありませんでした。
そのような状況だったため、フロントエンドの保守性は悪く、かつ、既存のシステムに継ぎ足しで改修していくことが多く、抜本的な改善を行うことができていませんでした。
開発効率の悪さ
簡単にリファクタリングできず、部内でフロントエンドをリードできる人間が少ないような状況は、開発効率にも影響してきます。
例えば、PHPでつくられた典型的なMPAから、段階的にモダンなフロントエンドへ移行したくても、専任のエンジニアによる技術選定や責務の分解が必要だとわかるとどうにも腰が重くなってしまいます。エコシステムもありませんし、共通コンポーネントや、ロギング、認証のような仕組みをアプリケーションごとにイチからつくる必要があるためです。
このように、開発効率を向上するフロントエンドのエコシステムと、それをリードできるチームが不足していました。様々な事業を展開する DMM では、サービスごとに独自の思想でUIデザインを行うこと自体自然なことではあります。しかし、各チームが独自の思想で開発していった結果、最低限のエコシステムも存在せず、サイロ化が進み、開発効率が悪くなっていました。
拡張性の低さ
プラットフォーム事業本部では、様々なサービスから使われるフロントエンドを提供しており、サービスによって機能を拡張したいケースがあります。例えば、事業内容に合わせてログイン画面のカラーを変更したり、サービス固有の決済手段や入力項目を提供するなどです。
そのような独立したフロントエンドを、パラメータひとつでUIを変化させられるような設計や、適切な技術選定が必要とされていましたが、これまで説明したような背景から対応ができていませんでした。
プラットフォーム事業本部におけるフロントエンドグループとは?
フロントエンドグループは、前述のような課題を解決するために2021年7月に発足しました。
1年ほど経った2022年8月現在では、以下のようなサービスを提供しています。
- モノレポファーストなエコシステム
- デザインシステム Turtle
- 静的アセット配信基盤 Panda
- コードレビューによる技術水準の向上
モノレポファーストなエコシステム
フロントエンドグループのエコシステムは、モノレポによる開発を大前提としています。
これにより、コード共有の簡単さ、アトミックなバージョン管理、技術スタックの統一など、モノレポならではのエコシステムの提供しやすさ、高い保守性などを享受できます。
もちろんトレードオフとして、大規模なコードベースの管理やブランチ設計・責任範囲の明確化など、解決すべき課題も多いですが、モノレポでなければ今ほど多くのものを同じコストで提供できていたとは思えません。
なんらかのエコシステムをつくりたいだけなら、例えば npm によるパッケージや、GitHub Actions の共通化だけでも可能です。しかし、私たちの場合、フロントエンドグループを中心として開発を進めたいという背景があり、このようなスタイルを取っています。
ツールは Nx を使用しており、現状うまく運用できていると思っていますが、実現したいことによっては、他のツールを使うことも積極的に検討したいと考えています。
すぐにアプリケーション開発を開始
私たちのモノレポでは、新規のアプリケーションをすぐに開発し始められるような工夫をしています。
技術スタックの統一
ひとつは、技術スタックの統一です。例を挙げると以下のようなものです。
- TypeScript
- Next.js
- SWR & Recoil
- Emotion
技術スタックを統一することで、モノレポ内のパッケージの恩恵を受けやすくなったり、あるいは、既存のアプリケーションの実装をエコシステムに切り出しやすくなったりします。また、社内での知見共有もしやすくなり、コーディング規約なども統一しやすくなります。
もちろん各チームに技術選定の自由とオーナーシップがあることは重要ですが、私たちの場合は、フロントエンドグループを中心にして、少ないエンジニアで効率的に開発したいというミッションがありました。
また、技術スタックを統一することで、アプリケーションの雛形をコマンドひとつで用意できるというメリットがあります。例えば、Node.js のパッケージを新たに作成したいときは、以下のようなコマンドを叩くだけで雛形を作成できます(Nx の generator という機能を使用しています)。あとは実装をして main ブランチにマージするだけで、パッケージがモノレポ内で使用できるようになります。
yarn nx workspace-generator libNode パッケージ名
アプリケーションの方はまだ generator を用意していませんが、基本的にはクラウドインフラも含め既存のアプリケーションとほぼ同じ構成をとっているので、特に悩まず雛形を用意できます。fetcher やロギング、後述するコンポーネントライブラリなど、最低限の機能も予め用意されています。
現状では、SSR を行う Next.js のアプリケーションが多いですが、例えば、script tag 経由で読み込んで MPA(DMM はまだまだMPAのアプリケーションが多いです)に組み込む独立したフロントエンドアプリケーションのような構成もあります。このあたりは、現状ではフロントエンドグループが主体となり、アプリケーションによって適切な技術選定を行っていたりします。
なにもしなくても手に入る CI/CD
モノレポにのると、なにもしなくてもCI/CDの仕組みが手に入ります。
例えば、以下のようなものです。
@swc/jest
によるユニットテスト- PR ごとの Storybook 環境デプロイ
- ビジュアルリグレッションテスト
- 実際にデプロイする Docker イメージのビルドと起動
- Next.js アプリの ECS へのコンテナデプロイ
- Lint
- ビルド
- etc
CI / CD 自体は Nx が計算した影響のあるアプリケーションのみを並列で実行しています。本番やステージングのCDに関してだけは、該当のアプリケーションだけがデプロイされるようになっていて、チームの自律性が損なわれないようなデプロイ戦略をとっています(RC 環境は main ブランチで影響のあるものをどんどんデプロイしています)。詳細を知りたい方は下記を参考にしてください。
上記のスライドからの大きな変化でいうと、ビジュアルリグレッションテストがあります。例えば、私たちはデザインシステム(後述)としてコンポーネントやデザイントークンを提供していますが、その変更が実際にどうUIに影響を与えているのかを一目で把握できます。
下記は、カラーパレットの更新を行ったときの様子ですが、このような差分が、モノレポ内で影響のあるアプリケーションすべてで差分を検知できます。
これにより、破壊的変更が発生するようなケースでは該当のPRで修正を行うことにより、アトミックに更新を行うことができます。デザインシステムに限らず、モノレポのエコシステムに変更があった場合はモノレポのCIで必ず検知できるので、安心して共通基盤の変更を行うことができます。
また、多くのアプリケーションを一度にテストするため、マシンを分散して実行することや、キャッシュを利用して高速化することが欠かせません。現在は GitHub Actions の matrix を活用していたり、Nx でビルドやテストなどあらゆる script をキャッシュしています。こういった何もせずとも最適化の恩恵を受けられることもモノレポにのるメリットになっています。
例えば、直近では、ボトルネックになりやすい Node.js による docker build の高速化を行いました。だいたいのケースで、40分-1時間ほどかかってしまっていたビルド時間が、5-10分程度で済むようになっています(もとが悪かったというのもありますが...)。現状 GitHub-hosted runner を使用していますが、(主にコスト面で)Self-hosted runner への移行をする予定です。
デザインシステム Turtle
UIの一貫性を保つ施策として、デザインシステムの提供もしています(Turtle と呼んでいます)。
Turtle は大きくわけて「デザイン原則」「デザイントークン」「コンポーネントライブラリ」で構成されています。
現在は、これらをプラットフォーム事業本部のフロントエンドに順次適応している最中です。
「なぜデザインシステムをつくるのか?」については機会があればもう少し詳細に加筆したいのですが、私たちの場合のひとつの目的として、品質と効率の両輪を実現できるというところにあると考えています。
品質の高いUIをつくるには、専門的な知識と、細部にまで目を光らせる努力が必要です(「品質の高いUIとは」というところはこの記事では割愛させていただきます)。それらを複数のビジネスを複数のデバイスに対して複数のチームで行うとしたらどうでしょうか。
例えば、苦労して様々なベストプラクティスを取り入れて「決済のUI」を完成させたとして、同じように細かい改善が必要なUIはマイクロな視点で無数に存在します。すべての組み合わせで、毎回同じだけのコストをかけるのは現実的でありません。多くの場合は、リリースを優先させると思います。
デザインシステムを利用することで、品質の高いプロダクトを少ないコストで開発しやすくなります。一度作ったものはデザインシステムとして取り込めば、各チームで車輪の再発明を行うことはありません。また、複数のチームでUIデザインをする際に共通言語として機能します。
スケールする組織でデザインのベストプラクティスを常に提供するためには、デザインシステムのようにスケールする仕組みを設計、提供することが必要になってきます。さらに、DMM.com の性質として、「多くの事業があるがひとつのサービスのように振る舞う」という特徴もあり、全体として一貫性をもたせたいという狙いもありました。
Turtle ではそのようなことを意識して、初期段階からデザイントークンの設計などを行ってきました。これも機会があれば記事を書きたいと思っています。
静的アセット配信基盤 Panda
HTML/CSS/JS/画像などの静的アセットを配信するインフラ基盤を提供しています(Panda と呼んでいます)。
技術的には CloudFront と S3 でファイル配信するという、よくある構成にはなっているのですが、Panda を提供することで、キャッシュ設定などのベストプラクティスの強制、複数アプリケーションを横断しての改善などができます。
また、DMM では PHP などでつくられた MPA もまだまだ現役で、そういったアプリケーションでは、そもそも S3 のようなオブジェクトストレージを使わずサーバーから直接配信しているケースも珍しくありません。そのような文化では、S3を作ること自体面倒事になってしまっているため、なにも構築せずに使用できる Panda のような基盤があるとコスト面でも嬉しいです。
Panda を提供するにあたっていくつか工夫している点があります。
バケット設計
Panda では、ひとつの S3 バケット内にアプリケーションごとにパスを切ることで責務の分解点としていて、チーム外のパスに対する権限は付与していません。自分のチーム以外のパスには無知でいられることが、独立して開発・運用を可能にしています。
キャッシュ戦略
なるべくなにも考えずにキャッシュ設定がされるようにしています(デフォルトでは CDN に1年キャッシュする)。
インフラ自体は Terraform をつかって構築していますが、利用者は Terraform を意識することはありません。その代わり、Panda では、キャッシュ設定に用いられる特殊なパスをいくつか用意しています。例えば、オブジェクトを格納するパスに「/private」を含めると「Cache-Control: private, max-age=5分」が自動的に設定されます。
「事故が起こりやすい設計になっているのでは」というつっこみがあるかもしれませんが、私たちの場合、「自分で設定しないとキャッシュされない」よりは、「なにも考えなくてもいい感じのキャッシュ設定が使われる」ということを重視しました。デフォルトのキャッシュ設定は利用ガイドに強く明記してあり、各チームで考えてもらうような考え方にしています。
コードレビューによる技術水準の向上
フロントエンドグループでは、プラットフォーム事業本部内のフロントエンドのコードレビューも行っています。
以下を満たすものを優先してレビューしています。
- モノレポにのってから間もない(1-3ヶ月くらい)アプリケーション
- Help Wanted ラベルの付いた Pull Request
特に1に関しては、毎日30分ほどで同期的にレビューを行う時間をとっています。もちろんすべてのアプリケーションをずっとレビューし続けるわけではありませんが、この仕組み上、モノレポに乗るすべてのアプリケーションの概要をフロントエンドグループが把握している状態となります。
この同期的なレビューでは、以下のような目的で行っています。
- 議論してより良いものを作る
- レビュアーとレビュイーが直接会話できることで効率よくレビューする
- 他の人のレビューの仕方や観点を学ぶ
- プロダクトを保有するチームがチームの力で品質を担保できるようにする
特に「学習」という目的は大きく、フロントエンドチームは全てのプロダクトをレビューすることはできないため、別チームのプロダクトについてはそのチームで担保してもらうための場としても活用しています。レビューが不要になったら、GitHub の CODEOWNERS を整備し、各チーム内でレビューしてもらうような運用にしています。
まとめ
今回は、フロントエンドグループについて紹介させていただきました。
フロントエンドグループとしては、DMM プラットフォーム事業本部のフロントエンドを効率的に開発するためのエコシステムを提供していて、具体的には以下のようなことに取り組んでいます。
- モノレポファーストなエコシステム
- デザインシステム Turtle
- 静的アセット配信基盤 Panda
- コードレビューによる技術水準の向上
これらはまだ施策の一部であり、記事冒頭で上げたような課題をすべて解決するわけではありません。そのため、以下のような施策も今後のロードマップにのっています。
- デザインシステムの拡充、a11y 基準の向上
- モニタリング、Web パフォーマンスの可視化
- フロントエンドアプリケーションインフラの整備
- アプリケーションより小さい独立したUIを提供できる仕組み
- テクニカルスタンダードの整備による技術水準向上
- DMM 全社的なフロントエンドの改善