mcpField
G
go-coding-standards

go-coding-standards

github.com/eduardo-sl開発83201 回インストール2 週間前に更新
リポジトリ

go-coding-standards について

go-coding-standardsは、Go開発者やコーディングエージェント向けの開発スキルです。慣用的な規約とコード品質チェックを扱い、ファイル構成、レシーバー、タグの詳細資料も用意しています。

主な機能

  1. 01インポートの分類と命名規則
  2. 02変数と構造体の初期化指針
  3. 03ネスト、順序、行長の規約
  4. 04レシーバー、時間、構造体タグの指針
  5. 05goimports、go vet、staticcheckによるチェック

活用シーン

  1. 01Goの慣用規約に沿ったコードレビュー
  2. 02宣言と構造体フィールドの整理
  3. 03コード完成前の品質チェック

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/eduardo-sl/go-agent-skills --skill go-coding-standards

インストール後、Claude Code で/go-coding-standardsを入力して読み込まれたか確認します。

同梱ファイルreferences/file-organization.mdreferences/receivers-and-tags.md

詳細

Go コーディング規約

Effective Go、Go Code Review Comments、および本番環境で実証された慣用表現に基づく、Go の慣用的な規約です。 すべてのコードは、エラーなしで goimports、go vet、staticcheck(または golangci-lint run)を通過しなければなりません。

コミュニティのデフォルトです。プロジェクトのスキルまたはエージェント設定ルールが go-coding-standards を明示的に上書きする場合は、そちらが優先されます。

詳細な参考資料は必要に応じて読み込みます。

  • references/file-organization.md — 宣言のグループ化、ファイル内の順序、 長いシグネチャの分割。
  • references/receivers-and-tags.md — レシーバーの一貫性と構造体タグの 例。

以下の概要だけでは不十分な場合に限り、参考ファイルを読んでください。

1. インポートの順序

インポートは空行で区切り、次の順序でグループ化します。

import (
    // 1. Standard library
    "context"
    "fmt"
    "log/slog"
    "net/http"

    // 2. External packages
    "github.com/gorilla/mux"

    // 3. Internal/project packages
    "github.com/myorg/myproject/internal/service"
)

ドットインポートは絶対に使用しないでください。エイリアスは名前の競合を解決する場合に限り使用してください。

2. 命名

命名は go-naming スキルに従います。対象はパッケージ名、名前の重複、頭字語、ゲッター、レシーバー、エラー名、テスト名です。宣言に関する次の 2 つのルールは、ここに記載します。事前宣言された識別子(len、new、error、min、max)をシャドーイングしないでください。また、コードベースでその規約を使用している場合、非公開のパッケージレベル変数には _defaultTimeout のように _ 接頭辞を付けてもかまいません。

3. 変数宣言

トップレベル

トップレベルの宣言には var を使用します。式と型が一致する場合、型は指定しないでください。

// ✅ Good
var _defaultPort = 8080
var _logger = slog.Default()

// ❌ Bad — redundant type
var _defaultPort int = 8080
ローカル
  • ローカル変数には := を優先して使用します。
  • ゼロ値での初期化に意図があり、意味を持つ場合に限り var を使用します。
// ✅ Good — zero value is meaningful
var buf bytes.Buffer

// ✅ Good — short declaration
name := getUserName()

4. 構造体の初期化

フィールド名を必ず使用し、意味を持つ場合を除いてゼロ値のフィールドは省略します。位置指定リテラルは、フィールドの追加や並べ替えによって気付かないうちに壊れるためです。

// ✅ Good
user := User{Name: "Alice", Email: "[email protected]"}

// ❌ Bad — positional
user := User{"Alice", "[email protected]", 0}

5. ネストを減らす

エラーや特殊なケースを最初に処理して早期リターンし、正常系の処理が左端から始まるようにします。if がすでにリターンする場合は else を省略し、デフォルト値を代入してから上書きする方法を優先してください。

// ✅ Good — guard clauses; no else
for _, v := range data {
    if !v.IsValid() {
        continue
    }
    if err := v.Process(); err != nil {
        return fmt.Errorf("process %s: %w", v.ID, err)
    }
}

