私が歌川です

@utgwkk が書いている

ピロリ菌除去日記 day0

blog.utgw.net

胃カメラを飲んだ結果、ピロリ菌が多いので除菌療法をやっていくことになった。1日2回、朝と夕方に数種類の薬を1週間忘れず飲み、2ヶ月ぐらい後にまた検査を受ける。

受け取った薬は以下2つ。

とりあえず日記をつけ始めたけど、目立った副作用とかイベントがないと日記に書くことがなくなって自然消滅すると思う。

VSCodeでModule Pluginを使ってプロジェクトごとにビルドしたgolangci-lintでlintする

golangci-lintにはModule Pluginという仕組みがあり、設定ファイルを書いてカスタムビルドすることで独自のlinterをgolangci-lintで走らせることができます。これを使って、プロジェクト固有のlinterを組み込んだgolangci-lintをビルドして、VSCodeでも使えるようにします。

だいたい おなかが空いたら golangci-lint の Module Plugin 使おう | 東京科学大学デジタル創作同好会traP に書いてある通りの設定を入れたらよいけど、プロジェクト固有のカスタムビルドを行ったgolangci-lintでlintするためには工夫が要ります。

プロジェクト内にgolangci-lintがビルドされるようにする

以下のような .custom-gcl.yml ファイルを用意します。

version: v2.12.2
name: custom-gcl
destination: ./tmp
plugins: # 略

コツは namedestination フィールドで、プロジェクト内の tmp/custom-gcl というパスにビルドされたバイナリが出力されるように設定します。このあたりはプロジェクトごとに好きな流儀で調整してください。

VSCode (vscode-go) でプロジェクト内にビルドしたgolangci-lintが使われるようにする

プロジェクト内の tmp/custom-gcl というパスにgolangci-lintがビルドされるとします。

以下のような設定を .vscode/settings.json ファイルに追加することで、VSCode内でカスタムビルドしたgolangci-lintを使ったlintが走るようになります。

{
  "go.lintTool": "golangci-lint-v2",
  "go.alternateTools": {
    "golangci-lint-v2": "${workspaceFolder}/tmp/custom-gcl"
  }
}

コツは ${workspaceFolder} という変数を使って設定を書くことです。VSCodeの機能として、settings.jsonなどのファイル内で展開される変数を使って設定を記述できます*1。こうすることで、カスタムビルドしたgolangci-lintのバイナリをPATHが通ったディレクトリにコピーする必要がなく、プロジェクト固有のlinterを組み込んで好きに使うことができます。

Goファイルの先頭に著作権・ライセンス表記が入っていることを検査するlinterを書いた

表題のものを書きました。どうぞご利用ください。

github.com

使い方

スタンドアロンバイナリ

go installgo tool コマンドなどで落としてきて直接使う方法です。-header オプションに必要な表記を文字列で渡して使います。-fix オプションを渡すことで自動修正できます。

% copyrightheader -header='Copyright (c) Your Name' ./...

go vet コマンド経由

go vet コマンドの -vettool オプション経由で使うことができます。

% go vet -vettool=$(which copyrightheader) -copyrightheader.header='Copyright (c) Your Name' ./...

golangci-lintのカスタムlinter

golangci-lintのModule Plugin Systemの仕組みを使うことで、カスタムlinterとして組み込んで動作させることができます。

plugins:
  - module: github.com/utgwkk/copyrightheader
    import: github.com/utgwkk/copyrightheader/plugin

設定項目はこういう感じで書けます。

linters:
  enable:
    - copyrightheader
  settings:
    custom:
      copyrightheader:
        type: module
        settings:
          header: 'Copyright (c) Your Name'

動機

Goファイル先頭のコメントの内容を検査するlinterとしては、すでにgo-headerが存在し、golangci-lintにデフォルトで組み込まれています。また、go-headerのほうが設定項目も機能も多いので、普通にgo-headerを使ったほうがいいんじゃないか、と思われるでしょう。

go-headerにはパフォーマンスの問題があります。既にissueで報告されているように、検査するファイルごとに git コマンドを実行しているため、ファイル数が多くなるとlinterの実行時間がどんどん長くなってしまいます。著作権表記のテンプレートに年を入れない場合でも git コマンドの実行を回避することができません。

github.com

自分が関わっているプロジェクトでも、まだコードベースがそこまで大きくないのにも関わらずgo-headerの実行時間が golangci-lint run --verbose コマンドの実行ログにTop10として表示されるようになっていました。これからコードベースが育っていくにつれて、linterの実行時間が問題になることが考えられます。

年を含まない著作権・ライセンス表記が各Goファイルに入っていることを保証できればよい、という要件に絞れば実装はそこまで難しくないので、さっと作ることにしました。

