mmuulan
BackendBeginner

Go キャッチアップメモ

Created 2026-07-05

Go キャッチアップメモ

概要

このドキュメントは、一般的なWeb開発経験はあるがGoの実務経験が浅い人向けに、Goの「設計思想・考え方」を15〜30分程度で把握できるようにまとめたものです。文法(ifの書き方、forループなど)の解説はほとんど含みません。代わりに、なぜGoのコードやプロジェクトがこういう形になるのかという判断基準に焦点を当てています。

読み終える頃には、AIコーディングツール(Claude Code、Cursorなど)にGoプロジェクトの実装を指示したり、生成されたコードが「Goらしいかどうか」をレビューしたりできる状態を目指します。

1. Goの全体思想

このセクションで分かること

Goがなぜ「シンプルさ」を最優先に設計されたのか、そしてそのポリシーがどうコードや設計の判断基準に反映されているかが分かります。

背景:何を解決するために生まれたか

GoはGoogleで開発された言語で、大規模なコードベースを多人数でメンテナンスする際の複雑さを減らすことを目的としています。この思想は今も強く残っており、公式ドキュメント自身が繰り返し「シンプルさ」を強調しています。

Good/Bad視点:他言語(Java、Rubyなど)の経験があると、つい「抽象化レイヤーを増やす」「継承階層を作る」方向に倒したくなりますが、Goではそれは基本的にBadとされます。Goには継承がなく、代わりにコンポジション(構造体の埋め込み)とシンプルなインターフェースを使います。

フォーマットは議論しない

Go最大の特徴の一つは、コードフォーマットに関する論争をgofmtという公式ツールでなくしたことです。gofmtプログラムはGoのプログラムを読み込み、インデントや縦の整列を標準スタイルで出力します。チームやAIが生成するコードのスタイルで揉めることがない、という前提で設計が進んでいる点は把握しておくと良いです。

エラーハンドリングの思想(例外を使わない)

他言語のtry/catchに慣れていると最初に戸惑うポイントです。Goでは通常のエラーハンドリングにpanicを使わず、errorと複数戻り値を使います。関数はほぼ必ず (結果, error) という形で値を返し、呼び出し側は都度 if err != nil でチェックします。

  • Goodif err != nil { return err } を都度書く(冗長に見えても、これがGoの標準)
  • Bad:例外機構のようにpanic/recoverを通常のフロー制御として使う。panicは通常のエラーハンドリングには使わず、errorと複数戻り値を使うべきとされています

またGoではエラーの握りつぶし(_への代入で無視すること)も避けるべきとされています。エラーを_変数で捨てず、関数がエラーを返す場合は必ずチェックして、処理するか、返すか、本当に例外的な状況であればpanicするべきだとされています。

プロジェクトレイアウトに「公式の唯一解」はない

これは他フレームワークとの大きな違いです。Goプロジェクトをどう構成すべきかは新しくGoを始めた開発者がよく持つ疑問であり、Go公式はいくつかのガイドラインを示していますが、プロジェクトの種類(単純なパッケージか、コマンドラインツールか、サーバーか)によって推奨構成を分けて説明しています。つまり「これが正解」というテンプレートを公式が強制しているわけではなく、プロジェクトの性質に応じて考えるのがGo流です。


2. ディレクトリ・プロジェクト構成

このセクションで分かること

Goの公式ガイドと、コミュニティで広く使われるgolang-standards/project-layoutという2つの情報源の違い、そして代表的なディレクトリの役割が分かります。

情報源が2つある点に注意

後者は非常によく参照されますが、Go公式のコア開発チームが定めた公式標準ではなく、Goエコシステムにおける歴史的・新興のプロジェクトレイアウトパターンをまとめたものである点は明確に区別してください。AIツールが生成する構成も、この非公式レイアウトに影響されていることが多いです。

基本パターン:小さいパッケージ

公式ドキュメントによれば、非常にシンプルなパッケージであれば、プロジェクトルート直下にgo.modと.goファイルを置くだけで十分だとされています。最初から複雑な構成にする必要はありません。

サーバー・アプリケーションの場合

公式ドキュメントは、サーバー用途では次のような構成を推奨しています。

