はじめに
個人開発を始める際、「今回は綺麗に作るぞ!」と意気込んでクリーンアーキテクチャを採用したことはありませんか?
私もそうでした。しかし、結果として待っていたのは「機能開発が進まない」「コード量だけが増える」という絶望でした。
本記事では、私がクリーンアーキテクチャを捨てて辿り着いた、**一人開発にちょうどいい「汚すぎない設計」**を紹介します。
なぜ個人開発でクリーンアーキテクチャは「毒」になるのか
理想を追い求めた結果、以下のような「設計のオーバーヘッド」に押しつぶされました。
-
ディレクトリの往復で日が暮れる:
Domain,Usecase,Infrastructure... 1つのAPIを作るのに5箇所のファイルを書き換える苦行。 - 「誰のため」のインターフェース?: 将来DBを差し替える予定もないのに、Repositoryパターンで抽象化しまくり、コードの8割が「準備」になる。
-
型の変換地獄:
Entity↔DTO↔Requestの変換コードを書くだけで力尽きる。
結論: 1人で開発しているのに、他人と疎結合になるためのコストを払いすぎていた。
行き着いた『ほどよい』設計ルール
「クリーン」であることより、**「1ヶ月後の自分が迷わず、かつ爆速で組める」**ことを優先したルールです。
1. レイヤーは「3つ」まで
複雑な階層は廃止し、責務を3つに集約します。
- UI / Routes: リクエストを受け取り、レスポンスを返す(Next.jsのApp RouterやController)。
- Services: ビジネスロジックの本体。ここが一番大事。
- Libs / Models: DB操作(Prisma等)や外部SDKの初期化。
2. 「依存の一方向化」だけは死守する
クリーンアーキテクチャの核である**「内側(ロジック)は外側(DBやWeb)を知らない」**というルールだけは守ります。
-
UI→Services→LibsはOK。 -
ServicesがHTTPリクエストに直接触れてはいけない。
3. 「早期の抽象化」を捨てる
-
Repositoryパターンは作らない: PrismaなどのORMを
Servicesで直接使ってもOKとする。 - Entity変換をやめる: DBの型をそのままUIまで流しても良い。型定義の重複を削除。
具体的な構成例 (TypeScript / Next.js想定)
src/
├── app/ # UI / Routes (Next.js)
├── services/ # ビジネスロジック (ここに全てを書く)
│ ├── userService.ts
│ └── postService.ts
├── lib/ # 外部接続 (Prisma, Stripe, AWS)
│ └── prisma.ts
└── types/ # 共有の型
サービス層の書き方(例)
インターフェースは作らず、素のクラスや関数で書きます。
// services/userService.ts
import { db } from "@/lib/prisma";
export const registerUser = async (email: string, name: string) => {
// 1. ビジネスロジック(バリデーション等)
const existing = await db.user.findUnique({ where: { email } });
if (existing) throw new Error("既に登録されています");
// 2. 直接DB操作(抽象化しすぎない!)
return await db.user.create({
data: { email, name }
});
};
この設計のメリット
-
ファイルを探さない: 「あのロジックどこだっけ?」となったら
services/を見るだけで済む。 -
ボイラープレートがゼロ:
interfaceやDI容器の設定が不要。 - 変更に強い: DBのカラムが増えても、修正箇所は最小限。
おわりに:個人開発の正解は「完成させること」
クリーンアーキテクチャは、大規模チームや長期運用で真価を発揮するものです。
しかし、個人開発の最大の敵は**「飽き」と「進捗のなさ」**です。
もし今、設計の美しさにこだわって手が止まっているなら、一度そのこだわりを捨てて「ほどよい設計」に逃げてみませんか?
「動くコードは、美しい設計図より価値がある」。私はそう信じています。