Edited at

不要なSwiftコードにWarningを出す【Periphery】


はじめに

使われていないコードをずっとプロジェクトに残しておくことは技術的負債になります。


  • 使われていないコードを読む時間のムダ

  • 使われていないコードを修正する時間のムダ

  • 使われていないコードをビルドする時間のムダ

使われていないコードは「到達不能コード」、「デッドコード」とも呼ばれます。

不要なコードは書かない、という「YAGNIの原則」はデッドコードにも適用されるべきです。

https://ja.wikipedia.org/wiki/YAGNI


"You ain't gonna need it"[1]、縮めて YAGNI とは、機能は実際に必要となるまでは追加しないのがよいとする、エクストリーム・プログラミングにおける原則である。


また、間違った実装により利用すべきコードを利用していない場合、使われていないコードを知ることで間違った実装方法に気づけるというメリットもありそうです。

そこで、無償で利用できるPeriphery(ペリフェリー)というツールで使われていないSwiftコードにWarningを出す方法のご紹介をします。


Peripheryとは

Periphery(ペリフェリー)はオープンソースとして提供されているデッドコードの分析ツールです。Pro Modeの機能以外は、無償で利用できます。商用利用可能なMIT Licenseで提供されています。

公式サイト: https://peripheryapp.com/

Githubリポジトリ: https://github.com/peripheryapp/periphery

例えば以下のようなものを検出できます。


  • 不要な型の検出(クラス、構造体、プロトコル)

  • 不要な関数とその引数、プロパティ

  • 不要なEnum、ケース

  • 不要なType aliases、associated types

PeripheryはCUIでの実行だけでなく、Xcodeに導入することで不要コードをWarningとしてハイライトすることも可能です。

image.png

Objective-Cと混在したプロジェクトでは、Objective-Cコードの利用有無は検出できないものの、一応@objc@objcMembersなどをみてObjective-Cで利用されていると判断してくれるようです。逆に未使用と判断されたものでもObjective-Cコードからの参照がある可能性があるのでここは注意が必要です。

https://peripheryapp.com/documentation/analysis/#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を選択します。

image.png

TargetのProduct Nameは「Periphery」などわかりやすいものにしておきます。

次に追加したTargetのBuild Phases+をクリックして、Run Scriptを追加します。

image.png

# Run Scriptの例(`--format xcode`オプションが必要)

periphery scan --workspace MyApp.xcworkspace --schemes MyApp --targets MyApp --format xcode

あとは作成したTargetに紐づくスキームを選択して実行するだけです。

image.png


おわりに

試しに個人プロジェクトで試したところ、以下のような結果となりました。


  • 3500行(LOC)くらいのプロジェクトで実行時間は90秒程度(大きなプロジェクトでは数十分かかりました)


  • 43件の不要コードを検出


  • 100行程度のコードの削減に成功

また一部のコードではClassを抽象化するProtocolを定義したもののClassを直接利用していたため実装方法の誤りに気づくことができました。

他にはSwiftGenで自動生成した画像リソースの取得コードが一部利用されていなかったため、画像リソースごと不要とみなして削除することができました。

より大規模なプロダクトではもっと効果を発揮しそうです。不要コードは気づかないうちに必ず溜まっていくものなので、こういったツールを利用してなるべくクリーンなコードを保ちたいです。