やらなイカ?

たぶん、iOS/Androidアプリの開発・テスト関係。

JetBrains ReSharper Command Line Tools 2019.3でコードインスペクションを実行する

JetBrains製のC# IDEであるRiderにあるコードインスペクション機能を、そのままコマンドラインで実行できるツールがReSharper Command Line Toolsとして提供されています。 ReSharper Command Line Toolsは、これまでWindows版しかサポートされていませんでしたが、2019.3からはmacOS及びLinuxでも動作するようになりました。

www.jetbrains.com

ReSharper Command Line Toolsには、コードインスペクションツールであるInspectCodeのほかにも、重複コードを検出するdupFinder、コードクリーンナップを行なうCleanupCodeが含まれています。 今回はInspectCodeのみ紹介します。

ReSharper Command Line Toolsのインストール

ReSharper Command Line Toolsは、上記サイトからプラットフォームを選んでダウンロードできます。無料で、ライセンスキーも不要です。

ダウンロードしたzipファイルは、任意のディレクトリに展開するだけでokです。ターミナルで直接コマンド実行するのであればPATHを通しておくのも良いでしょう*1

ツールの実行にUnityエディタは必要ありませんが、ソリューションファイル (.sln) およびプロジェクトファイル (.csproj) が必要です。CIサーバで実行するときにはあらかじめUnityエディタで生成しておく必要があります*2

InspectCodeの実行

InspectCodeは、以下のように実行できます。Windowsの場合、inspectcode.shinspectcode.exeに置き換えてください。

$ inspectcode.sh \
    $(RESHARPER_TARGET) \
    --output=$(LOG_DIR)/inspect.xml \
    --format=xml

$(RESHARPER_TARGET)には、ソリューションファイル (.sln) のパスを指定します。

出力されるxmlファイルは、例えばJenkinsのPMD Pluginなどで表示できます。また引数に--format=htmlと指定することでhtml形式でも出力できます。

インスペクション内容の設定

InspectCodeがインスペクションしてくれる項目およびデフォルト設定は、下記ページにまとめられています。

Code Inspections in C# - Help | JetBrains Rider

設定をプロジェクトに合わせてカスタマイズするには、IDE(RiderおよびReSharper)のPreferencesの設定内容をファイル出力し、プロジェクトのルートに置くか、--profile引数でパスを渡します。

ファイル出力には2種類の方法があります。

設定をteam-sharedとして保存する

Preferencesを変更するとき、"Save"ボタンではなく、その横のプルダウンで"Solution team-shared"を選択します。

f:id:nowsprinting:20200114035826p:plain

すると、プロジェクトのルートに "プロジェクト名.sln.DotSettings" として保存されます。このファイルをリポジトリに追加すれば、CIサーバでも同じ設定でインスペクションを実行できます。

コンピュータの設定をエクスポートする

すでに設定変更を"Save"ボタンで保存していた場合、それはプロジェクトでなくコンピュータ単位の設定ファイルに保存されています。これをエクスポートし、team-shared設定ファイルとして利用できます。

コンピュータ単位の設定をエクスポートするには、Preferencesウィンドウ左下の"Manage Layers"ボタンでPreferences Layersウィンドウを開きます。

f:id:nowsprinting:20200114035841p:plain

"This computer"行を選択し、ツールバーにある"Export to File"アイコンをクリック、Export To Fileウィンドウを開きます。

f:id:nowsprinting:20200114035847p:plain

ここでエクスポートする設定を選択できます。今回はコードインスペクション向けなので"CodeInspection"だけ選択していますが、他の設定もチームで共有したい場合はここで選択し、"OK"ボタンをクリックします。

続いてファイル指定ダイアログが表示されますので、プロジェクトのルートに "プロジェクト名.sln.DotSettings" として保存します。

プラグインの追加

InspectCodeには、.nupkg形式のプラグインを追加することができます。追加は、.nupkgファイルをReSharper Command Line Toolsを展開したディレクトリに入れるだけで完了します。

例えば、先日の記事で紹介した、コードの複雑度を測るプラグインも公開されています*3

コグニティブ複雑度

plugins.jetbrains.com

サイクロマティック複雑度

こちらはReSharper 2019.3.1で正しく動作しないようです。特にエラーも吐かれていないので設定まわりだと思うのですが、詳細未確認。

plugins.jetbrains.com

まとめ

インスペクションツールの実行はCIに頼るのでなく、IDEに備わっていることで問題の作り込みを早期に防ぐことができます。 その点、RiderやReSharperを使い、かつ警告にきちんと対処していれば、内部品質の高い状態を維持できるはずです。

しかしながら、すでにプロジェクトの内部品質が低くなっている状態から改善していく場合など、CIでメトリクスを採取して変化を監視するのは有効です。ぜひ導入を検討してみてください。