a := 10 // default, then override
if condition {
    a = 20
}

6. グループ化と順序

  • 関連する const と var の宣言は、1 つの括弧付きブロックにまとめます。
  • ファイル内の順序は、定数と変数、コンストラクター、公開メソッド(アルファベット順ではなく重要度順)、非公開メソッド、ヘルパーとします。
  • メソッドは、それが属する型のすぐ後に配置します。

7. 行の長さ

目安は 99 文字です。長いシグネチャはパラメーターごとに改行し、閉じ括弧は独立した行に置きます。例: references/file-organization.md。

8. defer の使用

クリーンアップには defer を使用します。リソースを取得した時点で意図が明確になります。

mu.Lock()
defer mu.Unlock()

f, err := os.Open(path)
if err != nil {
    return fmt.Errorf("open %s: %w", path, err)
}
defer f.Close() // read-only; check Close errors on files you write

9. 列挙型

ゼロ値は明示的な Unknown センチネル用に確保します。これにより、設定されていない値が実際の状態として扱われるのを防げます。

type Status int

const (
    StatusUnknown Status = iota
    StatusActive
    StatusInactive
)

10. time パッケージを適切に使用する

  • 期間には生の整数ではなく、time.Duration を使用します。
  • 時点には time.Time を使用します。time.Now().Sub(start) ではなく time.Since(start) を使用します。
  • 形式上 time.Duration を保持できない場合(JSON、YAML)は、フィールド名に単位を含めます。例:TimeoutSeconds int。変換は境界部分で行います。
// ✅ Good
func poll(interval time.Duration) { ... }
poll(10 * time.Second)

// ❌ Bad
func poll(intervalSecs int) { ... }
poll(10)

11. レシーバー

型ごとにレシーバーの種類を 1 つ選び、すべてのメソッドで統一してください。メソッドセットは値の保持方法によって変わるため、混在させないでください。メソッドが値を変更する場合、構造体が sync.Mutex などコピー不可のフィールドを持つ場合、構造体が大きい場合、または別のメソッドでポインタが必要な場合は、ポインタレシーバーを使用します。小さく不変の型には値レシーバーを使用します。レシーバー名は型名に基づく 1 文字または 2 文字(s *Server)とし、すべてのメソッドで統一してください。this や self は使用しないでください。例:references/receivers-and-tags.md。

12. 構造体タグ

コンパイラーはタグをチェックしないため、誤字があっても気づきません。

  • シリアライズ境界を越える型のすべてのフィールドに、名前がすでに一致していてもタグを付けます。
  • プロセスの外に絶対に出してはならないものには json:"-" を付けます。非公開フィールドは何も通知されずにスキップされるため、見落としのように見えてしまいます。
  • omitempty では「未設定」と「ゼロ値」を区別できません。その区別が重要な場合は、ポインターまたはラッパーを使います。omitempty は構造体を省略しません。time.Time のようなフィールドには、Go のゼロ値と IsZero() を尊重する omitzero(Go 1.24 以降)を使います。
  • go vet を実行します。structtag チェックで不正なタグを検出できます。

13. 関数の構成

  • オペランドが3つ以上ある条件では、各要素に名前(isOwner、isAdmin)を付け、if がビジネスルールとして読めるようにします。
  • 最初に ctx context.Context、次に入力、最後にオプションを置きます。
  • 引数が4つを超える場合、または同じ型の引数が複数並ぶ場合は、オプション構造体か関数オプションを使います。どちらも go-design-patterns スキルが担当します。
  • 名前なし戻り値は、すべての戻り値を一目で確認できる短い関数でのみ使います。

検証チェックリスト

コードを完成と見なす前に、次を確認します。

  1. goimports がエラーなく実行される
  2. go vet ./... が成功する
  3. golangci-lint run が成功する(設定されている場合)
  4. 組み込み識別子をシャドーイングしていない
  5. すべてのインポートが適切にグループ化され、順序付けられている
  6. 構造体の初期化でフィールド名を使用している
  7. 不要なネストや else ブロックがない
  8. 型のすべてのメソッドでレシーバーの種類が一貫している
  9. シリアライズされる構造体フィールドすべてに明示的なタグが付いている

コメント