結論
「アジリティ」「コスト最適化」「スモールな構成」「開発スピード」という観点でWebアプリケーションのアーキテクチャを考えてみました。
- ServerlessFrameworkを使い倒す
- フロントエンドはS3 hosting + CloudFrontで。SSRもLambda@Edgeでできます
- データベースはRDSは使わずにDynamoDBで
- APIは基本的にGraphQL。必要に応じてRESTも簡単に追加できるよ。
補足(2022/04/12)
最近個人開発しているこちらのWebサービスはこのアーキテクチャに沿って作られています。
このアーキテクチャでどんなものができるのよ、という視点で見ていただくと面白いかもしれません。
↓
背景 アーキテクチャに絶対の正解はない
アーキテクチャには絶対の正解はありません。
なぜなら、プロダクトやフェーズによって求められる要件が異なり、それに適したアーキテクチャを考える必要があるからです。
例えば、先日障害で証券取引が1日休場になった東証の高速取引システムは、安定性や信頼の要件に全振りをしていて、400台のサーバで負荷分散をしていたり業務系と運用系でネットワークを分けて障害の影響範囲を局所化するようなアーキテクチャになっています。
AWSやメルカリなどの成長企業では拡張性の要件が高く、イノベーションを起こし続けるために全体のアプリケーションに影響を与えずに新しいサービスを展開できるように、マイクロサービスアーキテクチャが採用されます。
では個人開発やスタートアップはどんな要件が重視されるか考えてみます。
こちらにスタートアップが失敗する理由のランキングが掲載されています。
スタートアップが失敗する理由ランキング
1位 市場ニーズがなかった
2位 資金の枯渇
3位 適切でないチーム構成
4位 競争力で負けた
5位 使いにくいプロダクト
これらはアーキテクチャで全て解決できる問題ではないですが、どんな要件が必要かが見えてきます。
1位 市場ニーズがなかった → 顧客の声に合わせて仕様を変化させていくアジリティ
2位 資金の枯渇 → コスト最適化
3位 適切でないチーム構成 → なるべく専門家を必要としないスモールな構成
4位 競争力で負けた → 開発スピードを高めて競合を抜き去る
5位 使いにくいプロダクト → 改善サイクルを高めるアジリティ
個人開発/スタートアップに必要な要件は**「アジリティ」「コスト最適化」「スモールな構成」「開発スピード」**ではないかという仮説が立ちます。
この観点で技術要素を検討してみました。
技術要素
背景にて、個人開発とスタートアップには**「アジリティ」「コスト最適化」「スモールな構成」「開発スピード」**が優れている技術要素を採用すべきだという検討を行いました。
この観点で私が優れていると思う技術要素を紹介していこうと思います。
構成は「フロントエンド」「データベース」「バックエンド(API)」の3段階で説明していきます。
フロントエンド
フロントエンドフレームワークの選定
フロントエンドフレームワークはReact,Vue,Angularの3大フレームがあります。
「開発スピード」「アジリティ」という観点で考えると、TypeScriptで型付けをすることが必須だと思います。入力補完の恩恵を受けつつ、どんなデータを受け渡せば良いかが一眼でわかることで開発効率をあげつつ、仕様変更でコードを変更した際のエラーチェックがコンパイル時にわかるためです。
そしてTypeScriptとの相性という観点ではReactが他の2つのフレームワークに比べて群を抜いているという印象で、フロントエンドフレームワークはReactを採用すべきだと思っています。
また、「開発速度」「スモールな構成」という観点で、私は素のReactを使うよりもNext.jsを使うことを推奨します。というのもNext.jsは、必要だが実装するのは面倒なことをNo Configで実現できるためです。具体的にいうとルーティングとSSR(SEO, SNSのOGPのため)です。
以上より、Next.js(TypeScript)をフロントエンドフレームワークとして推奨します。
フロントエンドのデプロイ先
Next.jsのデプロイ先として真っ先に頭に浮かぶのは、vercel, Netlify, Herokuなどがあります。
これらは非常に楽にデプロイができて、基本無料で使えるため選択肢に入ってきます。
しかし無料枠には必ず機能的な制限があるため、スケールすることを前提にするならばできればAWSで構築したいところです。
S3 hosting + CloudFrontであればAWS無料枠で使えますし、無料枠がなくなってもほぼ無料です(S3は0.025USD/GB, CloudFrontは0.114 USD/1GB)。
vercel等のサービスで有料アカウントになると固定費がかかってきますが、AWSのこの構成であればonDemandな課金になるので、「コスト最適」という点でS3hosting + CloudFrontを推奨します。
ちなみにvercelの無料枠もほぼ無制限みたいなものなので、極端なスケールを前提としないのであればvercelも全然ありです。
フロントエンドのデプロイ先としてEC2やECSなどのサーバを使うことは**「開発速度」「コスト最適化」という観点から論外**かなと思っています。
Next.jsのSSRはLambda@Edgeで行います。
この構成のデプロイはServerlessFrameworkを使うことで、No Configで簡単に行えます。
https://github.com/serverless-nextjs/serverless-next.js
データベース
RDS vs DynamoDB
結論から言うと問答無用でDynamoDBを選択することを推奨します。
正確にいうとDynamoDBでは表現しきれないデータ構造や複雑すぎるアクセスパターンの場合はRDSにせざるをえないのですが、初期のフェーズではDynamoDBで作って無理が出てきたらRDSとの併用を考えるという形が良いと思います。
「コストの最適化」という観点からいうと、Dynamoは従量課金ができるのに対してRDSはインスタンスの起動時間で課金されます。またRDS+LambdaはRDS Proxyの導入を行わないといけません。 Aurora Serverlessもありますが、こちらはコールドスタートが致命的です。
**「アジリティ」**という観点からいうと、DynamoはNoSQLなのでスキーマが固定されず仕様の変更に柔軟に対応できますが、RDBはテーブル間の依存関係があるためテーブルを捨てにくくマイグレーションやSQLの作り直しが発生します。
**「開発速度」**という観点では、Dynamoはデータベース機能の管理が不要であることとGraphQLと相性が良いことで開発効率をあげることができます。
DynamoDBの設計
DynamoDBを推奨しますが、RDBライクにDynamoDBを設計してしまうと確実に詰みます。DynamoDBはJoinができないため、Joinが必要のないようにテーブル設計をする必要があります。
RDBとNoSQLはテーブル設計のやり方が全く異なるので、ここに必ず最初学習コストをかけてください。
お勧めのリンクを貼っておきます。
サーバーレスアプリケーション向きのDB設計ベストプラクティス
Amazon DynamoDBのデータモデリング
DynamoDB に合わせた NoSQL 設計
バックエンド(API)
REST vs GraphQL
「アジリティ」「スモールな構成」「開発スピード」という観点でGraphQLを推奨します。
GraphQLは今まで持っていたバックエンドの責務をフロントエンドに移譲する側面があります。それによって、UIに変更が加えられるたびにAPI修正をする必要がなくなりアジリティが高まります。
またLambdaでREST APIを記述すると、エンドポイントの数だけLambdaを作ることになる(そうしない方法もあるが)が、GraphQLは単一エンドポイントなので「スモールな構成」を維持できます。
GraphQLはフロントエンドから利用する時に非常に扱いやすく、これは体感ですがRESTよりもフロントエンドの開発スピードは高くなっている気がします。
とはいえ、RESTの方が向いている処理もあります。例えばファイルアップロードなどはGraphQLでやろうとするとひと工夫が必要です。そういう場合はRESTのエンドポイントを併用することは全く問題ありません。API Gatewayを間におくことで同じドメインで対応が可能です。
デプロイについて
API Gateway + Lambda(GraphQL) + Lambda(REST) + DynamoDB の構成のデプロイはServerlessFrameworkを使えば簡単に可能です。
こちらに各言語のテンプレートが用意されているので探してデプロイまでやってみてください。その手軽さに驚くと思います。
ちなみに自分はこちらのテンプレートをカスタマイズして使いやすいようにしてから使っています。
認証認可について
認証認可はログイン機能などを実装する際はCognitoを活用します。開発スピードを意識すると自前実装しちゃった方が早い時もあったりしますが、セキュリティに関わるのでマネージドサービスを使った方がアンパイでしょう。
こちらもServerlessFrameworkで追加可能です。
最終形
以上をまとめると上の図のような構成になりました。
まとめ
「アジリティ」「コスト最適化」「スモールな構成」「開発スピード」という観点でWebアプリケーションのアーキテクチャを考えてみました。
- ServerlessFrameworkを使い倒す
- フロントエンドはS3 hosting + CloudFrontで。SSRもLambda@Edgeでできます
- データベースはRDSは使わずにDynamoDBで
- APIは基本的にGraphQL。必要に応じてRESTも簡単に追加できるよ。
がポイントだと思います。
個人開発/スタートアップに関わる方々の参考になればと思います。
もし興味がある人がいれば自分のテンプレートも公開しようかなと思います。
ありがとうございました。
追記 DynamoDBについて
DynamoDBをメインのDBにするところに非常に批判が殺到しているので少し追記します。
言いたいことは3つあります。
1、RDSのインスタンスコストは従量課金できないこと
全くアクセスがなくても月2000円~くらいかかってしまうのが惜しいところで、ほぼ無料で始められるサーバレスの1番のコストペインポイントだと思っています。個人開発だとここだけでDynamoを採用する大きな理由になると思います。事業としてやるならこれくらいのコストは誤差、というのは理解できます。
2、DynamoDBは思っている以上に表現力が豊か
「Dynamoは制約が多いから採用は慎重にすべき」は部分的に正しいと思います。ただ、DynamoDBの設計のプラクティスがあって、例えばAdjecent Patternを使えばMany to Manyの関係でも全く問題なくアクセスすることが可能です。検索条件が複雑でGSIを使い切るとか複合キーが複雑になるなど特殊な状況でない限りRDSを渇望するような事態にはならないと思っていて、十分にDynamoDBのポテンシャルを活かせていない可能性が高いと思っています。
3、DynamoDBは最初にサクサク開発したいから
記事に書いているようにDynamoDB採用の主な理由はアジリティ・開発速度・コストです。
プロダクトマーケットフィットしていないプロダクトは後の技術的負債を心配することよりも、小さく素早く失敗できるようにしておくことを重視すべきと思っています。
とは言ったもののRDBもいいよね
本心を言うとRDB+ORMで十分に開発速度とアジリティは出ると思っていて、インスタンスコストをケチりたかったと言うのが本心かもしれません。なのでDynamoの部分をRDS Proxy + RDSに置き換えるのは全く藪さかではありません
その他の意見について
「firebase, Netlify, Heroku, Amplifyでいいんじゃないか」説は、そうかもです。
ServerlessFrameworkとAWSを使うことのメリットは、「プロバイダ側の制約がない(無料枠だとコールドスタートがあるとか、アクセスレートがあるとかがない)」ことと「リソースに対して自由度が高い(CloudFormationで書けるので)ので発展性がある」というところかなと思います。