【テクニカル・上級編】ESLintのカスタムルールで「非推奨APIの追放」を自動化する:負債を溜めないチーム開発 – デバッグ・コード品質・テストツール生産性向上バイブル

負債の墓場を築かない:ESLintカスタムルールによる「非推奨APIの追放」とCI自動化の深淵

技術的負債とは、コードが書かれた瞬間に発生する「利子」ではない。「誰も使ってはならないと知りながら放置されたAPIが、静かにコードベースを蝕み続ける時間」のことだ。

多くのチームは、ドキュメントやREADMEで「このモジュールは非推奨です」と警告する。しかし、そんなものは誰も読まない。コードレビューで指摘するのも非効率だ。伝説的なDevOpsアーキテクトである我々が目指すべきは、「間違ったコードを書いた瞬間、その行が赤く染まり、CIが拒絶する」という、物理法則レベルの強制力を持つ仕組みである。

本稿では、ESLintを単なる静的解析ツールとしてではなく、組織の技術スタックを強制的に進化させる「ゲートキーパー」として運用する極意を伝授する。

—

1. 静的解析の境界線:なぜ `no-restricted-imports` では足りないのか

標準の `no-restricted-imports` は強力だが、あくまで「パッケージ単位」の禁止に留まる。しかし、現場で本当に必要なのは「特定のメソッド呼び出し」や「古いバージョンの関数シグネチャ」の追放だ。

ここで登場するのが、AST(抽象構文樹)を直接操作するESLintカスタムルールである。我々は、`eslint-plugin-local-rules` を活用し、リポジトリ内に独自のルールを直接埋め込む。

カスタムルールの実装アーキテクチャ

ルール定義は、ESTree specに基づいたパターンマッチングを行う。以下は、レガシーな `legacyClient.request()` を禁止し、現代的な `fetch` への移行を強制する最小構成のルール例だ。

// eslint-rules/no-legacy-api.js
module.exports = {
create(context) {
return {
// CallExpression(関数呼び出し)をフックする
CallExpression(node) {
// オブジェクトが ‘legacyClient’ かつ メソッドが ‘request’ かを検証
if (
node.callee.type === ‘MemberExpression’ &&
node.callee.object.name === ‘legacyClient’ &&
node.callee.property.name === ‘request’
) {
context.report({
node,
message: ‘🚨 警告: legacyClient.request は非推奨です。fetch API に移行してください。’,
});
}
},
};
},
};

このルールを `eslint-plugin-local-rules` を介して `.eslintrc.js` に登録することで、CI/CDパイプラインの深層部で、開発者のエディタ上でも即座に違反が検出されるようになる。

—

2. CI/CDパイプラインへの「拒絶」の実装

ルールを書いて終わりではない。最も重要なのは、「警告を放置させない」CI/CDフローの設計だ。多くのチームが `eslint –fix` を自動化しているが、これは諸刃の剣である。

パイプライン最適化のハック

CI環境(GitHub Actionsなど)では、メモリ消費を抑えつつ、差分のみをチェックする戦略をとる必要がある。`lint-staged` をローカルに仕込み、コミット単位での防壁を構築せよ。

.github/workflows/lint.yml
jobs:
lint:
runs-on: ubuntu-latest
steps:

  • uses: actions/checkout@v4
  • name: Setup Node

uses: actions/setup-node@v4
with:
cache: ‘npm’ # キャッシュ効率を最大化

  • run: npm ci

# –max-warnings 0 を付与し、警告一つでもビルドを落とす

  • run: npx eslint . –max-warnings 0

ここで重要なのは、「警告をエラーとして扱う」という厳格なポリシーだ。警告が放置される環境では、静的解析はノイズとなり、エンジニアはそれを無視するようになる。

—

3. 大規模リポジトリにおける「負債返済」の自動化戦略

ルールを導入した瞬間に、既存の数千行のコードがエラーで埋め尽くされるはずだ。これを一気に直すのは非現実的である。ここで、「新規ファイルは厳格に、既存コードは徐々に」という戦略をとる。

段階的な移行を支えるスクリプト

ESLintのルールを「警告」から「エラー」に切り替える際、既存の違反を一時的に無視する `eslint-disable` を自動挿入するスクリプトを走らせるのが定石だ。

ASTを解析し、特定のルール違反箇所にコメントを自動挿入するワンライナーの概念
実際には eslint-find-rules や jscodeshift を用いるのが賢明である
npx jscodeshift -t transform-add-eslint-disable.js src/

このアプローチにより、開発者は「新しい機能を作る際に、負債を積み増さない」ことを強制されつつ、既存コードの改修は「自分のタスクのついでに」という効率的なプロセスで進められるようになる。

—

4. アーキテクトの視点:パフォーマンスとメモリ消費の最適化

ESLintは強力だが、AST生成はメモリを大量に消費する。数万ファイル規模のプロジェクトでは、Lintの並列実行設定は必須だ。

  • キャッシュの永続化: `eslint –cache` を必ず利用すること。`.eslintcache` ファイルをCIのキャッシュストレージに保存することで、変更のないファイルの再解析を完全にスキップできる。
  • プロファイリング: `TIMING=1 eslint .` を実行せよ。どのカスタムルールがボトルネックになっているか、ミリ秒単位で可視化される。コストの高いルールは、特定のディレクトリに限定するなどして最適化せよ。

—

結論:ツールは文化を強制する

ESLintのカスタムルール作成は、単なるコードチェックではない。それは、「チームがどのような技術スタックを志向すべきか」という設計思想をコードとして具現化する作業である。

「古いAPIを使うな」と口頭で伝えるのはマネジメントだが、「古いAPIを使えないようにシステムを組む」のがエンジニアリングだ。この強固な自動化の輪を回し続けることで、あなたのチームは「過去の遺物」を修正する時間を減らし、「未来の価値」を創造する時間を最大化できる。

さあ、コードベースから「負債」という名の贅肉を削ぎ落とせ。あなたの書くルール一つが、組織の生産性を数年分前倒しにするのだから。

タイトルとURLをコピーしました