🥚

Rx チャーハン作る

2021/07/04に公開

カノジョできないエンジニアの@armorik83 です。13 日目を担当してます。

独身を謳歌している我々に付きまとう問題といえば、食事ですね。毎日外食をしてもコストが掛かるし、かといって毎日インスタントだと栄養が偏ります。となると手料理が最高なんですが、ご飯を作ってくれるカノジョがいなければ自炊するしかありません。

自炊の代表格といえば無論チャーハンでしょう。チャーハンは男子たるもの目をつぶってでも作れなければなりません。今回は RxJS を使ったおいしいチャーハンのレシピを紹介します。

チャーハンで ReactiveX を実装すると期待された方がいたら、すいません。

材料

ご飯

チャーハンといえば、ご飯ですね。

class ご飯 {
  freeze() {
    this.温度 = -10
    return this
  }

  cool() {
    this.温度 = 4
    return this
  }

  heat() {
    this.温度 = 45
    return this
  }
}

const 冷やご飯 = new ご飯().cool()

冷やご飯が必要です。炊きたてでもいいですが、冷やご飯のほうがパラパラに仕上がるのです。ちなみに炊きたてご飯の一番美味しい温度は 40〜48 度と言われています。

class 刻みネギ {}
class 刻みベーコン {}

const 長ネギ = [new 刻みネギ(), new 刻みネギ(), new 刻みネギ(), new 刻みネギ()]
const ベーコン = [new 刻みベーコン(), new 刻みベーコン(), new 刻みベーコン()]

次に具です。皆さんはスーパーに売ってる長ネギやベーコンを、それ自体がインスタンスだと思っているかもしれませんが、実は違います。それぞれ刻みネギ刻みベーコンの配列として格納されているものです。

卵は簡単そうに見えますが、カプセル化されていて中身は複雑です。まず、スーパーで売ってる卵は次のようになっています。

import 卵 from '業者'

const 卵パック = [
  new 卵(),
  new 卵(),
  new 卵(),
  new 卵(),
  new 卵(),
  new 卵(),
]

卵の実装詳細は業者によって隠蔽されており、我々は実装不明な卵 6 個の配列を取得します。ちなみに外食と自炊を両方やる場合、10 個より 6 個の方が痛めずに扱いやすいという結論を出しました。

卵を実装する

時間が 1 秒でも惜しいエンジニアならば卵を実装せずにインポートしたほうが早いですが、今回は実装してみます。

import {Observable} from 'rxjs'

卵の実装にはRxJSが必要です。RxJS は ver 4 系と ver 5 系の情報がよく混在していますが、RxJS 5 系のほうがモテます。

const 黄身 = new Observable((observer) => {
  observer.next(18)
  observer.complete()
})
const 白身 = new Observable((observer) => {
  observer.next(36)
  observer.complete()
})

const 卵 = Observable.merge(黄身, 白身)

卵はおよそ 60g で、そのうち 60%が白身、30%が黄身と言われています。黄身と白身はObservableのため、このように記述します。observer.complete()を呼ばないと無限に白身と黄身が湧いてきますが、そんなにあっても困るので必ずcomplete()を呼びましょう。

Observable.merge(黄身、白身)は溶き卵を作るわけではなく、殻の中に黄身と白身が入っている状態をイメージしてください。

調味料

調味料は塩、コショウ、醤油、鶏ガラスープです。これらは全て調味料クラスのインスタンスです。調味料クラスは RxJS のSubjectを利用します。

import {Subject} from 'rxjs'

class 調味料 {
  constructor(種類) {
    this.調味料$ = new Subject()
    this.種類 = 種類
  }

  sprinkle() {
    this.調味料$.next(this.種類)
  }

  prepare() {
    return this.調味料$
  }
}

const 塩 = new 調味料('塩')
const コショウ = new 調味料('コショウ')
const 醤油 = new 調味料('醤油')
const 鶏ガラスープ = new 調味料('鶏ガラスープ')

調味料は使う前に準備(prepare)してから振り掛けます(sprinkle)。

調理

具材を加工する

ようやく材料が揃いました。チャーハンを作っていきましょう。まずは具材を刻んでいきます。具材の配列はObservable.from()を使って刻めます。

const 刻まれたネギ = Observable.from(長ネギ)
const 刻まれたベーコン = Observable.from(ベーコン)

これで刻めました。次に溶き卵を作ります。黄身と白身を混ぜるにはscan()を使います。

const 溶き卵 = 卵.scan((acc, val) => acc + val).last()

