チョッパヤ本を読んだ

超速! Webページ速度改善ガイドを読んだ。

超速!  Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)

超速! Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)

普段あまりこういう本は買わないのだけれども、友人達が書いていたので購入してみた。特に献本などもないのでどうでもいいかと思ってたんだけど、あとで印税貢献分としてコーヒー一杯奢れと著者両人にたかるネタとして良さそうなので買いました。

内容はGoogleの出しているWeb Fundamentalsのうち、パフォーマンスに関連するセクションを捕捉・再構成したような感じ。

巷では玄人向けという評価もあるけれど、それは本のターゲットの説明として大雑把にすぎると思う。 一読者たる私の感じたターゲットは、

  • Chromeのdeveloper toolsのperformance profilerの使い方がよくわからない
  • Webサイトの動作が遅くて困っている・困っていないが予防のための知識が欲しい
    • サーバー側の負荷には余裕があるのでクライアントサイドが原因だと思っている
    • どこが原因なのかわからないので、まずクライアント側から調べていきたい
  • 「Webフロントエンド」に関した(限った)パフォーマンス戦術の頻出パターンが知りたい
    • 余談ですが私は 「Webフロントエンド」という呼称が大嫌いです
  • Webサイト構築・運用におけるパフォーマンスについての考え方を知りたい

あたりの人向けの本だと思った。基本的にはWebクライアントサイド慣れしてない人向けの本だと思うし、ビギナー向けの本だとも思う。

逆にこの本に書かれていない内容としては

  • 2010年代のGUIアプリはなぜ60fpsを出さないといけないのか
  • システム全域に関わるパフォーマンスについての話
  • 「速いソフトウェア」の作り方と組織

とか。

ここら辺が知りたい人はAndroidを支える技術 part 1の第1章とか、Brendan Greggの"System Performance"とか、Joe Duffyの"Performance Cultue"あたりを読んどけばいいと思う。

具体的に感じたこと

第1章

  • Webサイトのパフォーマンスに関する概論的なお話。パフォーマンスやる意味とかを偉い人に説明するのに使うと便利とか、どういう技術的な指標を用いるかという話
  • npmとかNode.jsの使い方に関しては第1章に入れなくてもいいと思った。この本を読むような人種でnpmの使い方がわからない人種はあまりいないだろうし、想定するにしても「はじめに」の直後とかでよかったんじゃないかなあ。

第2章・第3章

  • ここら辺まではWebサイト構築に携わるエンジニアなら誰でも大雑把には知っておきたいところ。細かい設定の話とか覚えなくていいから。
  • ネットワーク処理周りの概論と具体的な調査方法、と言いつつもだいたいwebページがロードされるまでの話と、どういう指標があるのかについて
  • クリティカルレンダリングパス周りについては、ここら辺も読んでおくといいと思います

第4~5章

  • ここら辺から「Webフロントエンド」っぽくなってくる
  • ちなみにpainting時のrasterization周りはoff main threadになりつつあるので、メインスレッド(JSスレッド)の邪魔はしにくい処理系も出てきています(Display Listの構築処理は残っているので、そこのコストが消えているわけではない)
  • GPUの場合では、なぜテクスチャ転送のコストが発生するのかという原理的な話(コンピュータアーキテクチャ)については、個人的には解説があったほうがすんなりのみ込みやすくなると思うけれども、ターゲットを考えると省いて正解だとも思います。

第6~7章

  • 1本のメインスレッド(JSスレッド)のイベントループの中で、如何に不要な処理を間引きつつやるかという話。GUIプログラマーっぽい話。
  • 私見として、メモリリーク周りに関しては、ページ中のオブジェクトのライフサイクルを常に意識して適切にデストラクトして参照をnull埋めなどしてリークしにくい(GCにオブジェクトが回収されやすい)コードを普段から書いた上での、デバッグテクニックとして捉えるべきだと思う。

第8章

  • 画像などに関する取り扱い
  • これは実質ネットワークリソースの話だから、第4章の前とかに持ってきてもよかったんではないかなあ。

第9章

  • ServiceWorkerとResource Hint周りの話なので、特に感想はない

エモい書評書かないの?

特にエモい感情がわかなかったので.... 

