ErgoDoxを2枚買ってキースイッチを交換した
ErgoDox始めました pic.twitter.com/lm2kCCwj3K
— 体調悪太郎 (@k0kubun) 2016年5月2日
なぜErgoDoxを2枚買ったのか
直近で使っていたキーボードは1300円で買える奴で、金に余裕ができたらいい奴を買おうと思っていた。HHKBとRealforceは以前所持していたことがある*1ので、Kinesisとかを検討していたけど47kするしもう少し安いErgoDoxから試すことにした。会社まで持ち歩くのは面倒なので2枚買った。
買ったErgoDoxたち
値段は実際にクレジットカードで支払った額 (送料込み)
- ErgoDox EZ Bundle: Blank: 36,190円
- リストレストとTilt/Tentキット(傾けるアーム)がついてる
- キースイッチはGateron Red
- FalbaTech + pimpmykeyboard: DSA PBT/ABS BLANK KEYCAP SETS: 35,553円
- Ergodox Acrylic Standard Case - Carbon Foil
- Acrylic Plate Stamdard or Fullhand 76-Key - Acrylic Only
- キースイッチはGreetech MX
届くまでにかかった時間は両方2週間くらい。ErgoDox EZ→FalbaTech→PMKの順で届いた。
キーマップ
迷走中。3箇所にマッピングされている意味不明のキーもある。もともとキーマップはいじりまくってるので、それに合わせて作ってる。画像はMac用の奴で、Linux用の奴はRGui(Cmdキー)をAltに変えてる。レイヤー2にはTeensyキーと矢印キーしかないので省略した。
今はMassdropで設定してるけどGUIポチポチするの面倒なのでそのうちk0kubun/qmk_firmwareに移す。
キースイッチの変更
もともと使っていたキーボードのキー荷重が62±15gだったので、キースイッチには45gのGateron RedとGreetech Redを選んでいた。ただ、届いてみると元のキーボードよりずっと疲れた*2ので、35gのGateron Clear (ErgoDox EZのサイトだとWhite) を買ってそれに変えることにした。
で、まあ実際には半田づけをやり直すのが面倒だったので、Feelとか含め完全に同じタイプのスイッチであることを利用してバネ(とついでに軸)だけ交換することにした。
150個注文して150個分同じ作業をやったら6時間かかった。スイッチの分解コストがかなり高いので半田づけした方が速いかもしれない。
良い/悪いと思ったこと
ErgoDox EZ
- 良いこと
- Tilt/Tentキットといい感じのリストレストが最初からついてるのがかなり便利
- キーキャップが位置によって形が違い、若干Kinesisみたいな感じになっている
- 最初からGateron Whiteが選べる
- 自己都合での返品による返金に対応している
- 悪いこと
- カバーが開けにくくカスタマイズはやりにくそう
- 滑りにくい & ガタガタしないようにすると傾け方の選択の幅があまりない
- FとJキーの突起が普通のキーボードよりちょっと気になる *3
FalbaTech + pimpmykeyboard: DSA PBT/ABS BLANK KEYCAP SETS
- 良いこと
- 外装の自由度が高い
- 分解しやすく作りもシンプルなので壊れた時対応しやすいしカスタマイズも楽そう
- FとJキーの突起がなく鬱陶しくない
- 悪いこと
- 傾けるのを自力でがんばらないといけないし、傾けると滑る
- キーキャップの形が全部同じで、完全な平面キーボードになる
- Gateron Whiteを採用できない
共通
- 良いこと
- キーボードレベルでリマップできるのでXを立ち上げる前から好きなキーマップが使える
- セパレートなので自分が楽な姿勢を選びやすい
- 悪いこと
- 右端のキーの数が少ないので、JISとかUSとか関係なくいままで使っていた通りの配置を再現するのは無理
気持ち
最適なキーマップと一番楽な傾きを見つけて最高の開発環境を得たい
Coffee, jQueryで書いていたElectronアプリをES6, React, Reduxで書き直した
ElectronベースのTwitterクライアント: Nocturn
ElectronでYoruFukurou風のTwitterクライアントを作った - k0kubun's blog の時にCoffeeScriptとjQueryで作っていたNocturnというTwitterクライアントがあり、これをES6, React, Reduxを使って書き直した。この記事ではその時に得た知見、感じた事を書いておく。
移行したスタックと移行時に感じたこと
あらかじめお断りしておくと、僕は普段はRubyでサーバサイドの実装や運用をやっている人であり、JavaScriptに関してはほぼ素人の意見なので、以下はReactとかRedux興味あるけどまだ触ったことないですみたいな人向けの内容になると思う。
CoffeeScript → ES6 移行
参考: 春からはじめるモダンJavaScript / ES2015 - Qiita
CoffeeScriptはオワコンか?
Sprocketsではv4からES6のサポートが入るんだけど、リリースされているSprockets 4はまだbeta2なので、Railsアプリ書いてる人からするとむしろES6がまだ始まってない。 けどCoffeeScriptの開発はもうあまり活発ではないし、普及すればコンパイルしなくても使えるようになるES6の方が未来が明るい感じがするので移行した。
decaf
decafでcoffeeのコードをES.next に書き換える - Qiita
自動変換が結構ちゃんと動く。よーし書き直すぞと思っても手で書き直してくのは大変で、今までCoffeeScriptで書いてきた資産が変換するだけで動いてくれるのはすごく助かる。これのおかげで移行は楽だった。
babel
babelとにかく最高で、めちゃくちゃ拡張性が高くできていて、プラグインを追加するだけでJavaScriptの文法を増やすことができる。例えば僕は引数のリストにケツカンマを書かないと気が済まない人間なんだけど、これはbabel-plugin-syntax-trailing-function-commas
を入れると使える。便利。
言語自体に関しては、CoffeeScriptでインデントをミスって壊れるみたいなストレスを感じなくて済むあたりは嬉しいけど、21世紀にもなってセミコロン書くのが普通な言語だし、まあどっちもどっちかなという印象。
jQuery → React 移行
比較対象がちょっとおかしい気がするけど、ここではビューのレンダリングをjQueryで生DOM操作してやるのかReact使ってVirtual DOMでやるのかみたいな意図。React、そのうち流行が過ぎて使われなくなるでしょとか思って放置してたけど意外とそうでもない雰囲気なので触ってみた。
Reactのメリット
- Componentを操作するインターフェースが限られるので、
- あるビューがどこから操作されるのか予測しやすい
- 結合が疎になり必然的に再利用性が高いコードが生まれる
Reactのデメリット
shouldComponentUpdate
*1の保守コストが高い- ちゃんと書かないとパフォーマンスのボトルネックになりうる
- ミスると、更新が必要でも描画されないなどの見つけにくいバグの原因になる
というのが一番印象が強かった。Reactで書くと保守性が高くなるみたいな空気を感じるけど、僕にはshouldComponentUpdate
を保守するコストがそれを相殺するように感じた。
Reduxの導入
Fluxフレームワークには、客観的に見て一番普及していて信頼性の高いReduxを採用した。 なんか@mizchiがReduxめっちゃdisってるんだけど、Redux触るまではこのまとめで言われてることがほとんど理解できなかったので*2、とりあえず彼が言ってることを理解したいというのもあって触っていた。
Reduxの良いところ
- Fluxを知らない初心者がとっつきやすい
- 実装の指針がそこそこあるのでSPAの設計に不慣れな初心者にはありがたい
- http://redux.js.org のドキュメントが親切だし、情報源も多い
- react-reduxが良い
- Reactの描画に関して自動でいい感じのチューニングをしてくれる
- バケツリレーが不要になる
Reduxに感じた不満
- ファイルの数が多くなるので疲れる
- ComponentのロジックをContainerに剥がしてくのやると結構大変
- 分割されたActionやReducerのファイルを追加する地味な作業が頻繁に発生する
- storeのstateに基づいてdispatchを行うContainerを書くのが大変
mergeProps
を書く必要があるんだけど、これ書くの辛い
- react-reduxを使っていると描画以外の部分が重くなることがある(後述)
いろいろ不満はあるけど、Reduxを導入したことで、Fluxやってない時に僕が適当に考えた設計よりはどこで何が行なわれてるかわかりやすくなったと思う。
ReactとReduxのパフォーマンスの問題
ReactとReduxで書き直したらすごい遅くなった
フルスクラッチ後、キー入力によってツイートのフォーカスを移動したりすると画面がめちゃくちゃ固まるようになった。あと、textareaに文字を打ち込むだけでもかなり重くなった。
@k0kubun そうですね。フリーズするまででもないんですけど, かなりメモリ使ってるときと同じ感じですね。たとえば僕が mahoushoujomadokamagika と普通に打ってると2-5文字ぐらい一度に遅れて表示される感じです。
— 野宿労仂者 (@akawshi) 2016年3月12日
HipChatも以前Reactで書き直されたんだけど、Reactで書き直された現在のバージョンはタブの切り替えがめちゃくちゃ重くて、そのHipChatと同じくらい重くなった。
量が多いComponentでeventをsubscribeしてはいけない
いろいろプロファイリングをやっていたんだけどなかなか原因がわからなくて、以下のツイートをした時点ではまだ勘違いしていた。
keydownイベントの処理のほとんどの時間をreduxのdispatchが消費していて、reduxやめたら良いのではという気がしてきた pic.twitter.com/pe3q5B5Gho
— k0kubun (@k0kubun) 2016年3月12日
実際にはdispatch
より2段ネストしたところのsetState
にかかる時間が問題になっていた。TwitterクライアントだとツイートComponentの数はかなり多くなるわけだけど、そのツイートのComponent全てがReduxのstoreのstateの変化をsubscribeしていて、ツイートの数だけsetState
されるのが重かった。
これはreact-reduxのconnect
というAPIを使ってContainerを作ると自動的に行なわれる処理なので、connect
をやめないといけない。数が多いComponentに接続するContainerはこういうコードを書いてconnect
なしで作るようにして回避した。
shouldComponentUpdate書くの辛い
connect
はshouldComponentUpdate
だけでなくrender
の中でもいろいろ最適化をやってくれるので、connect
をやめるなら自分でシビアにshouldComponentUpdate
を書かないと描画が遅くなってしまう。
React化したHipChatはチャットにいるユーザーのオンライン状況が更新されなくなったりする問題もあって、多分どこかのshouldComponentUpdate
がミスってて更新されてないんだろうなという感じがする。タブ切り替えの重さも含め、Reactのこの辛さがHipChatの品質を下げているような気がしているんだけど、最近のバージョンからユーザーのアイコンが表示されるようになったりとか機能が充実してきたのも確かで、Reactによって開発しやすくなったことによってこれが達成された可能性もあるし、一概に否定はできないなと思った。
結論
ReactやReduxは大規模なアプリケーションで開発速度を維持するのには一定の効果がありそうだけど、パフォーマンスが要求されるアプリケーションでの導入には慎重になった方が良い。
#CookpadTechConf 2016で「Railsアプリ開発環境の高速化」について話した
クックパッドの社員が発表するCookpad TechConfというイベントの第一回が今日行われ、「Railsアプリ開発環境の高速化」というテーマで話してきた。
開発環境の改善について
僕が技術部に入る前、サービス開発をやる中で一番不満だったのが開発環境のパフォーマンスだったので、技術部に配属されたころからこの仕事をやりたいと思っていた。
今回は先輩方が既に行っていた開発環境のパフォーマンスチューニング - クックパッド開発者ブログの一部を紹介しつつ、その続きとして自分がやってきたことを発表した。 業務で出した成果のうちいままで外部で発表したのはbyebugの高速化くらいだったので、普段僕がどんな仕事をやっているのか紹介する良い機会になった。
発表内容の補足
思ったより15分の枠で話せたことが少なかったので、発表内で話し足りなかったことについて書く。
libsassおすすめです
急いでて全然ちゃんと紹介できなかったんだけど、この発表の中で普段Railsアプリの開発をやっている人にとって目新しいことは多分libsassしかない。これはsassのC++実装で、今週sass gemからの移行が完了し、いれた次の日に同僚から突然速くなってよかったというフィードバックがあった。
libsassが良い理由
おすすめする理由は以下の4つある。
- とにかく速い
- Cookpadのcss全体のうち挙動に影響のある非互換が、関数による色の計算が少しズレることだけ
- gcc 4.6以上かclangならいまのところ普通にコンパイルできている
- Sprockets 4で標準サポートされるのでレールに乗ってる
導入効果
Sprockets 3だとなぜかlibsass以外のレイヤー*1が遅く、期待より効果が少し低かったのだけれど、それでも改善前のアセットプリコンパイルの71%がcssに費されていたので資料に書いた通りそこそこインパクトがあった。Sprockets 2だと cssを生成する時間が604秒から140秒に短縮される *2。
railsで使う場合は今はsassc-railsを使うと良い。なおsassc-rubyを普通に使うとscssのシンタックスエラーでscssでないコードがエラー画面に出てしまうのでパッチを投げていて、これを反映したフォークを運用している。
RubyのGC使います
発表内容的に完全に脱線なので質問されたら話そうと思っていた内容なんだけど、Cookpadでは例えば GC を止める・Ruby ウェブアプリケーションの高速化 - 2nd lifeにある通り1/23現在リクエスト処理中はGCが止まっていて、これを来週変える予定であるという話。
gctoolsがRuby 2.1でしか動かない
開発環境でOut-of-band GCもどき *3 を試していたとき、Unicorn::OobGC
のコードを読んでいたらRuby2.1以上ならtmm1/gctoolsがおすすめというコメントが書いてあった。そこで興味を持ってCookpadのRubyが2.0.0から2.2にアップグレードされた時gctoolsの検証を行ったのだけど、unicornのエラーがガンガン出たのですぐにロールバックした。
Ruby 2.2のRIncGCよさそう
それでgctoolsのissueを見てみたところ、どうもgctoolsの作者によると、Ruby 2.2で導入されたRIncGCのおかげでOobGCは不要であり、Ruby 2.2サポートはしないらしい。ちゃんとした説明はRIncGC jaを読んで欲しいのだけど、メジャーGCの長いマーク時間を解決するための改善が入ったようなので、普通にGC.enable
してOut-of-band GCもしない状態を本番の一部のサーバーで検証したところ、それほどパフォーマンスも劣化せず、かつCPU使用率が1割程度下げられそうな計測結果が得られた。
迷ったら健全な方
そこでインフラ部と相談し、「GC を無効化する運用は健全じゃないと考えています。Ruby の GC の改善がクックパッドにどう影響するのかというのをちゃんとコミュニティに還元するべき」という理由からGC.enable
の許可をインフラ部長のmirakuiさんからいただいたので、特に何も起こらなければ来週からGCが有効になる予定。*4 結果は何かの機会にコミュニティに還元されるでしょう。
2015年にやったこと
今年は卒論を書いて大学卒業後社会人になり、新卒研修を3ヶ月やり、部署に配属されて6ヶ月働いた。
以下、2015年にやったことをまとめる。
発表
2014年はどの勉強会にいっても誰にも知られてなくて寂しかったので、2015年はたくさん外部で発表するというのが目標だった。 今年は社外向けには10本発表した。
RubyKaigi 2015
1日目
k0kubun/hamlitの宣伝をした。発表練習をたくさんやっていろんな人に資料のレビューをいただいたので満足な発表ができた。関係者各位には本当にお世話になりました。LTじゃない発表するの初めてだったけど、いろんなことを伝えられるので長い発表の方がやってて面白いなあと思った。
2日目
頭がおかしくなって2日連続発表した。2日目も意外と評判が良くてホッとした。
Go Conference 2015 summer
k0kubun/ppの宣伝とメタプロの話をした。LTなんだけど、後でこの発表で僕を知ってくれた人に会ったのでGoConは大きくて良いなあと思った(小並)。
TokyuRuby会議09
k0kubun/rebuildとk0kubun/karabiner-dslの宣伝をした。とにかく上手い飯と酒が無限に提供される最高の会だった。
Itamae Meetup #1
普段itamaeを使ってて工夫していることを色々話した。itamae大好きな人がいっぱいいて、僕もこういうOSSが作れるようになりたいと思った。
Shibuya.rb 20150715
k0kubun/activerecord-precountの宣伝をした。結構気に入っているgemで、発表して以降割と良い評価をもらえているので良かった。
hikarie.go #4
k0kubun/go-ansiの宣伝と、GoをWindowsで動かすには結局自分でWindows APIを叩くしかないという話をした。つらい話。
マルチプラットフォームなインタラクティブシェルを楽に作る - Speaker Deck
その他
特に資料は公開してないけど、社外の人向けにはあと3回くらいLTしている。
- Cookpad x CyberAgent x DeNA 15卒エンジニア交流会
- Railsアプリ開発環境高速化の話をした。
- Donuts, DeNA, Yahoo, 弊社の交流会
- RubyKaigiのLTと同じくbyebugの話をした。
- Cookpad TechBar -vol.3-
- 学生時代と今やっていることについて話した。
ホッテントリ
今年はブログの読者とかQiitaのフォロワーがそこそこ増えたので嬉しい。 あと去年書いた奴だけど、うるう秒が挿入された時に Linux - topコマンドの使い方 - Qiita がやたらとブクマついた。
OSS活動
今年リリースしたOSS
Star | リポジトリ |
---|---|
★365 | k0kubun/md2key |
★304 | k0kubun/hamlit |
★102 | k0kubun/Nocturn |
Hamlitは最初の実装に1ヵ月、その後のフルスクラッチに2ヵ月かけてるけど、Nocturnは2日で作ったし、md2keyは2時間で完成した。でも書いてて楽しいのはHamlitみたいな奴なので、こういうのを作り続けたい。
それ以外だと去年作った奴を引き続きメンテしたり、誰かのOSSにプルリを投げたりしていた。
Itamaeで色々やってたらコミット権をもらえた。
あと今年は初めてCRubyにコミットして、以下の貢献はNEWSに入れてもらえた。
Ruby 2.3とRails 5を使っていたらテンプレートエンジンのHTMLエスケープが7倍くらい速くなるようにしておいたので、RubyとRailsのバージョンは最新にしておきましょう https://t.co/KZ76y0gi18 https://t.co/Fiu6HEXH3o
— k0kubun (@k0kubun) 2015, 12月 21
2016年は
入社後業務をやっていてわからないことだらけなので、2016年はインプット側に力を入れて地に足をつけたい。 アウトプットの目標としては、書籍になるようなOSSを作って自作OSSの単著を出したいとずっと思っているんだけど、逆算して計画を立ててどうにかなる話でもないと思っているので、引き続き自分が好きなこと、興味のあることをやって毎日成長するのを楽しむ生活を送りたい。
来年もよろしくお願いします。
#RubyKaigi 2015 でテンプレートエンジンの高速化について話しました
FamlとHamlitがなぜ高速かについて話しました
RubyKaigi 2015の1日目に、「High Performance Template Engine」というタイトルで発表しました。 @eagletmtさんが作ったFamlと、僕が作ったHamlitがなぜオリジナルのHamlに比べ高速か話しました。
発表は以下のような内容でした。
- テンプレートエンジンとは何か
- テンプレートエンジンの例
- テンプレートエンジンの仕組み
- パフォーマンス
- どのようにRubyのコードを速くするか
- ベンチマークがなぜ必要か
- プロファイリングの方法
- 改善の仕方
- 高速化のために何をしたか
- Famlがやったこと
- Attributeの最適化
- 高速なRuntime Attribute Builder
- Hamlitがやったこと
- String Interpolationのコンパイル
- 使われていない挙動の削除
- Famlがやったこと
以下、発表内で触れられなかったことについて書きたいと思います。
協力しています
同じ会社の人が別々に作って社内で競争しているように見えたかもしれないですがそれは気のせいで、Hamlitは完全に自分の勉強のための趣味プロジェクトとして作っていて、特に社内向けに作っていたわけではないです。
逆にFamlは社内のプロジェクトで使われているため、Famlのユーザーに影響のあるバグを発見した時に僕が直したりとか、Famlの開発初期の段階でKaminariが動くように対応したこともありました。
なので、業務レベルではHamlitを作った経験を生かしてFamlの開発に協力しているという状況であり、特に対立関係にあるわけではないというか、eagletmt先輩は会社では僕の教育担当です。
本家Hamlへの還元に関して
僕はOSSを改善する際は、社内モンキーパッチや野良forkを作るのではなく、元の実装を使わさせていただいたお礼としてupstreamに還元するべきだと思っていて、結構Haml本家を良くしたいという意思は強いです。
実際2ヶ月かけてHamlitをフルスクラッチしたときはパーサーを本家のものに置き変え、次のバージョンのHamlになるつもりで作っていたのですが、HamlにはTempleだと実装しにくい挙動があまりに多く、本家を一度に全てリプレースするのは途中で断念しました。
ただ作っている過程で、現在の挙動を完全に維持しつつ(FamlやHamlitまではいかないものの)ある程度高速化できそうなイメージがついたので、高速化の根幹となるTemple移行のプルリを出したのですが、まだマージされていないというステータスです。
今日Hamlコミッタの松田さんに聞いたところ、現在のメインのコミッタであるNormanしか基本的にマージボタンを押さない運用のため、彼が見るの待ちだそうです。
感想
eagletmtさんと一緒に発表の準備とかしたらテンプレートエンジンに関する面白い話や技術的に深い話が聞けるかなと思って一緒に発表しようと誘ったのですが、準備をしていくうち、本家の実装や仕様に対してどう思っていて何を考えてFamlを作っていたかが聞けてとても面白かったし、大成功でした。
その面白さの一部でも発表を聞いてくれた皆さんに伝わっていればよいなと思います。資料の修正や発表練習に協力いただいた皆さま、RubyKaigiを運営している皆さま、発表を聞いてくださった皆さま、そしてeagletmtさん、ありがとうございました!
#itamae_meetup で「itamaeを楽しく使うための工夫」について発表してきた
Itamae meetup #1 で発表した
趣味でちょくちょくコミットしているItamaeという構成管理ツールの第一回Meetupがあり、Itamaeについてどこかで話したいな〜とずっと思ってたので話してきた。個人的には、僕が作った機能のうち特に最近実装した以下のものを各位に使ってもらうことによって、Itamaeレシピの書かれ方やItamae自体をいい感じにしていきたくて発表した。
itamae generate cookbook
include_recipe
の.rb
省略bundle gem
の命名規則に従ったresource pluginの自動require
話した内容
普段5分だけ話すことが多くてあまり10分話すのには慣れてなかったのだけれど、ノリと勢いで以下のような雰囲気のことを口走っていたら10分経っていた。
去年の ISUCON は itamae でプロビジョニングした。今年は筋肉でやった #itamae_meetup
— Issei Naruta (@mirakui) 2015, 12月 9
「僕には長いコマンド打つの無理なんで」 #itamae_meetup
— c9e (@chiastolite) 2015, 12月 9
レシピからitamaeをぶっ壊せるのが素晴らしい #itamae_meetup
— 奈良阪 (@narazaka) 2015, 12月 9
“テンプレートエンジン書いてると gsub した瞬間に負け” #itamae_meetup
— Issei Naruta (@mirakui) 2015, 12月 9
遅いと思ったらシェルスクリプト書くしか無いww #itamae_meetup
— okumura takahiro (@hfm) 2015, 12月 9
itamaeも高速化してるし発表も超高速だった。 #itamae_meetup
— makoto takagi (@2celeb) 2015, 12月 9
落ちついて話したい
感想
いろんな人にItamaeが愛されてるのが伝わってきて、発表も面白いのが多くて良い会だった。弊社メンバーと発表を聞いてくださった皆さま、ありがとうございました!!
Hamlit v2.0をリリースしました & RubyKaigi登壇します
Slimより高速なHaml実装「Hamlit」
RubyでHTMLを生成するのにERB以外でよく使われるテンプレート言語にHamlやSlimがあります。haml *1 をやめて高速なslimに移行する人が多かったのですが、私はHamlのシンタックスの方が好きなので、slimが用意したベンチマークでslimより高速なHaml実装「Hamlit」を3月にリリースしました。 *2
これはslimが提供しているベンチマークでHTML escapeを有効にし *3、FamlとHamlitを追加したベンチマークの結果です。なおHamlitは完全にHaml互換の仕様ではなく、この非互換が有利に働いています。
互換性と性能が大幅に向上したHamlit v2.0
Hamlitの互換性の問題
Hamlitは最初のv0.1の時点で上記のようなベンチでSlimより高速ではあったのですが、以下のような欠陥がありました。
- HTMLエスケープがない
- エラーがコンパイル時に出る & ランタイムで出ても行番号がズレる
- コーナーケースで属性のレンダリングが重複したり、消えたりする
- 最適化の影響で、書き方が静的か動的かでHTMLのレンダリング結果が変わってしまう
- 空白除去オペレータの挙動がおかしい
社内の20,000個以上のテストケースがあるRailsアプリで使ってみたら5,000個くらいのテストが落ちる状態でした。 以前、これを地道に潰しながら致命的な仕様の見直しを行ったHamlit v1.0.0をリリースしました。v1のどこかのバージョンでそのアプリの全てのテストが通っています。
それでも上記の問題が完全に潰せていたわけではなく、保守性的にも様々な問題を抱えていたため、2ヶ月かけてフルスクラッチを行い、大幅に互換性を改善したHamlit v2.0をリリースしました。
もう一つのHaml実装「Faml」との戦い
Hamlitより先にリリースされたhamlより高速なHaml実装としてFamlがあります。 slimが提供しているベンチマーク(をFamlが公平に参加できるようにしたもの)ではHamlitの非互換性が有利に働きHamlitの方が高速に動作しますが、その他の多くのベンチマークではC拡張を持っているFamlの方が高速に動作する状態でした。
Famlが恣意的に用意したベンチマークでは、1.35倍程度Hamlitの方が遅い状態でした。 さて、 v2.0ではHamlitもC拡張を用意 してC言語レベルでの最適化を行い、上記のような動的なテンプレートでも以下のようにHamlitの方が高速に動作するようになりました。 (Travisでの結果)
hamlit2 v2.0.1: 24225.3 i/s (0.041ms) faml v0.7.0: 19405.8 i/s (0.052ms) - 1.25x slower hamlit1 v1.7.2: 10450.2 i/s (0.096ms) - 2.32x slower haml v5.0.0.beta.2: 5260.5 i/s (0.190ms) - 4.61x slower
でも昨日FamlがC++になって速くなってるので、明日には抜かれているかもしれません。
静的解析エンジン
FamlはRubyの式が静的であればコンパイル時にレンダリング結果を確定させる機構を持っているのですが、Hamlitのそれはかなり貧弱のため、そういったケースでもレンダリング速度で劣っていました。 真面目に実装しなおしたため、上記のテンプレートの値をFamlやHamlitが解析可能な位置にズラしたベンチマークでは、 本家hamlの569倍 の速度が出るようになりました。 (Travis)
hamlit2 v2.0.1: 3639877.1 i/s (0.000ms) faml v0.7.0: 1434853.5 i/s (0.001ms) - 2.54x slower hamlit1 v1.7.2: 17734.8 i/s (0.056ms) - 205.24x slower haml v5.0.0.beta.2: 6388.2 i/s (0.157ms) - 569.78x slower
コンパイル速度の問題
これまで出てきたのは全てレンダリング速度に関するベンチマークですが、本来はコンパイル速度も全体のパフォーマンスに影響し得ます。 Webサービスではあるテンプレートのコンパイル回数に比べてレンダリング回数の方がかなり多くなるためコンパイル速度は無視できますが、Hamlitはコンパイルが非常に遅く、レンダリング回数がそれほど多くないタスクで使うには必ずしもHamlitをオススメできない状態でした。
これはhamlのリポジトリにあるstandard.hamlという少し大きめのテンプレートですが、コンパイル速度でFamlに勝てるようになりました。(Travis) コンパイル時に最適化をあまり行わないhamlにはまだ勝てていません。
haml v5.0.0.beta.2: 297.5 i/s (3.361ms) hamlit2 v2.0.1: 152.6 i/s (6.551ms) - 1.95x slower faml v0.7.0: 139.4 i/s (7.173ms) - 2.13x slower hamlit1 v1.7.2: 78.0 i/s (12.827ms) - 3.82x slower
RubyKaigiでどうやって速くしたか話します
RubyKaigi 2015に、Famlの作者である @eagletmt さんと一緒に登壇します。一つの枠で二人のアイデアが聞けるのでお得です。 どう速くしたのかの詳細はあえてこの記事では書きませんでしたが、何を考えて作ったのかとかも含めRubyKaigiで話す予定です。是非聞きに来てください!!
*1:言語に関してはHaml、gemに関してはhamlで表記します
*2:Hamlit v0.1.0リリース時の記事: http://k0kubun.hatenablog.com/entry/2015/03/31/004021
*3:元のベンチではSlimもERBもRubyのスクリプトに対してHTML escapeを行わないオペレータを使っているんだけど、HamlにはHTML escapeされるオペレータを使っているのでSlimやERBでもHTML escapeされるように直してる。HTML escapeしない側に倒さないのは、ベンチに加えたいFamlにはHTML escapeしないオプションがないのと、Railsの標準だとescapeされるため。