GoでOSS書いてみました
GoでOSS書いてみました
表題の通りこの記事では Go
で書いた OSS
である constructor
を紹介します。
constructor
constructor は Go
製のGo
のコードを生成してくれるシンプルなCLIツールになっています。 constructorはいわゆるコンストラクタ関数を生成してくれます。
コンストラクタについてはEffective Goにも書かれているので気になる方はこちらもどうぞ。
例えば struct Foo
が Bar
という stirng型のフィールドが定義されている場合を考えます。
type Foo struct { Bar string }
これをファイルに保存して、 constructor generate
を実行します。すると下記のようなコンストラクタが自動で生成されます。
$ constructor generate
で、下のような Foo
に対応したコードが生成されます。
func NewFoo(bar string) Foo { return Foo { Bar: bar, } }
constructor を使う流れ、大まかな機能はこれで以上です。
なんで作ったの
今回このOSSを書いたモチベーションはGo
の構造体を安全に new
したかったからです。ここでいう安全とはstructを使用する側は定義されているフィールドをすべて使用してインスタンス化したい。そうでない場合はコンパイルエラーになってほしい。このコンパイルエラーで検知できる状態を安全と定義しています。確認のためにベタにstructを書いた場合に置き得る想定している課題を書いていきます。例には先程の Foo
を使用します。
func main() { foo := Foo { Bar: "#main", } }
こちらは Foo
のインスタンスを作って変数に代入しています。このFoo
をインスタンス化をしているコードがいくつかプロジェクト内に存在していたとしましょう。ここで Foo
にフィールドを一つ追加します。
type Foo struct { Bar string Piyo int // <- New field }
Piyo
というフィールドを追加しました。さて、このフィールドは 0
埋めじゃない値が入っている必要がある。そういうフィールドにする必要があると仮定します。この場合各 Foo
を使っている該当コードを検知する術はありますでしょうか。grepだったりUnitTestかもしれませんね。しかしこれらは見つけるのにはいささか人に依存した方法になります。つまりミスや対応し忘れを招く可能性が大きくなります。 constrructor はこの問題の早期発見、またはどのフィールドが Required
か Optional
かの判断材料を提供できるライブラリになっています。
constructor で生成されるコードは基本はstructが持っているフィールドを網羅する形で関数が引数を取って、構造体に代入して返す関数を作ります。constructor generate
を再度実行することで Piyo
フィールドを追加したときも先程の NewFoo
の関数は引数を取る数が変わることになります。
func NewFoo(bar string, piyo int) Foo { return Foo { Bar: bar, Piyo: piyo, } }
最初からこの NewFoo
を使って Foo
をインスタンス化していた場合のことを想像しましょう。 Piyo
フィールドが増えた場合は関数の引数が足りなくてコンパイルエラーになります。つまりGo
のプログラムが実行できない明らかな間違い状態にすることができます。残念ながら 0
埋めじゃない値が入っているというロジカル部分の保障はできませんが、それでも単純な間違いを一つ減らすことができたことに価値があると思います。
func main() { foo := NewFoo( "#main", 1000, ) }
しかし、これだと初期化したくないフィールドをコンストラクタに含めたくない気持ちも、まあわかります。(実はGo
でも初期化したくないには出会ったこと無いのですが) そこでコンストラクタの対象から外せる ignore_constructor
というフィールドにつけられるタグを用意してあります。下記のように対象から外したいフィールド(Piyo)にタグをつけるだけで NewFoo
メソッドの引数から除外されます。
type Foo struct { Bar string Piyo int `ignore_constructor:true` }
func NewFoo(bar string) Foo { return Foo { Bar: bar, } }
補足
constructor を使うで3つの形式のフォーマットのファイルが必要になってきます。
.go
ファイルです。コンストラクタを作る上で.go
で書かれたstruct
が必要です。.yaml
ファイルです。どのファイルから読み込んで、どこに出力するか等の設定情報が必要です。.tpl
ファイルです。NewFoo
関数をどのように構成するかのテンプレートファイルが必要です。詳しくはtemplate
2, 3 のファイルは constructor setup
コマンドで設定ファイルの雛形を手に入れたり、テンプレートを入手することができます。
READMEもぜひ見てみてください。
最後に
最後に簡単に自分のGo
の経歴を簡単に。1年ほどiOSアプリエンジニアをやりながらGoでAPIサーバーを書いていました。つい最近の3週間ほど前からメインの業務を切り替えてiOSエンジニアからGoでAPIサーバーを書くことになりました。そこでGo
になれるようにライブラリ作ってみるか。とかそういうモチベーションもあり今回のライブラリを作りました。もしかしたらまだGo
に慣れていないところもあるのでなにか違うことがあればbannzaiあてに連絡でもください。
さて、ところで私はiOSエンジニア界隈ではOSSを作っては発表していたらいつのまにかスター乞食とあだ名がついてしまい親しみのある代名詞があります。今後はGo
界隈にもOSS
作っては発表しに行くかもしれませんね。
それはさておき、このライブラリが便利!最高!クール!bannzaiいいぞ!bannzai応援しているぞ!Go界隈へようこそ!この乞食!と思ったそこの貴方
スターください
おしまい \(^o^)/