Go言語用のObject mapper generatorを書いた

Go言語で構造体と構造体をマッピングする、いわゆるObject mapperを生成するCLIを書きました。

経緯

READMEに書いてる通りですが、いわゆるClean architectureなど多層構造のアプリケーションではどうしても似たようなオブジェクトを定義せざるを得ないことがあります。

特にキツい(?)のがgRPCを採用した場合ですね。 protocが吐く構造体は完全にprotobufに依存したものになっておりある程度層をまたいで同じオブジェクトを持っていくのは許容しよう、と割り切ってもこれをいわゆるドメイン層にそのままもっていくのは結構ハードルが高いのではないかと思います。

#あと、gogo/protobuf 亡き今、protoc-gen-goが非標準命名規則でソースコードを出力するのもキモチワルイ。。。

WEB上にいっぱいあるGo + gRPCのクリーンアーキテクチャサンプル的なものでもここはかならず似たオブジェクトに詰め替えています。GoにはJavaにおけるDTOのような歴史はあまりないですし、アーキテクチャ上必要なことなんだから手で書くべき、という人もいますがとはいっても項目数が多くなってくるとつらいですよね。

これをある程度自動で詰め替えるライブラリはリフレクションを使ったものはそれなりにあるのですが、経験上

  • リフレクションを使ったものはデバッグがつらい
    • 項目が多くなってきたときに、1つだけなんかマッピングされてない!というときになんでマッピングされてないの? というのがわかりづらい
  • 性能が微妙
    • いくらGoのリフレクションが早いといってもリフレクション使わないコードよりは当たり前だが遅い

ということで、コード生成してくれるタイプのものが欲しかったんですがいいのが無かったので書いた、という次第です。

できること

構造体と構造体をマッピングするインタフェースと実装を生成できます。マッピング定義はYAMLに記載、結構柔軟に定義できます。 ネストしたものも再帰的にマッピングできます。

  • 例: stringtime.Timeをマッピングするものを登録しておけば自動的にこれらのフィールドを持つ構造体を変換可能

比較的にきれいな(自分的には)インタフェースを吐くので最悪、このツール使うのやめようとなってもインタフェースに対する実装を自分で書けばよいだけです。生成するソースはこんな感じ

 1package mapper
 2
 3import (
 4    pkg00002 "time"
 5
 6    pkg00001 "example.com/testmod/domain"
 7    pkg00000 "example.com/testmod/model"
 8)
 9
10type TodoMapperHelper interface {
11    ModelToEntity(*pkg00000.TodoModel, *pkg00001.Todo) error
12    EntityToModel(*pkg00001.Todo, *pkg00000.TodoModel) error
13}
14
15type TodoMapper interface {
16    ModelToEntity(*pkg00000.TodoModel) (*pkg00001.Todo, error)
17    EntityToModel(*pkg00001.Todo) (*pkg00000.TodoModel, error)
18}
19
20// ... (TodoMapper default implementation)

Goでの構造体のマッピング、結構どうにかしたいと思いつつとりあえず全部手でやってました、という人も多いと思うのでもしよければ使ってみてください。

comments powered by Disqus