サーバーサイドのレガシーシステムを、ビッグバンではなく堅実にリプレイスした話

サムネイル

はじめに

こんにちは。DMM.com 二次元コンテンツ事業 同人開発部 の鷹羽です。
普段は部長として約40名規模のエンジニア組織のマネジメントをしています。

本記事では長年利用されてきたサーバーサイドのレガシーシステムを、ビッグバンではなく堅実にリプレイスした ときの手法や学びについて記載します。
同じようなことで悩まれている方の参考になれば幸いです。

サーバーサイドのレガシーシステム

長年利用され続けているシステムであり、DMM社内で作られたPHPの独自フレームワークです。

新規機能の開発など長年使い続けてきた結果、様々な課題が出てきたため、リプレイスをするという決断をしました。

レガシーシステムの課題

リプレイスという判断に至った主な課題は以下の通りです。

  • 一般的なOSSのフレームワークではなく、独自フレームワークのためラーニングコストが高い
  • PHPのバージョンが古い(5系)、サーバのOSも古い
  • 長年の利用によってコードが複雑化し、通常の保守運用もままならない
  • ユニットテストツールも導入が難しく、品質担保が難しい
  • 仕様書や設計書などドキュメントもなく、あったとしてもメンテされていないため信用性が低い

コードの複雑化

課題の中でも特にコードが複雑化してしまっているのが致命的でした。
修正頻度の高い処理の循環的複雑度を計測すると、91 という結果になりました。

91という循環的複雑度がどれほど致命的かは、以下の表を見てもらうと分かりやすいかと思います。

循環的複雑度 複雑さの状態 バグ混入確率
10以下 非常に良い構造 25%
30以上 構造的なリスクあり 40%
50以上 テスト不能 70%
75以上(ココ) いかなる修正もバグを生む 98%

※参考:エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング

そのため、簡単な改修でも品質担保がかなり難しい状態でした。

また、新規機能開発などの案件着手時に担当エンジニアから

「サーバーサイドがこのレガシーシステムなので、実現が難しい。」
「実現しようとしたら、通常の数倍の工数がかかる」

という意見が出てしまうほどで、事業運営をしていく中で常にボトルネックになっていました。

プロジェクトの立ち上げ

リプレイスのプロジェクトを立ち上げるにあたって、「やること」「やらないこと」を定義しました。

やること

  • レガシーシステムをサーバごと全て新しいシステムに切り替える
  • 新しいシステムにおいて、コードの保守性や品質担保が高く保てる仕組みを構築する
  • 進め方として3段階のフェーズに分け、各フェーズごと順番に進める(詳細は後述)
  • 画面設計書を新規で作成し、それを元に実装を行う
  • URLによる振り分けを利用し、ページ単位で切り替えをリリースする

特に最後の

  • URLによる振り分けを利用し、ページ単位で切り替えをリリースする

という、いわゆるストラングラーパターンが本プロジェクトの重要な点でした。
この方法を取ることにより、1回のリリースまでの期間が短くなり、リスクを抑えてリリースすることが可能になりました。

もし新システムに全てのページ&機能を実装してからビッグバン的なリリースを行う場合、以下のデメリットがあると考えています。

  • リリースまでに時間がかかる
    • その間にレガシーシステムにリリースされた機能追加など案件の内容を追従しないといけなくなり、さらに時間がかかる
  • リリース後に不具合があった場合、切り戻しなどが難しく、最悪の場合は環境ごとすべて切り戻す必要が出てくる
    • 何かあったときのリスクが大きい

やらないこと

  • 他システムは本プロジェクトでは改修しない
  • テーブル定義などDB側の変更は基本的に行わない
  • 現行仕様を踏襲し、ユーザーからの見た目や使い勝手は変えない
  • フロントエンド改善の議論は行わない
  • 新しいシステムに切り替えたことにより、パフォーマンス劣化などユーザーにとって不利益を与えない

特に最後の

  • 新しいシステムに切り替えたことにより、パフォーマンス劣化などユーザーにとって不利益を与えない

が重要だと思っています。
いくら新しいシステムになって開発者が喜べる状況になっても、ユーザーにとって不利益があれば、それは改悪だと考えています。
ユーザーに不利益が無いよう、慎重に進めることを意識しました。

進め方とフェーズ