なお、ReSharper Command Line Toolsのマルチプラットフォーム対応については、昨年9月のJetBrains .NET Meetup TokyoおよびCEDEC 2019のJetBrainsブースで「2020.x以降になるだろう」と伺っていたのですが、2019.3に前倒されました。たいへんありがたい。

関連記事

www.nowsprinting.com

関連書籍

*1:CIサーバで実行することになりますので、PATHには頼らずにMakefile等にパス込みで書くことをおすすめします

*2:通常、.gitignoreでトラッキング対象外にしているはずなので

*3:Rider向けではなく、ReSharper向けのプラグインである必要があります

JetBrains Riderでコードの複雑度を計測する

JetBrains製のC# IDEであるRiderには、様々なプラグインが提供されています。 その中から、コードの複雑度を計測するプラグインを2つ紹介します。

www.jetbrains.com

サイクロマティック複雑度

サイクロマティック複雑度(cyclomatic complexity)は循環的複雑度とも呼ばれ、コードの複雑さを測る指標としてよく使われます。 メソッド単位に分岐によるパスの最大数を算出した数値で、一般に、32以上でバグ混入率が高い、50以上でテスト困難と言われています。

循環的複雑度 - Wikipedia

これをRiderのインスペクションに組み込むプラグインがCyclomaticComplexityです。

plugins.jetbrains.com

CyclomaticComplexityプラグインは、一般のプラグインと同様、Preferences... > Plugins からインストール・有効化できます。 有効化すると、エディタのメソッド定義の上にサイクロマティック複雑度が表示されるようになります。

f:id:nowsprinting:20200112202350p:plain

上図では、サイクロマティック複雑度が29、Wariningとなるしきい値20(デフォルト値)に対して145%であると表示されています。

しきい値は、Preferences > Languages & Frameworks > Cyclomatic Complexity で変更できます。 既存プロジェクトで数値の高いメソッドが多い場合は、しきい値を緩めの値にして目立つものから少しづつリファクタリングを進めていくことをおすすめします。

f:id:nowsprinting:20200112202402p:plain

コグニティブ複雑度

コグニティブ複雑度(cognitive complexity)とは、2016年からSonarSource社*1が提唱している比較的新しい複雑度の指標です。循環的複雑度にならって日本語化するのであれば「認知的複雑度」でしょうか。

Cognitive Complexity - A new way of measuring understandability

SonarSource社は、サイクロマティック複雑度では保守性を正しく数値化できておらず、その点を改善したものがコグニティブ複雑度であると書いています。

例えば、サイクロマティック複雑度ではネストしたループとswitch-caseは同じスコアになりますが、後者のほうが理解しやすいコードのはずです。 また、異常系の処理をif文で深くネストした中に書くよりも、メソッドの先頭でエラーチェックしてreturnしてしまうほうが読みやすくなります。

そのため、分岐ではなく処理の流れを阻害する個所を加点することで保守性・可読性の評価につなげようというものがコグニティブ複雑度です。

このコグニティブ複雑度をRiderのインスペクションに組み込むプラグインがCognitiveComplexityです。

plugins.jetbrains.com

CognitiveComplexityプラグインは、一般のプラグインと同様、Preferences... > Plugins からインストール・有効化できます。 有効化すると、エディタのメソッド定義の上にコグニティブ複雑度が表示されるようになります。

f:id:nowsprinting:20200112202240p:plain

上図では、コグニティブ複雑度が23、Wariningとなるしきい値10(デフォルト値)に対して230%であると表示されています。またクリックすることでコード内の加点された個所(上図ではif文の横にある"+1")を表示できます。

しきい値は、Preferences > Languages & Frameworks > Cognitive Complexity で変更できます。 既存プロジェクトで数値の高いメソッドが多い場合は、しきい値を緩めの値にして少しづつリファクタリングを進めていくことをおすすめします。

f:id:nowsprinting:20200112202303p:plain

プロジェクト単位のインスペクション実行

いずれのプラグインもRiderのインスペクション機能に組み込まれていますので、Code > Inspect Code... でスコープを指定して実行できます。

f:id:nowsprinting:20200112214547p:plain:w300

実行結果は"Inspection Results"ウィンドウに表示されます。

f:id:nowsprinting:20200112202335p:plain

上図のように、WARNING > Potential Code Quality Issues の下に、サイクロマティック複雑度とコグニティブ複雑度それぞれ別に表示されます。

  • Element exceeds cyclomatic complexity
  • Element exceeds Cognitive Complexity threshold

なお、両方のしきい値を超えているメソッドは、コグニティブ複雑度にのみ表示されます。

まとめ

同じ目的を持つ2つのプラグインを紹介しましたが、いくつかのプロジェクトで見比べた感じ、コグニティブ複雑度のみ適用しておけばよさそうです。

複雑度の高いメソッドは、条件の組み合わせも多くなりテストすることが難しく、バグも作り込まれやすくなります。 プラグインを入れて数値を気にすることで、適切にメソッドを分割して保守性の高い状態をキープできるようになるでしょう。

