🧩

関数型ドメインモデリング TypeScript 実装スタックまとめ

に公開

こんにちは!わたなべです!

最近、同僚から「関数型プログラミング」と「ドメイン駆動開発」を組み合わせると素敵なアプリケーションを作れると聞きました。ぜひ自分でも試してみたいと思ったのですが、どんな実装スタックを選べばよいのかわからず、ChatGPT o3 さんに相談してみました。

当初は得意な C# でやりたかったのですが、C# では関数型プログラミングを用いたドメインモデリングが難しそうだったため、今回は TypeScript を使った方法を調べてみることにしました。

はじめに

フロントエンドを含む JavaScript エコシステムにおいて、ドメイン駆動開発 (DDD)関数型プログラミング (FP) を組み合わせたいというニーズが高まっています。TypeScript を活用すれば、静的型付けによる安全性と多彩な OSS 群の恩恵を受けることができますが、選択する実装スタックによって生産性や保守性が大きく変わります。

本記事では、2025 年 5 月現在で特に注目されている 5 つの候補を比較し、シナリオごとのおすすめを整理して紹介します。

記事に登場する用語集
用語 解説
ドメイン駆動開発 (DDD) ソフトウェアをビジネスドメイン中心に設計・実装するアプローチ。エンティティ、値オブジェクト、集約などのパターンで複雑さを分割し、ドメインモデルの一貫性を保つ。
関数型プログラミング (FP) データの不変性と純粋関数を重視し、副作用を分離するプログラミングパラダイム。パイプライン、代数的データ型、モナドなどを用いてロジックを安全かつ再利用可能に合成できる。
オブジェクト指向プログラミング (OOP) クラス・オブジェクト・継承・ポリモーフィズムを用いてデータと振る舞いをカプセル化するパラダイム。状態と振る舞いを一体化することでモデリングしやすい一方、共有状態の複雑化には注意が必要。
CQRS 読み取り操作と書き込み操作をそれぞれ独立したモデルで扱い、スケーラビリティと保守性を高めるアーキテクチャパターン。
Event Sourcing すべての状態変更をイベントとして保存し、その履歴を再生して現在状態を導出する手法。アプリケーションの監査やタイムトラベルが容易になる。
Effect System I/O・例外・並行処理などの副作用を型で表現し、コンパイル時に安全性を担保する仕組み。Effect (旧 Effect Stack) で中心的役割を果たす。
Edge Runtime クラウドエッジ(CDN ノードなど)で動作する超軽量ランタイム。低レイテンシと大規模スケールアウトが特長。
TaskEither fp-ts の型で、非同期処理(Task)と成功/失敗の分岐(Either)を合成したもの。TaskEither<E, A> は「失敗時 E、成功時 A を返す遅延実行タスク」を表す。
Layer (Effect) Effect で依存サービスを注入するための構造体。サービス実装を切り替えつつ、純粋関数でビジネスロジックを記述できる。
ポート&アダプタ (Hexagonal Architecture) アプリケーション中心の六角形構造で、外部システムとの接続をポート(抽象)とアダプタ(実装)に分離する設計。
値オブジェクト 同一性ではなく値で比較される不変オブジェクト。ドメインモデルの整合性を保ちながら意図を明示できる。

比較対象候補一覧

# フレームワーク/スタック 概要 FP 支援度 DDD 支援度 学習コスト 主なデプロイ先
1 Effect(@effect/* ZIO に着想を得たエフェクトシステム。コアランタイム ≒ 15 kB gzip ★★★★★ ★★★★☆ Node / Deno / Bun / Edge
2 Booster Framework CQRS + Event Sourcing を宣言的に自動化。GraphQL API 生成。 ★★☆☆☆ ★★★★★ 低〜中 AWS (GA) / Azure (Preview)
3 Hono 約 14 kB の超軽量ルータ。Edge 402 k ops/sec・Node 47 k req/sec ★★★☆☆ ★★★☆☆ 低〜中 Edge / Node / Bun / Deno
4 fp-ts + Fastify @fastify/funky で TaskEither 返却をネイティブ化。 ★★★★☆ ★★★☆☆ Node
5 NestJS (Functional Style) OOP 重視フレームワークだが @nestjs/cqrs 等で DDD を実装可。 ★★☆☆☆ ★★★★☆ Node

★は ChatGPT o3 さんの主観による指標です。

各候補の特徴

1. Effect (ライブラリ群)

  • Effect.Effect<R, E, A> によって副作用・エラー・依存関係を型で明確に管理(公式ドキュメント)。
  • Layer を用いた依存関係管理でドメインとインフラを疎結合に保つ。ただし HTTP ルーティングや DI などのフルスタック機能は持たず、Web サーバは別途選定が必要
  • ストリーム、並列制御、スケジューラなど高負荷向け機能が標準搭載。
  • 学習曲線が比較的高い点が注意。

2. Booster Framework (フレームワーク)

  • 宣言的に CQRS + Event Sourcing を実現し、GraphQL API も自動生成(公式サイト)。
  • デコレータでコマンド・イベント・エンティティを記述すると、DynamoDB/SNS/Lambda まで自動セットアップ。
  • RDB 使用時には制約が多いため注意が必要。

3. Hono (マイクロフレームワーク)

import { Hono } from 'hono'
import { validator } from '@hono/effect-validator'
import { Effect, pipe } from 'effect'
import { createTodoSchema } from '../../domain/todo'
import { createTodoUseCase } from '../../usecase/create-todo'

export const app = new Hono()

app.post('/todos', validator('json', createTodoSchema), async c =>
  pipe(
    createTodoUseCase(c.req.valid('json')), // 純粋関数
    Effect.runPromise,                      // ここで副作用実行
  ).then(r => c.json(r))
)

4. fp-ts + Fastify (スタック)

  • fp-ts (ライブラリ) の TaskEither などを Fastify (フレームワーク) と組み合わせるレシピ。
  • @fastify/funky を使い、副作用を伴う関数型構造を HTTP ハンドラに直接返却可能(リポジトリ)。
  • 豊富なプラグインで段階的に導入しやすく、既存 Node.js 資産との親和性が高い。

5. NestJS (フレームワーク)

  • DI コンテナや AOP 機能など、企業向けのガイドラインが豊富。
  • @nestjs/cqrs を活用することでアプリケーション層の構造化が容易。
  • クラスとデコレータ中心設計のため、FP スタイルを徹底するには調整が必要

関数型 DDD 実践のポイント

  1. ドメインモデルを型と純粋関数で設計する。
  2. 副作用を特定の層(HTTP、CLI、Worker)に集約する。
  3. ポート&アダプタアーキテクチャで依存関係を反転する。
  4. ユースケース単位のテストを徹底する。
  5. ビジネス成長に合わせてドメインの境界を継続的にリファクタリングする。

まとめ

ニーズ 推奨候補
Edge での高性能な動作 Hono (マイクロフレームワーク)
型で副作用を管理 Effect (ライブラリ群)
CQRS/Event Sourcing を統合 Booster Framework (フレームワーク)
既存 Node 資産を活用した FP 導入 fp-ts + Fastify (スタック)
NestJS 文化を継承 NestJS (フレームワーク)

Discussion