この記事は カオナビ Advent Calendar 2025 12日目です。
みなさん、コード、消していますか?
ソフトウェアエンジニアであれば、何らかの言語やフレームワーク(例:PHP、Laravelなど)を利用して、日々コードを書いていると思います。 では、自分が書いたそのコードの「ライフサイクル」を意識したことはありますか?
本記事のタイトルにある「3万行をテストなしに削除する」という試みは、2025年に私が20以上のWeb APIと8つ以上の画面から構成される一つの機能を丸ごと削除した経験に基づいています。
前提:ソフトウェアの複雑性は増大する
詳細に入る前、まず「なぜコードを消すべきなのか」という前提を共有したいと思います。
当たり前なのですがアプリケーションは、機能追加や仕様変更のたびにコードが変更・追加されます。
その過程で条件分岐(if文)が増え、アーキテクチャは徐々に複雑化していきます。
やがて経緯や仕様を知る人がいなくなり、コードは誰も「読めない」あるいは「怖くて触れない」状態になっていきます。その結果、開発チームの生産性はゼロに向かって下がり続けます。(歴史あるサービスの開発に携わっている方なら、身に覚えがあるのではないでしょうか?)
では、どうすればこの「エントロピーの増大」に抗うことができるのでしょうか。
世の中には
- 特定のアーキテクチャ(例:クリーンアーキテクチャ、レイヤードアーキテクチャ)を導入する
- マイクロサービスに分割する
- 別言語で書き直す
など、様々なHowが存在します。
しかし私は、まずアジャイル宣言の背後にある原則の次の一節を思い出すようにしています。
シンプルさ(ムダなく作れる量を最大限にすること)が本質です。
つまり、「本質的でないこと(≒価値に貢献しない機能)を減らす」ことこそが、日々プロダクトに積もる複雑性を軽減する最も効果的な手段の一つだと考えています。
削除しやすい設計とは?
今回の大規模削除が可能だった最大の要因は、「責務ごとに適切に分割されたパーツ(モジュールやクラス)間の依存の方向を、意図をもってコントロールできていた」ことに尽きます。
適切なパッケージ分割や設計原則(SOLIDなど)の適用を通して、レイヤーや機能間の境界を明確にし、疎結合・高凝集な状態を作り出せれば、依存関係は驚くほどシンプルになります。
そうなれば、「他のどこからも参照されていないから、削除して大丈夫!」と自信を持って言える状態(=依存がゼロの状態)を作り出せるはずです。この状態を実現できれば、作業自体はものの数分で終わります。
※現職での取り組みの詳細は、今回消した機能を作ったチームの初期メンバーである@sanogemaruのソフトウェアは捨てやすく作ろうや、エキスパート@hanhan1978のレガシー回避のPHP開発術をご覧いただくと、より解像度が上がるかと思います。
削除までの具体的なステップ
とはいえ、APIが(ログやバッチ処理などから)間接的に参照されている可能性は常につきまといます。 今回の3万行オーバーの大規模な機能削除は、以下の手順で慎重に実施しました。
- フィーチャートグル(Feature Toggle) を利用して、フロントエンドのコンポーネントと、そこからアクセスしていたバックエンドのAPIを無効化する。(まずはユーザーから触れなくする)
- トグルによって無効化されたコンポーネントやAPIのコードを、意図的にデッドコード(到達不能なコード) にする。(関連する呼び出し元をコメントアウト・削除する)
- デッドコードになった部分を(CIなどで検知しながら)安全に順次削除していく
この2〜3の工程を約1か月かけて10回ほどのMR(マージリクエスト)に分割し、合計500ファイル・35,000行のコードを、QA(品質保証)チームによる手動テストなしで安全に削除することができました。
※この話の詳細は、PHPConference福岡2025で「10分以内に機能を消せる状態の実現のためにやっていること」というタイトルで発表しています。ご興味があれば、そちらもぜひご覧ください。
おわりに
そもそも、ソフトウェア開発において「本当にその機能が必要かどうか」は、リリースしてみるまで誰にも分からないのが現実です。私たちが日々追加しようとしている新機能も、実は誰も求めていない、あるいは開発や保守の工数を回収できない可能性が常にあります。
そしてソフトウェアのコードやデータは、物販の在庫とは異なり 「目に見えない」コスト です。エンジニア以外には、その存在や維持コスト(負債)が観測されにくいという厄介な特性があります。
その「見えないコード」が、ソフトウェア全体の認知負荷(理解や把握に必要な労力)を増大させ、バージョンアップや保守開発の生産性を低下させ、結果として企業の競争力をも奪っていきます。こうした問題は、気づいた時には手遅れ(あるいは解消が非常に困難)になっていることがほとんどです。
だからこそ、私たちソフトウェアエンジニアは開発時からデータやソースコードの「ライフサイクル」を意識し、自分たちが開発したものプロダクトがどのようなROI(投資対効果)を生み出しているかを知るべきです。そして、ROIがマイナスになるようであれば、すぐに対象の機能を「消せる」ように作っておく必要がある、と私は強く考えています。
この記事を読んだ方が、一人でも多く「ライフサイクル」とその終わりにあるはずの「削除」を意識して、日々のものづくりに取り組んでいただけることを願っています。