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

「所属は1つ」という前提が崩れるとき兼務と共通所属

職員は1つの所属に属する、という素朴な前提が兼務と共通所属で崩れたとき、文書管理はどんなバグを生み、どう直したかを綴る。

ひとりに、ひとつの所属

文書管理の最初の設計は、とても素直な前提の上に立っていた。「職員はひとつの所属に属する」。この一文があれば、多くのことが自動的に決まる。誰かがログインすれば、その人の所属が分かる。所属が分かれば、既定の文書記号(文書を分類する記号)が決まり、文書記号が決まれば、決裁経路もほぼ決まる。ドミノのように、ユーザーの一挙手一投足が主たる所属から導けた。

ところが、この気持ちのよいドミノが、現場では倒れなかった。

現実は多対多だった

自治体には、ひとつの所属だけで仕事をする職員ばかりではない。いくつもの兼務所属を抱える職員がいる。「全係共通」のような、複数の係をまたぐ共通所属を運用する団体もある。そして職員は、作業する所属を一日のうちに何度も切り替える。午前は本務の課で起案し、午後は兼務先の名義で決裁を回す。さらにやっかいなのは、既存の文書を別の所属で引用起案する——つまり複製して別の所属から起こし直す——という使い方が、ごく日常的に行われることだった。

こうした運用は、最初の前提がまったく想定していないものだった。そして予想どおり、一群のバグが生まれた。兼務先で起案したはずなのに文書記号が本務のものになる。決裁経路が空になって回せない。引用起案した文書の所属が、なぜか元の文書の所属を引きずる。症状はばらばらに見えたが、根はひとつだった。

ロジックが、職員の「主たる所属」だけを見ていたのだ。いま画面で選択している所属——兼務先の文脈——を、コードは見ようとしていなかった。

問題を厄介にしたのは、文書記号が「課」単位で管理され、決裁経路が (所属, 文書記号) の組で決まるという構造だった。ここに主たる所属の既定文書記号を押し付けると、兼務先ではその組が存在せず、経路が空になる。前提の綻びが、そのまま連鎖して末端の帳票まで届いていた。

// 綻びていた発想: ログイン職員の「主たる所属」を正とする
$division   = $staff->getPrimaryDivision();       // 兼務先を無視
$docSymbol  = $division->getDefaultDocSymbol();    // 本務の記号を押し付け
$route      = findRoute($division, $docSymbol);    // → 空になりうる

選択された文脈を第一級で扱う

直し方の原則は、拍子抜けするほど単純に言える。「主たる所属」ではなく「選択中の所属(兼務を含む)」を常に尊重する。

具体的には、判定の入口を差し替える。誰であるか(who)から所属を導くのではなく、いまどの文脈で作業しているか(which context)を第一級の入力として受け取る。文書記号は選択中の所属の課で選び、決裁経路とその判定に使うマトリクスも、その (選択所属, 文書記号) で組み直す。

// 直した発想: いま選択している文脈を正とする
$division   = $context->getSelectedDivision();     // 兼務先ならそれ
$docSymbol  = $division->getDefaultDocSymbol();    // 選択所属の課で選ぶ
$route      = findRoute($division, $docSymbol);    // その組で組み直す

もうひとつ、引用起案が突きつけた問いがある。複製した文書の「真の所属」はどこにあるのか。素直に考えれば、起案時に保存された所属フィールドを読めばよさそうに見える。だがそれは、引用元の値を引きずる罠だった。文書の真の所属は、起案レコードに書かれた値ではなく、その文書を綴じている簿冊(綴り)の管理部門から導くのが正しい。所属という情報の権威ある出所(source of truth)を、可変なコピー値から、安定した綴じ先へ移したわけだ。

前提は置いてよい、崩れる使い方が主流なら見直す

この一件から学んだことを、ひとつに絞りたい。

「1エンティティにつき1つ」という素朴な前提——1ユーザー1所属、1注文1住所、1アカウント1メール——は、設計の初速をくれる。決めてしまえば多くが芋づる式に導ける。だから前提を置くこと自体は悪くない。問題は、その前提が崩れる使い方が例外ではなく主流になったときだ。

兼務も共通所属も引用起案も、この現場では「たまに起きる特殊ケース」ではなかった。日常だった。前提が主流の運用とずれているなら、対症療法で穴をふさぎ続けても追いつかない。必要なのは、選択された文脈(context)をモデルの中心へ据え直すことだ。「誰か」から属性を導くのをやめ、「いまどの文脈にいるか」を明示的な入力として受け取る。真の所属のような重要な属性は、コピーされやすい値ではなく、安定した親(簿冊の管理部門)から引く。

素朴な前提はスケッチには向く。だが現実が多対多で押し寄せてくるなら、文脈を一級市民に昇格させる。その一手間が、末端の帳票まで届く連鎖バグを、入口で断ち切ってくれる。