@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Web Operations Weekly issue 2

Web Operations Weekly Issue 2: February 19, 2015

HTTP/2 の話題で持ちきり。

Etsy のパフォーマンスエンジニアリング担当者のインタビューが面白かった。「経営陣にパフォーマンスの重要さを認めさせるには?」という質問に「ユーザーテストの動画でサービスが『重い』様子を見せる、地球の裏側で動いてるテスト環境にアクセスさせてネットワークが遅い状態を体験させる、自社サービスが遅いビデオに続けて競合サービスが速いビデオを見せて自尊心に訴える」とか。

Heroku | Introducing Heroku Enterprise: New Features for Teams

セールスフォースらしさが出てきた。

i18next.js をテスト環境で正しく設定する方法

CI環境下では pass するがローカルマシンで実行すると fail するテストがあった。テスト環境用の i18n.init のオプションが不十分なのが原因だった。

ローカルでのみ落ちるテストは pluralization rule の単数形・複数形にまつわるもので、以下のような翻訳リソースがあるとき、 "2 activities" を期待している部分が "2 activity" となってしまいアサーションが失敗する、というものだった。

locales/en-US/translation.json

{
  "activity": "__count__ activity",
  "activity_plural": "__count__ activities"
}

実行結果が "1 activity" になってしまうのならともかく、 "2 activity" はおかしい。このテストは Mocha と PhantomJS で実行しており、調べた結果、端末のシェルの環境変数 LANG が ja_JP.UTF-8 だと fail し、 en_US.UTF-8 だと pass していた。

その時点での、テストランナー用の HTML に書かれていた i18next の初期化オプションは以下。なお window.__locale にはすでに locales/en-US/translation.json の内容が代入されているものとする。

i18n.init({
  customLoad: function(lng, ns, options, loadComplete) {
    loadComplete(null, window.__locale); // or loadComplete('some error'); if failed
  },
  load: 'current',
  fallbackLng: false
});

この場合 lng オプションを設定していないので、 i18next の言語設定はブラウザ(この場合 PhantomJS)の言語設定により決定される。 PhantomJS は環境変数 LC_ALL や LANG の値を利用するので、端末のシェルの LANG が ja_JP.UTF-8 になっている状態でテストを実行すると i18n.lng() === 'ja' となる。

日本語の pluralization rule は英語と異なり、数値によって単数と複数が変化しない。 "__count__個の活動" という翻訳リソース一種類で「1個の活動」「2個の活動」の両方をまかなえる。

しかし、テスト環境用には英語向けの翻訳リソースデータしか用意していなかったため、 i18next は日本語の pluralization rule に基づいて "activity_plural" ではなく "activity" のほうを選び、 "2 activity" という期待はずれの翻訳結果が得られてしまったのだ。

i18n.init の初期化オプションを以下のように変更することで、他のコードを変更することなく、ローカル環境でも CI 環境でもテストが pass するようになった。

i18n.init({
  lng: 'en-US',
  resStore: {
    'en-US': {
      translation: window.__locale
    }
  },
  fallbackLng: 'en-US'
});

lng を明示的に en-US にすることで PhantomJS のブラウザ言語(つまり端末のシェルの環境変数 LANG)に左右されず、常に i18n.lng() === 'en-US' でテストが実行されるようになる。なお、テスト環境用に en-US の翻訳リソースをセットしていることからもわかるように、このアプリケーションのデフォルト言語は英語である。

テストの内容によっては i18n.setLng を利用して言語設定を変更することもある。英語と日本語では姓名の並び順が逆なので、氏名の入力フォームのテキストフィールドの表示順も逆になっていることをテストしたい、など。そういう場合に ja の翻訳リソースが存在しないと i18n.t は翻訳を行わないので、 fallbackLng を en-US にしておくことで、テスト環境下では用意されていない言語に変更した状態で i18n.t が呼び出されても翻訳結果が得られるようになる。


言語設定とは関係ないが、 i18next の ajax リクエストによる翻訳リソースダウンロードの仕組みを使わず、直接翻訳リソースをセットする場合は、 customLoad よりも resStore を使ったほうがよい。 customLoad は ajax リクエストをカスタマイズする用途向けにある機能だ。

