資源計算機能の追加

前記事で認証・認可を追加したことで準備が整ったので、こちらのPRで資源計算機能を追加した。 本機能は現時点ではまだダミー版だが、資源タイプに応じた計算方法が使われるように動いており、業務ロジックのエッセンスは押さえている。

前提知識

実装の概要

ここまで、業務を構成するドメインモデルを作り込んできたので、実装はかなり楽だった。 具体的手続きをファクトリとリポジトリに委譲できるようになっていたことで、ABC計算計算結果の保存も、すっきりしたサーバーアクションとして書けた:

// ABC計算

export async function calculateAbcAction(
  stockGroupName: StockGroupName,
  catchDataValue: string,
  biologicalDataValue: string,
): Promise<AcceptableBiologicalCatch> {
  const stockGroup = createStockGroup(stockGroupName);
  const stock = createFisheryStock(stockGroup);

  const catchData: CatchData = { value: catchDataValue };
  const biologicalData: BiologicalData = { value: biologicalDataValue };

  return calculateAbc(stock, catchData, biologicalData);
}
// 計算結果の保存

export async function saveAssessmentResultAction(
  stockGroupName: StockGroupName,
  result: AcceptableBiologicalCatch,
): Promise<void> {
  const stockGroup = createStockGroup(stockGroupName);
  const stock = createFisheryStock(stockGroup);

  const repository = createAssessmentResultRepository();
  const service = new SaveAssessmentResultService(repository);

  await service.execute(stock, result);
}

実際の計算は、計算実行ボタンのクリックによって上記のサーバーアクションが呼び出されることで実行される。

        <button
          type="button"
          onClick={handleCalculate}
          disabled={!catchDataValue || !biologicalDataValue || isCalculating}
          className="px-6 py-3 bg-primary text-white rounded-lg hover:bg-primary-hover disabled:bg-disabled disabled:cursor-not-allowed transition-colors"
        >

UX概要

まだダミー版ではあるが、現時点における資源計算機能の使い勝手をメモしておく。

正常系

資源計算機能はDBへの書き込みを伴う機能なので、ログアウト状態でアクセスしても利用できない。

未認証で利用しようとしたときの画面

未認証で利用しようとしたときの画面

ログインすると、そのユーザーが担当している資源の評価画面へのリンクと、ロール名(主担当|副担当)が表示される。 下記は複数の資源を担当しているユーザーから見える画面:

3資源を担当させられてしまった気の毒な職員の画面

3資源を担当させられてしまった気の毒な職員の画面

ちなみに、ズワイガニオホーツク海系群のみを担当しているユーザーが同じ画面にアクセスすると、下記のように表示される:

別の担当者から見た同じ画面

別の担当者から見た同じ画面

資源ごとの評価画面のURLは/assess/{資源名}の形式で動的に生成される。

表意文字の恩恵を受けられるのはアドレスバーにあるうちだけ

表意文字の恩恵を受けられるのはアドレスバーにあるうちだけ

ただし、この仕様は今後変えるかもしれない(すべての機能に言えるが)。アドレスバーに表示されているうちは見やすいが、コピペして共有するときにURLエンコードされて結局読めなくなってしまう。 URLの中身が読めないと、共有ミスも起こりやすくなるので、将来的には英数字構成にするかもしれない。

さて、資源を1つ選んで、その評価ページにアクセスしてみると、次のように表示される:

アクセス直後の様子。データがないので計算できない状態

アクセス直後の様子。データがないので計算できない状態

フィールドに値を入れると、計算を実行できるようになる:

データ(?)を入力して計算準備OK

データ(?)を入力して計算準備OK

ボタンを押してABC計算を実行すると1、結果が表示される。

投げやりな実装だが、一応1系資源としての専用ロジックが動いている

投げやりな実装だが、一応1系資源としての専用ロジックが動いている

現時点では資源計算ロジック自体がまだダミー版で、入力したデータを表示するだけの実装になっている。 各種データは数値ですらないが、これらは業務フローを通せるようになったら実装していこうと考えている。

異常系

ログイン自体には成功していても、自身が担当していない資源の評価ページにアクセスすると、権限不足でエラーとなる2:

未ログイン状態でもこの画面になる

未ログイン状態でもこの画面になる

今後の課題

計算結果の状態遷移図を描く

資源評価では、主担当者がまず計算・報告書執筆を終え、その結果は内部レビューを経て外部公開される。 評価結果は、この時点ではまだ「評価""」と呼ばれる。 公開から有識者を招いての評価会議までの間は質疑受付期間で、寄せられた質疑の内容によっては再検討が発生することもある。 評価会議当日に議論がまとまれば、「案」が取れて晴れて確定版となる。

