カヤック独自の職能? リエゾンについて

ソーシャルゲーム事業部でリエゾンをしている飛鷹と言います。
自己紹介で早速出てくるリエゾンというワードですが、今日はこのリエゾンというものの紹介をさせてください。

リエゾンとは

チームによりリエゾンのカバーする範囲は異なりますが、基本的にはプロジェクトマネージャー(以下PM)に近い存在です。
ですがPMとあえて別の呼称をしているのは、弊社ではゲームタイトルには利益を最大限化するプロデューサーがいて、ゲームの面白さを追求するディレクターがいます。
本来PMがカバーしている範囲とプロデューサーやディレクターのカバーしている範囲と被ることがあり、そこを最適化しようとして生まれたのがリエゾンです。

あまり一般的ではないリエゾンと呼称ですが、リエゾンとは 仲介役連絡係 という意のフランス語です。
ググったら少し出てきましたが、恐らく一番世間的に認知されているのがシン・ゴジラで 警視庁リエゾン というゼッケンを付けた人がいてリエゾンってなんだ?ってなった時でしょうか(?)
弊社では2016年の5月頃から社内で使われはじめました。

ブログタイトルで カヤック独自の職能? と注意を引く感じに書いていますが、実際に他社さんでリエゾンという言葉を使っている事例を知りません。
他社さん社内で同様の仕事をしている人がいれば、その呼称を教えて欲しいです。

発生の経緯

若干齟齬もありますし過去の言葉になりつつありますが、分かりやすいのでヒト、モノ、カネで紹介します。
PMであればチーム内のヒト、モノ、カネ全てを担いますが、プロデューサー/ディレクター/リエゾンがチーム内にいれば、ヒトをリエゾンが担い、モノをディレクターが担い、カネをプロデューサーが担います。

10人くらいのチームではPMだけでPMの仕事を全て担えそうですが、最近のソーシャルゲームは大規模化でメンバーが40人や50人を超えるのはざらにあります。
また分業や専門化や市場の成熟もあり、プロデュース業やディレクション業も数年前よりとても深い知識が要求されるようになりました。
そこをプロジェクトマネジメントを学んできた人だけで担うことはできません。
そのためプロデューサー、ディレクター、リエゾンで得意分野を活かしつつ3役に別々の権力を持たせ協議し協調してプロジェクトに関わるようにしています。
日本国憲法での三権分立と似たような考え方ですね。

ねらい

どこの会社もどこのチームもプロダクトの売上を最大化して利益をだすことを目標にしていると思います。
プロデューサーもディレクターもリエゾンも最終的には売上の最大化という同じ目標を持っています。
売上を出すという目標ですが、その中でリエゾンはヒトを使い最大化を目指します。
働きやすい環境を提供し、ワークフローをシンプルでストレスのないものにし、チームビルディングを行いチームに貢献します。

役割の分割

本来1人のPMが担うところを常に3人で協議しているのでは無駄な時間を過ごしがちです。
そこで予め役割を決めておくことが必要になります。

言葉がぶれてしまうと分かりにくのでプロジェクトマネジメントの国際標準であるPMBOK内の言葉で説明します。
PMBOKでPMの知識エリアとして提示されているのが、統合スコープスケジュールコスト品質資源コミュニケーションリスク調達ステークホルダ の10種のマネジメントがあります。
チームや人によって役割が異なりますが、この10個の中でリエゾンが主に担当するのが以下です。

  • スケジュール
  • 資源
  • コミュニケーション
  • リスク

ざっくり言うと人まわりとスケジュールまわりのマネージがメインになっています。

また、物事を決めていくプロデューサーやディレクターと実際に手を動かすメンバーとの意識のズレは良く発生します。
プロデューサーやディレクターはMTGで離席していることも多くチームのメンバーとのコミュニケーションが満足にいかない場合もあります。
こういったメンバーとプロデューサーやディレクターを繋いだり、メンバー同士のコミュニケーションを円滑にするのがリエゾンという言葉の由来である「仲介役」、「連絡係」に繋がります。

リエゾンの面白さ

エンジニアが自分で考えた設計がそのままシュッと実装できて、レビューでも問題なく、本番でも不具合がないというのが気持ちいいように、リエゾンでも気持ちのいい瞬間や面白いところがあります。

