mcpField
G
golang-code-style

golang-code-style

github.com/samber開発3.7k44.6k 回インストール5 日前に更新
リポジトリ

golang-code-style について

golang-code-styleは、明瞭さと保守性を重視したGoコードの作成・レビュー向けスキルです。リンターだけでは判断しにくいスタイルを扱い、大規模なレビューを専門別のサブエージェントに分担できます。

主な機能

  1. 01読みやすいGoコードの指針
  2. 02宣言と制御フローのルール
  3. 03関数とファイル構成の指針
  4. 04型と文字列処理の助言
  5. 05コードスタイルの並行レビュー

活用シーン

  1. 01Goコードの明瞭さのレビュー
  2. 02コードベース全体でのスタイル統一
  3. 03大規模なスタイルレビューのサブエージェント分担

インストール

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

$npx skills add https://github.com/samber/cc-skills-golang --skill golang-code-style

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

同梱ファイルevals/evals.jsonreferences/details.md

詳細

オーケストレーションモード: 大規模なコードベース全体のコードスタイルをレビューする際は、「Parallelizing Code Style Reviews」セクションで説明されているサブエージェントを並列で実行し、それぞれ独立したスタイル上の懸念事項を担当させて、調査結果を統合します。Claude Code では、マルチエージェントオーケストレーションを明示的に有効にするために ultracode を使用してください。

コミュニティのデフォルト。 samber/cc-skills-golang@golang-code-style スキルを明示的に置き換える会社のスキルが優先されます。

Go コードスタイル

人間の判断が必要なスタイルルールを扱います。フォーマットはリンターが処理し、このスキルは明瞭さを扱います。命名については samber/cc-skills-golang@golang-naming スキルを、デザインパターンについては samber/cc-skills-golang@golang-design-patterns スキルを、構造体とインターフェースの設計については samber/cc-skills-golang@golang-structs-interfaces スキルを参照してください。

「明快さは巧妙さに勝ります。」— Go の格言

ルールに従わない場合は、コードにコメントを追加してください。

行の長さと改行

厳密な行の長さ制限はありませんが、約120文字を超える行は必ず分割してください。任意の文字数で分割するのではなく、意味のまとまりで分割してください。引数が4つ以上の関数呼び出しは、1行のコードを求めるプロンプトであっても、必ず引数ごとに1行を使用してください。

// Good — each argument on its own line, closing paren separate
mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
    handleUsers(
        w,
        r,
        serviceName,
        cfg,
        logger,
        authMiddleware,
    )
})

関数シグネチャが長すぎる場合、実際の解決策は、改行の工夫ではなく、オプション構造体を使うなどしてパラメーターを減らすことです。複数行のシグネチャでは、パラメーターごとに1行を使用してください。

変数宣言

ゼロ値以外の値には := を、ゼロ値で初期化する場合には var を使用することが望ましいです。この形式は意図を示します。var は「これはゼロ値から始まる」という意味です。

var count int              // zero value, set later
name := "default"          // non-zero, := is appropriate
var buf bytes.Buffer       // zero value is ready to use
スライスとマップの初期化

スライスとマップは必ず明示的に初期化し、nil のままにしてはいけません。nil マップへの書き込みはパニックを引き起こします。また、nil スライスは JSON で null にシリアライズされます(空のスライスは [] になります)。これは API の利用者を困惑させます。

users := []User{}                       // always initialized
m := map[string]int{}                   // always initialized
users := make([]User, 0, len(ids))      // preallocate when capacity is known
m := make(map[string]int, len(items))   // preallocate when size is known

推測で事前割り当てをしないでください。一般的なケースが10項目の場合、make([]T, 0, 1000) はメモリを無駄にします。

複合リテラル

複合リテラルでは必ずフィールド名を指定してください。フィールドの位置に依存すると、型にフィールドが追加されたり、順序が変更されたりしたときに壊れます。

srv := &http.Server{
    Addr:         ":8080",
    ReadTimeout:  5 * time.Second,
    WriteTimeout: 10 * time.Second,
}

制御フロー

ネストを減らす

エラーやエッジケースは必ず先に処理してください(早期リターン)。正常系のインデントは最小限に抑えてください。

func process(data []byte) (*Result, error) {
    if len(data) == 0 {
        return nil, errors.New("empty data")
    }

    parsed, err := parse(data)
    if err != nil {
        return nil, fmt.Errorf("parsing: %w", err)
    }

    return transform(parsed), nil
}
不要な else をなくす

if の本体が return/break/continue で終わる場合、else は必ず省略してください。単純な代入では、デフォルト値を設定してから上書きしてください。デフォルト値を代入し、その後、独立した条件や switch で上書きします。

// Good — default-then-override with switch (cleanest for mutually exclusive overrides)
level := slog.LevelInfo
switch {
case debug:
    level = slog.LevelDebug
case verbose:
    level = slog.LevelWarn
}

// Bad — else-if chain hides that there's a default
if debug {
    level = slog.LevelDebug
} else if verbose {
    level = slog.LevelWarn
} else {
    level = slog.LevelInfo
}
複雑な条件式と初期化スコープ

if 条件に3つ以上のオペランドがある場合は、必ず名前付きブール値に切り出してください。|| が並ぶ条件式は読みにくく、ビジネスロジックを見えにくくします。短絡評価による利点がある場合は、コストの高いチェックをインラインに保ってください。詳細

