メインコンテンツまでスキップ

第1章 この章のゴール宣言 🎯✨

![hex_ts_study_001[(./picture/hex_ts_study_001_introduction_to_hexagonal_arch.png)


1. この章のゴール宣言 🎯✨

この章を読み終わったら、次の3つができるようになるのがゴールだよ😊💖

  • 「Port/Adapterって何?」を、自分の言葉で説明できる🔌🧩✨
  • “中心(ルール)を守る”ってどういう意味かが腹落ちする🏰🛡️
  • **依存の向き(外→中はOK、中→外はNG)**を判断できる🧭🔥

そして、この後の章で作っていく“今日のゴールアプリ”は… **小さなToDo(追加・一覧・完了)**みたいなミニアプリ📝🍰✅ いきなり完璧を目指さず、小さく作って育てる方針だよ🌱✨

つまずきやすいポイントも先に言っちゃうね😊 概念だけ読むとふわっとする → だからこの章は「あるある → 1枚絵 → 合言葉 → 依存の向き」って順で、体感しながら整理するよ🧠💞


2. 直結コードの「つらさ」あるある 😵‍💫💥

設計をまだ本格的にやってない時って、ついこうなりがち👇😵

  • 画面(UI)で入力チェックして
  • そのままファイル保存して
  • そのまま外部APIも叩いて
  • ついでにログも混ぜて…

全部が1か所に混ざるやつ😇💣

何がつらいの?(痛みポイント)😱

  • ちょっと仕様変えるだけで、どこが壊れるか分からない🧨
  • テストしようとしても、DB/ファイル/ネットが絡んでムリゲーになる🧪💔
  • “本来のルール”がどこにあるか迷子になる🌀

これ、根っこは超シンプル👇 **「依存が散らばってる」**から怖いの😵‍💫


3. ヘキサゴナルの1枚絵(城の中心を守る)🏰🛡️

ヘキサゴナルは、ざっくり言うとこう👇✨

  • 中心(城の中):アプリのルール(ドメイン/ユースケース)🧠❤️
  • 外側(城の外):入出力(画面・HTTP・DB・ファイル・外部API)🌐💾📄📨

そして大事なのはこれ👇 中心は、外側の都合を知らない🙅‍♀️ (中心は“ルール”に集中する✨)

「Ports & Adapters」って名前は、提唱者の Alistair Cockburn がこの考え方を説明するときに使った言い方だよ🔌🧩 (アリステア・コックバーン) AWSの解説も「UIやデータストアに依存せずにテストしやすくする」って趣旨で説明してるよ🧪✨ (AWS ドキュメント)

六角形(ヘキサゴン)の形が重要ってわけじゃないよ🙆‍♀️ **“中心を守る比喩”**として受け取ればOK😊✨ (アリステア・コックバーン)


4. まず覚える合言葉3つ 🗣️✨

この章は、まずこれだけ覚えたら勝ち🥇✨

  • 中心を守る🛡️(ルールを外の都合から隔離する)
  • 約束はPort🔌(中心が「こう呼んでね」と決める)
  • 変換はAdapter🧩(外の都合を、中心の約束に合わせて翻訳する)

これ、あとで何回も効いてくるやつ🧠💞


5. Portってなに?(差し込み口=約束)🔌😊

Portは一言でいうと👇 **中心が外側にお願いするときの“契約(インターフェース)”**だよ📌✨

たとえば中心(ユースケース)が「ToDoを保存したい」とするよね? そのとき中心はこう言う感じ👇

  • 「保存してね」
  • 「一覧ちょうだい」
  • 「IDで取ってきてね」

でも、中心は “どこに保存するか” は知らない🙅‍♀️ ファイル?DB?メモリ?クラウド?…それは外側の仕事🌍✨

だから中心は、必要最小限の約束だけ決めるのがコツ✂️✨

Portが増えすぎると死ぬ話⚠️😇

Portを「なんでもかんでも」作り始めると、

  • 似たPortが乱立して
  • どれ使うか分からなくなって
  • 結局、設計が複雑化する 🌀

予防線はこれ👇 ✅ “中心が本当に必要な会話だけ” Portにする1つのPortは、目的が1つ(会話がブレない) (アリステア・コックバーン)


6. Adapterってなに?(変換器=実装)🧩✨

Adapterは一言でいうと👇 **外側の都合を吸収して、Portの約束どおりに動かす“翻訳係”**🔁✨

例:

  • DBの書き方(SQL/ORM)→ Portの形に合わせる💾🔁
  • HTTPリクエスト → ユースケース入力に変換する🌐📮
  • ファイル読み書きの例外 → 中心が扱える形に包む📄🧯

Adapterは「薄い」が正義🥗✨

Adapterにルール(業務判断)を入れ始めると…

  • ルールが外側へ漏れて
  • 中心が空っぽになって
  • 差し替えもテストも微妙になる😱💔

Adapterは基本こう👇 ✅ 変換(入力・出力の形を整える) ✅ 呼び出し(DB/外部API/ファイルへ) ✅ 例外のラップ(外の失敗を扱いやすくする)


7. Inbound / Outbound の超やさしい整理 🚪➡️⬅️

ここ、最初に混乱しやすいけど、めっちゃ単純だよ😊✨

Inbound(外→中)🚪➡️🏰

外側が中心を呼び出す入口 例:CLI / HTTP API / 画面ボタン / バッチ実行 など⌨️🌐🖱️

→ 「ユーザー操作」や「外部からの入力」が来るところ✨

Outbound(中→外)🏰➡️🌍

中心が外側にお願いする出口 例:DB / ファイル / 外部API / メール送信 など💾📄📨


8. 依存の向き(これだけは最重要)🧭🔥

ヘキサゴナルで一番大事なの、ほんとにここ🥺✨

ルール:中心は外側を知らない 🙅‍♀️

  • 中心(ドメイン/ユースケース)は HTTPもDBもファイル形式も知らない🙅‍♀️

外側は中心を知っていい 👌

  • 外側(Adapter)は 中心のPortを実装するために中心を知ってOK😊

つまり依存はこう👇

  • 外 → 中(OK)
  • 中 → 外(NG)

これが守れると、何がうれしい?🎁✨

  • UIをCLI→HTTPに変えても中心ノーダメ🌐🔁⌨️
  • DBをファイル→SQLite→クラウドに変えても中心ノーダメ💾🔁📄
  • テストで外側を差し替えて、中心だけ爆速で試せる🧪🚀

Nodeの世界でも、実運用はLTS系を使って周辺を入れ替えながら育てることが多いんだけど、入れ替えやすさがあるとこういう更新にも強くなるよ🔁✨(Nodeの現行/LTSの扱いは公式が整理してるよ) (Node.js)


ちょい実感:ミニ例で「混ざるとつらい」を見る👀💥

(※ここは“嫌な例”を一瞬見るだけ!すぐ戻るよ😊)

// 😵 ありがちな「全部入り」例(こうはなりたくない)
import { readFileSync, writeFileSync } from "node:fs";

function addTodo(title: string) {
if (!title.trim()) throw new Error("タイトル空はダメ");

// ファイル読み込み(I/O)
const json = readFileSync("todos.json", "utf-8");
const todos = JSON.parse(json) as { id: string; title: string; completed: boolean }[];

// ルール・状態作成
const todo = { id: crypto.randomUUID(), title, completed: false };

// 保存(I/O)
todos.push(todo);
writeFileSync("todos.json", JSON.stringify(todos, null, 2), "utf-8");

return todo;
}

このコード、今は短いけど、すぐこうなる😇

  • HTTP化したい → この関数の中を改造する羽目🌐💥
  • テストしたい → ファイル必須でつらい🧪📄
  • ルール増えた → さらに巨大化😵‍💫

ヘキサゴナルの発想だと、こう分けるイメージ👇✨

  • 中心:「タイトル空はダメ」「ToDoを追加する手順」🧠
  • 外側:「保存先がファイルである」「JSONである」📄

AI拡張ちょい活用(この章向け)🤖💖

AIはこの章だと、理解の補助に使うのが超おすすめ😊✨ (設計の芯を丸投げはまだ早い⚠️)

そのまま使える質問テンプレ📝🤖

  • 「Ports & Adapters を、ToDoアプリの例で“中心/外側”に分けて説明して」
  • 「このコードは中心が外部都合を知ってしまってる?どこが境界?」
  • 「Portを“必要最小限”にするために、会話(目的)を1つに絞って提案して」

最近はGitHub Copilot周辺も“提案”だけじゃなく“エージェントっぽい動き”まで広がってきてるから、レビュー相手として使うのもすごく相性いいよ🕵️‍♀️✨ (The Verge)


まとめ:第1章で持ち帰る3行 🎁💖

  • 中心を守る🛡️(ルールを外の都合から隔離)
  • 約束はPort🔌(中心が必要な会話をインターフェース化) (アリステア・コックバーン)
  • 変換はAdapter🧩(外の都合をPortに合わせて翻訳)

かんたん理解チェック✅✨(3問だけ)

  1. 「中心はDBを知っていい?🙆‍♀️🙅‍♀️」
  2. Portは「実装」?それとも「約束」?🔌
  3. 「外→中」「中→外」どっちがOK?🧭

次章への予告🌉✨

次の章からは、もう少し手を動かしながら、 「直結のつらさ」→「分けたらラク!」を体験していくよ😊💻✨

(※ちなみにTypeScriptは現時点で npmの最新が 5.9.x 系として案内されてるよ📦✨) (npmjs.com)