問題のある職能間に入りいい感じのワークフローが作り直せたとか、効率の悪そうな仕事をしていたらこういうツールやこの人に教えてもらえばもっと早くなるかもよと提案できたりとか、決めていたスケジュールにドンピシャで着地できたとか...
人的資源やスケジュールを扱うので自分がした行動が数字に出てきやすいです。
KPI的な数字やコミュニケーションや効率化が好きな人は向いている仕事だと思います。

さいごに

あれエンジニアリング要素あったか?ここは技術ブログでは???と思った方、正解です。技術ブログです。
エンジニアリング要素なかったですが、自分も元はサーバーサイドエンジニアでした。
リエゾンになった今でもたまにテストの補強とか期限のないタスクでコード書いたりしています。
リエゾンでもGASが書けたり、必要なスクリプトをさっとかけたり、新しいツールをすぐ使いこなせると少し強みになりますね。
けれど古い知識でエンジニアにオラオラ言うようなマネージャーみたいにはならないようにしたいですね。

さて、明日は@suzukunによる「regl入門」です。

【Unity】LINQのパフォーマンス検証

はじめに

はじめまして、2年目Unityエンジニアの大谷です。
この記事はカヤックUnityアドベントカレンダー2018の20日目の記事になります。
今回はUnityでLINQのパフォーマンスの比較をしてみました。

経緯

今回アドベントカレンダーを書いてみないかと勧められたものの、
僕はアドベントカレンダー初心者だったのでネタ探しに困っていました。
そんな中、LINQのパフォーマンス検証してみたら?
と、どこからかお告げを頂いたのでやってみることにしました。(圧倒的感謝...)

検証

今回検証するのは、LINQでよく使いそうなWhere(要素を絞り込む)、Select(全要素に対して処理)、OrderBy(並べ替え)
の3つにしてみました。比較するのは、それらの処理をforeachに置き換えたものにします。
また、LINQで操作した要素をList型に変換するToList()を使用するとパフォーマンスに大きく影響がでるらしいので、
そちらも別物として比較対象に追加します。まとめると、検証する対象になるのは

1. LINQ(IEnumerable型)
2. foreach(List型)
3. LINQ(List型)

の3つです。
検証用のサンプルコード(LinqTest.cs)はこちらになります。
Unityを用いた検証なので、Unity上で動作するようにします。

LinqTest.cs

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;

public class LinqTest : MonoBehaviour {

    void Update()
    {
        CompareSpeed();
    }

    void CompareSpeed()
    {
        var range1 = Enumerable.Range(1, 10000);
        var range2 = Enumerable.Range(1, 10000);
        var range3 = Enumerable.Range(1, 10000);

        Profiler.BeginSample("foreach処理");

        var list1 = new List<int>();

        foreach (var x in range1)
        {
            if (x % 2 == 0)
            {
                list1.Add(x * -10);
            }
        }

        list1.Sort();

        Profiler.EndSample();


        Profiler.BeginSample("LINQ処理");

        var list2 = range2.Where(x => x % 2 == 0)
                          .Select(x => x * -10)
                          .OrderBy(x => x);
        
        foreach (var x in list2)
        {
            // クエリを実行させる
        }

        Profiler.EndSample();


        Profiler.BeginSample("LINQ処理(ToList)");

        var list3 = range3.Where(x => x % 2 == 0)
                          .Select(x => x * -10)
                          .OrderBy(x => x)
                          .ToList();

        Profiler.EndSample();
    }
}

コードの補足

計測範囲はProfilerのSampleメソッドで囲まれているところになります。(Profiler.BeginSample(" ")とProfiler.EndSample()の間)。
このようにすると、指定した名称でUnityエディタのProfilerに表示されるようになり、その間の処理速度やGC Allocなどが見られます。ちなみに command + 7 でウィンドウが開きます。

where()やselect()を書いた段階ではクエリの式のみ保持されており、要素に対する処理はまだ行われていません。
なので、クエリの実行をさせる必要があります。LINQのクエリ実行タイミングは

1. foreachによるループ処理をする時
2. Single Maxなど一つの値を得る時
3. ToListなどで列挙する時