なお、CyclomaticComplexityプラグインの存在はUnityゲーム開発者ギルドのSlackで知りました。色々と役立つ情報を交換ができるコミュニティですので、Unityでゲームを開発している方は入ってみてはいかがでしょうか。

scrapbox.io

関連記事

www.nowsprinting.com

www.nowsprinting.com

関連書籍

IntelliJ IDEA パーフェクトガイド

IntelliJ IDEA パーフェクトガイド

仮面ライダーゼロワン 変身ベルト DXザイアサウザンドライバー

仮面ライダーゼロワン 変身ベルト DXザイアサウザンドライバー

  • 発売日: 2019/12/28
  • メディア: おもちゃ&ホビー

*1:SonarQubeの開発・運営会社

JetBrains Rider 2019.3でUnityテストのカバレッジを採取する

JetBrains製のC# IDEであるRiderには、テスト実行時にステートメントカバレッジを採取するdotCoverプラグインが提供されています。

これまで、dotCoverプラグインはUnity Test Framework*1に対応していませんでしたが、2019.3からEdit Mode tests実行時のカバレッジを採取・表示できるようになりました。

www.jetbrains.com

dotCoverプラグインの有効化

dotCoverプラグインは、一般のプラグインと同様、Preferences... > Plugins から有効化できます。 ただし使用するには、"ReSharper Ultimate + Rider" または "All Products Pack" のライセンスが必要です(30日間の試用あり)。

また、計測対象のUnityプロジェクトには、JetBrains Rider Editorパッケージの1.2.0以降が必要です。バージョンが古い場合は、UnityエディタのPackage Managerでアップデートしてください。

本稿では以下のバージョンで動作を確認しています。

  • JetBrains Rider 2019.3.1
  • Unity 2019.3.0f1
  • JetBrains Rider Editor 1.2.1
  • Test Framework 1.1.9

カバレッジ採取の準備

dotCoverプラグインカバレッジを採取するには、以下の準備が必要です。

1. Unityエディタを "Start Unity with Coverage" で起動する

RiderでUnityテストを実行するにはUnityエディタとのコネクトが必要ですが、dotCoverを使用するときには通常とは異なる方法でコネクトします。 Unityエディタは一旦閉じ、RiderのUnityツールバー左端にあるUnityロゴをクリックして "Start Unity with Coverage" で起動します。

f:id:nowsprinting:20200111201900p:plain

もしほかの方法で起動したUnityエディタとコネクトした状態でカバレッジを採取しようとすると、下図のアラートが表示されます*2

f:id:nowsprinting:20200111201903p:plain

2. 実行環境にEdit Modeを選択する

カバレッジの採取は、"Unit Tests"タブにあるプルダウンで"Unity Editor - Edit Mode"を選択した状態で実行する必要があります。

f:id:nowsprinting:20200111204832p:plain

つまり必然的に、Play Mode testsのカバレッジは採取できません。

カバレッジの採取

カバレッジは、以下の手順でテスト実行することで採取できます。

  1. Riderのエディタでテストコードを開き、テストメソッド定義にカーソルを置いて alt + enter*2 でContext Actionsメニューを表示します
  2. すると下図のように "Cover" が選択できますので、enterを押下すると当該メソッドが実行されます

f:id:nowsprinting:20200111202202p:plain

もしくは、Rider下部の"Unit Tests"ウィンドウにある"Explorer"タブでEdit Modeテストのアセンブリを選択し、左にある"Cover"アイコンをクリックすると、すべてのEdit Modeテストを実行できます*3

f:id:nowsprinting:20200111215057p:plain

Coverを実行すると、テスト実行結果が"Unit Tests"ウィンドウに表示されるほか、"Unit Tests Coverage"ウィンドウにステートメントカバレッジが表示されます。

カバレッジの見かた

"Unit Tests Coverage"ウィンドウでは、テスト対象のステートメント数と、テスト実行によって通過した/していないステートメント数、またその割合が確認できます。

f:id:nowsprinting:20200111201855p:plain

また、この状態でテスト対象ソースコードをエディタタブで開くと、通過した/していないステートメントを確認できます。 グリーンでマークされた行(下図16〜19, 25行目)は通過したステートメント、グレーでマークされた行(同22〜23行目)は通過していないステートメントです。

f:id:nowsprinting:20200111201857p:plain

ステートメントカバレッジの使いどころ

ステートメントカバレッジとは、ユニットテストによってテスト対象コードの全ステートメントのうち何%がテストされているかを示すメトリクスです。命令網羅、C0とも呼ばれます。

カバレッジ」には、ほかに、デシジョンカバレッジ、条件カバレッジなどが使われます。 上の例では19行目が通過していることしか確認できませんが、デシジョンカバレジを満たすには a == 0 のテストケースと、a != 0 かつ b == 0 のテストケースが必要です。

また、ステートメントが実行されたことは確認できますが、それが正しい実行結果であるかはアサーションで適切に判定されている必要があります。

