Findy Engineer Lab

エンジニアの"ちょい先"を考えるメディア

Goはシンプルな言語仕様。ゆえにコーディングルールや認識の統一がさらに重要

f:id:poniki:20220127163336p:plain Goはモダンな言語として注目度が高く、採用する企業が少しずつ増えています。とはいえ、実際に使用されている割合は未だ多くありません。

そこでFindyでは、2021年12月8日(水)に「注目の言語Go、開発現場でどう使われる?活用企業の現場に聞く vol.3」と題し、6回目となる最新バックエンド井戸端会議を開催。

Goを活用している株式会社Kyashの松浦さん、マネーフォワードケッサイ株式会社の大菅さん、株式会社ミクシィの萩原さんをお招きし、実際に使ってみて感じたメリット・デメリットについて語っていただきました。

本稿では、イベント中に語られたGoの特徴や活用法についてまとめています。

パネリスト
松浦 優彦さん/@masamatsu66
株式会社Kyash エンジニアリングマネージャー
映像機器メーカー、物流スタートアップを経て、2020年06月にデジタルウォレットアプリ を提供するKyashに入社。 Engineering ManagerとしてKyashの機能開発を行うチーム3つ全てを担当。 C/C++の組込機器制御など低レイヤーな部分からPHP/LaravelのようなWFまで幅広く経験。 趣味はアウトドア全般。

Shunya Osugaさん/@garsue
マネーフォワードケッサイ株式会社 ソフトウェアエンジニア
2017年7月にマネーフォワードのグループ会社であるマネーフォワードケッサイに入社。入社以来、一貫して企業間後払い決済サービス「マネーフォワード ケッサイ」の設計・開発を担当。現在は「マネーフォワード ケッサイ」とパートナー企業様をつなぐ連携部分の開発に携わっている。

萩原 涼介さん/@raryosu
株式会社ミクシィ 次世代エンターテインメント事業本部 TIPSTAR開発部 システム2グループ マネージャー
2018年4月にミクシィ新卒入社。サロンスタッフ予約サービス「minimo(ミニモ)」のサーバサイド開発や、Web版プロダクトのディレクションなどを担当。2020年7月から 共遊型スポーツベッティングサービス「TIPSTAR(ティップスター)」で Go言語によるサーバサイド開発や運用改善などに取り組む。2021年4月から、開発速度の向上やDevOpsなどを推進するグループのマネージャーに就く。

モデレーター
大原 和人/@kaacun
ファインディ株式会社
’12年に株式会社オールアバウトに新卒エンジニア1期生として入社。サーバのクラウド移行やDevOpsの推進、サイトリニューアルの開発などを担当。その傍ら、週末に3社ほどのスタートアップの開発や立ち上げの手伝いを行う。’17年11月よりFindyに正社員1人目として参画。

「シンプルな仕様」「コンパイル」「メンバーの希望」など、Goを採用した理由は三社三様

──多数の言語がある中で、なぜGoを採用したのでしょう?

松浦さん:Kyashは創業当時からGoのみで統一していて、言語を選定したのは代表の鷹取です。彼は大手の銀行で働いており、プログラミングには縁がなかったのですが、起業するにあたり「自分自身が無知な状態では話にならない」と思い、某企業が主催しているもくもく会に参加して、プログラミングの勉強をしていました。そこで現場のエンジニアたちに話を聞いて、仕様のシンプルさや将来性を考えてGoを採用したそうです。

大菅さん:私たちの場合、グループ会社であるマネーフォワードではRubyを使っていたのですが、マネーフォワードケッサイの立ち上げメンバーにGo経験者がいました。その方が導入を推進していたのが、Go採用のきっかけですね。

最終的にGoを選んだ理由は、言語仕様がシンプルで、Rubyを使っていたエンジニアでもキャッチアップしやすく、コンパイル時の型検査があるからです。我々は松浦さん達と同じく決済サービスを開発しているので、できる限り障害を発生させたくない。動的検査のスクリプト言語では実行してみないとわからない部分も多いですし、動かす前に問題を把握するためには、コンパイルがある言語が良かったんです。

萩原さん:私が担当しているTIPSTARは、2019年に開発をスタートしています。当時はちょうどGoが盛り上がり始めていた時期でもあり、技術選定時にはRuby on RailsかGoのどちらを使うのか、かなり議論していました。

というのも、当時のミクシィ社内ではRuby on Railsが多く使用されていたんですね。ただGoとGoogle Cloudの使用について、ある程度のナレッジが社内に蓄えられていて、コミュニティーも活発だったので、長期的な視点で考えGoを選びました。裏話としては、メンバーの「Goを書きたい気持ち」が強かったのが、Go採用の大きな理由だと聞いています(笑)。

シンプルな言語仕様は一長一短。Goを上手く使いこなすコツは、コーディングの認識を揃えること

──実際にGoを使用してみて感じたメリットを教えていただけますか?

松浦さん:使っていて良いと感じるのは、シンプルな言語仕様ですね。私はKyashに入社するまでGoは未経験で、過去にはCやC++、PHP、Laravelなどを使用していました。入社当初は業務のドメイン知識などを覚えるのが大変だったものの、Goのキャッチアップで苦労することはほとんどなかったですし、学習コストの低さはGoの大きなメリットだと感じています。

