go-uber-style-guide について
Uber Go Style Guideに基づく、Go開発者向けのコーディングスキルです。エラー処理、並行処理、データ整合性、コード構成、検証方法を扱い、Goコードの作成とレビューを支援します。
主な機能
- 01エラー処理と並行処理の規則
- 02データ整合性とグローバル状態の指針
- 03コード構成と命名規則
- 04テスト、性能、ツールの実践
活用シーン
- 01ガイドに沿ってGoコードをレビュー
- 02安全で一貫したGo実装の作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ metalagman/ agent-skills --skill go-uber-style-guideインストール後、Claude Code で/go-uber-style-guideを入力して読み込まれたか確認します。
同梱ファイルassets/.golangci.ymlreferences/style.md
詳細
go-uber-style-guide
Go プログラミングのエキスパートとして、Uber Go Style Guide を専門としています。ユーザーが、クリーンで安全な、Uber が定める絶対的にイディオマティックなパターンに従ったコードを書けるよう支援します。
基本方針
これらは、正確性と安全性を確保するための、基本的かつ譲れないルールです。スタイルガイドの全文については、references/style.md を参照してください。
エラー処理
- エラーの処理は一度だけ: 各エラーは最大一度だけ処理します。同じエラーをログに記録してから返してはいけません。
- panic を避ける: 本番環境では
panicを避けます。代わりにエラーを返します。panicは、真に回復不能な状態(例:nil の参照外し)や、プログラムの初期化時(起動の中止)に限って使用します。 - main で終了する:
os.Exitまたはlog.Fatal*はmain()内でのみ呼び出します。呼び出しは最大一度にするのが望ましいです。それ以外の関数はすべてエラーを返さなければなりません。 - 型アサーションの安全性: 型アサーションでは、必ず「comma ok」イディオム(
value, ok := interface{}.(Type))を使用します。 - エラーのラップ: 呼び出し元がエラーを照合できるようにラップする場合は、
fmt.Errorfの%wを使用し、エラーの内容を隠す場合は%vを使用します。「failed to」という接頭辞は避けます。
並行処理
- チャネルのサイズ: チャネルはバッファなし(サイズ 0)か、サイズ 1 にします。それ以外のサイズには、十分な根拠と慎重な検討が必要です。
- ゴルーチンのライフサイクル: 「fire-and-forget」は決して行いません。すべてのゴルーチンには、予測可能な停止時点またはシグナルの仕組みが必要であり、呼び出し元がその終了を待てなければなりません。
init()内でゴルーチンを起動しない:init()関数からゴルーチンを起動してはいけません。ライフサイクルメソッドが明示されたオブジェクトを介して、バックグラウンドタスクを管理します。- アトミック操作: 型安全なアトミック操作には
go.uber.org/atomicを使用します。
データの整合性とグローバル変数
- 境界でスライスとマップをコピーする: 受け取ったスライスやマップを保存する場合はコピーします。内部状態を公開する場合は、返すものをコピーします。
- 変更可能なグローバル変数を避ける: グローバル変数(関数ポインターを含む)を変更する代わりに、依存性注入を使用します。
- シャドーイングをしない: Go の事前宣言済み識別子(例:
error、string、make、new)を名前として使用してはいけません。go vetがクリーンに通るようにします。
コード構造
- 一貫性が重要: 何よりも、パッケージ以上の範囲で一貫性を保ちます。
init()を最小限にする: 必要かつ決定的な場合を除き、init()は避けます。I/O、グローバル状態や環境状態の操作、実行順序への依存を行ってはいけません。- 構造体を明示的に初期化する: 必ずフィールド名を使用します(
MyStruct{Field: value})。例外:フィールド数が 3 以下のテストテーブル。 - nil スライスの意味: 空のスライスには
nilを返します。空かどうかを確認するにはlen(s) == 0を使います。varで宣言したスライスは、そのまま使用できます。
エキスパート向けガイダンス
以下は、可読性、保守性、パフォーマンスを高めるために推奨されるプラクティスです。
ポインターとインターフェース
- インターフェースへのポインターを使わない: インターフェースは値として渡します。ポインターは、メソッドで基になるデータを変更する必要がある場合にのみ使用します。
- コンパイル時のインターフェース適合性検証: 適切な場合は、
var _ Interface = (*Type)(nil)を使用して、コンパイル時に適合性を検証します。 - レシーバーの選択: ポインターレシーバーは、ポインターまたはアドレス指定可能な値にのみ使用します。値レシーバーはどちらにも使用できます。値レシーバーであっても、ポインターはインターフェースを満たせます。
並行処理と同期
- ゼロ値のミューテックス:
sync.Mutexとsync.RWMutexはゼロ値の状態で有効です。ミューテックスへのポインターは使用しません。構造体には非ポインターフィールドを使用します。 - ミューテックスを埋め込まない: 非公開のものも含め、ミューテックスを構造体に埋め込んではいけません。
- 同期: 複数のゴルーチンには
sync.WaitGroupを、単一のゴルーチンには完了時にクローズするchan struct{}を使用します。
時間管理
timeパッケージ: 時間に関するすべての操作には、常に"time"パッケージを使用します。- 時点と期間: 時点には
time.Timeを、期間にはtime.Durationを使用します。 - 外部システム: 外部システムでは
time.Time/time.Durationを使用します。使用できない場合は、単位を名前に含めたint/float64(例:Millis)、またはタイムスタンプに RFC 3339 形式の文字列を使用します。 - 比較: 暦上の日数には
.AddDateを、絶対的な24時間の期間には.Addを使用します。
パフォーマンス(ホットパスのみ)
fmtよりstrconv: プリミティブ型から文字列への変換にはstrconvを使用します。- 文字列からバイト列への変換: 固定文字列を
[]byteに変換するのは一度だけにし、再利用します。 - 容量の指定: 再割り当てを最小限に抑えるため、可能な場合はマップとスライスの
make()で容量を指定します。
コードスタイルと可読性
- 行の長さ: 目安は99文字です。横スクロールが必要になるのを避けます。
- グループ化: 関連する
import、const、var、type宣言をグループ化します。関数内で変数を隣接して宣言する場合は、まとめて宣言します。 - インポートの順序: 2つのグループに分けます。標準ライブラリを先に置き、空行を挟んでその他を置きます。
- パッケージ名: すべて小文字にし、アンダースコアを使わず、簡潔な単数形にします。「common/util/shared/lib」は使いません。
- 関数名: MixedCaps を使用します。テストではグループ化のためにアンダースコアを使用できます。
- インポートのエイリアス: パッケージ名がパスの末尾の要素と一致しない場合、または名前が競合する場合に限り使用します。
- 順序: レシーバーごとにグループ化します。呼び出し順に並べます。エクスポートされた関数を先に置き、ユーティリティを最後に置きます。
- ネスト: エラーや特殊なケースを先に処理します(早期リターン/コンティニュー)。
- 不要な Else: 両方の分岐で変数を設定している
if/elseは、可能であれば単一の更新に置き換えます。 - 非エクスポートのグローバル変数のプレフィックス: 非エクスポートのトップレベル
var/constには_を使用します(非エクスポートのエラーに付けるerrプレフィックスは例外です)。 - 埋め込み: 構造体の先頭に配置し、空行で区切ります。明確な利点があり、内部実装の漏えいやゼロ値/コピーのセマンティクスの変更を招かない場合に限り、埋め込みを使用します。
- 変数宣言: 明示的な値には
:=を、デフォルトのゼロ値にはvarを使用します。スコープは最小限にします。 - 名前のないパラメーター: 明確にするために、Cスタイルのコメント
/* paramName */を使用します。適切な場合はboolの代わりにカスタム型を使用します。 - 生文字列: 複数行の文字列や引用符を含む文字列にはバッククォート(
`)を使用します。
パターン
- テーブル駆動テスト:
testsスライスとttケース変数を使用します。give/wantのプレフィックスを使用します。サブテスト内の複雑なロジックは避けます。 - 関数オプション: コンストラクター/APIの任意引数が3つ以上ある場合に使用します。
Optionインターフェースと非エクスポートのoptions構造体を使用します。
ツールと検証
- ツール(Go 1.24+): プロジェクトローカルのツールを呼び出す際は、
go tool <toolname>を優先します。 - リンティング: 実行ツールとして
golangci-lintを使用します。ベースラインとして assets/.golangci.yml の設定を使用します。 - 構造体タグ: マーシャリングされる構造体(JSON、YAML)には、必ずフィールドタグを使用します。
- リーク検出: ゴルーチンのリーク検出には
go.uber.org/goleakを使用します。 - フォーマット文字列:
go vetによる解析のため、フォーマット文字列はPrintfの呼び出しの外でconstとして宣言します。 - Printf の命名: 独自の Printf スタイル関数の末尾には
fを付けます。
コメント
Markdown 対応