Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

人事評価のためのWebアプリケーションを内製化しました

人事部 高橋 です。
本記事は Sansan Advent Calendar 2021 - Adventar の10日目の記事です。

このたび、社内で人事評価に使うシステムを内製しました。

このたびと言いつつ1年ほど前から運用が始まっていたのですが、やり残し等も落ち着いたこのタイミングで記事にしてみます。

背景

従来は Kintone に人事評価のためのシステムがあり、4年ほど運用していました。Kintone の設計、カスタマイズは外注でした。

以下の要因から、システムを内製する判断が下りました。

  • 評価設計の定期的な見直しやデータの増加に Kintone のカスタマイズ性と性能が耐えきれなくなった。
  • 今後も人事評価の仕組みは柔軟に(同時に、効率的に入力できるように)見直していきたいという経営陣の意志があった。そのためパッケージを導入するリスクが強かった。
  • 人事部に所属しながらWeb開発ができる人(私)がいた。*1

Sansanの人事評価 概要

Sansan では人事評価は360度評価をベースにしたもので、年に2回実施しています。
ざっくりとした流れを紹介します。

  1. 管理者:社員マスタに基づき、被評価者と評価者の関連を設定する
  2. メンバー:自己評価を入力する
    1. その期間で達成したこと(Achievement)を複数入力する。各Achievementで同僚は誰か、兼務や期中の異動があった場合はどの上長に評価してもらうか、を選択する。また、Sansanのカタチをどのように体現したか、なども入力する。
  3. 一次評価者:自己評価の入力内容が適切(指名している同僚など)かをレビューする。場合に応じてコメントとともに差し戻しをする。
  4. 全社員:指名を受けた同僚のAchievementについて評価を入力する。
  5. 一次評価者:同僚評価や日々の1on1などを参考に評価を入力する。
  6. 最終評価者:同僚評価や一次評価の内容を参考に評価を入力する。
  7. 評価委員会:最終評価をベースに報酬を決定する。

Sansanの人事評価の特徴のひとつ。それは、Achievementごとの同僚評価者を本人が選ぶということです。
努力と成果を最もよく知るメンバーから声をもらうということですね。

一方で、複数プロジェクトに関与している人はそれだけ多くのメンバーから指名を受けます。全てのAchievementについて細かく評価を入力するとなると膨大な時間がかかり、本業に影響を与えかねません。それでは本末転倒です。人事評価は適正さとコストの最適化問題をどう解くか、という勝負です。このポイントは評価のたびに手法のマイナーチェンジを繰り返しています。

なお目標管理の手法としては会社としては OKR を用いています。これは評価には必ずしも連動させません。「当初予定していたプロジェクトの優先度が下がり、別のプロジェクトが立ち上がった」なんてことはよくある話(というかあるべき姿)。OKRに関わらず「達成したこと」は Achievement になります。

また、この Sansan Builders Blog への寄稿や技術イベントの登壇、あるいはちょっとした業務改善など、「プロジェクトってほどのものじゃないんだけど、会社に貢献すること」も評価の対象です。上記の Achievement とは別の立て付けですが、「本来業務以外の貢献」ということでアピールが可能です。もちろん、これが無いからと言ってもマイナス評価になることはありません。

技術要素

手を動かすメンバーは私+業務委託の方の2名体制。今後の運用も軽くしたかったので、できるだけシンプルな構成にしました。

  • インフラ
    • Amazon Lightsail (Instance / DB (PostgreSQL) / Load Balancer)
    • Amazon S3
    • Amazon CloudWatch
    • AWS CodeBuild / CodeDeploy
  • バックエンド
    • Node.js / TypeScript / NestJS
  • フロントエンド
    • Vue.js (Non-SPA)
  • ほか関連サービス
    • 認証:Okta
    • リポジトリ:GitHub
ポイント
  • Lightsail を採用してみました。いずれSansanでも軽めのWebアプリケーションのニーズが出た際の知見も得られたと思います。
    • Lightsail とは、 Web サーバーや DB がパッケージ化された VPS です。スペックも料金体系もシンプルなので、インフラに詳しくない人でも気軽に使えます。
    • CodeDeploy と Lightsail Instance や Cloudwatch との繋ぎなどでハマりました。
  • バックエンドは、大量データを扱ったりするわけでもなく技術的な要件はほとんどありません。将来的に誰がメンテするか決まっていないことから、比較的「誰でも読めそう & 書けそう」な Node.js にしました。
  • フロントエンドは non-SPA です。SPA にする意味が無いという判断です。また SPA での実装は通常何かしらのフレームワークの知識が必要なため、将来のメンテメンバーの負担を増やしてしまいます。
  • 社内の認証基盤として Okta が使われているので、乗っかりました。認証結果を JWT として Cookie に保存し、有効期限切れたら裏で Okta に問い合わせにいく感じです。
    • ご想像のとおりハマりました。

少しだけ実装の話

せっかくなので少しだけ実装の話も。*2

ちょっとしたこだわり:入力内容を自動保存する

評価の入力は時間がかかるものです。
ちょっと書いて、悩んで、消して、書いて。
その間に別の作業をして、タブがどっかにいっちゃって。保存しようとしたら認証が切れてて。画面更新したら全部消えてた。

そんな悲劇は見たくない!*3

というわけで、 Vue.js のウォッチャなどと lodash の debounce を使って入力のたびにサーバーへ POST させるようにしました。

import _ from 'lodash';
import axios from 'axios';

export default {
  data() {
    return { description: '' }
  },
  watch: {
    description: _.debounce(async function(value) {
      await axios.post('/my-api', params);
    }, 1000)
  }
}

lodash.debounce を使わないと1文字打つごとに POST されてサーバーに不要な負荷をかけてしまいます。 lodash.debounce を使うことで、値が変更されてからウォッチャが起動されるまでミリ秒単位で待たせることができます。

これから

すでに触れたように、人事評価は適正さをいかに低コストで獲得するか、という勝負。Sansan は事業戦略に呼応して組織の規模、構成も変えていくため人事評価の最適化問題は常に変化し続ける。そのためのシステム内製化でした。

現時点でも「こんな評価ができたら面白そう」が積み上がってますので、これからが楽しみです。現場の声も集めながら、いいものを作っていきたいですね。

*1:データが非常にセンシティブなので人事部でないメンバーが関わるのはかなりのリスク。実装と運用を分けるにしても大変だろうなぁ。。

*2:各種ハマりポイントは個別のトピックで記事が書けそう

*3:この記事も書いている途中にPCがフリーズしてガッツリ消えました。

© Sansan, Inc.