kitak blog

Kみたいなエンジニアになりたいブログ

Node.js で Request Local なコンテキストを Zone.js で作る

具体的には Request 毎に id を生成して、ログに書き出す内容に含めたいと思った。例えば、ログを出力する箇所が express のレイヤーだけであれば、Request オブジェクトにプロパティを生やせば実現できるが、モデルや他のレイヤーも考慮すると難しくなる。 リクエスト毎に実行コンテキストが作られる場合は、グローバル変数で id を扱えばよいが、Node.js は全てのリクエストを基本的にひとつのスレッドで捌くので、グローバル変数で扱うとリクエストの度に id が上書きされ、複数のリクエストを同時に捌く際、新しいリクエストの id が以前のリクエストの id として出力されてしまうから。

domain という標準モジュールや、それを使った request-local というモジュールを使うと、やりたいことは実現できるのだが、かなり前のバージョンから pending deprecation になっている。代わりになる API が用意されれば、deprecated になるので、使うのはためらう。

他に実現する方法はないのか調べたところ、Zone.js というライブラリでできそうだった。Zone.js は Angular が内部で使っているライブラリで、非同期処理に跨ったコンテキストを作成することができる。Zone.js の APIECMAScript の Spec として提案されているので、これの策定が進めば、Node.js でも実装されて domain に置き換わるのかな、と勝手に思っている。Zone.js 自体の説明は AngularとZone.jsとテストの話 - Qiita が詳しい。コードは以下のようになる。middleware でリクエスト毎にコンテキストを作って、後は任意の箇所で Zone.current を通して、コンテキストにアクセスすればよい。

const express = require('express');
const uuidv1 = require('uuid/v1');
require('zone.js');

class Foo {
    constructor() {
        console.log(`[trxId=${Zone.current.get('trxId')}]: create Foo instance`)
    }
}

const app = express();

app.use(function (req, res, next) {
    Zone.current.fork({
        properties: {
            trxId: uuidv1(),
        },
    }).run(next);
});

app.get('/', (req, res) => {
    new Foo();
    res.send('Hello World!');
});

app.listen(3000, () => {
    console.log('listening port on 3000.');
});

Zone.js はライブラリの仕様を実現するために setTimeout 等の非同期処理をおこなう API をラップしていて、アプリケーション全体に影響がある「つよい」造りになっているので、もう少し個人プロダクトで試して検証する予定。

ロジ・コミックスとラッセル幸福論

最近の100分de名著でバートランド・ラッセルの幸福論を取り上げているので読んでいる。という話を友人にしたら、「ラッセルといえば、ロジ・コミックスのイメージだった」という話を聞いたので、合わせて読んでみた。

ラッセルの幸福論はラッセルが50代の頃に書いた本で、幸福論の冒頭に述べているように、彼がこれまでの自分の人生を振り返ったり、周囲の人間を観察した結果、導き出されたパターンや法則がまとめられている。一方でロジ・コミックスは、ラッセルの伝記を通して、論理学と数学の証明論の発展を解説しようとした異色のコミックだ。

ロジ・コミックスに出てくるラッセルは人間的に何か問題があったり、大きい挫折を味わうような描き方がされている。例えば、数学や論理学にのめりこみライフワークバランスを崩した結果、家庭を不幸にしたり、同僚の妻に恋をしたり、苦しんで世に出したプリンキピア・マテマティカウィトゲンシュタインゲーデルのような天才に(建設的にだが)批判されるといったように。

幸福論というと、賢者が述べているなんだか浮世離れしたものというイメージがあったが、ロジ・コミックスを読んだことで、ラッセルの主張の背景にある不幸や挫折、成功、克服といった彼の経験が浮かび上がり、その主張に対する納得感のようなものが高まった気がするのだった。

ロジ・コミックス: ラッセルとめぐる論理哲学入門 (単行本)

ロジ・コミックス: ラッセルとめぐる論理哲学入門 (単行本)

ラッセル幸福論 (岩波文庫)

ラッセル幸福論 (岩波文庫)

MobX の runInAction とは

故あって、React + MobX なプログラムを読んでいたら、

runInAction(() => {
  this.state = "done";
});

