※ この記事はシラフで書いています。
前回が年末だったので少し早めですが、前回を書いた時はベロベロだったのとライブラリ/フレームワーク周りで面白い進展があったので書きます。
前提
以下の2つに分けて考えます。
公開用アプリ:初期費用を抑えたい & スケールしたい & 落としたくない & CI/CDもラクに設定したい → サーバーレスアーキテクチャ
自分・身内用アプリ:できれば無料で動かしたい & 落ちても手動で復旧すれば良い & CI/CDもラクに設定したい → 自宅サーバーKubernetes もしくは 格安PaaS(Koyebとか)
以下では自宅サーバーについてだけ書きますが、自宅サーバーでも格安PaaSでもCPU/メモリ/ネットワーク使用量を抑えることに気を配る必要がある点が共通しているのでそのまま格安PaaSに読み替えてもらって大丈夫だと思います
また、どちらにおいても以下を前提とします。
可能な限り静的型解析できる言語を採用
WebフロントエンドにはReact+TypeScriptを採用
ノーコード / ローコード系のツールは用いない
ビジネスロジック部分が増えると結局開発工数が逆転する場合が多いため
NoSQLは(リアルタイム通信等、特に向いている要件が無ければ)用いない
スキーマレスによる型バグが起こりやすい
特にRead時に複数回リクエストが必要な場合が多く、パフォーマンスが悪化しやすい
(公開用アプリの場合)スケール時に料金が高くなりやすい
「フルスタックフレームワーク」という言葉を「フロントエンド機能もバックエンド機能も含まれたフレームワーク」くらいの意味で用いる(ORM等で永続化周りの面倒を見なくてもフルスタックフレームワークと呼ぶ)
Appleを信じる者は救われるため、モバイルやデスクトップアプリは全てSwiftを書くものとして省略します
公開用アプリ
フレームワーク
前述の通り、サーバーレスアーキテクチャを採用します。現状安く運用できるサーバーレスなバックエンドは2種類あります。
VercelやCloudflare Pages(Workers)等のJavaScript系のプラットフォーム
AWS Lambda等のFaaS
他にもサーバーレスでコンテナを動かせるFargateやCloud Run、格安PaaS等がありますが、料金面で不利です。格安PaaSは無料枠が多いものが多いですが、スケールした時に急に料金が跳ね上がるものがほとんどなので、今のところは避けた方が良いと思います。
Lambdaは安いですが、LambdaでフルにWebアプリを作ろうと思うと可搬性の低い知識を要求されることになるため、あまりお勧めしません。
そんな訳で、VercelやCloudflare PagesでTypeScript製のアプリを動かすのが良いと思います。バックエンドをTypeScriptで書くなら、個人開発規模であれば、もはやフロントエンドとバックエンドを分ける理由はないため、Next.jsやRemix等をフルスタックフレームワークとして用いるのが効率的です。
その中でも僕はNext.jsを推します。後述しますが、サーバーレスで安くDBを運用しようと思うと、機能か速度のどちらかを妥協する必要が出てきます。React Server ComponentsやServer ActionsをサポートしているNext.jsを採用することで、DBの速度を落としてもUXを損なわないようなアプリが簡単に作れます。
Next.jsの場合、VercelでもCloudflare Pagesでもどっちでもある程度動きますが、next/imageが使えるVercelでやると画像周りが少しラクです。
データベース
僕はPostgreSQLが好きです。柔軟な日時型があり、JSONを高速に扱うことができ、幾何データや配列まで使え、さらには豊富な拡張機能があるためです。PostgreSQL互換で安いサーバーレスDBを動かそうと思うと、現状の選択肢はNeonのみとなります。Vercel Postgresもありますが、あれはNeonのラッパーなので気にしないでください。
さて、Neonは現状使えるリージョンが多くありません。最も近いものでもシンガポールです。だいたい100ms程度の遅延がDBアクセスの度に乗ります。
PostgreSQLを諦めてMySQL互換のサーバーレスDB(PlanetScaleとか)を使えば東京リージョンを選択することができますが、そうすると前述したPostgreSQLの柔軟性を見捨てることになり、その分アプリケーションコード側が複雑になってしまいます(この辺がしっくり来ない人は是非1度PostgreSQLの機能をフルに使って開発してみてください)。
その妥協策としてNext.jsのReact Server ComponentsやServer Actionsによる強力なキャッシュとOptimistic updatesを用いることで、ユーザーに遅延を感じさせないアプリが簡単に構築できます。
そんな訳で、僕は公開用アプリは基本的にフルスタックなNext.jsをVercelにデプロイして、DBにはNeonを用いる構成を取っています。
その他の部分
オブジェクトストレージ:大容量ならWasabi、小~中容量で高速が良ければR2
CSSライブラリ:Tailwind CSS
全部自分で書くとしんどいけど、Tailwind CSSで書かれたコンポーネント集がネット上に色々あるので、それを使うとカスタマイズも容易で快適
自分・身内用アプリ
公開用アプリと違ってCPU/メモリ/ネットワーク使用量を抑えることが要求されるため、フルスタックフレームワークではなくバックエンドとフロントエンドを分離する構成が良いと思います。
フロントエンドはSPAとして構築することで、例えばCloudflare Pagesでほぼ無制限かつ無料で動かすことができます。バックエンドのみを自宅サーバーに置くことでリソースの節約になります。
バックエンド
前述の通り、できる限りリソースを節約したいので、現実的な選択肢としてGoかRustを選択することになると思います。
Rustは関数型チックな文法のおかげで、慣れればGoよりもかなり効率的にビジネスロジック部分(自分用アプリの話なのでビジネスではないですが)を記述できます。
Goはライブラリが充実しているので、ライブラリで完結できる処理が多い場合には開発速度を出せます。
という訳でビジネスロジック部分が多ければRust、そうで無ければGoが良さそうです。
とはいえ経験則的にですが、好き勝手に作れる自分用アプリのほとんどは後からどんどん機能を追加していって、ビジネスロジックが肥大化しがちです。大抵の場合は最初からRustを選んでおいた方が後で後悔しないと思います。
ちなみにフロントエンドとバックエンドを型安全に繋げるためにOpenAPIやGraphQLを使った方が良いですが、RustとGoはどちらも問題なく対応しています。
フロントエンド
SPAをReact+TypeScriptで開発したいという要件があるので、選択肢としては以下があります。
Vite + 何らかのルーターライブラリ
esbuild等のバンドラ + 何らかのルーターライブラリ
Next.js の静的エクスポート
Remix SPAモード
タイムリーなことに、上2つは今日それに言及する記事が挙がっていたのでついでに紹介しておきます。
どちらもWouterという軽量版React Routerのようなルーターライブラリが使われていましたが、個人的にはfile-system based routingが好きなので、できれば使いたいです。例えばViteの場合にはgeneroutedというライブラリでfile-system based routingが使えるようになりますが、挙動に癖があり、Hot Reloadが効かない等の問題がしばし発生します。
他の選択肢も見ましょう。Next.jsの静的エクスポートは基本的にはお勧めしません。Next.js特有の機能はほとんどがサーバー上で動くことが前提のものなので、ただのfile-system based routing専用ライブラリとして動くことになってしまいます。そうすると、Viteと比べた時にビルドの遅さだけが残ってしまい、完全な下位互換になります。
Remix SPAモードはかなり注目しています。「ライブラリ/フレームワーク周りで面白い進展があった」と冒頭で書きましたが、これのことです。
RemixのSPAモードはRemixからサーバー前提の機能を削って、クライアント側で動く最低限の代替機能を容易しただけのものです。file-system based routingはそのまま搭載されており、しかもViteベースなのでNext.jsと違ってビルドは爆速です。
すなわち、RemixのSPAモードはfile-system based routingセットアップ済みのVite+Reactとして使うことができます。さらにRemixのサーバー前提じゃない機能(headタグ管理とか)が使える分、手動で設定するVite+Reactよりも機能的には上です。
という訳で自分・身内用アプリにはバックエンドRustとフロントエンドRemix SPAモードを使うのがベストアンサーです。
その他の部分
RustのWebフレームワーク:Axum
Actix-Webと思想は近いですが、Actix-Webのハンドラがマクロで隠蔽される一方、Axumのハンドラは単純なtokioベースの非同期関数なのでデバッグしやすいという特徴があります
CSSライブラリ:MUI もしくは Ant Design
公開用アプリは独自色を出さなければならないですが、個人用は見やすければ何でも良いので、ユーティリティファーストなライブラリよりも単純なコンポーネントセットを使った方が簡単な気がしています
DB:PostgreSQL
以上です。毎度のことですが、他の人のも読みたいのでこれを読んだ人は必ず書いてください。