Serverless Frameworkで構築したAWS Lambdaプロジェクトに、いつの間にか溜まってしまった未使用コード。どこから手をつけるべきか、悩んでいるエンジニアは多いはずだ。
本記事では、現場のエンジニアが直面するこの課題に対し、未使用コードを効率的に発見し、削除するための具体的なアプローチを解説する。筆者の経験上、未使用コードは放置すればするほど、コストと開発効率の両面で悪影響が大きくなる。
Serverless Frameworkにおける未使用コードの課題と背景
Serverless Frameworkは、インフラ管理をコード化し、開発者がビジネスロジックに集中できる環境を提供する。しかし、プロジェクトのライフサイクルが長くなるにつれて、以下のような理由で未使用コードが発生しやすい。
- 過去の機能削除やリファクタリングの際に、関連するコードが完全に削除されなかった。
- 複数の移行プロジェクトが並行して進み、一部のコードが置き去りにされた。
- Lambda関数が直接呼び出さない(API Gatewayや他のイベントトリガーから参照されない)モジュールやディレクトリが存在する。
これらの未使用コードは、デプロイパッケージのサイズを増大させ、ビルド時間を長くするだけでなく、誤って修正・削除してしまうリスクを高める。また、コードベースが複雑化し、新規開発や既存機能の改修の際の可読性と保守性を低下させる要因となる。これは、開発チーム全体の生産性を直接的に下げる行為に他ならない。
未使用コード検出による具体的メリット
未使用コードを特定し、削除することで、開発チームは以下の具体的なメリットを享受できる。
- デプロイパッケージサイズの削減: 不要なコードがなくなることで、デプロイパッケージのサイズが小さくなり、デプロイ時間の短縮に繋がる。これにより、CI/CDパイプラインの効率が劇的に向上する。
- 実行コストの削減: Lambda関数の実行時間やメモリ使用量に影響を与える可能性のある未使用コードを削除することで、AWSの利用料金を最適化できる。これは、数%の削減でも積み重なれば大きなインパクトとなる。
- 保守性の向上: コードベースがシンプルになることで、開発者は必要なコードに集中でき、バグの混入リスクを低減し、開発効率を向上させる。
- セキュリティリスクの低減: 未使用のコードであっても、脆弱性が含まれている可能性はゼロではない。それらを削除することで、潜在的なセキュリティリスクを排除できる。
現場での注意点とハマりどころ
未使用コードの検出にあたっては、いくつかの注意点と、現場で遭遇しやすいハマりどころが存在する。
1. 静的解析ツールの限界とServerless Framework特有の参照関係
knipのような汎用的な静的解析ツールは、Node.jsプロジェクトにおいては強力だが、Serverless FrameworkのようなIaC(Infrastructure as Code)ツールと連携した環境では、その真価を発揮しにくい場合がある。
これは、Serverless Frameworkがserverless.ymlなどの設定ファイルでLambda関数のエントリーポイントやリソース定義を行っており、コード内のrequireやimportといった静的なimport文だけでは、実際の実行パスを完全に把握できないためだ。
例えば、serverless.ymlで定義された関数が、特定のディレクトリにあるモジュールを動的にロードしたり、環境変数に基づいて異なるモジュールを呼び出したりする場合、静的解析ツールはそれらの依存関係を正しく追跡できない。
筆者の経験上、この「動的なロード」こそが、静的解析ツールを悩ませる最大の要因である。
2. Serverless Frameworkのデプロイ構造の理解
Serverless Frameworkは、プロジェクト全体を一つのデプロイパッケージとして扱う場合もあれば、個別の関数ごとにパッケージ化する場合もある。未使用コードの特定においては、このデプロイ単位を正確に理解することが必須だ。
また、Lambda Layersを利用している場合、レイヤー内のコードがどの関数からも参照されていないか、といった点も考慮する必要がある。
3. 動的インポートや外部サービス連携
コード内でrequire(variable)のような動的なモジュール読み込みや、Lambda関数が外部のAPI Gatewayエンドポイントや他のAWSサービス(SQS, S3イベントなど)からのトリガーによって呼び出される場合、これらの依存関係は静的なコード解析だけでは捉えきれない。
4. テストコードとの区別
テストコードやユーティリティスクリプトなども、静的解析ツールによっては未使用と判定される可能性がある。これらはプロジェクトにとって必要なコードであるため、検出対象から除外するか、手動で確認する必要がある。
現場での解決策:段階的なアプローチ
これらの課題を踏まえ、現場で実践可能な未使用コード検出のアプローチは以下の通りだ。
ステップ1: 基本的な静的解析ツールの導入と設定(knipの活用)
まずはknipのようなツールを導入し、基本的な未使用モジュールや依存関係の検出を行う。
Serverless Frameworkのプロジェクトでknipがうまく機能しない場合でも、knip.jsonの設定を工夫することで、ある程度の効果は期待できる。
例えば、ignoreUnusedDependenciesやignoreDependenciesオプションを活用して、Serverless Frameworkが管理する設定ファイルや、一時的に使用されていないが将来的に必要となる可能性のあるモジュールを除外する設定を検討すべきだ。
また、knipの設定ファイルで、files.includeやfiles.excludeを適切に設定し、Serverless Framework固有のファイル(serverless.ymlなど)や、Lambda関数が直接利用しないがデプロイに必要なアセットファイルなどを除外対象とする。
// knip.json (設定例)
{
"extends": [
"//node_modules/@types/eslint/config/recommended.js"
],
"functions": {
// "src/**/*.js": {
// "ignores": ["path/to/ignore"]
// },
"glob": "src/**/*.js",
"ignorePatterns": [
"**/*.test.js",
"**/*.spec.js",
"dist/**/*",
"node_modules/**/*"
]
},
"dependencies": [
"glob:src/**/*.js"
],
"devDependencies": [
"glob:tests/**/*.js"
],
"//": "Serverless Framework固有の設定例"
// "ignoreUnusedDependencies": ["serverless", "aws-sdk"], // 不要な依存関係の無視
// "ignoreDependencies": ["@serverless/platform-client"], // 特定の依存関係の無視
"plugins": [
"@knip/plugin-typescript"
], // TypeScriptの場合
"typescript": {
"compilerOptions": {
"allowJs": true,
"checkJs": false
}
}
}
ステップ2: Serverless Frameworkのデプロイ設定と実行パスの分析
serverless.ymlを直接確認し、各Lambda関数がどのエントリーポイントから開始され、どのファイルやディレクトリを参照しているかを把握する。AWS Lambdaのコンソールから、各関数の設定(Handler、Runtimeなど)を確認し、コードベースの構造と照らし合わせる。
また、Serverless Frameworkのデプロイコマンド(例: sls deploy --verbose)で出力される詳細なログを確認することで、ビルドプロセスやデプロイされるファイル群に関する情報を得ることができる。
ステップ3: 実行時ログとカバレッジツールの活用
最も確実な方法の一つは、本番環境またはステージング環境で実行されているLambda関数の実行時ログを分析することだ。AWS CloudWatch Logs Insightsなどを活用し、どのモジュールや関数が実際に呼び出されているかを分析する。このアプローチは、静的解析では捉えきれない動的な呼び出しや、特定のイベントトリガーにのみ依存するコードの特定に有効だ。
Node.jsのコードカバレッジツール(例: nyc/istanbul)をテスト実行時に適用し、その結果をServerless Frameworkのビルドプロセスに組み込むことも検討できる。ただし、これはあくまでテスト実行時のカバレッジであり、実際の実行パスを完全に網羅するわけではない点に注意すべきだ。
ステップ4: 手動による確認と段階的な削除
上記の自動・半自動的な検出手法で候補を洗い出した後は、必ず開発者自身がコードを確認し、そのコードが本当に不要であるかを判断する必要がある。特に、エラーハンドリングやロギング、設定値の読み込みなど、直接的なビジネスロジックではない部分が、間接的に参照されている可能性も考慮すべきだ。
削除は一度に行わず、小さな単位で段階的に行い、デプロイ後に動作確認を徹底することが重要だ。これにより、万が一誤って必要なコードを削除してしまった場合でも、影響範囲を限定し、迅速なロールバックが可能となる。これは、サーバーレス開発における基本中の基本と言える。
結論
Serverless Frameworkにおける未使用コードの発見は、単一のツールで完結するものではなく、静的解析、IaC設定の理解、実行時ログ分析、そして開発者による慎重な判断を組み合わせた多角的なアプローチが求められる。knipのようなツールを初期段階で活用しつつ、serverless.ymlの分析やCloudWatch Logs Insightsでの実行パスの追跡を行うことで、効果的に未使用コードを特定できる。
これらの取り組みにより、AWSリソースのコスト削減、開発サイクルの高速化、そしてコードベースの健全性維持を実現し、より効率的で堅牢なサーバーレスアプリケーションの開発・運用に繋げることができる。今すぐ未使用コードの棚卸しに着手すべきだ。

