go-service について
Go Service は、標準ライブラリ、SQL、コマンドラインツールを使った Go マイクロサービス開発向けのスキルです。依存性注入、HTTP ハンドラー、構造化ログ、データベースコード生成、テスト手順を扱います。
主な機能
- 01標準ライブラリによるサービス構築
- 02HTTP ミドルウェアの合成
- 03依存関係の明示的な受け渡し
- 04slog による構造化ログ
- 05sqlc による型安全なコード生成
- 06合成可能なコマンドラインの構築
活用シーン
- 01Go マイクロサービスの構成設計
- 02HTTP ハンドラーとミドルウェアの実装
- 03SQL スキーマ変更後のコード生成
- 04サービス用 CLI の構築
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ brojonat/ llmsrules --skill go-serviceインストール後、Claude Code で/go-serviceを入力して読み込まれたか確認します。
詳細
Go Service
標準ライブラリ、SQL 用の sqlc、コマンド用の urfave/cli、構造化ログ用の slog を使用した、本番環境向けの Go マイクロサービスです。
基本原則
- 一つのことをうまく行う:各コンポーネントの責務は一つにします
- 複雑さよりシンプルさを重視する:プレーンな JSON、標準 SQL、環境変数を使用します
- 組み合わせる:パイプ処理や標準インターフェースに適した設計にします
- 依存関係を明示する:グローバル変数やシングルトンを使わず、すべてをパラメーターとして渡します
プロジェクト構成
.
├── cmd/
│ ├── server/ # Backend service entry point
│ └── client/ # CLI entry point
├── cli/ # CLI implementation
├── client/ # Public client library
├── internal/ # Internal packages
│ └── db/ # Generated code (from sqlc)
├── migrations/ # SQL schema migrations
├── queries/ # SQL queries for sqlc
├── examples/ # Usage examples
├── testdata/ # Test fixtures
├── Makefile
├── .air.toml # Air configuration
├── sqlc.yaml # sqlc configuration
├── go.mod
├── README.md
└── CHANGELOG.md
ハンドラー関数のパターン
http.Handler を返す関数を記述します(Mat Ryer のアプローチに従います)。
func handleListWallets(store TransactionStore, logger *slog.Logger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
wallets, err := store.ListWallets(ctx)
if err != nil {
logger.ErrorContext(ctx, "failed to list wallets", "error", err)
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(wallets)
})
}
ミドルウェアの組み合わせ
type adapter func(http.Handler) http.Handler
// adaptHandler applies adapters in reverse order so the first is outermost
func adaptHandler(h http.Handler, adapters ...adapter) http.Handler {
for i := len(adapters) - 1; i >= 0; i-- {
h = adapters[i](h)
}
return h
}
// Usage:
mux.Handle("GET /wallets", adaptHandler(
handleListWallets(store, logger),
withRequestID(),
withLogging(logger),
withMetrics(promRegistry),
withJWTAuth(jwtSecret),
))
依存性注入
// Bad: hidden dependency on global
var db *sql.DB
func SaveTransaction(txn *Transaction) error {
_, err := db.Exec("INSERT INTO transactions ...")
return err
}
// Good: explicit dependencies
type TransactionStore interface {
Save(ctx context.Context, txn *Transaction) error
}
type PostgresStore struct {
db *sql.DB
}
func NewPostgresStore(db *sql.DB) *PostgresStore {
return &PostgresStore{db: db}
}
// Dependencies are clear at construction time
store := NewPostgresStore(db)
poller := NewWalletPoller(solanaClient, store, natsConn)
slog による構造化ログ
func setupLogger(level slog.Level) *slog.Logger {
opts := &slog.HandlerOptions{Level: level}
return slog.New(slog.NewJSONHandler(os.Stderr, opts))
}
// Most logs at DEBUG level
logger.DebugContext(ctx, "polling wallet", "wallet", walletAddress, "last_slot", lastSlot)
// INFO for lifecycle events only
logger.InfoContext(ctx, "server started", "addr", addr, "version", version)
// ERROR for failures
logger.ErrorContext(ctx, "failed to store transaction", "error", err, "signature", sig)
LOG_LEVEL 環境変数で詳細度を制御します。本番環境ではデフォルトを WARN、開発環境では DEBUG にします。
sqlc による SQL
SQL を記述すると、型安全な Go コードが生成されます。
# sqlc.yaml
version: "2"
sql:
- engine: "postgresql"
queries: "queries/"
schema: "migrations/"
gen:
go:
package: "db"
out: "internal/db"
スキーマを変更したら必ず再生成し、生成されたコードをコミットしてください。
エラー処理
// Always handle errors
txns, err := client.GetTransactions(ctx)
if err != nil {
return fmt.Errorf("failed to get transactions: %w", err)
}
urfave/cli による CLI
環境変数への自動バインドとヘルプ機能を備えた、シンプルで組み合わせやすいコマンドラインインターフェースです。
開発ワークフロー
- 計画:まずインターフェースを設計します
- テストファースト(TDD):テストを記述し、最小限のコードを書いてからリファクタリングします
- サーバー+クライアント:サーバー機能を追加したら、クライアントメソッドと CLI サブコマンドも追加します
- Makefile:
make test、make lint、make dev、make build-server - ホットリロード:開発には Air を使用します
- リンティング:厳格な設定の
golangci-lintを使用し、警告をすべて修正します
Unix の哲学
- デフォルトでは静かにする:エラーや重要なイベントがある場合にのみ出力します
- 標準出力に JSON を出力する:機械可読な出力を使用し、人間向けには
--format=table|json|csvを使います - エラーは標準エラーに出力する:パイプ処理に備えて標準出力を汚しません
- 終了コード:0 は成功、0 以外はエラーです
コメント
Markdown 対応