The Go Blog
Gofix のご紹介
次回の Go リリースでは、いくつかの基本的な Go パッケージにおいて、大幅な API 変更が含まれます。HTTP サーバーハンドラーを実装する、net.Dial を呼び出す、os.Open を呼び出す、またはreflect パッケージを使用するコードは、新しい API を使用するように更新しない限り、ビルドされません。リリースがより安定し、頻度が低くなった現在、これはよくある状況になるでしょう。これらの API 変更はそれぞれ異なる週次スナップショットで発生し、単独であれば管理可能だったかもしれませんが、合わせて考えると、既存のコードを更新するにはかなりの手作業が必要になります。
Gofix は、既存のコードを更新するために必要な労力を削減する新しいツールです。ソースファイルからプログラムを読み込み、古い API の使用箇所を探し、それらを現在の API を使用するように書き換え、プログラムをファイルに書き戻します。すべての API 変更が古い API のすべての機能を保持するわけではないため、gofix が常に完璧な仕事をできるわけではありません。gofix が古い API の使用箇所を書き換えられない場合、その使用箇所のあるファイル名と行番号を示す警告を出力し、開発者がコードを調べて書き換えることができるようにします。Gofix は、簡単で反復的な、退屈な変更を処理するため、開発者は本当に注意を払うべき変更に集中できます。
重要な API 変更を行うたびに、機械的に可能な限り、変換を処理するためのコードを gofix に追加します。新しい Go リリースに更新してコードがビルドされなくなった場合は、ソースディレクトリで gofix を実行するだけです。
gofix を拡張して、独自の API の変更をサポートすることもできます。gofix プログラムは、特定の API 変更をそれぞれ処理する、fix と呼ばれるプラグインを囲むシンプルなドライバーです。現在、新しい fix を作成するには、go/ast 構文ツリーのいくつかのスキャンと書き換えが必要であり、通常、API 変更の複雑さに比例します。調査したい場合は、netdialFix、osopenFix、httpserverFix、およびreflectFix がすべて、複雑さの昇順で示唆に富む例です。
もちろん、私たちも Go コードを書いており、私たちのコードもこれらの API 変更の影響を受けます。通常、私たちは API 変更と同時に gofix サポートを作成し、gofix を使用してメインソースツリーの使用箇所を書き換えます。私たちは gofix を使用して、他の Go コードベースや個人的なプロジェクトを更新します。新しい Go リリースに対してビルドする時期が来たときには、Google の内部ソースツリーを更新するためにも gofix を使用します。
例として、gofix は、fmt/print.go からのこのスニペットのようなコードを書き換えることができます。
switch f := value.(type) {
case *reflect.BoolValue:
p.fmtBool(f.Get(), verb, field)
case *reflect.IntValue:
p.fmtInt64(f.Get(), verb, field)
// ...
case reflect.ArrayOrSliceValue:
// Byte slices are special.
if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
// ...
}
// ...
}
新しい reflect API に適応させるために
switch f := value; f.Kind() {
case reflect.Bool:
p.fmtBool(f.Bool(), verb, field)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.fmtInt64(f.Int(), verb, field)
// ...
case reflect.Array, reflect.Slice:
// Byte slices are special.
if f.Type().Elem().Kind() == reflect.Uint8 {
// ...
}
// ...
}
上記のほとんどすべての行が何らかの形で少し変更されました。書き換えに伴う変更は広範ですが、ほとんど完全に機械的であり、まさにコンピューターが得意とする種類のものです。
Gofix が可能であるのは、Go の標準ライブラリに、Go ソースファイルを構文木に解析する機能と、その構文木を Go ソースコードに書き戻す機能がサポートされているためです。重要なことに、Go の印刷ライブラリは公式フォーマットでプログラムを印刷します(通常、gofmt ツールによって強制されます)。これにより、gofix はGo プログラムに機械的な変更を加えながら、余計な書式設定の変更を引き起こすことがありません。実際、gofmt を作成した主な動機の一つは、特定の括弧の位置に関する議論を避けることと並んで、gofix のように Go プログラムを書き換えるツールの作成を簡素化することでした。
Gofix はすでに不可欠なものとなっています。特に、最近の reflect の変更は、自動変換がなければ受け入れがたいものであり、reflect API は大幅な見直しが必要でした。Gofix は、既存のコードを変換するコストを心配することなく、間違いを修正したり、パッケージ API を完全に再考したりする能力を私たちに与えてくれます。私たちと同様に、皆様も gofix が便利で役立つことを願っています。
次の記事:Heroku での Go
前の記事:Godoc:Go コードのドキュメント化
ブログインデックス