実装

例によって、Claude Codeに全てを実装してもらいました。自分でも何をやっているのか読める範囲のコードではあるけど、試行錯誤のスピードが段違いなので全て任せてしまうほうが早いですね。

golangci-lintにデフォルトで組み込めるかどうか

go-headerと検査ルールが丸かぶりしている上に機能も足りていないので、すぐには取り込めないんじゃないかな~。自分としてはデフォルトで組み込みたいというモチベーションは今のところないです。それよりは、go-headerのパフォーマンスの問題を解決できるほうがよさそう。

あわせて読みたい

Go Conference 2026 CfS落ちた

無念!! Go Conference 2026は個人でスポンサーしているし、万難を排して行くつもりです。中野セントラルパークカンファレンスで会いましょう。

CfS

Goでアプリケーションを開発する際、複雑なドメインロジックをどうコードに落とし込むべきか悩んだことはありませんか。また、いざドメインロジックを実装してみたものの、データストアや外部APIの都合に引きずられ、後からコードを読んでも結局何がどうなるのか理解しづらいと思った経験はありませんか。そんなあなたに「関数型ドメインモデリング」を知っていただきたいです。

「関数型ドメインモデリング」(Domain Modeling Made Functional) [1][2] は、関数型プログラミングと型システムを活用したドメイン駆動設計の手法について説明した本です。「関数型ドメインモデリング」の主要な考え方を要約すると、以下のようになります。

  • ドメイン駆動設計の考え方に基づき、ドメインを理解する
  • ドメインモデルを代数的データ型でモデリングする
  • 一連の手続きをワークフロー (副作用を持たない状態遷移の単位) に分解し、連結させる
  • ドメインロジックを純粋関数で記述し、副作用を端に追いやる

「関数型ドメインモデリング」では実装言語として F# が用いられていますが、考え方のエッセンスはプログラミング言語に依存しません。私が所属する会社では「関数型ドメインモデリング」を輪読し、チームに分かれて複数の言語で実装を移植する会が過去に開催され、Goでの移植も行いました[3]。また、筆者は実際にGo製Webアプリケーションの開発に対して、関数型ドメインモデリングの考え方を取り入れた経験があり、また別のプロジェクトでもまさに現在進行形で実践しています。

本トークでは、Goでどのようにドメインの複雑さに立ち向かうことができるのか・Goでの関数型ドメインモデリングを「夢」で終わらせないためにどのようにアレンジして取り入れたのか、についてお話しします。 以下のような話題について、簡単な (しかし自明でないドメインロジックがある) アプリケーションを例に挙げつつお話しする予定です。

  • 「関数型ドメインモデリング」のおさらい
  • ワークフローをGoのコードとして表現する
  • Goの型・言語機能を活かしたドメインモデリング
  • 永続化層での表現とドメインモデルとのギャップを吸収する
  • 関数型ドメインモデリングと「Goらしい」コードとのギャップを埋め、すこやかに開発できるポイントを探求する
  • どうやって依存を注入するか
  • error interfaceと Result
  • nilOption
  • Goの言語機能の進化と関数型ドメインモデリング
  • メソッドのジェネリクス対応 [4]

本トークを通じて、複雑なドメインロジックをGoで実装する際の選択肢を増やすことにつながり、健やかなアプリケーション開発への一助となれば幸いです。

[1]: https://tatsu-zine.com/books/domain-modeling-made-functional
[2]: https://pragprog.com/titles/swdddf/domain-modeling-made-functional/
[3]: https://developer.hatenastaff.com/entry/2025/10/31/153000
[4]: https://github.com/golang/go/issues/77273

stephenafamo/bobでBIGINT型のカラムに対してGoのint64型じゃなくてint型を対応させたい

tl;dr

設定ファイルに以下のような記述を足したらよいです。

replacements:
  - tables: []
    match:
      db_type: 'bigint'
    replace: 'int'

仕組み

stephenafamo/bobはGoのO/Rマッパーで、DBスキーマの定義からGoのコードを生成することで型安全に扱えるという特徴を持っています。

stephenafamo/bobには、ドライバが推論した型を上書きするための設定項目があるので、これを利用して、全てのテーブルの BIGINT 型のカラムをGoの int 型に対応させるように上書きしています。

Goの int 型は64ビットとは限らないけど大丈夫なの?

Goの言語仕様をよく読むと、int 型について以下のように規定されています。

uint either 32 or 64 bits
int same size as uint

すなわち、int 型は処理系によって32ビットもしくは64ビット整数のいずれかを表しています。手元のパソコンやVM・Dockerコンテナではだいたい64ビットになっていると思います。より正確に調べるには unsafe.Sizeof(int(0)) の実行結果 (バイト数が表示される) を確認するとよいです。

