この記事はエイチーム引越し侍/エイチームコネクトの社員による、Ateam Hikkoshi samurai Inc.× Ateam Connect Inc. Advent Calendar 2021一日目の記事です。
2021年も終わりが近づいて来ましたね〜!
初日は、エイチーム引越し侍でバックエンドを主に担当している新卒2年目・完全感覚programmerの@sho-hataが担当します!!
はじめに
「引越し侍 ネット見積もりサービス」
今までの引越し見積もりサービスは、複数の引越し業者と電話・メール・訪問対応の必要があったのですが、本サービスは引越し業者の比較・相談・申込をネットで完結できる業界初のサービスになっています。
β版のため、現在は関東エリア発着の引越しのみ対応ですが、今後機能・エリア拡充し2022年6月頃に正式版をリリース予定です。
本記事では、「引越し侍 ネット見積もりサービス(β版)」(以下、新規サービス)を作るにあたり、どういった技術・アーキテクチャを採用したのか、その概要と背景を共有します。
技術選定に関して
新サービスの技術選定では、以下のような状況・要望がありました。
- 🧑🏻💻「引越し見積もり」というドメインはビジネスフローがかなり複雑なため、できるだけシンプルかつスケールしやすい構成にする必要
- 🙋♂️サービス立ち上げ期のためできるだけ早く世に出したいというビジネス要件
このような背景のもと、具体的な技術選定の方針として以下の2つの基準で検討が進められました。
・開発にかかる工数を限りなく少なくする
・ビジネスロジックを分離してスケールしやすくする
ここからは、採用したアーキテクチャ・技術について述べていきます。
アーキテクチャの全体像
フロントエンドはWebになっており、Next.jsで動いています。認証/チャット機能はFirebaseが担っており、基本的なデータ取得はHasura Cloud(GraphQLサーバー)が担っています。ビジネスロジックが絡む処理は、Hasuraの後ろのGoで稼働するREST(ful)APIサーバーが担います。データベースはPostgreSQLです。
以下では、それぞれの技術の採用理由をまとめています。
サービスを支える技術
1.GraphQL
GraphQL APIを採用した理由は以下になります。
・フロントエンドのユースケースに合わせて、柔軟にデータを提供したい
・データ取得のパフォーマンスを良くしたい
既存サービスは長らくPHPで稼働するRESTful APIを用いていました。その歴史はとても古く、度重なる改修によって
・必要ないデータフェッチをしてしまっているAPI
・1つのページで4~5回APIを叩いている
などのパフォーマンス面で課題がありました。また、フロントエンドのユースケースが1つ増えるごとに専用のAPIを開発する必要があるなど、工数/設計面においても課題がありました。
このような反省から、よりフロントエンドから扱いやすいGraphQLを選択しています。採用実績がなかったため、最初の教育・学習コストは低くありませんでしたが、Fragment colocation
などの機能によりフロントエンドの設計の見通しが良くなるなど、開発者体験が大きく改善されました。
2.Hasura
GraphQLサーバーには、Hasuraを使用しています。フロントエンドからのリクエストを一手に引き受けており、いわゆる"BFF"(Backend For Frontend)的な使い方をしています。また、セルフホスティングではなくマネージドのHasura Cloud
を使用しています。
Go
のライブラリgql-gen
やAWSのAppSync
と比較し、以下の理由でHasuraを採用しました。
・工数ゼロで、CRUDリゾルバが作成できる
・認証周りの機能が組み込みで充実しており、Firebaseとの相性も良い
・ビジネスロジックを既存・外部のGraphQL・REST(ful)APIで拡張できる
Hasuraは、DB設計さえしてしまえば工数ゼロで基本的なリゾルバが作成できるため、かなり開発工数を短縮することができました。
ただ、裏を返せばロックインしている状態でもあります。また、幸いサービスの段階的にそれほどではありませんが、ビジネスロジックがサービスの成長に伴いどんどん増えていくことが予想されます。Remote Schema・Actionで拡張ができるのは強力ですが、設計方針を決めておかないと管理できずカオスになっていくため、方針を確定してしっかりと運用に乗せていかなければなりません。
ここではざっくりとまとめましたが、Hasuraを半年間使用してみてのメリット/デメリットについて、より踏み込んだ内容を以下の記事でまとめています。合わせて読んでいただけると幸いです。
3.Go
Hasuraではできないようなドメイン固有のビジネスロジック(ユーザーの入力情報から引越し業者を選択する・概算料金を算出するなど)はGoで書かれています。具体的な採用理由は以下になります。
・静的型付けによる型安全
・言語仕様がシンプル。学習コストが他の静的型付け言語より比較的低い
・後方互換性が保たれている(1.x系)
こちらのGoプロジェクトでは、Clean Architecture
に寄せた設計技法を採用しています。他の言語だと、モノリシックなデザインのフレームワーク・ライブラリが多いですが、Goのライブラリは言語仕様と同じく小さくシンプルなものが多いため、プログラムがフレームワークに依存しにくく非常に相性が良かったです。
また、強力な周辺ツール・ライブラリが揃っており、開発者体験向上の恩恵を受けています。
例えば、gomockを使用することで、インタフェース定義からモックを生成して手軽にテストができています。また、gotestsはコマンド一発でテストコードの雛形を自動生成してくれるので、開発者はテストケースを書くだけで良い状態にしてくれます。使用法もシンプルで扱いやすいため、大きく役立っています。
4.PostgreSQL
RDBには、PostgreSQLを採用しています。既存システムはほぼMySQLだったのでMySQLを検討していたのですが、プロジェクト発足時点ではHasuraがPostgreSQLしかサポートしていませんでした。今後Hasuraのバージョンアップにより全面的にMySQLがサポートされるため、そのときにメリット/デメリットを再吟味した上でMySQLへの移転を検討しています。
5.Firebase
新サービスでは引越しに必要な情報を入力した後、マイページにて引越し業者とのチャットでのやりとりや、引越し予約の確定が可能です。この認証の仕組みにはFirebase Authenticationを使用しています。
以下が、採用の理由になります。
・チャット機能でFirebase Cloud Firestoreを採用しているため、アクセス制御の連携が楽
・Firebase Authで認証・発行したJWT TokenをHasuraで使用できる
また、チャット機能はNoSQLを採用しており、Firebase Cloud Firestoreを使用しています。
その他開発を支える技術
以下では、直接サービスを構成しているわけではありませんが、開発者体験向上などを支えている技術を紹介します。
6.Renovate
新サービスでは、Renovateによってアプリケーションの依存パッケージ・DockerFileなどのアップデート作業を半自動化しています。
一週間に一度、GitlLab Cl/CD PipelineでスケジューリングされたRenovateが実行され、アップデートがあったライブラリ・Dockerイメージのマージリクエストが作成されます。レビュアーとしてランダムアサインされたメンバーは該当のリリースノート・自動テスト結果をチェックし、問題なければ手動でマージするという運用です。
Renovateの導入によって、人力の手動アップデートの面倒さから開放されるとともに、開発メンバーのアップデート内容への感度も、プロジェクト発足時と比較すると高くなるなどのメリットがありました。
よりポピュラーなDependabot
がありますが、GitLabへの導入の手軽さという点からRenovateを選択しています。
Go × GitLab CIによるGo Packagesの自動更新の詳細については下記にまとめています。
7.Husky, Commitlint
huskyを使用して、各Gitアクション(commit
・merge
)時にlinterやスクリプトを走らせています。
コミット時には、コミットメッセージがチームで決めたコミット規約に従っているかをチェックするCommitlintを走らせており、コミットメッセージのスタイルを合わせています。
また、プロジェクトの依存パッケージ(npm
・gomod
)・DockerイメージはRenovateによってどんどん半自動的にアップデートされていきます。そこで、リモートからpullした際にpackage.json
やDockerfile
に差分があった場合、yarn install
を実行するなどのスクリプトが走るような仕組みになっています。
8.カバレッジツール
カバレッジ算出・表示には、coberturaを採用しており、Go用のヘルパー https://github.com/boumenot/gocover-cobertura を使用しています。
算出されたテストカバレッジ情報をXMLファイルに出力し、GitlabのTest Coverage Visualization
機能を使用して、マージリクエスト(MR)の差分に表示しています。
MRの差分ビューでテストが通っていない部分が視覚的にすぐわかるため、コードレビュー時に非常に役に立っています。
まとめ
ここまで新サービスのバックエンド全体の技術スタックを紹介しました。
最初にも述べましたが、
・開発にかかる工数を限りなく少なくする
・ビジネスロジックを分離してスケールしやすくする
という思想・ビジネス要件の下、上記のような技術を選択しました。これらの技術の採用により、引越し侍の新サービス立ち上げを少エネルギーかつスピーディーに進めることができました。
ただ、現在のアーキテクチャ構成はベストではなく、課題がいくつもあります。一例を挙げると、マルチクラウド構成になっている(AWS、GCP)ため複数のクラウドベンダーの障害を気にしないといけません。
こういった課題については、2週間に1回ペースでこれからのアーキテクチャ構成について話し合う"Architecture talks"という取り組みを行い、試行錯誤しながら改善サイクルを回しています。
おわりに
ここまで読んでいただき、ありがとうございました!新サービスの立ち上げにおいて自分達が行なってきた技術選択の意思決定が、これから新規プロジェクトを立ち上げる方々にとって少しでも役に立てれば幸いです。
次回🤪✏️📖
Ateam Hikkoshi samurai Inc.× Ateam Connect Inc. Advent Calendar 2021初日の記事はいかがでしたでしょうか!?
明日は、同じチームのめちゃつよ先輩フロントエンドエンジニア、@anneauによる「新サービスを支えるフロントエンド」についての記事です!
本記事で説明したバックエンドと表裏一体の関係、フロントエンドはどうなっているのか。こちらもトレンドの開発スタイルを取り入れたりなど、多くの技術的なチャレンジをしているのでお楽しみに〜〜!!