元記事

記事の要約翻訳

シニアのバックエンド開発者は、HTTP、DB、キュー、キャッシュ、監視、デプロイ、障害対応という難しい問題をすでに知っている。Goで新たに学ぶ中心は文法ではなく、これらを明示的で小さな部品の組み合わせとして実装する感覚である。

重要な転換: 「LaravelのGo版は何か」を探すより、まずは net/http、context、database/sql、testing を中心に、小さなルータ・DBドライバ・マイグレーションツールを必要な分だけ足す。Goらしさは、魔法を減らし、依存・エラー・ライフサイクルをコードから追えることにある。

最優先で身につける5つの感覚

1. 型とデータ構造

  • struct、メソッド、値/ポインタレシーバ、slice、map、pointer、package、module。
  • ゼロ値を前提にAPIを読む。未初期化でも安全に扱える設計が多い。
  • 先頭文字の大文字/小文字でエクスポート可否が決まる。

完了条件: DTO相当のstructを作り、JSON変換、slice/map操作、別packageからの利用を自力で説明・実装できる。

2. 小さなインターフェースと明示的DI

  • interfaceは実装の親ではなく、必要な振る舞いだけを表す契約。
  • 消費側が小さなinterfaceを定義し、実装はstructで返す(accept interfaces, return structs)。
  • main.go で DB → repository → service → handler をコンストラクタで接続する。

解説: テストではin-memory/fakeへ差し替えられ、本番構成もmainを読めば把握できる。最初から汎用DIコンテナを入れない。

3. errorを制御フローとして設計する

  • 失敗しうる処理は (result, error) で返し、fmt.Errorf("…: %w", err) で文脈を付けてラップする。
  • errors.Is はセンチネルエラーとの同一性確認、errors.As は特定エラー型の取得に使う。
  • repositoryはDBエラー、serviceはドメインエラー、handlerはHTTPステータスへ翻訳する。
  • panic はプログラマーの不変条件違反や回復不能な起動時失敗に限定する。

完了条件: sql.ErrNoRows を ErrUserNotFound に変換し、HTTP層で404に変換できる。main → run() error にして起動処理をテスト可能にする。

4. context とタイムアウトを最初から使う

  • context.Context はキャンセル・期限・デッドラインを下流へ伝える。HTTP、DB、外部HTTP呼び出しに渡す。
  • 第1引数に置く。structに保持しない。nilを渡さない。WithTimeout/WithCancelの直後にdefer cancel()。
  • 全ネットワーク呼び出しにtimeoutを置き、HTTPレスポンスのBodyは必ず閉じる。

解説: 接続枯渇、不要なDBクエリ、goroutineリークを防ぐ運用上の必須事項。

5. 並行処理は必要性を測ってから使う

  • goroutine、channel、sync.WaitGroup、Mutex、worker pool、fan-out/fan-in、contextによる停止を順に学ぶ。
  • 無条件に並列化しない。I/Oボトルネックなら単純なストリーミング処理の方が速く安全なことがある。
  • CIで go test -race ./... を実行する。ただしrace detectorは実行された経路でしか競合を検出できない。

実践用12週間ロードマップ

週6〜10時間を目安に、読む : 書く = 1 : 2以上にする。

Weeks 1–2 — 基礎とerror

学ぶ: syntax、struct、値/ポインタレシーバ、slice、map、pointer、package、module、interface、%w・errors.Is・errors.As。

成果物: 小さな関数群とテーブル駆動テスト。毎日短いコードを書く。

チェック: go mod init、go mod tidy、go test ./... を使い、エラーをラップして層ごとに翻訳できる。

Weeks 3–4 — CLIで標準ライブラリに慣れる

作る(2つ以上):

  • 大容量対応CSVバリデータ(行をストリーミングし、エラーをJSON出力)
  • JSON変換器
  • 複数URLのヘルスチェッカー
  • ログ解析器

学ぶ: os、io、bufio、encoding/json、encoding/csv、HTTP client、flag(必要ならCobra)。

チェック: flag、異常系、テーブル駆動テスト、go test -bench を追加。並列化はプロファイルで有効性が見えるまでしない。

Weeks 5–6 — 実用的なREST API

作る: タスク管理API。POST /tasks、GET /tasks/{id}、GET /tasksから開始。

含めるもの:

  • Go 1.22以降のnet/http ServeMux、handler / service / repositoryの分離
  • PostgreSQL(pgxまたはdatabase/sql)、migration、入力検証
  • context、リクエスト期限、構造化ログ(log/slog)
  • Docker Compose、DB実装とin-memory実装の差し替え

チェック: main.go は配線に集中し、同じrepository interfaceでin-memory版からPostgreSQL版へ入れ替えられる。

Weeks 7–8 — テストを製品品質に上げる

学ぶ/加える:

  • テーブル駆動テスト、httptest、fake/in-memory実装
  • 実DBを使う統合テスト(例: testcontainers-go)
  • benchmark、入力境界が多い箇所のfuzzing
go test ./...
go test -race ./...
go test -bench=. -benchmem ./...
go test -fuzz=FuzzMyParser

Weeks 9–10 — concurrencyとworker

作る: キューを消費するworker。メール通知など、失敗しても安全に再実行できる題材にする。

含めるもの: worker pool、WaitGroup、channel、errgroup、timeout、指数バックオフ+jitter、dead-letter処理、idempotency key、Prometheus metrics、停止時にin-flight jobをdrainする処理。

チェック: 停止信号で新規取得を止め、進行中jobを期限内に終了し、-raceが通る。

Week 11 — 観測可能性と性能

加える: log/slog、Prometheus metrics、OpenTelemetryの基本、内部限定のpprof、CPU/heap profile、接続プール調整。

原則: 最適化は計測後。benchmarkとprofileで仮説を確認してから変更する。

Week 12 — ポートフォリオ化

1つを選び、他人が5分で起動・理解できる状態まで磨く。

完成条件: README、アーキテクチャ説明、ワンコマンドのローカル起動、Docker Compose、妥当なテスト、CI、リクエスト例、デプロイノート。単なるCRUDではなく、health/readiness、graceful shutdown、timeout、ログ、error設計を入れる。

まず5日で立ち上がる短縮版

この5日版は「既存サービスを読み、小さな変更を安全に出す」ための入口。runtime、GC、generics、build tags、cgo、unsafeの深い理解は後でよい。

プロダクションGoの必須チェックリスト

学び方の原則

  1. 毎週、動く成果物を1つ残す。 チュートリアル視聴だけを続けない。
  2. 標準ライブラリから始める。 frameworkは不足が具体化してから導入する。
  3. 良い実コードを局所的に読む。 package構成、context、error、test、設定、shutdown、metricsの一項目ずつ観察する。
  4. 退屈で明快なコードを目指す。 小さなinterface、直接的なerror処理、最小限の魔法、明示的な依存関係がGoの強みになる。

参考