終わりに

  • なんかダメ出し多くなってしまったけど、最近のWebサイトのパフォーマンスに関する話題をつまむのにちょうどいい本だと思います。
  • @著者両名 そのうちコーヒー一杯奢ってください

詰まないための二要素認証運用(エンドユーザー編)

最近、使ってた携帯電話が即死してちょっと詰みかけたり、周りでも携帯が突然死して困った同僚がいたのでまとめておく。

基本戦略

  • 防水だろうがなんだろうが携帯電話は精密機器なので割と簡単に壊れるということを思い出す
    • 壊さなくてもなくしたりどこかに置いて来てしまったりする
  • リスクを分散させる

やっておくこと

リカバリコードをちゃんと取得しておく

  • 基本なんだけど、後でやろうと思って忘れがちなので二要素認証を有効にしたタイミングでやっておく

GitHubなど物理トークンで二要素認証できるサービスはFIDO U2F対応のトークンを買って登録しておくこと

  • たとえばyubikeyを買って使いましょうという話です.
  • いちいち携帯を取り出すよりも簡単だし、紛失してもたかだか5千円なので、とっとと諦めてrevokeできるのがよい.
    • とっととrevokeすれば悪意のある第三者がこれでログインするのも難しくなる.
    • 普通に家の鍵とかと同じ扱いをしましょう.

ワンタイムトークンをSMSで発行可能なサービスはアプリではなくSMSを使う

  • アプリだと携帯電話が壊れると即死なことがおおいけれども、SMSなら代替機さえ用意できればなんとかできることが多い.

二要素認証アプリ以外で二要素認証できないサービスは使わない

  • たまにアプリとリカバリコード以外で二要素認証できないサービスがある
  • そんなところに二要素認証が必要な重要なデータを預けるべきではない
  • 真面目に取り出せないリスクがある
  • 法人とかでグループ管理者とか他に復旧してくれる人がいる場合はともかく、なるべく使わないのが正解

色々かんがえること

SMSと物理トークンのどちらか一方しか鍵として登録できないサービスではどちらを登録すべきか

  • GitHubとかはどちらをプライマリキーにするかを選んだ上で登録できるけど、そうじゃないサービスもある
    • AWSとかがこんな感じだった記憶(うろ覚え)
  • 利便性は物理トークンの方が楽なことが多い
  • あんまり深く考えてないけど好きな方でいいんじゃない?
  • リカバリコードの方が重要

まとめ

  • アプリでの二要素認証は回復が大変
    • ハードウェア起因の理由で
  • FIDO U2F対応の物理キー便利です
    • 二要素認証必須の会社は会社支給で配って欲しいし、配るといいと思うし、配らないなら経費申請しよう
  • リカバリコードはちゃんと取っておけ

Bought MacBook Pro 15 (2017 mid)

MacBook Pro 15 (2017mid)を6月に買った。Kaby Lake積んでるやつね。 macOSそのものはそこまでこだわりはなかった。けれどもLinux Desktopをlaptop PCで使う気にはなれなかったのと、物理4コアなノートPCが欲しかったのと、そろそろ2012mid/IvyBridgeなMacBook Airを更新する目的で新しいMacが一台欲しかったので。Winは何年か前にXPS13買って使ってたので、ちょっとMacに戻ることにした。

カスタマイズはほとんどしてないし、CPUも増してない。

キーボードとかtouchbarとか

touchbar無しを選ぶと旧筐体になってしまうので已む無くtouchbar付きを選択。 touchbarにせよキーボードにせよ、みんな使いにくい使いにくいと言うけど、言うほど使いにくいかな? どちらも噂ほど酷いもんでもないかなーと。

キーボードはもともと私はキーストローク浅めのものが好きなんで、そこまで苦労しなかった。とはいえ今までと同じように打ってると不満はたまる。ここは打ち方変えないとダメだろう。キートップ安定してるのとストローク含めて、MacBookみたいなサイズ感で鞄から取り出して使うには向いてるとは思う。が、Pro 15だと不満になりやすいとも思う。前の世代の筐体に慣れてる人は特に。

touchbarは、確かにエスケープキーの感覚は狂うけど、それ以外はそんなんでもなく。慣れれば音量調節とかは便利かな。

あと、そもそもガチでコード書くときは自分は外付けのキーボードを繋ぐんで、どちらもそんなに困らなかった。

