古いNode.js APIを安全に改修する優先順位
「このNode.jsのAPI、触るたびに壊れないか怖い」——数年前に作られたNode.js APIを引き継いだ企業から、こういう相談をよく受けます。Express 3系や4系の初期バージョンのまま止まっていたり、callback(err, data) を延々とネストさせたコールバック地獄が残っていたり、npm audit を実行すると数十件の警告が出て見なかったことにしている、という状態です。
こうしたAPIは動いてはいるので、経営側からは「なぜ今すぐ直す必要があるのか」が見えにくいものです。一方でエンジニア側は「いつか壊れる」という不安を抱えながら機能追加を続けています。この記事では、古いNode.js APIをいきなり書き直すのではなく、動かしたまま安全に改修していく優先順位を整理します。
なぜ「今すぐ全部書き直す」が危険なのか
古いNode.js APIを見ると、書き直したくなる気持ちはよく分かります。しかし全面リプレイスには次のリスクがあります。
- 仕様がコードにしか残っていない: 数年運用されたAPIには、過去の障害対応や取引先の特殊要件に対応した分岐が埋め込まれている。書き直すとその知識ごと失われる
- 止められない: 本番で稼働中のAPIは、書き直している間も外部から叩かれ続ける。切り替えのタイミングで一括移行すると、失敗時の影響範囲が大きすぎる
- 見積もりが破綻しやすい: 「全部を新しい構成で作り直す」は、着手してから未知の仕様が次々出てきて期間もコストも膨らみやすい
改修とフルリプレイスのどちらを選ぶべきかという判断軸そのものは、既存プロダクト改善の最初の確認観点でも扱っていますが、Node.js APIに関して言えば、多くのケースは全体を作り直さずに部分改修の積み重ねで立て直せます。
改修に着手する前に見る3つの観点
いきなりコードに手を入れる前に、次の3点を確認します。
- 依存パッケージの状態:
package.jsonの各パッケージが、開発が止まっている(deprecated)か、既知の脆弱性を抱えているか - テストの有無: 現状の挙動を保証する自動テストがどれだけあるか。ゼロに近いケースがほとんど
- エラーハンドリングの一貫性: コールバック・Promise・async/awaitが混在していないか。混在しているAPIはエラーが握りつぶされている箇所が高確率で存在する
この3点の状態次第で、改修の順番と工数の見積もりが大きく変わります。
改修の優先順位
私たちが古いNode.js APIの改修を依頼されたとき、基本的に次の順番で進めます。
1. 危険な依存パッケージの置き換え
まず着手すべきは、セキュリティリスクの高い依存の置き換えです。開発が止まっているパッケージ、既知の脆弱性を含むバージョンで固定されているパッケージを洗い出します。
npm auditで機械的に脆弱性を検出する- 代替が容易なもの(例: 古いHTTPクライアントを標準の
fetchやaxiosに寄せる)から着手する - Express自体が古い場合、まずは同一メジャーバージョン内の最新パッチに上げてから、メジャーバージョンアップを検討する
ここは「動作が変わらないこと」を確認しながら進める工程なので、後述するテストの網が先にあるほど安全に進みます。テストが無い状態でここに手を入れる場合は、置き換える機能に絞った最小限のテストを先に書きます。
2. コールバック地獄の解消
callback(err, data) の入れ子が3段・4段と続いているコードは、読むだけで時間がかかり、エラーハンドリングの漏れも起きやすくなります。ここは以下の順で解消します。
- 新しく書くコード・触る箇所から
async/awaitに寄せる。全ファイルを一気に書き換えない - 既存のコールバックベースの関数は
util.promisifyなどで段階的にPromise化し、呼び出し側から徐々に置き換える - try/catchの粒度を揃え、エラーが握りつぶされていないか(catchブロックが空、あるいはログだけ出して処理を続けている箇所)を重点的に確認する
コールバック地獄の解消自体は見た目の改善に留まらず、エラーが実際にどこで発生し、どこで処理されているかを追えるようにすることが本質的な目的です。ここが曖昧なままだと、後続のテスト追加や機能改修のたびに「このエラーは本当に想定通り処理されているのか」を毎回調べ直すことになります。
3. テストの安全網を張る
Node.js APIの改修で最も効果が高いのは、実は「テストを全部書く」ことではなく、これから触るエンドポイントに絞って回帰テストを足すことです。
- 既存の主要エンドポイントに対して、リクエスト→レスポンスの形を保証する統合テストを最初に書く(Jest + supertestなどの構成が一般的)
- 内部ロジックの単体テストは、改修で手を入れる箇所から順に足していく
- テストが「今の挙動」を保証するものであり、「あるべき挙動」ではないことを意識する。改修前のテストは、まず現状を固定するためのものと割り切る
この安全網があることで、後続の依存アップグレードやリファクタリングを「壊れていないか」を都度目視確認しなくても進められるようになります。テストの張り方自体をより詳しく知りたい場合は、テストがないシステムを安全に改修する進め方も参考にしてください。
4. フレームワーク・ランタイムのアップグレード
依存パッケージとコールバック地獄がある程度片付いた段階で、Express本体やNode.jsランタイムのメジャーバージョンアップに着手します。ここを最初にやりたくなる気持ちは分かりますが、土台が不安定なままメジャーアップグレードすると、どの変更が原因で挙動が変わったのか切り分けられなくなるため、順番を後ろにしています。
- Node.jsのEOL(サポート終了)バージョンを使っている場合は最優先で上げる
- Expressのメジャーバージョンアップはミドルウェアの互換性を個別に確認する。特に認証・ロギング周りのミドルウェアは非推奨化されているものが多い
- アップグレードは1段階ずつ行い、各段階でテストと本番相当環境での動作確認を挟む
TypeScript化は必要か
「この機会にTypeScript化すべきか」もよく聞かれる論点です。結論としては、改修の目的次第で優先度が変わるというのが実情です。
- API境界(リクエスト・レスポンスの型)から始めるのは効果が高い: 外部と接するインターフェースの型を固定するだけで、パラメータの取り違えのようなケアレスミスをコンパイル時に検出できるようになる
- 全ファイルを一気にTypeScript化するのは推奨しない: JavaScriptのまま
anyだらけでTypeScript化しても、型の恩恵はほとんど得られず、移行コストだけがかかる - 改修対象のファイルから段階的に
.ts化する:allowJsを有効にしてJSとTSを共存させ、触ったファイルから型を足していく方が、投資対効果が高い
TypeScript化そのものが目的化してしまうと、本来の目的である「安全に改修できる状態を作る」から外れてしまいます。まずは1〜3の改修を進め、その延長線上で型を足していくのが現実的な順番です。
外注する場合に確認すべきこと
古いNode.js APIの改修を外部チームに依頼する際は、次の点を発注前に確認しておくと安心です。
- 「全部書き直します」を最初の提案にしていないか: 部分改修の積み重ねで進める具体的な計画を示せるか
- 依存パッケージの棚卸しを最初の工程に含めているか: いきなりコードの書き換えから入らず、まずリスクの可視化から始めるか
- テストの位置づけを説明できるか: 「今の挙動を保証するテスト」なのか「あるべき挙動のテスト」なのかを区別して進められるか
- ロールバック手順があるか: 依存アップグレードやランタイム更新で問題が起きたとき、すぐ前の状態に戻せる計画になっているか
こうした進め方の丁寧さが、稼働中のAPIを止めずに改修できるかどうかを大きく左右します。私たちが対応する技術スタックの詳細はフロントエンド関連の技術ページに、進め方全体はモダナイゼーション支援サービスにまとめています。
まとめ
- 古いNode.js APIは全面書き直しではなく、危険な依存の置き換え→コールバック地獄の解消→テストの安全網→フレームワークアップグレードの順で段階的に改修する
- TypeScript化は目的化せず、API境界から始めて改修対象ファイルから段階的に導入するのが現実的
- 外注する場合は「部分改修の計画」「依存の棚卸し」「テストの位置づけ」「ロールバック手順」を発注前に確認する
「触るたびに壊れないか不安」という状態のNode.js APIをお持ちの方は、まず現状の診断から始めることをおすすめします。torcheeesでは既存プロダクト改善の診断と、継続的な改善支援を提供しています。まずはお問い合わせフォームから現状を聞かせてください。