ハイパフォーマンス ブラウザネットワーキング、読むべき本だった
Twitterで「なんかやばそうな本が出るぞ!!!」みたいな事を言っていたら、それが偶然拾われて、献本して頂く流れになりました。オライリーさん、ありがとうございます。
とりあえずざっと全体を流し読みした(と言っても3時間弱は読んだ)ので、書評っぽいことを書いておく。
読むべき人間
以下に該当する人間に対しては必読に値する本だと思う。
- HTTPを扱うアプリケーション*1のアーキテクチャを設計する人間
- Webサーバ等のHTTPに関連するインフラを担当する人間
- HTTP 2.0、WebSocket、Server-Sent Events、WebRTCのプロトコルについて日本語の文書が読みたい人間
普通に技術的な読み物としても面白い内容なので、Webの世界に近いエンジニアからネットワークを扱う組み込みエンジニアまで、軽く読んでおいて損はないと思う。ただし、読むにあたり最低限のネットワークの知識(OSI参照モデルとかそのあたり)は要求されるので、そのあたりの知識がない人間には読むのはつらいかなぁという感じがする。
個人的には、読書会をやると楽しそうな本だと思った。
内容について
とりあえず目次を。詳細な目次については オライリーのページを参照して欲しいのだが、この内容で380ページである。
I部 ネットワークの基礎
1章 レイテンシ・帯域幅入門
2章 TCPの構成要素
3章 UDPの構成要素
4章 TLSII部 ワイヤレスネットワークのパフォーマンス
5章 ワイヤレスネットワーク入門
6章 WiFi
7章 モバイルネットワーク
8章 モバイルネットワークの最適化III部 HTTP
9章 HTTPの歴史
10章 Webパフォーマンス入門
11章 HTTP 1.x
12章 HTTP 2.0
13章 アプリケーション配信最適化IV部 ブラウザAPIとプロトコル
14章 ブラウザネットワーク入門
15章 XMLHttpRequest
16章 Server-Sent Events
17章 WebSocket
18章 WebRTC
読む前は「えっ、こんなに広範なトピックを扱って、なんでこんな薄いの…?」と多少の心配はあった。しかし、実際に読んでみると「ネットワークのプロトコル及びパフォーマンスのみに話題を絞る」「チューニング方法については一般論のみ(具体的なチューニングツールの紹介はない)」という内容になっているため、非常にわかりやすく、かつシンプルにまとまったのだなぁと感じた。
全体の流れ
まず、冒頭で「スピードこそユーザエクスペリエンス!!」「Webのネットワークにおけるスピードとはレイテンシの改善である!!!(現在の数Mbps程度の回線速度が一般化している状況下において)」という旨の内容が書かれており、クーガーさんの事が思い出され本書の取り扱う問題点の明確化を行っている。その上で以下のような順序で解説が行われている。
まとめ
良書っぽいので買いましょう。
*1:Webブラウザ、デスクトップ、モバイル等、全て該当
abstractを使ってDOMとjQueryを透過的に扱う
abstractを使うと、「C言語のunion」みたいなのを型安全かつ便利に書ける。引数をabstractで受けると非常に便利。
例として、js.html.Elementとjs.JQueryを透過的に扱ってみる。
abstract Html(Element) { inline function new(x: Element) { this = x; } @:from public static inline function fromElement(x: Element): Html { return new Html(x); } @:to public inline function toElement(): Element { return this; } @:from public static inline function fromJQuery(x: JQuery): Html { return new Html(x[0]); } @:to public inline function toJQuery(): JQuery { return new JQuery(this); } }
function appendToBody(x: Html) { Browser.document.body.appendChild(x); //Html -> Element に暗黙の型変換 } var div = new JQuery("<div></div>"); appendToBody(div); //JQuery -> Html に暗黙の型変換
ここでは "abstract Html(Element)" とElement型を主にしてみたけど、JQuery型を主にした方が良いかもって気もするし、NodeListも扱えた方が…とか色々あるのだけど、このあたりは好みですね。
Haxeのmacroでanonymous structureを動的に生成する
公式Wikiで解説が発見できなくて、ググりながら色々試しててたら、JSON-schema type builder prototype. · GitHubにたどり着いた。
理解できてしまえば簡単なのだが、ポイントとしては、
- Expr.ComplexType.TAnonymousを生成して、
- ComplexTypeTools.toType()でTypeに変換して、
- MacroTypeに食わせる
// MyMacro.hx class MyMacro { macro public static function build(): Type { var t = ComplexType.TAnonymous([ { name: "field", pos: Context.currentPos(), kind: FVar(macro : Int), meta: [] } ]); return ComplexTypeTools.toType(t); } }
// Foo.hx
typedef Foo = MacroType<[MyMacro.build()]>;
こんなかんじで、"var field: Int;"なフィールドを持ったtypedefというかanonymous structureを生成できる。
ちなみに、typedef自体もmacroで生成したい場合は、Context.defineType()を使えばいいらしい(試してない)。Build.hx · GitHubを参照。
Haxeのexternとinlineを同時に書くとinlineが優先されるっぽい
HaxeのjQuery externで new JQuery("selector"); って書くのがダサいなぁと思って、いろいろ試していたときにコンパイルできたコードをメモ。externとinlineを同時に書くとinlineの方が優先されるらしい。
Haxe 3.1.3で確認。
@:native("jQuery") extern class JQuery { public static inline function create(selector: String, ?context: Dynamic): JQuery { return untyped __js__("jQuery")(selector, context); } }
var elem = JQuery.create("body"); var tag = JQuery.create("<div/>");
その他のポイントとしては、untyped __js__("jQuery")で、Functionを取得して、それをコールしていること。
で、ここまでやってみたいのだけど、そもそも「jQueryの $() が色々できてしまうこと」自体がHaxeの文化にマッチしていないので、$.find() とか $.parseHTML() を使った方がいいよねという考えに至ったので、不採用とした。
HaxeのJavaScriptターゲット用のビルトイン
Haxe 3.0から __js__() 以外にもいくつか追加されてたらしい。知らんかった。
untyped __js__(js : String) : Dynamic
インラインJavaScript。
var console = untyped __js__("console");
untyped __js__("console.trace()");
untyped __instanceof__(obj : Dynamic, type : Dynamic) : Bool
JavaScriptの"instanceof"。@ktz_aliasさんが、標準APIのStd.is()を使えば良いのではって言ってたけど、本当にそうだと思う。
if (untyped __instanceof([], Array)) { // if ([] instanceof Array) { }
untyped __typeof__(obj : Dynamic) : String
JavaScriptの"typeof"。Haxe 3.1から使えるようになったっぽい。
switch (untyped __typeof__(x)) { // switch (typeof(x)) { case "string": case "number": case "boolean" default: }
untyped __strict_eq__(a : Dynamic, b : Dynamic) : Bool
JavaScriptの"==="。Haxe 3.1から使えるようになったっぽい。
if (untyped __strict_eq__(x, "hoge")) { // x === "hoge" }
untyped __strict_neq__(a : Dynamic, b : Dynamic) : Bool
JavaScriptの"!=="。Haxe 3.1から使えるようになったっぽい。
if (untyped __strict_neq__(x, "fuga")) { // x !== "fuga" }
Haxeの構造的部分型(typedef)ってstaticでも使える
Haxeを使い始めて2年ぐらい経つけど、今更こういうコードが書けることに気が付いた。
typedef Foo = { function print(): Void; }
class Hoge { public static function print() { trace("Hoge"); } }
var foo: Foo = Hoge; foo.print();