Rails
PostgreSQL
ポエム

Salseforce、Node.jsをRailsに移行した話

今年1番の成果であったAPI、DB基盤のRailsへの移行をまとめてみました。
Railsに移行したことで得られたものは計り知れません。

  • DBマイグレーションが楽になった
  • 開発生産性が飛躍的に向上した(当社比200%アップ)
  • Circle CIでAPIのテストが行えるようになった
  • Railsはドキュメント、ノウハウが広く普及しているのでキャッチアップが比較的に容易

以前に書いた Node.jsのSequelizeでDBのmigrationを実行する も併せて読んでいただくと味わい深さが増すと思います。

概要

2017年7月~9月と10月の2段階に分けてDB統合とAPIをRails(5.1.2)に移行を実施しました。
API基盤としてRailsを選択したのはかつて実装、運用していたことがあったのが大きいです。
なお、謎のロジックや重複するAPIの廃止、統合も行いました。

  • 第1段階
    • DBをPostgreSQLに統合する
    • SalseforceのAPIを移行する(API数 80)
  • 第2段階
    • Node.jsのAPIを移行する(API数 40)

参考情報:旧システム構成

謎なシステム構成なのは歴史的経緯とか大人の事情とかなので論理的に考えてはいけません。

  • SalseforceとPostgreSQLの2つのDBがあり、一部テーブルはSalseforceからPostgreSQLに連携していた
  • 認証と主要APIはSalseforce、新規APIはNode.jsに実装する方針

移行作業詳細

DBをPostgreSQLに統合する

DBマイグレーションはRailsで管理、運用するようにしました。
新規にDB作成するケースを考慮して現状のDBスキーマの状態を作成する初期セットアップスクリプトを用意しています。Railsプロジェクトに db/migrate_init ディレクトリを用意し、 INITIAL_MIGRATE=true を指定した場合は初期セットアップを実行するようにしました。

INITIAL_MIGRATE=true bin/rake db:migrate

初期セットアップ用のDBマイグレーションスクリプトは以下のようなSQLの結果を利用して生成しています。

SELECT table_name, column_name, data_type,  is_nullable, column_default, character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position

APIを移行する

フロント側の修正が必要なのと検証コストを考慮して最初にSalseforce、次にNode.jsと段階を分けています。APIを移行する上で以下のルールを徹底し、URIだけでどんな処理をするかが分かりやすくなるようにしました。

  • URIはREST APIのルールを徹底する
  • 正常系のテストは必ず書く
    • RSpecはコントローラーのテストが書きやすいので苦にはならなかった
  • curlや DHC で実際に動かす

移行作業を行ううえで大事なこと

  • 信念と強い意志でやり抜く
  • チーム内に移行の意義、生産性向上を強く訴え続ける

オマケ:移行に至った背景

Salseforce、Node.jsともプロダクトが対象とするドメインと運用方法に噛み合っておらず、開発生産性が低く、運用がツラかったことによります。

Salseforceのつらいところ

  • 独自言語であるApex(Java風味)で実装しなければならない
  • デプロイ方法が古式ゆかしい
    • ユニットテストのカバレッジ70%を超えていないとデプロイできないがテスト支援が微妙
    • 意味のないユニットテストをはびこらせる温床
  • DBの仕様が独特
    • テーブル、カラムを追加する場合は __c という接尾辞をつける必要がある
    • IDは独自の採番ルールによる18桁の文字列になる
    • IDはユーザーが指定できないので複数環境で運用するのがつらい
  • 外部からDB操作をする際は SELECT文しか 実行できない
    • しかも SELECT * が使えない、必ずカラム名を指定する必要がある
  • ガバナ制限により実装方法が制限される
    • 1トランザクション内で実行できるDMLが150回まで
    • LongText型を使用しているとSOQLのLIMITのOFFSETが200までに制限される
  • ドキュメント、ノウハウを調べるのがつらい

Node.jsのつらいところ

  • 認証やログ出力などの基盤処理を共通化できず、API毎に呼び出しを書かないといけない
    • Expressが微妙なだけなのかも
  • 1リクエストで複数のリソースにアクセスする必要があると途端に実装がつらくなる
    • 業務系のドメインには向かない
  • CPUヘヴィな処理があると死ぬ
  • ライブラリが未成熟なものが多く、ハマった時につらい
  • デバッグ・テストがつらい

DBマイグレーションの変遷

  • PostgreSQLは当初は初期セットアップ用のSQLスクリプトのみしかなかった
    • 変更が発生した場合は手作業でスキーマを変更していた
  • DBマイグレーションをNode.jsのSequelizeで行うようにした
    • スキーマ変更毎にモデルクラスを修正するのがダルい
    • 複数の環境に適用するための手段が標準で用意されていない
  • ActiveRecordクローンのSequelizeより、ActiveRecordでDBマイグレーションをしたくなる