こんにちは、エンジニアの id:kiryuanzu です。
今回の記事は、私のチームが数年の間頓挫していた社内の管理画面の立て直しPJをリブートし、ゴールに導くまでの動き方についてご紹介します。
直近の記事で to_lz1さんによる Claude Code を活用したレガシーコードのリプレース事例について紹介されていました。
本記事もリプレース事例を扱う内容となります。このPJでも Claude Code を駆使して開発を進める場面が多くありました。
ただし、機能群も多く歴史的なシステムだったこともあり、Claude Code を使う以前の場面で一筋縄ではいかない問題があり、システムリプレースは数年間ずっと頓挫し続けていました。
本文では、頓挫し続けてきた理由、そしてそこからゴールへと導くために決めた意思決定と進め方について焦点を置いてお伝えしていきます。
今レガシーシステムのリプレースに取り組んでいる方にとって、リプレースの進め方や判断軸について参考にできる部分がありましたら幸いです。
状況と課題
社内には、Classiの顧客対応を担当するメンバーを中心に利用されているFuelPHP製の社内の顧客管理システムがあります。
このシステムは、2015年からFuelPHPによる開発・運用を続けてきましたが、以下の理由により2021年頃から Rails に全て作り替える方針をチームで決めました。
- FuelPHPの公式のサポートが事実上止まっている
- チーム内では Rails でのアプリケーション開発が中心となっており、FuelPHPで新機能の追加・機能改善の敷居が高い状況が続いている*1
この社内システムは学校ごとの受注情報・ユーザー情報の登録やClassiから学校へのお知らせ配信といった、Classiの顧客管理を扱う上で欠かせない機能が集約されたシステムです。
管理システムの要望改善を社内からいただきつつも、FuelPHPでの運用では気軽に改善に手を出すことが難しく、チームで慣れているRailsでの開発に移行するという方針に至りました。
並行して、自チームではエンドユーザー(先生・生徒・保護者)向けのサービスの開発・運用も行っています。
エンドユーザーを中心とする顧客価値への貢献もチーム内でとても優先度の高い取り組みとなります。
そのため、そちらのサービスの改善の案件が持ち上がりそちらにメンバーを集中させることになると、社内システムのタスクは優先度を落とさざるをえません。
上記の背景によりタスクを担当するメンバーの入れ替わりが続き、一人以上のメンバーでまとまった期間で着手できず開発がストップする時期を繰り返しました。
ただ、今年度からは組織統合もあり Classi の管理システムを触る社内メンバーはさらに増えていくことになります。
その流れで、利用ユーザーからの改善要望がさらに求められることは大いに予想され、機能改善をよりスムーズに進められることが組織のメンバーへの価値貢献に繋がるのではないかとチームで再認識しました。
そういった経緯を踏まえ、エンドユーザ向けのサービス改善も継続しつつ、社内システムのリプレースを完遂せねばならないとチームで判断しました。
リプレースPJの完遂に向け現状と今後の方針の見直しを行い、定めた方針に即して開発に着手し無事期日までに最終的にはゴールに到達することができました。
ゴールに到達するまで我々はどういった意思決定を経てきたのか、ここからお話していきます。
リプレースを完遂させるための意思決定
課題を再認識し、ゴールを切り分ける
当初の計画 今回のPJの開始にあたって、当初は「Railsの全面リプレースによって対象のシステムが抱える課題を一括で解消する」という狙いがありました。
具体的には、以下の課題を完遂することをゴールとし、そのためには FuelPHP をなくして全機能を置き換えることが必須であると違和感なく受け入れていました。
- コンテナイメージ・フレームワークなどのEOL対応
- サポート終了する amazon linux2 や PHP 7.2、FuelPHP など、現状の技術スタック全体を全て置き換える
- 利用者が望むシステム改善
- 現場の顧客対応メンバーから上がっていた社内システムの機能改善や、業務効率化の要望への対応
しかし、EOLの期限を意識してスケジュールを計画する場合、社内システムの全ての機能を期日までに一つずつ置き換えるのはかなりタイトかつ現実的に難しいものに見えました。
元々計画されていたリプレースPJの趣旨には、EOL対応以外にも「社内システムの改善を容易に行えるようにすること」も含まれています。むしろ、顧客価値の貢献を意識するならば、こちらの趣旨が確実に達成されることが今後の動きとして大事であると言えます。
たとえEOL対応の期限に急いで開発を遂行させたとしても、今後の運用を意識したコードの品質を担保する余裕が維持できるのか懐疑的でした。
意思決定後のアプローチ
上記の背景を踏まえた結果、以下のようにEOL対応とリプレースのゴールを切り分けて進めることにしました。
- EOL対応は現状の技術スタックでアップデートを実施し、まずはこちらを最優先で終わらせる
- 具体的には以下のアップデート作業を実施(作業の具体的な内容は本記事では割愛します)
- サポート終了する amazon linux2 イメージ → PHP公式イメージへの置き換え
- PHP7.2 → PHP 8.x系のアップデート
- まずはEOL対応を終わらせることで、EOLの期日を意識せずにリプレースPJの開発スケジュールを敷くことが可能となる
- 具体的には以下のアップデート作業を実施(作業の具体的な内容は本記事では割愛します)
- 今回のリプレースPJの趣旨は「社内システムの継続的な改善を可能とする」のみとする
- まずはユーザーの利用頻度の高い画面を抽出したリプレース完遂を本PJのゴールとする
- 本PJ完遂後、別PJ扱いとして今回対象外とした画面を含む移行を実施しフレームワーク単位での移行を完遂させる
小さな機能であれば最初からフレームワーク単位のリプレースを計画し、EOL対応もまとめて解決する方針も現実的ではあったと思います。
しかし、複数の機能が連なった規模の大きいシステムのリプレースをタイトなスケジュールで実施するのはコードの品質を意識する以上、困難であると判断しました。
そこで、まずはClassiとしてクリアしたいと考えるEOL対応を先に終わらせることによって、リプレースPJの遂行に際してEOL対応で迫られる期日のことは考慮しなくて良いようにしました。
そのおかげで、余裕をもってリプレースを進める段取りとスケジュールを準備することができました。
その後、本PJではリプレースのゴールの見直しを行い、まずはリプレースを通して「社内システムの継続的な改善を可能とする」のみに絞り込むようにしました。
これらの判断をもって、具体的にどのように着手を進めたかどうかについて次にお話しします。
リプレース対象の画面を絞り込む
前章では抱えている課題を切り分け、まずは目先で優先すべきタスクだったEOL対応のためのアップデート作業を完遂させました。
そこから、リプレースPJの完遂に向けて今までの状況を見直し、今見据えるべきゴールは「社内システムの継続的な改善を可能とする」ことであると認識し、着手対象を絞り込むことを決めました。
当初は前述のように本PJの完了条件は「FuelPHPをやめるために全ての画面を置き換える」と定めていました。
しかし、「社内システムの継続的な改善を可能とする」ことを目的と掲げるならば、一律で全ての画面の置き換えるのではなく「ユーザーが今頻繁に使っている画面を優先して置き換える」ことにフォーカスした開発が現実的なアプローチではないかとチームで認識を改めました。
よって、以下の二つの軸を元にユーザーに影響がある画面を絞り込んで着手する対象を確定させるようにしました。
- ユーザーにとって必須機能であるかどうか
- 管理機能でしか操作・閲覧できないデータがあるかどうか調査
- ユーザーが頻繁に使う・今後使われる可能性が高い機能であること
- 顧客対応などを中心に行うメンバーにヒアリングを実施し、利用頻度の高い機能・それらの改善要望の情報収集
中には、機能クローズによって今後使われないことが確定した管理機能や、サービスの運用の都合上もう使われていない機能もありました。
開発着手前に優先度の低い機能を洗い出すことで、必要なものだけに絞り込むのは開発コストを下げるために重要な作業だったと認識しています。
対象画面の絞り込みを行った後、実際に開発に着手する上での段取りを計画しました。
フェーズ単位で対象画面と担当者を振り分ける
画面の優先度・そこに画面の着手難易度も加味し、フェーズを3つに分けて対象画面を振り分けました。
以下の表にあるフェーズ2の完遂をもって、今回の目的となる「社内システムの継続的な改善を可能とする」ラインまで到達できるように計画しました。
フェーズ1
- 難易度が低~中の不確実性がない参照系画面 → 更新系画面
- 最低限ユーザーに使われる機能であること
- ユーザーリスクの低い参照系・更新系機能が中心
- 利用頻度が高く、難易度の高い更新系画面
- フェーズ2も継続して固定のメンバーに開発を担当してもらう
フェーズ2
- 中難易度の更新系画面
- フェーズ1の高難易度画面よりは難しくないが、社外サービスへの影響があり、より複雑なドメイン知識が求められる
- 低難易度の参照系画面
- 新しくジョインした新卒メンバーのオンボーディングタスクとして扱う
フェーズ3
- 難易度関係なく、優先度がかなり低い画面
- サービスの運用上ほぼ使われない機能や・改善要望が発生しにくい画面
- これらはPJ内に終わらせる必要はなし
- 今後予定するフレームワーク単位での移行PJ発足に合わせて対応する
上記のフェーズごとに着手対象の画面を振り分け、チーム内の2〜3名のエンジニアで担当画面をそれぞれ持ってリプレース移行対応を進めました。
優先度を整理し対象画面の振り分けをしたことで、チーム内で並走してPJの進捗を共有し開発に向き合う環境を整えることができました。
例えば、途中からPJに参画したメンバーがこれらの振り分けを元にすることで、「どこから着手すればよいかわからない」といった認知負荷を抱えることなく、担当がまだ置かれていない画面を振り分けて進めてもらいました。
他にも、新しくチームにジョインした新卒メンバーに管理画面のリプレースを通して Classiのサービスの仕様理解を深めてもらう目的で難易度の低い画面を担当してもらう取り組みも実施しました。
計画の旗振り役をした筆者がチームのタスクの都合上一時的にこのPJから離れる時期もありました。その間も、他メンバーがPJ内のタスクの優先度を把握し予定通りリプレース作業を継続することができました。
今までは、主要の開発メンバーが一度PJから離れるとキャッチアップが難しくなり頓挫してしまうのを繰り返していましたが、今回はチーム全体でリプレース対象画面の優先度を把握できるようにし、ゴールを見据える状況を作り出すことに成功しました。
これらの取り組みによって、PJを頓挫させずに無事期日までにフェーズ2のリプレースまで完遂させることができました。
まとめ
今回のPJを進めた上で意識したこととして、主に以下の2点があります。
より効率的かつ現実的なアプローチを探り続けること
当初は、全ての画面の移行をゴールとして定めていましたが、今のチームのキャパシティを鑑みると「それらを最初のゴールとして扱うことは難しいのでは?」という状況が見えてきました。
そこから課題を整理し、今求められているものだけを抽出してゴールを再定義し完遂させることができました。
ただし、いま最小限の画面で使っているFuelPHPを残し続けるのは今後のEOL対応を意識するといずれは取り除きたい現状があります。
そのためには、ここからまたチームのスケジュールに合わせて新しいリプレースPJを策定し完全な移行を目指す必要があります。
ただ、今回のリプレースの趣旨だった「社内システムの継続的な改善を可能とする」目的は達成されたので、対象画面は今までよりかなり絞られ、現実的なスケジュールを敷くことが可能になりました。
このようにして、今求められている状況を把握して現実的なアプローチを定め、効率的な進め方を模索することが中長期的なPJで必要な動きだと捉えるようになりました。
腕力だけで解決しないやり方を見つけ出すこと
今回のリプレース移行ですが、たとえ膨大な作業量であっても人によっては Claude Codeによる開発支援を駆使して一人でとにかく勢いをかけて進めるといった選択肢も可能だったかもしれません。
ただ、開発を進めていく上では、社内システムのドメイン知識をはじめとしたプロダクトの知見・サービス開発の知識がやはり必要となります。
一人で進められたとしても、今までの頓挫した背景のように外部的な要因で集中して開発することが困難になることも大いに予想できます。
それらを踏まえると、一人の腕力に依存せずにチームで継続して連携するといったアプローチも今回のゴールに到達する上で確実に必要な動きであったと考えています。
おわりに
はじめて中長期的なPJの旗振り役を担ってみて、PJを頓挫させずに進める動き方について改めて考えさせられる機会となりました。
これらの経験を通して今後の課題でも活用できる意思決定のやり方を学べたように思います。
もし今、中長期的な課題やレガシーシステムのリプレースに向き合う方にとって、参考になる振る舞い・考え方の一助となりましたら幸いです。
次回予告: 開発面での取り組みについて
今回のPJでは、サービス開発を最小限のコストで進めるために、チーム内のRailsアプリケーション開発のコーディング方針を策定する取り組みや、将来的にHotwire導入を検討しチーム内でHotwireのインプット会を企画するなど、開発面でのアプローチも複数実施しました。
今回はリプレースを終わらせるための意思決定についての話が中心となるため割愛としましたが、これらの具体的な対応例についてもまた別の機会で紹介できたらと考えています。
*1:https://github.com/fuel/core/tree/1.8/master 最終の stable バージョンである 1.8.2 は2019年以降リリースされておらず、正式なリリース情報が出ていない