以上の観点から、ステートメントカバレッジは品質の指標として信頼度の高いものとは言えず、あくまで「めやす」くらいにとどめるのが良いでしょう。

関連記事

www.nowsprinting.com

www.nowsprinting.com

関連書籍

IntelliJ IDEA パーフェクトガイド

IntelliJ IDEA パーフェクトガイド

仮面ライダーゼロワン 変身ベルト DXエイムズショットライザー

仮面ライダーゼロワン 変身ベルト DXエイムズショットライザー

  • 発売日: 2019/08/31
  • メディア: おもちゃ&ホビー

*1:Unity 2019.2以降パッケージ化された名称。詳しくは https://www.nowsprinting.com/entry/2019/09/28/132800 を参照

*2:Rider 2019.3.1から表示されるようになった模様

*3:Play Modeテストが存在しないのであれば、Tests > Cover All Tests from Solution でもすべてのテストを実行できます

JetBrains Rider 2019.3でUnityのPlay Mode testsを実行する

JetBrains製のC# IDEであるRiderの2019.3がリリースされました。 これまで、RiderからはUnity Test Framework*1のEdit Mode testsのみ直接実行することができましたが、2019.3からはPlay Mode testsも実行できるようになりました。

www.jetbrains.com

Unityテストの実行方法

基本的には、Edit ModeもPlay Modeも以下の手順で実行できます。

  1. Riderのエディタでテストコードを開き、テストメソッド定義にカーソルを置いて alt + enter*2 でContext Actionsメニューを表示します
  2. すると下図のように "Run" が選択できますので、enterを押下すると当該メソッドが実行されます

f:id:nowsprinting:20200110230813p:plain:w200

テスト実行結果は、Rider下部の"Unit Tests"ウィンドウに表示されます。

Unityテスト実行の前提条件

テストの実行はUnityエディタで行われるため、UnityエディタのプロセスとRiderとがコネクトされてる必要があります。

Unityエディタとのコネクトは、Rider右下に表示されているアイコンで判断できます。下図、右から3つめのUnityロゴ右下にグリーンの丸が表示されていればコネクトされています。

f:id:nowsprinting:20200110233055p:plain

UnityエディタからRiderを開いた場合はコネクトされた状態のはずです。Unityエディタを再起動したなどコネクトが切れた場合、Unityツールバーの左端にあるUnityロゴをクリックし、"Start Unity"で起動しなおすか、すでに起動しているプロセスに"Attach to Unity Process..."でコネクトできます。

f:id:nowsprinting:20200110233103p:plain

Play Mode testsの実行方法

Play Mode testsも、上記と同じ手順でテスト実行することができます。 ただし、"Unit Tests"ウィンドウにあるプルダウンで"Unity Editor - Play Mode"を選択した状態で実行する必要があります。

f:id:nowsprinting:20200110230824p:plain:w500

これを切り替えずに実行すると、上図のように"Inconclusive: Test not run"と表示され、テスト実行されませんので注意してください。

なお、逆に、Edit Mode testsを"Unity Editor - Play Mode"で実行しようとしても同様にテスト実行できません。"Unity Editor - Edit Mode"を選択した状態で実行する必要があります。

所感

Riderから直接Play Mode testsが実行できるようになったことは喜ばしいことです。 しかし、プルダウンでの切り替えが必要ですし、Play Mode testsの最大のメリットであるプレイヤー(iOSAndroidの実機など)での実行ができるわけではありません。 個人的には、引き続きEdit Mode testsを中心に書いていくのがよいと考えています。

Tips

デバッグ実行

Context Actionsメニューに表示される "Debug" を選択すると、テストをデバッグ実行することができます。 もちろん、ブレイクポイント、ステップ実行、変数のインスペクションなども使用できます。

アセットの自動リフレッシュを抑止する

Riderのデフォルト設定では、テスト実行の都度、Unityエディタでアセットのリフレッシュが実行されます。 特にTDD (Test Driven Development: テスト駆動開発) で開発を進める場合など、頻繁に待ち時間が発生してしまいますので、この設定をオフにすることもできます。

Preferences... > Languages & Frameworks > Unity Engine を開き、"Automatically refresh assets in Unity" チェックボックスをoffにします。

www.jetbrains.com

関連記事

www.nowsprinting.com

www.nowsprinting.com

関連書籍

IntelliJ IDEA パーフェクトガイド

IntelliJ IDEA パーフェクトガイド

*1:Unity 2019.2以降パッケージ化された名称。詳しくは https://www.nowsprinting.com/entry/2019/09/28/132800 を参照

*2:Mac OS X 10.5+ Keymapの場合

モブプロはまだ腰痛には効かないがそのうち効くようになる

この記事は、モブプログラミング Advent Calendar 2019の6日目の記事です。 タイトルでお察しの通り、ネタエントリです。

※この記事は個人の感想であり、効果・効能を示すものではありません

