🧠

個人開発の技術が煮詰まってきた話

に公開

TypeScript中心の個人開発を始めて約1年半、独学でひたすらTwitterでエンジニアのツイートを眺めて色々な技術を学び、既存コードのリファクタリングを続けた結果、そこそこの落としどころを見つけた気がするので共有します。てか普通にみんなこれでやってると思う。僕が気付くのが遅いだけです。

アーキテクチャ

以下は僕が熱心に開発している大学軽音サークルの部員専用機能と公開ホームページを備えたポータルサイトashitabo.netのアーキテクチャです。

ashitabo.netのアーキテクチャ図

これはもう僕はNext.jsを採用する場合、総じてこのアーキテクチャにすると思います。

  • /apiとServer ActionがBFFとproxyの役割を担う部分
  • DBにCloudflare D1を使わずNeonを利用している部分

などは歴史的背景という名の技術負債で、変わる可能性が大いにありますが

  • Cloudflareの無料枠の寛大さ
  • Hono on Workersの開発体験の良さ
  • Next.js 16+Vercelのcacheの強力さ

などが相まって変える必要性が全くなさそうです。

技術選定

上記で少しライブラリ・フレームワークの話をしてしまいましたがashitabo.netでは

フロントエンド

  • Next.js 16
  • TypeScript
  • zod
  • React Hook Form
  • SWR
  • Tailwind CSS
  • daisyUI

バックエンド

  • Hono
  • zod
  • drizzle
  • hono/zod-openapi
  • auth.js(@auth/core)

あたりを使っています。

まずフロントエンドに関して、React Hook Formはかなり歴史的背景という名の技術負債になりそうですがNext.jsのあまりの遅さに耐え兼ねたらそろってTanStackに切り替えようと思っています。yupはとうの昔にzodに置き換わりました。
またデザインコンポーネントでは流行りのshadcn/uiの採用を見送って自作のUIコンポーネントを大量に作るという奇策に出ています。これも新規のプロダクトを作る場合はshadcn/uiとまではいかなくともHeadlessUIくらいは使うと思います。普通に便利だし

フロントエンドは思い切ってリポジトリを公開しています(GitHub - ashitabo_frontend)。 正直冗長だったり不整合があったり複数の問題を抱えていますが概ねよくできたプロダクトになっていると思います。

フロントエンドはディレクトリ構造が結構特殊で、関心事に対して完ぺきとは言わずとも、比較的アクセスしやすい構造になっていると思いたいです。

src/
├─ app/
│  ├─ **/page.tsx
│  └─ **/_components/    # ページ固有のクライアントコンポーネント
│     ├─ index.tsx       # ページ専用コンポーネント (page.tsx を薄く保持するためのもの)
│     └─ ...             # その他のページ専用コンポーネント
├─ domain/               # ドメイン単位のまとまり
│  └─ */ui/              # ドメイン固有の共通 UI コンポーネント
└─ shared/               
   ├─ ui/                # 共通 UI コンポーネント
   ├─ hooks/             # 共通カスタムフック
   ├─ lib/               # API ラッパー・フォント・R2 ストレージなどの基盤層
   ├─ types/             # アプリ共通の型定義
   └─ utils/             # 日付、キャッシュ制御、ロガー等のユーティリティ

まあ微妙かも、ドメイン単位で機能を考えるとドメイン内と単体ページとドメイン共通利用と...と複数のことを考える必要が出てきて正解が見当たりません。

次にバックエンドに関して、FE,BEどちらもTypeScriptなのにhono/rpcや型共有を行わずにhono/zod-openapiで攻めるというかなりハードボイルドな実装を行っていますがこれはいずれ直したい部分でもあり、すこし好きな部分でもあります(swaggerのOpenAPI楽しいから)。
またhonoでのバックエンド開発は体験をよくするために色々な工夫をしてみていて、 GitHub - hono-template にまとまっています。このテンプレートはディレクトリ構造の考え方にpackage by featureを採用していて、今考えると正直微妙なんですが、小規模なら関心事を全部ひとまとめにしてあるのも便利だと思います。

ただフロントエンドとは違って、正直バックエンドはWorkersを使う限りHono+drizzle+zodは手放さないと思います。開発体験が本当にいいし

キャッシュ戦略

このプロジェクトでは特に「絶対に無料構成にしたい」との思いが強く、かなりキャッシュに力を入れています。無料構成を実現させるうえで一番のボトルネックがDBです。
Neonの無料枠は

  • CPU: 100h/month
  • Storage: 0.5GB

とかなり小さく、このCPU計算時間の超過が多くみられました。
そのため出来るだけDBを叩かないよう、Next.jsの潤沢なcache, revalidateで対応しました。特にtagでの再検証を多く採用しています。そのためWorkers側ではあまりキャッシュの処理を用意しておらず、KV Storeとかを別で立てる必要がなくなっています。めっちゃ楽!

まあ今この記事を書いてて普通にD1に移行する気概が湧いてきたので無用の長物ではありますが、キャッシュ戦略は普通にとても大切なので今後も意識しておきたいです。

まとめ

こうまとめてみるとあまり煮詰まり感が出ないですが、「Netlifyを試す時期」や「RenderをDBaaSとして使う時期」、「Vercelにフルスタックすべて任せる時期」などを通して、この構成に落ち着きました。VercelやNext.jsがどうというよりかはCloudflareが最強すぎますね。

Discussion