一般的なWebアプリケーションの動作環境を念頭に置くと、現代で64ビットプロセッサが使えない環境をわざわざ選ぶ理由もないと思うし、まあいいんじゃないでしょうか。逆に、シビアな環境の場合は気にする意味が出てくると思います。

Goのstructのコンストラクタ関数をコード生成するツール gosimplectorgen をリリースした

はじめに

表題のものをリリースしました。

github.com

go install コマンドもしくは go get -tool コマンドでインストールして使うことを推奨しています。現代なので go get -tool コマンドを使うのがいいと思います。

どういうツールなのか

たとえば、resolver.go というファイルに以下のようなstruct定義があったとします。各 Usecase 型はinterfaceになっており、対応する実装を何らかの方法で依存注入する必要があります。

type Resolver struct {
  user    user.Usecase
  blog    blog.Usecase
  entry   entry.Usecase
  comment comment.Usecase
}

gosimplectorgenを使って gosimplectorgen resolver.go というコマンドを実行すると、以下のような関数が resolver_gen.go というファイルに生成されます。このように、引数から受け取った値をstructのフィールドに埋めて返す関数のことをコンストラクタ関数と個人的に呼んでいます (以下、この記事内でもそのように呼びます)。

func NewResolver(
  user user.Usecase,
  blog blog.Usecase,
  entry entry.Usecase,
  comment comment.Usecase,
) *Resolver {
  return &Resolver{
    user:    user,
    blog:    blog,
    entry:   entry,
    comment: comment,
  }
}

基本的な機能はこれだけです。

以下のコマンドライン引数でコード生成の挙動を変えられます。

  • -out
    • コードを生成する先のファイル名を指定します
  • -targetTypes
    • 渡されたファイルに含まれるstruct型のうち、コンストラクタ関数を生成する対象の型名をカンマ区切りで指定します
    • 未指定のときは、ファイルに含まれる全てのstruct型を対象とします

動機

Goでstructに対してinterfaceを経由して依存注入を行う場合、なんらかの方法でstructのフィールドをセットしていくことになると思います。よくあるのが、先述したようにコンストラクタ関数 (structのフィールドを埋めて返す関数) を定義する方法です。

コンストラクタ関数は簡単に定義できますが、以下のような課題を抱えています。

  • structリテラルのフィールドの値を埋め忘れて、実行時エラーになる
  • struct定義とコンストラクタ関数の定義を両方とも更新する必要があり、二度手間である

前者はたとえばexhaustruct linterで簡単に検査できますが、後者は手書きしているうちはどうしようもありません。VSCodeのGo拡張の機能を使ってstructリテラルのフィールドを自動的に埋めることで多少緩和はできますが、それでも手書きしなければならないものが残ってしまいます。

手書きするとミスの余地があるし、なんだかんだで手間な作業ではあるので、コード生成の力で自動化してしまおう、ということでツールを作りました。

実装

サンプルコードと方針のメモ書きだけを渡してClaude Codeにだいたい実装してもらいました。本質的な実装は200行ちょっとぐらいです

これぐらいのコードであれば、Goの静的解析を多少かじっていれば手書きできると思うけど、Claude Codeにばしばし実装してもらうほうが早いですね。OSS仕草としてREADMEやコミットメッセージなどを英語で書くようにしているけど、これもClaude Codeに文言を考えてもらったので楽でした。

他のツールとの比較

golang constructor generatorで検索すると、いくつか同様のツールが出てきます。

以下の理由により、これらのツールを採用せずに自作することにしました。

  • コンストラクタ関数を生成できること
    • 自分のユースケース的にはこれさえあれば十分
  • メンテナンスされている・あるいはこれからメンテナンスしていく自信があること
    • 足りない機能やバグ修正などをすぐにリリースしてもらえると、プロダクト開発に採用しやすい
  • 外部コマンドに依存せずに動作すること
    • この条件がクリアできれば github.com/moznion/gonstructor をまっすぐ採用していたと思う

ツール名にsimpleとあるように、アグレッシブな機能拡張をする予定はなく、自分にとって必要な最小限のユースケースに絞って実装しています。裏を返すと、自分が欲しいユースケースが出てきたら機能が増える可能性があります。

おわりに

Goのstructのコンストラクタ関数をコード生成するツール gosimplectorgen をリリースしました。コンストラクタ関数を自動生成する、という最小限のユースケースに絞って実装したため、2時間ぐらいでだいたいできたと思います。

ユースケースに合う場合は、どうぞご利用ください。

時間のないサイト運営者リング