Edited at

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

久しぶりの投稿となります。

今月から現場が変わってメンテするプロジェクトが変わりました。

私のしばらくの業務は既存のソースコードに溜まっている技術的負債を返済するタスクになるそうです。

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

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

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


SwiftLintについて

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

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

SwiftLint(Githubリポジトリ)

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をインストールしましょう。

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

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

brew install swiftlint

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

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

pod 'SwiftLint'

そしてterminalで

pod install

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


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

次にSwiftLintを正常に動かすためにプロジェクトファイルのTargetsのところでBuild Phasesの部分で

Run Scriptを追加します。

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

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 さんのコメントを参照ですが、

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の次の記事を参考にして設定していきました。

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

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

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

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で次のコマンドを叩くだけです。

swiftlint autocorrect

これでちょっと汚いと思われていたコードの箇所が適用クラスに限り自動で修正されます。

自動修正自体はものの5秒程度で完了しますので本当にすぐです。

これでXcodeでソースコードを見ていきましょう。

そしてXcode上で⌘ + Bでビルドして見ましょう。

大体は感動の代わりに落胆になるかと思います。

少なくとも私は落胆しました。

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

ビルドエラーになってしまいました。

はい。デフォルトルールに違反しているコードが多く存在していました。

例えば、メソッドの命名だったり定数・変数の命名で違反しているところが多かったです。


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

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

定数・変数レベルでビルドが失敗していた場合には.swiftlint.ymlでルールを緩和していきます。

ただ、.swiftlint.ymlファイルは通常は非表示ファイルなのでFinder上では見つけられません。

どうするかというと、

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

defaults write com.apple.finder AppleShowAllFiles TRUE

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

killall Finder

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

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

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

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ライフが送れるようになると思います。

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