FineractはApache Foundation傘下のオープンソースプロジェクトとして、金融サービスのためのオープンソースプラットフォームとして知られています。近年、コミュニティの成長と貢獻量の増加に伴い、単體アーキテクチャの限界が顕在化し、モジュール化の必要性が高まっています。本記事では、Fineractのモジュール化における現狀、技術的課題、および今後の方向性について解説します。
モジュール化の動機
Fineractのモジュール化は、以下の要因から必要とされています。
- コミュニティの成長と貢獻量の増加:過去2年間で貢獻量が前年比で數倍に増加し、年間4つのバージョンのリリースが可能となっています。しかし、開発者の経験不足により、開発プロセスが不安定化しています。
- 開発者體験の改善:単體アーキテクチャでは、機能間の依存関係が複雑になり、開発者が不必要なツールクラスを再利用しやすいため、機能間の結合度が高まっています。
- 安定性の向上:コミュニティが安定したコードベースを求める中、モジュール化によりバージョン管理と機能の隔離が可能になります。
- カスタマイズの柔軟性:単體アーキテクチャではカスタマイズが困難なため、標準化されたモジュール化フレームワークの構築が求められています。
アーキテクチャと技術的詳細
Fineractのモジュール化には以下のアーキテクチャと技術的選択が採用されています。
- 分層構造:
- REST API層:初期はJAX-RSを使用していましたが、Spring BootのJSONシリアライズを採用。しかし、データ構造の複雑さにより手動処理が必要な狀況が生じています。
- CQRSパターン:読み取り要求とデータ変更要求を分離し、獨立した拡張性を実現しています(書き込みインスタンス/読み取りインスタンス)。
- データ層:初期はHibernateを使用していましたが、Apache Foundationのライセンス問題によりOpenJPAに切り替え、最終的にはEclipseLinkを採用。一部の機能ではPostgreSQLをサポートするため、原生SQLの使用が行われていました。
- サービス層:Springの@Serviceアノテーションを使用し、ビジネスロジックとデータベースアクセス(Repository)を含んでいます。
- モジュール化の実踐:
- レポートエンジンモジュール:GPLライセンスの問題により獨立モジュールとして分離され、獨立したJARファイルとして提供されています。Fineractのデータパラメータを修正し、外部モジュールのサポートを実現しています。
- Fineractクライアントモジュール:標準化されたAPIクライアントを構築し、OpenAPIの記述子を用いて機械可読なドキュメントを生成。Code Generatorツールの開発も進められています。
- コアモジュールの分割:コアモジュール(Core Module)とその他の機能モジュールの分割を試みましたが、モジュール間の依存関係の問題が殘っています。
技術的課題
モジュール化の進展に伴い、以下の課題が顕在化しています。
- JSONシリアライズの問題:
- 手動でのJSONシリアライズ/デシリアライズにより、ビジネスロジック層と通信プロトコルが結合しています(今後gRPCへの移行が検討されています)。
- データ層の複雑さ:JPAと手動SQLの混合により、データベースの獨立性とクエリ生成ツール(QueryDSL、JQ)の統合が課題となっています。
- モジュール化構造の設計:
- モジュールパッケージ構造:
API
:RESTリソースクラス(エントリポイント)。
Data
:データ転送オブジェクト(DTOs)、サービスインターフェースと実裝(ビジネスロジック)。
Domain
:データベースとJavaオブジェクトのマッピング。
Repository
:データベースアクセス層。
- 現在の問題:データ層とサービス層の結合が強く、真のモジュール化を実現するための再設計が求められています。
今後の展望
Fineractのモジュール化には以下の方向性が示されています。
- Spring Modulithフレームワークの導入:単體アーキテクチャとモジュール化の特徴を融合させ、モジュール化設計の參考として活用されます。
- モジュール化の標準化:
- コアモジュールと機能モジュールのさらに明確な分割を行い、モジュール間の依存関係を削減します。
- OpenAPIを用いたクライアントツールの生成により、APIの利用効率を向上させます。
- 技術的最適化の方向:
- QueryDSLやJQなどのツールを導入し、手動SQLとJPAの混合使用の問題を解決します。
- データベースの獨立性を高め、PostgreSQLなどの多様なデータベースへのサポートを強化します。
現在の狀況
- モジュール化の進捗:レポートエンジンとクライアントモジュールの実裝が完了していますが、コアアーキテクチャはまだ単體アプリケーションのままです。
- コミュニティとバージョン管理:
- 最大3つのマイナーバージョンをサポートし、安定性を確保しています。
- バージョンリリースの頻度が向上していますが、開発者のボトルネックの改善が課題です。
- アーキテクチャの改善:
- Gradleモジュールを段階的に分割し、単體コードの結合度を低下させています。
- 技術的なディスカッションを通じて、JPAの完全な除去を検討し、より柔軟なデータベース操作方式への移行を模索しています。
モジュール構造と設計
- モジュールの分割:
- モジュールはJavaパッケージ(package)に似ており、サブパッケージ(sub-packages)を含みます。
- 現在の構造には以下が含まれます:
- APIパッケージ:RESTリソースクラス(エントリポイント)。
- データパッケージ:データ転送オブジェクト(DTOs)、サービスインターフェースと実裝(ビジネスロジック)、ドメインクラス(データベースとJavaのマッピング)、リポジトリ(データベース操作)。
- デザイン図と実際の実裝の間にはギャップがあります。
- データ層の問題:
- JSONデータとJavaの対応処理は手動で行われ(Gsonを使用)、冗長で複雑な処理が発生しています。
- プロセスを簡略化するために、一部の層はデータ層をスキップし、サービス層に直接データを渡すことで、ビジネスロジックと通信プロトコルの結合が生じています。
- 現在の技術的負債:ローンエンティティクラス(Loan Entity)には7,000行ものコードが含まれており、屬性とGetter/Setterのみを含めるべきであるにもかかわらず、実際にはビジネスロジックやユーティリティ関數が混在しています。
技術的負債と依存関係の問題
- ドメイン境界の曖昧さ:
- ローン、ユーザーなどのエンティティデータには、モジュール間の依存関係(例:ローンとユーザー表の関連性)が存在しています。
- ユーザー情報はセキュリティモジュールに屬するべきですが、ローンモジュールが直接參照しているため、データの隔離性が損なわれています。
- ユーザーインターフェースの要件(例:ユーザー名をIDではなく表示)がデータ構造設計を駆動し、結合度を高めています。
- テストとビルドの課題:
- テストケースの數は約900以上ありますが、ビルドプロセスはシリアル実行され、フィードバックループが1時間以上かかることがあります。
- 開発者はGitHub Actionsを使用してテストを実行する傾向があり、問題の発見が遅延しています。
- データベース層の問題:
- 手動でSQLを書く際、データの隔離性を考慮せず、モジュール間のJOIN操作が行われています。
- コンパイラがこのような問題を検出できないため、靜的チェックメカニズムの不足が問題となっています。
カスタムモジュールと解決策
- カスタムモジュールの設計:
- 新しい機能は獨立したディレクトリに分離し、上流プロジェクトと混在しないようにする必要があります。
- 自動化ツールの提供:
- 依存関係の自動処理(例:Gradleの構成)。
- カスタムJavaコードとLiquibaseスクリプトのサポート。
- カスタムモジュールを含むDockerイメージの自動パッケージング。
- モジュール置換メカニズム:
- 原サービスインターフェースの
@Service
アノテーションを削除し、Javaの構成で條件付きロードを実裝。
- 原機能の完全置換または拡張(特定のメソッドの上書き)が可能になります。
セキュリティモジュール化と今後の方向
- セキュリティモジュールの進捗:
- 現在はSpring Securityを使用していますが、権限やロールなどの情報はデータベースに保存されています。
- Spring Authorization Serverとの統合を計畫しており、Fineractが獨立したIDサービスとして機能するようになります。
- 外部サービス(例:Keycloak)をIDサービスとしてサポートし、今後は置き換え可能な設計に移行します。
- 他の改善方向:
- 必要のないモジュール(例:インフラストラクチャ構成モジュール)を削除し、Kubernetesなどの構成管理ツールを使用。
- ArcUnitなどのツールを導入し、アーキテクチャのチェックを自動化し、アーキテクチャルルールのテストを実施。
現在の課題と提案
- モジュール化の進捗:
- 現在は単體アプリケーションですが、內部ではモジュール化された機能を管理しています。
- 今後の目標は、モジュールを段階的に分割し、ドメイン境界とデータの隔離性を強化することです。
- カスタムモジュールのルール:
- 新しい機能を追加する際には、ドメイン境界を明確にし、非関連のデータを混入させないことが求められます。
- カスタムモジュールは命名空間ルール(例:會社名)に従い、ネストレベルを最大3層に制限する必要があります。