それまでの問題
これまで銀行口座は専用モデルを持たず、その他の預金配下のSubAccountの1行として存在するだけだった。銀行口座かどうかは親のAccount名で判定し、口座名はSubAccount.nameに直接入っていた。つまり「銀行口座という管理対象」「会計上の補助科目」「年度ごとの開始残高」という3つの責務が1つの概念に混ざっていた。
表示名や並び順、有効/無効を持たせたくなったり、将来的に銀行名・支店名・下4桁を持たせたくなったりしたときに、この混ざり方だと苦しくなる。プライベート銀行口座の登録機能を作るタイミングで、先にこの整理をすることにした。
業務モデルと会計モデルを分ける
BankAccountをBusinessUnit配下に新設し、SubAccountとは1対1で紐づける形にした。
BusinessUnit
-> BankAccount
-> SubAccount
-> JournalEntry
BankAccountが一覧表示・表示名・並び順・有効無効の正本、SubAccountは仕訳保存先の正本、と役割をはっきり分けた。表示名はdisplay_nameが空ならnameにフォールバックする形にし、SubAccount.nameは会計参照の安定性を優先して自動追従させないことにした。口座名を変えても仕訳の参照名までは変わらない、という割り切り。
年度依存の情報(開始残高)はBankAccount本体には持たせず、従来どおりFiscalYearの期首仕訳側に残した。銀行口座そのものは年度非依存の概念として扱う。
サービスを2つに割った
これまで1つのサービスが「SubAccountの作成」と「期首仕訳への反映」を両方やっていたのを、BankAccountCreatorとOpeningBalanceUpdaterに分割した。前者は口座の作成(既存の同名口座があれば再利用)、後者は複数口座の開始残高をまとめて1回の期首仕訳改訂に反映する役目に専念する。
複数口座をまとめて1トランザクション・1期首仕訳に束ねるという既存の挙動は崩さずに保った。ここを崩すと監査ログやTransactionRevisorの改訂回数が口座数分に増えてしまう。
backfillは実利用前だったので身軽だった
このモデルは公開済みだが実利用はまだ始まっていないタイミングだったので、その他の預金配下の既存SubAccountをそのままBankAccountに変換するだけの単純なbackfillで済んだ。所有権の推論のような面倒な作業は不要だった。設計を変えるなら実データが積み上がる前に済ませておくのが楽、というのを改めて感じた。
読み取り側は段階的に移行
書き込み(作成)はすぐにBankAccount経由に切り替えたが、読み取り側(口座一覧、選択肢生成)は一気に置き換えず段階的に進める方針にした。振替に使えるAccount取得や、Livewire用のdebit/creditアカウントリスト作成をBusinessUnitに集約したのはこの一環。その他の預金のSubAccount参照を直接見ているコードを、BankAccount起点に少しずつ寄せていっている。