技術改善チームの心強いエンジニアメンバーから学んだインボイス対応「攻めのアーキテクチャ」

こんにちは、アドプラットフォーム事業で開発業務を行っているリードアプリケーションエンジニアのまっちゃんです。

同じ時期(2月)に執筆し続けて、今回で3回目(3年目)を迎えることができました。
去年執筆時から今までをふりかえってみると、プロダクトチームのプロジェクトリーダーから技術改善チームへ異動、異動後はアプリケーションコードの修正・GitHub Actionsの実装・新しいアーキテクチャでの開発など、開発比率を少しずつ増やすことができました。
ですが開発量はまだまだ少ないと感じるため、日々のお問い合わせやアラート対応を始めとした運用業務を後輩に任せつつ、メインプロジェクトの開発にコミットメントできるよう日々奮闘しています。

本日は技術改善チームの心強いエンジニアメンバーと一緒に、インボイス対応の開発を行いました。
どのようなアーキテクチャで開発を行ったのか、簡単に学びを共有させて頂きます。

背景

インボイス制度そのものについてはADWAYS DEEE公式サイトより引用させて頂きます。

インボイス制度とは インボイス制度とは、2023年10月より開始される「適格請求書(インボイス)」を用いた消費税の仕入税額控除を受けるための制度です。従来は区分記載請求書に基づいて仕入税額控除を行っておりましたが、2023年10月以降は適格請求書(インボイス)の保存等をもって仕入税額控除を行わせていただきます。

適格請求書(インボイス)とは、現行の「区分記載請求書」に「登録番号」、「適用税率」及び「消費税額等」の記載が追加された書類、またはデータです。

引用: ADWAYS DEEE | インボイス制度に関する対応方針について

ASP(アフィリエイト・サービス・プロバイダー)事業者として、下記2点の対応が必要になります。

  • 適格請求書発行事業者登録番号(以下登録番号)の登録ができること
  • 適格請求書(インボイス)を満たす支払い明細書の発行ができること

私達の部署では複数のサービスを運用しているため、それぞれのサービスで登録番号の登録や支払い明細書の発行ができるようになる必要があります。
インボイス対応が必要なサービスへの対応はすべて技術改善チームで行うことになりました。
技術改善チームはメインで担当しているサービスはあるものの、基本的には技術的な課題を解決することが求められるため、複数サービスへの対応が必要になることがあります。

システム構成

上記の背景を踏まえ、どのようにシステムと紐づけていったのかを紹介します。

フェーズ0: 開発準備

まずは登録番号を登録できるようにする必要がありますが、今回はゼロから作るのでどのような構成にするかを考える必要があります。
方針としては「各サービスでAPIやDBを持たず、基盤APIや共通DBを作成する」ことになりました。

1サービスだけのスコープで考えてしまうと、各サービスで処理やデータを持つことになります。

この状態だと1サービスを作れば横展開だけで済みそうですが、純粋にサービスの数だけ開発・運用のコストが増えることになります。
同じコードが複数のサービスで存在することになり、修正時も全サービスの修正しないとおかしな挙動になってしまいます。
そのため今回はインボイス対応に伴う処理については基盤APIや共通DBを作成し、各サービスでは作成した基盤APIを利用することにしました。

サービスごとにAWSアカウントが異なることが障壁になるかと思いましたが、ちょうど Amazon VPC Lattice(以下VPC Lattice)が一般利用可能になるというナイスタイミングでした!
VPC Latticeを利用することで、複数のAWSアカウント間でのネットワーク接続を簡単に行うことができるのでとても便利です!
インフラストラクチャーDivの担当者に相談を行い、サービスネットワークを構築してもらいました。(すぐに検証、設定してもらい助かりました!)

インフラストラクチャーDiv側でVPC Latticeのネットワークを構築した記事もありますのでぜひそちらもご覧ください!

API実行環境は社内でも利用が増えているAmazon ECS/AWS Fargate(以下ECS)を引き続き採用しました。

