Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go のフラットな パッケージに 「ファイル単位の private」を 〜Linter “de...

Avatar for mpyw mpyw
September 17, 2026

Go のフラットな パッケージに 「ファイル単位の private」を 〜Linter “declscope” を作った話〜

https://zenn.dev/yumemi_inc/articles/go-declscope-file-scoped-private のスライド版です。 AI に書かせました。

Avatar for mpyw

mpyw

September 17, 2026

More Decks by mpyw

Other Decks in Programming

Transcript

  1. Go のフラットな パッケージに 「ファイル単位の private」を GO × STATIC ANALYSIS ×

    AI Linter “declscope” を作った話 🔒 mpyw / Accenture Japan Ltd 2026 01 / 14
  2. THE GAP Go の可視性は、ほぼ 2 段階 レベル Exported unexported file

    単位 unexported ≠ このファイルだけ 届く範囲 import した全 package 同じ package の全 file ない package database user_repository.go order_repository.go scanUser scanOrder normalizeEmail listOrders 02 / 14
  3. TRADE-OFF だからといって、package を割れば 終わりでもない 単一 フラットに保つ 依存は素直。ただし package 内の全宣言が互いに見える。 複数

    細かく分ける 循環参照 共有名の export internal/ の階層 境界を動かすコスト 欲しいのは package 分割ではなく、その内側にある軽い境界 03 / 14
  4. INVISIBLE OWNERSHIP 暗黙の所有権は、コードから見えない package database user_repository.go order_repository.go func scanUser(...) {

    ... } func scanOrder(...) { func normalizeEmail(...) { ... } email = normalizeEmail(email) } コンパイルは通る 「この helper は、この file のもの」—— コンパイラは知らない 04 / 14
  5. AGENTIC CODING AI は規約を破るというより、 見える API を使う 規約を書く CLAUDE.md コメント

    レビュー文化 → 見えるものを使う helper を呼ぶ field を書く compile は成功 負債も高速化 曖昧な境界も速く → 生成が速いぶん、 崩れる 自然言語の規約は効く。でも、守られたかの判定は確率的 05 / 14
  6. WHAT DECLSCOPE GUARDS declscope が守るのは、2 種類の境界 boundary qualify この file

    から、あの宣言に 触ってよいか? シンボルに namespace を含めて 識別性を確保しているか? orderRepository → normalizeEmail in userRepository 既定で ON boundary は利用関係、qualify は名前と置き場所を検査する。 B scan → 誰の? scanUser → user のもの 既定は OFF・ON 推奨 Q 06 / 14
  7. ONLY TWO CONCEPTS 覚えることは 2 つだけ 01 file 名が namespace

    user_repository.go ↓ userRepository 02 scope は 2 種類 private package 自分の namespace package 内のどこでも public は Go の Exported がすでに担当。 07 / 14
  8. BOUNDARY RULE boundary 違反への答えは、必ず 2 つ A B 境界を守る 使用箇所や宣言を同一

    namespace に移す。 move usage move declaration email.go OR 共有を宣言する //declscope:package func normalizeEmail(s string) string に移し、共有物だという判断をソースへ残す 08 / 14
  9. SHARED NAMESPACE 複数 file で 1 つの関心なら、束ねられる namespace: statement //declscope:namespace

    statement package database func (s *Statement) Where(...) { ... } statement.go query.go type Statement func (*Statement) wheres []string Where(...) args []any 物理 file を出発点にしつつ、実際の関心範囲へ合わせられる。 09 / 14
  10. QUALIFY RULE qualify は「名前を長くしろ」ではない scanUser 機械提案どおり rename? 自動修正提案では namespace がプレフィクスになる。でも、

    名前が不自然。 → userRepositoryScanUser namespace のほうを見直す //declscope:namespace user scanUser が自然に収まる。 問われているのは、その名前と置き場所が噛み合っているか 10 / 14
  11. CASE STUDY: SPF13/COBRA 最も古い file だけ、リネームを忘れていた ほかの completion generators genZshComp

    genFishComp genPowerShellComp genBashComp // V2 どれも、自分の shell 名を名乗っている。 古い bash_completions.go gen writeFlag writeCommands → → → genBashCommands writeBashFlag writeBashCommands Bash の名前がなかった。リネームで namespace を明示。 「 scan は 1 つしか置けない」が、実在 OSS でも起きていた。 spf13/cobra: 14 files / 6,138 lines、開始時 boundary 35 / qualify 119 → 最終 0 / 0 11 / 14
  12. DURABLE INTENT AI 時代に欲しいのは、判断が残ること 👤 人間 診断 何の境界を越えたか → source

    code //declscope:package //declscope:namespace user 診断・ディレクティブ・導入 skill directive 何を共有してよいか → 🤖 次の agent skill 安全な導入順序 12 / 14
  13. TAKEAWAYS フラットさを保ったまま、 内側の境界を検査する ✓ Go には file 単位の private がない

    ✓ 暗黙の所有は、人にも AI にも見えにくい ✓ declscope は越境を決定論的に検査する ✓ 答えは「守る」か「共有を宣言する」 ✓ directive が設計判断の引き継ぎになる github.com/mpyw/declscope 使ってみた感想・Issue、お待ちしています。 13 / 14