以下3つのフェーズに分けて進めました。

  1. 新しいシステムに1ページのみ置き換え、効果測定
  2. 全てのページを新しいシステムに置き換える
  3. レガシーシステムをサーバごと全て無くす

フェーズ1.新しいシステムに1ページのみ置き換え、効果測定

まずはPVが少なく、万が一何かがあってもユーザー影響の少ないページを選出し、そのページのみ新システムに移行しました。
「1ページ」の中には全ページで利用が必要な共通処理(ログイン処理など)や開発環境整備、新システム用サーバ構築なども含まれます。
※次フェーズで全ページを移行していくための土台作りが本フェーズに当たります。

開発環境整備と一言で言っても、今までなかったユニットテストの導入、循環的複雑度を低く保つための仕組みづくりなど、やるべきことは多岐にわたりました。
しかし、ここを軽んじてプロジェクトを進めてしまうと、過去のレガシーシステムの二の舞であると関係者全員が分かっていたため、しっかり話し合って進めることができました。

効果測定としては以下を実施しました。

  • 循環的複雑度の計測
  • ページ表示速度の比較
  • メモリ使用量の比較

効果測定の結果、もし悪くなっていたらサービスインせずに切り戻し、改善して再度効果測定をする、という流れでこのフェーズは進めました。

このフェーズで起きたこと、学び

実際、初めて新システムができた時のページ表示速度は、レガシーシステムより悪い という結果になりました。
明らかに新システムの方が実行されるコード量も少なく、シンプルになった理想形のはずなのに……。

頭を悩ませながら調査したところ、レガシーシステムは長年にわたり利用されてきた秘伝のタレ的な感じで(かなり読み解きづらかったですが)随所にキャッシュ利用などの高速化処理が実施されていることが分かりました。
レガシーシステムだからといって侮るなかれ、学ぶものは多々ある ということを思い知らされたフェーズでした。

また循環的複雑度については、前述の通り91だったところから、すべて10以下を保つ仕組みが構築できた のがこのフェーズの大きな成果でした。

その他、いくつかの課題をクリアしたうえで、次フェーズへ進めることができました。

フェーズ2.全てのページを新しいシステムに置き換える

このフェーズでは、ページ単位で新システムに移植していきました。

フェーズ1で実施した効果測定もページ単位で常に実施し、リリースしてもよいかの判定として利用しました。

このフェーズで起きたこと、学び

ページ単位でのリリースを行うことで、かなりのメリットがあると学べた フェーズでした。
具体的には以下の通りです。

  • 1ページごとに担当エンジニアをアサインすることで、同時並行で複数のページの移植作業が進められた
  • 他の機能追加などのキャッチアップやリリース調整が容易
  • ページ単位でのリリースのため、何が不具合があった場合の切り戻しなどが容易
  • 画面設計書作成や効果測定など常に行う作業もリリースをこなすごとにルーティン化し、徐々にスピードアップすることができた

フェーズ3.レガシーシステムをサーバごと全て無くす

フェーズ2で全ページの移植が完了したのち、本フェーズでレガシーシステムを無くすための撤去作業を行います。
また、サーバ撤去だけでなく、コード管理していたリポジトリの削除なども対応しました。

このフェーズで起きたこと、学び

長年使い続けてきたシステムだったので、撤去に向けてサーバへの残通信調査など想定以上の作業が発生しました。
また、サーバやソースコード関連の作業だけでなく、ドキュメントの修正など作業範囲は多岐にわたりました。

当初から予定していたフェーズでしたが、レガシーシステムからのリプレイスは新システムをリリースしてサービスインしておしまいではない ということを、改めて気づかされたフェーズでした。

最後に

本施策は大掛かりだったため、私一人の力では完了できなかったと思います。
ご協力いただいた方々(各ページ移設の担当者やプロジェクト進行を主導いただいた方(特に同人開発部 唐崎さん、荒尾さん))に感謝を。

本記事に関して詳細が知りたい、もう少し話を聞いてみたい、求人に少し興味が出たが応募までにカジュアル面談してみたいなどあれば、遠慮なくお声がけください。
以下からカジュアル面談も可能ですので、気軽にリクエストしてください。

https://pitta.me/matches/QbXoDwORqszC
https://youtrust.jp/recruitment_posts/dc2daf42866dc054bc815588d968806b

二次元コンテンツ事業 同人開発部では、一緒に働く仲間を募集しています。
ぜひご応募ください。