C#
VisualStudio
.NETFramework
ReSharper
Rider

RiderはVS+ReSharperに比べて大規模ソリューションにおいて良好なパフォーマンスを発揮しました

More than 1 year has passed since last update.

はじめに

Visual Studio 2017にReSharperをインストールして使っていますが、開発中のとある大規模なソリューションを開くと、動作が全般的に遅い状況です。この状況に対し、JetBrains社が提供しているRiderを使ってみたところ、パフォーマンス的にとても良好な使用感を得られたので、その経緯を含めてシェアしようと思います。

経緯

Visual Studioで開発中のとあるソリューションを開くと、ソリューションを開く、コードを編集する、デバック中にステップ実行するといった基本的な動作が全般的に遅いです。私のPCのスペックは下記の通りで、開発マシンとしてはかなり良いはずです。

  • Processor: Intel Xeon CPU E5-1620 @ 3.60GHz
  • RAM: 44.0 GB

他の人のPCでも同様に遅いうえに、より小規模なソリューションでは問題ないので、このソリューションの規模が大きすぎることが問題ではないかと考えています。参考までに、Visual Studioの機能でCode Metricsを見てみたところ、全127プロジェクト中のトップ10のLOCは、
2017-09-25_00h01_49.png
となり、概算ですが、ソリューション全体で合計すると約160万LOCとなります。他にも、循環的複雑度をプロジェクト毎に出すと(正確にはプロジェクト内に存在する全メソッドの循環的複雑度の合計値を出すと)、
2017-09-25_00h28_03.png
となります。これらの数字はあくまで参考程度ですが、大まかに、一つのソリューションとしては大規模かつ実行パスの多い複雑なコードが入っていると分かっていただけると思います。

なお、計算したCode MetricsをExcelに出力する機能があります。下図のボタンでは、ソリューション全体について出力します。
2017-09-25_00h49_01.png
だだし、このボタンをクリックすると、
2017-09-25_00h51_04.png
と、エラーが出力されます。プロジェクトを右クリックして、一つのプロジェクトについても出せるのですが(下図)、そちらは問題なくExcelファイルに出力できました。
2017-09-25_00h52_47.png
これはつまり、Visual StudioのCode Metricsの機能がサポートしきれないほどのソリューションの規模だということでしょうか。

ちなみに、タスクマネージャーでVisual Studioのプロセス(devenv.exe)を見てみると、メモリ使用量が2.7GBぐらいから伸びていきません。44GBもRAMを積んでるのでどんどん使ってくれてかまわないのですが・・・。devenv.exeは32-bitプロセスなので、1プロセスあたりのメモリ使用量の上限にひっかかるということなのでしょうか。

長くなりましたが、要は、一つのソリューションに入れておくには大きすぎる規模のコードが入っているということです。対応策としては、複数のソリューションに分割することが挙げられます。しかし、開発体制上、残念ながらソリューションの分割は私が関与できないところなのです・・・。

Riderの登場

JetBrains社がRiderという.NET向けのIDEを出すと聞いた時点で、かなり期待していました。あのReSharperの開発元です。ReSharperが提供するNavigationやRefactoring機能にはかなりお世話になっています。他にも、IntelliJ IDEAを使ったことがありますが、こちらはまさにReSharperの機能が組み込まれたIDEといった印象を受けていました。

更に、Riderの公式ページには、世間で良く言われているCross-platformでの動作やNavigationやRefactoring機能といったところだけではなく、パフォーマンスについても売り文句があります。Featuresのページに、下図のように書かれています。
image.png
注目したいのは、

Rider isn't jammed into a 32-bit process, which helps it gain deep insight into your code while still being responsive.

です。これは明らかに、32-bit版しか存在しないVisual Studioへのあてつけです。この売り文句を聞いて、私のRiderへ期待度は大変高まりました。

Riderを使ってみた感想

