SwiftLintを導入してソースコードを整えたのでその知見を紹介します

久しぶりの投稿となります。
今月から現場が変わってメンテするプロジェクトが変わりました。
私のしばらくの業務は既存のソースコードに溜まっている技術的負債を返済するタスクになるそうです。

で、実際にソースコードを確認したのですが、これを自分がメンテするにはまずは`SwiftLint`を導入しないとダメだなと思い先週から`SwiftLint`の導入方法を調査していました。

というのも今までは既に`SwiftLint`を導入しているプロジェクトに参画していたので自分では導入したことはなかったのですね。

ということ今回はこの`SwiftLint`の調査と導入する過程で得られた知見を備忘録として残したいと思います。

# SwiftLintについて

ではそもそも`SwiftLint`ってなんぞやということから紹介します。

簡単にいうとSwiftのソースコードで独自ルールを設定してそれに沿って既存のソースコードを自動修正していくツールです。ツールですが、実際にはライブラリですので導入にはCocoapodsを使います。

[SwiftLint(Githubリポジトリ)](https://github.com/realm/SwiftLint)

Githubページに移れば分かりますがモバイルアプリのDBでお世話になる`Realm`社が提供しているライブラリになります。

このSwiftLintを既存コードに導入するとどのようなメリットがあるかというと

例えば、以下のソースコードがあったとします。

```Sample.swift

import UIKit
import UIKit // 重複import です

class MainViewController:UIViewController {
    @IBOutlet var button:UIButton!
    
    override func viewDidLoad(){
        super.viewDidLoad()
    }
    
    func sampleMethod()->Int{
        var count:Int = 1
        count += 1
        return count
    }
}
```

パッと見あんまり見たくないコードですよね。できればコードフォーマッタを使って`型`のスペース部分とかを修正したいかと思います。その気持ちがあれば十分だと思います。

こういったクラスが2,3個だけならいいのですが、数百個レベルになると個人的には辛くなってくると思います。
そんなあなたにとっては`SwiftLint`は大きな味方です。

SwiftLintに既にあるデフォルトのルールを適用させるだけでも上記のコードを綺麗に整えることができます。

例えば、上記のコードは正確には

```Sample.swift
import UIKit

class MainViewController: UIViewController {
    @IBOutlet var button: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    func sampleMethod() -> Int {
        var count: Int = 1
        count += 1
        return count
    }
}
```

このように修正されます。
これがSwiftLintのパワーです。

あなたがメンテしているコードで上記の部分が該当している場合にはチームリーダーに相談してSwiftLintを導入して見ましょう。

そんなSwiftLintの導入の仕方を紹介します。

# SwiftLintの導入方法について

簡単にまとめると

1. Cocoapodsに`Swiftlint`を追加するimportする
2. Run Scriptを追加してとあるコードを差し込む
3. ルートディレクトリに`.swiftlint.yml`を追加して最初のルールを簡単に記載する
4. Terminalで`swiftlint autocorrect`を叩く

たったこれだけの作業でSwiftLintを導入して既存コードを修正していくことができます。

ではそれぞれ説明していきます。

## Cocoapodsに`SwiftLint`を追加してimportする

githubページの解説に従ってpodsを使ってライブラリをimportしましょう。

まずはMacに`Homebrew`がない場合は`Homebrew`をインストールします。

https://brew.sh/ のトップページにある下記のコマンドを叩いて`Homebrew`をインストールしましょう。

```sh
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

`Homebrew`が無事にインストールできたら次のコマンドを叩きます。

```sh
brew install swiftlint
```

これでMacにswiftlintがインポートされます。

それが完了したら`CocoaPods`を使ってSwiftLintをインポートします。

```podfile
pod 'SwiftLint'
```

そしてterminalで

```sh
pod install
```
を叩くことで無事にSwiftLintがプロジェクトファイルに入ります。

## Run Scriptを追加してとあるコードを差し込む

次にSwiftLintを正常に動かすためにプロジェクトファイルの`Targets`のところで`Build Phases`の部分で
`Run Script`を追加します。

そのRun Scriptを追加してシェル上に次のコードを差し込みます。

```sh
if which "${PODS_ROOT}/SwiftLint/swiftlint" >/dev/null; then
${PODS_ROOT}/SwiftLint/swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
```

これで基本的な設定が完了しました。

[注記]  
@uhooi さんのコメントを参照ですが、

```sh
if which "${PODS_ROOT}/SwiftLint/swiftlint" >/dev/null; then
    swiftlint autocorrect --format
    swiftlint
else
    echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
```

と記載するとコミット毎に自動修正が入るようになります。
こちらの方が運用上楽かと思います。

## ルートディレクトリに`.swiftlint.yml`を追加して最初のルールを簡単に記載する

さてこれからソースコードに適用させるlintのルールを設定していきます。
このルールの把握に時間が取られました。

流石にここはQiitaの次の記事を参考にして設定していきました。

- [SwiftLintのRules全まとめ](https://qiita.com/kagemiku/items/80e6d905dc0059c342b3)
- [SwiftLintのRules一覧（2018年3月最新版）](https://qiita.com/yuukiw00w/items/075253a868805227bc78)
- [SwiftLintの運用ノウハウ](https://qiita.com/shtnkgm/items/6dd756aa14926736c6f5)

非常にお世話になりましたのでこの場をお借りして感謝のお礼を申し上げます。

そして、続きの説明に入りますが、プロジェクトファイルのルートディレクトリ(簡単に言えばPodfileなどが入ってい階層のこと)に`.swiftlint.yml`ファイルを追加します。

ターミナルでルートディレクトに移動したらviコマンドでファイルを追加します。

```sh
vi .swiftlint.yml
```

これでvimが使えるようになるのでルールの詳細がわからない導入期は下記のコードをコピーペーストしましょう。

```.swiftlint.yml
# 無効にするルール
disabled_rules:
# xcodeでviolation warningが表示されたり違反でXcodeがビルドできないルールを差し込んでいきます。

# デフォルトルール以外でopt-inから適用させるルールの設定
opt_in_rules:
# ここに採用したいルールを追加していく #


# SwiftLintの適用から外すディレクトリ
# (UnitTestやUITestもある場合は修正されますので入れます)
excluded:
# cocoapodsを使っている場合#
- Pods/
# Carthageを使っている場合#
- Carthage/



# 1行あたりの文字数制限を300に変更
line_length: 300

# etc
```

これをペースとして`:wq`で保存します。
これでSwiftLintに適用させたいルールの設定が終わります。

## Terminalで`swiftlint autocorrect`を叩く

ここまでの設定が終わればあとはTerminalで次のコマンドを叩くだけです。

```sh
swiftlint autocorrect
```

これでちょっと汚いと思われていたコードの箇所が適用クラスに限り自動で修正されます。
自動修正自体はものの5秒程度で完了しますので本当にすぐです。

これでXcodeでソースコードを見ていきましょう。
そしてXcode上で`⌘ + B`でビルドして見ましょう。

大体は感動の代わりに落胆になるかと思います。
少なくとも私は落胆しました。

Swiftの標準的な書き方を踏襲していたらそんな違反になることはないと思いましたが私がやって見た限りは
ビルドエラーになってしまいました。

はい。デフォルトルールに違反しているコードが多く存在していました。
例えば、メソッドの命名だったり定数・変数の命名で違反しているところが多かったです。


## 既存のコードでviolationや違反があってビルドが失敗する場合の対処方法

そこでデフォルトのSwiftLintのルールに違反していてビルドが成功しなかった場合の対処方法を紹介します。

定数・変数レベルでビルドが失敗していた場合には`.swiftlint.yml`でルールを緩和していきます。
ただ、`.swiftlint.yml`ファイルは通常は非表示ファイルなのでFinder上では見つけられません。

どうするかというと、

ターミナル上で次のコマンドを叩きます。

```sh
defaults write com.apple.finder AppleShowAllFiles TRUE
```

そして、次のコマンドでFinderを一度切ります。

```sh
killall Finder
```

再度、Finderを開くと非表示ファイルが見えるようになります。

これで`.swiftlint.yml`をVScodeとかでひらけます。

そして`disabled_rules`に次のようなルールを入れてそのルールを`無効`にしていきます

```sh
disabled_rules:
# warningが走るため無効にする

# ビルドが失敗するルールを無効にする
- variable_name
- file_length
- function_body_length
- line_length
- type_body_length
- variable_name_max_length
- variable_name_min_length
- force_cast
- force_try
- shorthand_operator
- empty_count
- cyclomatic_complexity
- type_name
- implicit_getter
```

このあたりのルールを無効化したらSwiftLintが許してくれるようになりました(笑)。
結構、規約に無視したコードでも割とビルドに成功すると思います。

全体的なファイルをもう一度記載すると

```.swiftlint.yml
# 無効にするルール
disabled_rules:
# warningが走るため無効にする

# ビルドが失敗するルールを無効にする
- variable_name
- file_length
- function_body_length
- line_length
- type_body_length
- variable_name_max_length
- variable_name_min_length
- force_cast
- force_try
- shorthand_operator
- empty_count
- cyclomatic_complexity
- type_name
- implicit_getter

# デフォルトルール以外でopt-inから適用させるルールの設定
opt_in_rules:
# ここに採用したいルールを追加していく #


# SwiftLintの適用から外すディレクトリ
# (UnitTestやUITestもある場合は修正されますので入れます)
excluded:
# cocoapodsを使っている場合#
- Pods/
# Carthageを使っている場合#
- Carthage/



# 1行あたりの文字数制限を300に変更
line_length: 300

# etc
```

こんな感じにして再度`swiftlint autocorrect`を叩いてXcode上で`⌘ + B`して見てください。
これよりひどい場合にはやっぱりビルドは失敗すると思いますが私の場合はこれでなんとかビルドが成功するようになりました。

あとはコミットのたびに`swiftlint autocorrect`していけばSwiftLintを適用した快適なSwiftライフが送れるようになると思います。

では以上で記事を終わります。