Go にも“rails g scaffold”を:爆速CLIツール「gon」の紹介
Go でアプリケーションを開発していると、毎回同じようなパッケージ構造・ファイル名・初期実装を書くことに疲れてきませんか?
Rails には rails generate scaffold
という便利なコマンドがあります。これがあるおかげで、開発者は構造を気にせず「まずは作る」ことに集中できます。
そんな体験を Go にも持ち込めないか?
そう思って作ったのが、CLI ツール gon
です。
✪ gon ってなに?
gon
は、Rails のように 1 コマンドで model、use-case、handler を生成できる、意見の強い Go 向けの scaffold ツールです。
gon g scaffold User name:string email:string
これを叩くだけで、以下のような構造が生成されます:
internal/
└── domain/
└── user/
├── model/
├── repository/
├── usecase/
├── handler/
└── fixture/
クリーンアーキテクチャに基づいた構成で、ディレクトリごとにパッケージも分けています。
✨ gon の特徴
- Rails ライクなコマンドで爆速開発
- model, usecase, や handler を一度に生成
- クリーンアーキテクチャ準拠のディレクトリ構成
- テストコードや fixture も自動で生成
- テンプレートは
embed
ベースでカスタマイズ可能
🔧 インストール
Go 1.17+ なら以下でインストールできます:
go install github.com/mickamy/gon@latest
Go 1.24+ の場合は go get -tool
でもOK:
go get -tool github.com/mickamy/gon
初期化とテンプレートの準備は次の 2 ステップです:
gon init # gon.yaml を作成
gon install # テンプレートとテストヘルパーを準備
✨ 実際に使ってみる
modle の生成
gon g model User name:string email:string
use-case の追加
gon g usecase CreateUser
handler の生成
gon g handler User list create
ぜんぶ一括で
gon g scaffold User name:string email:string
このコマンドを実行すると、以下のようなファイルが自動生成されます:
internal/
└── domain/
└── user/
└── fixture/
│ └── user.go
├── model/
│ └── user_model.go
├── usecase/
│ ├── create_user_use_case.go
│ ├── get_user_use_case.go
│ ├── list_user_use_case.go
│ ├── update_user_use_case.go
│ └── delete_user_use_case.go
├── repository/
│ └── user_repository.go
└── handler/
└── user_handler.go
削除もできます:
gon d scaffold User
🧱 「意見の強さ」が gon の魅力
gon は柔軟性よりも、「迷わず使える」ことを重視しています。
ディレクトリ構成や命名規則を統一することで、チーム開発でも迷子になりません。
テンプレートは embed
されており、必要なら gon install
後にカスタマイズも可能です。
🧩 作成されるコードの一例
実際に作成されるコードの一部をご紹介します。
handler(ListUserHandler)
type ListUserHandler echo.HandlerFunc
func ListUser(uc usecase.ListUser) ListUserHandler {
return func(c echo.Context) error {
ctx := c.Request().Context()
output, err := uc.Do(ctx, usecase.ListUserInput{})
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
return c.JSON(http.StatusOK, output)
}
}
usecase(CreateUser)
package usecase
import (
"context"
)
type CreateUserInput struct {}
type CreateUserOutput struct {}
//go:generate mockgen -source=$GOFILE -destination=./mock_$GOPACKAGE/mock_$GOFILE -package=mock_$GOPACKAGE
type CreateUser interface {
Do(ctx context.Context, input CreateUserInput) (CreateUserOutput, error)
}
type createUser struct {}
func NewCreateUser() CreateUser {
return &createUser{}
}
func (uc createUser) Do(ctx context.Context, input CreateUserInput) (CreateUserOutput, error) {
return CreateUserOutput{}, nil
}
repository(User)
package repository
// ...
func (repo *user) List(ctx context.Context, scopes ...func(*gorm.DB) *gorm.DB) ([]model.User, error) {
var m []model.User
err := repo.db.WithContext(ctx).Scopes(scopes...).Find(&m).Error
return m, err
}
// 他のメソッドは省略
🤪 例を見てみたい?
example/
ディレクトリに、gon を使ったサンプルアプリを置いています。ぜひ覗いてみてください。
🔭 今後の展望
- DI ライブラリへの対応
- google/wire を想定
- http request/response につめる DTO の生成
- gorm/echo 以外のライブラリ対応
- より洗練されたアーキテクチャへの改造
など、いろいろアイデアがあります。Issue や PR も歓迎しています!
🙏 最後に
gon
は「Go でも Rails みたいに開発したい!」という思いから生まれました。
ぜひ試して、フィードバックをもらえると嬉しいです。
Discussion