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

第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を差し替えても平気になるのが気持ちいいのだ…😎✨)