大菅さん:Goは学習コストが低い分、継続的に開発してメンテナンスをするのに適していますよね。特定の少人数で開発するとか、スポットで実行するだけのパッチを書くとかであれば、Goにこだわる必要もなく、自分たちが一番得意な言語で開発する方がいいと思います。開発するものにもよりますが、複数のエンジニアが集まり入れ替わりでチーム開発する場合には、Goがおすすめですね。

またGoogle Cloudを使うためのライブラリが揃っていて、品質が高いのも嬉しいポイントですね。設定さえしておけば、標準で分散トレーシングのようなものも取れます。Googleの言語だからかサポートも手厚いですし、Google Cloudを使う上ではGoがベストな選択でした。

静的型付け言語と比べてビルドが速いのも魅力です。ビルドの速さは開発効率と生産性に直結するものだと思いますし、Goが支持される理由の一つなのではないでしょうか。

松浦さん:ScalaとかJavaScriptを使っている方であれば、いい意味で衝撃を受けますよね。

──萩原さんはいかがですか?

萩原さん:大菅さんが仰ったように、Google Cloudとの親和性の高さはメリットです。TIPSTARではサービスを開発した当初、MySQLを使っていて、途中でSpannerへ移行した経緯があります。SpannerはRubyでもサポートされているんですが、Goの方が細かいバグのようなものが少なく、移行もスムーズでしたね。

あとはお二人がお話しされていたように、言語の学習コストが低い。私はもともとPerlで書いていたのですが、Goでもすぐに書けるようになりましたし、最終的には型があるので何とかなると言いますか。

──シンプルな言語仕様とビルドの速さ、Google Cloudとの親和性がメリットなんですね。逆にデメリットはどんなところなのでしょう?

松浦さん:Ruby on Railsのようにリッチなフレームワークがあるわけではないし、チーム内でコーティングルールをある程度決めるか、輪読会などで擦り合わせをしておかないと、各エンジニアによってコードにバラツキが出てしまうのは、デメリットだと言えるかもしれませんね。

萩原さん:その辺りは難しいところですよね。私たちはコーディングルールをドキュメントにまとめていて、それを読み込んだメンバーがコードレビューすることで全体に浸透させようとしています。ただ、メンバーの増加に伴いプルリクエストも増えていくと、 必ずしもコーディングルールを理解しているメンバーがレビューするとも限らない。今後どうしていくかは、議論をしているところでもあります。

──悩ましいところですね。大菅さんはこの辺りをどのように解決するのがいいと思われますか?

大菅さん:教科書のようなものがあるわけではないですし、やはりレビューなどで醸成するものなのかなと思っています。

私たちの場合は、輪読会などで基本的なドメイン駆動設計を学び、実装前の設計段階でビジネスメンバーも含めて「何を作ろうとしているのか」について理解を深めるようにしています。表現したいことを正確に理解できていれば、コードのバラツキなどは生まれにくいのかなと。

エンジニアメンバー内にドメインエキスパートがいるケースはあまり多くないと思うので、いかに他部署のメンバーを巻き込んで開発を進めるかが重要だと考えています。

ライブラリのバグで障害発生。「ゼロ値の扱い」は、Go特有の難しさ?

──Goを使用していて苦労したことはありますか?

松浦さん:非同期的な処理をする上で、SQSを通した非同期実行をメインとしているものの、Goにはジョブワーカーのようなシステムを管理する良いものがないんですよね。管理ツールを自作する必要があったのは、なかなか大変だったなと。

あとは決済障害が発生した際も大変でした。一般的なDBでは、テーブルを作るときにcreated_atなどがあり、TIMESTAMPの面倒を見てくれるのがO/Rマッパーのいいところですよね。しかし、当時使用していたGoのO/RマッパーであるGORMにバグがあり、リファクタリング時にcreated_atが00:00:00で更新されてしまいまして……。さらにcreated_atに依存した処理が決済にまで繋がっていたので、結果的に決済障害を引き起こしていまいました。

テストをした時に「おかしいかも?」と気がついたのですが、決済に影響を及ぼすとは思っておらず「修正できるから大丈夫だろう」と動き出した結果、恥ずかしい障害を起こしてしまったエピソードですね。

──なるほど。当時はまだそのようなバグがあったんですね。

萩原さん:TIPSTARでも似たようなことがありました。Structタグを用いて制約をつけることができるValidatorパッケージがあって、例えばrequiredと書いたら値が必ず存在することをバリテーションしてくれるんですが、あるタグがついているときに、ゼロ値は許容されないんです。それを見落としていたことがあり、0になりうるカラムにrequiredをつけてしまっていて、本番環境でエラーが出る障害を起こしたことがあります。

松浦さんのお話を伺っていて、ゼロ値の扱いについては、Goの難しいところなのかもしれないなと思いました。