touchbarそのものに対しては、便利といえば便利だけど、ロジックボードの発熱部品のほぼ真上に位置しているのと、そもそもとして故障しうる部品が増えるのは好きじゃないので、出来ればtouchbar無しモデルがあればそっちを買うとは思う。ただ、よく聞くような「このtouchbarというUIがクソだから買わない」みたいな理由ではないかな。

USB type C

Amazonでtype Aメス - type Cオスのコネクタをいくつか眺めてもどれもレビューがイマイチだったんで、Appleの純正アダプタを買うことに。今の所これ由来の不具合はない。USB type-Aな周辺機器は、このアダプタにUSBハブを経由して繋いでる。

電源アダプタもtype Cなのは、ちょっと不便だなーと。mag safeの時はうっかりケーブルに足を引っ掛けてもちゃんと抜けてくれる安心感があったけど、type Cだとそれはないので、間違えて引っ掛けてコネクタを破損してしまわないか心配だったりする。左右両方に電源ケーブルを刺せるのは便利なんだけど、ケーブルはmag safeにして欲しかったなあ。

液晶とかスピーカーとか

いいんじゃない

Benchmark

  • とりあえず参考までに
  • なお、macOS Sierra 10.12.6
  • rlsとfuture-rsは以下の条件でビルド
    • rustc 1.21.0-nightly (215e0b10e 2017-08-08)
    • cargo 0.22.0-nightly (305bc25d5 2017-07-28)
command time
future-rs, rev 3c067a7 cargo build 2.68 secs
rls, rev ecdbf0c cargo build 98.77 secs
servo, rev 8074c6a mach build –dev 1105.77 secs

総評

一昔前の14 inchノートPCのサイズ感とMacBook Pro 13の重量感で物理4コア15 inchノートが展開できるのは便利。電源確保もできれば憂いなくだいたいのソフトウェアはビルドできる。電源アダプタ入れても2.2kg弱だから、リュックサックに背負う分にはそんなに苦労しない。出先で確実に作業するのであれば普通に持ち運べる感じ。本体のキーボードも出先用と割り切れば十分。

ただ値段も結構いい値段するので、そこが結構ネックだったりする(それでも13 inch touchbarモデルを特盛にした場合と大差ないけど)。これで20万円代前半なら最高なんだけど…… 値段割り切れればいい買い物でしたよ。

/<role>/<domain>/DomainNameRoleみたいなディレクトリ階層よりも/<domain>/<role>/DomainNameRoleみたいな階層の方が素直だと思う

こんなの探せば10年とか20年前にも似た議論があって結論出てそうだし、ドメイン駆動設計系の人が実践論として言ってそうなものだけど。

アプリケーションフレームワークとかボイラープレートみたいなものをいくつか眺めていると、/Controller/SignIn/SignControllerみたいなディレクトリの組み方を薦めてるものが結構あるけれど、これは素直じゃないなと思った。

だいたいこんな階層になるやつ。

  • /
    • Action/
      • Signin/
      • Report/
      • Editor/
    • View/
      • Signin/
      • Report/
      • Editor/
    • Repository/
      • Signin/
      • Report/
      • Editor/
    • UseCase/
      • Signin/
      • Report/
      • Editor/

何が素直ではないと思ったかというと、

  1. 具体的な問題領域よりも先に教条主義的なコードの役割分担が優先されている
    • 問題領域に応じてHelper増えたりとか色々あるのが本当だよね
    • 例えばバージョン情報みたいな画面だと View だけに色々ベタに書いていいはずで(バージョン情報の他問題領域から再利用とか、普通そんなに起きねえよ)
  2. 結果, 同一の問題領域のコードなのに木構造的に再従兄弟みたいな位置にいるコードが多くて見通しが悪い
    • 凝集度悪くね?
  3. 問題領域に応じたコードの組み方がやりにくい
    • 例えば「ReportドメインのViewはReactじゃなくてVue使いたい!(そちらの方が技術的に向いている)」みたいな需要に合わない。この構成だと、例えばView/の下の一箇所を変えると、隣接するディレクトリに配置されたコード全てを同じように変えたくなってしまう。それが人情ってもんです。

な辺り。

