🙊

Rx部品の命名案

2024/12/12に公開

はじめに

以前、下記記事にイベントハンドラの命名案を記載しました。

https://zenn.dev/lilytechlab/articles/ba599338ce469b

RxはC#のevent構文の上位互換と言われています。
では、同じ解釈を適用する場合、Rxの IObservable 等の部品の命名パターンはどのように構築すれば良いのか考えてみます。

今回の内容は下記記事に記載したRxの解釈に基づいたものとなります。

https://zenn.dev/lilytechlab/articles/96d5c913e267ea

Rx全般に適用可能だと思いますが、ここではUniRxのみを検討範囲とします。

クラス別命名案

以下の形で整理できるのではないかと考えました。

Subject

Subject という型の名前自体は、恐らく「主題」という意味で使用しているのではないかと思います。
Observer と繋がるように「観測テーマ」と意訳しても良いと思います。
イベントを発火させる役割で利用する場合は、 Subject はイベントのフィールドの置き換えとなります。

イベント構文でのフィールド宣言部分
private EventHandler eventHandler;
Rxでのフィールド宣言部分
private readonly Subject<Unit> eventHandler = new Subject<Unit>();

このため、イベントハンドラと同じ命名方法が使えそうです。

イベントハンドラの命名例
public class Enemy
{
    public event EventHandler OnDead;
}
イベントハンドラの命名例をSubjectに適用
public class Enemy
{
    private readonly Subject<Unit> onDead  = new Subject<Unit>();
}

Observable

event構文を置き換える場合、Observable はイベントプロパティを置き換える部分となります。

イベント構文でのイベントプロパティ
private EventHandler eventHandler;
public event EventHandler EventHandler 
{
    add { this.eventHandler += value; }
    // removeの方は検討範囲外なので省略
}
RxでのObservable公開部分
private readonly Subject<Unit> eventHandler = new Subject<Unit>();
public IObservable<Unit> EventHandler => this.eventHandler;

このため、こちらもイベントハンドラ名と同じ命名方法でいけそうです。

イベントハンドラの命名例
public class Enemy
{
    public event EventHandler OnDead;
}
イベントハンドラの命名例をObservableに適用
public class Enemy
{
    private readonly Subject<Unit> onDead  = new Subject<Unit>();
    public IObservable<Unit> OnDead => this.onDead;
}

Observer

Observer そのものについては、インスタンスに名前を付けて保持することがまずないので、検討対象外とします。

Observer に登録する、イベント発火時に呼び出すメソッドの登録処理は以下のように置き換わります。

イベント構文でのイベント購読処理
this.EventHandler += this.OnFired();
RxでのObservable購読処理
this.EventHandler.Subscribe(_ => this.OnFired());

このため、こちらはイベントハンドラのメソッド名と同じ考え方が使えそうです。

イベントハンドラのメソッド名の命名例
public class Enemy
{
    public event EventHandler OnDead;
}

public class Player
{
    public void StartBattle(Enemy enemy)
    {
        enemy.OnDead += this.OnEnemyDead;
    }
}
イベントハンドラのメソッド名の命名例をObserverに登録するメソッドに適用
public class Enemy
{
    public IObservable<Unit> OnDead { get; }
}

public class Player
{
    public void StartBattle(Enemy enemy)
    {
        enemy.OnDead.Subscribe(_ => this.OnEnemyDead());
    }
}

例文で検証

上記の考え方で書いたプログラムが「英語の自然言語に近いプログラム」となり得るのかどうか、例文を作って検証してみます。

Rx命名案検証用の例文
public class Enemy
{
    // (1)
    private readonly Subject<Unit> onDead = new();
    
    public IObservable<Unit> OnDead => onDead;
    
    public void Die()  
    {
        // (2)
        this.onDead.OnNext(Unit.Default);
    }
}

public class Player
{
    public void SratBattle(Enemy enemy)
    {
        // (3)                 (4)
        enemy.OnDead.Subscribe(onNext: _ => this.OnEnemyDead());
    }

    private void OnEnemyDead()
    {
        // 敵死亡時の処理
    }
}

(1)〜(4)それぞれのコードを英文になるように組み立て、翻訳サイトDeepLで翻訳して意味の通る日本語となるか検証します。