2017年8月3日にRiderは正式リリースとなりました。気になっていたので、そろそろ使ってみることにしました。2ヶ月ほど、前述の大規模ソリューションで使ってみた感想です。

良好なパフォーマンス

サクサク動きます。ソリューションを開く時、コードを編集する時、デバッグ中にステップ実行する時など、全ての面においてVisual Studio + ReSharperに比べて良好なパフォーマンスを発揮します。Riderのパフォーマンスに慣れたうえで、Visual Studio + ReSharperの環境に戻ると、元から重いと認識していた操作以外にも、様々な操作をする度に待ち時間が発生していたこと、そしてその待ち時間に慣れてしまっていたことに気が付かされます・・・。

完全なReSharperが入っている訳ではない

ReSharperで使える全ての機能が入っている訳ではないようです。例えば、Copying Fully-qualified nameがありませんでした。ただし、Riderの公式サイトでも

Rider provides 2500+ live code inspections, hundreds of context actions and refactorings brought by ReSharper, and combines them with the IntelliJ platform's solid IDE features.

と書かれているだけでReSharperの機能が全て入っているとは書かれていないので、仕方のないことかもしれません。それでも、十分な機能が揃っているとは思います。

Visual Studioとは異なるルック&フィール

ルック&フィールは、IntelliJ IDEAがベースなので、Visual Studioとは異なります。単なるルック&フィールの差だけなら慣れればいいのですが、明らかにVisual Studioの方が良い場合があります。一つの例としては、Quick Infoについては、Visual Studioでは色付きで表示されるのに対し、Riderでは色が付いていないことです。前述のReSharperの機能についてもそうですが、まだ改善の余地は残っているという感触を受けました。

まとめ

大規模なソリューションにおいてVisual Studio + ReSharperでは動作が遅い場合に、Riderはパフォーマンスの観点から良い選択肢になると思います。ReSharperの機能が完全に入っていないことやルック&フィールが異なるという点については、そもそもサクサク動かないという問題に比べれば小さいものです。JetBrains社は良い開発ツールを作る会社だと再認識しました。

余談

ここからは余談です。

RiderからTFVCを使おうとして失敗した話

前述の大規模ソリューションのソース管理がTFVCなので、RiderでTFVCを使おうとしましたが、そのプラグイン(Team Explorer Everywhere)は環境変数PATHにダウンロードしたtf.exeを設定することが前提のようです。(はっきり書かれたドキュメントは見ていないのですが、PATHを通さずに使っている例をみたことがありません。)会社の開発環境ではすでに異なるtf.exe向けにPATHを通してあり、会社のスクリプトがそれを前提に動いているので、自分だけ異なるtf.exeを使っていて事故を起こすのは避けたい・・・という思惑があり、PATHを通さずに使おうとしました。しかし、tf eula相当のことをしようとしたら
image.png
というエラーが出力されて、解決策が分からず、それ以降、RiderからTFVCを使うことを諦めている状況です。ですので、Visual StudioとRiderの両方で同じソリューションを同時に開いて、Visual Studioのソース管理機能を使いつつ(check outしたりdiffを見つつ)、Riderでコードの調査や編集をするといった使い方をしています。

2017/11/03追記
Visual StudioでTFVCの操作をしている場合は、workspaceをlocal workspaceにすると良いです。local workspaceの場合は、ファイルに変更が入った時点で自動的にcheck outされた状態になります。
対して、もう一つの選択肢であるserver workspaceでは、check outされていないファイルをRiderで編集しようとすると、Read-onlyを外すかどうか聞いてくるウィンドウが出てきます。もしここでRead-onlyを外した上で変更をすると、ファイルが変更されているにもかかわらず、TFVCはそのファイルの変更を検知していない状態になります。ですので、Riderで編集する前に手作業でcheck outする必要があります。具体的な例としては、methodをrenameする場合に、そのmethodを呼び出すコードが入っている全てのファイルを手作業でcheck outするという、とても煩雑な作業が発生します。
参考:Decide between using a local or a server workspace