第2章 直結コードの「つらさ」あるある 😵💫💥
![hex_ts_study_002[(./picture/hex_ts_study_002_the_layered_architecture_probl.png)
この章は、ざっくり言うと「なんで“設計”が必要になるの?」を体感する回だよ〜😊✨ ヘキサゴナル(Ports & Adapters)は、中心(ルール)を外側(UI/DB/外部API)から守って、交換しやすく&テストしやすくする考え方なんだけど、まずは「守られてない世界」のしんどさを見ちゃおう…!🏰🧨 (AWS ドキュメント)
2.1 今日のゴール 🎯✨
この章が終わったら、こんなことが言えるようになるよ😊🗣️
- 「直結コードって、どこがつらいの?」を説明できる💬
- 「つらいのは気合が足りないから」じゃなくて、構造の問題だと分かる🧠✨
- 次の章で出てくる「中心を守る🛡️」が、なぜ効くのか腹落ちする🌱
2.2 直結コードってなに?(ざっくり)🧷
直結コードは、1つの場所にこういうのが全部混ざってる状態👇
- 画面・HTTPの受け取り(入力)📮
- ルール(業務判断)🧠
- DBやファイル保存(永続化)💾
- 外部サービス呼び出し(メール/通知など)📨
- 例外処理やログ📊
混ざると「全部わかる人しか触れないコード」になりがち😇💥
2.3 直結コードあるある集 😵💫(“怖い”の正体)
よく起きる悲劇を、あるある形式でいくね😂✨
あるある①:ちょっと直しただけで別の場所が壊れる 😱🔧
- 仕様変更:タイトルの最大文字数が変わった
- なのに、入力チェックがあちこちに散ってて、直し漏れが出る…🧨
- しかも壊れるのは「実行してみないと分からない」タイプ💥
👉「修正が怖い」って、気持ちの問題じゃなくて 変更箇所が読めない構造の問題なんだよね🌀
あるある②:テストができない(or すっごい遅い)🐢🧪
- ちょっとしたルールを確認したいだけなのに DB起動・HTTP起動・環境変数…みたいな儀式が必要😵💫
- その結果、「テスト書くのやめよ…」になって事故る😭
ヘキサゴナルが狙うのは、中心(ルール)を外部から切り離して 中心だけテストできる状態だよ🧠✨ (AWS ドキュメント)
あるある③:別の入口(CLI/バッチ/別画面)を作りたくなった瞬間に詰む 🚪💥
- Web画面で動くように作った
- 後から「CLIでも同じ処理したい!」
- でも処理がControllerにベッタリで、コピペ祭り🎪🔥
コピペが増えるほど、仕様変更のときに地獄👹
あるある④:障害の切り分けがむずい(原因がどこか分からん)🕵️♀️💣
直結コードは「入口も保存もルールも全部そこ」だから、
- バリデーションが悪い?
- DBが落ちてる?
- 外部APIが遅い?
- ルールが間違ってる?
が混ざって、ログ見ても「???」になりがち😵💫📉
2.4 “なぜ怖いのか”=依存が散らばるから 🧨🧭
直結コードのいちばんの問題はこれ👇
中心(ルール)が、外側(DB/HTTP/フレームワーク/外部サービス)に引っ張られる😵💫
こうなると、ルールを直したいだけなのに外側の都合も一緒に考えなきゃいけない。 結果、変更が雪だるま式に膨らむ☃️💥
ヘキサゴナル(Ports & Adapters)は、まさにこの「汚染」を防ぐために考えられた枠組みだよ〜🛡️✨ (ウィキペディア)
2.5 “読みにくい直結”ミニ例(※わざとヒドい😇)👀
一瞬だけ、混ざるとどうなるか見よっか😂 「Todo追加」のつもりなのに、入口・ルール・保存・通知が全部ここに…みたいな感じ👇
// わざと悪い例:全部まぜまぜ😇💥
import express from "express";
import fs from "node:fs/promises";
const app = express();
app.use(express.json());
app.post("/todos", async (req, res) => {
// 入力チェック(本当は入口側でやるにしても、散らばると地獄)
const title = String(req.body.title ?? "");
if (!title.trim()) return res.status(400).json({ message: "title is required" });
// ルール(本当は中心に置きたい)
if (title.length > 30) return res.status(400).json({ message: "too long" });
// 保存(I/O)
const path = "./todos.json";
const json = await fs.readFile(path, "utf-8").catch(() => "[]");
const todos = JSON.parse(json);
const todo = { id: crypto.randomUUID(), title, completed: false };
todos.push(todo);
await fs.writeFile(path, JSON.stringify(todos, null, 2), "utf-8");
// ついでに通知(外部APIの代わり…のつもり)
console.log("notify: new todo", todo.id);
res.status(201).json(todo);
});
app.listen(3000);
これ、何がイヤ?😵💫
- 「タイトル空NG」を変えたいだけなのに、HTTPとファイル保存のことも触る羽目になる🧨
- 後から保存先をDBにしたら、この関数まるごと大工事になりがち🏗️💥
- ルールのテストをしたいのに、ファイルI/Oが絡んで遅い&壊れやすい🐢
2.6 ちょいワーク✍️:どれが「ルール」で、どれが「I/O」?
上のコードを見て、頭の中でいいから分けてみて〜😊✨
- 🧠 ルール(例:title空NG、長さ制限)
- 📮 入口(HTTPで受け取って返す)
- 💾 I/O(ファイル読み書き)
- 🧩 変換(req.body → string、例外→レスポンス)
分けられたら勝ち🎉 この「分けたい欲」が、次章の“城の中心を守る”につながるよ🏰🛡️
2.7 AIに聞くと理解が速い🤖💖(でも使い方は安全に)
直結コードを貼って、AIにこう聞くと学びが爆速になるよ🚀✨
- 「このコードの責務を3〜5個に分解して説明して」🧩
- 「仕様変更(例:title最大30→50)の影響範囲を列挙して」📌
- 「テストしづらい理由を“外部依存”の観点で説明して」🧪
ポイントは、答えを丸呑みしないで「責務」「依存」「混ざり」を言語化すること😊🫶
2.8 まとめ 🎁💖(今日の結論)
- 直結がつらいのは、あなたのせいじゃない🥺 依存が散らばって、変更が爆発する構造のせい💥
- だから次にやることは、「中心(ルール)を外側から守る」方向に寄せること🛡️✨
- ヘキサゴナル(Ports & Adapters)は、そのための考え方だよ🏰🔌🧩 (AWS ドキュメント)
2.9 次章予告 🌉✨
次は、ヘキサゴナルの「1枚絵」を見て、 “中心=城、外側=城下町” みたいなイメージで掴みにいくよ〜🏰💕
(中心を守れると、DBやUIを差し替えても平気になるのが気持ちいいのだ…😎✨)