あとで移行とかリファクタをしようと思った場合に一番面倒なのは 3 だし、普段コードをいじるときは 2 がストレスになるけど、何れにしても「問題領域に応じて最適な道具を用いる」という思想とは噛み合わせが悪いし、私はそういう思想なので、息苦しさとかデメリットばかりなように思う。なので、自分がゼロから組む場合はもっぱら:

  • /
    • Signin/
      • Action/
      • View/
      • Repository/
      • UseCase/
    • Report/
      • Action/
      • View/
      • Repository/
      • UseCase/
    • Editor/
      • Action/
      • View/
      • Repository/
      • UseCase/
      • Helper/

みたいに, 問題領域の方を階層の上に置くようになった。 こっちの方が問題に合わせてコードを書く、という場合は素直だと思う。

/<コードの役割>/<問題領域>/問題領域_コードの役割.拡張子 みたいなディレクトリ構成を採用してるフレームワークは、そのフレームワークが想定する・楽にできる問題領域が1つ〜2つ程度なんじゃないか、それ以上を単一のアプリケーションに入れ込むことを想定してないんじゃないかと思うし、用途としてはそんなに向かないだろう。

だからと言って「マイクロサービス最高!時代はマイクロサービス!マイクロサービスしない奴は何をやってもダメ!」とか言うつもりはないんだけど、そこらへんの射程の距離感は常に意識しておくべきで、それを忘れるとコードが無秩序に増え続けるのをウッカリ見過ごしてしまいそう。

rustcを通らないコードは間違っている

Rustを書いていると、慣れるまではrustcに頻繁に怒られる。慣れても結構怒られる。とにかくrustcに怒られる。きっと貴方はこう思うだろう、「Rustはなんて煩い言語なんだ!俺の愛する****(好きな言語の名前を入れてください)ならばこんなことはないのに!」

このように「rustcが煩くて俺のコードが通らない」場合、とりあえず自分のコードが間違っていると疑って問題はない。え、「俺のコードは正しい」? 違う違う、コードのロジックの話じゃない。「そのコードがRust wayではない」という点で「間違っている」。microなスタイルからmacroな設計まで、ありとあらゆる点でRust的なコードであることを暗黙的ではあるが極めて強く要求する。それがRustというプログラミング言語だ。時たまrustcが間違っていることもあるんだけど、体感値として97%はrustcの方が正しいと言っていい。

なぜこのように「不自由な」言語なのか? それはRustは「人間が考えなくても静的に解析できる情報を増やせば、コンパイルの時点でリソースの取り扱いに関するバグを減らせる」という世界観で構築されているからだ。それを実現する為に「言語仕様としてセマンティクスを強く定義し、rustcでそれを機械的に徹底検証する」というモデルを提供している。

こういう世界観で構築されているので、論理的に検証できない・すなわちコード内に自明ではない整合性はRustにおいては、しばしばrustcに禁止させている。パワーバランス的には人間よりもrustcの方が強い。コンパイルの通らないコードはそもそも動かないからだ。セマンティクスと相俟って人間はrustcが解釈できるようなコードを書く必要がある。GoとかTypeScriptよりは間違いなく圧が強い。見返りに、人間はRustの世界観を受け取る。Rustはコンパイルさえ通れば、(後述する例外はあるが)書かれたコードの通りに動く。書いたコードがバグっていればバグ通りに動く。 Noneunwrap()すればそこでクラッシュする。 { ... }でスコープを縮めてやればlockは縮めた分だけすぐに解放される。それがRustである。「〜っぽいコードを書こう」なんて、ゆるふわは無い。勧められるままに書かねば何も動かないか無駄に歪なコードが残るだけだ。

このように世界観の主張が強いので他言語のコードを安直に置き換えても上手く行くとは限らない。moveで済む場合はborrowせずmoveせよ、goroutineみたいにスレッドをたくさん建てずアクター的にせよ(これはownership制約と同時にカーネルスレッド使ってるのが理由だったりもするけど)、下手に高次の言語からportするよりも、スレッドも何も使ってないCやJavaScriptからportの方が簡単かもね。とにかくRustの世界に合わせてコードと設計を変えなければならない。さすればrustcはコンパイルを通してくれる。