// Good — named booleans make intent clear
isAdmin := user.Role == RoleAdmin
isOwner := resource.OwnerID == user.ID
isPublicVerified := resource.IsPublic && user.IsVerified
if isAdmin || isOwner || isPublicVerified || permissions.Contains(PermOverride) {
    allow()
}

チェックにしか使わない変数は、if ブロック内でスコープを限定してください。

if err := validate(input); err != nil {
    return err
}
if-else チェーンより switch

同じ変数を複数回比較する場合は、switch を優先してください。

switch status {
case StatusActive:
    activate()
case StatusInactive:
    deactivate()
default:
    panic(fmt.Sprintf("unexpected status: %d", status))
}

関数の設計

  • 関数は短く、目的を絞ることが望ましいです。1つの関数が担う役割は1つにします。
  • 関数のパラメーターは4つ以下が望ましいです。それ以上になる場合は、オプション構造体を使用してください(samber/cc-skills-golang@golang-design-patterns スキルを参照)。
  • パラメーターの順序:最初に context.Context、次に入力、その後に出力先を指定します。
  • 名前なしの戻り値は、戻り値が明らかな1~3行の非常に短い関数では役立ちます。しかし、何が返されるのかを確認するためにスクロールが必要な場合は分かりにくくなるため、長い関数では戻り値に明示的な名前を付けてください。
func FetchUser(ctx context.Context, id string) (*User, error)
func SendEmail(ctx context.Context, msg EmailMessage) error  // grouped into struct
反復には range を優先する

インデックスベースのループよりも range を使用することが望ましいです。単純な回数カウントには range n(Go 1.22以降)を使用してください。

for _, user := range users {
    process(user)
}

値渡しとポインター渡し

小さな型(string、int、bool、time.Time)は値渡しにしてください。変更を加える場合、大きな構造体(約128バイト以上)を扱う場合、または nil に意味がある場合はポインターを使用してください。詳細

ファイル内のコード構成

  • 関連する宣言をまとめる:型、コンストラクター、メソッドをまとめます
  • 順序:パッケージのドキュメント、インポート、定数、型、コンストラクター、メソッド、ヘルパー
  • 重要なメソッドを持つ場合は、1 ファイルにつき主要な型を 1 つにします
  • ブランクインポート(_ "pkg")は、副作用(init 関数)を登録します。これを main とテストのパッケージに限定すると、副作用がライブラリーコードに隠れず、アプリケーションのルートで確認できます
  • ドットインポートは名前空間を汚染し、名前の出どころを判別できなくするため、ライブラリーコードでは決して使いません
  • 積極的に非公開にする — 必要になればいつでも公開できますが、公開済みの名前を非公開にする変更は破壊的変更です。→ 安全に非公開にする方法については、samber/cc-skills-golang@golang-gopls スキルを参照してください。このスキルでは、名前の変更によってすべての呼び出し箇所を一括更新します。また、メソッド名を小文字にしたときにインターフェースの実装が崩れる場合は変更を拒否します。このような破壊は、grep/sed では気付かないままリリースされます。

文字列の処理

単純な変換には strconv(より高速)を、複雑な書式設定には fmt.Sprintf を使います。エラーメッセージでは %q を使い、文字列の境界を明確にします。ループでは strings.Builder を、単純な連結では + を使います。

型変換

明示的で範囲の狭い変換を優先します。具体的な型を使える場合は、any よりジェネリクスを使います。

func Contains[T comparable](slice []T, target T) bool  // not []any

基本方針

  • 「少しコピーする方が、少し依存するよりよい」
  • 標準パッケージの slices と maps を使います。フィルター、グループ化、チャンク分割には github.com/samber/lo を使います
  • 「リフレクションは決して明快ではありません」 — 必要な場合を除き、reflect は避けます
  • 早まって抽象化しない — パターンが安定してから切り出します
  • 公開範囲を最小限にする — 公開する名前はすべて、維持する責任を伴います

コードスタイルレビューの並列化

大規模なコードベースでコードスタイルをレビューする際は、最大 5 つの並列サブエージェントを使い、それぞれが独立したスタイル上の観点(制御フロー、関数設計、変数宣言、文字列処理、コード構成など)を担当するようにします。

リンターで適用する

多くのルールは gofmt、gofumpt、goimports、gocritic、revive、wsl_v5 によって自動的に適用されます。→ samber/cc-skills-golang@golang-lint スキルを参照してください。

相互参照

  • → 識別子の命名規則については、samber/cc-skills-golang@golang-naming スキルを参照してください
  • → ポインターレシーバーと値レシーバー、インターフェース設計については、samber/cc-skills-golang@golang-structs-interfaces スキルを参照してください
  • → 関数オプション、ビルダー、コンストラクターについては、samber/cc-skills-golang@golang-design-patterns スキルを参照してください
  • → 自動フォーマットの適用については、samber/cc-skills-golang@golang-lint スキルを参照してください
  • → これらのガイドラインを使った、CI での AI 主導コードレビューの自動化については、samber/cc-skills-golang@golang-continuous-integration スキルを参照してください
  • → レビューで違反が大規模に見つかった場合に、多数の呼び出し箇所にわたってガード節への変換、関数の切り出し、オプション構造体への移行を安全に機械的に適用する方法については、samber/cc-skills-golang@golang-refactoring スキルを参照してください

コメント