XXXManager という名前は本当に良くない

XXXManager という名前は良くない。ということは、僕が言うまでもなく過去にたくさんの人が指摘しています。

『名前が漠然としているから』と言うのが大きな理由なのですが、実際に開発をしていると、この手の役割をクラスを作りたくなることは多く、それにどう名前をつけるか毎度考えあぐねるのですが、簡単に考えをまとめておきます。

なぜ管理クラスを作るのか

そもそも、XXXが何か処理を行うときは自身がその処理を行えばいいのです。

xxx.doSomething();

しかし、時としてそれを直接呼びたくないケースがあります。その多くは、メソッドを呼ぶときに、他のオブジェクトとの相互作用が発生するようなケースです。

実際のところ、管理クラスは何であるのか

XXXManager が複数の XXX を管理する場合、管理する XXX をメンバとして所有するのですから、単にそれを表すクラスにすればいいのです。

XXXCluster
XXXs
XXXQueue

XXXManager はこの形の改名で解決することが多い気がします。もっと別の理由で管理クラスを挟みたいケースでは、用途に応じた命名をすればいいと思います。もし、そのどちらにも当てはまらないなら、そもそもそのクラスが本当に必要なのか検討するべきです。

Electron でファイルを保存するパターン

意外と簡単に書けるので、面倒くさがらずに書くとすぐです。

レンダラ側

document.getElementById('saveButton').addEventListener('click', () => {
  ipcRenderer.send('save-state', JSON.stringify(state));
});

メイン側

ipcMain.on('save-state', (event, stateString) => {
  const defaultPath = 'my-data.json';
  dialog.showSaveDialog(
    {
      defaultPath,
      properties: {
        multiSelections: false,
      },
    },
    filePath => {
      if (filePath == null) {
        return;
      }
      fs.writeFileSync(filePath, stateString);
    },
  );
});

開くときもだいたい同じ

最小の Unity プロジェクト

Unity はプロジェクトを構成する要素が意外と少ないです。そもそも中核となるプロジェクトファイルのようなものがない。

Unity 2017 では、新規プロジェクトを作成すると次のようなディレクトリが作成されます。

├Assets/
├Library/
│└いろんなふぁいる
├ProjectSettings/
│└いろんなふぁいる
├UnityPackageManager/
└ProjectName.sln

Assets/ にはモデルやテクスチャ、音源やスクリプト、具体的なシーンデータといった、実際にアプリケーション内で利用するファイルが入ります。Library/ はキャッシュ的な何かが入るらしいです。これはコミットしない。ProjectSettings/ はビルドやグラフィック設定、Unityのバージョンなど、ゲーム全体の設定に関するファイルが入ります。UnityPackageManager/ はよく知らないけど、パッケージ用のなにかでしょ(適当)ProjectName.sln は VisualStudio 用のファイルですね。

ここから Unity Editor がプロジェクトであることを認識する最小構成までファイルを減らすとこうなります。

├Assets(空ディレクトリ)/
└ProjectSettings/
 └ProjectSettings.asset

なんとたったこれだけで Unity プロジェクトであると認識してくれます。

Unity の MonoBehaviour と Coroutine

やってみて当たり前だと気づいたのですが、StartCoroutine を使うには、MonoBehaviour を継承している必要があります。

つまり、これはダメ

public class MyAwesomeClass {
  void BestMethodEver() {
    StartCoroutine(SomeCoroutine());
  }
}

どうしても使いたかったら、ちゃんと MonoBehaviour を継承するか、

public class MyAwesomeClass : MonoBehaviour {
  void BestMethodEver() {
    StartCoroutine(SomeCoroutine());
  }
}

StartCoroutine を呼ぶ依代を探します。

public class MyAwesomeClass {
  void BestMethodEver() {
    Yorishiro yorishiro = GameObject.Find("Yorishiro").GetComponent<Yorishiro>();
    yorishiro.StartCoroutine(SomeCoroutine());
  }
}

Unity は、シングルスレッドでの動作が基本で、Coroutine もシングルスレッドで動作します(ちょうど、Node のような感じ)。StartCoroutine で呼び出せば、ちゃんとゲームループと同じメインスレッドで動いてくれるので、自分で Coroutine を実装するよりは、↑のような方法で解決するほうが良さそうです。

Unity のスクリプトの実行順を設定する。

Unity では、MonoBehaviour に設定した Update や LateUpdate は順不同で呼び出される。

これらの順番は、メニューの [Edit] → [Project Settings] → [Script Execution Order] を開き、各スクリプトの優先順位を数値で指定することで、制御することが出来る。 ただし、同じクラスのインスタンス同士の実行順は制御できないので、その場合は管理するためのクラスなどを用意する必要がある。

Script Execution Order は、各スクリプトの meta ファイルに保存されるため、パッケージの Export などをしても引き継ぐことが出来る。

Google Apps Script とロック

恐ろしいことに Google Apps Script(以降 GAS)は並列で実行される。普段 JS を書いていると意識しないが、並列実行ほどプログラムにおいて恐ろしいものはない。

ロックは、以下のような関数で取得できる。

var documentLock = LockService.getDocumentLock();

最大で10秒間待って、ロックを取得するには以下のようなコードを書く。

if (documentLock.tryLock(10000)) {
  // ロックを取得したときの処理
}

取得したロックを解除するには次の関数を呼ぶ。

documentLock.releaseLock();

シートを編集するような処理を書く場合、そもそもロックしなくて良いケースなどレアなので、次のようなコードを脳死で書いておけばいいと思いました。

var documentLock = LockService.getDocumentLock();

if (documentLock.tryLock(10000)) {
  try {
    main();
  } finally {
    documentLock.releaseLock();
  }
} else {
  console.log("failed to aquire lock.");
}

Unity の meta ファイルと guid

本日は Unity のパッケージ読み込みで一日を潰してしまいました。 Unity のプロジェクト上で扱われるリソースは Asset と呼ばれ、 実ファイルと meta ファイルの組で管理されます。

meta ファイルは実ファイルに付加的な情報を与えるものです。 guid やインスペクタで設定するような情報(リグとか)を実ファイルを編集することなく修正することができ、かしこいです。

guid は同一のファイルを識別するために利用されており、 Unity の project 内でファイルを移動しても参照が外れないのはこの仕組のおかげです。

一方で、パッケージを読み込むときなどは、この guid が悪さをすることもあり、 素直に上書きしてほしいのに、guid とバージョニングの問題で上書きしてくれなかったりする。

正直不便なことの方が多い気もする。 git でプロジェクトを管理していると、バージョニングが二重になる。