Chromium の hpack 実装をソースコードリーディング #http2study

はじめに

このエントリーは HTTP2 Advent Calendar の 14 日目の記事です。

Chromium の実装については現時点の最新の master を元にしています。

おおよそ 40.0.2214.42 相当と考えていただければ良いかと思います。

自分自身まだ完全に理解しきれていない部分が多いので説明を端折っている場合があります。

間違い等ございましたらご指摘いただけると幸いです。

ソースコードについて

Chromium の hpack 実装は net/spdy にあります。

% ls net/spdy | grep hpack
hpack_constants.cc
hpack_constants.h
hpack_decoder.cc
hpack_decoder.h
hpack_decoder_test.cc
hpack_encoder.cc
hpack_encoder.h
hpack_encoder_test.cc
hpack_entry.cc
hpack_entry.h
hpack_entry_test.cc
hpack_header_table.cc
hpack_header_table.h
hpack_header_table_test.cc
hpack_huffman_aggregator.cc
hpack_huffman_aggregator.h
hpack_huffman_aggregator_test.cc
hpack_huffman_table.cc
hpack_huffman_table.h
hpack_huffman_table_test.cc
hpack_input_stream.cc
hpack_input_stream.h
hpack_input_stream_test.cc
hpack_output_stream.cc
hpack_output_stream.h
hpack_output_stream_test.cc
hpack_round_trip_test.cc
hpack_static_table.cc
hpack_static_table.h
hpack_static_table_test.cc
hpack_string_util.cc
hpack_string_util.h
hpack_string_util_test.cc

今回は

net/spdy/hpack_huffman_table_test.cc - chromium/src - Git at Google

を中心に読んでみたいと思います。以下にテスト名称で説明していきます。

InitializeEdgeCases

HpackHuffmanSymbol の配列を初期化する際の一般的な正常系、異常系のテストが並んでいます。

内容はコメントを見ていただければだいたい分かるかと思います。

draft-ietf-httpbis-header-compression-09 - HPACK - Header Compression for HTTP/2net/spdy/hpack_huffman_table.cc - chromium/src - Git at Google の HpackHuffmanTable::Initialize の辺りを眺めていただくと雰囲気がつかめるのではないかと思います。

ValidateInternalsWithSmallCode

TEST_F(HpackHuffmanTableTest, ValidateInternalsWithSmallCode) {
  HpackHuffmanSymbol code[] = {
    {bits32("01100000000000000000000000000000"), 4, 0},  // 3rd.
    {bits32("01110000000000000000000000000000"), 4, 1},  // 4th.
    {bits32("00000000000000000000000000000000"), 2, 2},  // 1st assigned code.
    {bits32("01000000000000000000000000000000"), 3, 3},  // 2nd.
    {bits32("10000000000000000000000000000000"), 5, 4},  // 5th.
    {bits32("10001000000000000000000000000000"), 5, 5},  // 6th.
    {bits32("10011000000000000000000000000000"), 8, 6},  // 8th.
    {bits32("10010000000000000000000000000000"), 5, 7}};  // 7th.
  EXPECT_TRUE(table_.Initialize(code, arraysize(code)));
  ASSERT_EQ(arraysize(code), peer_.code_by_id().size());
  ASSERT_EQ(arraysize(code), peer_.length_by_id().size());
  for (size_t i = 0; i < arraysize(code); ++i) {
    EXPECT_EQ(code[i].code, peer_.code_by_id()[i]);
    EXPECT_EQ(code[i].length, peer_.length_by_id()[i]);
  }

  EXPECT_EQ(1u, peer_.decode_tables().size());
  {
    std::vector<DecodeEntry> expected;
    expected.resize(128, DecodeEntry(0, 2, 2));  // Fills 128.
    expected.resize(192, DecodeEntry(0, 3, 3));  // Fills 64.
    expected.resize(224, DecodeEntry(0, 4, 0));  // Fills 32.
    expected.resize(256, DecodeEntry(0, 4, 1));  // Fills 32.
    expected.resize(272, DecodeEntry(0, 5, 4));  // Fills 16.
    expected.resize(288, DecodeEntry(0, 5, 5));  // Fills 16.
    expected.resize(304, DecodeEntry(0, 5, 7));  // Fills 16.
    expected.resize(306, DecodeEntry(0, 8, 6));  // Fills 2.
    expected.resize(512, DecodeEntry());  // Remainder is empty.

    EXPECT_THAT(peer_.decode_entries(peer_.decode_tables()[0]),
                Pointwise(DecodeEntryEq(), expected));
  }
  EXPECT_EQ(bits8("10011000"), peer_.pad_bits());

  char input_storage[] = {2, 3, 2, 7, 4};
  StringPiece input(input_storage, arraysize(input_storage));
  // By symbol: (2) 00 (3) 010 (2) 00 (7) 10010 (4) 10000 (6 as pad) 1001100.
  char expect_storage[] = {
    bits8("00010001"),
    bits8("00101000"),
    bits8("01001100")};
  StringPiece expect(expect_storage, arraysize(expect_storage));

  string buffer_in = EncodeString(input);
  EXPECT_EQ(expect, buffer_in);

  string buffer_out;
  HpackInputStream input_stream(kuint32max, buffer_in);
  EXPECT_TRUE(table_.DecodeString(&input_stream, input.size(),  &buffer_out));
  EXPECT_EQ(buffer_out, input);
}