scan()の関数内でストリームを流れる黄身と白身を足して返すことで、溶き卵になります。ただし混ぜてる過程は調理に不要なのでlast()を付けることを忘れずに。

ご飯は一度レンジに入れて 30 秒チンします。30 秒チンするストリームを作りましょう。

const チンご飯 = new Observable((observer) => {
  observer.next(冷やご飯)
  observer.complete()
}).delay(30 * 1000)
  .map((ご飯30秒後) => {
    return ご飯30秒後.heat()
  })

フライパンを火にかける

ここから炒めていきます。まずはフライパンを火にかけます。

const フライパン = Observable.interval(1000)

これは 1 秒ごとに加熱ができるフライパンで、まだ冷めています。言い換えると、まだ Cold Observable です。熱するためには Cold Observable を Hot Observable にしなければなりません。

const フライパン = Observable
  .interval(1000)
  .do((v) => {
    console.log(`
 ∧,,∧
(;\`・ω・)  。・゚・⌒) チャーハン作るよ!!
/   o━ヽニニフ))
しー-J
    `)
  })
  .publish()

publish()を呼んだことでフライパンを加熱する準備ができました。まだ Hot にはなっていませんが、コンロに置いた状態だと思ってください。あと、調理中の様子が見たいので、do()を挟みました。

では着火します。publish()を呼んだときの戻り値ConnectableObservableに対してconnect()を呼んだとき、Cold は Hot に変換されます。

フライパン.connect()

これでフライパンが加熱されました。

炒める

炒めていきましょう。まずは油です。

const ごま油 = new 調味料('ごま油')
フライパン.merge(ごま油.prepare())

// たぶん小さじ1はこれくらい
ごま油.sprinkle()
ごま油.sprinkle()
ごま油.sprinkle()
ごま油.sprinkle()

使う油は、サラダ油よりもごま油の方が合います。ごま油も調味料として生成して、先にフライパンに投入する準備(prepare())をしましょう。そのあと小さじ 1 を入れます。

続いて具材を炒めます。ここは先にベーコンから炒めたほうがおいしく仕上がります。

フライパン
  .merge(ごま油.prepare())
  .merge(刻まれたベーコン)
  .merge(刻まれたネギ)

軽く塩コショウしておきましょう。

フライパン
  .merge(ごま油.prepare())
  .merge(刻まれたベーコン)
  .merge(刻まれたネギ)
  .merge(塩.prepare())
  .merge(コショウ.prepare())

塩.sprinkle()
コショウ.sprinkle()
塩.sprinkle()
コショウ.sprinkle()

いい感じですね!フライパンに溶き卵を入れます。

フライパン
  .merge(ごま油.prepare())
  .merge(刻まれたベーコン)
  .merge(刻まれたネギ)
  .merge(塩.prepare())
  .merge(コショウ.prepare())
  .merge(溶き卵)

卵が固まりきる前に、すぐにご飯を投入しましょう!

フライパン
  .merge(ごま油.prepare())
  .merge(刻まれたベーコン)
  .merge(刻まれたネギ)
  .merge(塩.prepare())
  .merge(コショウ.prepare())
  .merge(溶き卵)
  .merge(チンご飯)

水気が飛んできたら醤油、鶏ガラスープを足して、塩コショウで味を整えます。

フライパン
  .merge(ごま油.prepare())
  .merge(刻まれたベーコン)
  .merge(刻まれたネギ)
  .merge(塩.prepare())
  .merge(コショウ.prepare())
  .merge(溶き卵)
  .merge(チンご飯)
  .merge(醤油.prepare())
  .merge(鶏ガラスープ.prepare())

醤油.sprinkle()
醤油.sprinkle()
鶏ガラスープ.sprinkle()
塩.sprinkle()
コショウ.sprinkle()

完成

おめでとうございます!チャーハンが完成しました。

const チャーハン = フライパン
  .merge(ごま油.prepare())
  .merge(刻まれたベーコン)
  .merge(刻まれたネギ)
  .merge(塩.prepare())
  .merge(コショウ.prepare())
  .merge(溶き卵)
  .merge(チンご飯)
  .merge(醤油.prepare())
  .merge(鶏ガラスープ.prepare())

さっそくいただきましょう。

https://gist.github.com/okunokentaro/0a2857cdb91722d7eacb6de5dd39228c

実食

class ぼく {
  eat(食べ物) {
    食べ物.subscribe(() => {
      console.log('おいしい!')
    })
  }
}

new ぼく().eat(チャーハン)

✌('ω')✌ おいしい!


RxJS を使えば簡単においしいチャーハンが作れることが分かりました。皆さんもやってみてください。それではよいクリスマスを。

Discussion