システムアーキテクチャ 2023 年 6 月版

こんにちは、早いもので 2023 年ももうすぐ半分が終わろうとしています。

HQ 開発チームではリモート HQ の開発を積極的に進めており、アーキテクチャレベルでの変更が行われることも珍しくありません。 今回は 2023 年 6 月時点でのリモート HQ のシステムアーキテクチャの概観を紹介します1

2023 年 6 月時点システムアーキテクチャ

リモート HQ のシステムアーキテクチャ

リモート HQ は基本的に Google Cloud Platform(GCP)上に構築されており、主要なコンポーネントは Cloud Run で動いている core, api-gateway そして enduser の 3 つです。 また、 Retool や Contentful, Azure OpenAI Service など多くの外部サービスを利用しています。

core:コアドメインのためのモノリス

coreはリモート HQ のサーバーサイドの機能を提供するモノリシックなアプリケーションです。 core にはリモート HQ のコアドメインや大部分のビジネスロジックが Go 言語2で実装されています。

リモート HQ はそれなりに複雑なドメインを持つ福利厚生のためのプロダクトです。 ドメインが持つ本質的な複雑さに対処するため、境界づけられたコンテキストやより深い洞察へと向かうリファクタリングなどドメイン駆動設計のプラクティスを積極的に取り入れています。

core は GraphQL API を提供しており、一般のユーザーだけでなく社内向けの管理画面や Bubble などの外部サービスからも利用しています。(ちなみに HQ では社外の利用者のことをエンドユーザー、社内の利用者のことをスタッフと呼んで区別しています。)

core は多くの外部サービスと接続されており、例えばメール送信に SendGrid、決済に Stripe などを利用しています。

api-gateway:API ゲートウェイ

api-gatewayは GCP の外部向けに API ゲートウェイを提供するサービスです。 主な役割は外部からの GraphQL クエリを core の GraphQL API へ中継することですが、 core だけでなく外部サービスとの統合も行っています。

api-gateway では主要なツールとして graphql-tools の schema stitching を使っており、その結果 core と外部サービスの GraphQL API を統合した GraphQL API を提供しています。 これによりクライアントからは API がどこで実装されているかを意識することなく、 api-gateway に GraphQL クエリを投げるだけでサービスを横断してデータを相互に参照し合いながら取得できるようになっています。 例えば、リモート HQ では CMS として一部 Contentful を活用していて、 core で管理されている商品情報と、Contentful で管理されているおすすめ情報を組み合わせてトップページの商品一覧を構成しています。

また Azure OpenAI Service を使った機能が一部存在し、OpenAI は Go 言語の公式 SDK が無いので core ではなく Node.js で実装された api-gateway 上で GraphQL resolver として実装されています。

enduser:エンドユーザー向け Web UI

enduser は読んで字のごとくエンドユーザー向けのアプリケーションです。 TypeScript と Next.js で書かれており、リモート HQ は SEO が不要なサービスであり、 SSR を行う必要がないため、基本的にブラウザから api-gateway にアクセスする CSR で実装されています。

Retool:スタッフ向け管理画面

Retool はローコードで管理画面を構築できるサービスで、リモート HQ ではスタッフ向けの管理画面を作るために使っています。

ノーコードやローコードサービスを活用するとアプリケーションを素早く作れる反面、規律を持って開発を行わないとメンテナンスが困難になります。 HQ ではビジネスロジックは core に集約し、 Retool は GraphQL を呼び出すためのインターフェース以上の役割を極力持たせないようにした上で、 core の GraphQL 変更時に CI で自動的に Retool の GraphQL クエリが壊れないかスキーマレベルでの検査を行うなど、壊れにくくする工夫を色々と行っています。

しかし、一方でローコード・ノーコードの良さを活かすには、壊れても素早く直せばいいといったある程度の割り切りが必要だとも考えています。 当初、スタッフ向けの管理画面も enduser と同様に Next.js で実装していたのですが、堅牢ではあるものの開発工数がかかって実装に時間がかかるという課題意識から Retool への切り替えを始めました。 銀の弾丸は存在しない以上、アプリケーションに求められる特性に応じて柔軟に構成を変更し、適切にツールを活用することを心がけています。

Bubble:過去のシステムとの連携

今でこそリモート HQ の大部分が GCP 上で稼働していますが、移行する前は Bubble で実装されていて3、歴史的な経緯もあって現在も一部の機能が Bubble 常に残っています。

Bubble との連携についても極力 core に大事な部分は寄せて、 Bubble と core で役割が重複しないようにしています。ただ、これは移行中の一時的な措置であり、いずれは Bubble は完全に廃止する予定です。

今後の展望

今後数ヶ月から遅くとも年内のうちに以下のようにしたいと考えています:

enduser は Cloud Run から Vercel に移行する

歴史的な経緯で enduser は Cloud Run にデプロイされていますが、これを Vercel に変更したいと考えています。 餅は餅屋に任せた方が効率がいいし、現状の GitHub Actions でビルドして Cloud Run にデプロイするよりリリース速度そのものも早くなるためです。 また、これまでも Preview Deployments を目的に Vercel と契約をしており、本番環境のホスト機能分も料金を払っているにも関わらずそれを使わないのは純粋にお金がもったいないという現実的な問題もあります。

Contentful から self-hosted Strapi へ

Contentful は CMS というサービスの都合上コンテンツモデルの定義に応じて動的に GraphQL スキーマが変わってしまいます。

GraphQL schema stitching による外部 GrahpQL を統合した上で GraphQL クエリの検査を行っているのですが、検査の度に Contentful にアクセスしなければならなくなっています4。Strapi のセルフホストではモデルの定義や GraphQL スキーマを全てファイルとして書き出すことになるため、バージョン管理が容易になります。

CMS の機能を全て core に実装することなども検討しましたが、セルフホストする運用コストを踏まえても Strapi のセルフホストが最も理にかなっているのではないかと現時点では考えています。ただしこれはあくまでも現時点での計画に過ぎないため、 Contentful を使い続けることも含めて蓋を開けてみたら全く別のことをする可能性もゼロではありません。

おわりに

以上が、現時点でのリモート HQ のシステムアーキテクチャの概観です。 私たちは、最新の技術を駆使して、より良いサービスを提供するために日々開発を進めています。 そして、その開発の過程で得た知識や経験を共有し、技術者としての成長を促進することを大切にしています。

これからもリモート HQ のシステムアーキテクチャは進化し続けます。 新たな技術の採用、既存のシステムの改善、そしてそれらを通じて得られる新たな知見を、これからも発信していきたいと思います。

HQ 開発チームでは一緒に新たな挑戦をしてくれる仲間を常に募集しています。 真剣に技術に取り組む私たちと一緒に、新たな価値を創造していきませんか?

Footnotes

  1. 当初は 1 月ごろに同じテーマでブログを書こうとしていたのですが、瞬きをする間に半年が経ってしまいました。

  2. GCP 向けの SDK が充実している、コンパイルが高速な型付言語である、大きなユーザーコミュニティが存在する、GC があるためよりアプリケーションの実装に集中できる、などの理由で採用しました。

  3. Bubble を使っていた頃の話や移行時のあれこれは SaaS なのにほぼノーコードで 2 億円調達した話| Kotaro Harada | HQ「ノーコード」だけで 7 億円のシリーズ A までスピード調達、HQ に聞く | Coral Capital などで紹介されています。

  4. そのほかにも無料プランをはみ出した時の値段が高すぎるという経済的な問題も。