LayerX エンジニアブログ

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

複雑なドメインに立ち向かう 〜「バクラク請求書受取」のアーキテクチャ改善戦略編〜

こんにちは。バクラク請求書受取(債務管理)の開発を担当しているakahaneです。

エンジニアとして請求書や仕訳といった業務領域にディープダイブし、複雑なビジネスドメインと立ち向かってきた経験をご紹介いたします。

はじめに

LayerXが提供する「バクラク請求書受取」は、請求書の受領から会計ソフト連携までを一気通貫で支援するサービスです。 バクラクシリーズ最古参のプロダクトとして多くの企業で利用されていますが、その開発は「複雑なビジネスドメイン」と「技術的負債」という二つの大きな課題との戦いでした。 長期運用されるソフトウェアプロダクトは、シンプルに見える機能の裏に奥深い業務知識が隠れており、度重なる変更により「秘伝のタレ」化したコードベースを抱えがちです。 本記事では、こうした課題に開発チームがどう立ち向かったか、その実践を共有します。

請求書受取業務の実態

企業の経理部門にとって、請求書の処理は避けて通れない重要な業務です。毎月、取引先から届く数十枚から数百枚の請求書。これらは郵送で届く紙の請求書、メールに添付されたPDF、取引先のポータルサイトからダウンロードする電子ファイルなど、形式も受取方法もバラバラです。 経理担当者は、これらの請求書を一枚ずつ目視で確認し、取引先名、請求金額、支払期日、税額などの情報をExcelや台帳に転記します。その後、上司の承認を得て、銀行振込用のデータを作成し、支払いを実行。最後に、会計ソフトに仕訳データとして入力するという一連の作業を行います。 この手作業による処理は、転記ミスのリスクが常につきまとい、二重払いや支払い漏れといった重大なミスにつながる可能性があります。また、月末月初の繁忙期には残業が常態化し、経理部門の大きな負担となっています。 バクラク請求書受取は、このような請求書処理業務をデジタル化・自動化することで、経理部門の業務効率を飛躍的に向上させるプロダクトです。AI-OCRによる自動読み取りから、会計ソフトへの自動連携まで、請求書処理の全工程をカバーしています。

しかし、このバクラク請求書受取の裏側には、とても複雑な課題が潜んでいました。

直面した「複雑さ」の正体

請求書受取(債務管理)ドメイン特有の難しさ

債務管理とは、企業が仕入先などに対して行う支払い(債務)を適切に管理する業務です。 この領域には、一般的なソフトウェア開発では触れることのない専門的な業務知識が求められました。 開発チームにとって最大の壁は、会計・経理の専門用語と概念の理解でした。「仕訳」とは何か、「源泉税」はどのように計算され、いつ控除されるのか。 請求書に記載された一つ一つの項目が、どのように会計処理に影響するのか。 エンジニアには馴染みのない複雑なビジネスルールが無数に存在していました。 さらに厄介なのは、これらのルールが企業ごとに微妙に異なることです。 大企業と中小企業、製造業とサービス業では、同じ「請求書処理」でも異なるルールや処理フローが存在します。この多様性に対応する柔軟なシステム設計が求められました。

会計ソフト連携の終わらない戦い

市場にはfreee、マネーフォワード、弥生会計など多数の会計ソフトが存在し、それぞれ独自の仕様を持っています。各ソフトのAPI仕様、データフォーマット、認証方式、勘定科目等のマスタ体系それぞれに個別に対応する必要がありました。 例えば「税区分」一つとっても、会計ソフトごとに異なり、単純なマッピングでは対応できません。この課題は 連携先の数 × 仕様の差異 の組み合わせで複雑性が増大し、新規会計ソフト対応や仕様変更のたびに場当たり的なコードが追加され、システム全体の複雑性が雪だるま式に増大していました。

歴史あるプロダクトの宿命:蓄積された技術的負債

バクラクシリーズ最古参として、長年の開発で避けられない技術的負債が蓄積していました。

  • トランザクションスクリプト + DAOの実装: 初期アーキテクチャはプロダクト立ち上げのスピードに貢献したものの、長年にわたる機能追加や改修の結果、ビジネスロジックが分散し、請求書関連だけで100以上のメソッドが乱立する状態になっていました。
  • 変更への恐怖: コードの結合度が高く、一つの変更の影響範囲が予測困難で、デグレッションへの恐れが常に存在しました。
  • ドメイン知識の属人化: 特定機能の詳細が特定開発者の頭の中にのみ存在する「ブラックボックス」化が進んでいました。

技術的負債は単なる「コードの複雑さ」ではなく、開発速度を鈍化させ、変更コストを増大させる「抵抗係数」として作用します。複雑なドメインと多数の外部連携を持つプロダクトにおいて、この抵抗は新機能開発やバグ修正の時間の増大、テスト負荷の増加、新たな問題発生リスクの上昇という形で、ビジネスの適応能力そのものへの直接的な障害となっていました。

複雑さに立ち向かうための戦略と実践

前述の「複雑さ」に立ち向かうため、開発チームは「ドメイン駆動設計(DDD)の導入」と「会計ソフト依存からの解放」という二つの柱でアーキテクチャを大きく見直しました。

ドメイン駆動設計(DDD)の導入:ビジネスの本質と向き合う

