LayerX エンジニアブログ

LayerX の エンジニアブログです。

バクラク上のテナント情報を SmartHR から API で同期するようにした話、または組織情報マスタを一旦諦めてデータ連携フレームワークを作った件について #LayerXテックアドカレ

この記事は、LayerX Tech Advent Calendar 2024 の9日目の記事です。

昨日は budougumi0617 さんによるリクエストログミドルウェアに後続ロジックから情報を渡したいときの2つのアプローチでした。確かにな〜という課題感と、懸念はありつつもちゃんと検討した上で決め切る姿勢が良いなという記事でした。

すべての経済活動をデジタル化するためにすべての業務活動をデジタル化したい、コーポレートエンジニアリング室アプリケーションチームの @yuya-takeyama です。

アプリケーションチームはソフトウェアエンジニアリングに対する理解と開発力を持ち、「技術をつくる」ことによる課題解決をしていくチームとなっています。

昨今は社内で利用する各種 SaaS だったり様々な業務の間でのスムーズなデータ連携が課題になっており、その辺の話をしていきます。

直近でもブログやイベントでの登壇などで同様のトピックを扱っていますが、そこから一歩進んだ話となっております。

tl; dr

  • バクラク上のテナント情報のメンテナンスを手動管理だったところから SmartHR からの自動同期をするようにしました
  • それを作るにあたって、SmartHR・バクラク間だけでなく、その他諸々のサービスもカバーできるようにと考え、組織情報マスタを作らないアプローチを選択しました
  • そのアプローチを実現するにあたって、データ連携のためのフレームワークを設計・実装し、Synthetix と名付けました

組織情報マスタとは

本題に入る前に、この記事における「組織情報マスタ」とはどんなものかについてできるだけ明確にしておきます。

インターネット上で検索すると「組織マスタ」「人事マスタ」など様々な名前で呼ばれているようです。(むしろ「組織情報マスタ」と呼称しているケースはかなり少数派のようですが、私は「組織情報」「組織情報マスタ」と自然と呼んでいるので、このままいきます)

一旦この記事においては以下のような情報をデータベース化したもの、ぐらいに思っていただければと思います。

  • 会社に所属する人に関する情報
    • 社員をはじめ、業務委託や派遣社員なども含めて、社内での業務に携わる人々のあらゆる情報を集約する
    • どういった情報を持つべきか、は要件によって異なるが、一般的には名前、社員番号、社員としてのメールアドレス、所属部署、役職、職種などを含む
  • 会社に存在する大小様々な組織に関する情報
    • 事業部、部、室、グループ、チームなどなど
    • それらが持つ名前や部署コード
    • そしてそれらの親子関係。組織図のツリーを表現するように必要な情報
    • 所属情報においても、部署コードを用いて「どこに所属するのか」を表現する

労務グループの SaaS 管理大変問題

以前より、労務グループのメンバーから「手動で管理している SaaS が多くて大変」という相談をもらっていました。もともと、労務グループでは主に以下の SaaS を運用していて、メンバーの入社時にはアカウント招待をしたり、異動が発生するとそれに合わせて所属情報を変更したりというところに工数を取られていました。

  • バクラク (社内での申請や経費精算、その他関係する経理業務等)
  • SmartHR (労務管理や人事管理)
  • 某勤怠管理サービス

勤怠について、先日発表のあった通りバクラク勤怠というサービスがリリースされました。

LayerXにおいては現在、バクラク勤怠導入のための移行期間となっており、間も無く完全に移行が完了となります。これが完了すると、もともと勤怠に使っていたサービス上のテナント情報のメンテナンスは当然不要となります。

残り 2 つのうち、バクラクは申請等に必要な粒度でのみ組織情報が登録されていたのに対し、SmartHR には基本的に組織図上の情報がほぼ完全な形で登録されています。というわけで SmartHR から自動でのデータ同期を行うようにすれば、労務グループ的には組織情報の変更に合わせてメンテナンスが必要なサービスは SmartHR だけということになります。

データ連携のためのアプローチを考える

労務グループの関係者はじめ何人かと話して「バクラク上のテナント情報は SmartHR から同期する」ということ自体は決まり、どう作っていくかを雑に話している中で、上長の @kanny さんから「今後組織情報の同期要求は一定高まってくる。シンプルに 1:1 で連携するよりは中間テーブルを挟む形のほうが良いんじゃないか」というアドバイスをもらいました。

これまでにもコーポレートエンジニアリング室内で「組織情報マスタ欲しいよね」的な話をしていたことはありました。それと似ている部分もあるとは思いつつ、設計を練っているうちに、目指すべきアプローチは以下の 2 つがあるな、ということが少しずつ見えてきました。

アプローチ 1: 「組織情報マスタ」と呼ばれるデータベースに全ての情報を集約し、それを中心に様々な業務や自動化を行う

会社が大きくなってくると、コーポレート部門の業務が少しずつ細分化していく過程の中で、それぞれの部署ごとに業務やデータが分かれていくのはよくあると思います。データが MECE に分かれるのなら良いのですが、実際には似たようなデータを重複して管理していたり、抜け漏れがあったりすると思います。

例えばコーポレートエンジニリング室では IdP として Microsoft Entra ID を管理しており、会社アカウントは雇用形態に関係なく発行するので基本的に全員網羅されてはいますが、部署情報やそこへの所属情報を持っているわけではありません。一方、SmartHR には部署情報・所属情報は持っていますが、直接雇用関係のないメンバーについてはそもそも登録されていません。

そうした問題を解決するアプローチとして、よく言われるのは Single Source of Truth としての組織情報マスタ的な何かを持つことでしょう。