この思想故、Rustは言語機能こそ多いが局所局所で取れるmicroなパターンは極端に多くない。syntax的には組み合わせられても、micro/macroでのownershipやlifetimeによって組めないパターンが幾つも現れる。

もちろんそんな理想論ばかりが通ることはない。C/C++の資産との接続、明らかに安全かつ性能のためのdirty hack。そんな時はコードをunsafeに括り出せばよい。ただし全てunsafeにしてはいけない。unsafe由来のコードはRustの世界を容易に侵食し、コンパイルが通ったコードがいきなりセグフォで落ちるようになりかねない。なので、必要最低限の分だけ括り出さねばrustcの加護は得られない。このため、FFIを用いるbinding crateは***-sysという薄いFFIするだけのwrapperと、それの上にRustの殻をかぶせたAPIの二段構成を取ることになる。 いくらrustcが全てを視てくれると言っても、そのために全ての変数の型やlifetimeを明記するのは怠い。故に推論による省略が出来る。

rustcに無制限の自由を差し出す代わりに、偉大なるrustcの監視の目を用いてコードの穴は塞がれる。代償とした自由は大きくも見えるが、現実的に取り得るコードのパターンに於いては概ねプログラマ側に自由があるので問題はない。発想が少々oxydizeされるだけだ。プログラマはロジックを書くのに専念すればよい。IDEに一定範囲の自由を売る代わりに、IDEによってコードやリポジトリに対する人間の認知力を拡張するのと発想は同じ。ScalaとかKotlinとかJavaとかC#とか、あの辺りの作法と大差はない。問題のレイヤーを低次に下げた結果、機械に売り渡す自由は増えたが、多くはレイヤー固有の事情なので問題にはならない。

(とはいえ今のRustはIDE支援が半端で色々片手落ちになってるので、Rust Projectの2017年のRoadmapに「IDEを頑張る」って入ってるんだけど)

言語に合わせて思考と設計を変える。今までの固定観念を捨ててRustに合わせて再構築し直す。これがRustでコードを書くということだ。

rust-bindgenのupstreamが変わった

cargo:bindgenのupstreamがYamakaky/rust-bindgenからservo/rust-bindgenに変わった。変わった結果どうなったかというと、C++のヘッダのパース機能が大幅に改善したりする。

rust-bindgenを知らなかった人に簡単に解説しておくと、clangを使ってC/C++のヘッダをパースして、それを元にRustのC FFI binding用途のglue codeを生成するcrateのこと。

元々rust-bindgenはRust ProjectではなくJyun-Yan Youが始めたらしい。らしいというのは「git logを辿った限りだとそうなっている」以上のことを言えないから。その後、メンテナー間での移譲があったのかどうかはよくわからないが、2015年末の時点ではYamakaky/rust-bindgenがupstreamとなっていた記憶がある。自信ないけど。

Mozillastylo(Quantum CSS)をやる関係でC++で書かれたGeckoとのglue codeを作る必要が出て、2015年の後半ぐらいからservo/rust-bindgenとしてforkしてMozillaのpaid staffが用が足りるようになるまでコードを書いていた(今も続いている)。元々のbindgenはC++サポートはそんなに強く無かったと記憶しているけど、Mozilla側で手を突っ込みまくった結果として改善され、たとえばleveldbのC++ヘッダが丸々パース可能だったりする(実体験)。

で、merge into upstream! · Issue #21 · servo/rust-bindgenというissueが立っていて、色々あったんだけど、最終的にservo側がupstreamを引き継ぐことになった。

RFC 1774で2017年のターゲットの一つにC/C++との相互運用を挙げているし、Servoがupstreamを引き継ぐのは間違っていないのではないかな。RFCを考えるとrust-lang-nurseryが引き継ぐのが一番いいけれども、Rust Project最大のパトロンであるMozillaの一門であるServo Projectの下に置いておくのは妥当なように思う。

生成されるコードは何も指定しないと大きい。依存先を含めてシンボルを再帰的に変換していくので当然といえば当然である。 実用上はpublic apiだけを変換対象のホワイトリストに指定することのほうが多いと思う。なんとか-sysを作るための道具なので、そこで生成したコードをそのままアプリケーションコードから呼ぶべきではない。

使い方?それはREADMEでも読めばいいんじゃないかな。