メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックカンパニーのエンジニアブログです。読者に有用な情報発信ができるよう心がけたいので応援のほどよろしくお願いします。

レガシーな独自フレームワークから脱却してRailsへ徐々に移行している話

みなさんこんにちわ。 メドピアでエンジニアをやっている内田と申します。

現在メドピアではPHPで作られたレガシーな独自フレームワーク (以下FW) からRailsへと移行するプロジェクトが進んでいます。 今回は移行に向けて行ったことについて共有したいと思います。

移行の計画

メドピア株式会社では、医師限定のコミュニティサイト「MedPeer 」を運営しています。 「MedPeer 」サービス内では、薬剤評価掲示版、症例相談、Forum、ニュースなど、医師同士が情報交換をするための、機能の異なる複数のサービスを提供しています。

それらサービスの内部では7年前に作られたPHPの独自FWが採用されており、コードが肥大化したことで機能の変更や追加がとても困難になっていたことが課題でした。

そうした課題を解決するために、アーキテクチャの見直しを含めたリプレースがエンジニアの主導で計画されました。 様々な言語を比較する中で、生産性の高さやコミュニティが活発なところに魅力を感じて言語はRubyへと決め、FWは独自で作るよりもOSSの方がより多くの開発者によって開発が行われているため、新しい機能が使えたり安定性が高いといったメリットがあるだろうと考え、Railsへと移行することに決めました。

しかし、移行するにしても「MedPeer」はとてもモノリシックな上に、機能によってはもはや誰も知らないコードなども存在しており、一筋縄ではいきません。 一度に全てを移行するという方針だと数年はかかりそうです。その間ビジネスを止めるわけにはいかないので、移行の間も新サービスの開発だったり機能の追加を常に行っていく必要があります。

そこで、既存の機能追加は今まで通りレガシーな旧環境で開発しつつ、新サービスやサービスごと移行したいものに関してはRailsの新環境で開発していく、という方針を取ることにして、両環境を運用しながら徐々に移行することにしました。そのためにまずは旧環境と新環境2つを連携して並列稼働させる仕組みが必要でした。

やったこと

具体的にやったことは以下の3つです

  • urlごとの振り分け

  • 共通処理の切り出し

  • データの同期

urlごとの振り分け

urlの振り分けは、nginxを使ったリバースプロキシー先の振り分けです。ドメインは両環境で同じにしてたとえば、/aaaときたurlは旧環境に、/bbbときたurlは新環境にと振り分けるようにしました。 幸いMedPeerは前述の通り複数のサービスで成り立っておりサービスごとにurlが異なり依存度も少ないためこの方法は合っていました。 注意点としては両環境でurlがバッティングしないように設計する必要があったり、同一ドメインであるためcookieの扱いに気をつける必要があることです。

f:id:yutauchida:20170130140305p:plain

共通処理の切り出し

両環境にて共通に処理する必要のある機能が存在します。たとえば認証です。認証したら環境をまたいでもセッションをセキュアに維持できる仕組みが必要です。 これに対しては既にAPIゲートウェイとして認証部分を別のアプリケーションとして切り出していたためそれを新環境でも利用するようにしました。こういった共通処理を切り出しておくと他サービスでも連携しやすいといったメリットがあります。実際にメドピアの他サービス(キャリア、イシコメ)でも認証部分はAPIゲートウェイを利用しており、サービスのスケールに寄与しています。APIゲートウェイを開発した際の話についてご興味ある方はこちらをご参照ください。

Golang(Go言語)を採用して、たった二人で基盤となるAPIゲートウェイを開発した話 - メドピア開発者ブログ

データの同期

両環境ではユーザーテーブルなど共通のデータを利用する必要があります。 当初は現行のDBを共用することも考えましたが以下の理由でやめました。

  • テーブルの設計がRailsに最適化されていない

  • 移行を機にDB構造を見直したい

RailsはDBに対してある一定の規約があります。例えば主キーはidが望ましいといったことです。 旧環境のDBでは主キーがid以外に設定されていたり、テーブル名が複数形になっていないなどRailsを利用する にあたって最適化されていないという問題がありました。また、長年DBを運用していて設計上見直したい部分が多々ありました。例えば 以下の内容です。

  • 不要なテーブル、カラムが存在している

  • カラム名が適切でないため理解しにくい

  • 正規化が適切にされていない

  • indexã‚„unique制約が適切に貼られていない

移行をいい機会としてこれらを見直して再設計したいこともあり、DBは新しく作るという方針を立てました。 そのために2つのDBのデータを同期する必要があったため、両環境のDBを橋渡しする役割のアプリケーションを作りました。 それがDB-SYNCです。

f:id:yutauchida:20170130152525p:plain

DB-SYNCは旧環境のデータを新環境でも使いたい場合にデータを任意の形にコンバートします。例えば旧環境であるユーザーのEmailが更新されたとします。 その際に更新があったことを通知するテーブルに登録されます。DB-SYNCはcron&キューの処理としてそのテーブルをreadして更新のあった対象のテーブル とデータを判別します。その後、旧環境のDBから対象のデータをFetchして、新環境のDBに新しく設計されたテーブルのどのカラムに対応するのか を変換ルールが定義されたファイルを参照しながらUPSERTを行います。変換ルールが定義されたファイルは例えば以下のような内容が記載されます。

user:
  old_table: portal.users
  column_name_mappings:
    id:              old_user_id
    last_login_time: last_logged_in_at
    account_id:      email
    state_cd:        registration_status
    profession_id:   profession_type
    physical_deletable: true
    unsync_columns:
      - id

DB-SYNCでは命名の変更だけでなく、2つのテーブル を統合して再設計した一つのテーブルにデータを登録していくといったことも可能になっています。その他のポイントとしてはデータの流れは 旧環境から新環境への一方向のみとしています。理由としては、両環境でデータが行き来すると煩雑になり障害発生時に原因の究明に時間がかか るのではと考えたのと、逆方向へのデータ同期によりそれを使う機能を開発する要件があるならば、それは新環境での開発を促すべきだというポリシ ーのもとで、そのようにルール化しました。

まとめ

以上のような施策を行い2016年の夏にRailsで作られた新システムがリリースされており、現在は2つの環境が安定して動いています。 徐々に移行することで比較的小さいリリースとなるので大きな障害が起きにくいといった安心感があるのと、Railsでの開発ができるようになったので楽しんで開発しているエンジニアが見られるようになったのはポジティブな要素だと感じています。

また、Railsアプリケーションの立ち上げについてはパーフェクトRuby on Rails共著の前島さんを始め、株式会社 万葉のエンジニアさんなどRails に知見があるメンバーに推進してもらいました。今後規模が大きくなると予想されるアプリケーションで新しい言語やFWを採用するに あたって経験豊富なエンジニアにしっかりとした土台を作ってもらい、その上で開発していくことが長く運用していくうえで大事だと考えています。

近頃、大規模アプリケーションをRails化しているという案件を聞くことが多くなった気がします。そういった計画を考えている方に弊社 の事例が一つでも参考になれば幸いです。