腰痛

腰痛の原因には個人差があります。私の場合は同じ姿勢で座りっぱなしで、腰の一部の筋肉にずっと負荷をかけ続けてしまうことだと言われていて、以下のような緩和対策をしています。

  • 椅子に後傾姿勢で座り、背もたれに負荷を分散させる
  • 適度に立ち上がって動かす

このうち、2番目についてはApple Watchの「スタンド」アクティビティが1時間ごとに立ち上がって歩くことを促してくれます。これは心臓疾患などのリスクを回避するためのものらしいのですが、私のケースでは腰痛の緩和にも寄与します。

ただし、アラートに従えばの話。興が乗ってるとチラッと見て無視しますよね…

モブプロ

そこでモブプロです!

ここを読んでいる皆さんは御存知の通り、モブプログラミング(モブワーク)では数分単位でドライバーを交代していきますので、強制的に席を替わるために立ち上がって少し移動しなければなりません。 またすぐ座って再開するものの、ちょっと身体を動かすきっかけには十分ですね。

とはいえ、ただちに「モブプロで腰痛緩和!」とまでは言えません。 席移動しないでモニターだけ切り替える形式だと席移動は発生しませんし、席移動のたびに集中を切らしていては効率が悪くなってしまいそう。うまくモブプロに腰痛対策を組み込んでいければいいなと思っています。

参考文献

WEB+DB PRESS Vol.102

WEB+DB PRESS Vol.102

  • 作者:
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/12/23
  • メディア: 単行本

.NET Conf in Tokyo 2019に行ってきました #dotnetconf #dotnetconfunity

日本マイクロソフトさんで行われた、.NET Conf in Tokyo 2019 に行ってきました。

vsuc.connpass.com

午後は2部屋に分かれたうちの Room B(Unityトラック)にずっといました。 Room C+D(.NETトラック)が気になる方はハッシュタグ #dotnetconfdotnet を参照。

以下、スライドは拾えたものだけ。Unityトラック分は近日中にUnity Learning Materialsで公開されるはずです。

What’s New in .NET Core 3.0 and Visual Studio 2019 for .NET developers

MicrosoftのSteve Carrollさん

サテライトの音声よくなかったこともあって*1ろくにメモできていません…

デモアプリ等はここに。

github.com

Clean Architecture for Unity

www.slideshare.net

  • @monry さん
  • Visual Studio Users Community Japan #1における@nuits_jpさんの『世界一わかりやすいClean Architecture』とかぶった
  • Clean Architecture(以下CA)とはなにか → そんなものはない
    • ざっくりとした指針は示されている
  • CAの図は、あくまで一例。押さえるべきポイントを押さえれば自ずとCAになる
  • SOLID原則とDI
    • SOLIDの元論文は2000年、Robert C. Martin氏
      • CA本の著者
      • その時点ではSOLIDという略称ではない
    • DI
      • DIPを実現するパターン
      • Zenject
        • Unityにおいては、MonoBehaviourに対するinjectが難しい
        • Installerで実体の作り方/探し方を定義
  • UnityにおけるCA
    • ざっくりした方針は2つだけ
      • 依存の向きは外から内のみ
      • 制御の流れは依存と切り離して考える
    • pros: 疎結合、テスタビリティ、慣れると可読性が高い
    • cons: interface/class多い(3-4倍+)、要IDEVSCodeでは厳しそうなレベル)、慣れるまで可読性低い
    • CAFU (Clean Architecture for Unity) を作って使っている(キッズスター社)
    • レイヤ定義
      • Application:
        • CAの文脈から外れる要素はここに置く。他から結構依存される
        • ValueObject
          • マスタデータ用の型、enum
          • 状態管理、transaction
        • Installer
          • ZenjectのInstaller
        • Signal
          • 抽象を用いないで制御を授受するための型。struct
          • UniRx.MessageBroker, Zenject.SignalBusとか
      • Domain: Entity, Use Case
        • Entity: 計算。Use Caseとのみ対話する
        • Use Case: Entityと対話。RepositoryやPresenterをつなぐ。Use Caseのみで完結可能な処理もある(Entity使わない)
      • Data: Repository, Datastore
        • Repository: Datastoreと対話。窓口。CRUDなインタフェース
        • DataStore: 実際に管理。メモリ、DB
      • Presentation: Presenter, View
        • Presenter: ユーザ対話の窓口、Viewと対話
        • View: ユーザとの対話。要するにUnity
    • 処理の起点はUse Caseに担わせるとよさげ
    • Zenject.IInitializable.Initialize()を実装させる
    • 状態をDataレイヤに取り扱わせる(Entityだとめんどくさかった)
    • 特にwriteはDataで行なう
    • Viewをいかに一般化するか。UniFlowを作っている

参考

Clean Architecture 達人に学ぶソフトウェアの構造と設計

Clean Architecture 達人に学ぶソフトウェアの構造と設計

booth.pm

