規約の自動化こそが最強のアーキテクチャ:ESLintカスタムルールで「レビューコスト」をゼロにする
多くのプロジェクトで ESLint と Prettier は「コードを綺麗にするためのツール」として導入されています。しかし、それは宝の持ち腐れです。真のテックリードにとって、これらは「人間の記憶力に依存するレビューコストを排除し、チームの意思決定をコード化するエンジン」でなければなりません。
「このメソッドは直接呼ばず、必ずラッパー経由で呼んでください」
「このライブラリのこのAPIは、特定の条件下でメモリリークするから使わないでください」
こうした「口頭の注意」を繰り返していませんか?それは負債です。本稿では、AST(抽象構文木)を操作し、プロジェクト固有の禁忌をコードレベルで弾く「カスタムルール」の極意を伝授します。
—
1. なぜ「設定」ではなく「ルール作成」なのか
既存のルール(`no-console` など)を並べるだけでは、ビジネスロジックの制約は守れません。カスタムルールを作ることは、チームに対して「言語仕様を拡張する」ことと同義です。
AST(抽象構文木)という設計図を読む
ESLintはソースコードを解析し、プログラムの構造をツリー状のデータ(AST)に変換します。カスタムルール作成とは、このツリーを巡回(Visitorパターン)し、特定のノードを見つけた瞬間に「警告(Report)」を発するプログラムを書く作業です。
[AST Explorer](https://astexplorer.net/) を開き、対象のコードを貼り付けてみてください。自分たちが禁止したいコードが、どのノード(例: `CallExpression`, `MemberExpression`)として表現されているかを確認する。これが全ての出発点です。
—
2. 実践:プロジェクト固有の「禁止ルール」を作る
例えば、「特定の非推奨なユーティリティ関数を、特定のファイル以外で呼び出すことを禁止する」ルールを作ります。
カスタムルール実装の雛形
`eslint-rules/no-deprecated-util.js` として以下を配置します。
module.exports = {
create(context) {
return {
// CallExpressionノード(関数呼び出し)をフックする
CallExpression(node) {
// 呼び出されているのが “deprecatedUtil” か確認
if (node.callee.name === ‘deprecatedUtil’) {
// 禁止したい旨を警告する
context.report({
node,
message: ‘deprecatedUtilは廃止予定です。代わりにNewUtilを使用してください。’,
});
}
},
};
},
};
これを `.eslintrc.js` で読み込みます。
module.exports = {
// ローカルルールを読み込むためのプラグイン設定
plugins: [‘local-rules’],
rules: {
// 自作ルールを適用
‘local-rules/no-deprecated-util’: ‘error’,
},
};
この設定により、CI上で非推奨コードが混入した瞬間にビルドが落ちるようになります。「レビューで指摘して修正を待つ」という数時間のラグが、瞬時に解消されます。
—
3. 開発効率を極限まで引き上げる「神設定」と運用術
カスタムルールだけでは不十分です。日常のコーディング体験を劇的に変える設定を共有します。
神プラグイン:`eslint-plugin-perfectionist`
importの順序やオブジェクトのプロパティ順序を自動でソートするプラグインです。これを導入すると、Gitのコンフリクトが激減します。「なんとなくの並び順」を巡る不毛な議論をIDEに委ねてください。
究極の `.eslintrc.js` 構成例
チーム開発において、設定は「階層化」と「自動修正」が鍵です。
module.exports = {
extends: [
‘eslint:recommended’,
‘plugin:@typescript-eslint/recommended’,
‘plugin:prettier/recommended’ // Prettierとの競合を排除する必須設定
],
rules: {
// 「警告」ではなく「エラー」に強制することで、緩みを許さない
‘@typescript-eslint/no-explicit-any’: ‘error’,
// 未使用変数は即座に削除対象として赤線を引く
‘no-unused-vars’: [‘error’, { argsIgnorePattern: ‘^_’ }],
},
// CI/CDでキャッシュを活用し、検証速度を数倍に引き上げる
// lint実行時に –cache を付与するのが鉄則
};
—
4. チームへの浸透:共有のステップ
ルールを強制する際、最も重要なのは「なぜこのルールが必要か」というコンテキストの共有です。
1. PRでの解説: 新ルールを追加する際は、必ず「なぜそのノードを禁止するのか」の理由を `README.md` または Wiki に追記する。
2. 既存コードの負債管理: ルール追加時、既存コードが大量にエラーを出す場合は `eslint-disable` を使わず、`–fix` で自動修正可能な範囲を広げるか、もしくは `eslint-config-prettier` のような段階的な適用戦略をとる。
3. IDEの自動統合: `VS Code` の `.vscode/settings.json` をリポジトリに含め、保存時に自動整形が走る環境をチーム全員に強制する。
{
“editor.codeActionsOnSave”: {
“source.fixAll.eslint”: true // 保存した瞬間にルール違反が直る世界を作る
},
“editor.formatOnSave”: true
}
結論:ツールは「文化」である
カスタムルールを作成することは、単なる技術的な作業ではありません。それは「チームとしてどのようなコードを美しいとし、何をリスクとみなすか」という合意形成そのものです。
ルールが増えるたびに、あなたのチームのレビュー負荷は減り、空いた時間は「より価値のある設計」や「新機能の開発」に充てられます。さあ、今すぐAST Explorerを開き、チームのボトルネックとなっているコードを検知する最初のルールを書いてみてください。その一歩が、数ヶ月後のチームの生産性を劇的に変えるはずです。