のようなので、foreachを回してクエリを実行させている部分があります。
では実際にUnityエディタのProfilerで結果を見てみましょう。

結果

Profilerをみてみるとこんな感じになりました。

editor

  LINQ LINQ(ToList) foreach
速度 5.8〜6.6ms 5.7〜6.5ms 2.4〜3.2ms
GC 123.4KB 187.8KB 64.4KB

CPU: foreach > LINQ(ToList) ≒ LINQ
メモリ: foreach > LINQ > LINQ(ToList)


の順でパフォーマンスが良さそうです。
速度に関しては、要素数を10000にしてようやくLINQとforeachの差が3.3〜3.4ms程になりました。
メモリに関しては、LINQ(ToList)は foreachの約3倍のGCを消費していました。
この差は実機でも変わらないのでしょうか?

ということで、実機だとどれほど違いが出るのか、iOSとAndroid端末で追加検証を行なっていきます。

実機で検証してみる

検証端末は、手元にあるiPhone8とXperia Z5 Compactを使用します。
実機でのプロファイリング方法はUnityの公式ドキュメントを参考にしました。今回はWiFiプロファイリングを行います。

iOS

1. iOS デバイスを WiFi ネットワークに接続  
2. UnityのBuild Settings ダイアログで"Development Build"と“Autoconnect Profiler” にチェック  
3. ケーブル経由で Mac にデバイスを接続し,Unity エディタで “Build & Run” をクリック  
4. デバイスでアプリが起動した後,Unity エディタで Profiler ウィンドウを開く  
5. 自動で接続されない場合は、ProfilerウィンドウのActive Profilerから接続されている端末を選択

Android

1. Androidデバイスで モバイルデータ通信 を無効化  
2. Android デバイスを WiFi ネットワークに接続  
3. UnityのBuild Settings ダイアログで"Development Build"と“Autoconnect Profiler” にチェック  
4. ケーブル経由で Mac/PC にデバイスを接続し,Unity エディタで “Build & Run” をクリック  
5. デバイスでアプリが起動した後,Unity エディタで Profiler ウィンドウを開く  
6. 自動で接続されない場合は、ProfilerウィンドウのActive Profilerから接続されている端末を選択

それぞれの結果はこちらです。

iPhone8

iphone 8

  LINQ LINQ(ToList) foreach
速度 4.9〜5.9ms 4.0〜5.3ms 1.9〜2.6ms
GC 123.4KB 187.8KB 64.4KB

CPU: foreach > LINQ(ToList) > LINQ
メモリ: foreach > LINQ > LINQ(ToList)

Xperia Z5 compact

xperia

  LINQ LINQ(ToList) foreach
速度 5.2〜5.6ms 5.0〜5.6ms 2.8〜3.3ms
GC 123.0KB 187.2KB 64.2KB

CPU: foreach > LINQ(ToList) ≒ LINQ
メモリ: foreach > LINQ > LINQ(ToList)


エディターと比較すると、
iPhone8ではLINQとforeachの差が3.0〜3.3ms程であまり変化はありませんでした。
一方、Xperia Z5 compactではLINQとforeachの差が2.3〜2.4msになり1msほど差が縮みました。
GCに関してはAndroidだとそれぞれ消費が若干少なくなりました。
これはAndroidのみ64bitではなく32bit版で動かしていることが原因のようです。
実際にAndroidを64bitで動かすとiOSと同じGC Alloc になりました。
数値にばらつきはあるものの、実機で改めて検証した甲斐があったのではないでしょうか。

LINQ自体はやはりクエリを実行するとエディター・実機関わらず処理が重くなったり大量にGCを消費してしまうようです。
使い分けるとすれば、
Updateなどで毎フレームに近く処理されるなら速度優先でforeach、
LINQを利用する場合はトレードオフを考えながら注意してから使う、
とするのが良さそうです。

LINQはforeachでの処理と比べて、簡潔にかけたり、どんな処理をしているのかが分かりやすくなる
などのメリットも多いので上手く使い分けられるようになれば取り入れていきたいですね。

おわりに

というわけでLINQのパフォーマンス検証でした。
明日は額田さんの「日本語テキストの自動改行」についての記事になります。
最後まで見ていただきありがとうございました。