Swift のビルドを高速化する (30秒→4秒に)

  • 33
    いいね
  • 3
    コメント

Classi Advent Calendar 2016 17日目です!

Swift ファイル数 80 ほどの開発中盤段階のプロジェクトですが、ビルドに時間がかかり開発効率が落ちていたため 2 日ほどかけて高速化を行いました。

ローカルビルドが30秒から4秒ほどになり、 CircleCI のビルド〜テスト完了までの時間を10分から4分になりましたので、 実施内容を書いていきます。

3行でいうと

  • Build Target の設定を見直し
  • CocoaPods から Carthage に移行しソース管理に含める
  • ソースコードを改善

マシンスペック

一世代前の MacBook Pro で、 CPU は増してないです。

MacBook Pro (Retina 13-inch、Early 2015)
プロセッサ: 2.7 GHz Intel Core i5
メモリ: 16 GB 1867 MHz DDR3

ashfurrow/xcode-hardware-performance でいうと中の上くらいのスペックです。

1. Build Target の設定を見直し

まずおかしいと思っていたのが、Target が複数ある場合全ての Target が Build されていること。

Target は API を本番/テスト環境の切り分けのために3つ用意し、テスト用の Target を1つの計4つ用意していた。

unspecified.png

この構成で、 ClassiDevelop をビルドしただけなのに ClassiStagingClassi もビルドされており3倍時間がかかっていた :cry:

なぜ指定外の Target がビルドされていた?

ClassiTestsClassi, ClassiStaging, ClassiDevelopment の3つに依存していたため、依存されていたもの全てビルドされていた。

それを ClassiDevelopment のみ依存するようにした。
こうすると ClassiDevelopment でしかテストを実行できなくなるが、それは大きな問題でないため依存を減らした。

before after
unspecified.png unspecified.png

私は Target 複数にしたことなかったのでハマったが、界隈では常識なのかな... :rolling_eyes:

2. CocoaPods から Carthage に移行しソース管理に含める

今まで CocoaPods を使っていたのを Carthage に移行し、ライブラリをソース管理するようにした。
やり方はググれば出てくるのでここでは書かないが、 Cartfile にライブラリを移して地道に Podfile から消していった。

また、 CocoaPods を .gitignore すべきか の理由で Pods/* を gitignore してたが、 git 管理するように変更した。
Clone やコンパイルの時間が必要なくなるので CircleCI のビルドが早くなったり、 clone 後にライブラリのインストールが不要になる。

残課題

R.swiftFabric, Crashlytics は Carthage 未対応だったのでそのまま CocoaPods に残してある。

また、 [iOS] アプリの設定画面にバージョン表記と謝辞を自動で設定する のやり方でライブラリの権利情報など載せていたが、 Carthage だとそれができない。

下記を参考になんとかする予定。

3. 地道にソースコードを改善

コンパイルに時間がかかるSwiftのコードへWarningを発生させる のやり方でビルド時間を測定。

unspecified.png

この設定でコンパイル時間が 100ms を超えるメソッドに warning が出るようになった。

ただし、 100ms 以上かかっているメソッドが 1 つかなく、大してやることはなかった。
閾値を 50ms にして確認したところ、幾つか出てきたので「これはどうしようもないやろ...」というの以外は直した。

直した一例

Cookie を保存する処理だが、無駄に for 分で回しててしかも ?? を使っていたので修正し 100ms 以下にした。

-        var targetCookies: [HTTPCookie] = []
-        for cookie in HTTPCookieStorage.shared.cookies ?? [] {
-            targetCookies.append(cookie)
+        guard let cookies = HTTPCookieStorage.shared.cookies else {
+            return
         }
-        let cookiesData = NSKeyedArchiver.archivedData(withRootObject: targetCookies)
+        let cookiesData = NSKeyedArchiver.archivedData(withRootObject: cookies)

高速化の結果

before after
unspecified.png unspecified.png
:clock: 約30秒 unspecified.png

CircleCI のビルド + テストに10分以上かかっていたのが4分以下に :tada:
ローカルマシンビルドも4秒以下に :blush:

これ以上は...?

iOS エンジニアだけ他の人より良いマシンを要求するのは申し訳ないのだが、
ローカルマシンの馬力が開発効率と直結するから良いマシンが欲しい... :eyes:

最後に

Classi 株式会社ではエンジニアを募集しています。
iOS エンジニア自分しかいなくて寂しいので興味ある人は話を聞きに来てください!!!!!

日本の教育を変える!先生・生徒向けアプリを作るiOSエンジニア募集! - Classi株式会社のモバイルエンジニア中途の求人 - Wantedly