Peripheryによる未使用コードの検知方法（ローカル + CI）

# 概要
iOSアプリ開発において、プロジェクト内の未使用コードを検知するためのライブラリとして[Periphery](https://github.com/peripheryapp/periphery)が有名かと思います。
本記事ではPeripheryを使って、
* ローカル（Xcode）上
* CI（PR作成時）上

の二つの環境下で未使用コードを検知する方法を紹介します。

# 準備
Peripheryを導入する方法として、Homebrew・Mint・CocoaPods などいくつかあると思います。
Peripheryの導入方法を調べると、Homebrew でインストールする方法がよくあがってきますが、今回はCocoaPods でインストールしていきます。
理由としては、CocoaPodsでインストールした方が、チームで開発する際にバージョンを固定でき、管理がしやすくなるためです。

プロジェクト内の`Podfile`に下記を記述します。
```ruby:Podfile
pod 'Periphery'
```
そして、`pod install`すれば、バージョンが固定されチーム内で同じバージョンのPeripheryがインストールされます。
このとき、`Pods/Periphery/periphery`に実行ファイルがインストールされます

# ローカル（Xcode）上での実行
未使用コードに対して、Xcode上で警告を表示するための方法です。

## .periphery.yml の作成
下記のような設定ファイルをプロジェクトのルートに作成します。
ルールはドキュメントをご確認し、適宜設定してください。（以下は例です）
```yml:.periphery.yml
retain_public: true
external_encodable_protocols: true
retain_unused_protocol_func_params: true
retain_assign_only_properties: true
retain_objc_accessible: true
schemes:
- [適宜スキーム名を設定してください]
targets:
- [適宜ターゲット名を設定してください]
workspace: [適宜ワークスペースを設定してください]
format: xcode
```

## Xcodeの設定
Xcode上でPeripheryを実行する場合は、Aggregate を使用します。
File > New > Target から「Aggregate」を選択します。
![スクリーンショット 2024-02-18 13.33.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91285/f9ccb02f-b291-c54b-6612-446aabc5b05d.png)

今回は`Product Name`を`Periphery`としました。
![スクリーンショット 2024-02-18 13.34.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91285/3854bca4-cd80-7153-ce7d-ed3d33422ae8.png)

追加したTargetを選択し、「Run Script」を追加します。
そして、Peripheryを実行するスクリプトを記述します。
ここでの注意点としては、先ほど`pod install`して生成された`Pods/Periphery/periphery` の実行ファイルへのパスを記述することです。
```
./Pods/Periphery/periphery scan
```

そして、スキームに追加、選択して実行します。
![スクリーンショット 2024-02-18 13.34.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91285/11b035dc-e6d1-c4e0-192b-2034fc0a2aef.png)

これで、`.periphery.yml`に記述したルールに従ってPeripheryを実行するようになります。
以下は、警告の例です。
![スクリーンショット 2024-02-18 13.51.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91285/fcb11542-f6cf-9301-6ce8-990f07eb97cf.png)

以上が、Xcode上でPeripheryを実行し警告を出す方法になります。

# CI上での実行
次はCI上でPeripheryを実行する方法です。
今回はGitHub Actionsで、PR作成時に、Peripheryを実行し、未使用コードがあった場合はPR上で警告を表示するようにします。

## danger-periphery の設定
PRのチェックを自動化するツールとして、[Danger](https://github.com/danger/danger)があると思います。
今回は、[danger-periphery](https://github.com/manicmaniac/danger-periphery)という便利なプラグインがあったため、そちらを使うことにしました。

（まだGemfileが存在しない場合は）プロジェクトのルートディレクトリに`Gemfile`を作成します。
```ruby:Gemfile
gem "danger-periphery"
```

次にプロジェクトのルートディレクトリに`Dangerfile`というファイルを追加します。（`Dangerfile`がまだ存在しない場合）
ここでも注意点としては、`Pods/`配下に存在する実行ファイルを指定することです。
```ruby:Dangerfile
periphery.binary_path = "./Pods/Periphery/periphery"
periphery.scan
```

## GitHub Actionsの設定
今回はGitHub Actions でCIを実行することを想定していますので、その設定になります。

bundlerを使うことを想定していますので、そのための設定をGitHub Actions のWorkflowに記述します。既存のビルドのWorkflowがあれば、そちらに追記していきます。
※ Rubyのバージョンは適宜プロジェクトで使用しているバージョンに合わせてください。
```yml:build.yml
- name: Rubyをセットアップ
  uses: ruby/setup-ruby@v1
    with:
      ruby-version: '3.3'
      bundler-cache: true
```

次に、Dangerを実行する設定をWorkflowに記述します。
```yml:build.yml
- name: Dangerを実行する
  env: 
    DANGER_GITHUB_API_TOKEN: ${{ 適宜トークンを設定してください }}  
  run: bundle exec danger
```

以上で、PR作成時に未使用コードがあった場合、[こちらの記事](https://blog.studysapuri.jp/entry/2021/10/25/remove-unused-codes-with-periphery)の画像のように、Dangerが警告を表示してくれるようになります。

細かい設定等は、[danger-periphery](https://github.com/manicmaniac/danger-periphery)から確認できると思います。

# まとめ
PeripheryはSwiftの未使用コードを検出するツールですが、XcodeやCIと連携することで、より効果的にコードの品質を向上させることができます。
Xcode上でPeripheryを実行できるようにすることで、プロジェクト内に既に存在してしまっている未使用コードを削除していくための方針を決めるのに役に立つと思いますし、CI上でPeripheryを実行できるようにすることで、新たな未使用コードがプロジェクト内に混入してしまうのを防ぐことができると思います。
Peripheryを試してみて、Swiftのコードをよりクリーンに保ちましょう。👍