はじめに
使われていないコードをずっとプロジェクトに残しておくことは技術的負債になります。
- 使われていないコードを読む時間のムダ
- 使われていないコードを修正する時間のムダ
- 使われていないコードをビルドする時間のムダ
使われていないコードは**「到達不能コード」、「デッドコード」とも呼ばれます。
不要なコードは書かない、という「YAGNIの原則」**はデッドコードにも適用されるべきです。
"You ain't gonna need it"[1]、縮めて YAGNI とは、機能は実際に必要となるまでは追加しないのがよいとする、エクストリーム・プログラミングにおける原則である。
また、間違った実装により利用すべきコードを利用していない場合、使われていないコードを知ることで間違った実装方法に気づけるというメリットもありそうです。
そこで、無償で利用できるPeriphery(ペリフェリー)というツールで使われていないSwiftコードにWarningを出す方法のご紹介をします。
Peripheryとは
Periphery(ペリフェリー)はオープンソースとして提供されているデッドコードの分析ツールです。商用利用可能なMIT Licenseで提供されています。
Githubリポジトリ: https://github.com/peripheryapp/periphery
例えば以下のようなものを検出できます。
- 不要な型の検出(クラス、構造体、プロトコル)
- 不要な関数とその引数、プロパティ
- 不要なEnum、ケース
- 不要なType aliases、associated types
PeripheryはCUIでの実行だけでなく、Xcodeに導入することで不要コードをWarningとしてハイライトすることも可能です。
Objective-Cと混在したプロジェクトでは、Objective-Cコードの利用有無は検出できないものの、一応@objc
や@objcMembers
などをみてObjective-Cで利用されていると判断してくれるようです。逆に未使用と判断されたものでもObjective-Cコードからの参照がある可能性があるのでここは注意が必要です。
https://github.com/peripheryapp/periphery?tab=readme-ov-file#objective-c
Peripheryの導入と実行
Homebrewでの導入方法です。
# Homebrewのインストール(必要に応じて)
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
# Peripheryのインストール
brew tap peripheryapp/periphery
brew cask install periphery
CUIで実行する場合は以下のコマンドで実行できます。
periphery scan
# workspaceなど指定する場合
periphery scan --workspace MyApp.xcworkspace --schemes MyApp --targets MyApp
Xcode上で実行する場合は、Aggregate Targetとして別ターゲットに追加すると良いです。
Run Scriptでメインターゲットのビルド毎に実行することも可能ですが、実行に少し時間がかかってしまいます。
File > New > Target...
を開き、Cross-platform
内のAggregate
を選択します。
TargetのProduct Nameは「Periphery」などわかりやすいものにしておきます。
次に追加したTargetのBuild Phases
で+
をクリックして、Run Scriptを追加します。
# Run Scriptの例(`--format xcode`オプションが必要)
periphery scan --workspace MyApp.xcworkspace --schemes MyApp --targets MyApp --format xcode
あとは作成したTargetに紐づくスキームを選択して実行するだけです。
おわりに
試しに個人プロジェクトで試したところ、以下のような結果となりました。
- 3500行(LOC)くらいのプロジェクトで実行時間は90秒程度(大きなプロジェクトでは数十分かかりました)
- 43件の不要コードを検出
- 100行程度のコードの削減に成功
また一部のコードではClassを抽象化するProtocolを定義したもののClassを直接利用していたため実装方法の誤りに気づくことができました。
他にはSwiftGenで自動生成した画像リソースの取得コードが一部利用されていなかったため、画像リソースごと不要とみなして削除することができました。
より大規模なプロダクトではもっと効果を発揮しそうです。不要コードは気づかないうちに必ず溜まっていくものなので、こういったツールを利用してなるべくクリーンなコードを保ちたいです。