2011年4月16日土曜日

Go fix that **** code...

Goのユーザーとしてちょっと辟易していたこととして、開発チームがGoそのものの文法や標準ライブラリのAPIをガツガツ変更することが挙げられる。いやホントに良く変わる。発表されてからもう1年経ったけど、まだ当分安定するようには見えない。

で変更されて何が困るかというと、古いコードのコンパイルが通らなくなること。自分が書いたコードならいざしらず、他人が書いたコードのコンパイルが通らなくなってしまうと結構厄介。メンテナー次第では下手すると当分コードがアップデートされずにそのままなんてこともありうる。じゃあ自分で直そうにも、もしかしたらエンバグするかもしれないし、そもそもが面倒だからあんまりヤル気にならない。そうすると自分が使ってたパッケージが使えなくなって、でもかといって古いバージョンのGoを使う気にもなれなくて、開発に対するモチベーションが下がって…という酷い悪循環におちいる。自分は。

Gofix

そういう状況を開発チームも理解していたのか、ちょっと前にGofixなんていうツールが発表された。詳しくはRussの書いたブログを読んでもらうとして、Gofixがやってくれるのは簡単に言うと「コードの自動修復」だ。どうやら古いAPIやら文法が使われているコードを自動的に修復して、ナウいバージョンに仕立てなおしてくれるらしい。

Go fix Thrift

ということで、実益と実験も兼ねてThriftのGoコードをGofixにかける実験をやってみた。なお使用したバージョンはGoがr8131、Thriftがr1093950。

Thrift修正前

Thriftの修正前ライブラリを普通にコンパイルしようとしたら、以下のようになる。net.DialあたりのAPIが変わったせいでコンパイルが通らない。

$ make
cd thrift/ && gomake install
make[1]: Entering directory `/home/masato/lib/thrift/lib/go/thrift'
8g -o _go_.8 tapplication_exception.go tbase.go tbinary_protocol.go tcompact_protocol.go tcompare.go tcontainer.go texception.go tfield.go tframed_transport.go thttp_client.go tiostream_transport.go tlist.go tjson_protocol.go tmap.go tmemory_buffer.go tmessage.go tmessagetype.go tnonblocking_server.go tnonblocking_server_socket.go tnonblocking_socket.go tnonblocking_transport.go tnumeric.go tprocessor.go tprocessor_factory.go tprotocol.go tprotocol_exception.go tprotocol_factory.go tserver.go tserver_socket.go tserver_transport.go tset.go tsimple_server.go tsimple_json_protocol.go tsocket.go tstruct.go ttransport.go ttransport_exception.go ttransport_factory.go ttype.go
tnonblocking_socket.go:111: too many arguments in call to net.Dial
tsocket.go:137: too many arguments in call to net.Dial
make[1]: *** [_go_.8] Error 1
make[1]: Leaving directory `/home/masato/lib/thrift/lib/go/thrift'
make: *** [thrift/.install] Error 2

Thrift修正後

この状況から、まずGofixを走らせた上でmakeすると…

$ gofix .
thrift/tnonblocking_socket.go: fixed netdial
thrift/tsocket.go: fixed netdial
$ make
cd thrift/ && gomake install
make[1]: Entering directory `/home/masato/lib/thrift/lib/go/thrift'
8g -o _go_.8 tapplication_exception.go tbase.go tbinary_protocol.go tcompact_protocol.go tcompare.go tcontainer.go texception.go tfield.go tframed_transport.go thttp_client.go tiostream_transport.go tlist.go tjson_protocol.go tmap.go tmemory_buffer.go tmessage.go tmessagetype.go tnonblocking_server.go tnonblocking_server_socket.go tnonblocking_socket.go tnonblocking_transport.go tnumeric.go tprocessor.go tprocessor_factory.go tprotocol.go tprotocol_exception.go tprotocol_factory.go tserver.go tserver_socket.go tserver_transport.go tset.go tsimple_server.go tsimple_json_protocol.go tsocket.go tstruct.go ttransport.go ttransport_exception.go ttransport_factory.go ttype.go
rm -f _obj/thrift.a
gopack grc _obj/thrift.a _go_.8
cp _obj/thrift.a "/home/masato/lib/google-go/pkg/linux_386/thrift.a"
make[1]: Leaving directory `/home/masato/lib/thrift/lib/go/thrift'

こんな感じで上手く行く。スバラシイ。

Thrift修正差分

ついでにどういう差分が適用されたかを見てみる。下はdiffをとった結果の一部だけど、net.Dialのところに注目するとちゃんと引数が減らされてる。

-  var err os.Error
-  if p.conn, err = net.Dial(p.addr.Network(), "", p.addr.String()); err != nil {
-    LOGGER.Print("Could not open socket", err.String())
-    return NewTTransportException(NOT_OPEN, err.String())
-  }
-  if p.conn != nil {
-    p.conn.SetTimeout(p.nsecTimeout)
-  }
-  return nil
+       var err os.Error
+       if p.conn, err = net.Dial(p.addr.Network(), p.addr.String()); err != nil {
+               LOGGER.Print("Could not open socket", err.String())
+               return NewTTransportException(NOT_OPEN, err.String())
+       }
+       if p.conn != nil {
+               p.conn.SetTimeout(p.nsecTimeout)
+       }
+       return nil

まとめ

ということで、Thriftという実例をつかってGofixの便利さを体感してみた。こういう便利ツールが公式に提供されて、かつほとんどが自動的に修正されるのであればAPIやら文法の変更もバンバンやってくれて構わないかも。

ちなみに、Thriftが生成したCassandraへのインタフェースライブラリをGofixしてもコンパイルが通らなかったことに関しては、また別の話。これThriftのバグなのか…? いまいち追う気になれない。

0 件のコメント:

コメントを投稿