2017年1月4日水曜日

規模の大きい本番システムをGo言語で書き直した感想

I quoted it for studying
勉強の為に引用しました。


1 comment | 0 points | by Jshiike 約3年前




 Jshiike 約3年前 | ▲upvoteする | link
Go言語の4周年をテーマにしたgolang.orgのブログで紹介されていた、GoogleのMobile Web Performanceチームに所属するMatt Welshのブログです。大規模な本番システムの作り直しにGo言語を採用した経験を語っています。



1) 背景


C++のオリジナルのコードベースは問題なく作動していたが、何年も複数の目的の違うプロジェクトで共有されていたため、スピーディーに改修するのが難しくなっていた。(何のシステムなのか具体的に書いてないのは残念。。


イメージフォーマットをトランスコードするライブラリはC++で完璧に動作していたので、そのまま残し、それ以外を全てGo言語で書き直した。


元のコードベースの20%を利用すれば機能としては十分だとわかり、コアロジックの大胆な改修にも手をつけたかった。


2) Why Go?


当初不安だったことがいくつかあった。この本番システムは、ユーザとそのコンテンツの橋渡しの役割をもってるので、早くなくてはいけない。また、大量のクエリを扱うのでCPU/メモリ効率が鍵となる。Go言語がガベージコレクタに頼ってることは、メモリ容量のコントロールに苦労するのではないかという不安を抱いた。このシステムでは依存関係が多いので、C++で完成しているたくさんのライブラリを全部Goで書き直さなくてはいけないことも負担であった。


しかし、コアシステムをGo言語で書き直す最初のコードを見たとき、優秀なエンジニアが1週間以内でやった作業であったが、Go言語の可読性に感心した。C++の場合、数十のソースファイルにまたがった非同期コールバックのチェーンが、goroutineのおかげで、数百行のコードで一つのファイルにまとめることができた。また、HTTP/URL処理/ソケット/暗号化/日付 & タイムスタンプの処理/データ圧縮など、web開発に適した標準ライブラリが揃っている。しかも、コンパイル言語なので処理が早く、これは大型のプロジェクトではメリットが大きい。Goのモジュールデザインでは、コードがモジュール間でうまくわかれ、依存関係がわかりやすい。


3) Being terse


長い変数名で何行にも渡ってコードを書くのに慣れていたので、Go言語の簡潔なスタイルに最初は戸惑ったが、結果、可読性があがり、スピードアップしたので感謝している。雛形構文をたくさん書かなくてもいいし、C++のようにヘッダーファイルとccファイルにロジックを分けなくてもよい。また、Javaと違って、コンパイラーが推察できるもの(変数のタイプとか)を何でも書いたりする必要がない。Pythonのような簡潔なスクリプト言語を書いてる感覚で、タイプセーフを実現できます。


最終的には、Go言語で、21,000行、121ファイルのコードベスになった。オリジナルのC++は、460,000行、1,400ファイル。もちろんこの差分は、機能を一部に絞り書き直した結果であるが、機能の削減以上にコードは減ったという感覚がある。


4) What about ramp-up time?


標準ライブラリのドキュメントオンラインチュートリアルが充実しているので、C言語系の経験がある人にはすぐにキャッチアップできる。


今回のプロジェクトは、書き直しと、3 or 4 件の新機能追加で、全部で5ヶ月。新しいコードベースへの移行で生産性は大幅アップ。


5) Why not Go?


Goで苦労していることは、


まず、自分が扱っている変数がinterfaceかstructか理解してなくてはいけない。もちろんstructはinterfaceをインプリできるので、一般的には同じものと扱える。しかし、structを扱っているとき、*myStructというタイプの参照を渡されるかもしれないし、mStructというタイプの変数を渡されるかもしれない。一方で、もし単なるinterfaceを扱っていたら、それはポインタをもたない。ある意味interfaceがポインタだから。structでなくinterfaceだった場合、* をつけないで渡しているコードを見て実はポインタかもしれないと思わなければいけないことで混乱するかもしれない。


Goのタイプを推察するスタイルは簡潔なコードになるが、どのタイプの変数なのかが明示されてなければ、調べなくてはいけなくなる。例えば、foo, bar := someFunc(baz) として、もしfooとbarを操作するためにコードを書き足したいのであれば、fooとbarが何なのか確認しなくてはいけない。(IDEでできるのかも知れないが、コードを書くときにマウスを使うのはイヤ。)


また、意図せずにstructがinterfaceをインプリしてしまうことがある。structがどのinterfaceをインプリするのか明示する必要がない。これはコードにコメントを残しておくべきだが、他人のコードを読んだときに意図がわかりづらくなる。また、interfaceをリファクタリングするときに宣言されてないインプリも含めて全て確認しなくてはいけなくなる。















#golang #コーディング

0 コメント:

コメントを投稿