なぜ、エンジニア採用にコードチェックを導入したのか?
最初にファシリテータの山根氏が、エンジニア採用の現状とゆめみの取り組みについて簡単に紹介した。
「最近は、技術者が人事部のミッションを持ちながら採用に関わることが増えています。どのようにしてエンジニアの仲間集めをしていくのか。候補者となるエンジニアの方には自分の技術力を正しくアピールしてもらって、最適なマッチングを図っていくのか。選考プロセスの中での最適化が重要になっています」
ゆめみでは、コードチェックを実施して、丁寧にレビューした結果を合否に寄らず一人ひとりにフィードバックするという、候補者の技術力向上につながる育成的な選考プロセスを作っており、これに挑戦したい優秀な求職者の応募が年々増えている。
続いて、ゆめみでエンジニア採用を担当している仲川氏が、「いろんな部門があり部門ごとに採用の方針は異なりますが、フロントエンドとAndroid・iOS・サーバーサイドの採用でコーディングテストを実施しています」と自社を紹介した。
では、ゆめみではなぜコーディングテストを導入しているのだろうか。
仲川氏は、5年以上前から新卒採用で、実際にしっかりコードが書けるかポテンシャルを見るためにコーディングテストを始めたと説明した。この段階では、コードを全く書けない人の足切りが目的だった。
「ただ現在は会社のブランド力が向上して応募者が増えており、応募してくださる方のレベルがどんどん上がってきています。単純な足切りだと、ほとんどの方が満点に近い状態です」
そのために、業務で必要となるコーディング力やグループ開発の経験値を見るためにコーディングテストを使っている。
コーディングテストでは、どの観点で見て何を重視するのか
現在、ゆめみのサーバサイドエンジニア採用では次のような選考フローを採用している。コーディング試験は、カジュアル面接と書類審査のあとで実施しており、機械採点による足切りのあとエンジニアがコードレビューを実施している。このコーディングテストには、ギブリーのTrackを採用している。そして、エンジニアによる一次面接のあと、代表者による最終面接に進むというフローだ。
一次面接のコストは大きい。その前にある程度絞り込みつつ、より優秀な人と面接できるようにするため、この位置にコーディングテストを入れている。コーディングテストでは、次図のポイントを重視している。
これは企業によって異なると前置きした上で、ゆめみでは業務でよく扱う領域や、チーム開発や長期メンテナンスが必要になる経験などを意識していると説明した。
「逆にそこまで重視してないのが、迅速に回答できることや特定のプログラミング言語やライブラリ・フレームワークを使えることです。効率的なアルゴリズムについても、ちょっとググったら出てきますし、ChatGPTのようなものが実用的になるかもしれません」
では、こうした重視ポイントを具体的にどの観点で見るのだろうか。
「大きく3つあって、可読性とデータ整合性・安全性、あと将来のメンテナンス性の観点で見ていきます。仕様を満たす実装力だけでなく、チーム開発や運用の経験を推し量りたいからです」
コーディング問題の難易度とレビューの粒度をどうそろえるか
問題については、Trackが用意している700問以上の問題にほとんど目を通したうえで選んでいるそうだ。難易度は、コーディングテストを実施している他の会社よりも簡単になっている。問題が解けるかどうかではなく、ちゃんとリファクタリングしたコードや、自分はこういうポリシーで書いたというコードをみたいからだ。
「難しい問題だと、どうしても書きかけのコードになりがちで、評価しにくいです。実際に動いたコード同士だと比較しやすいですが、『これはちゃんと動くはずだけど今のところ動いてない部品です』みたいなコードだと判断が難しくなります」
そのために、プログラミング経験者であればイメージがつきやすい簡単な問題を用意している。力技でも書けるし、ちゃんと書くこともできるような問題だ。難しくて手が出ない問題だと応募する気にもならないが、腕に自信があるなら「応募してみようかな」というところを狙っているそうだ。
「解答できるプログラミング言語は、弊社でレビュー可能なものを複数用意しています。学生に人気のあるPythonも入れてあります」
こうして応募された解答は、機械的な採点で足切りをしたあと、複数のエンジニアによるレビューを実施している。面接官同士で、レビューの粒度をそろえるために次図のような工夫をしている。
ゆめみでは、現在サーバーサイドのレビューを16人ほどで実施している。各プログラミング言語で模範解答と観点ごとに項目を分けた評価テンプレートを用意している。さらに必ず2名以上でレビューし、評価が難しい場合は3人目の評価を仰いでいる。
「この解答は面白そうだとか、この書き方はよくないかなといった評価の分かれる解答は、オープンな評価会で検討・共有しています。これは、私たちを含めてかなり勉強になりました」
実践コードレビュー:サンプル問題の内容は
ここでいよいよサンプル問題の解答について具体的なコードレビュー内容を解説した。問題は、サーバーサイドエンジニア応募者向けの模試である。サンプル問題は次の通り。
「対象のプレイログは、肥大化して数千行を超えることがあります。上限は特に書いていないのでメモリのことを考慮する必要があります。プレイヤー総数は1万人を超えません。また、同点の平均スコアのプレイヤーが存在した場合、rankingに同じ数字が割り当てられます。この場合、10名以上のランキングが作られます」
解答したコードは、ギブリーのビジネスサイドでプログラミングを学習しているメンバーが書いたものだという。準備しておいたテストパターンで解答を機械採点すると通過率100%となった。これで次のコードレビューに進むことになる。
実際にコードレビューしてみた
「解答コードを見ると全部で55行くらいあり関数化もされていて、シンプルに書いてあったと思います。ただコメントが記述されていませんでした」
実際の採点テンプレートとレビュー結果は次図の通り。
本セッションでは、各評価項目について実際に詳しく解説したが、本レポートでは代表的な項目に限って紹介する。まず全体的に可読性の高いコードか調べるため、メインロジックの記述内容を見た。すると、csv_info変数があるが、一度も利用されていないことが分かった。また、scores変数とplayers変数・plyayer_score変数を唐突に利用していた。
「コードをよく読むと、唐突に出てきた変数をすべて先頭行でグローバル変数として定義していました。この時点でグローバル変数に中身は入っていないので、各関数でこのグローバル変数を自由に読み書きしているようでした。おそらく最初は関数化せずに、頭から作っていって、それを処理のブロックごとに関数化したのではないかと考えました」
これは、もちろんグローバル変数の汚染につながりやすい。あるべきコードとしては、グローバル変数をすべて削除し、main()関数のなかで各関数を呼び出して、その戻り値をmain()関数のスコープ内だけで利用する形にしたい。
次は個別の関数を調べていった。ここでは、load_csv()関数の責務に注目した。すると、players変数とscores変数を返しており、それからjoin_list()関数で、この2つの値を連結したplayer_score変数を作成していた。
「このデータをよく見みると、インデックス値は同じでplayers変数はプレイヤーIDだけ、scores変数はそのプレイヤーIDの人が取った得点をリストで含んだデータでした。インデックス値が同じだけど2つの別データは、扱いづらい不安定なものだと考えています。どちらか片方だけデータを挿入すると全部ずれてしまう。そういうものがバグを生み出しやすいと思います」
load_csv()関数が辞書型でデータを返すようにすれば再度連結しなくても良くなる。次図の右下のように、プレイヤーIDに対するスコアのリストを保持するのだ。
いずれも現場でコードを書くにあたって必要となる実践的なテクニックばかりだ。本セッションのコードレビューでは、この他にも「プログラムの処理の流れが適切な粒度で分離されているか」「関数名と変数名のリファクタリング」「唐突なマジックナンバーの使用と、問題に対応した数字の使用」「ファイルI/O周りの処理」「メモリとCPUの効率」など、多くのポイントについて詳しく解説した。
ゆめみでは、このようやレビュー結果を、テキストでキレイにまとめてフィードバックするのは難しいので、評価でよかったところと改善ポイントをセットにして不合格になった応募者にも伝えているそうだ。
「もしかすると応募者によってはピンとこないところがあるかもしれませんが、『我々はこのように見ました』という内容を改善ポイントとしてお伝えするようにしています」
なお、講演後のAsk The Speakerで「合否関係なくレビューのコメントを応募者に伝えるのはなぜでしょうか?」という質問があった。
これについて仲川氏は「不合格だった場合も6カ月とか一定の期間をおいて再チャレンジできる仕組みを用意している」と説明した。コードレビューの内容をちゃんと自分で理解して、もう一度チャレンジして、そこが改善されていたらそれを評価するというのだ。
「あとは、学生さん全体への貢献といった側面もあり、こういうことをやっている会社だよと見ていただければと思います」