HpackHuffmanTable::Initialize の最後の方に HpackHuffmanTable::BuildDecodeTables と HpackHuffmanTable::BuildEncodeTable が実行されます。

まず HpackHuffmanTable::BuildDecodeTables の際に HpackHuffmanTable::DecodeTable と HpackHuffmanTable::DecodeEntry の配列が作成されます。

その際、先頭9ビット (kDecodeTableRootBits) から6ビット (kDecodeTableBranchBits) づつ処理されます。

このテストの場合 symbol が9ビット以内に収まっているため HpackHuffmanTable::BuildDecodeTables の配列は一つです。

decode_tables_: {
  prefix_length: 0, indexed_length:  9, entries_offset: 0
}

一番目の ”00" が長さ2なので9ビットから引いた数7ビット分で表される数は仕様上許されません。その分の127(0b1111111)を含んだ128個分 HpackHuffmanTable::DecodeEntry の配列が作成されます。

decode_entries_: {
  next_table_index: 0, length: 2, symbol_id: 2
  ... 以降インデックス 1 〜 127 まで同様

以降長さ3、4、5ビットの symbol も同様に処理されます。

最後の symbol は7ビットより長い必要があり、これは padding に利用されます。

なので peer_.pad_bits() が "10011000" になります。

※ peer_ はテスト用に private な変数にアクセス出来るようにしたクラス(friend class)で HpackHuffmanTablePeer のインスタンス

net/spdy/hpack_huffman_table.h - chromium/src - Git at Google

このテストの最終的な decode_tables と decode_entries について気になる方はこちらを参考にしてください。

https://gist.github.com/kysnm/4f0864f28f8dfb9dd72a

最後の EncodeString はごく単純で id の列を渡して HpackHuffmanTable::BuildEncodeTable 時に生成される code_by_id と length_by_id から対応する length と code を取り出して、先頭から順番にビット列に詰め込んでいくだけです。

ValidateMultiLevelDecodeTables

TEST_F(HpackHuffmanTableTest, ValidateMultiLevelDecodeTables) {
  HpackHuffmanSymbol code[] = {
    {bits32("00000000000000000000000000000000"), 6, 0},
    {bits32("00000100000000000000000000000000"), 6, 1},
    {bits32("00001000000000000000000000000000"), 11, 2},
    {bits32("00001000001000000000000000000000"), 11, 3},
    {bits32("00001000010000000000000000000000"), 12, 4},
  };
  EXPECT_TRUE(table_.Initialize(code, arraysize(code)));

  EXPECT_EQ(2u, peer_.decode_tables().size());
  {
    std::vector<DecodeEntry> expected;
    expected.resize(8, DecodeEntry(0, 6, 0));  // Fills 8.
    expected.resize(16, DecodeEntry(0, 6, 1));  // Fills 8.
    expected.resize(17, DecodeEntry(1, 12, 0));  // Pointer. Fills 1.
    expected.resize(512, DecodeEntry());  // Remainder is empty.

    const DecodeTable& decode_table = peer_.decode_tables()[0];
    EXPECT_EQ(decode_table.prefix_length, 0);
    EXPECT_EQ(decode_table.indexed_length, 9);
    EXPECT_THAT(peer_.decode_entries(decode_table),
                Pointwise(DecodeEntryEq(), expected));
  }
  {
    std::vector<DecodeEntry> expected;
    expected.resize(2, DecodeEntry(1, 11, 2));  // Fills 2.
    expected.resize(4, DecodeEntry(1, 11, 3));  // Fills 2.
    expected.resize(5, DecodeEntry(1, 12, 4));  // Fills 1.
    expected.resize(8, DecodeEntry());  // Remainder is empty.

    const DecodeTable& decode_table = peer_.decode_tables()[1];
    EXPECT_EQ(decode_table.prefix_length, 9);
    EXPECT_EQ(decode_table.indexed_length, 3);
    EXPECT_THAT(peer_.decode_entries(decode_table),
                Pointwise(DecodeEntryEq(), expected));
  }
  EXPECT_EQ(bits8("00001000"), peer_.pad_bits());
}

このテストは長さ9ビットを超えた symbol がある場合のテストです。HpackHuffmanTable::BuildDecodeTables の配列が2つになります。

それ以外については上のテストと同様です。

SpecRequestExamples

TEST_F(HpackHuffmanTableTest, SpecRequestExamples) {
  std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode();
  EXPECT_TRUE(table_.Initialize(&code[0], code.size()));

  string buffer;
  string test_table[] = {
    a2b_hex("f1e3c2e5f23a6ba0ab90f4ff"),
    "www.example.com",
    a2b_hex("a8eb10649cbf"),
    "no-cache",
    a2b_hex("25a849e95ba97d7f"),
    "custom-key",
    a2b_hex("25a849e95bb8e8b4bf"),
    "custom-value",
  };
  // Round-trip each test example.
  for (size_t i = 0; i != arraysize(test_table); i += 2) {
    const string& encodedFixture(test_table[i]);
    const string& decodedFixture(test_table[i+1]);
    HpackInputStream input_stream(kuint32max, encodedFixture);

    EXPECT_TRUE(table_.DecodeString(&input_stream, decodedFixture.size(),
                                    &buffer));
    EXPECT_EQ(decodedFixture, buffer);
    buffer = EncodeString(decodedFixture);
    EXPECT_EQ(encodedFixture, buffer);
  }
}

a2b_hex は16進数文字列をバイナリ変換する関数です。

実装は以下にありますので興味のある方は見てみてください。

net/spdy/spdy_test_utils.cc - chromium/src - Git at Google base/strings/string_number_conversions.cc - chromium/src - Git at Google

"a8eb10649cbf" だと "101010001110101100010000011001001001110010111111" の 48ビットになります。

Appendix C. Huffman Code を元に "no-cache" をエンコードすると "101010", "00111", "010110", "00100", "00011", "00100", "100111", "00101", "11111" (pad) で上の48ビットと同じですね。

HpackHuffmanTable::DecodeString の内部では各種初期化の後 HpackInputStream::PeekBits で uint32_t に先頭8ビットのみを読み込みます。

具体的には bits に 10101000000000000000000000000000 が代入されます。

ここから先頭の9ビット 101010000 が index になります。10進数で 336 です。

HpackHuffmanTable::Entry は return decode_entries[table.entries_offset + index]; するので decode_entries[336] が返ります。

この部分は kDecodeIterations (= static_cast(std::ceil((32.f - kDecodeTableRootBits) / kDecodeTableBranchBits)))、具体的には4回ループしますが、 decode_entries[336] の next_table_index は 0 なので同じ decode_tables[0] を参照するので { prefix_length: 0, indexed_length: 9, entries_offset: 0 } のままです。デコード対象の code が長くなると next_table_index で違うテーブルを参照し最終的に symbol_id にたどり着きます。

decode_entries_[336] は { next_table_index: 0, length: 6, symbol_id: 110 } なので entry.length は 6 で bits_available は HpackInputStream::PeekBits で設定された peeked_count なので 8 になっています。

peeked_success は true になっているので 331 行目の else 節に進みます。

out_capacity は decodedFixture.size() なのでデコード対象の文字列サイズを超えないようエラーチェックがあります。また symbol_id 256 は EOF になるのでそのチェックも行われます。

ここで entry.symbol_id 110 を char にキャストし出力用変数 out に "n" が代入されます。

次に HpackInputStream::ConsumeBits で読み込み済ビット長6ビットのを消費したということで、bit_offset_ が 6 に設定されます。2ビット残りがあり、先頭バイトは全て消費されていないのでこの時点では先頭バイトは削除されません。また bits から読み込み済の先頭 6ビットがビットシフトにより捨てられ、bit_available は entry.length 分引かれて 2 になります。

最後に HpackInputStream::PeekBits で追加の読み込みが行われます。peeked_count が 32 以上になるか bit_offset_ + peeked_count の合計がデコード対象の文字列サイズ以上になった場合に peeked_success がfalse になるので if 文の判定条件のところで return します。

これを繰り返すことにより "no-cache" の文字列をデコードします。

ちなみに net/spdy/hpack_constants.cc - chromium/src - Git at Google 用意された Huffman Code を元に Initialize された decode_tables と decode_entries が気になる方は以下のリンクをご確認ください。

https://gist.github.com/kysnm/0fdf0149f40a26f6703f

おわりに

時間が厳しくなってきたのでこのくらいで終わります。まだまだ全然理解が足りていませんし、読めていない部分も多いので引き続き読んでいきたいと思います。あとでできたら Chromium のコールドリーディングの tips 的なことも追記したいと思います。

C++ は普段使わない言語なのでここまで理解するのに結構時間がかかってしまいました。もっと詳しい方にいろいろ教えて欲しいのでもしよろしければお声がけください。使わない部分を潰す為に std::vector::resize で使っている部分とかパフォーマンス的にどうなのかとか気になります。

今年は http2 の年だったと言えるくらいいろいろな面でコミュニティの中心となる皆さんが頑張っていらっしゃいました。このエントリーで少しでも感謝が伝えられたらいいなと思います。

余談ですが, 現在の仕様では "HTTP2.0" ではなく "HTTP/2" もしくは "HTTP2" が正しい名称です.

東京Node学園祭を支える技術 #nodefest

はじめに

もうすでにだいぶ時間がたってしまいましたが、11/15(土)四回目となる東京Node学園祭2014が開催されました
自分の肌で感じる限りは全体的に好評だったのではないかと思っています。ご参加いただいた皆様、登壇者の皆様ありがとうございました!

僕は初めてノベルティの作成を担当し、さらには参加者募集と受付、登壇者への連絡、広報といつもより多めのタスクをこなしていました

今回はNode.js日本ユーザグループ代表が交代して初めての学園祭で、去年の国内にフォーカスした小規模な開催に比べ2倍以上の規模で海外ゲストありの豪華版でした

イベント支援サイト

https://connpass.com/static/img/common/sitelogo_295x100.png

参加者募集担当の仕事は募集サイトの準備、公開時期の決定、公開及び広報、当日の受付、問合せ対応です。
今回はいつも利用している connpass を選択しました。

不満があるとすれば

  • QRコードに対応していないので、アカウント名か受付番号でページ内検索しないといけない

  • 有償イベントの際に補欠で登録することができない

ですね。 doorkeeper は両方出来た気がしまするんだけど、どうなんだろう?

QR コードを利用する場合も connpass のようにサイト上で受付処理をする場合も受付周辺にネットワークが必要なのでその点注意が必要です
最悪の場合を考えて csv などを印刷して用意しておくと良いのではないかと思います

あと数年前は Paypal だとクレジットカードを持っていない学生さんが参加しづらいってよく聞いてたんですが最近聞かないですね。 やっぱり Paypal 以外の決済方法があった方が嬉しいっていう人多いのかな?

受付当日は声がけをして人の流れを誘導するのも大切です
初めての会場では受付も少しづつメンバーのやりやすい形に変わっていくので、打合せだけでカッチリ段取りを決めるのは難しい部分もあります

また当日受付では毎回受付番号もアカウントもわからないという方が何人かいらっしゃいます
前日のリマインダーメールにはアカウント名の記載がないですが、こちらから能動的に出したメッセージだとアカウント名が記載されているのでそのメッセージを見つけていただくとなんとかなります
最悪の場合はその場で思いつくアカウントでログインしてもらうしか方法がないですね

ちなみに東京Node学園祭は今まで以下のようなサービスを使ってきました

2011: doorkeeper

代表のポールさんのサポートが素晴らしいです。やはり入場時にQRコードがあると手間が減ります
支払い方法は Paypal 決済のみでしたが最近銀行振込をプライベートベータで始めたようです

銀行振込のご利用方法について | Doorkeeper

2012: イベントatnd

既にサービスは終了してしまいましたが、βじゃない方のサービスでした。当時参加者のアカウント登録が少し煩雑だった気がします。ちなみに運営のリクルートさんは初回からのスポンサー様です
こちらもQRコードに対応していたので受付はスムーズでした
支払い方法はクレジットカード決済とコンビニ決済が選択できたようです

「eventATND」でセミナーを開催します:(1)イベントの作成 | マイナビニュース

2013/2014: connpass

東京Node学園 4時限目からずっと利用しているサービスです
シリーズという概念があったのが connpass のみで、リッチエディタでいろいろと装飾が出来たのが高評価だったと記憶しています
(現在は Markdown で編集に変わっています)
最近は doorkeeper もいろいろなイベントで使われているので比較検討してみると良いと思います

peatix は直接使った事がないんですが、キャンセルの場合主催者へのメッセージでやり取りをしなければならないのが若干マイナスかなと思います
ただし東京Node学園祭もそうですが、有償イベントの場合基本的にキャンセルは受けないとは思います
運営的に処理が煩雑になってしまい、手が回らなくなってしまうので譲渡での対応をお願いしています

peatix の強みは決済方法の多彩さでしょうか

Peatix Help | チケット販売の決済方法は?

下記のリンクもすごく参考になりますね

connpassと他イベントサービスとの比較 - connpass

ノベルティ

今年は訳あって例年担当してくださっていたスタッフが抜けてしまったので、いろいろ調べながら手探りでやっていました
今までは株式会社プラン・ドゥ・ワンというところに一括で出していたようです
こちらは担当者のフットワークが軽くて、一括でお任せするのには適していそうですが、今回は海外ゲストも多く、コストダウンしたかったのでそれぞれのアイテム毎に探しました

スタッフTシャツ

https://cldup.com/oIo3NNQjkk-3000x3000.jpeg

今回は 株式会社spice life(スパイスライフ) さんの オリジナルTシャツ/クラスTシャツのプリント作成ならtmaker というサービスを利用させていただきました
実は今年の Rubykaigi も当日スタッフとして参加させていただいたんですが、その際に spicelife の方と知り合ったので相談したのがキッカケです
rubyhiroba でドラおっさんやった時にもらったTシャツも tmaker でしたね
仕上がりも問題無くて好感触でした

エコバッグ

https://cldup.com/SzLokTDQfs-3000x3000.jpeg

ザッと検索してみて一番安そうだったトートバッグの専門店のトートバッグ工房さんにお願いしました
エコバッグ意外と高いです。YAPC Asia Tokyo とか Rubykaigi は厚手だし結構良いもの使ってるんじゃないかな

デザインは公式サイトのロゴを流用させていただきました。シナップ の @sooup28 さん、ご協力ありがとうございました!

名札

https://cldup.com/9LSsSP9EOA-3000x3000.jpeg

https://cldup.com/a08kZU_7pv-3000x3000.jpeg

今回は昼食時の出入りがあるので入退場管理が必要でした
なのでコクヨナフ-E90B とその色違いを利用しました
受付ではヒモが絡みやすくてちょっと不評でした

中紙の印刷は 印刷通販の【グラフィック】 さんです
依頼を出すのがギリギリになってしまったのでコストが高くなってしまったんですが、24時間サポートがあるし、フレキシブルに対応してくれて好印象でした

ちなみにパンフレットもグラフィックさんでした パンフレットと名札の中紙のデザインに協力していただいた @un_nyan_ さんありがとうございました!

ステッカー

https://cldup.com/OSV9wKaSMV.JPG

これは仕上がりの品質が気になったのでコストよりも実績重視でプラン・ドゥ・ワンさんにお願いしました
アドプリント印刷通販デジタ といったところがコスト的には良さそうです

ステッカーは仕様があるそうで、その辺を参考にしました

terinjokes/StickerConstructorSpec · GitHub

おわりに

一つ一つは細かい作業なんですが、仕事の合間で1ヶ月の間にこれだけのタスクがあると結構大変でした
これまでノベルティの担当をしてくださった方は難なくサラッとこなしていたので本当に今までの貢献に感謝しています

懇親会の無限LTでも少し話させていただきましたが、コミュニティも新しい風を吹き込むことが必要です
実際前代表の @meso さんもそのような趣旨の話をされていました

先日こんなエントリーが話題になっていました

社員がフリーランスになる前に教えておきたいこと | fladdict

ブログ、オープンソース、勉強会・・・etc。なんでもよいので、業界とコミュニティに明解な形で貢献しなさい。スキル、経験、情報、チャンス、仲間、仕事、あらゆるものが貴方の周辺に集まります。与えたものは必ず何倍にもなって返ってきます

これまさに自分がスタッフをやって実感していることと同じでした

この学園祭のスタッフをやることで @meso さん、@jxck_ さん、@yosuke_furukawa さんや名前を出したらキリがないくらいの人達と知りあえて、いろいろな事を教えてもらいましたし、今も継続的に教えてもらっています
実際に行動を共にすることで壇上だけではなく、普段の考え方なんかも間近で感じられるのでお勧めです

ただしスタッフはある程度自発的にタスクを拾っていく事が求められる部分もあるので、細かい事でも良いのでタスクを拾ってくださる方が必要です
一人が多くのタスクを抱えて属人性を持ってしまうとそれだけでボトルネックになりますので、これからは複数人で協力してタスクをこなしていく体制づくりも必要でしょう

僕の担当以外にもスポンサー対応、海外ゲスト対応、公式サイト対応、配信対応、懇親会対応などありそれぞれ担当者が手分けしてやっています

また Strongloop がわざわざ日本に来てワークショップを開いてくれるということは、日本の市場に興味があるということだと思います
@nkzawa さんのように Socket.io の開発メンバーとなった人もいます

日本のコミュニティが Node.js の進化に影響を与えることが出来るかもしれません 皆さんの力でコミュニティをもっと盛り上げてみませんか?

ということでスタッフは継続的に募集中です。よろしくお願いします!

YAPC Asia Tokyo 2014 でスタッフしてきた #yapcasia

スタッフに応募した理由

今回初めて YAPC Asia Tokyo にスタッフとして参加してきました

僕は東京Node学園祭2011から三年間スタッフとして参加しているんですが、そのキッカケは当時仕事でPerlを書いていて shibuya.pm や smiley hackathon など Perl 関係の勉強会に良く参加していて、コミュニティに恩返しをしたいという気持ちが高まっていたタイミングで、YAPC Asia Tokyo 2011 のスタッフ募集があったんですが、躊躇している間に募集が終了してしまって後悔していたところ、その直後に東京Node学園祭のスタッフ募集があったので、Node.jsにも興味があった僕は今度こそ遅れないぞと応募したのでした

今は仕事ではRailsを使っているので、Perlは縁遠くなってしまったんですが、YAPC Asia Tokyo は言語にとらわれない魅力があり、毎年今年は行かないぞと思いつつ結局行ってしまっていて、今年もまた同じように悩んでしまいました

そんな時、ふと今こそコミュニティに恩返しするチャンスだと感じてスタッフにも応募したという流れです

キックオフ

少しさかのぼりますが都内某所にて顔合わせを兼ねた当日スタッフの飲み会が行われました

たまたま座った場所に CONBU チームの方がいたので、いつも快適にネットワークを使わせてもらっている感謝を伝えて、ネットワークの話を聞いたりしていました

後から @yusukebe さんとも話して、mixi で行われた Perl Casual Talks#1 一般募集 : ATND や初台にあった頃の DeNA で行われた カジュアルPerl #02 (初心者枠) : ATND の頃からお世話になっている事を伝えました

yosukebe さんは DeNAが初台にあった事を忘れていたらしく、すごく懐かしがってくれました(笑)

前夜祭

各種設営があるので当日スタッフは昼過ぎに集合

軽いブリーフィングの後ノベルティー詰め部隊とTシャツたたみ部隊に分かれました

僕はTシャツたたみ部隊でたたみ方を教えてもらってせっせとたたみました

一度調べたことのあった伊東家の食卓方式だったのですぐに慣れてスイスイたためて快調でした

XXL や XXXL なんてサイズは初めて触るので感覚の違いに新鮮な驚きを感じたりして楽しかったですね

その後各担当部署に別れて作業となりました

僕は三日間イベントホールの担当です

スポンサー様からの水を運び並べて、配達されたお酒やおつまみを並べ、スタッフも結構ワイワイと楽しんでやれました

前夜祭では Ruby 界隈でちょっと親交のある ppworks さんの話や masuidrive さんの話が印象に残ったな

Day 1

Go For Perl Mongers - YAPC::Asia Tokyo 2014 を聞きたかったけど、会場のキャパ的に難しそうなので断念

スタッフTシャツ着て混んだ会場にいると肩身が狭いですしね

そんなこんなで午前中はまったり過ごして、いよいよランチセッション、東京Node学園でいつもお世話になっている @yosuke_furukawa さんのセッションです

しかも次のセッションも連続で furukawa さんがやるとの事

普段どんな感じで開発しているか垣間見えて非常に楽しいセッションでした

そして @songmu さんのライブコーディング

開始ギリギリに songmu さんが現れ、我らがイベントホールのリーダー uzulla さんが「おこ」になるハプニングから始まりました

ライブコーディングには魔物が棲むと言われるように、途中エラーに見舞われ少し時間を食われたようですが、

見事に時間内にまとめてさすがの貫禄ですね

DMMカキ氷は午後の売れ行きが良い感じでした。しかしまだまだ在庫が山積みです、、、

この日のイベントホールは懇親会準備のため一旦撤収

少しの間伝説の CPAN Author 円卓会議も拝めました

ホールも混んでいそうだし、一日ほぼ立ちっぱなしだったので控室でのんびりしながらモニター越しにLTを眺めました

懇親会

そして間も無く懇親会準備、peatix のチケット確認の仕事が待っています

ここでハプニングが起こりました

peatix のサーバーダウンらしき現象が起こり、参加者の皆さんのチケットが表示出来ないというトラブルです

しかしエンジニアのイベントは参加者の協力で成り立っている部分も強く、怒るどころか表示された早い者勝ちという状況を楽しんでくださる方もいて非常に助かりました

ご協力いただいた皆さんありがとうございました。次回はこんな状況でも早急に対応できるよう準備が必要ですね

※ ちなみに peatix さんは受付でもフル稼働していたので、この時間帯本当にたまたま運悪くだと思います

懇親会も一般の参加者の方と溶け込みきれず、受付にいたスタッフの人達とまったり過ごしました

Day 2

この日も午前中はまったりしていましたが、DMMカキ氷の在庫を減らすため朝カキ氷に勤しんだり、来場者に

オススメしたり、前日より熱心にアピールしました

この日は我らがリーダー @uzulla さんと @karupanerura さんのセッションがあり、ちょっと手薄になりそうな予感

この日もセッションはランチセッションからでしたが、uzulla さんのセッションが11時20分からの40分でギリギリ間に合わないタイミングなので yosukebe さんが取り仕切ってくれました

その後地域.pm ミートアップ 2014 で uzulla さん、yusukebe さんは登壇、取材に回るスタッフもいました

このタイミングで yusukebe さんの隠し球レッドブルガールの来場です

イベントホールは無限コーヒー、DMMカキ氷、レッドブルの三本だてで、撤収時の在庫一掃に燃える部隊から追加カキ氷が台車で送り込まれテンヤワンヤ(死語)です(笑)

メッセンジャーで情報が飛び交っていたようですが、忙しいとなかなか見られないので気付いた人が周りに口頭で伝達すると良さそうです

地域.pm ミートアップが終わるとレッドブルガールは退場し一安心と思いきや、なんとキラーコンテンツ

Perlあるある」です!

Perl界隈のスーパースターが集まるセッションに徐々に聴衆が増え、とうとう入場制限をするまでになってしまいました

イベントホールは無限コーヒーで一息つきたい人もいると思うので、入場制限をするのはちょっと心苦しかったです

この日はランチセッションからずっと、出入口で飲食物の持ち出しが無いよう気を配っていたので、結構疲れました

最後のあやかNowもなかなか好評で入場制限は無かったものの結構な入場者数でした

事務所に所属しているタレントさんなので、いろいろ注意することがあったのですが、無事終わる事が出来てホッとしましたね

そして伝説の CPAN Author 円卓会議を眺めつつ、ゆっくりとイベントホールの撤収を進め、三日間お世話になったイベントホールともお別れしました

一日目より疲れて、少しゆっくりしたいところでしたが撤収準備があります。

モニターから聞こえる声を聞きつつ、何かあれば手伝いつつ、とうとうエンディングになりました

そしてベストスピーカー賞に我らがリーダー uzulla さんが選ばれました!

正直今回スタッフをすることで初めて話したくらいなんですが、なぜかすごく嬉しかった!!

最後にみんなで壇上に上がりエンディングです

実は HTML5 Conference の当日スタッフでも一度上がったことのある舞台でしたが、壇上からの眺めは素晴らしいですね

そして参加者の皆さんを送り出し全て終了です

お土産にカキ氷を配っていましたが、その場で食べてしまう人も多く、イベントホールで飲食物の持ち出しが無いよう気を配っていた身からするとちょっと心苦しかったです

まあとにかく配り切りたいという勢いが強かったので仕方がないですよね

まとめ

という訳でこれで僕の YAPC Asia Tokyo 2014 も終わり!

Perl コミュニティに少しでも貢献できたならば幸いです!!

お世話になった皆さんありがとうございました

何か貢献したいと迷っているあなた、次はあなたの番ですよ

おまけ

ノベルティー争奪戦でパーカー貰えなかったの悔しかったー。でもすぎゃーんさん、karupanerura さん達はスピーカー、個人スポンサー、スタッフまでやっているのそんな僕の不満はお門違いでした

Day 1 の Hub では某社CTOが泥酔する事件があったようですが、僕は三日間一度も Hub に寄りませんでした。普段の出社時間より朝早いしスタッフは意外と体力仕事なのでちょっと無理でした、、、

追記

今年はあと2つスタッフをやる予定です

チケット残り僅か!

チケットは近日発売 @nodefest や Node.js 日本ユーザグループ ML でご連絡いたします

LL Diver に行ってきた #lldiver

開催が近づくにつれてプログラムが充実してきて結果的にとても楽しめるイベントでした

見たいものが多くてトイレに行く暇もない感じで、もう少し余裕があっても良いかな

以下見たもの

昼の部

ちょっと遅れて到着

それでも Node.js をやる

我らが Node.s 日本ユーザーグループ代表の @yosuke_furukawa さんによる発表

睡眠時間を削って資料を作っていたらしく、Node.js の歴史がまとまった非常に良い発表でした

LLDiver で「それでもNode.jsをやる」というタイトルで発表してきた - from scratch

ペパボのエンジニア新人研修

あんちぽくんさんの独特の雰囲気で、参加者に対する事前オリエンテーションということで始まりました

以前から語彙豊富に、細かく対象を言語化することが素晴らしいと思っていました

ネット上で見かける雰囲気がちょっと怖いんですが、一度お話してみたいなと思っています

タイムリーに式年遷宮の話も出てきて面白かった

GMOペパボのエンジニア新人研修 #lldiver - delirious thoughts

@takesakoだけどなんか質問ある?

懐かしいw

相変わらずの takesako ワールドで楽しめました!

Qiitaを賑わしてるhiroki_daichiだけどなんか質問ある?

折角なので質問しました。

ちょっと失礼ですが、

長めのエントリーが多いように感じますが、最後まで読まれていると思いますか?

です

ところがこれが大当りで、長いととりあえず後でということでブクマしてくれるので、

それを狙っているということでした

そこまで計算するものなんですね

mozaic.fm出張版: TypeScript and Dart

いつも楽しみにしている mozaic.fm をライブで聴けるとあってワクワクしちゃいました

大雑把に言うとこの発言が全てを物語っていると思います

最近は Railsリファクタリングしたり、テスト書いたりすることが増えて静的型付言語が羨ましいなと感じることがあります

すごく気になっているんですが、実務ではなかなか使えそうにないのがもどかしい

ドワンゴの技術部隊を立て直したmesoだけどなんか質問ある?

普段から自分の役割に満足して、仕事を楽しんでいるように見える meso さん

自然体で力が抜けていて、あがり症な自分もあんな風になれたらいいなと思います

エディタ対決(仮)

kaoriya さんがすごいパワフルでした

最近は Sublime text 2 を主に使っているので、他のエディタの情報が聞けて良かった

ライトニングトーク

brainfuck-node の話、無理やり感がすごかった

shigemk2/brainfuck-node · GitHub

夜の部

Jxck さん、yosuke_furukawa さん、mizchi さんという豪華メンバーと同席させてもらいました

もうお二方いらっしゃったんですが、ギリギリに会場に入ったためご挨拶できず、失礼しました

この設計がひどい2014

会場を出たらで忘れるという約束だったけど、Rails の話やら、ccs infection の話やら、某社の話やらものすごく面白かった

いや、忘れましたけど

帰ってきただめ自慢

各言語ともものすごい愛情に溢れただめ自慢、堪能しました

帰りの電車で

設計について少し話しました

最近開発手法も旧来のウォーターフォールだけでなく、アジャイルな取り組みも良く耳にするようになりました

アジャイルな開発スタイルだと必要な機能を小さく作っていくので、詳細設計的なことはあまりしないような気がします

そうなってくると設計という言葉で同じことを思い浮かべるかちょっと疑問です

僕はきちんとした教育を受けたわけではないので、もっと設計について知りたいと思っています

良い勉強会とか書籍があったら教えてほしいなー

まとめ

丸一日なので疲れましたが、とても充実した一日を過ごせたと思います

スタッフのみなさん、登壇者のみなさん、ありがとうございました!

#mozaicfm #7 REST を聞いて

LL Diver | Dive into Lightweight Languages に向かう途中でこれを書いています

毎回何度も聞き返してしまうくらい勉強になっています!

以下思ったことをツラツラと

REST の影響について

Perl や他の言語界隈の影響についても聞いてみたかったので、zigorou さんがいたらまた違った話になっていたかもですね

restful なリソース設計という単語にビビっときたので勉強したい

API versioning 問題について

話を聞いていて思ったのは、マーケティングと政治的な配慮があるのかなと思いました

t_wada さんが言っていたように「使われてみて初めてわかる」事はあるだろうし、環境の変化に対応する為には変更は避けられないかなと

その上で外部に提供する API ならば、変更を考慮している事がわかれば使いやすいんじゃないかな

さらには実際に変更する際には移行期間を設ける事で変更に対する摩擦を軽減出来るような気がする

HATEOAS について

何度か話題に上がっているように複雑な仕組みは流行らないと思いました

という訳でリンクを含んだ表現はエラー処理が増えたりしないのかな?

レスポンスを信じて遷移を行なうよりクライアントが遷移先を知っていたほうがセキュリティ的にも良いような気がするんだけどどうなんだろう?

なので単純なデータをやりとりする仕組みが現時点では主流になっているような気がする

でなければ RPC の方が流行ってるんではないかなと思いました

パーマリンクのないデータ

全然関係ないけど、なんか pplog - ゆるふわインターネットにポエムを刻もう を思い出した

難しいこと抜きにこの辺の流れ肌で感じてるのスゴイなー

終わりに

午後から mozaic.fm出張版: TypeScript and Dart があるので楽しみです!

Node.js について学び直そうと思った

ポッドキャスト rebuildfm で Matz が Node.js について言及していて
うっかりこんな風につぶやいたところ @yosuke_furukawa さんからこんな
ツッコミをいただきました。

あらためて調べてみたところこちらの記事がとても良くまとまっていました。

Node.jsの問題点、デメリットと解決方法まとめ - Qiita

その中でも紹介されている大津さんの記事で cluster の導入でマルチプロセス
が可能になったことが書かれています。

注目のサーバサイドJavaScript実行環境「Node.js」 | 最新の技術・取り組み | IIJ

マルチプロセスについての情報も 探してみると結構ありました。

node.js multi process - Google 検索

ただシングルスレッドのイベント駆動 だから CPU を使い切れない部分はある
んじゃないかなとは思います。ちょっと負け惜しみっぽいですが。

おまけ

調べていたら Isolates なんて懐かしい機能も出てきました。
マルチスレッドを実現する機能だったんですね。

Node v0.7.0の新機能Isolates(マルチスレッド)を試す - y-kawazの日記

記事中にあるようにこの機能はすでに削除されています。

終わりに

せっかくなので Node.js の利点が公式サイトに載っているので
そちらを紹介したいと思います。

About | node.js

This is in contrast to today's more common concurrency model where OS threads are employed. Thread-based networking is relatively inefficient and very difficult to use. Furthermore, users of Node are free from worries of dead-locking the process—there are no locks. Almost no function in Node directly performs I/O, so the process never blocks. Because nothing blocks, less-than-expert programmers are able to develop scalable systems.


Just because Node is designed without threads, doesn't mean you cannot take advantage of multiple cores in your environment. You can spawn child processes that are easy to communicate with by using our child_process.fork() API. Built upon that same interface is the cluster module, which allows you to share sockets between processes to enable load balancing over your cores.

というわけで時間を作ってもう少しきちんと理解していきたいと
思っています。

そして LL Diver で furukawa さんがどんな話をしてくれるか楽しみですっ!

プログラム | LL Diver

チケットもまだまだ買えますね!

チケット | LL Diver

参考:

http://mew.org/~kazu/material/2011-server.pdf

dirty check について調べてみた

はじめに

自分は普段 Backbone.js や Angular.js を書く機会はあまりありません。

Backbone.js、Angular.js についてはかじった程度、Ember.js についてはほとんど知りません。

なので理解不足な部分があると思います。よろしければツッコミをお願いします。

この記事の対象となる Angular.js のバージョンは最新の安定版 v1.2.16 です。

この記事の大部分は Angular.js について書かれていますが、基本的に Node.js や JavaScript Engine v8 についての興味から書かれたものです。

tl; dr

ざっくり言うと

  • dirty check とは object の状態を記録して、特定のキッカケを元に変更をチェックする仕組みである

  • パフォーマンスの懸念もあるが、人間の体感速度などを加味し、Angular.js では dirty check を選んだ

  • しかしながら現実的にパフォーマンス問題は存在する

  • Object.observe を利用することで問題を解決したい

ということのようです。

なぜ dirty check が気になったのか

Node.js v0.12 では Promise や Object.observe、WeakMap が使えるようになるらしいです

「こいつはすげー」と思いましたが、「けど Object.observe ってなにが嬉しいの?」と疑問に思い、ちょっと調べてみました。

まずは大津さんの過去のブログからチェックしてみました。

次世代JavaScriptでデータバインディング: Object.observe() を試す - ぼちぼち日記

ここで dirty check という単語にぶつかります。

Accessors vs Dirty-checking

調べてみると以下の記事が見つかりました。

Brendan Graetz • Accessors vs Dirty-checking in Javascript Frameworks

どうやら Angular.js、Ember.js が dirty check を行っているようです。

ご存知の方も多いと思いますが Backbone.js は 専用にラップされたオブジェクトのイベントに Listener を登録することで変更を伝搬させています。

対して Angular.js は dirty check と言われる手法で変更を伝搬しており、Ember.js はこの両方を使えるようです。

Angular.js のドキュメントの Scope Life Cycle を見ると

  • スコープの作成
  • Watcher の登録
  • モデルの変更
  • 変化の観察
  • スコープの破棄

となっていて model の変更時に scope.$apply が呼ばれ(基本的に暗黙的に呼び出される、外部のイベントをハンドリングするには明示的な呼び出しが必要)、scope.$apply の終わりに $digest cycle が実行され、モデルの変化をチェックし、Listener を呼び出します。

https://code.angularjs.org/1.2.16/docs/api/ng/type/$rootScope.Scope#$apply

https://github.com/angular/angular.js/blob/v1.2.16/src/ng/rootScope.js#L581

dirty check の利点

上述の記事 Brendan Graetz • Accessors vs Dirty-checking in Javascript Frameworks によると accessors 方式 (Backbone.js) の場合以下の特徴があります。

  • framework が提供する model オブジェクトをラップしなくてはいけない

  • Listener を正しく発火させるためにプロパティの操作には getter や setter を覚えなければいけない

POJSO (Plain Old JavaScript Object) が扱える dirty checking の方がプロパティのアクセスも Listener の発火も簡単に書けると主張されています。

パフォーマンス

javascript - Databinding in angularjs - Stack Overflow

Angular.js の作者である Misko Hevery が StackOverflow の質問に対して dirty check は十分早いと回答しています

要約すると以下のような事を言っているようです。

  • model をループで順に追加する場合、毎回イベントが発火して view が描画される。UI を一度だけ変更したい場合、これはパフォーマンスを悪化させる。

  • change イベントに対応する Listener が更に change イベントを発生するとスレッドロックのような状態になりかねない

  • 50ms 以内なら人間は早いと感じる

  • 2000 以上の情報を単一のページで見せるのは良い UI とは言えないだろう

しかしながらこの記事は 2012年のものでした。

Backbone.js もこの時点からはだいぶ進化しているかと思われます。

AngularJS 2.0

AngularJS: AngularJS 2.0

Change Detection - Google ドキュメント

現時点では Angular.js のパフォーマンス問題は認識されているようです。

design doc を見ると GC の問題もあるようです。

これを解決するために GoogleChrome M35 に Object.observe を実装したという流れのようです。

まとめ

だいぶ Angular.js よりの話なので Backbone.js 側の反論も聞いてみたいと思いました。

思わぬところからいろいろな事がつながって調べてみて良かったです。

新しい ES6 の機能で Node.js や v8 がどのように進化するか楽しみです!!

参考

AngularJSのパフォーマンス改善入門 - Qiita