# Architecture Proposal

> アプリの性質（何を中心に回るか・外の世界との境界・状態の持ち方・変わりやすい場所・実行環境）をコードとドキュメントから読み取り、それに合ったアーキテクチャの様式とディレクトリ構造を、候補の比較・現状との差分・移行の段階つきの提案書としてリポジトリに書く。ユーザーが「アーキテクチャを整えたい／見直したい」「ディレクトリ構造をどうすべきか」「層の切り方に迷う」「構造がごちゃついてきた」「どこに何を置けばいいか分からなくなった」と言ったとき、新しいプロジェクトの骨組みを決めるとき、既存の構造への違和感を漏らしたときは、「アーキテクチャ」という言葉が無くても必ずこのスキルを使う。個々のモジュールの深さやインターフェースの設計は codebase-design、用語の整理は domain-modeling に任せる。

- Skill: `sinnlosses/architecture-proposal` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add sinnlosses/architecture-proposal`
- Raw SKILL.md: https://api.skillmd.com/api/skills/sinnlosses/architecture-proposal/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: sinnlosses (https://skillmd.com/u/sinnlosses)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/sinnlosses/architecture-proposal

---


# アーキテクチャ提案

アプリの**性質**から出発して、それに合う**様式**（層の切り方）と**ディレクトリ構造**を提案書として書く。
流行や好みから様式を選ぶのではなく、「このアプリはこういう性質だから、この形が合う」という
筋道を残すことが目的。提案書は読んだ人がそのまま移行に着手できる粒度まで落とす。

**現状の様式が正しいことも多い。** その場合の提案は「様式は変えず、中の割り方や守り方を直す」に
なる。「新しい様式を選ぶ」ことがこのスキルの成果ではない。

## 出すもの / 出さないもの

**出す**: 提案書1つ（`references/proposal-template.md` の形）。性質の分析、候補の比較と選んだ理由、
目標のディレクトリ構造、許す依存の辺、現状との差分、移行の段階、採らなかった案、未決事項。

**出さない**: コードの移動・リネーム・書き換え。提案は読んだ人（ユーザー）が採否を決めるものであり、
提案書を書いた同じターンで適用まで進めると、判断の機会を奪う。適用はユーザーの指示で別に行う。

## 手順

### 1. 性質を読む

様式を決めるのは性質であって規模ではない。だから最初にコードとドキュメントから次の軸を読み取り、
**根拠となるファイルや行を添えて**メモする（根拠が無い性質は、後の手順で「聞く」対象になる）。

| 軸 | 見るもの | 何が決まるか |
| --- | --- | --- |
| 何を中心に回るか | エントリポイント、メインループ、リクエストの入口。**入力から出力までの流れを1本、手で追う** | 要求応答型か、イベント流入型か、常駐プロセスか、バッチか、ライブラリか。**中心の形が層の切り方をほぼ決める** |
| 外の世界との境界 | 子プロセス、ネットワーク、ファイル、環境変数、ホスト（端末・ブラウザ・IDE）への依存 | 境界の数と種類。多いほど「差し替え口を1箇所に集める」形（ポート／アダプタ）の価値が上がる |
| 状態の持ち方 | メモリ上のセッション、永続化、復元の要否 | 状態を持つ層をどこに閉じ込めるか |
| 実行環境の数 | サーバとブラウザ、CLI とデーモン、同一言語で複数の実行環境か | 「共有する契約」を独立した層にするかどうか |
| 変わりやすい場所 | git の変更頻度（下のコマンド）、TODO、ドキュメントの「未決事項」、残っているタスク | 変更が集中する場所を、他から切り離して薄い依存にする |
| 守られている制約 | 依存の向きを落とすテスト、lint の境界ルール、設計書の「採らなかった案」、`CONTEXT.md` / ADR | すでに決まっている辺を壊さない。既存の判断を尊重したうえで直す |
| 利用者と開発体制 | README、CLAUDE.md、対象ユーザーの記述、サブエージェントに委譲する運用か | 個人開発なら儀式（層の数・抽象の数）を減らす方向に倒す。委譲する体制ではディレクトリ名が指示書の代わりになる |
| テストできる範囲 | テストの配置、目視で確かめている領域 | 自動で守れる境界と目視でしか守れない境界を分けて設計する |

読む順番は、**ドキュメント（README・CLAUDE.md・`CONTEXT.md`・ADR・docs/ の要件と設計書）→
マニフェスト（依存とスクリプト）→ エントリポイント → ディレクトリ木 → 依存の辺 → 変更頻度**。
読む量が多いリポジトリでは、この手順だけを Explore 系のサブエージェントに任せて、表と根拠だけを
受け取ってよい（本体のコンテキストを読み込みで埋めないため）。

**依存の辺は感覚で語らず数える。** 同梱の `scripts/import_edges.py` が、ディレクトリ同士の import の
本数・外部パッケージへの依存・循環・ディレクトリごとのファイル数を出す（JS/TS 向け。他の言語は
正規表現を直して使う）:

```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/import_edges.py src --markdown           # 第1階層で集計（行数つき）
python3 ${CLAUDE_SKILL_DIR}/scripts/import_edges.py src --depth 2 --markdown # 領域の中まで
python3 ${CLAUDE_SKILL_DIR}/scripts/import_edges.py src --reach protocol     # protocol の各ファイルを誰が引くか
```

`--reach` は「共有する契約」の層に効く。両側から到達されないファイルは、その層に居る理由が弱い。

**変更頻度**は git から数える。上位に来たファイルが「変わりやすい場所」の根拠になる:

```bash
git log --since=<いまの構造になった日> --format= --name-only -- src | sort | uniq -c | sort -rn | head -20
```

`--since` を付けないと、移行で消えたファイルが上位を占めて役に立たない。

数字と並べて、**いま痛んでいる兆候**も拾う。性質の軸だけだと「何が合っていないか」が抜けやすい。

- 1つのことを理解するのに、小さなファイルを何個も跳ね回る
- 「ここだけが外に触る」という約束がコメントにしかなく、テストが落とさない
- 境界を差し替えられないので、テストが本物のプロセスやネットワークを要る
- 切り出された関数が、呼び出し元の複雑さを隠しているだけで減らしていない
- 同じ定数や経路名が2箇所以上に書かれている
- 新しいものを置く場所が、規約を読まないと決められない
- 正典どうしで層の定義が食い違う、または同じ種類のファイルが層を行き来している（置き場所の基準が
  1つでない証拠。**これがいちばん効く発見になりやすい**）

性質の読み取りが甘いと、後の候補がすべて空回りする。**手順1に全体の半分の時間をかけてよい。**

### 2. 足りないところだけ聞く

読んで分からなかった性質のうち、**答えによって提案が材料から変わるもの**だけを聞く。
「どの様式が好きか」は聞かない（それを決めるのがこのスキルの仕事）。
聞くべき例: 今後の実行環境が増える予定があるか、状態の永続化が視野に入っているか、
一番手を入れたい場所はどこか、守りたい既存の判断は何か。
逆に、コードから読み取れることを確認のために聞くのは、ユーザーの時間を奪うだけなのでしない。

無人で回している（質問に答える人がいない）ときは、聞かずに **仮定として提案書の「未決事項」に書き**、
仮定が外れたときに変わる箇所を明示して進める。

**既存のルールの解釈が割れるとき**（設計書の基準が2通りに読める、など）は、提案の本文では
**自分の読み方を1つ選んで進め**、「未決事項」に「別の読み方を採ると何が変わるか」を書く。
両方を本文に並べると、提案が決まらない。

### 3. 候補を2つ以上立てて選ぶ

`references/style-catalog.md` から、性質に合う様式を **2つ以上** 選んで並べる。1つしか出さないと、
その1つが正しいかを誰も検証できない。候補ごとに次を書く。

- その様式が**この性質のどこに**効くか（一般論ではなく、手順1の軸に対応づけて）
- **合わない点**と、それをどう補うか
- その様式が要求するディレクトリの形（ざっくり）
- **確度**: `固い`（性質の表から直接出る）/ `試す価値あり`（合いそうだが根拠が一部推測）/
  `推測`（聞けなかった性質に依存する）。読む側が「どこまで信じてよいか」を見分けるため

**現状の様式が性質に合っているなら、それを土台として固定し、候補は「土台の中の割り方」で
立てる**（例: 「共有契約 + クライアント/サーバ分割」は動かさず、サーバ側の中を「検査だけ足す」
「核と境界に割る」「概念で縦切り」で比べる）。「現状維持 + 検査だけ」はたいてい有力な候補で、
選ばれなくても移行の第1段階になる。

そのうえで1つ選び、**選ばなかった候補を捨てた理由**を残す。将来「なぜこの形なのか」を問われたとき、
採らなかった案が書いてあると答えになる。候補を並べる際の考え方は
`codebase-design` スキルの `DESIGN-IT-TWICE.md` と同じ。

規模が小さいアプリに多層の様式を当てると、層をまたぐ配線だけが増えて振る舞いは増えない。
**層の数は、境界の数と実行環境の数から逆算する**。逆算の根拠が書けていれば層が増えてもよい。
**根拠なしに**4層以上になっていたら疑う。

### 4. ディレクトリ構造を書く

目標の木を、ディレクトリごとに **「何が住むか」と「何を置いてはいけないか」を1行ずつ** 添えて書く。
置いてはいけないものを書かないと、境界が半年で溶ける。

- **名前は概念**にする。`helpers` / `utils` / `common` / `misc` のような「置き場所」を名前にしたディレクトリは
  作らない（そこに何でも入るようになり、依存の向きが読めなくなる）
- 単数か複数か、階層の深さは、**そのリポジトリの既存の慣習**に合わせる。慣習が無ければ提案書で決めて理由を書く
- 用語集（glossary / `CONTEXT.md`）があるリポジトリでは、ディレクトリ名もそこの識別子に合わせる。
  新しい言葉が要るなら、**用語集に足す項目の文面案（1〜2行）を提案書に書く**。「足す」とだけ書くと、
  採用時に言葉の定義をもう一度考えることになる
- **許す依存の辺を明示する**（A → B は可、B → A は不可）。すでに依存を落とすテストがあれば、
  その一覧をどう変えるかまで書く。無ければ、そのテストを足す段階を移行に入れる
- テストの置き場所（同居か `test/` か、境界のテストはどこか）も木に含める
- 言葉より図が速く伝わるとき（辺が5本以上、向きが変わる）は、現状と目標の依存図を並べて添える。
  図は任意で、表があれば省いてよい

### 5. 差分と移行の段階を書く

現状の木と目標の木を並べ、**どこが動くか**をファイル単位で書く。そのうえで移行を段階に切る。

- 各段階は **単独でチェック（型検査・lint・テスト）が通る**ようにする。途中で壊れた状態を長く持たない
- 最初の段階は「境界を守るテストを足す」か「1つの層を切り出す」のどちらか小さいほうにする。
  ファイルを動かさない段階が先にあると、そこで止めても価値が残る
- 動かさないものを明記する（すべてを動かす提案は、たいてい性質を読めていない）
- 段階ごとに「終わったと分かる証拠」を1行書く
- 段階にも確度を付ける。後ろの段階ほど「推測」になりやすく、それ自体が正直な情報になる。
  1つの候補を複数の段階に割ったときは、候補の確度を引き継がず**段階ごとに付け直す**

### 6. 提案書を置く

提案書は `docs/architecture-proposal.md` に置く。ユーザーが場所を指定したらそれに従う。

**採用後の正典は `docs/architecture.md` で、提案書とは別ファイル。** このスキルは
`docs/architecture.md` を書かない。提案が採用されたとき正典へ反映するのは人の作業であり、
**既存の設計書（正典）を直接書き換えない。** 2回目以降の提案も `docs/architecture-proposal.md` を
差し替えるだけで、正典は動かさない。

`docs/` にファイルを足したら、索引 `docs/README.md` に1行足す（パスと一行説明）。
`docs/README.md` が無ければそのとき作る。**空の索引を先回りして作らない。**

```
- `docs/architecture-proposal.md` — 様式の候補比較と移行の段階（提案。採否は未定）
```

書き終えたら、提案書の冒頭に **結論を3行**（性質の要約・選んだ様式・最初の段階）で置き直す。
本文を読む前に採否を判断できるようにするため。

提案書を渡すときに、次の一手を1行添える: 選んだ候補を問い詰めたいなら `grilling`、
採用して段階を進めるなら移行の第1段階から。

## やりがちな失敗

- **性質の分析を飛ばして様式から入る**: 「クリーンアーキテクチャにしましょう」から始まる提案は、
  どの性質に効くのかが書けない。手順1に戻る
- **既存の判断を無視する**: 設計書に「採らなかった案」があるのに同じ案を提案する。読んでいない証拠になる。
  同じ案を出すなら「当時と何が変わったか」を書く
- **抽象を先に足す**: 実装が1つしかないものにインターフェースを切る提案。差し替えの予定が性質から
  読めるときだけ切る。ポートとアダプタの様式でも、実装が1つの境界は「置き場所」だけで表してよい
- **ディレクトリを増やして解決した気になる**: ファイルが2つしかない層。層は境界の数から逆算する
- **移行を1段階で書く**: 「全部動かす」は実行されない。小さく切る
- **提案と同時に適用する**: ユーザーの採否の機会を奪う。このスキルは書くところまで

## 他のスキルとの分担

| やること | スキル |
| --- | --- |
| アプリ全体の様式と木を決める（このスキル） | `architecture-proposal` |
| 決めた層の中で、モジュールの深さ・シームの置き場所を設計する | `codebase-design` |
| ディレクトリ名や層の名前を用語集と揃える、ADR に残す | `domain-modeling` |
| 提案書の選んだ候補を問い詰めて固める | `grilling` |
| 提案を実装したあと、規約と仕様に沿っているか見る | `code-review` |

提案書の中で個々のモジュールの内部設計に踏み込みそうになったら、そこは `codebase-design` の領分なので
「この層の中は別途設計する」と書いて止める。

