こんにちは。dodaダイレクトアーキテクトGの池田です。
私達が開発しているdoda ダイレクトは企業が転職希望者さまに対して直接スカウトをするダイレクトソーシングサービスです。今後、ダイレクトソーシング市場は拡大していくことが予想され、弊社システムも機能追加やユーザの増加に耐えられるアーキテクチャにすることが急務となってきます。
開発当初からサービスが急成長したこともあり、規模感に合わないアーキテクチャとなりました。目先のリファクタリングだけでは品質や生産性の問題を解決することが難しい状態であるため、システムをアーキテクチャから再構築し根本から解決する事となりました。
多くのサービスが成長して、10->100のフェーズに入ると少なからず同様の問題が発生すると思います。プロジェクトの規模としては大きく挑戦的な事をしていくので同じような状況の方に参考になれば幸いです。
アーキテクチャ再構築に至った理由
現状
ロジックが全体的に密に結合しており、コードのメンテナンスが困難でバグの修正や新機能の追加にも相当な時間を要します。また、他のシステムとデータが同居する「共有データベース」になっています。そのためデータのメンテナンスが困難で他システムと修正の整合性を合わせる必要があります。いわゆる「分散モノリス」となっています。
まとめると下記のような問題が発生していました。
- コードのメンテナンスが困難
- 品質の劣化
- 生産性が上がらない
- ライブラリなどを気軽に更新できない
- パフォーマンスチューニングが困難
- 共有データベース・分散モノリス
- テーブルをどのシステムから利用されているかわからないので影響範囲の調査に時間がかかる
- 他プロダクトとバージョンの整合性を確保するためにソースの改修を止める必要がある
問題の特定
なぜ、現状のようになったのかということを考えました。
機能ベースの設計
弊社が扱っているシステムの規模になると機能数が膨大になります。それを1つのシステムで賄おうとするとメンテナンスが困難になるほどのモノリスシステムが出来てしまうのでシステムを分割する必要が出てきます。問題はその分割を機能で分割していることです。システムは業務的に関連を持っているためデータを共有する必要が出てきます。それが共有データベースになったと推測しました。
書込み可能なデータ共有
意図した形で安全に他のシステムとデータベースのテーブルを共有すること自体が完全に悪いというわけではありませんが、問題は同じスキーマにどのシステムからも書込み可能な形で公開しているということです。そのため、意図しない形でデータの書き換えが行われる可能性が高く、影響調査に時間がかかり改修を困難にしています。
共通のコードベース
クローンしたコードをベースにプログラムが作成されています。良い部分も悪い部分も引き継がれてしまっています。問題は仕様を共有する部分までもがコードで引き継がれていることです。改善するときも同じようなコード修正が必要となります。分散モノリスの一因となっていると推測されます。
密結合のフロントエンドとバックエンド
アーキテクチャのレイヤーの責務がうまく理解されておらず、レイヤー間が密結合になっています。特に深刻なのはフロントエンドとバックエンドの結合です。ロジックが複雑になり手を付けられなくなっています。
対策
現状から迅速な機能の追加やユーザの増加に耐えられるアーキテクチャにすることは困難であるため、アーキテクチャ再構築を行うという決断となりました。
アーキテクチャ再構築の方針 - ドメイン駆動設計(DDD)
新アーキテクチャはドメイン駆動設計(DDD)に基づき設計を行っていきます。
業務的にも技術的にも密に結合してしまった分散モノリスをマイクロサービスに分離するためのアプローチとして最適だと考えました。
ドメインモデリング
現行のシステムでは機能ベースで考えられ入力されたデータをテーブルに保存するといったデータ中心の考え方で設計されています。結果的にシステムには業務的な意味合いが薄くなり、メンテナンスが行いづらいシステムになっています。また、システムをどこで分割すればよいのかという明確な指針がないため機能的にシステムは分割されていますがデータベースは共有されています。そのためお互いが依存し合うといった状況となっています。
ドメインモデリングを行う事により実現したい業務が視覚化されて整理を行うことが出来ます。何も考えずにモデリングを行うと巨大なモノリス構成のモデリングになるので、業務的な関連を見極めて業務を分類します。これがマイクロサービスへ分割するための最初の一歩となります。
アーキテクチャ
完全移行するためにはいくつかのフェーズが必要になると想定しています。最初のフェーズとしては下記の構成を考えています。
- 対象ドメインのデータを特定し、共有データベースからデータを独立させます。
- 自ドメイン以外のサービスからの直接利用を避けるため、データベースはそのままでマイクロサービスとして切り離します。
- マイクロサービスとして切り離したサービスはGraphQLとして公開し、Federationを使ってサービスを合成します。これにより、フロントエンドから見たサービスは1つのエンドポイントとなり、バックエンドに隠れているマイクロサービスを意識せずに利用できます。
- バックエンドではデータが更新されるたびにドメインイベントを発生させます。
- ドメインイベントはオーケストレーターで一元的に購読されます。オーケストレーターでは、結果整合性のためのワークフローを実現することもあります。
- オーケストレーターはデータ同期のためのData Sync Serviceを呼び出します。新しいデータベースに書き込まれた内容と同等のものを共有データベースにも書き込みます。 同等のデータを書き込んでおくことで、既存のバッチ処理などの仕組みに影響を与えないことを想定しています。
GraphQL
これまではフロントエンドとバックエンドが密に結合し修正の影響があちこちに起きていました。新しいアーキテクチャではドメインモデリングしたモデルをGraphQLのモデルとして表現しクライアントに公開していきます。このようなAPIデザインにすることでフロントエンドとバックエンドの連携がシームレスになります。
また、GraphQLはFederationという仕組みを使うことでマイクロサービスとして分割されたサービスをまとめることができます。この仕組みによりフロントエンドはバックエンドのマイクロサービスを意識せずに1つのエンドポイントへのアクセスで済みます。
ドメインイベント
エンティティの変化に応じてドメインイベントを発行します。イベントをサブスクライブすることでシステム間を疎に保ち連携させていきます。実現するためのプラットフォームとしてDaprを採用し、イベントソーシングやマイクロサービスの呼び出しの複雑な部分を解消していきます。
フロントエンド
詳細はまだ決まっていませんが、SPAフレームワークで作成していきます。バックエンドのGraphQLが動的なBFFのような振る舞いとなるため、軽微な機能改修はフロントエンドだけの修正となり、開発リードタイムが縮まることを想定しています。
システム移行の計画
データの同期
先述したように共有データベースを使っているためデータが別のシステムから利用されている可能性があり、うかつにデータを移行させたからと言って削除することは危険です。安全性を確認できるまでは既存のデータベースに新データベースに書き込んだ内容と同等のものを書き込む必要があります。データが変更されるとドメインイベントが発行されるのでそれをトリガーにデータを同期させる事とします。
機能別の移行
ドメインを分析し、業務的に疎結合かつ機能的にも分割できそうな箇所を探し、機能ごとに分割することを模索しています。
ビッグバンリリースを避け、機能別に移行することで不測の事態へのリスクを軽減させます。
まとめ
全体的にDDDの考え方をベースとしたアーキテクチャとなっています。 現行のシステムと考え方も作り方も大きく変わるため、アーキテクチャだけでなく、メンバーの技術スキルのアップデートもセットで行う必要があり挑戦的なプロジェクトになりそうですが頑張っていこうと思います。
池田 庸一 Yoichi Ikeda
タレントソーシング事業開発本部 プロダクト統括部 プロダクト開発部 dodaダイレクト_エンジニアリンググループ シニアエンジニア
基幹系のエンタープライズシステムからSaaSなど様々なシステム開発を経験し、2023年9月にパーソルキャリアに入社。 現在はシニアエンジニアとしてプロジェクトを牽引。
※2024年4月現在の情報です。