第1章:SoCってなに?30秒でつかむ超入門🎀🧠✨
この章でできるようになること(ゴール)✅🌸
この章が終わるころには、こんな状態になれます😊✨
- 「このコード、いろいろ混ざってない?😇」を“感覚じゃなくて理由つき”で言える
- SoC(関心の分離)を ひとことで説明 できる(超大事!)
- コードを見て「UI」「ルール」「通信」などの“関心”を ざっくり仕分け できる
- AI(Copilot/Codex系)に 分離案を出させる ときの聞き方がわかる🤖💬✨
1. SoCってなに?いきなり結論🍓
SoC(Separation of Concerns / 関心の分離)は、超ざっくり言うと👇
「変更理由が違うものは、同じ場所に混ぜない」 🧁✨ (=“別々に直せるように分けておく”ってこと!)
「関心の分離」自体が、ソフトウェアを“いくつかの側面に分けて扱えるようにする”考え方として説明されています。 (ウィキペディア)
2. 「関心(Concern)」ってなに?🧺💡

“関心”って言われると難しそうだけど、実はめちゃ身近です😊
関心=「気にする理由」「やりたいことの種類」📌
たとえばアプリで言うと…
- 見た目・画面(ボタン、表示、入力)🖥️🎀
- 業務ルール(割引、在庫チェック、ポイント付与)📏🧠
- 通信(API呼び出し、リトライ、エラー処理)🌐📡
- ログ(調査のための記録)📝
- 保存(localStorage/DB/ファイル)🗄️✨
こういう“種類の違い”が「関心」です🌸
3. “混ぜると事故る”ってどういうこと?😵💫💥(直感でOK)
ありがちな事故シーン🎬
「ボタン押したら注文する」だけのはずが、1つの関数に全部入ってると…👇
- デザイン変更(UI)したいだけなのに、割引ロジック(ルール)を壊す😇
- APIの仕様が変わった(通信)だけなのに、画面表示(UI)にバグが出る😇
- どこを直せばいいか分からなくて、修正が怖くなる😇
これが “修正が怖いコード” の入り口です🚪💥
4. まずは「ごちゃ混ぜ例」を見てみよ〜😇🍝
「こういうの、見たことある!」ってなるはず😂
// 例:注文ボタンのクリック処理(ごちゃ混ぜ🍝)
async function onClickOrder() {
// UI: 入力を読む
const name = (document.querySelector("#name") as HTMLInputElement).value;
const coupon = (document.querySelector("#coupon") as HTMLInputElement).value;
// ルール: バリデーション
if (!name) {
alert("名前を入力してね!");
return;
}
// ルール: 割引計算
const basePrice = 1200;
const discount = coupon === "HAPPY" ? 200 : 0;
const total = basePrice - discount;
// 通信: APIに送信
const res = await fetch("/api/orders", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, total }),
});
// UI: 結果表示
if (res.ok) {
document.querySelector("#result")!.textContent = `注文OK!合計 ${total}円`;
} else {
document.querySelector("#result")!.textContent = "注文失敗…";
}
// ログ: 記録
console.log("[order]", { name, total, ok: res.ok });
}
何が問題?(責めないでね😂)
この関数の中に…
- UI 🖥️(DOM読む/表示する)
- ルール 📏(バリデーション/割引計算)
- 通信 🌐(fetch)
- ログ 📝(console.log)
が ぜーんぶ一緒 に入ってます🍝💥 だから、どれか1つ変えるだけでも、他が巻き添えになりやすいんです😇
5. SoCの最初の一歩:「分ける」はこうやる✂️✨
いきなり“完璧な設計”はしません🙆♀️ まずは 分けやすいところから でOKです🌸
5.1 いちばん分けやすいのは「純粋な処理」🧼✨
純粋な処理=入力が同じなら出力が同じ(外の世界に触らない)💎 例:割引計算、合計計算、判定、変換…など
// ルール(純粋✨):割引計算
export function calcTotal(basePrice: number, coupon: string): number {
const discount = coupon === "HAPPY" ? 200 : 0;
return basePrice - discount;
}
これ、めっちゃテストしやすいです🧪✨ UIも通信も関係ないから、壊れにくい中心(コア)になれます🛡️
5.2 “外の世界”は副作用ゾーン⚡🌐
副作用=通信・表示・保存・時刻・乱数…みたいに外に触るもの。
// 通信(副作用🌐):API送信だけ担当
export async function postOrder(data: { name: string; total: number }) {
return fetch("/api/orders", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
}
5.3 最後に「つなぐ役」を作る🧩(ここが気持ちいい✨)
UIはUI、ルールはルール、通信は通信。 最後に“組み立てる役” が「じゃあ順番に呼ぶね😊」を担当します。
import { calcTotal } from "./calcTotal";
import { postOrder } from "./postOrder";
export async function onClickOrderSeparated() {
const name = (document.querySelector("#name") as HTMLInputElement).value;
const coupon = (document.querySelector("#coupon") as HTMLInputElement).value;
if (!name) {
alert("名前を入力してね!");
return;
}
const total = calcTotal(1200, coupon); // ルール🧼
const res = await postOrder({ name, total }); // 通信🌐
document.querySelector("#result")!.textContent =
res.ok ? `注文OK!合計 ${total}円` : "注文失敗…";
}
同じ機能なのに、見通しが急に良くなる😍✨ これがSoCの気持ちよさです🎀
6. SoCができると何がうれしいの?🎁✨
うれしさ①:変更が怖くなくなる😌🔧
UI変えるならUIだけ、割引変えるなら計算だけ。 影響範囲が小さい=事故が減る🚑✨
うれしさ②:テストがラクになる🧪🌸
純粋関数(ルール)だけなら、UIも通信も不要! 「入力→出力」を見るだけでOKになります😊
うれしさ③:AIが当てやすくなる🤖🎯
ごちゃ混ぜだとAIも「どこ直すのが正解?」で迷います😇 分かれてると、AIは 狙い撃ち できるようになります✨
7. ミニ練習:この処理、どの関心?仕分けゲーム🎮✨
次の項目を、(A)UI /(B)ルール /(C)通信 /(D)保存 /(E)ログ に分けてみてね😊💕
- 入力フォームの値を読む
- クーポンが有効かチェックする
- APIに注文内容をPOSTする
- 注文成功メッセージを表示する
- 失敗したときの原因をconsoleに出す
- 注文履歴をlocalStorageに保存する
コツ👉「それ、何が変わったら直す?」で考えると当たりやすいです🎯 (表示が変わる→UI、ルールが変わる→ルール、API仕様→通信…みたいに✨)
8. AIに手伝わせるコツ(超重要🤖💬✨)
SoCは、AIと相性めちゃ良いです💞 ただし、聞き方がポイント!
8.1 分離案を出してもらうプロンプト例🎁
(そのままコピペでOKだよ😊)
- 「この関数の中の“関心”を列挙して、UI/ルール/通信/保存/ログに分類して」
- 「“変更理由が違うもの”が混ざっている箇所を指摘して、分割案を3つ出して」
- 「純粋関数にできる部分だけ抜き出して、関数名も提案して」
- 「副作用(fetch/DOM/localStorage)を隔離する案にして」
8.2 1つだけ注意⚠️
AIの分割はたまに「分けすぎ」「名前がふわふわ」になりがちです😂 そのときは👇を追加すると安定します✨
- 「今はファイル数を増やしすぎないで。まずは2〜3個の関心に分けて」
- 「命名は“何をするか”じゃなく“何の関心か”が伝わる名前で」
9. コラム:いまどきTypeScriptの小ネタ(知ってると得💎)🧠✨
- 現時点での TypeScript の最新版は 5.9 系(npm上の “Latest” が 5.9.3 として表示)です。 (NPM)
- TypeScript 5.9 では
tsc --initの初期設定が“ミニマル寄り”に更新されて、最初の迷子が減る方向になっています🧭✨ (Microsoft for Developers) - VS CodeはTypeScriptの言語サービスを内蔵していて、必要ならワークスペース側のTypeScriptに切り替えて使えます🔄(チームで揃えたいとき便利!) (Visual Studio Code)
(この教材では、設計が主役なので“必要なときだけ”使っていくよ😊)
10. まとめ🎀✨(今日の合言葉)
- SoC=変更理由が違うものは混ぜない 🧁
- まずは「純粋な処理(ルール)」と「副作用(UI/通信/保存)」を分ける🧼⚡
- 分けたら最後に「つなぐ役」を置く🧩
- AIは“関心の分類”が得意!聞き方で強くなる🤖✨
次章の予告📚🌸
次は 「なぜ混ぜるとツラいの?」 を、もっとリアルな修正事故で体験します😵💫💥 「修正が怖いコード」の正体、いっしょに暴きにいこ〜っ🔍✨