サーバーはプロトコル(REST・gRPC)、デプロイ方法、フロントエンド、コンテナ化など多様な側面があるため構成のばらつきが大きいものの、サーバーのロジックを実装するGoパッケージはinternalディレクトリに置き、Goのコマンド群はcmdディレクトリにまとめておくことが推奨されています。

project-root/
  go.mod
  internal/
    auth/
    metrics/
    model/
  cmd/
    api-server/
      main.go
    metrics-analyzer/
      main.go

主要ディレクトリの役割

ディレクトリ 役割
cmd/ 実行可能ファイルのエントリーポイント。各サブディレクトリが特定の実行可能ファイルのmainパッケージであり、main関数の役割は初期化とロジック層をつなぐグルーコードに徹するべき
internal/ 公開したくない実装コード。internal配下のパッケージは、それが属するGoモジュールの外からはアクセスできず、Goツールチェーン自体がこの規約を強制する
pkg/ 外部プロジェクトからimportされて良い公開ライブラリコード。他のプロジェクトはここにあるライブラリをimportして使うことを期待するため、ここに置く前によく考える必要がある(賛否が分かれる。後述)
api/ API定義(OpenAPI/Protobufなど)
web/ Webアセット(テンプレート、静的ファイル)
configs/, scripts/, docs/ 設定、ビルドスクリプト、ドキュメント

pkg vs internal論争(公式見解なし・出典明記)

これはGoコミュニティで意見が分かれる代表的なトピックです。

  • ある立場:internalディレクトリは、自分のプライベートなパッケージが外部からimportされないことをGoの仕組みで保証できるという意味で優れているという考え方
  • 別の立場:pkgとinternalの使い分けについて論じたブログ記事では、pkgよりinternalを使うべきという意見もある一方、pkgディレクトリはGo以外の言語やコンポーネントがルートディレクトリに混在するプロジェクトで、Goのコードを一箇所にまとめて各種Goツールを実行しやすくするのに便利だ、という意見もある

出典:golang-standards/project-layout (GitHub)

実務での判断の目安:迷ったらinternal/だけで十分なケースが多いです。他プロジェクトから使い回す明確な公開ライブラリが必要になったときだけpkg/や別モジュール化を検討する、という考え方が公式寄りの姿勢に近いです(サーバーのGoパッケージがエクスポート用に成長した場合は、それらを別モジュールに切り出すのが最善とされています)。

機能ごと(Feature-based)構成

近年、特にAPIサーバーではドメイン(機能)ごとにファイルをまとめる構成もよく見られます。

internal/
  users/
    handler.go
    store.go
    routes.go
    model.go
  products/
    handler.go
    store.go
    routes.go
    model.go

出典:A Practical, Production-Ready Go Project Structure (Medium) ※コミュニティ記事であり公式見解ではない

  • Good:機能単位で変更が閉じるため、大規模チーム・大規模プロジェクトで見通しが良い
  • Bad(トレードオフ):小規模プロジェクトでは逆に「同じディレクトリ構造の繰り返し」が冗長になりやすい

避けるべきパターン(公式寄りの注意)

util、models、controllers、helpersのような「何でも入れられる」パッケージ名は避けるべきとされています。また、一部のGoプロジェクトにはsrcフォルダがあるが、これは開発者がJavaの世界から来た場合によく見られるパターンであり、Goプロジェクトをこのように見せないほうが良いとも指摘されています。AIがJavaやNode.js的なsrc/構成を提案してきた場合は、Go的には不自然である可能性を疑ってください。


3. コンポーネント/モジュール設計の考え方

このセクションで分かること

Goにおける「分割の単位」がパッケージであること、そして継承ではなくコンポジションとインターフェースで抽象化する考え方が分かります。

分割の単位は「パッケージ」

Reactの「コンポーネント」に相当する分割単位は、Goでは基本的にパッケージです。1パッケージ1ディレクトリが原則で、モジュールは複数のimport可能なパッケージから構成でき、各パッケージは専用のディレクトリを持ち、階層的に構成できます。

抽象化はインターフェースで、しかも小さく