請求書受取という複雑な業務ドメインを適切に扱うため、DDDを採用しました。これにより、ドメインエキスパートと開発者が共通言語で対話し、ビジネスモデルをコードに直接反映させることが可能になりました。

やったこと①:トランザクション境界の整理

従来は、一つの業務プロセスが複数のDBトランザクションにまたがったり、巨大な単一トランザクション内で多様な処理を実行したりと、トランザクション単位が曖昧でした。 DDDの「集約」概念を導入し、これをトランザクション整合性の単位としました。アプリケーションサービスが1つのトランザクション内で1つの集約ルートのメソッドを呼び出し、状態変更と永続化を行うよう整理しました。

やったこと②:Repositoryパターンの導入

以前のDAOパターンでは請求書関連だけで100を超えるメソッドが存在し、サービス層が具体的な永続化技術に密結合していました。 ドメイン層とインフラ層を分離するRepositoryパターンを導入しました。Repositoryは集約単位でのデータ取得・保存のインターフェースを提供し、具体的な実装はインフラ層に配置しました。これによりドメインロジックは永続化の詳細から解放されました。

このリポジトリレイヤーのリファクタリングとその効果に関する詳細については、同僚のwataruさんによる以下の発表資料が非常に参考になります。 speakerdeck.com

やったこと③:ビジネスロジックのエンティティへの集約

トランザクションスクリプトベースでは、ビジネスロジックがサービス層に散在し、エンティティは単なるデータコンテナ(貧血ドメインモデル)になりがちでした。 エンティティ自身が状態とビジネスロジックを併せ持つよう設計変更しました。例えば「請求書を処理済みにする」という操作は、請求書エンティティのComplete()メソッドとして実装し、条件チェックやステータス変更、さらには関連データの更新といった処理を内部で完結させるようにしました。

モデリングイメージ

会計ソフト依存からの解放:アダプターと設定ベースで柔軟性を獲得

やったこと①:連携部分のアダプター化と集約

会計ソフトごとの連携ロジックがコアロジックに散在し、 if (accountingSoftware == "A") {...} のような条件分岐が大量に存在していました。 アダプターパターンを導入し、共通インターフェース(AccountingSoftAdapter)を定義しました。 各会計ソフト用の具象アダプター(FreeeAdapter等)がAPI詳細を隠蔽し、コアロジックは共通インターフェースのみに依存するよう変更しました。 これは単なる互換性の確保にとどまらず、DDDの「腐敗防止層」としても機能しています。外部会計システムの多様なモデルから、バクラクの内部ドメインモデルを保護する役割を果たしています。

やったこと②:設定ベースの分岐による条件分岐の排除

アダプター選択や会計ソフトごとの微妙な振る舞いの違いが、依然としてコード内の条件分岐として記述されていました。 これらの差異を設定に分離しました。テナントごとに設定を読み込み、使用するアダプターや振る舞いを動的に決定するようにしました。 この変更により、分岐ロジックが命令的(コード駆動)から宣言的(データ駆動)へと変化しました。新しい会計ソフトへの対応や既存連携の変更が、多くの場合コード変更なしに設定ファイルの更新だけで可能になり、システムの柔軟性と保守性が大幅に向上しました。

改善による効果と学び

一連のアーキテクチャ変更は、「バクラク請求書受取」プロダクトに以下の顕著な効果をもたらしました。

開発効率と保守性の劇的な向上

DDDの導入により、ドメインロジックの関心事が明確に分離され、コードの見通しが格段に向上しました。ビジネスルールの変更時の影響範囲が特定のエンティティや集約に限定されるようになり、修正コストが低減し、不具合対応も容易になりました。 Repositoryパターンによってビジネスロジックと永続化ロジックが分離され、独立したテストや変更が可能になりました。請求書関連だけで100以上あったメソッドも集約単位に整理され、大幅に削減されました。

新機能追加・新規会計ソフト対応の容易化

アダプターパターンと設定ベースの分岐により、新しい会計ソフトへの対応が格段に容易になりました。多くの場合、新しいアダプタークラスの実装と設定ファイルへのエントリ追加だけで新規連携が可能になり、ビジネス要求への迅速な対応が実現しました。

エンジニアの心理的安全性向上とドメイン理解の深化

コードベースの変更が予期せぬ影響を与えにくくなり、エンジニアがリファクタリングや技術的負債の返済により積極的に取り組めるようになりました。また、DDDを通じてビジネスドメインへの理解が深まり、真に価値ある機能開発が可能になりました。

スコープを絞り、機能開発とセットでリファクタリングを行うこれらのアプローチにより、開発速度を落とさずに改善を実現しました。 技術的負債の返済は、長期的な開発生産性向上のための重要な投資であることが再確認できました。

おわりに

「バクラク請求書受取」が直面した複雑なビジネスドメインと技術的負債への取り組みを紹介しました。これらは多くの長期運用プロダクトに共通する課題です。 地道な改善サイクルを粘り強く回し続けたチーム全体の努力により大幅な改善を実現しました。しかし、これはゴールではなく更なる進化への一歩に過ぎません。 今後も業務プロセスの自動化やAI活用拡大など、ユーザーにとってより価値のあるサービスを提供するための技術的挑戦を続けていきます。

LayerXの「すべての経済活動を、デジタル化する。」というミッションに共感いただける方、技術の力で社会課題解決に貢献したい方は、ぜひ以下からご応募ください!

jobs.layerx.co.jp