awesome-copilot/instructions/go.instructions_ja.md

12 KiB
Raw Blame History

description applyTo
慣用的なGoプラクティスとコミュニティ標準に従ったGoコード記述の指針 **/*.go,**/go.mod,**/go.sum

Go開発指針

Goコードを書く際は慣用的なGoプラクティスとコミュニティ標準に従ってください。これらの指針はEffective GoGo Code Review CommentsGoogleのGoスタイルガイドに基づいています。

全般指針

  • シンプルで明確、慣用的なGoコードを記述
  • 巧妙さよりも明確性とシンプルさを優先
  • 最小驚きの原則に従う
  • ハッピーパスを左寄せにする(インデントを最小化)
  • ネストを減らすため早期リターンを使用
  • ゼロ値を有用にする
  • エクスポートされた型、関数、メソッド、パッケージを文書化
  • 依存関係管理にはGoモジュールを使用

命名規則

パッケージ

  • 小文字の単語でパッケージ名を使用
  • アンダースコア、ハイフン、mixedCapsを避ける
  • パッケージが何を含むかではなく、何を提供するかを説明する名前を選択
  • utilcommonbaseなどの汎用的な名前を避ける
  • パッケージ名は複数形ではなく単数形にする

変数と関数

  • アンダースコアではなくmixedCapsまたはMixedCapscamelCaseを使用
  • 短いが説明的な名前を維持
  • 単文字変数は非常に短いスコープ(ループインデックスなど)でのみ使用
  • エクスポートされた名前は大文字で始まる
  • エクスポートされていない名前は小文字で始まる
  • 重複を避ける(例:http.HTTPServerを避け、http.Serverを使用)

