Baseconnect
Baseconnect、企業情報データベース「Musubu」の営業リスト機能をRails+Neo4jからGoへ移行
Neo4jのORMであるactivegraphが依存するドライバーが公式サポート外で、最新メジャーバージョン11ではCRubyのサポート自体が切られたこと、Elasticsearchとの複数DB更新でデータずれが起きていたことから、営業リスト機能だけをGoで作り直した。
課題
Neo4jのORMが公式サポート外のドライバーに依存し、最新版ではCRubyサポートも切られた
アプローチ
全面移行はせず、営業リスト機能だけをGo+軽量DDD/クリーンアーキテクチャで作り直す
効果
レイヤーが疎結合になり、APIテスト中心から単体テストを書ける状態へ改善
背景
Baseconnectが提供する企業情報データベース「Musubu」は、メインDBにNeo4j、検索用のDBとしてElasticsearchを採用し、バックエンドはRuby on Railsで実装されていた。ところがグラフDBであるNeo4jの特性は、採用された当初で想定していたほどには必要とされておらず、Neo4jを採用するメリットが極めて薄い状態になっていた。技術的な足かせも大きく、Neo4jのORMであるactivegraphが内部で依存しているドライバー(neo4j-ruby-driver)はNeo4j公式サポートのものではなく、さらにORMの最新のメジャーバージョン11ではCRuby自体のサポートが切られていたため、Neo4jのバージョンを上げていくことも難しくなっていた。運用面では、データの変更があった場合にそれをElasticsearchへ逐次反映させる必要があり、この「複数DBの更新」という行為がトランザクションの制御や更新トリガーの漏れといった問題を容易に引き起こし、かなりのデータのずれを引き起こしていた。Rails MVCではビジネスロジックの記述場所が不明確でモデルが肥大化しやすい、という設計上の課題も重なっていた。
移行のプロセス
Goへのリプレイスを既存のアプリケーション全てで行うことは、あまりにもシステムが大きすぎるため現実的ではないと判断された。そこで機能領域で分割し、段階的に進める形を採った。
- 営業リストの機能をGoでリプレイスし、それ以外の機能はRailsに残す
- Go側のアーキテクチャとして軽量DDDとクリーンアーキテクチャを採用し、関心の分離とレイヤーの責務を明確化する
- アーキテクトがベースとなる実装を用意したうえで、Go未経験のエンジニアも開発に加わる体制をとる
- パフォーマンス最適化とコードの可読性のトレードオフを都度検討しながら実装する
Goの厳密な型定義により、Rubyのメタプログラミングによる曖昧さが排除され、IDEの補完も効くようになった。一方でGo向けのデファクトスタンダードと呼べるライブラリが不足している領域もあり、選定には手間がかかった。
結果
営業リスト機能をGoへ移すことで、Neo4jのORMとドライバーのサポート状況に開発が縛られる状態から抜け出せた。アーキテクチャ面では、軽量DDDとクリーンアーキテクチャの採用によりレイヤー間が疎結合になり、単体テストもしやすくなった。それまではほぼAPIのテストしか書かれていなかったが、安心してコードの再利用ができるという状態になった。型が厳密になったことで認知負荷も下がっている。なお記事中に移行期間やコスト削減額などの定量的な数値は示されていない。
学び
大きなシステムを一度に置き換えようとせず、機能領域で切って営業リストだけを移すという判断が移行を現実的なものにした。一方で筆者は「私自身、振り返ってみるとクリーンアーキテクチャをちゃんとした形で実現できていない部分もあるな、という感想もあります」と述べており、設計パターンの導入は移行と同時に完成するものではないことも率直に語られている。
