SmartHR Tech Blog

SmartHR 開発者ブログ

勤怠管理機能の開発における労働時間計算の難しさとやりがい

目次

  • 勤怠管理機能の紹介
  • 勤怠管理機能開発の難しさ
  • 労働時間計算でやりたいこと
  • 労働時間計算の難しさ
  • 私達の向き合い方
  • まとめ

勤怠管理機能の紹介

初めまして、勤怠開発部でプロダクトエンジニアをしている角田と申します。

SmartHR では昨年の 10 月に勤怠管理機能をリリースし、多くのお客さまにご利用いただいております。 勤怠は従業員の皆さまの「打刻」や「申請」で労働時間を記録し、それを元に「労働時間計算」をするのが主な機能になります。

従業員の皆さまにほぼ毎日使っていただく、SmartHR の入口になるプロダクトですし、労働時間はそのまま給与計算に直結する重要な情報でもあります。 いかに手間なく、正確な情報を入力していただくか? また、それを正しく計算・集計するか? がとても重要です。

今回はさまざまある難しいポイントの中から、私が最近入門している労働時間計算を紹介したいと思います。

勤怠管理機能開発の難しさ

勤怠管理機能の開発には、さまざまな難しさがあります。 皆さんは「勤怠管理機能の開発」と聞いてどんな難しさを想像されるでしょうか?

私は正直なところ、入社して開発を始めるまで「打刻データ保存するだけの簡単なお仕事」...は言いすぎですが、そんなに難しくなさそうだなと甘い考えを持っていました。 しかし、実際はとても考えることが多く、難しい側面を持った機能でした。

具体的にどういった点が難しいのでしょうか?

勤怠管理機能の開発には主に 3 つの難しい側面があります。

多様な働き方に対応しないといけない

日本には固定労働時間制、フレックスタイム制、変形労働時間制、裁量労働制などさまざまな労働時間制度が存在しています。

これらは法律でどういうルールに則って勤務するのか? が決められています。 「決められている」一方で、詳細が各企業に任されている部分もあるため、同じ労働時間制度でも企業様ごとに微妙に違う形で運用されている場合もあります。 わかりやすいところでは、企業様ごとに「定時」は違いますし、「休日出勤」の考え方(給与の割増率)なども違っています。

こういった働き方の違いをすべて表現し、企業様ごとの運用に対応できるプロダクトにしなければいけません。

大量の情報を整理しないといけない

勤怠は大量の打刻データを取り扱います。

1 人の従業員が 1 日の労働で「出勤」「休憩開始」「休憩終了」「退勤」で打刻をします。打刻以外に申請という手段も一般的です。 他にも「年次有給休暇」や「代休」「特別休暇」などの休暇を取得したり、1 日の中の情報は意外に多いです。

さらに、毎日入力していただいたこれらのデータを、月度毎(場合によっては年度ごと)に集計し、労務の担当者の方がチェックをしていきます。 結果として、1 人の従業員だけでも 1 か月のデータは膨大なものになるので、これを全従業員分チェックする労務担当者の方の労力は計り知れません。

また、設定も膨大です。 さまざまな労働時間制度と、その設定可能な項目や組み合わせがとてもたくさんあります。

労務の担当者の方が労働時間の集計を少しでも見やすく、チェックしやすいように、また、意図したとおりに自社に適した設定をできるように、情報を整理する必要があります。

給与に影響する間違えられない計算をしないといけない

前述の通り、労働時間は給与計算に直結する重要な情報です。

従業員の方が正確な情報を毎日入力してくださったとしても、その集計が間違えていては元も子もありません。 集計結果を元に給与計算が行なわれるため、集計の間違いは即インシデントになりえます。 法律や運用、大量のデータ、設定など多くの変数と、その組み合わせに対して適切な計算を設計し、実装しなければなりません。

以降では労働時間計算にフォーカスして、その難しさとやりがいが伝われば幸いです。

労働時間計算でやりたいこと

労働時間計算でやりたいことは何でしょうか?

これは意外とシンプルで、1 か月の労働時間を給与の割増率ごとに分類することです。

具体的には以下の様な名前が付いた時間に分類します。

  • 所定内労働時間
    • 普通の労働時間、会社で定めた労働時間以内の労働時間
  • 所定外労働時間
    • 会社で定めた労働時間を超えた労働時間、法定労働時間(基本 8 時間)以内の労働時間
  • 法定外労働時間
    • 法定労働時間(基本 8 時間) を超えた労働時間
  • etc

これらはそれぞれ、給与の割増率が異なります。 挙げた以外にも、以下のような割増率が異なる時間は個別に分類します。

  • 日中なのか? 深夜なのか?
  • 労働日なのか? 休日なのか?

日の労働時間計算

月の労働時間を計算するために、まずは日の労働時間計算をします。 ここでは出勤から退勤までの時間を、給与の割増率ごとに分類します。

