- 既存顧客へのアポイント業務
- 【SaaS】インサイドセールス
- 機械学習エンジニア
- Other occupations (5)
- Development
- Business
- Other
2021年11月13日(土)に開催された、Go Conference 2021 Autumnにて、ミイダスは"Go"ld スポンサーを務めさせて頂きました。
また、「Goで開発したサービスを6年間運用した"しくじり"」というタイトルで、弊社の磯崎が発表をしました。
転職サービス「ミイダス」ではリリース当初からGoを採用し、現在運用6年目です。この間にやらかしてしまったこと、いまも残っている課題についての事例を共有しました。
イベント詳細ページ
https://gocon.jp/2021autumn/sessions/sponsor-miidas/
発表の動画
https://youtu.be/EVUCSrj83uM?t=1002
Goによるサービス開発6年のしくじり
ミイダスのサービスは7年目に突入しました。Goでスクラッチで作っていて、順調に成長しているサービスです。本日はこんなこと「やってしまった」という内容を具体的に紹介していければと思います。よろしくお願いします。
私は磯崎勢と申します。SI会社でしばらく働いた後、6くらい前にミイダスの立ち上げに参画しました。初期から現在までバックエンドエンジニアとしてやっています。
Goの経験も6年、今7年目になります。
それでは次にミイダスのサービスを簡単に紹介させてください。
ミイダスは転職をサポートするサービスです。
今のユーザー数は73万人で、利用ユーザーも徐々に伸びてきます。
入社後の活躍を目的とした「アセスメントリクルーティング」で適材適所の採用を実現します、とありますが、転職斡旋して終わり、というサービスではなく、転職後の活躍も含めて、本当にその人にとって良い職場をサポートできたら良いな、というコンセプトで開発しています。
「転職後の活躍をどうやって測るのか?」
このように思われるかもしれませんが、
ミイダスにはコンピテンシー診断という機能があって、200問くらいのアンケートに答えると、図の右側にあるような「パーソナリティの特徴」が分かります。色々な切り口で診断してくれる機能となっています。
ここにはバイタリティー、チームワーク、人当たりなど書いてありますが、こういうデータがミイダスには30万以上今集まっている状態です。
今回はその中でもGoのエンジニアはどういう特徴があるのかな、というのを調べてみました。
Go経験者の特徴
特徴その1として、問題解決力が高いという傾向がありました。
7.2とありますが、これは10点満点で平均が5.5になるように調整されている数字です。7.2は相当高い数値になっていますね。ITエンジニア自体、高めの傾向があるのですが、Python, PHP, Javaの経験があるエンジニアよりも高い数値を出していたので、すごいなと思いました。
ただ問題解決力だけでいうと、R言語だけを使ったことがある人や、BIツールを使ったことがある人の方がさらに高い数値を出していました。
次に、人当たりという項目です。こちらは4.7という数字でした。
ミイダスには2000弱のスキルがあり、営業、事務、企画、専門職を含めてかなり網羅率が高いマスターを作っています。4.7という数字はそこまで低くないかなと思っていたのですが、その全てのスキルの中でNo.1に低い数字だったので驚きました。
人当たりという項目は、人当たりが悪いというわけではなく、自分の意見をちゃんと主張できるという意味になります。Goのシンプルな仕様がこういう思考にさせる傾向にあるのかな、と考えると面白かったので小ネタ的に共有させていただきました。
ミイダスのデータには、Goの経験者は300人以上居たのですが、そもそもミイダスのエンジニアの率が高いかもしれないと後から気付いてしまいました。ミイダスのエンジニアが実はこの数値を下げているのではないのかな、という気も少ししますね(笑)
このデータ自体はサクッと取ったものなので、先ほどお伝えした言葉通りに受け取って欲しくないという部分もあります。(実際にはデータ分析の専門チームが解析しています)
ただ、このようなデータを基にして適材適所な働き方をさせていこうというサービスになっているので、面白いなと思いましたらミイダスに登録して診断してみてください。
バックエンドはほぼすべてGo
ミイダスの開発のバックエンドは、ほぼすべてGoで書かれています。
スクラッチで0から作っていて7年目に突入しました。トータルで35万行、バックエンドエンジニアは20名以上が在籍しています。
これまでの6年間に、色々とやってしまったことや、「他のサービスはどうやっているの?」といった論点をこれれから紹介していきたいと思います。
ミイダス 前提その2
初回リリースは突貫で作り仕様書もテストもない状態でした。またビジネス都合でピボットも何回もしているのですが、現在の売り上げは数十億の規模に成長しています。
ですので、Goでサービスを立ち上げるというところから成長フェーズにいるような方に参考にしていただけると幸いです。
フレームワークや開発のルールなど、広く浅く色々とご紹介していく予定です。
開発環境
フレームワーク
フレームワークについてですが、最初の頃は自作で作っていました。6.7年前はフレームワークを使わずに、自分達でhttpサーブを書いていました。これはこれで結構面白かったのですが、今は使わない理由がはっきりとないかなと思います。
今はechoを採用し全部差し替えています。
orm
gormというライブラリを使っているのですが、これは6年前から変わっていません。今だともっと選択肢があると思いますが、クエリビルダもしっかりしていますし、デバッグもやりやすいので、このライブラリは気に入っています。
Validation
APIのリクエストなどを構造体定義し、タグをうってValidationをかけています。カナチェックなどを拡張したりして使っています。
もともとJava出身のエンジニアが多く、アノテーションなどのメタプログラミングが好きでやりたい気持ちがありましたが、Goのタグに関してIDEのサポートが弱いので、あまり複雑なものを組むべきではなく、シンプルな単項目チェックだけに留めているという使い方をしています。
こういう割り切りは、結構良かったのではないかなと思っています。
APM
APMはNewRelicを最近使っています。これは建て付けの良い言語だと、導入するだけで色々なモニタリングができてとても良いです。しかし、Goの場合は、Aopの構文がないという点だからなのか、必要なところに多くのコードを書くことになり、逆にコストがかかってしまっている懸念があります。
結局コンテキストを書いていくということになるのですが、6年前はコンテキスト自体なかったので、全部やりたい気持ちにはなるのですが、今の所は優先度が低いと思っています。
また、Goroutineのリークに気付いたりと、良いところはありましたが、運用に乗ったばかりなので、導入してよかった点は、まだ良く分かっていないというのが正直なところです。ただ、導入時には気をつけたほうが良い点は色々とありますね。
開発ルール
次は開発ルールについてです。これに関しては、色々とやらかしてしまった事があるのですが、順にお話ししていきます。
const
最初に、業務定数用のパッケージを作ったのは結構失敗したなというポイントです。あとは定数をGoのルールに従わず、全部大文字にしてました。
最近はパッケージごとにGoの標準ルールで定数も書いていくことにしたので、落ち着きましたね。機能ごとでパッケージを切るとか、機能ごとの参照関係をきちんと定義しておかないと循環してしまうとか、そういう問題もあるので、最初によく考えてから作れば問題がなかったのにな、と思っています。
type
モデルの状態をEnumで定義することはよくやっていたのですが、userIDなどの数値項目は、intを使って定義をしていました。そこからtype UserID int のような型を定義するルールに変更しました。
これは、取り違いの事故が起きていたわけではないのですが、一度書いてしまえばそれほど面倒でもないし、安心感もあってこれは良かったなと思っています。
Panic
業務の中で実行時ErrorをErrorでやりとりしない(panicを使う)と紹介していますが、これはデータベースの接続エラーのようなものを実行時Errorと呼んでいます。
このpanicを使うことで、Goっぽくないと社内で言われたりすることもありましたが、個人的には業務のロジックをシンプルにするのであれば、これを両方Errorとして扱うのは結構辛いなと思っています。
建て付け上は業務の外にはpanicを出さないでね、というルールで運用しています。今の所これで良いと思っていますが、他の皆さんはどのようにしているのか、少し気になる所です。
interface
フレームワークレベルでは結構使ってはいるのですが、業務ロジックでもinterfaceを作ったほうがいいのではないかという議論が少しあったりもします。
基本的に業務の共通部分はかなりあるのですが、それでも使わないでほしいなと思っています。少なくともオブジェクト指向言語のように気軽には作らないですし、関数を引数に取るだけで解決すると感じることが多いです。
良し悪しだとは思いますが、単体テストのためだけにInterfaceをいっぱい切るというのは、Goっぽくないのでやめようという話を内部ではしています。
go routine
開発の初期の頃は簡単に並列処理をかけるのは、Goのメリットということで軽い気持ちで使っていました。
性能に問題があった時に暫定的にすぐに対応できるという点がメリットですね。ちなみに、ミイダスの一番重たい処理だと10並列でCPUとDBを使うAPIがあったりします。
また、色々と良くないこともあって、性能改善をしようとすると多重度を上げるだけのPRが飛んできたり、並列で動かしてエラー処理がバグっていると地獄になったりなどあります。ちょっとバグっているだけで大量のリソースを取ってしまったりするので、リソースが読めないというのが結構デメリットとしてはあるかなと思います。
さらに最近インフラの方がGoの実行ファイルをECSで動かしたり、Dockerで多重度をコントロールするなどの取り組みをしているので、Goroutineをあまり使わない方が良いのではないかなと思ってきています。
データベースがネックになっているのであれば、尚更使うべきではないのではと思っています。
最近はアプリケーションサーバーのCPUやメモリに処理を転嫁できるように設計を変更中です。そうなるとGoroutineのメリットが出てくるのではないかなと思っています。
template
ミイダスではメールにだけしか使っていないのですが、これはとにかく書くのが辛くて、評判が良くないですね。go:embedで多少マシにはなったという話も聞きますが、そもそもメールをリッチにしない方が良いのではないかなと思っています。
リッチにしたい人が多く非常に困っているので、何とかならないかなと思っているところです(笑)
開発プロセス
次は開発プロセスに関してです。
最近Goを始めた方は知らないかもしれないのですが、6年前はライブラリ管理はGoに標準で入ってなくて、venderディレクトリとか色々とやっていました。今go.modでいい感じになっています。同じようなライブラリが複数入ってしまう、ライブラリの更新をどのタイミングでするかなど細かい問題はありますが、概ねいい感じにはなっているかなと思います。ライブラリの更新に関しては、有料のサービスがあったりとかなのですが、今の所はエイヤでやっていますね。
go generate
GoでAOPやメタ言語が弱いのは、これでカバーしようと当初考えていました。しかし廃れてしまったので、今はあまり気にしていなく、すごく良い使い方があればぜひやりたいと思っています。
astの利用
astの利用に関しては、コーディングルールで機能の跨ったiimportをしない、というのがあるので、それをチェックをする為に使っています。
GitHubのリポジトリを分ければ良いのではという話もありますが、リリースやチーム編成の都合上、GitHubのプロジェクトは1個で運用しているので、今の所はこういうツールで制限をかけています。
URL設計
これはあまりGoとは関係ないのですが、一時期RESTっぽいURLで作っていたのは黒歴史になっています。。
利用者のロールがいっぱいあるようなサービスで、同じリソースのURLにするのは、良くなかったなと今は考えています。
API仕様書
私たちは仕様書と名のつくものは基本作っていないのですが、Swaggerでやりとりしている人たちが一定数います。ルールとして「メンテナンスはしない」と。
個人的にも仕様書は必要ないかなと思っているのですが、仕様書があることによってすごく良かったということがあれば別ですが、今の所は困っていないので問題ないと思っています。
go test
go testについては、こちらのスライドに色々書いていますが、やっていませんということを書いています。
やっていないので語るべきことはないのですが、今後うまく導入していきたいと思ってはいます。今は、データベースをどうするのか、テストのためだけにコードを冗長にするのとかは嫌だ、とか開発組織内で合意が取れていないという感じです。
発表は以上となります。
としくじったというよりは、余計なことを結構やってしまったなと思うことの紹介になりました。今となってはカバーできているところも結構ありますし、ビジネスのスピード感とかに合わせてうまく変えていくこともできたと言えるかなと思っています。
これらの細かい課題を解決する為に、Goでも全部入りのフレームワークが出てくるのかな?という気持ちもありますし、今のシンプルなライブラリを色々と組み合わせていくのも楽しいので、どうなっていくのか楽しみに思っています。
最後に
ミイダスでは業務委託を含め50名ほどGoエンジニアを採用してきました。
経験者はほぼなしで、PHPエンジニアやJavaの経験者の方に入っていただいているのですが、Goが分からないのでやめます。といったエンジニアはゼロでした。
もちろん色々な事情でやめた方はいるのですが、言語の仕様的に取っつきやすさがあって、新しいことにチャレンジしたいとか、そういう技術を身に付けたいというエンジニアに参画してもらい、トータル的に非常に上手くサービスを開発することができました。
以上となります。ありがとうございました。