様々な業務の中心にその組織情報マスタをおき、業務の過程で必要に応じてデータを登録・更新したり、そこから様々な自動化を行おうというものです。

これはイメージとしては美しく、理想的な状態に思えます。ですが、実現するのは並大抵のことではありません。関連する業務もそのためのシステムもそのために全て追従する必要があるからです。

アプローチ 2: 「組織情報マスタ」は一旦諦めて、各所からデータを一箇所に集めて、それを元に様々な業務や自動化を行えるようにする

Single Source of Truth それ自体をいきなり作ろうとするととても大変ですが、まずは社内に散逸している様々なデータをかき集めることで、少しずつ Single Source of Truth めいた何かが見えてくるのではないか、というアイディアです。

このアプローチを考えていく上で、最初に以下のような図を書きました。 (社内の実際のものから情報を落として、伝わりやすいものにしています)

データ連携の設計を表すフロー図

図中の ABAC Generator というのは前述のブログ記事にて紹介されているのもので、バクラク Sync というのが今回の記事で紹介している同期処理です。

なお、この図はあくまでもこれから作っていきたい理想系であり、ABAC Generator は現状まだ Microsoft Graph API と直接やりとりをする実装のままです。

組織情報データ連携フレームワーク Synthetix

この図に示したフレームワークを Synthetix と名づけました。名前の由来は以下の単語を元に、LayerX の X をミックスして作った造語です:

  • synthetic: 統合的な
  • synthesize: 合成する
  • synchronize: 同期させる

一言でいうと組織情報の ETL パイプラインみたいな感じです。各種 SaaS から Extract したデータをデータモデルにしたがって Transform し、データストアに Load して、そのデータストア上のデータを元に様々な処理を実行するようにすれば、データソース部分の SaaS を乗り換えることがあったとしても影響範囲を限定的なものにできます。

おそらく Embulk などで実装することもできなくはないと思いますが、私自身特別 Embulk の経験があるわけでもないので、TypeScript の monorepo として素朴に実装しました。

まず loader と呼ばれるコンポーネントが各種 SaaS だったり、何らかのデータベース (手書きのスプレッドシートなども可) などからデータを読み込みます。loader はデータを読み込むのに必要なクライアントライブラリと、一元化されたデータモデルを表現する schema というパッケージに依存します。

そして schema は人や部署など、組織情報を表現するための社内標準のスキーマです。スキーマの定義には zod を使っています。

loader によって出力されたデータを処理するのは processor と呼ばれるコンポーネントです。各 processor は、組織情報にアクセスする際は原則として loader によって出力されたデータのみを元に様々な処理を行います。

現在は全て単一ホスト上で全て実行しており、データは改行区切りの JSON としてファイルに書き出しているだけです。実行開始時に ULID のディレクトリを生成し、loader ごとにサブディレクトリを作成し、データ種別ごとのファイルを持ちます。

01JEMSZPVE8VB3W4Z8976TAKX6/
└── smarthr/
    ├── people.json
    ├── departments.json
    └── memberships.json

ここは何らかのデータベースにしても良かったのですが、スキーマはまだ試行錯誤している段階では変更しやすい形が良いなと思い、TypeScript のコードだけで完結するように一旦このような形にしています。

Synthetix の展望

というわけで SmartHR からバクラクへの組織情報の同期を、両サービスの API を使って Synthetix 上に実装しました。すでに数ヶ月の運用を行なっている状態です。

とはいえ、現在は SmartHR 上の情報を多少の変換を加えた上でバクラクテナント上にも入れ直しているだけなので、これは Synthetix がなくても実現できることです。

今後は Synthetix で本来やりたかった以下にも取り組んでいきます。

直接雇用メンバーと業務委託メンバーをデータ上統合して扱えるようにする

SmartHR には基本的に雇用関係のあるメンバーだけが登録されますが、業務委託として携わっていただいている方々のデータは登録されません。SmartHR は労務管理等のために使っているので、その点ではそういうものなのですが、先述の通り ABAC Generator というツールでは組織情報のデータソースとして扱っており、そこに業務委託メンバーは含まれていないことになります。

これまでの記事・発表等では話としてややこしくなるので省いてきましたが、これは運用上はとても大きなポイントです。業務委託メンバーについては所属情報を元にしたグループへの割り当てができないので、別途個別での割り当てを行っています。

しかも、これには人事・コーポレートエンジニアリング室・所属する部署という3部署での細かいやりとりが発生するものです。必要な作業自体はそこまで時間がかかるわけではないですが、やはりコミュニケーションが発生すると認識がずれないように気を使ったりする必要があるし、ミスや漏れの可能性も高まります。

これを解消するには、前提としての業務委託メンバーを格納するデータベースを設計・実装する必要があります。そして既存のアカウント発行フローからうまく接続して、データが適切にメンテナンスされるような業務フローを構築する必要があります。

ですが今は、そこをちゃんと作りきって、そのデータベース用の loader を Synthetix 上に実装すれば、業務委託メンバーも直接雇用メンバー同様に自動的にグループへの割り当てが行われるようになります。

まとめ

といった具合に、コーポレートエンジニアリング室では、社内全体に関わる業務活動をデジタル化し、各事業部が生産性高く、かつセキュアで統制のとれた状態で働けるよう、ソフトウェア・業務フローの両面から取り組んでいます。

興味ある方は是非以下からカジュアル面談等ご応募ください:

明日の担当は ken5scal さんです。先日の大統領令の話の続きでしょうか?他ではなかなか見られないまとめなのでこれも要チェック!