ユニファ開発者ブログユニファ開発者ブログユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。性能改善はじめまして、ユニファ株式会社でWebエンジニアとして働いている本間と申します。Railsを使ったサービスのサーバーサイドの機能追加や改善を担当しています。くみーは2013年5月に開発がスタートし、あと少しで5年目を迎えようとしています。開発がこれだけの期間続けられているというのはとても喜ばしいことだと思うのですが、一方で開発初期にはなかった問題も発生してきています。そのような問題の1つに「テストコードの実行完了までに時間がかかる」というものがあり、弊社でも発生しておりました。今回、この問題に対して改善施策を実施し、それなりの効果を得ることができましたのでご紹介したいと思います。実施しなかった対策Werckerでも並列実行まとめ結果比較はじめに改善施策の実施前後の結果の比較です。2015))で全てのテストコードを走らせた時の実行時間の比較です。実施前(17:02)実施後(3:16)改善対象の洗い出し性能改善を始めるにあたって、最初に攻めどころを明確化を行いました。RSpecはデフォルトで時間がかかるexampleやspecファイルを表示してくれますが、今回の用途に少しマッチしなかったため「合計実行時間」が大きい順にspecファイルを表示してくれるFormatterを自作して対応しました。2系でしか動きません)。このFomatterを使ってRSpecのテストを実行すると、下記のように合計実行時間の上位10specファイルが表示されます(クラス名とパスは隠しています)。合計実行時間が長い順にspecファイルを調べ、原因と思われる箇所に対して対策を実施していきました。実行時間がかかる上位のspecの中に、今後使う予定がないrakeタスクのテストコードがいくつかありました。このコードは不要でしたので本体コードごと削除しました。弊社サービスには何種類かのロールがあり、ロールによって操作可能なアクションが異なります。エラーのテストを実施していました。具体的には、以下のようなコードになります。endendロールによる権限チェックのテストは重要なのですが、「テストデータ作成」と「アクション処理」が複数回実施されていて、ここに改善の余地があると考えました。controllerを使用することで「テストデータの作成」と「成功時のアクション処理」をスキップするようにしました。RSpecが提供する機能の一つで、テスト対象のControllerを継承したクラスをテストコード内で定義することができます。実施している権限チェックのコードをテストしつつ、アクション処理の実行時間を短縮できます。修正後は以下のようなコードになりました。時間のかかるspecの多くでは、DBへのデータ書き込み(特にどのテストでも使う共通のオブジェクトの作成)で時間がかかっていました。事前に作成し、これを各exampleで参照するようにしました。この方法はテスト間の独立性を壊してしまう可能性があるため利用には注意を払う必要があります。今回、以下のルールに沿って実施しました。共有するのは参照専用のオブジェクトのみ。共有する範囲は1つのspecファイル内まで。対象は合計実行時間の上位20specファイルまで。作成したオブジェクトを全て削除する。テストコードは以下のようになります。上記施策を実施して実行時間を10分前後に減らすことはできたのですが、大きな改善を見込める箇所が見当たらなくなってしまいました。そこで、最終手段としていたテストの並列実行を導入しました。RSpecを並列実行するGemとしてparallel_testsとtest-queueが有名なようです。今回は「parallel_tests」を使用しました。導入にあたって実施した内容は以下になります。