Goのインターフェースは他言語と使い方が異なります。Goのインターフェース名は特殊で、他言語のように頭に大文字のIを付けるのではなく、Reader・Writer・Closerのように-erで終わる名前を選ぶのが慣習であり、さらにインターフェースは小さく、1つの関数だけを持つことも珍しくないとされています。

  • GoodReaderインターフェースにRead()メソッド1つだけ、のように小さく保つ
  • Bad:多数のメソッドを持つ「万能インターフェース」を最初から作る

小さいインターフェースを組み合わせる設計は、Goコミュニティでよく引用される格言 “The bigger the interface, the weaker the abstraction”(インターフェースが大きいほど抽象化は弱くなる)にも表れています。

パッケージ名とその中身の関係(スタッター回避)

パッケージ名と関数名が重複する「スタッター(吃音)」を避けるのがGoらしさです。パッケージ名がvectordbであれば、NewVectorDBやOpenVectorDBのような関数は作らず、パッケージ名と一緒に使われることを踏まえてNewやOpenとするべきであり、これがスタッターを避けるということです。

// Good
vectordb.New()
vectordb.Open()

// Bad(スタッター)
vectordb.NewVectorDB()
vectordb.OpenVectorDB()

「Getter」にGetを付けない

値を読み取るだけのメソッドにはGetを前置しない。例えばURLを返すメソッドはGetURLではなくURLと名付けるべきとされています。ここもJavaやC#の慣習と異なる点なので、AIがGetXxx()ばかり生成してくる場合は指摘すると良いポイントです。

エラーの扱い方(早期return・ラップ)

Goらしいエラーハンドリングの型は、早期returnで正常系を左側に保つことです。エラーがnilでない場合はそのif文の中でreturnし、正常系のコードを画面の左側に保って読みやすくするのがGoの慣習であり、err == nilの場合に処理を続ける書き方だとif文のネストが深くなってしまうという理由があります。

またエラーの発生元情報を保持したまま上位へ伝える「エラーラップ」も一般的な設計判断です(例:fmt.Errorf("reading config: %w", err)のように%wで元エラーを包む)。出典:Go Coding Official Standards and Best Practices (Medium) ※コミュニティ記事

依存の向き:mainは薄く

cmd/配下のmain関数は、依存を組み立てる役割に徹するべきという考え方が広く共有されています。main関数の仕事は最小限であるべきで、初期化を担い、データベースやロガー、ビジネスロジック層といった依存関係を結びつけるグルーコードとして振る舞うべきです。出典:Mastering Go Project Structure (Chandrashekhar Kachawa Tech Blog) ※コミュニティ記事


4. 命名規則

このセクションで分かること

Goの命名規則が「大文字/小文字で公開範囲が決まる」という言語仕様と直結していること、ファイル名・パッケージ名・エラー変数名などの慣習が分かります。

大文字・小文字が可視性を決める(最重要)

Goでは他言語のようなpublic/privateキーワードがなく、識別子の先頭が大文字か小文字かでパッケージ外に公開するかどうかが決まります。名前はGoにおいて他の言語と同様に重要であり、パッケージ外での名前の可視性は最初の文字が大文字かどうかで決まる、という意味的な効果を持ちます。

  • 大文字始まり(User, NewClient)→ 外部から参照可能(exported)
  • 小文字始まり(user, parseURL)→ パッケージ内限定(unexported)

単語のつなぎ方:camelCase/PascalCase、アンダースコアは使わない

Goの慣習では複数単語の名前を書くのにアンダースコアではなくmixedCapsまたはMixedCapsを使います。

// Good
var userCount int
func CalculateNetIncome() {}

// Bad
var user_count int
func Calculate_Net_Income() {}

パッケージ名

パッケージ名は慣習として小文字・単語ひとつで、アンダースコアやmixedCapsは不要とされ、短く・簡潔で・分かりやすい名前が望ましいとされています。またutil、common、misc、api、types、interfacesのような意味の薄いパッケージ名は避けるべきです。

エラー変数名

エラーを表す変数・値にはerrという接頭辞を使うのが強い慣習です。errFooやErrFooのようにerrで始まる名前を付けることで、コードを読んだときにその変数がエラーであるとひと目で分かり、可読性が上がり、コードの検索性も向上するとされています。出典:Datadog Static Analysis Rules