ajax リクエストを送信せず loadComplete に翻訳リソースを渡すのも resStore を使って翻訳リソースをセットするのも最終的には同じ結果となるが、テスト環境では ajax リクエストは利用できないことが多いだろうから、 resStore を使ったほうが意図が明確になる。 resStore は以後の初期化処理をスキップするので無駄がなくより高速でもある(もっとも、実行速度の差は数ミリ秒程度に過ぎないだろう)

実は件の落ちるテストの調査を始めた当初は customLoad を使っていることが原因ではないかと疑い、 resStore に置き換えればなおるはずだと思っていた。 i18next.js のソースもその仮説に基づいて読み込み、デモ用のコードまで書いたものの、問題のアプリケーションのテストは pass せず、検証しなおした結果 lngfallbackLng をセットする必要があるという結論に達した。

MRI検査を受けた

いろいろややこしい事情があり、ちくのう症の検査が目的でMRIをやった。CTは何年か前にやった覚えがあるがMRIは初めてで、検査中はちょっと不安になった。

検査結果は問題なく(ついでに脳のMRIもとったが異常なし)主治医に言われるがままだったけど後日耳鼻科へ行くとかでも十分だったのではという気もした。

MRIの検査中に鳴る音、特に高低のビープ音をなぜ鳴らすのか不思議で、気を紛らわすために「本当は無音でできるが、技師が装置から『いまこういう磁場ですよ』というフィードバックを得て誤動作してないか確認するためにあえて鳴らしているのでは?(昔何かの映画で観た、放射能が漏れて汚染された世界で、目に見えたほうがわかりやすいという理由で空気が赤や黄色になっていき、恐怖がそこまで迫っている絶望感を煽るだけだった、というエピソードのように。または危険なガスが漏れたらすぐ気付くようにアンモニア臭をつけているように)、いやでもフィードバックなら装置の画面に表示されるに決まってるから別に音を鳴らさなくていいよな、しかも被験者はどの音のパターンが何の意味なのか知らないのだからなおさら意味がない」などと考えていた。検査後聞いたら「仕組み上音が鳴ってしまうものなのだ、これでもだいぶ小さくなってきたんだ」と予想外の回答で、驚いて待ち時間に検索して興味深く読んだ(原理はいまだに理解できていないが)

コイルの回転という原理がモーターとかスピーカーという技術に応用されていると知って、学生時代全く興味が持てなかった電磁力学などが急に面白そうなものに感じられた。数学にしろ科学にしろ、社会人になってから「つまりこういうことだったのか!」と繋がって興味がわく、というありがちな経験をすることが最近何度かあった。

MRIの画像は検査中に動いてしまっていてやや不鮮明なものも少なくなかったが、検査方法への理解がない状態では「これはおそらく音が鳴ってる間に何かを照射し、設定を変える間に音が消えるのだな(レントゲンを照射し続けないように)つまり音が鳴っているときはじっとしているべきで、鳴り止んでいるときは息抜きのタイミングなのだろう」などと予想するのも無理ないと思う。

DB Weekly issue 48

DB Weekly Issue 48: February 20, 2015



構造化されていなくて何のデータかわからないデータを検索する方法についての実装に興味を持つひとが少ないのは残念だ、みたいな言い分の意味がわからなかった。


勉強になった。苦手な GROUP BY の説明が物足りなかったのでウェブで調べたら、自分が GROUP BY の動作を間違って理解していることがわかった(複数のフィールドで『グループ化』する、というのの脳内モデリングが間違っていた)このページの解説がわかりやすかった(スプレッドシートのスクリーンショットが) SELECT 文の活用 (GROUP BY) - オラクル・Oracle SQL 入門

仕事では(上の記事でインタビューに答えてるえらいひとがこきおろしてる NoSQL の雄である) MongoDB しか使ってないから SQL を使う機会が乏しくなっていたが、ログ解析やデータ解析のために BigQuery を使えるように社内インフラが整備されてきたので SQL もちゃんと勉強しなおしたい。

Node Weekly issue 74

Node Weekly Issue 74: February 20, 2015


dowjones? ダウジョーンズ、ってまさか、と思ったらそのまさかでびっくりした。ウェブサイトのモバイル版がなんか嘘くさくて(海外のよくあるWeb制作会社っぽくみえる)Wikipediaのダウ・ジョーンズのページからリンクを辿り直してホスト名確認し直したけどやっぱりあってて二度びっくりした。