NGW開発BLOG
← 記事一覧へ
·#009

決裁者は「いつ時点の役職」で決まるかマトリクスの基準日

決裁経路の役職から決裁者を解決するとき、どの日付時点の人事配置で写像するかで結果が変わる。時点を持つデータの設計論を綴る。

役職は人ではない

オンライン決裁の経路は、たいてい「役職」の列で定義される。係長 → 課長 → 部長、という具合だ。だが実際に承認ボタンを押すのは役職ではなく人である。だから決裁経路を回す前に、どこかで「役職 → 個人」の変換をしなければならない。この変換表を、NGWは決裁マトリクスと呼ぶ。

一見すると単純な引き当てに見える。組織図を引いて、課長のポストに座っている人を返せばよい。ところが、この写像には見落としやすい引数がもうひとつある。基準日だ。「いつ時点の人事配置で役職を人に変換するのか」を決めないと、答えが一意に定まらない。

人事は時間とともに動く。今日の課長と半年前の課長は別人かもしれない。過去に起案された文書を今あらためて処理するとき、当時の課長に回すのか、現在の課長に回すのか。この問いに答えるのが基準日である。

文書の種類ごとに基準日が違う

厄介なのは、「正しい基準日」が文書の性質によって変わる点だ。実運用では概ねこう分かれる。

  • 起案文書 … 起案日
  • 収受・発信文書 … 受発日
  • 令達文書 … 公布・公示日
  • 会議録 … 会議録の作成日

つまり基準日はハードコードできない。文書モジュールごとに「その文書にとって意味のある日付」を選ぶ設計が要る。ここに落とし穴が潜む。

  1. 似た日付フィールドの取り違えだ。会議録には「開催日」と「作成日」が併存する。人の直感は開催日を選びたがるが、正しいのは作成日のほうだ。近い意味のフィールドが複数並んでいると、レビューでも見逃されやすい。日付を受け取る関数の引数名を意味で明示し、どのフィールドを基準日として渡すかをコード上で一目で追えるようにしておきたい。
  2. キャッシュの陳腐化だ。マトリクスは変換の結果、つまり解決済みの「個人」を保持する。だから基準日だけをこっそり変えても、あるいは画面を再描画しても、中身は古い決裁者のまま残る。基準日が変わったら、経路定義から既定マトリクスを新しい基準日で組み直す処理を、明示的に呼ぶ必要がある。
# アンチパターン: 基準日を差し替えても中身は古いまま
matrix.baseDate = newDate        # ラベルだけ変わる

# あるべき姿: 基準日を引数に取り直して作り直す
matrix = buildMatrix(routeDef, newDate)

時点を持つデータの設計論

この話は決裁に限らない、temporal data(時点を持つデータ)の典型的な論点だ。役職から個人への写像は、基準日を引数に取る純粋な関数として設計するのが素直である。resolve(役職, 基準日) → 個人。同じ入力なら常に同じ人を返し、外部状態に依存しない。

そして関数の返り値は、それ単体では意味を持たない。「この個人は、どの基準日で解決した結果か」という文脈とセットにして初めて再利用できる。基準日を捨ててキャッシュした個人は、時間が経てば必ず陳腐化する。解決結果を保存するなら、根拠にした日付も必ず一緒に保存する。

学びをひとつに絞ればこうだ。人事のように時間で変わる対象を扱うとき、写像の結果を裸で持ってはいけない。何を基準にいつ時点で解決したのかを、値の隣に添えておく。基準が変われば作り直す。この規律さえあれば、「なぜ古い課長に回ったのか」という事故はたいてい防げる。