またエラー文字列自体の書き方にも規約があります。エラー文字列は大文字で始めたり(固有名詞や略語を除く)句読点で終えたりしてはならない、なぜなら他の文脈と一緒にログ出力されることが多いためです。

ファイル名

Goのファイル名は基本的に小文字・スネークケースです。

user.go
user_service.go
payment_handler.go

出典:The Complete Guide to Go Naming (DEV Community) ※コミュニティ記事

Go言語仕様として決まっている特殊なファイル名規約もあります。

ファイル名パターン 役割
*_test.go テストファイル。go testが自動的に実行対象として認識する
TestXxx関数 テスト関数。Testから始まる関数名をgo testが自動検出する
doc.go パッケージ全体のドキュメンテーションコメント専用ファイル(慣習)

略語(Acronym)の扱い

URLHTTPのような略語は、大文字・小文字を統一して書きます。略語を使う場合は大文字小文字を統一するべきで、公開名であればすべて大文字(HTTPServer)、内部名であればすべて小文字(httpServer)にするのが標準的な慣習です。

// Good
type HTTPServer struct{}
var httpServer httpServer

// Bad
type HttpServer struct{}

Must系の命名

初期化時に失敗したらpanicしてよい関数にはMustを接頭辞として付ける慣習があります。プログラム失敗時に停止するセットアップ用のヘルパー関数はMustXYZ(またはmustXYZ)という命名規則に従い、これは基本的にプログラム起動時の早い段階でのみ呼び出されるべきで、ユーザー入力のような通常のGoのエラーハンドリングが望ましい場面では使うべきではないとされています。


5. AIコーディングを見据えた注意点

このセクションで分かること

AIにGoコードを書かせる際に、あらかじめ人間が決めておくべきことと、AIが誤りやすい典型パターンが分かります。

事前に決めておくべきこと

  1. プロジェクトレイアウトの方針golang-standards/project-layout風のフルセット構成にするのか、シンプルなcmd/+internal/の最小構成にするのかを最初に明言する。Goには強制力のある公式レイアウトがないため、AIに任せると毎回違う構成を提案してくることがあります。
  2. pkg/を使うかどうかの方針:外部公開を想定する部分があるかどうかを事前に伝える。特に理由がなければ「internal/のみで統一してほしい」と指示するとブレを防げます。
  3. エラーハンドリングの方針:エラーラップの書式(%wを使うか等)やセンチネルエラー(ErrNotFoundのような定義済みエラー値)の使用方針を先に伝える。

AIが誤りやすいポイント

  • Java/Node.js的な構成の混入src/ディレクトリ、utils/helpers/といった意味の薄いパッケージ名、GetXxx()のようなgetterの多用など、他言語の慣習をそのまま持ち込みがちです。Goプロジェクトが他言語のsrcパターンを真似ることは推奨されていませんし、GetURLではなくURLとすべきという慣習も見落とされやすい点です。
  • panicの濫用:例外処理に慣れていると、AIが通常のエラーケースにまでpanicを使ったコードを生成することがあります。通常のエラーハンドリングにpanicを使わないという原則を踏まえてレビューしてください。
  • エラーの握りつぶし_でエラーを受け取って捨てるコードが紛れ込むことがあります。エラーを_で捨てず、必ずチェックするべきという点を確認しましょう。
  • 巨大インターフェースの生成:AIは要件を満たそうとして多機能なインターフェースを1つ作りがちですが、Goではインターフェースは小さく、1メソッドのものも珍しくないという設計が好まれます。分割を促す指示が有効です。
  • golang-standards/project-layoutを「公式」と誤認して提案してくる:AIがこのレイアウトを無条件に「Goの標準」として提示してくることがありますが、これは公式標準ではなくコミュニティのパターン集です。プロジェクト規模に見合わない過剰な構成を提案された場合は、簡略化を指示してください。

AIへの指示で押さえておくと良い語彙

  • internal/にまとめて」「cmd/にエントリーポイントを分離して」など、ディレクトリの役割語彙を使うと意図が伝わりやすい
  • 「エラーは%wでラップして返して」「センチネルエラーはErrXxxで定義して」など、エラー処理の書式を具体的に指定する
  • 「インターフェースは小さく保って」「Getは付けないで」など、Go特有の命名・設計規約を明示的に伝える

参考文献一覧