0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クリーンアーキテクチャのエッセンスを“図で挫折した人向け”に超わかりやすくまとめた

Posted at

👋 はじめに

クリーンアーキテクチャの図を見ると、
「円がいっぱいあって、結局どうすればいいの…?」
となった経験はありませんか?

実際、現場のエンジニアでも

  • 何が目的なのかよく分からない
  • 層は知ってるけど実務にどう落とすの?
  • 小規模案件に導入すると途端に“過剰設計感”が出る

といった悩みが多いアーキテクチャです。

この記事では クリーンアーキテクチャの本質だけにフォーカスし、
最低限これだけ知っていればOK
というエッセンスだけをカジュアルに整理しました。

TypeScript の極小サンプルコードもあるので、実装イメージまで掴めます。

🎯 記事のゴール

この記事を読み終えると次のことができるようになります。

  • クリーンアーキテクチャを 一言で説明
  • 4 層の役割(Entities / UseCases / InterfaceAdapters / Frameworks)が理解できる
  • 自プロジェクトにどう当てはめるかイメージできる
  • 最小構成でクリーンアーキ風の設計が再現できる

🧭 クリーンアーキテクチャを一言でいうと?

Uncle Bob(Robert C. Martin)が提唱した、

「ビジネスロジックを外界(フレームワーク・DB)から守るための設計」

です。

もっと雑に言うと…

“技術の寿命にビジネスロジックを巻き込ませないための仕組み”

この考え方を支える鉄則が Dependency Rule(依存の向き)

依存は内側(ビジネスルール)へ向く

  • Express は UseCase を知らない
  • DB は Entity を知らない
  • 内側は外の詳細を import しない

という構造を作るだけで“クリーンアーキっぽさ”が生まれます。

🧩 クリーンアーキの4層(図を文字だけで超シンプル解説)

① Entities(エンティティ)

ビジネスルールの“原則”部分。
技術要素を知らないのが理想。

② Use Cases(ユースケース)

操作手順(アプリ固有のシナリオ)。
DB も UI も知らず、抽象インターフェースに依存する。

③ Interface Adapters(アダプタ)

Webフレームワーク・DB・外部APIを
ユースケースが扱いやすい形に変換する層。

④ Frameworks & Drivers

Express / Spring / DB / 外部API / メッセージキューなどすべてここ。
最も外側で技術詳細の塊。

💡 他アーキテクチャとの関係

Layered / Hexagonal / Onion と本質は共通。

「ドメインを中心に据えて、外側が変わっても壊れない構造をつくる」
という思想に基づいているだけ。

🛠 メリット(実務で効くポイント)

  • Express→Fastify のような乗り換えが楽
  • UseCase が“純粋なクラス”なのでテスト容易
  • 外部API変更をアダプタ側だけで吸収しやすい
  • 責務分離が自然にでき、保守性UP

⚠️ 注意点(“罠”ポイント)

特に小規模プロジェクトで発生しがち:

  • 層だけ立派で中身が薄くなる
  • ただのフォルダ分けになる
  • 初手からガチでやりすぎると過剰設計に

まずは “依存の向き” だけ意識すれば十分。

🏪 例え話:チェーン店の本部と店舗

  • Entities → 本部ルールブック
  • UseCases → 業務マニュアル
  • Adapters → 店長(店舗事情に合わせて橋渡し)
  • Frameworks → 店舗設備(レジ、建物、回線など)

目的:

設備(技術詳細)が変わっても、マニュアル(ユースケース)とルールブック(エンティティ)は変わらない状態。

これがクリーンアーキの思想です。

🧪 TypeScriptでつくる“最小”クリーンアーキ構成

ディレクトリ構成

src/
  core/
    domain/
    usecase/
  adapters/
    db/
    mail/
    web/
  frameworks/

Entity

export class User {
  constructor(public readonly id: string, public readonly email: string) {
    if (!email.includes('@')) throw new Error('Invalid email');
  }
}

UseCase

export class RegisterUser {
  constructor(private readonly repo: UserRepository, private readonly mailer: Mailer) {}

  async execute(input: { email: string }) {
    const exists = await this.repo.findByEmail(input.email);
    if (exists) throw new Error('Already exists');

    const user = new User(crypto.randomUUID(), input.email);
    await this.repo.save(user);
    await this.mailer.sendWelcomeMail(user.email);
  }
}

Adapter(DB)

export class InMemoryUserRepository implements UserRepository {
  private users: User[] = [];
  async findByEmail(email: string) { return this.users.find(u => u.email === email) ?? null; }
  async save(user: User) { this.users.push(user); }
}

Framework(Express)

app.post('/users', controller.handle);

🧾 まとめ:エッセンスはこの2つ

  1. 依存はビジネスルール(内側)へ向ける
  2. 技術詳細は外側に追い出し、いつでも交換できるようにする

これさえ守れば、図の形やフォルダ構造に厳密でなくても
「実質クリーンアーキ」になります。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?