この記事は Goodpatch Advent Calendar の13日目の記事です✨
本日の担当、やっはー は主にSaaSサービスでバックエンド寄りの開発をしてきました。
これは、2019年の年初くらいの話、Goodpatchが提供しているビジュアルコラボレーションツール『Strap』において、どのようにバックエンドの技術選定を行っていったのか、当時を思い出しながら少しだけ紹介していきたいと思います 🤗
- Strapのプロトタイプ、そのバックエンド
- 「ビジュアルコラボレーションツール」に求められるバックエンドの役割とは何か
- 要件はわかった。では早く決めてしまえばいいのだよ 👻
- さぁ選定してみよう 🏃♂️
- 挙げられたデータベースの候補から組み合わせる 🎛
- 幸いにして巡り会えたCloud Firestore 🤣
- 技術選定の後、2年間運用してみての雑感 😎
- 3行でまとめると 🍡
- おわりに 🤡
Strapのプロトタイプ、そのバックエンド
Strap開発の経緯については代表の土屋の note や、以下の記事に詳細が書かれています。
進め方としては、まず、フロントエンドを中心にプロトタイプを作成して価値検証を行っていました。
当時のプロトタイプはバックエンドについてもほとんど出来上がっており、見た目上は適切に動作していましたが、B2B SaaSのバックエンドとして考えると、セキュリティ面などの点で不足している部分があり、再設計する必要がありました🤔
よって、まずは求められるバックエンドを整理することから始めました💪
「ビジュアルコラボレーションツール」に求められるバックエンドの役割とは何か
まず、プロダクトが目指す世界を指標にして、機能要件、非機能要件、組織における要件(制約)をまとめていきました。
Strapが目指す世界 👀
Strapは全てのチームのためのプロダクトです。
誰もが簡単に思考を図表化して、チームに共有し同じモノを見ながらコラボレーションすることでどのような流れでプロジェクトが推進されていったのかがチーム内で残り続けます。
(Strap - Strapができるまでのストーリー より)
Strapチームでは、ここにも記載のあるような、「なぜStrapが必要なのか」というプロダクトのアイデンティティとも言える世界観の部分を、言語化していました。
そこには以下のようなキーワードがありました。
- 図表化できる
- チームのためのプロダクト
- 同時に同じものを見る
プロトタイプでも実現していたこれらをユースケースとして改めて考え、要件を洗い出していきました。
機能要件として
最低限必要なバックエンドの機能として、以下をあげました。
- 作成した図表データやアップロードした画像を、再読み込みなしで同期できる
- 複数のユーザーが同時にデータの更新を行える
- 他のユーザーのアクセス状況を、リアルタイムに表示できる
非機能要件として
やれることは限りなくありますが、いきなり爆発的にトラフィックが増えるようなサービスではないのて、まずは以下の点をどこまで満たせるのかを検討しました。
- ISO27001/ISO27017に準拠した体制を将来的に構築できるか
- Enterprise Ready の項目をどこまで満たせるか
- データの保存場所を設定できるか
- データ同期のリードタイムをどのくらい短くできるか
プロトタイプで不足していたのは主にこの非機能要件辺りでした 🤗
組織における要件(制約)として
前述の記事に記載のある通り、チームの人数がおよそ半減していた状況だったので、限られたリソースで物事を進めていく必要がありました。
よって、重視したのは開発を止めないスピード感、人的コストでした。
- バックエンドエンジニア以外の、他の職能を得意とするメンバーだけでも、データの属性追加や開発環境の構築ができるように
- 障害発生時の対応やインフラのメンテナンス対応を最小のメンバーでもできるように
要件はわかった。では早く決めてしまえばいいのだよ 👻
まずは、ざっくり以下の方針を決めました。
インフラ面
インフラは特に他のメンバーが触りにくいので、できる限りマネージドサービスを利用するようにします。
- EC2などsshでログインできるような仮想サーバーはできる限り作成しない
- オートスケーリングする従量課金で稼働時間課金ではないもの
- できれば自分たちが管理するようなコンテナもなくしたい 🙏
アプリケーション面
前述の記事もあったPrott2では、設計を行なった非常に優秀なエンジニアが立ててくれた以下のようなバックエンドの基本思想がありました。
Backendでしなくていいこと(Frontendでできること)はしない
これには責務の分離として非常に説得力があったので、強く意識するようにしました。
- バックエンドアプリケーションの役割を最小限にし、 原則的に、認証・認可・バリデーションのみを行う
- 別の役割が必要な場合はできる限りサービスを分ける
さぁ選定してみよう 🏃♂️
政府も提唱しているクラウド・バイ・デフォルト原則でも書かれている通り、AWS/GCP/Azure などのIaaS/PaaSで構築する前提で考えました。
まずはユースケースを考慮した上で、データベースから考えました。
想定されるメインのデータ型
ビジュアルコラボレーションツールなので、メインのデータは何と言っても図表データになります。
その場合の最小単位を Element
と名付けて型と想定していきます。
- 座標を持つ(x, y)
- 大きさを持つ(width, height)
- 表示に関わる属性を持つ(color, shape, etc…)
- テキスト情報を持つ(text, align, etc...)
このうち、表示に関わる属性は増えていきそうなので、拡張が容易な構成にしたい。 そうなるとfrontendで扱う最低限のデータ型は、TypeScriptで言えばこのようになりそうです。
type Element = { x: number; y: number; width: number; height: number; text: string; properties: { color: string; shape: string; }; };
RDB型かNoSQL型か
MongoDBの経験があったので、NoSQL型に対して便利さしか感じていませんでしたし、RDBでいくならJSON型を許容してくれるようなDBでないと厳しそうです。
また、Relationalでクエリを投げるようなユースケースは、検索以外では現時点ではなさそうなのと、RDBMSで複数名で更新した場合の制御が複雑になりそうな懸念がありました。
となると、拡張性重視でNoSQL型で保存を行い、検索は別のサービスを構築するなどで対応できそうです。
データの削除を迅速に行えるか
データの完全削除は意外と見落とされがちですが、重要なファクターの1つです。
削除をワンクエリ実行できるくらいの簡便さにしたいと考えました。
(もちろん適切な手順を踏んだ上で😉)
挙げられたデータベースの候補から組み合わせる 🎛
その時点で以下の4つをあげました。
- AWS DynamoDB
- Azure CosmosDB
- Cloud Firestore
- MongoDB(自分たちでIaaS上で運用するとしたら)
これらの候補に対して、それぞれの機能を組み合わせた、以下のような表を作成して評価していきました。
(この時点でAzureはAWSと大きく変わらなそうなので、自分たちが慣れているという点でもAzureを外しました)
また、その評価項目はこんな感じでした。
- フロントエンド 開発スピード
- フロントエンド 拡張自由度
- バックエンド 開発工数少なさ
- バックエンド 運用工数少なさ
- バックエンド 拡張自由度
- 価格
- 認証・認可 設計自由度
- Blob制御
- ロギング
- バックアップ / リストア
- データの管理画面
- 全文検索
この表を作って、特に収穫だったのは自分が思っていたよりも今ならマネージドサービスでほとんどいけるという点でした。
というのも、特に認可周りやロギングにおいて、マネージドサービスだけではB2B SaaSのセキュリティ要件に満たない部分があるのではと考えていました。
しかしながら、実際に設計・検証してみると、組み合わせやデータ構成の工夫次第で突破できるところも多かったです。
(もちろん、より厳しいセキュリティ要件が求められるサービスでは採用できない場合もあると思います。)
詳細な技術検証 ✅
最終候補に残った
- Firebaseを中心にした構成
- AppSyncを中心にした構成
で、より詳細に技術検証を行いました。 当時のIssueでは以下の感じに記載してました (他にもやったことはありましたが今回は割愛します😌)
幸いにして巡り会えたCloud Firestore 🤣
最終的にFirebaseを中心にした構成としましたが、決め手となったのは以下の2点です。
- Cloud Firestoreが認可・バリデーション+リアルタイム同期を行える
- (認証はFirebase Auth)
- Cloud Firestoreのスピード、将来性
要するにCloud FirestoreがあったからFirebaseにしたと言っても過言ではないです。
そのくらいCloud FirestoreはStrapの要求事項に合致したなと思いました 🙌
技術選定の後、2年間運用してみての雑感 😎
プロダクトとして
- 当初予定していた部分は着実にクリアできている
- この2年間、障害らしい障害はほぼなし
- レスポンススピードも一度に取得するデータ量が多すぎなければ問題ない
- 取得するデータ量が多い場合の対策を別途検討中 🧐
チームとして
- 人的コストも金銭的コストも格段に安い
- 想定通り、職能を超えても問題なく拡張している
- 開発者自身がマニュアルを見ながら本番と同等の環境が構築できている
要は、この2年間においては完全勝利とも言えるに良い選択ができたと思っています 🎉 🥳 🎉
この先はプロダクトのスケールに合わせて、各マネージドサービスの利用制限に達する前に、それぞれ移行や対策を考えていく必要があります。
ただ、それらもある程度は目処が立っているため、プロダクトの機能開発と並行しながら、適切なタイミングで対応していきたいと思います😋
3行でまとめると 🍡
- バックエンドの選定前にWhyを軸に洗い出したユースケースから、機能要件・非機能要件・組織の上での要件(制約)を改めて抽出しました
- データベースから選定を初めて、周辺の機能を選択していき、 結果、StrapにはCloud Firestoreがとても相性が良かったです
- B2Bで厳しいセキュリティ要件があったとしても、ケースによってはマネージドサービスだけでも運用できる
おわりに 🤡
Strapを開発/運用するGoodpatchのStrapチームでは世界を前進させるプロダクトを一緒に創っていける仲間を募集しています!
オラと握手(リモートでも)しようぜ 🙌
また、Goodpatchとしてもデザイン好きなエンジニアの仲間を募集しています 🤗
- 新卒採用エンジニア 23卒
- 中途採用フロントエンドエンジニア
- 中途採用Androidデベロッパー
- 中途採用iOSデベロッパー
少しでもご興味を持たれた方は、ぜひ一度カジュアルにお話ししましょう!💪💪💪💪💪