といった runInAction の呼び出しを多く見かけて、なんだろこれ、と思ったのでメモ。MobX 1日目で変なこと書いているかもしれません。

Writing async actions | MobX を順に読んでいけば分かるのだけど、

  • MobX では strict mode を有効にすることで Action 外で state を変更しようとしたらエラーにすることができる
  • ↑の制約を設けた場合、Action で呼び出した非同期処理のコールバックがただの無名関数だと Action 外ということになるので、コールバックにはメソッドとして定義したアクションを指定する必要がある
  • とはいえ、コールバックのためだけにメソッドを定義するのもまわりくどいので、無名関数を Action にできるユーティリティ関数が用意されている
  • さらに TypeScript で書いている場合に、↑だとコールバックの引数の型を都度記述する必要があって面倒なので、最後の state の変更だけを無名関数に切り出して、アクション内として呼ぶためのユーティリティ関数が用意されている。それが runInAction

ということだった(なんか問題を解決しようとして、さらに問題を生んでを繰り返していて、複雑...)。Action 内の非同期処理のコールバックで state を変更する場合はとりあえず runInAction 経由でおこなえばとりあえずは動く。

Vuex の場合は副作用の伴う処理は Action, state の変更は Mutation で役割が分かれていたのだけど、MobX の Action は副作用の伴う処理も state の変更のいずれも Action 内でおこなうことができる。ただ、「できる」というだけであって、Vuex のように副作用の伴う処理と state の変更で分離する設計をしてもよい。
個人的には副作用が伴う処理とそうでない処理が明確に分かれていたほうが見通しが良いし、書く時に迷わないので、多少は面倒だけども、メソッドをアクションとして定義して、それをコールバックに指定する形で分けると思う。

getUserMedia でバックカメラを要求する

Andoid Chrome で動くQRコード・バーコードを読み取るアプリを書いていて知った。

navigator.mediaDevices.getUserMedia でカメラを要求すると、デフォルトではフロントのカメラになるのだけど、以下のようにすることでバックカメラを要求することができる。

navigator.mediaDevices.getUserMedia({
  video: {
    facingMode: {
      exact: "environment"
    }
  }
})

参考

THE INCAL を読んだ

読んだ。

DUNE で出会ったアレハンドロ・ホドロフスキーメビウスが再びタッグを組んで作ったフレンチSFコミック。
街の一角のありふれた場面からビッグバンのように爆発して、宇宙を覆い尽くさんばかりに物語が膨らんでいく。読んでいて圧倒される作品。 両性具有の話が小道具として出てくるのだけど、その表現がダ・ヴィンチ・コードと繋がるものがあって興味深かった。

アンカル

アンカル

Ethereum トークン (ERC20 Token Standard) の残高を取得する

8月頃にプレセールで買ったとあるトークンが最近発行されて、Etherscan や My Ether Wallet でトークンが発行されたことを確認したのだけど、自分用の Wallet App を作ってみたくなったので、プログラムからトークンの残高を取得する方法を調べてみた。

web3 という Ethereum JavaScript API の module を使う。version は 1.0.0-beta.23。

const Web3 = require('web3');
const web3 = new Web3();
const WALLET_ADDRESS = 'XXX';
const CONTRACT_ADDRESS = 'XXX';

web3.setProvider(new web3.providers.HttpProvider('https://api.myetherapi.com/eth'));
web3.eth.call({
  data: `0x70a08231000000000000000000000000${WALLET_ADDRESS}`,
  to: CONTRACT_ADDRESS
}, "pending").then((res) => {
  console.log(parseInt(res, 16));
})

data の部分は、コントラクトのメソッドを SHA3 256 でエンコードした値(web3.utils.sha3('balanceOf(address)').substring(0,10))とトークンを保管しているアドレスを合わせて、全体が 32 byte になるように結合したもの。

参考

vue-router で初期表示後に、どのルートで解決されたか知りたい

初期ナビゲーションが終わった後のルーターオブジェクトにアクセスすればよい。onReadycurrentRoute のコンボでいける。

router.onReady(() => {
  router.currentRoute;
});

vue-router ひと通りドキュメントに目を通していたつもりだったのですが、ひさしぶりにみたら router オブジェクトのメソッドが色々増えていたり、学びがあった。