所定労働時間が7時間、9時出勤、23時退勤、12時から13時が休憩の場合。6時から12時が所定内労働時間。12時から13時が休憩時間。13時から14時が所定内労働時間。14時から15時が所定外労働時間。15時から22時が法定外労働時間。22時から23時が深夜法定外労働時間。
日の労働時間計算の例

こうして求めた日の労働時間の内訳を、1 か月分合計することで月の労働時間が計算できます。

労働時間制度ごとに計算の仕方は異なるものの...至ってシンプルに見えますね...?

労働時間計算の難しさ

やりたいことはシンプルなのに、何が難しいのでしょうか?

週の労働時間計算

私が思う労働時間計算の最も難しいポイントが週の労働時間計算です。

さて、以下のように前述しました。

日の労働時間の内訳を、1 か月分合計することで月の労働時間が計算できます。

しかし、実はこれは嘘です。

日本では週の法定労働時間というものが決められています。 1 日 8 時間労働で、一般的な週の平日 5 日間働いた場合の 40 時間です。 つまり 1 週間で 40 時間を超えて働いた時間は法定外労働時間になり、割増の必要があります。

次のような例を考えます。

所定労働時間が7時間、法定休日が日曜日、所定休日が土曜日の場合。月曜日から土曜日まで毎日9時間働くと、全ての日で所定内労働時間が7時間、所定外労働時間が1時間、法定外労働時間が1時間。
1週間の労働時間の例(週の計算未適用)

この例では月曜から土曜までの 6 日間、毎日 9 時間働いているので、日の労働時間は以下のようになります。

  • 所定内労働時間: 7 時間
  • 所定外労働時間: 1 時間
  • 法定外労働時間: 1 時間

単純にこの労働時間を合計して 1 週間分を求めると以下の様になりそうです。

  • 所定内労働時間: 7 時間 \times 6 日間 = 42 時間
  • 所定外労働時間: 1 時間 \times 6 日間 = 6 時間
  • 法定外労働時間: 1 時間 \times 6 日間 = 6 時間

ですが、実際は、以下のようになります。

  • 所定内労働時間: 40 時間
  • 所定外労働時間: 0 時間
  • 法定外労働時間: 14 時間

所定労働時間が7時間、法定休日が日曜日、所定休日が土曜日の場合。月曜日から土曜日まで毎日9時間働くと、月曜日から金曜日は所定内労働時間が7時間、法定外労働時間が2時間。土曜日は所定内労働時間が5時間、法定外労働時間が4時間。
1週間の労働時間の例(週の計算適用後)

前述の通り、週の法定労働時間は 40 時間ですので、40 時間を超えた 8 時間は法定外労働時間になるためこの様な集計結果になります。 図では何気なく所定外労働時間を法定外労働時間にしていますが、どこを優先して法定外労働時間にするのか? なども優先度が決まっていたりします。 他にも所定休日の労働時間をどう扱うのか? など、この計算結果に影響を与えるパラメーターはたくさんあります。

比較的シンプルな例で、1 週間分だけを考えているので手計算でも求められますが、これを実装するには色々と考慮が必要です。 (例えば週が月を跨ぐとどうなるでしょう...? )

その他の難しさ

挙げればきりがないので、箇条書きにとどめて個別の説明は省きますが労働時間計算はとても複雑です。

  • 時間休の取り扱い
  • 自動休憩
  • 休暇取得時の労働時間の取り扱い
  • 固定労働時間制の所定労働時間主義での残業の取り扱い
    • (主義とは...?)
  • 裁量労働制の休憩時間
  • etc

これら 1 つ 1 つで 1 記事書けるかも知れません。

私達の向き合い方

こうした難しさがある上に、シビアに正確さを求められる領域に対して、私達がどう向き合っているのかを紹介します。

属人化の許容

SmartHR の勤怠はリリースして 1 年経っているものの、まだまだ機能が足りていません。 導入企業様に安心してご利用いただくためにも、足りない機能を素早くリリースしていくことが求められています。

素早く、正確な労働時間計算機能をリリースするためにいくつか方法は考えられますが、私達は一定の属人化を許容しています。 仕様検討から設計、実装、テスト、リリースまで計算界隈と呼んでいる特定のメンバーで対応しています。

この方法には大きく 2 つのメリットがあります。

  • 知識が蓄積する
    • 労働時間制ごとの共通点と違うところを把握して応用していくことができる
    • 難しい要件や法律も少しだけわかるようになる
    • 仕様・実装に詳しくなる
    • 労働時間をチェックする労務担当者の気持ちが少しだけわかるようになる
  • 進め方が洗練されていく

労働時間制ごとに大きく違う実装をするのですが、それでも「他の労働時間制度ではこう考えたのに、今回は違うの?」のような思考が効いてくる場面が多々あります。 そのため知識が蓄積するメリットは特に大きいです。