DBについては基本的に登録番号関連の情報のみを管理します。
とにかくシンプルさを重視し、コストも抑えることができるDynamoDBを採用しました。

フェーズ1: 登録番号の登録

基盤側ができたら、各サービスでは登録番号を入力してもらうインターフェースを作成し、基盤APIを呼び出します。
そうすることで登録番号を反映できます。
登録番号は国税局から提供されているAPIを利用して現状の情報が正しいのか、を登録時や定期的にチェックも行うようにしてます。

ここまでをまとめるとこんなイメージです。

フェーズ2: 支払い明細書の発行

登録番号を登録できるようになったら、次は支払い明細書の発行ができるようにする必要があります。
支払明細書発行自体の処理は基盤APIに乗せることになりますが、SQSをポーリングするデーモンとして動かすため、ECS上には同じクラスターの別サービスとして乗せました。
また、定期生成や手動再生成について考える必要があります。

定期生成にはAmazon EventBridge(以下EventBridge)のスケジュール機能を利用しました。
スケジュール設定でAmazon SQS(以下SQS)のキューに対して一定間隔でメッセージ送信ができます。
SQSをポーリングしているデーモンはSQSにメッセージが入っていれば、支払い明細書の発行処理を実施します。

手動再生成については、直接SQSのキューにメッセージを送信すればOKです。
記事公開時点ではすでに運用が開始されてますが、運用難易度が低くチームに配属された新卒メンバーもすぐに対応できるようになりました。

学びポイント

1: VPC Lattice採用までの流れとスピード感

現状クラウド移行が進んでいますが、既存の内部実装には手を加えずまるっと実行環境を置き換えるケースが多いです。
そのためAmazon EC2/Amazon Aurora(以下Aurora)の構成が中心となっています。
さらにコンテナ推進の動きもあり、一部サービスについてはECS/Aurora構成もあります。

今回は本番実績の少ないDynamoDBの採用や、一般利用可能となったばかりのVPC Latticeの採用などがありました。
VPC Latticeは世界的に見ても新しいサービスで情報が少ない状況だったのですが、提案したシニアエンジニアがすぐに情報収集、技術検証、社内の関係者との調整を行い、即本番投入することができました。
間近で見ていても一般利用可能から本番導入までのスピード感はとんでもなかったです!
要件がニーズにマッチしていたり、技術的な課題を解決するための最善な選択として情報量が少なくても積極的に選定する姿勢はまさに「攻めのアーキテクチャ」だと感じました。

内部実装については触れていませんが、 Scala3/ZIO2の最新バージョンの使用、APIサーバをPlay Frameworkからtapirへ変更するなどを行い開発を進めました。こちらも攻めてます。

2: サーバーレスなイベント駆動アーキテクチャ

支払い明細書の発行部分はクラウド環境を活かしたイベント駆動のアーキテクチャとなっています。
EventBridge -> SQS -> ECSで処理を行うことで、支払い明細書の発行は完全に独立して処理を考えることができます。
SQSへのメッセージ内容を設計することで、定期生成や手動再生成についても柔軟に対応できるようになりました。

クラウドのメリットを活かしたアーキテクチャだと思います。

最後に

今回はインボイス対応の開発において、どのようなアーキテクチャで開発を行ったのかをまとめてみました。

久々の大きめの開発でしたが、アプリケーションもインフラも強いエンジニアメンバーと一緒に開発を行うことで、とても楽しい時間を過ごすことができました。

日々さまざまな議論やアウトプットがある一方で開発がしばらくできていなかった自分にとってはついていくのがやっとで貢献量も少なく、技術力を維持するためには一定の開発が必要だと強く感じました。
引き続き新規開発、リファクタリング問わずプルリクエスト総数を増やしていくことが今期の目標です。

もし次に技術選定を頂ける機会があればこのような攻めのアーキテクチャで開発を行いたいですね!!