公式リクルーターの権限をリニューアルしました

こんにちは。YOUTRUSTのエンジニアのなろ(YOUTRUST/Twitter)です。

YOUTRUSTの公式リクルーターの権限機能がリニューアルされて、採用情報の管理がより柔軟になりました。

この記事では、開発に至った背景や手法などの裏側について、簡潔に記載をします。

前提:公式リクルーターとは?

まず前提としてYOUTRUSTにおける「公式リクルーター」の説明をします。

「公式リクルーター」とは、有料プランをご契約の上、自社の採用活動を行っている企業の担当者を指しています。 ユーザーの詳細ページで名前の横に「公式リクルーター」のバッジが表示されているのが目印です。

今までの権限について

公式リクルーターは、管理画面を利用することができます。

管理画面では、採用活動に有効な機能が利用できます。機能の一部を以下に記載します。

  • タレント検索
  • タレントプール管理
  • タレントの採用ステータス管理
  • AIによるタレントピックアップ
  • 採用チームメンバーの管理
  • チームメンバーの採用活動状況の管理
  • 外部サービス連携の管理

今までは、公式リクルーターの権限は「オーナー」「管理メンバー」「メンバー」の3つでした。

「採用チームメンバーの管理」の機能が利用できるかの点以外に大きな違いはなく、殆どの公式リクルーターは「管理メンバー」の権限で運用されていました。

課題について

ここ数ヶ月で管理画面の機能が増えました。

それに伴い採用情報の管理をより柔軟におこなえるようにする必要がありました。

以下に具体例を記載します。

  • このタレントの採用ステータスは一部のチームメンバーのみに公開したい
  • このタレントプールは一部のチームメンバーのみに公開したい
  • 上記2つのようなアクセス制限を管理できる権限が欲しい
  • タレントの検索とタレントプールへの追加はできるが、スカウトの送信はできないという権限が欲しい

利用場面ごとに適切に「できること」を管理できる「権限」が必要になりました。

多くの機能が増えたこともあり、再整理の目的も含めて「権限」をリニューアルすることを決めました。

仕様の整理

利用場面ごとに適切に「できること」を管理できる「権限」にリニューアルする!を達成できる仕様を考えていきます。

利用場面と重要な機能をまとめる

サービスにおいて、どのような画面や機能を遷移して採用業務を行うかを整理して、重要な機能を洗い出しました。

この「重要な機能」が権限管理の対象になります。

  • 採用チームメンバーの管理
  • タレント検索
  • タレントの採用ステータス管理
  • タレントの採用ステータスの社内メモへの管理
  • タレントプール管理
  • タレントプール内のタレントの管理
  • 候補者内のタレントの管理
  • スカウトの送信
  • 採用チームメンバーのスカウト履歴の閲覧

ただ、上記の機能のひとつひとつに対応する権限を採用チームメンバーそれぞれに設定するのは大変であり、サービスの段階を考えても機能としては過剰だと感じました。

概念を整理してシンプルにする

整理を続けていく中で「利用場面」と「重要な機能」は、採用活動における業務内容によって異なることがわかりました。

そのため「採用チームメンバー」に「役割(業務内容)」を設定して「権限(できること)」が決まるというシンプルな仕様にしました。

今回は4つの役割を定義しました。

  • オーナー:採用活動と採用チームの管理を行う
  • メンバー:採用活動を行う
  • アシスタント:採用活動の補佐を行う
  • つながりサポーター:採用活動は行わないが、つながりの支援を行う

※採用活動は多様なため、将来的には自由に「役割(業務内容)」を作成して設定できるようにしたいと考えています。

実装方針の整理

最初にRailsにおけるサンプルコードを記載します。(簡潔な説明になるように実際のものとは異なります。)

class User < ApplicationRecord
  enum role: {
    owner: 1, # オーナー: 採用活動と採用チームの管理を行う
    member: 2, # メンバー: 採用活動を行う
    assistant: 3, # アシスタント: 採用活動の補佐を行う
    supporter: 4, # つながりサポーター: 採用活動は行わないが、つながりの支援を行う
  }

  # スカウトの送信ができるか?
  def permission_send_scout?
    owner? || member?
  end