(1) Subject<Unit> onDead

まずは(1)の部分を英文にしてみます。

RxをPub/Subパターンで捉えてみるの解釈では、 Subject のインスタンス生成は、 Subject の内部 ObserverSubject 利用クラスを観測開始することを意味するのでした。
この役割を示すような英文を考えると、以下のようになりました。

A subject of onDead is messages published on the enemy’s being dead.
→onDeadの観測テーマは、敵が死んだことで発行されるメッセージです。

翻訳サイトの翻訳結果から、 Subject の部分のみ「観測テーマ」に変更しています。

onDead から創造されたとは思えない程長くなってしまっていますが、以下の部分以外はボイラープレートです。

  • onDead - フィールド名
  • enemy - クラス名
  • being dead - イベント発火タイミング

(2) onDead.OnNext()

続いて(2)の方です。
自然な文となるように、 onDead(Subject)をJohnとします。

John, do the process for on next message's having been published. 
→ジョンさん、次のメッセージが公開された時の処理をしてください。

OnNext() は、上記の文章の中で一番重要な部分のみを抜き出しているという考えです。

(3) enemy.OnDead.Subscribe()

enemy.OnDeadSubscribe() に分解して考えます。

enemy.OnDead

RxをPub/Subパターンで捉えてみるの解釈では Observable はBrokerとなるので、それを説明する文を作りました。

An observable one called OnDead is a broker for messages published on the enemy’s being dead.
→OnDeadと呼ばれる観察可能なものは、敵が死んだ時に発行されるメッセージの仲介者です。

(1)と同じで、以下の部分以外はボイラープレートです。

  • OnDead - プロパティ名
  • enemy - インスタンス名
  • being dead - イベント発火タイミング

Subscribe()

RxをPub/Subパターンで捉えてみるの解釈では、 Subscribe()Observable に対して購読の手続きを行うように命令しているのでした。
これを説明するように英文を組み立てます。
自然な文となるように、今度はJaneに OnDead(=Observable)になってもらいます。

Jane, start procedure for subscribing to messages.
→ジェーンさん、メッセージを購読する手続きを開始します。

命令文として訳してほしいところですが、残念ながら平叙文になってしまいました。
とりあえずそのまま貼っておきます。

(4) Subscribe(onNext: _ => this.OnEnemyDead())

Subscribe() の引数である onNext: _ => this.EnemyDead() の部分はこのようになります。
Player の代表はJackに務めてもらいます。

Jack, on next message's having been published, do the process on enemy's being dead.
→ジャック、次のメッセージが公開されたら、敵が死んだときの処理をしてください。

こちらも以下の部分以外はボイラープレートです。

  • enemy - インスタンス名
  • being dead - イベント発火タイミング

文を繋げると…

(1)〜(4)の英文とその訳を繋げました。
便宜上付与したJohn等の名前はメンバ名に戻し、理解しやすいように少し日本語訳に手を入れました。

A subject of onDead is messages published on the enemy’s being dead.
"onDead, do the process for on next message's having been published. "

An observable one called OnDead is a broker for messages published on the enemy’s being dead.
"OnDead, start procedure for subscribing to messages."

"Player, on next message's having been published, do the process on enemy's being dead."
onDeadの観測テーマは、敵が死ぬことで発行されるメッセージです。
「onDead、次のメッセージが公開された時の処理をしてください。」

OnDeadと呼ばれる観察可能なものは、敵が死んだ時に発行されるメッセージの仲介者です。
「OnDead、メッセージを購読する手続きを開始してください。」

「Player、次のメッセージが公開されたら、敵が死んだときの処理をしてください。」

これだけで仕様を説明する文章を作ることができました。

おわりに

補完しているしている語句が多いので、こじつけのように感じられるかもしれません。
しかし、補完している部分は、クラス名やインスタンス名、イベントの内容が変わってもそのまま使えます。
このため、場面によって変わる部分のみコードに記載し、共通部分は脳内でテンプレート化しておいて随時脳内補完するという整理も可能なのではないかと思います。
この脳内補完と翻訳がスムーズに行えるようになると、プログラムを理解する速度が上がりそうです。

リリテックラボ

Discussion