結果の読み方
数字をどう解釈するか、そして何を無視すべきか。
hotspot スコア
score = rank(変更頻度) × rank(複雑度)0〜1 の値で、両方が高いものだけが上位に来ます。
| 状況 | score | 解釈 |
|---|---|---|
| 頻繁に変更 × 複雑 | 高い | 投資対効果が最も高い。ここから手を付ける |
| 複雑だが誰も触らない | 0 | 直しても ROI はほぼゼロ。放置してよい |
| 頻繁に変更されるが単純 | 低い | 問題になっていない |
変更が一度もないファイルは必ず 0 になります
「複雑だが安定している」コードを提案しないためです。動いていて誰も触らないコードを綺麗にしても、得られるものはありません。
ランクであって絶対値ではない
score はリポジトリ内での相対順位です。「score 0.9 だから危険」ではなく「このリポジトリの中で上位 10% に入る」という意味です。リポジトリをまたいだ比較には使えません。
テストファイルが上位に来るのは正常
実データではテストファイルが hotspot 上位に多く現れます。これはバグではありません。テストのメンテナンスも実コストであり、頻繁に壊れて直されるテストは実際に問題です。
プロダクションコードだけを見たい場合は、結果を絞り込んでください。
change coupling の degree
degree(A,B) = 2·|A∩B| / (|A|+|B|)degree が低くても shared が多ければ重要です。 活発なパッケージ同士は分母(それぞれの総変更回数)が大きくなるため、degree は下がります。
| ペア | degree | 共変更 | 解釈 |
|---|---|---|---|
| A ↔ B | 26% | 90 回 | 既定閾値(30%)に届かないが、90 回一緒に変わっている事実は無視できない |
既定の閾値で出てこない場合は下げてください。
dowse coupling --hidden --min-degree 15隠れた結合の 2 つの顔
kind: "hidden" は「依存グラフに辺がないのに共変更している」ことしか意味しません。それが問題かどうかは中身次第です。実際の例を 2 つ挙げます。
問題があるケース: 重複コード
@acme/admin-web ↔ @acme/customer-web 33%, 91 回
src/lib/server-api.ts ↔ src/lib/server-api.ts 13 回
src/app/(authed)/page.tsx ↔ 同名ファイル 15 回同名のファイルが両方に存在し、同じ変更が手作業でコピーされていました。共通パッケージへの抽出候補です。
問題がないケース: 設計上のプロトコル
@acme/api-contract ↔ @acme/audit-event-names 25%, 49 回
openapi.json ↔ audit-event-names/src/index.ts 34 回「API を追加したら監査イベント名も追加する」という設計上妥当な規約でした。直す必要はありません。
必ず中身を確認してください
dowse why <a> <b> を実行せずに「結合しているから直すべき」と判断しないでください。この 2 つは数字の上では同じ「hidden coupling」です。
Code Health と LoC ベースライン
health の隣に必ず「LoC だけで決めた場合のスコア」が併記されます。
| ファイル | health | LoC ベースライン | 解釈 |
|---|---|---|---|
env-guard.ts | 4.9 | 10.0 | 短いが密。行数だけ見ると見落とす |
big-but-simple.ts | 8.0 | 8.0 | 差がない = health は実質「ファイルが大きい」と言っているだけ |
差が小さい場合、その health スコアはファイル長の言い換えでしかありません。「大きいファイルだ」以上の指摘をしないでください。
閾値はすべて仮説です
| 閾値 | 既定 | 出典 |
|---|---|---|
| cyclomatic 警告 | 10 | McCabe / ESLint |
| cognitive 警告 | 15 | SonarSource |
| coupling 最小結合度 | 30% | Code Maat |
| minor contributor | < 5% | Bird et al. |
いずれも文献に基づいていますが、あなたのリポジトリに合っている保証はありません。すべて設定で変更できます。現状を測ってから校正してください。
bus factor は人ではなくリスクの話
bus factor 1 は「この人がボトルネックだ」ではなく「このパッケージは知識が集中していて、担当者が抜けると保守できなくなる」という意味です。
個人の評価に使わないでください
開発者名を成績のように並べる用途は明確に非推奨です。これはチームが構造的リスクを把握するための指標です。Tornhill も同じ警告をしています。
また、bus factor の計算は .mailmap による同一人物の統合と bot 除外が前提です。同じ人が複数のメールアドレスを使っていると、bus factor を過大評価します(実際より安全に見えてしまう)。
除外されているもの
すべての実行で、除外した件数が表示されます。
excluded: 6 merge, 0 bot, 1 format-only, 0 ignore-revs (51 large changesets flagged)| 種類 | 理由 |
|---|---|
| merge コミット | 変更の実体を持たない |
| bot コミット | dependabot 等が ownership を歪める |
| format-only | 空白だけの変更が churn を膨らませる |
| ignore-revs | .git-blame-ignore-revs の記載を尊重 |
| 巨大 changeset(50 ファイル超) | tangled commit で偽の結合を生む(coupling のみ除外、churn には含む) |
また、生成コード(generated/、*.gen.ts)とロックファイルは既定で対象外です。