はじめに
2022年頃、あるCtoC型のオンラインサービスのシステム刷新を1人で担うことになりました。
依頼のきっかけはM&Aです。買収直後、買収側から相談を受けました。買収後の体制は以下の通りでした。
- 買収側:ビジネス統括の社員1人・経理1人
- 買収された側:オペレーター(兼何でも屋)1人
- エンジニア:私のみ(副業インフラエンジニアあり)
そのオペレーターの方が、講師採用からレッスンの振替・クレーム処理まで、ほぼ1人で業務を回していました。月間流通金額1,000万円規模のサービスで、少人数で回している状態です。
そしてそのサービスを支えるシステムは、創業者が10年かけて手作りしたPHP5製のフルスクラッチ。私が参画した時点で、創業者はすでに不在でした。
本記事はその刷新プロジェクトを振り返るシリーズの第1回として、なぜ刷新が必要だったのか・どう方針を決めたのかをビジネス視点も含めて記録します。
レガシーシステムはなぜ刷新しないといけないのか(ビジネスへの説明)
ビジネス側も何となく古いし刷新かな?みたいな雰囲気はありましたが、私が刷新の理由を明確にし、推進しました。理由は以下と説明しました。
セキュリティリスク:ある日心臓発作のように止まる
PHP5系はすでにサポートが終了しており、セキュリティパッチも提供されていません。買収側は上場企業のグループ会社であり、社内のセキュリティ基準を満たす必要もありました。
こちらについては
「セキュアでなければ、ある日心臓発作のように急にシステムが止まることもありますよ。」
という言い方をして事業継続性の観点から最優先で対処すべき問題として理解してもらいました。
拡張性の確保:リリースのたびにバグが出るモグラ叩きからの解放
技術負債が積み重なったシステムでは、「ここを直せばあちらがエラー」 という状態が常態化していました。創業者しか意図を知らない、あるいは創業者自身もわからないような過去のロジックが絡み合い、クレーム対応に追われながらなんとか運用している状態です。実際に技術的な問題でリリースを見送っている機能も存在しました。
この状態ではビジネス側が「この機能を追加したい」「この動作を修正したい」と言い出しにくい環境になります。エンジニアに相談しても「今の状態では難しい」という返答が続けば、ビジネス側は自然とシステムへの要望を諦めるようになります。
フルリプレースとその後のリファクタリングによってロジックの見通しが良くなり、機能追加やリリース時のバグ数も大幅に減りました。そして何より、ビジネス側が機能追加や修正を気軽に相談してくれる環境になったことが最大の成果だったと思っています。
事業継続性:後任エンジニアの採用リスク
最後の理由は、エンジニアの採用リスクです。PHP5・ノーフレームワークという技術要件では、質の良いエンジニアを市場で探すことはほぼ不可能です。私がいなくなっても後任のエンジニアがスムーズにシステムを回すことができる。こういう理想的な状態にするために、質の良いエンジニアの生息場所(最新フレームワークのモダンな環境)を用意しましょうと。PHP5・ノーフレームワークというレガシーシステムに依存し続けることは、人的資本の意味からも中長期的な事業運営のリスク になります。
幸い、M&A前にリプレースの予算が確保されており、この2点の説明でビジネス側の合意はスムーズに得られました。
システムの概要
サービスの内容はシンプルで、講師と生徒をマッチングして外部ビデオツール経由のレッスンを予約するCtoCプラットフォームです。料金体系はポイント購入制と月額サブスク制の2つ。一見シンプルに見えますが、コードやデータに10年分の歴史が詰まっていました。
負債の全貌
参画直後に直面した現実を、コード・DB・インフラの観点から整理します。
コード
- フレームワークなし。素のPHP5系で、
.phpのファイルパスがそのままURLになっている構成 - MVCなどの分離は一切なく、すべてのロジックがViewに書かれています
- 変数名は
$hoge1、$hoge2のような状態で可読性は壊滅的 - サーバー上に
_bak.phpのようなファイルが散在
DB
- テーブルの命名規則はあってないようなもの
- 講師テーブル・生徒テーブルのカラム数が約100カラム
- 不要カラムが大量に存在しますが、何が不要かはコードを読まないと不明
- カラム追加時にデータ移行をしていないようで、ある時点より過去はすべてnullのようなカラムが散在する
インフラ
- さくらインターネットのVPSで運用
- デプロイはFTPツールによる手動アップロード(推定)
- ソース管理リポジトリが存在しない
- 創業者のローカル環境が事実上の正、という状況でした。参画時点で創業者はすでに不在のため、サーバーからコピーしてきたファイルを正とするしかありません
負債の可視化
まずリポジトリを作る
最初にやったことは、サーバーからコピーしたファイル群をそのままGitHubリポジトリに登録することでした。
その際、同一リポジトリのルート直下にLaravel用の laravel/ ディレクトリを作成し、新旧のプロジェクトを1つのリポジトリで管理する構成を取りました。インフラ移行後は旧ディレクトリをルーティングで参照させ、Laravel側が完成したタイミングで切り替える設計です。
コードとヒアリングを往復する
コードの可読性が低く、なぜそのロジックになっているかを確認できる創業者は不在。そのためビジネス側へのヒアリングを軸に全体像を把握し、詳細はコードで確認するというサイクルを繰り返しました。
幸い、MA前から在籍しているスタッフがビジネス側におり、毎週業務確認のヒアリングを実施しました。これが負債可視化の中心的な作業となりました。
想定外だった負債たち
コードとヒアリングを進める中で、想定外の負債がいくつも出てきました。
講師報酬の例外祭り
創業初期は講師の獲得に苦労したようで、特定の講師に対して特別報酬・ドル払い・手数料免除といった個別対応が多数存在しました。それらがすべてコードの分岐として残っており、報酬計算ロジックは複雑怪奇な状態でした。また、例外をシステムで処理している講師と、締め処理後にエクスポートしたデータをExcel上で担当者が手動で修正している講師が混在していました。
ブラックリストのIDハードコード
問題のある生徒のIDが、ロジック内に直接書き込まれていました。
メール送信にGmailを使用
システムメールの送信にGmailアカウントを使っており、1日の送信上限に引っかかるリスクが高い状態でした。SESまたはSendGridへの早急な切り替えが必要と判断しました。
ファイルがWebサーバーのストレージ上に存在
プロフィール画像などがさくらVPS上に直接置かれており、Webサーバーの拡張性を根本から損なっていました。これがインフラ設計に大きく影響することになります(後述)。
刷新方針の決定
なぜシステムと業務を同時に刷新しなかったのか
技術的に考えれば、業務フローも含めてゼロから設計し直すほうがきれいなシステムができます。しかしこのプロジェクトではその判断を取りませんでした。
理由は体制にあります。MA後も引き続き、1人のオペレーターが長年の独自ルールを含む業務を属人的に回していました。ビジネス側から業務改善の要望もなく、少人数で事業を回すことが決まっていた状況では、業務の可視化・改善はシステム刷新と並行できる作業量ではありません。
そこで方針をこう定めました。
「まずシステム刷新中に業務を把握する。本人も意味がないと感じている業務や改善したい業務をヒアリングし、改善はリプレース後に行う。」
現場のオペレーターを尊重し、業務を壊さないことを最優先としました。
アプリケーション:フルリプレース一択
PHP5系のサポートはすでに終了しており、かつフレームワーク不使用の構成。段階的移行は現実的ではなく、フルリプレース一択という判断に迷いはありませんでした。
技術選定はLaravelを採用しました。当時でもGo+Reactのような選択肢はありましたが、理由は明快です。
- ビジネス側はシステムに無関心なため、工数最小化が最優先
- フル稼働のメンバーは私1人であり、モノリシックな構成のほうが手早くリプレースできる
- Laravelならbladeも活用でき、このプロジェクトとの親和性が高い
- 私自身がLaravelに最も習熟していた
移行の順序
創業者不在でロジックの意図が確認できないため、以下の順序で段階的に品質を上げる戦略を取りました。
- PHP5コードをある程度コピーしながらLaravelへ移植(無駄なロジックの書き写しを一時的に許容)
- テストコードを書き、現行の挙動を保証
- ビジネス側と仕様・運用を確認しながらリファクタリング
- 不要ロジックの削除と、業務フロー自体の改善を並行して進める
この順序は「ビジネスへの影響を最小化しながら品質を上げる」という考え方に基づいています。
インフラ:2段階で移行
ファイルがWebサーバーのストレージ上にある問題から、単純なサーバー移行では拡張性が担保できません。副業インフラエンジニアと相談しながら、以下の2段階で移行することとしました。
第1段階:さくらVPS → AWS EC2 + EFS
まずEC2へ移行し、既存のプロフィール画像等はEFSをマウントして参照する形で対応します。これにより、PHP5系の旧システムもEC2上で稼働可能になります。
第2段階:EFS → S3、EC2 → ECS Fargate
システムをLaravelへ完全に切り替えた後、ファイルをS3に移行した上で、コンテナ化してFargateへ移行します。拡張性とコスト最適化を実現するための構成です。
なお、インフラは先にEC2へ移行して旧システムを稼働させ、アプリケーションの切り替えはEC2上で一気に切り替える判断をしました。現状のシステム品質では段階的移行のメリットよりリスクのほうが大きいと判断したためです。
ビジネス側への意識付け:「エラーはむしろ改善の証拠」
技術的な方針と並行して、刷新前にビジネス側と意識のすり合わせをしました。これはある意味、技術的な方針よりも重要な作業でした。
「システムはレガシーのままにしておくほうがエラーは出ません。エラーが増えるのは、改善しようとしているからです。」
レガシーシステムは長年の運用で「動く状態」が固定化されており、誰も触らなければエラーは出ません。しかし刷新や改善を進めるほど、眠っていた問題が表面化したり、新旧の切り替え時に予期しない挙動が出たりします。これを事前に共有しておかないと、刷新中にエラーが増えたとき 「刷新したせいで悪化した」という誤解を生みます 。
その後も、非効率なロジックの改善やリファクタリングを進めるたびに同じ説明を繰り返しました。ビジネス側がエラーを「改善が進んでいるサイン」として受け取れるようになったことで、刷新中も信頼関係を保ちながらプロジェクトを進めることができました。
まとめ
この記事では、PHP5レガシーシステムの全貌把握と刷新方針の決定までを振り返りました。
ポイントを整理すると以下のとおりです。
- セキュリティと事業継続性の観点から刷新の必要性をエンジニア側から経営に提言することが重要です
- 業務とシステムの同時刷新は現場体制を無視したリスクになりえます。今回は業務改善をリプレース後に切り分けたことが結果的に正解でした
- 技術選定は「最新・最適」より「このプロジェクトと工数に最も合う技術」を選ぶことが現実解です
- インフラの負債(今回はファイルのWebサーバー依存)がアプリ移行の設計制約になることを早めに把握しておくことが重要です
- 「エラーは改善の証拠」という意識付けをビジネス側と事前に共有することが、刷新中の信頼関係を維持する鍵になります
次回は実際のLaravel移植とインフラ移行の実録を書く予定です。