それ以外でいうと、RustのようにResultがないのは少し不便だと感じています。Goでは関数の一般的な型として、オブジェクトのポインタとエラーオブジェクトを返す形にすることが多いと思うのですが、稀に、返すべきオブジェクトもエラーオブジェクトも nil として返すような実装をしてしまうことがあるんです。エラーがnilで、返すべきオブジェクトもnilを返している場合があり、ハンドリングが難しいなと感じています。特定のユースケースに対してはうまくハンドリングできるのですが、全く実装を知らない人がある関数を使った時に、ハンドリングできていないといったケースが起きることがありました。

対策としては「エラーオブジェクトを返して対応しましょう」と啓蒙活動をしたり、Linterでwarningを出す実装パッケージを作ってLintを回したりしています。

大菅さん:値の有無をどう表現するかについては、Goエンジニアの中でも流派が別れるところかもしれませんね。

──大菅さんは、Goで苦労したエピソードはありますか?

大菅さん:エピソードと言いますか、苦労しているところでいうと、Goはシンプルな言語仕様がメリットでもありますが、他の言語と比べて表現力があるわけではないので、コード量が増えてしまうのは大変なところではありますね。解決方法としては、コード生成系のツールを使ったり、自作したりしているケースが多く、私たちは後者で対応しています。

とはいえ簡単に作れるものではないですし、コード生成をすることでGoのシンプルさを損なうことにも繋がるので、バランス感覚が必要な部分です。

──質問で「メジャーなモック生成、コード生成のツールはありますか?」と来ていますね。こちらについてはいかがですか?

大菅さん:モック生成であれば、gomockが一番メジャーだと思います。コード生成であれば、ASTパッケージがおすすめですが、最初はとっつきにくい可能性もある。単純にコードを組み立てるだけであれば、Jenniferを使ってコード生成ツールを作るのもいいかもしれません。加えてお話しすると、2022年にGenericsが導入されるので、上手く使いこなせれば、コード生成に頼らずとも良くなるのではないかとも考えています。

私たちは、社内のプロダクト開発で使用しているユニットテストを書く時のテストデータ用のファクトリー関数群を自作のコード生成ツールで吐き出しているのですが、そんなに使いやすいものではないので、Genericsが導入されたら真っ先に書き換えたいと思っています。

──Genericsを使えば、書くコード量が少なくなるようなイメージなのでしょうか?

大菅さん:手書きしていた部分を関数一つで処理できるようになると思うので、活用できる部分は多いと考えています。

Goを使用するなら、セキュアな開発に取り組むことが重要なポイント

──「エディタは何を使用されていますか?」という質問も来ています。

松浦さん:たまにvimやEmacsを使うこともありますが、ほとんどGoLandを使用していますね。

大菅さん:私もGoLandですね。もともとはvimを使っていてVS Codeに移った後、GoLandに辿り着きました。

萩原さん:同じくGoLandを使っています。チームメンバーの中にはEmacsを使用しているエンジニアもいますね。

──GoLandが人気なんですね。続けて「おすすめの教材を教えてください」という質問も来ています。こちらはいかがですか?

松浦さん:教材ではないのですが、Goを学習するなら最初に「A Tour of Go」を読んで、その後は実際に使って知見を蓄えていくのがいいのではないでしょうか。

大菅さん:私は教材がない時代に使い始めたので、パッと出てこないですね。最近ではO'Reillyから、いくつか書籍が出ているようです。

萩原さん:おすすめの教材が何かと聞かれると、確かに出てこないですね。私の場合はTIPSTARのコードを読んだ上で「A Tour of Go」を見て知識を定着させました。既にあるコードを読み書きするのが、一番効率のいい学習方法なのではないかと思っています。

──ありがとうございます。最後に、今後Goで挑戦したいことや展望があればお話いただけますか。

松浦さん:(Goというよりアーキテクチャの話ですが)様々な技術的負債があるので立ち向かっていきたいと思っています。例えばかつてモノリシックに作っていたものをマイクロサービスに分割していくことが挙げられます。

とはいえ特にDBを後から分割するというのは容易ではなく、特に決済や残高の管理に関わる部分は剥がすのが難しいので、今後はマイクロサービス化をいかに進めるか議論していきたいと思っています。

──大菅さん、萩原さんはいかがですか?

大菅さん:リモートでビルドするケースにおいて、依存しているライブラリがアタックを受けて不正なコードが入ってしまい、本番環境のデータを抜かれてしまうとか、CIの最中にコードをどこか別のところに通してしまうとか、Node.js周りでサプライチェーン攻撃されたケースをよく聞くので、そこはなんとかしたいですね。

セキュリティDBと照らし合わせて問題がないか認証できる機能がパッケージツールに入る予定なので、そういったものを積極的に使い、セキュアな開発に取り組んでいきたいと考えています。

萩原さん:TIPSTARでは、アーキテクチャを改善して、変更容易性と可読性を向上させ、よりスピーディなユーザへの価値提供に努めたいと思っています。

──Goは活用事例が少ない分、最適解を手探りで探していくところがあるものの、シンプルでキャッチアップしやすく、挑戦しやすい言語であることがわかりました。松浦さん、大菅さん、萩原さん、本日はお時間いただきありがとうございました!