インターフェース

  • 可能な場合はインターフェース名に-er接尾辞を使用ReaderWriterFormatter
  • 単一メソッドインターフェースはメソッド名で命名(例:ReadReader
  • インターフェースは小さく焦点を絞って維持

定数

  • エクスポートされた定数にはMixedCapsを使用
  • エクスポートされていない定数にはmixedCapsを使用
  • 関連する定数はconstブロックでグループ化
  • より良い型安全性のため型付き定数を検討

コードスタイルとフォーマット

フォーマット

  • コードのフォーマットには常にgofmtを使用
  • インポートの自動管理にはgoimportsを使用
  • 行の長さを適度に保つ(厳格な制限はないが、可読性を考慮)
  • 論理的なコードグループを分離するため空行を追加

コメント

  • 完全な文でコメントを記述
  • 説明される対象の名前で文を開始
  • パッケージコメントは「Package [name]」で開始
  • ほとんどのコメントには行コメント(//)を使用
  • ブロックコメント(/* */)は控えめに使用、主にパッケージ文書化用
  • 何をするかではなく、なぜするかを文書化(何が複雑でない限り)

エラーハンドリング

  • 関数呼び出しの直後にエラーをチェック
  • 良い理由がない限り_を使ってエラーを無視しない(理由を文書化)
  • fmt.Errorf%w動詞を使用してコンテキストでエラーをラップ
  • 特定のエラーをチェックする必要がある場合はカスタムエラー型を作成
  • エラー戻り値を最後の戻り値として配置
  • エラー変数はerrと命名
  • エラーメッセージは小文字で、句読点で終わらない

アーキテクチャとプロジェクト構造

パッケージ構成

  • 標準Go プロジェクトレイアウト規則に従う
  • mainパッケージはcmd/ディレクトリに保持
  • 再利用可能なパッケージはpkg/またはinternal/に配置
  • 外部プロジェクトにインポートされるべきでないパッケージにはinternal/を使用
  • 関連機能をパッケージにグループ化
  • 循環依存関係を避ける

依存関係管理

  • Goモジュールgo.modgo.sum)を使用
  • 依存関係を最小限に保つ
  • セキュリティパッチのため定期的に依存関係を更新
  • go mod tidyを使用して未使用の依存関係をクリーンアップ
  • 必要な場合のみ依存関係をベンダー化

型安全性と言語機能

型定義

  • 意味と型安全性を追加するため型を定義
  • JSON、XML、データベースマッピングには構造体タグを使用
  • 明示的な型変換を優先
  • 型アサーションは慎重に使用し、第二戻り値をチェック

ポインターvs値

  • 大きな構造体またはレシーバーを変更する必要がある場合はポインターを使用
  • 小さな構造体とイミュータビリティが望ましい場合は値を使用
  • 型のメソッドセット内で一貫性を保つ
  • ポインターvs値レシーバーを選択する際はゼロ値を考慮

インターフェースと合成

  • インターフェースを受け入れ、具象型を返す
  • インターフェースを小さく保つ1〜3メソッドが理想的
  • 合成には埋め込みを使用
  • 実装される場所ではなく使用される場所の近くでインターフェースを定義
  • 必要でない限りインターフェースをエクスポートしない

並行性

ゴルーチン

  • ライブラリでゴルーチンを作成しない;呼び出し元に並行性を制御させる
  • ゴルーチンがどのように終了するかを常に知る
  • ゴルーチンを待つためにsync.WaitGroupまたはチャネルを使用
  • クリーンアップを確実に行うことでゴルーチンリークを避ける

チャネル

  • ゴルーチン間の通信にはチャネルを使用
  • メモリを共有して通信するのではなく、通信してメモリを共有する
  • 受信側ではなく送信側からチャネルを閉じる
  • 容量が分かっている場合はバッファードチャネルを使用
  • 非ブロッキング操作にはselectを使用

同期

  • 共有状態の保護にはsync.Mutexを使用
  • クリティカルセクションを小さく保つ
  • 多くの読み手がいる場合はsync.RWMutexを使用
  • 可能な場合はミューテックスよりもチャネルを優先
  • 一度だけの初期化にはsync.Onceを使用

エラーハンドリングパターン

エラー作成

  • シンプルな静的エラーにはerrors.Newを使用
  • 動的エラーにはfmt.Errorfを使用
  • ドメイン固有のエラーにはカスタムエラー型を作成
  • センチネルエラーにはエラー変数をエクスポート
  • エラーチェックにはerrors.Iserrors.Asを使用

エラー伝播

  • スタックを上に伝播する際にコンテキストを追加
  • エラーをログして返す(どちらか一方を選択)
  • 適切なレベルでエラーを処理
  • より良いデバッグのため構造化エラーの使用を検討

API設計

HTTPハンドラー

  • シンプルなハンドラーにはhttp.HandlerFuncを使用
  • 状態が必要なハンドラーにはhttp.Handlerを実装
  • 横断的関心事にはミドルウェアを使用
  • 適切なステータスコードとヘッダーを設定
  • エラーを適切に処理し、適切なエラーレスポンスを返す

JSON API

  • JSONマーシャリングを制御するため構造体タグを使用
  • 入力データを検証
  • オプションフィールドにはポインターを使用
  • 遅延解析のためjson.RawMessageの使用を検討
  • JSONエラーを適切に処理

パフォーマンス最適化

メモリ管理

  • ホットパスでのアロケーションを最小化
  • 可能な場合はオブジェクトを再利用(sync.Poolを検討)
  • 小さな構造体には値レシーバーを使用
  • サイズが分かっている場合はスライスを事前割り当て
  • 不要な文字列変換を避ける

プロファイリング

  • 組み込みプロファイリングツール(pprof)を使用
  • 重要なコードパスをベンチマーク
  • 最適化前にプロファイル
  • まずアルゴリズムの改善に焦点を当てる
  • ベンチマークにはtesting.Bの使用を検討

テスト

テスト構成

  • テストは同じパッケージに保持(ホワイトボックステスト)
  • ブラックボックステストには_testパッケージ接尾辞を使用
  • テストファイルは_test.go接尾辞で命名
  • テストファイルはテスト対象コードの隣に配置

テスト記述

  • 複数のテストケースにはテーブル駆動テストを使用
  • Test_functionName_scenarioを使って説明的にテストを命名
  • より良い構成のためt.Runでサブテストを使用
  • 成功ケースとエラーケースの両方をテスト
  • testifyや類似のライブラリは控えめに使用

テストヘルパー

  • ヘルパー関数にt.Helper()をマーク
  • 複雑なセットアップにはテストフィクスチャを作成
  • テストとベンチマークで使用される関数にはtesting.TBインターフェースを使用
  • t.Cleanup()を使ってリソースをクリーンアップ

セキュリティベストプラクティス

入力検証

  • すべての外部入力を検証
  • 無効な状態を防ぐため強い型付けを使用
  • SQLクエリで使用する前にデータをサニタイズ
  • ユーザー入力からのファイルパスに注意
  • 異なるコンテキストHTML、SQL、シェルのためデータを検証・エスケープ

暗号化

  • 標準ライブラリのcryptoパッケージを使用
  • 独自の暗号化を実装しない
  • 乱数生成にはcrypto/randを使用
  • bcryptまたは類似を使用してパスワードを保存
  • ネットワーク通信にはTLSを使用

文書化

コード文書化

  • すべてのエクスポートされたシンボルを文書化
  • シンボル名で文書化を開始
  • 有用な場合は文書化に例を使用
  • 文書をコードの近くに保持
  • コード変更時に文書を更新

READMEと文書化ファイル

  • 明確なセットアップ指示を含める
  • 依存関係と要件を文書化
  • 使用例を提供
  • 設定オプションを文書化
  • トラブルシューティングセクションを含める

ツールと開発ワークフロー

必須ツール

  • go fmt: コードフォーマット
  • go vet: 疑わしい構造を発見
  • golintまたはgolangci-lint: 追加リンティング
  • go test: テスト実行
  • go mod: 依存関係管理
  • go generate: コード生成

開発プラクティス

  • コミット前にテストを実行
  • フォーマットとリンティングにプリコミットフックを使用
  • コミットを焦点を絞ってアトミックに保つ
  • 意味のあるコミットメッセージを記述
  • コミット前に差分をレビュー

避けるべき一般的な落とし穴

  • エラーをチェックしない
  • 競合状態を無視する
  • ゴルーチンリークを作成
  • クリーンアップにdeferを使用しない
  • マップを同時変更
  • nilインターフェースvsポインターを理解していない
  • リソース(ファイル、接続)を閉じるのを忘れる
  • グローバル変数を不必要に使用
  • 空インターフェース(interface{})を過度に使用
  • 型のゼロ値を考慮しない