end
class ScoutController < ApplicationController
  def create
    # スカウトの送信の権限がない場合はforbiddenを返す
    return head :forbidden unless current_user.permission_send_scout?
  end
end

1. 役割(enum role)を定義する

採用活動は時代によって変化していくため、役割は追加・変更・削除されます。

役割を追加・変更・削除しやすいようにしています。

2. それぞれの重要な機能の権限を判定する関数(permission_***?)を定義する

YOUTRUSTは今後も改善されるため、機能は追加・変更・削除されます。

それぞれの重要な機能の権限を判定する関数を定義することで、権限を追加・変更・削除しやすいようにしています。

また、この関数内でroleを参照することで「役割(業務内容)」によって「権限(できること)」が決まることを実現しています。

※ 自由に「役割(業務内容)」を作成して設定できるといった将来的な機能改善の際にも移行が楽になります。例えば、この関数名のカラムを持つ新規テーブルを作成してユーザーと紐つけることで実現できます。

3. ロジックは権限を判定する関数(permission_***?)のみを参照する

ロジックで重要なのは「役割(業務内容)」でなく「権限(できること)」のため、ロジックからはroleは参照しないようにします。

この制約により、今後のroleのリニューアルの際には変更範囲が権限を判定する関数(permission_***?)のみになります。

また、権限の判定をしている箇所が検索(grep)しやすくなります。

リリース手順の整理

権限のリニューアルは、サービス全体に影響があります。

リリースの過程でサービス影響が出ないように工夫をしたので、一部を紹介します。

1. 最初にtrueを返すだけの権限を判定する関数(permission_***?)を定義する

今回の権限のリニューアルは、サービス全体に影響があり、コードの変更箇所が多いです。

最初にtrueを返すだけの権限を判定する関数(permission_***?)を定義して、ロジックに権限の判定を追加していきました。

今まで権限の判定がなかった箇所にtrueを返すだけの関数を利用した判定を追加しても挙動は変わりません。

この挙動の変更がないリリースをある程度のまとまりで細かく行うことで、Gitにおける競合(コンフリクト)の範囲を小さくしました。

また、もし障害が発生した場合も原因の特定が楽になります。

挙動に変更がないため、(ユーザーから見たときの)サービス影響はありません。

2. 旧権限と新役割を共存させる

移行の際によくある手法ですが、一時的に古いものと新しいものを共存させることで互換性を保てます。

今回の権限のリニューアルでも同様の手法を利用しました。(実際はより複雑でしたが簡潔に記載しています。)

  1. 旧権限を元に新役割を付与して同期する
  2. 権限を判定する関数(permission_***?)の参照先を新役割に変える
  3. 旧権限を削除する

工夫をすることで、(ユーザーから見たときの)サービス影響が出ないようにリリースを進めることができます。

まとめ

これまでに記載した内容で、安全に「公式リクルーターの権限のリニューアル」を終えることができました。

サービスとしても採用情報の管理がより柔軟になりました🎉

転職後に任せてもらった初のプロジェクトがサービス全体に影響する内容で緊張しましたが、無事に終えることができて良かったです。

既存の実装を読み込んで現在を理解して、実装当時の意思決定の背景や仕様の変遷など過去を理解して、これからの未来を考慮した上で最善を選ぶ必要がありました。(既存コードの8割程度を読み込んだと思います。)

また、開発体験を損なわないように進め、サービス影響が出ないようにリリースを進める必要がありました。

エンジニアとしての総合力を試された仕事で非常に良い経験でした。


YOUTRUSTは一緒に働いてくれるメンバーを絶賛募集しています。 Web/モバイル開発に興味がある方は一度お話しできればと思っています。まずはカジュアル面談からでもご応募いただけると嬉しいです!

herp.careers