こんにちは。転職ドラフトでエンジニアをしている @verdy_266 です。
今回は、昨年末から取り組んでいた「指名禁止企業設定」のリニューアルについて、要件定義や実装で悩んだことが多くあったのでまとめます。
転職ドラフトでの仕事の進め方について、参考になれば幸いです。
指名禁止企業設定とは
指名禁止企業設定とは、ユーザーが特定の企業に対し、レジュメなどの情報を非公開にする機能です。前職や現職の会社を登録するケースや、以前に接触があったので関わりたくないという企業を設定することがほとんどのようです。
前職や現職の会社を登録するケースが多いことから、まだ転職ドラフトに登録していない企業も指名禁止できるようにしたいというニーズがあり、従来は「指名禁止ワード」を設定してそれに一致する企業が指名禁止になるような仕様になっていました。「株式会社リブセンス」を指名禁止にしたい場合は、指名禁止ワードとして「リブセンス」を登録するといった具合です。
しかし、この仕様だと、名前は似ているが関係のない企業が勝手に指名禁止になってしまうという不都合がありました。「株式会社ほげほげ」と「株式会社ほげほげシステム」があったとして、前者のみを指名禁止にしようと指名禁止ワードに「ほげほげ」を設定しても、両方とも指名禁止になってしまうのです。
そこで、ユーザーが設定した指名禁止ワードではなく、ユーザーが指名禁止にした企業の情報を直接DBに保存したいというニーズが生まれました。
要件定義
当初検討していたのは、以下の2つの方針です。
- 企業マスターを購入し、バイネームで指名禁止企業を設定できるようにする:転職ドラフトに登録されている企業は世の中のごく一部なので、わざわざ企業マスターを購入するのはもったいないという懸念があります。
- 従来の指名禁止ワードをベースとした指名禁止に加え、意図せず指名禁止になってしまった企業を指名許可できるようにする:ユーザーは指名禁止リストを定期的に見直す必要が出てくるほか、UIやテーブル構造が複雑になるという懸念があります。
どちらもそれほど良くないなあと思っていたところに、国税庁の法人番号APIが利用できるという情報を得ました。
これを利用することで、企業マスターを購入する必要もなければ、UIやテーブル構造が複雑になる懸念もありません。
ただ、転職ドラフトに登録済みの企業との対応をとるには法人番号をキーとする必要があるため、社内のメンバーに協力いただいて、すでに登録済みの企業の法人番号を全てDBに入れてもらう必要がありました。
悩んだこと
企業名は一意ではない
このタスクに取り組んでいて初めて知ったのですが、企業名って重複が許されているんですね。そのため、検索結果として表示する項目を企業名のみとしてしまうと、指名禁止にしたかったのがどの企業なのかを判別することができません。
他社のUIを参考にすると住所を併記している例がほとんどだったことや、前職や現職を指名禁止にするユースケースにおいては住所があれば判別可能なのではということから、住所を併記することにしました。
法人番号の登録を自動化したかったが……
法人番号をしらみつぶしに入れる作業は大変なので、バッチを作って省力化しようとしました。
- 企業名で国税庁のAPIを検索し、候補を取得する
- 出てきた候補のうち、DBに保存されている住所と一致したものを特定する
- その候補の法人番号を取得し、DBに保存する
しかし、2 で住所の正規化がうまくいかず、あまり効果的な実装になりませんでした。郵便番号の有無、スペースの有無、ビル名の有無、漢数字をアラビア数字に直すと「六本木」とかが困る、などなど。図らずも住所の正規化の大変さを体験する結果になりました。
モック作成の話
仕様策定の話がほとんどになってしまったので、ここらで実装の話もいくつか。
国税庁の法人番号APIにアクセスするためのクラスとして KokuzeichoApiService クラスを作成しており、このクラスのインスタンスメソッドの返り値をスタブしてテストを書きたいと思っていました。
RSpec.describe SomeModelUsingKokuzeichoApiService, type: :model do describe '.some_method' do before do kokuzeicho_api_mock = KokuzeichoApiService.new allow(kokuzeicho_api_mock) .to receive(:fetch_by_corporate_numbers).with(['1234567890123']) .and_return( [{ name: 'ONE株式会社', corporate_number: '1234567890123', address: '東京都港区' }] ) end it 'fetch_by_corporate_numbers を使ったテスト' do # KokuzeichoApiService.new.fetch_by_corporate_numbers(['1234567890123']) を使ったテスト end end end
しかしこうすると、スタブしたはずの fetch_by_corporate_numbers が実行されてしまいます。
この場合、 .new
をスタブしなければいけないことを学びました。
RSpec.describe SomeModelUsingKokuzeichoApiService, type: :model do describe '.some_method' do before do + kokuzeicho_api_mock = instance_double(KokuzeichoApiService) + allow(KokuzeichoApiService).to receive(:new).and_return(kokuzeicho_api_mock) - kokuzeicho_api_mock = KokuzeichoApiService.new allow(kokuzeicho_api_mock) .to receive(:fetch_by_corporate_numbers).with(['1234567890123']) .and_return( [{ name: 'ONE株式会社', corporate_number: '1234567890123', address: '東京都港区' }] ) end it 'fetch_by_corporate_numbers を使ったテスト' do # KokuzeichoApiService.new.fetch_by_corporate_numbers(['1234567890123']) を使ったテスト end end end
こちらのブログがとても参考になりました。ありがとうございました。
リリース方法
リリースの段取りとしては、以下の流れを想定しました。
- 従来の指名禁止データから新しい指名禁止データを生成するバッチをリリースし、実行する
- 新しい指名禁止設定パーツをリリースする
- クエリを実行して 1. での移行漏れが存在するかどうかを確認し、存在する場合は 1. のバッチを再実行する
- 従来の指名禁止企業設定で使用していたメソッドなどのお掃除をする
今回のリリースで、指名禁止企業の設定方法だけでなく、保存先のテーブルも変わる結果となったため、上記 1. でバッチを実行してから 2. でパーツをリリースするまでの間に従来のUIで指名禁止ワードを登録されてしまうと、移行が漏れてしまうケースが想定されました。そこで、移行漏れをチェックするクエリを作って実行し、確認を行うフローとしました。
最終的に
この件について相談を受けてから8ヶ月、合わせて27個ものPRをリリースすることができました!
PRの個数がすごいことになっていますが、1つ1つのPRを小さくすることは常に意識していました。
この機能をリリースするにあたって、依頼者との相談を綿密に行いながら、「こういうケースは考慮できてないのでは?」「これだとちょっと使いづらいのでこうしたほうが良さそうですね」などといった提案もさせていただき、エンジニアとしてもやりがいのある実装となりました。
今後も、転職ドラフトを良いプロダクトにしていくために力を尽くしていこうと思います!