MagicOnion〜C#でゲームサーバを開発しよう〜

www.slideshare.net

  • @toRisouP さん
  • サーバ: .NET Core, クライアント: Unity or .Net Core という構成
  • gRPCだが、データフォーマットはMessagePack for C#、protoc不要
  • 定義(C#コード)をクライアントとサーバのプロジェクトで共有
  • gRPCコネクションを張って、あとはasync/awaitでメソッドを呼ぶだけ
  • 実装できるAPI: Service, StreamingHub
    • StreamingHub: gRPCのBidirectional Streaming RPC
  • Filter: 通信の前後に処理を追加できる
    • フィルタメソッド定義して、フィルタ有効にしたいメソッドにAttributeつければok
    • 認証とかログとかエラー処理とか
  • Swagger, Telemetry対応
  • 環境構築はむつかしい
  • StreamingHub
    • クラサバ両方で状態を管理する必要があるので複雑になりがち
    • Receiver: サーバ → クライアント
    • Hub: クライアント → サーバ
    • MessagePackObjectを定義
      • サーバ側にMessagePack.UnityShimsを入れると、Vector3とか使えてべんり
    • Group: Hubを束ねる
    • Broadcast: いろいろある
  • 実装時の注意
    • クライアント
      • gRPCのコネクション管理ちゃんとしないとフリーズしたりする。Unmanaged
    • サーバ
      • .NETのServer GCを使うのおすすめ
      • ThreadPoolのサイズを上げる。デフォルト25なので
      • Generic Hostを使う
  • デプロイ
    • Docker, CircleCI, Kubernetesでコンテナ管理がよさげ
    • MagicOnionのサーバ構成
      • ステートフル: インメモリでデータを保持する、Groupはインスタンス縛り、リアルタイムに向く
        • Agonesに期待
      • ステートレス: Load Balanserに繋げばやってくれる。オートスケーリングできる
        • バックエンドにRedisが必要

Riderはいいぞ!

speakerdeck.com

  • @RyotaMurohoshi さん
  • Code Inspection
  • solution-wide analysis
    • preferencesで有効化。デフォルトはerrorのみ?
    • ディレクトリを指定できる
  • Quick Fix
    • 書いているソースだけでなくプロジェクト全体とか特定範囲とかもできる
  • Code Vision
    • Find Unity Usage
  • Live Template
    • preferencesで設定
    • 自分でも登録できる
  • File Template
  • Code Generation
    • MonoBehaviourのメソッドを作ってくれる: Unity Event Functions
  • Performance Indicators: Update()から呼ばれてるメソッドで非効率なコードを書くと怒られる
  • Unity連携、デバッガ*3
  • おすすめショートカット
    • alt + enter : Quick Action*4
    • shift + command + A : Find Action
    • shift + shift : Search
  • チュートリアルがある*5

参考

[.NET/Unity開発者向け] JetBrains .NET Meetup Tokyo #JBRiderTokyo - JetBrains | Doorkeeper におけるJetBrains社のKirill Skryganさんのセッション動画

www.youtube.com www.youtube.com

書籍

IntelliJ IDEA パーフェクトガイド

IntelliJ IDEA パーフェクトガイド

C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜

learning.unity3d.jp

  • Unity 安原さん、名雪さん
  • 以前: C# → IL → Mono(AOT/JIT) → 機械語
  • IL2CPP*6: C# → IL → C++機械語
  • Burst: C# → IL →(Burst)→ IR*7 →(LLVM)→ 機械語
  • なぜBurstが速いのか
    • LLVMがIRをすごい最適化する
      • IL2CPPは互換性重視、インライン展開されにくいなど
    • SIMD*8を使う
      • SSE (Intel), NEON (ARM)
      • プラットフォームによって対応情報は違う。SSE2, SSE4とか
    • メモリエイリアス
      • memcpy()もベクタライズ
      • srcとdstの範囲が重なっている可能性 → 結果が変わってしまう → ビルドエラーが出てくれる
  • 制約
    • C# Job Systemのみ
    • クラスなど参照型が使えない → struct, NativeArray, NativeString
    • 例外処理できない。throwは使える
  • 実演
    • DOTSのプロファイリングはPlayerビルドしてプロファイラつないで見る
    • 25ms → 3msに高速化
  • メニューの Jobs > Burst : エディタ実行するとき設定
    • Enable Compilation
    • Safety Checks
  • Project Settings > Burst AOT Settings : Playerビルドするときはこちらの設定が使われるので注意
  • メニューの Jobs > Burst > Open Inspector...
    • "Refresh Disassembly"をクリックすると表示される
    • このウィンドウ用にコンパイルされるので、"Safty Checks"トグルとかもここだけに影響する(上記2つの設定とはまた別)
    • "Enhanced Disassembly"をonにすると、コメントとしてC#コードが出てくれるはず
  • float4を使うコードに書き換えるなどしないと勝手にベクタライズはされにくい。やっても早くなるとは限らない。LLVMだけでも十分速くなるはず
  • 機種間deterministic
    • 単精度のadd, sub, mul, div, sqrtは保証されている。すごい
  • Unity.Burst.Intrinsics
    • public static m128 load_ps_128(void* ptr) とか

所感

いずれのセッションも濃い話でたいへん勉強になりました。 はじめ、Unity側は(中途半端には)知っている話もあるし.NET側に行こうかとも考えたのですが、Unity側で正解でした。 Burstコンパイラ完全に理解した。

お土産にいただいたピンバッジ。かわいい。C#ステッカーもかわいい。

f:id:nowsprinting:20191027202108j:plain:w300

*1:最初C+Dに入ったのですがどうせ午後Bだからと移動して、そのまま居着いてしまった

*2:作者の@neueccさんのお言葉: https://twitter.com/neuecc/status/1188329065318498305, https://twitter.com/neuecc/status/1188330470515208193

*3:ちなみにEdit Mode testsもデバッガで実行できます。べんり!

*4:ちなみにテストメソッドにフォーカスした状態ではRunとDebugが出てきます。べんり!

*5:Riderのスプラッシュ画面右下のGet Help > Tutorials...

*6:WebGLで動かすためにハックウィークで作ってみたのが発端とか。後になって速度面とかiOSの64bit対応問題でメインストリームになったと

*7:Intermediate Representation: 中間表現

*8:Single Instruction Multiple Data: しむど

UWA GOTでUnityアプリのプロファイリング(Android編)

UWA*1 GOT*2は、Unityアプリのプロファイリングを行なう商用ツールです。 CEDEC 2019のセッション『あなたのモバイルゲーム開発の最適化時間を数ヶ月節約する方法』で紹介されました。

セッション後にUWAのブースやメール*3で問い合わせた内容も含め、簡単な使い方をまとめます。

jp.uwa4d.com

UWA GOTは、Unity 4.6以降で使用できます。ただし、後述のUWA GOT オンラインを利用する場合は、Unity 5.6以上が推奨とのこと。

プロファイリング対象プラットフォームは、CEDEC 2019時点のv2.0.0ではAndroid (Mono)とWindows (Mono)でしたが、最近リリースされたv2.0.1でiOS (IL2CPP)も対象となりました*4

プロファイリングは、以下の流れで行ないます。

  1. プラグインを組み込んでビルドしたアプリを端末にインストール
  2. アプリを実行・計測し、別の専用アプリでデータをプロファイラ(ローカルとオンラインの2種類から選択できます)に送信
  3. プロファイラで測定データを表示し、性能ボトルネックを調査

計測をアプリ単体で行なうことができるため、テスター・デバッガの手で実行することができます。反面、現状どうしても手作業が必要になるため、デバイスファーム等で大量の自動テストを実行しながらプロファイリングを行なうようなユースケースには向きません*5

UWA GOTの構成

構成要素がいくつかありますので、先に説明します。

GOT SDK

UWA GOT公式サイトからダウンロードできます。プラットフォームごとにunitypackageが分かれており、いずれかをインポートします。内容は以下。

  • GOT Editor: Unityエディタ拡張。2つの機能を持っています
    • 対象アプリへのGOTプラグインのインテグレーションサポート
    • ローカルサーバ機能
  • GOT プラグイン: 各プラットフォーム向けのプラグイン
  • ドキュメント: 少々古いものなので、ドキュメントは公式サイトからダウンロードできる日本語版を参照

GOT App

計測結果をプロファイラ(ビューア)にアップロードするためのアプリで、Android版とWindows版がzipに同梱されています。計測対象アプリとともに端末にインストールする必要があります。

iOSではプラグインにデータ送信機能が備わっているため、GOT Appは必要ありません。

GOT ローカルサーバ(ローカルテストツール)

Unityエディタ上で動作します。アプリで計測したプロファイリングデータを受信し、表示を行なうビューアです。

GOT オンライン

オンラインでプロファイリング表示を行なうサービスです。 ローカルサーバでのプロファイリング表示に比べ、表示できる項目が多く、また他のアプリの実測値をもとにしたサジェスト機能もあります。

料金体系

ローカルサーバは、使用するマシン1台ごとに¥11,500/年。15日間のトライアルが可能です。

オンラインは、計測データをアップロードできる時間(アプリの実行時間)に対する課金で、¥5,000/時間。 トライアルはありませんが、公式サイトでデモデータを閲覧できます*6

プラグインを組み込むアプリ数、アプリをインストールする端末数、計測回数および時間に制限はありません。

利用手順

まず、UWAのWebサイトで ログイン > 新規登録 から、新規ユーザ登録を行ないます。確認メールが届くまで数分かかります。 ログインできたら、ダウンロードページからSDKと日本語マニュアルをダウンロードできます。

以下、マニュアルを参照してください。以下、わかりにくいところだけ説明します。

SDKインテグレーション

  • ライセンスキーは購入*7後、Webサイト右上のアイコン > アカウント設定 > アカウントの残額 ページの「購入済ライセンス」に表示されます。メールで送られたりしませんのでご注意ください
  • アカウントの残額 ページでは、ライセンスと開発マシンの紐付けを解除して別のマシンに付け替えることも可能です。解除しようとすると「以下のライセンスとアカウントの紐付き関係を解除しますが、操作の取り消しできないため、継続しますか?」というメッセージが表示されますが、オンライン認証であれば特に制限なく解除・付け替え可能とのことです
  • UWA/Prefabs/UWA_AndroidもしくはUWA_IOSを最初に開くSceneのヒエラルキに追加するように書かれていますが、APIでも初期化が可能です。[RuntimeInitializeOnLoadMethod]アトリビュートを付けたメソッドからUWAEngine.StaticInit()を呼び出せば実現できます。APIについてはマニュアルの付録に記載があります
  • GOT Editor > "SDK インテグレーション" > "Build here"でビルドできますが、前提条件を満たしていれば普通にPlayerのビルドを行ってもUWA GOTが組み込まれたビルドとなります
  • ビルドに何らかの原因で失敗しても特にダイアログ等が出るわけではないので、コンソールを見る必要があります
  • UnityエディタのPlayモードではプロファイリングは実行できません
  • デフォルトのビルド出力先UWA_Builds/と、プロファイルデータ格納先TestData/をバージョン管理のトラッキングから外しておくのがいいでしょう
  • Androidでは、デバイスのファイルアクセスを許可する必要があります。v2.0.1ではアプリ起動時にダイアログが出ますが、v2.0.0では設定画面かadbコマンドで許可する必要があります

計測

UWA GOTをバンドルしたアプリを起動すると、下図のGUIがオーバーレイされます。

f:id:nowsprinting:20191025071100p:plain

"Overview", "Mono", "Assets"いずれかをタップすると計測がはじまります。ボタンによって採取できるプロファイルが異なります(後述)。

"Direct Mode"は、onにするとアプリが終了し、再起動するところから計測を開始できます。offのときは、"Overview", "Mono", "Assets"いずれかをタップしたタイミングで計測を開始します。

計測が開始されると"Stop"ボタンが表示されるので、一通り動作させたらこれをタップして計測を終了します。 一度計測を行ったら、アプリを再起動しなければ次の(他の)計測はできません*8

計測データのアップロード

計測データは端末に保存されますので、UWA GOT Appを起動してアップロードします。

f:id:nowsprinting:20191025071124p:plain:w400

"UWAローカルサーバ"は、Unityエディタ上でGOT Editorを開き、"WIFI"ボタンをクリックすると起動します(IPアドレスが表示されます)。 ローカルサーバを起動した状態でGOT AppにIPアドレスを入力(ポート番号は不要)し、"チェックする"をタップします。問題なければ左のマークが緑色になります。

"自分のデータ"の下に計測したデータが並びますので、アップロード先の"Online"もしくは"Local Server"をタップ、最後に"データ提出"をタップするとアップロードできます。

なお、ローカルサーバに上げたデータをGOT Editorからオンラインにアップロードすることもできます。

計測データの表示

GOT Editorの"Overview", "Mono", "Assets"いずれかをクリックするとウィンドウが開くので、右上の"バージョン"でアップロードした計測データを選択します。

f:id:nowsprinting:20191025071430p:plain:w400

f:id:nowsprinting:20191025073622p:plain:w400

"Overview"では、"ファンクション"でCPU, FPS, MonoHeap, Hardware, markerを切り替えて表示できます。

それぞれの数値のグラフ表示、選択した場所(上図の赤い縦線のところ)のスクリーンショット*9、また、メソッド単位でヒープ使用量やオブジェクトカウントの表示*10などが便利な点です。

また、オンライン版では、DrawCall*11Canvas Batching*12なども表示できます。

*1:ゆーわ: 会社名

*2:ごーと: Game Optimization Toolkitの略

*3:UWA Technologiesは中国の会社ですが、日本に代理店があるので日本語で質問できます

*4:AndroidWindowsは引き続きMonoのみですが、近日中にIL2CPP対応されるとのこと

*5:大量のプロファイリングを行ないたい場合は、同じくCEDEC 2019のセッション『Android向けUnity製ゲーム最適化のためのCI/CDと連携した自動プロファイリングシステム』の方式が向いていそうです

*6:プロジェクト > Overview等 > デモプロジェクトを選択。オペレーション列の[確認]クリックで詳細を見ることができます

*7:PayPalで購入できます

*8:改善要望はしており、修正予定はあるそうです

*9:30fpsで撮られていますが、アプリ実行に遅延を感じること無く高速に撮影されているようです

*10:数値は10フレームごとの最大値を出しているそうです

*11:Overview > レンダリングモジュール

*12:Overview > UIモジュール