これを整理すると、各資源の評価は、業務の進行に応じて複数の「状態」を取ると考えることができる。 そう考えると新たに「評価」というエンティティを定義する設計案が考えられる。 現時点ではこれが妥当かわからないが、実際に評価業務を担当していた者として見ても大きな違和感はない。 状態遷移をモデル化することで、バックエンド・フロントエンドともに実装がシンプルになるだろうし、評価業務の進捗把握もしやすくなる副次効果もありそうだ。

各種データのモデリング

言うまでもなく、現時点のデータはひどすぎる。 また、データ形式に目を瞑るとしても、実際の資源計算と比べると、現時点の資源計算機能は、データとの関わり方が大きく異なる。 いまの資源評価では、計算作業はほとんどエクセルで実施されており、担当者は送付される時系列データを何日も操作し続ける。 長い時系列データにどっぷり浸かって作業することに慣れている現役の評価担当者にとっては、単一の値をフォームに入力して送信する現時点のUXは、アプリケーションの信頼性に影響を及ぼすレベルの強烈な違和感を伴うだろう。

単一の値をフォーム送信、というやり方はさすがにひどすぎるが、それでも資源評価で扱うデータの本質については一考の余地はある。 年次で送付される時系列データを毎年そのまま使う現状の資源評価のやりかたは、時系列データを毎年全上書きしているかのような手順だが、資源評価におけるデータの登録作業は、実際には下記に分類される差分更新である:

  • A. 最新年データの追加
  • B. 昨年速報値の確定値化(微修正を伴うこともある)
  • C. 過去の値の修正(めったに起こらない)

特にC.はめったに起こらないので、新しい時系列データを受け取ってそのまま使っても、結果的に行われているのはほぼA.B.の差分更新なのだ。 さらに言えば、資源評価では各種データはソースなので、C.のケースはもちろん、B.のケースでもコメントとともに明示的に登録(コミットという意味)するような入口管理をしてもいいくらいだ。

将来的には、本アプリのデータ登録UXは「エクセルファイルのアップロード」程度まで現状フローに寄せるかもしれないが、背後のドメインモデルは差分更新を維持したほうがよいように思われる。 この設計の妥当性についてはまだ言語化が十分にできないので、ADRを書きながら解像度を高めたい。

言語の壁が気になる

内心触れるのが怖くて(?)、ここまで全く話題に上げずにきてしまったが、本アプリでは実装言語にTypeScriptを選んでいる(関連: ADR-001)。 将来予測などの統計計算をゴリゴリやっている本家は、統計パッケージのエコシステム資産が潤沢なR言語で書かれている。 プロットにおいても、TypeScript(JavaScript)はRに比べてかなり不利だろう。 といってもこれは設計を学ぶ目的の趣味プロジェクトなので、個人的にはTypeScriptによる実装をちょっと試してみようかと思う。 最終手段として、資源計算エンジンだけRにする方法もあるので、頓挫することはまずないはず。

パフォーマンスとアーキテクチャ

「言語の壁」の話とも少し関係する話だが、本アプリのパフォーマンスボトルネックはどこになるだろうか。 担当者の絶対数はたかだか十数人なので、toCのSaaSのような使われ方はしないものの、技術的制約をいったん無視して、資源評価の「あるべき姿」を考えてみると、実はパフォーマンス要件は厳しいかもしれない。 技術的制約がないならば、将来予測に使う複数パラメータの組み合わせ数をもっと増やしたいかもしれない。 複数の資源量推定シナリオ×複数の将来予測シナリオと考えると、組み合わせ数はかなり多いのだ。

クラウドネイティブアプリケーションの形を取っていれば、並列実行が可能な部分をコンテナやFaaSで実行するように設計すれば、スケール性をかなり高められる。 一番雑な実装は、frasyrを実行可能なRコンテナを作り、LambdaなどにデプロイしてFaaSとして利用する方法だろう。 デフォルトでも、同時に1000個のfrasyrコンテナで並列計算できることになる。

資源のページを作りたい

これは資源評価の当事者だったころから思っていたことだが、なんとしても資源別のwebページが欲しい。 れっきとした国家事業なのに、その評価対象資源がいったいどういうものなのかを参照できるページがないのはおかしいだろう。 もしそのページが存在したなら、歴代のデータや評価結果などもまとまって掲載されているはずだ。 ということで、このプロジェクトでやってみようと思う。

まとめ

前記事で実装した認証・認可機能と連携して動く資源計算機能をリリースした。 まだまだ課題が多く、見えてないこともありそうだが、今回はここまで。


  1. 計算量にもよるが、将来的には、パラメータの入力が落ち着いててから2秒後に自動実行、としたりするかも。ボタンの入力がそもそも不要 ↩︎

  2. 今思えば、画面遷移をさせずに、確定を押した瞬間に拒否すれば、「担当資源一覧に戻る」リンクを出す必要もなかったか ↩︎


comments powered by Disqus