もちろんデメリットもあります。

  • 典型的な属人化問題
    • 計算界隈以外のメンバーが理解する時間がかかる
  • 議論が短期間に早くたくさん発生する
    • 経緯などが Slack にしか残らない

許容しているとはいえ属人化による問題は発生します。 お客さまからのお問い合わせや性能問題の調査などをする際に、計算界隈以外のメンバーにとってはコストが高く時間がかかってしまうこともあります。 また労働時間計算は各値間の依存関係が多いこともあり、仕様や要件について議論をしていると連鎖的に話が広がっていく傾向にあります。 複雑なことを考えることに楽しさを見出しているメンバーが多いこともあり、白熱していることも多く議事録などが残っていないこともしばしばあります。

計算界隈でも問題は認識していて、新しい労働時間制度をリリースするごとに振り返りを実施して対策をしています。

  • リリース前テストの段階でエンジニアへの設計・実装共有会の実施
  • 少しずつ計算界隈の新メンバーを増やす
  • Slack ワークフローを作って記録を丁寧に残す意識付け
    • こちらはまだまだ改善の余地あり

こうした工夫や対策の効果もあって、高速に労働時間制度の追加を行なっていますし、お問い合わせなどもスムーズに対応できています。

ドメインエキスパート、QA エンジニア、プロダクトエンジニア間の仕様すり合わせ

正確性の担保のために、私達はドメインエキスパート(Domain Expert)と QA エンジニア(QA Engineer)、プロダクトエンジニア(Product Engineer)による相互の仕様すり合わせを行なっています(ドメインエキスパートについては、「エッジケースでも正しさを守るドメインエキスパートのお仕事と仕組み」 で紹介していますので参考にされてください)。 ドメインエキスパートが作成した要件定義書を元に、QA エンジニアはテストケースを、プロダクトエンジニアは設計と実装をそれぞれ作成し、テストケースを通す過程で各々の認識を戦わせています。

ドメインエキスパート vs QAE vs PdE

意識して異なる視点から要件を表現することで要件漏れや考慮漏れ、認識のズレなどが解消していき、最終的にリリースされるものの正確性が担保されています。

日本語名変数/メソッドの導入とコードの仕様書化

コードレベルでやっていることもあります。 これらは早く開発することにも、正確性の担保にも繋がっています。

勤怠では Ruby の特性を活かして日本語名変数/メソッドを導入しました。

以下は裁量労働制での一例です。

  # みなし労働時間
  def deemed_working_minutes
    if 休暇を取得している
      return nil
    end

    if 労働日の実労働時間.present? && 労働日の実労働時間 > 0 # 労働日に1分でも働いている
      return 労働日のみなし労働時間
    end

    nil
  end
  alias_method :みなし労働時間, :deemed_working_minutes

他チームの別記事で紹介されていますので方法などの詳細は省きますが、この効果は大きかったです。

tech.smarthr.jp

日本語名のお陰で、仕様を理解するための負荷がかなり軽減されています。 複雑な業務ロジックについては理解しやすいことが最も重要なのだと気付かされました。 また、プログラムが仕様書を兼ねることができるので、仕様書のメンテコストがなくなるという効果もあります。

プログラムに日本語名を導入して仕様書を兼ねることで、日本語としての読みやすさを意識することになりました。 後置 if 文や ? 系のフラグメソッドなど、日本語としては読みづらくものをなるべく使わないことになり、プログラムとしては不便さもあります。 また、どこまで日本語名にするのか? など悩ましいポイントもありますが、メリットが大きく上回っています。

導入にあたって、SmartHR の他のチームにインタビューをしました。 そこでも同様にメリットが十分に大きいという回答でした。 唯一、エディタでの補完などが微妙になるという問題はありましたが、昨今の AI 事情で、まぁまぁな精度でサジェストしてくれるので、実装中に困ることはあまりありませんでした。

複雑なロジックの実装への日本語名変数/メソッドの導入は比較的簡単にできるのでおすすめです。

まとめ

勤怠管理機能の開発のなかでも労働時間計算はとても複雑で難しいですし、計算を間違えられないシビアな機能開発です。 ですが、いかに品質を高めていくか? 素早くリリースしていくか? を考えて改善していくプロセスも含めて、とてもやりがいのある領域です。 将来的には勤怠開発部全体で取り組んでいけるように、体制を整備したり、認知負荷軽減の施策を実施したりして、使いやすくわかりやすいサービスを作っていきたいと思っています! こんな計算界隈を知って、少しでも興味を持っていただければ幸いです。

We Are Hiring!

SmartHR では一緒に SmartHR を作りあげていく仲間を募集中です!

勤怠計算の複雑さやその改善はもちろん、勤怠管理機能に少しでもご興味を持っていただけましたら、お気軽にご応募ください!

ウェブアプリケーションエンジニア(勤怠管理領域 バックエンド) / 株式会社SmartHR

まずはカジュアル面談でざっくばらんにお話ししましょう!

hello-world.smarthr.co.jp