Ruby コミッターになりました
m_sekiさんとhsbtさんの推薦で、ERBのメンテナとしてRubyのコミット権をいただきました。
以下が初コミットです。
普段テンプレート言語Hamlの高速化やその更に高速な別実装Hamlitの実装をやっていてテンプレートエンジンの高速化に知見があり、ちょこちょこERBにも知見を還元したりしていたのですが、一昨日ふとERBの生成コードのiseqを眺めていた時に気付いてパッチを送った後、「入れるのめんどくさいし、ERBのコミッタやりますか」とお声がけいただいた形です。
というわけで、引き続き主に高速化の方面でERBのメンテナンスをやっていきますが、他にも以前僕がC拡張にしたHTMLエスケープとか、広い範囲でパフォーマンス改善をやれたらいいなと思います。
さっきのパッチに関連してto_sもメソッド呼び出しをバイパスできるようにしたら結構いろんなものが速くなるんじゃないかなと思ったんですが、ベンチを取ってみたところ効果が微妙だったので、コアの改善は難しいなあとか考えています。 *1
どうぞよろしくお願いいたします。
*1:前提として僕はメソッド探索をしなくなれば速くなると思っていて、メソッドキャッシュの影響はありそうなものの String#concat と String#to_s の呼び出しの間にどういう違いが発生するのかちゃんと調査していないのでわかっていない。
Treasure Data に入社しました
3月から Treasure Data で働いています。入社初日からタスクをアサインされ、RailsでAPIの開発をやりました。
なぜ Treasure Data に転職したのか
前職もやりたいことができて優秀な同僚に囲まれ文句ない環境だったのですが、アルバイト入社から数えるともう3年半が経っていたし、入社前にイメージしていたような仕事も大体経験できていました。
そのままいても良かったのですが、ある程度の間隔で新しいことに挑戦しないと成長は止まってしまうと思っているので職場ごと変えることも考え始め、以下のような観点から Treasure Data に転職することに決めました。
- エンジニアがユーザーになる仕事をしてみたい
- 僕は開発者が使うツールを作るのが好きで、技術を売っている会社の方がそういうものを作る機会が増えそう
- 正直あまりエンジニアリング以外に興味がないので、一般の人を対象にしたサービスを作っている会社より、エンジニアがユーザーな方が会社のビジネスに興味が持てる
- 前職だとあまりやらなそうなことに挑戦する選択肢が増えそう *1
- アメリカ (シリコンバレー) で働くチャンスを増やしたい*2
- 上記を踏まえて今後のキャリアを考えると、日本にいるよりはアメリカにいた方が楽しい人生が送れそう*3なので、チャンスがあれば移住したい
その他、転職先に求めていたこと
市場調査のため転職ドラフトに登録していた時にいろんな企業様から声をかけていただいたきとてもありがたかったのですが、上記に加え下記のようなことを考慮し決めさせていただきました。
- 自分が興味があったり得意な分野で尊敬できる人が多くいる
- 積極的にOSS活動や外部への発信をしている
- 流石に全部オープンにするべきとは思ってないけど、何かすごい成果を出せたら社外に自慢する機会がないとモチベーションが維持しにくいと思っていて、そうしている人が多い会社の方がきっと楽しく仕事をしてるんだろうなと思う
- 待遇が良い
- 技術的な成長だけが人生じゃないし、総合的に見て幸せになるにはやっぱりお金も必要
気持ち
偉そうなことをいっぱい書いていますが、まだまだとても経験の浅い身ですので、早く成果を出して同僚の方に認めていただけるようがんばります。
Hamlを3倍速くした
Hamlコミッターになった
RubyKaigi 2015で「Hamlは遅いしメンテされてないので使わない方がいい」と言ったところ、じゃあ自分でメンテして速くしろということになりコミッターになった*1。
当時から2年ごしなのは、当時のHamlのオーナーがあまりアクティブではなく、最近a_matsudaさんがオーナーになったため。
HamlのTemple化・高速化を行った
Templeというのは、テンプレートエンジンをパイプライン的に構築するためのフレームワークで、テンプレートエンジン用の中間表現とその最適化エンジンを持つ。実装をTempleベースにすると、SlimやHamlitに使われているような中間表現を使った最適化を適用しやすくなる。
コミット権をもらったので、RubyKaigi 2015でマージされないと言っていたパッチを自分でマージし、コード生成とattributeのコンパイルをTemple化しながら高速化した*2。 それ以外にもいろいろ遅い原因を調べて改善した。
Hamlはどのくらい速くなったのか
Haml4 vs Haml5
つい昨日、それらの高速化を含むHaml 5.0.0.beta.2がリリースされた。
同じgem同士であるHaml4とHaml5を同時に比較するためのリポジトリを作っていて、これはslim-template/slimに入っているベンチマークからHTMLエスケープの回数が違う問題を修正したもの。
Ruby 2.4.0でHaml 4.0.7と現在のHamlのmasterを比較すると以下のようになる。 (Travisでの結果)
Rendering: /home/travis/build/k0kubun/haml_bench/templates/slim_bench.haml Warming up -------------------------------------- haml 4.0.7 1.595k i/100ms haml 5.0.0.beta.2 5.497k i/100ms Calculating ------------------------------------- haml 4.0.7 17.011k (± 9.9%) i/s - 84.535k in 5.031171s haml 5.0.0.beta.2 63.100k (± 1.8%) i/s - 318.826k in 5.054222s Comparison: haml 5.0.0.beta.2: 63100.1 i/s haml 4.0.7: 17010.5 i/s - 3.71x slower
というわけで、masterだとHaml4の3.71倍速くなっている*3。本当はmasterじゃなくて5.0.0.beta.2にしたいんだけど、あるバグ修正の際に誤って遅くしてしまったケースがあり、その対応を入れたリビジョンにしているので注意。5.0.0.beta.2だと3.28倍とかになる。
vs Slim, Faml, Hamlit, Erubi…
もともとslim-template/slimのベンチマークがテンプレート言語を超えて比較するベンチマークだったため、Slimなどとの比較もでき、以下のような結果になる*4。(Travisでの結果)
まあまあ縮まったけどまだ遅いですねという感じ。やっていくぞ。
Erubiとは
これは完全に余談だけど、ErubiというERB実装をご存知だろうか。Railsで長らく使われていたErubisは、今年Erubiに置き替わった。
Erubisはかなり前にメンテが止まっていた分frozen string literalが使われていなかったりして遅いんだけど、それがErubiでは解消され*5、ついうっかり僕もErubiのHTMLエスケープを速くしてしまったため、Hamlitとほぼ変わらないパフォーマンスが出るERB実装になっている。
どうやってHamlを速くしたのか
僕は自分のHaml実装を持っているので正直Haml使わないのに何故高速化をやっているかというと、何が原因でHamlが遅いのかに興味があったからである。というわけで、同じ興味を持っている人向けに、どうやって速くしたかを書いておく。高速化の手法自体はRubyKaigi 2015で話したので、以下では個別の話だけ書く。
以下はベンチマークの結果を見て効果があったと思われる順になっている。
1. attributeレンダリング用生成コードの最適化 haml/haml#904
このパッチが最も高速化に貢献しており、その分書くのも一番大変だった。簡単に言うと、以下のテンプレートは
.foo#bar{ class: 'baz', data: 'a' * 3 }
いままでは以下のようにコンパイルされていたが、
_hamlout.push_text( "<div#{ _hamlout.attributes({"class"=>"foo", "id"=>"bar"}, nil, class: 'baz', data: 'a' * 3 ) }></div>\n", 0, false, )
以下のようにコンパイルされるようにした、ということである。
_hamlout.buffer << "<div class='baz foo'".freeze _haml_attribute_compiler1 = 'a' * 3 case _haml_attribute_compiler1 when Hash _hamlout.buffer << _hamlout.attributes({ "data".freeze => _haml_attribute_compiler1 }, nil).to_s when true _hamlout.buffer << " data".freeze when false, nil else _hamlout.buffer << " data='".freeze _hamlout.buffer << ::Haml::Helpers.html_escape(_haml_attribute_compiler1) _hamlout.buffer << "'".freeze end _hamlout.buffer << " id='bar'></div>\n".freeze
_hamlout.attributes
って何、と思うかもしれないが、これはとにかく遅いメソッドであり、これを呼ばなくすると速くなる*6。コードの通り、動的な式('a' * 3
の部分)の結果がHash
じゃない限りはこの遅いメソッドが呼ばれず、また他の場所では可能な限り事前に連結された状態でバッファにconcatされるので、速い。
これをやるためには、ものすごく複雑なHaml attributeの仕様を正確に把握している必要があり大変だった。みんなもこの記事を5秒くらい見て欲しい。
このパッチで追加したHaml::AttributeCompiler
は、互換性を一切崩さずに高速なコードを生成しようとしてものすごく色々なことを考えて書いてあるので語りたいことがたくさんあるんだけど、長くなるので何かのLTのネタとしてとっておく。
2. Haml::Bufferのオプション向けのオブジェクト生成を減らした haml/haml#897
Hamlのレンダリングコードには必ず以下のコードが最初に入っていた。
_hamlout = @haml_buffer = Haml::Buffer.new( haml_buffer, { :autoclose=>["area", "base", "basefont", "br", "col", "command", "embed", "frame", "hr", "img", "input", "isindex", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"], :preserve=>["textarea", "pre", "code"], :attr_wrapper=>"'", :ugly=>false, :format=>:html5, :encoding=>"UTF-8", :escape_html=>true, :escape_attrs=>true, :hyphenate_data_attrs=>true, :cdata=>false } )
これが何を意味するかというと、レンダリングする度に毎回同じString 25個・Array 2個・Hash 1個を生成していることになる。毎回同じならこんなに渡す必要はないので、デフォルトとは違うオプションのみ渡されるようにした。そのため、普通に使っていれば、以下のようなコードが生成される。
_hamlout = @haml_buffer = Haml::Buffer.new(haml_buffer, {})
余計なオブジェクトが作られなくなるので速くなる。
3. attribute値のpreserveの無効化 haml/haml#903
以下のテンプレートは、
%p{ data: "foo\nbar" }
Haml4だと以下のようになるんだけど、
<p data='foo
bar'></p>
Haml5では以下のようになるようにした。
<p data='foo bar'></p>
これに関しては完全に仕様を変えているので全く褒められた改善ではないのだが、このpreserve
と呼ばれる機能はとても遅い。遅いのは、ただでさえgsub
が遅いのにそれ以外にもいろいろやっているからである。
SlimやFaml, Hamlitは後者の挙動で問題なく動いているし、入った時のコミットを見ても何で必要なのかよくわからん仕様なので、遅くなるデメリットの方が大きいと判断し削った。何か意見のある識者は声をかけてほしい。
4. 文字列リテラルのfreeze haml/haml#893
あまり解説する必要はなさそうだけど、静的な文字列をバッファに渡す時に必ず.freeze
がついた状態で文字列を作るため、レンダリング時に文字列オブジェクトが生成しなくて済むというもの。
Temple化をすると静的な文字列は全て:static
という中間表現になるため、これに全部.freeze
をつけていくのが簡単になる。
5. HTMLエスケープの高速化 haml/haml#902
Ruby 2.3でRuby本体のHTMLエスケープメソッドを高速化したので、gsub
ではなくそっちを活用するようにした。その際、古いHamlのものすごく複雑なエスケープの挙動が邪魔になるので、FamlやHamlitと同じごく普通の挙動にした。そこは後方互換性のない変更になってしまうが、流石にこれで困る人はいない気がしている。
HamlitよりHamlを使った方がよくなる?
ならない。Hamlitが速いのはHaml::Buffer
が必要な機能を諦めているのとC拡張があるからで、少なくとも前者をやるのはHaml::Helpers
を消せない都合かなり難しいし、後者はまだボトルネックではないのでやらなそう。
というわけで、Haml特有のヘルパーを使っている人などがHaml 5の想定ユーザーになるが、何らかの理由でFamlやHamlitへの移行を諦めた人には普通に嬉しいリリースなんじゃないだろうか。
僕も最終的にはみんなhaml.gemを使えばいい状態にはしたいが、そう簡単に後方互換性は切れるものじゃないと思うので、結構先になる気がする。
気持ち
FamlやHamlitではなくHamlを使っているアプリがある人はHaml 5.0.0.beta.2を試してみて欲しい。
*1:これは冗談で、a_matsudaさんからお誘いがあり、僕も興味があったのでやりますと言い、メンテをさせていただけることになった。
*2:余談だけど、HamlのTemple化をやりながらTempleを直していたところ、Templeの方のコミット権もいただいた。
*3:僕が変更を加える前のmasterは1.09倍くらい https://travis-ci.org/k0kubun/haml_bench/jobs/205696677
*4:Hamlは先ほどと同じリビジョンで、Erubiも現在のmasterである ad41891 にしてある
*5:なお遅かったのは素のErubisの話で、もともとActionViewはErubisを魔改造していたためRails上ではこの問題はなかった
*6:真面目に説明すると、改善後のコードがコンパイル時に済ませている文字列連結を全部レンダリング時にやっているのが_hamlout.attributesである
Linux デスクトップ環境 2017
Linux デスクトップ環境 2016 - eagletmt's blogの人に影響を受けて自作PCでLinuxデスクトップを使い始めてから約1年半が経ち、僕の使う環境が一通り満足な状態になったので今どういう構成なのか書いておく。
僕はKeynoteを使う時とか会社のマシンでmacOSも割と使う都合、基本的に操作性がmacOSに近くなるようにしているので、macOSからLinuxに移行したい人の参考になるかもしれない。 *1
そもそも何故Linuxデスクトップを使っているのか
「苦労してmacOSに近づけるくらいなら最初からmacOS使えばいいじゃん」と言われそうだが、今この瞬間は大体以下の理由でLinuxデスクトップを使っている。
- 趣味で作ったスペックが高めの自作PCにmacOSが入れられない *2
- 最新のmacOSではKarabinerが使えないが、Linuxでは自作のキーリマッパーが使える
- Kababiner-Elements+keyhacに移行したけど、keyhacはたまにリマップされないことがあり困る
- 仕事でサーバー用途にLinuxを使うことが多いのでLinuxに触る機会を増やしたい
- パッケージ管理システムとか、strace, perfみたいにmacOSでは使えないツールの話
- MacBookが高いので今後ノートPCを買う時にThinkpadとかにしたい
現在のLinuxデスクトップ環境
ディストリビューション: Ubuntu GNOME 16.04
去年はずっとArch Linuxを使っていたんだけど新年になってから気分転換にUbuntu GNOME 16.04を使っている。上述の「サーバー用途にLinuxを使う」勉強のため、サーバーやDockerによく使っているUbuntuにしている。
ArchはArchWikiが充実してるのと常に最新のパッケージが降ってくるのが便利だけど、パッケージをアップグレードするとたまに壊れる。Ubuntuはそこは安定しているイメージ*3だが、その分パッケージで普通に入るソフトウェアが基本的に古いので開発者にとっては多分Archの方が使ってて楽しい。
デスクトップ環境, ウィンドウマネージャ: GNOME, Mutter
普通のUbuntuだとデスクトップ環境としてUnityが入るんだけど、compizのウィンドウ切り替えがあまりにも遅くて苦痛だったのでGNOMEにした。ディストリビューションがUbuntu GNOMEなのはそのため。
タイル型WMに興味があったのと動作が軽いので最初の半年くらいデスクトップ環境を使わずawesomeやxmonadを使っていたけど、僕はターミナルを半透明にしてTwitterとブラウザに重ねてVimとshellとTwitterとブラウザを同時に見るということをやっていて、ウィンドウを重ねるのがタイル型WMと相性が悪いのでやめた。
動作の軽さで言うとデスクトップ環境にxfceは試したことがあるが、僕は4KディスプレイをHiDPI(x2.0)で使っていて、HiDPIの対応がGNOMEに比べ微妙なので使っていない。GNOMEは綺麗かつまあまあ軽快なのでおすすめ。
キーリマッパー: xmodmap, xremap
ErgoDox以外のキーボードを使う時にキー単位のリマップはxmodmapを使っていて、キーの組み合わせのリマップにはLinux向けの最強のキーリマッパーを作った - k0kubun's blogに書いたxremapを使っている。
xremapを使ってターミナル以外の場所でのEmacsバインディングを有効化*4していて、これがとても捗る。普通に設定するとデフォルトのC-a(全て選択)等が潰れてしまうが、macOSのCmd-aのようにAlt-aをC-aとして使っていて、大体macOSと同じように操作できる。xremapはDSLがシンプルなのでそういう複雑な設定を書きやすいのが利点だと思う。
ターミナル: rxvt-unicode
最初にrxvt-unicodeを選んでから他のを試していないけど、macOSでiTermを使っていた時に比べると高速に感じるし、特に困ることがないのでそのまま使っている。
日本語入力: ibus-skk
Linuxデスクトップを始めた時にuim-skkが何故か動かなくてworkaroundとしてibus-skkを選択しそのまま使っている。ibusはたまになんか困るような気がする*5けどまあAquaSKKとかと同じ感覚で普通に使える。
ファイラ, ビューア, スクリーンショット: Nautilus, eog, gnome-screenshot
特にこだわりがないのでGNOMEに標準添付のものを使っている。スクリーンショットにImageMagickのimport(1)
を使うと画像に枠線が入ってしまうことがあるのでそれはやめた。
フォント: Ricty Diminished
ArchだとRictyを使っていたが、UbuntuだとRictyを入れるのが面倒なのでRicty Diminishedを使っている(雑)。4KディスプレイかつHiDPIだとフォントに関わらず文字が綺麗に見えるので金パワーは便利。
ブラウザ: Google Chrome
ほとんど説明不要だと思うけど、インストールが楽なchromium-browserを使っていないのは、「論理行単位の移動」を使うためにgtkrcのparagraph-endsを活用したくて.gtkrc-2.0が使える方を選んだため。
Twitterクライアント: Nocturn
LinuxだとYoruFukurouが使えないので、ElectronでYoruFukurou風のTwitterクライアントを作った - k0kubun's blog *6に書いたNocturnを使っている。自分好みに作ったので全OSで常用していて、そこそこメンテしている。
パスワードマネージャ: 1Password
他にLastPassとKeePass(X)を微妙に試したんだけど、今節約中なのでLastPassに課金したくなかった*7のと、KeePass(X)はHiDPI対応が微妙で1Passwordと比較して特にメリットがなかったので、結局使い慣れている1Passwordを渋々wineで使っている。インストールは面倒なので自動化してある。
ブラウザ拡張も動くしDropboxでVaultを同期すればまあ普通に使えるが、挙動が遅めなのでLastPassへの移行も考えている。
音楽プレーヤ: Google Play Music
iTunesから移行した。たまたまiTunes Storeで買ってた曲が全てm4a(DRM free)だったので、曲のフォルダをまるごとアップロードするだけで移行が完了した。iTunes Matchと違って50,000曲まで曲のアップロードが無料だし、iOSアプリのクライアントも使いやすいので普通に便利だと思う。
気持ち
UbuntuとかGNOME使ってて大分ミーハーな感じだけど普通に使いやすい。MacBook高いしやめたいと思っていて、iOSアプリ作るみたいな用事もないみたいな人はLinuxデスクトップは試す価値があると思う。
*1:実際の設定手順は http://qiita.com/k0kubun/items/d2359ad51cf1cf783f4d に書いてメンテしている。自動化しない方が運用コストが低いものは手で入れている。
*2:スペックが高いので普段使いしたいが、自作している以上Appleのハードウェアではないので利用規約上macOSを入れてはいけないという話 id:otituke
*3:Ubuntuを使ってる期間はまだ浅くて実際はどうなのか知らないので、あくまでイメージ
*4:ちなみに、C-aがC-Alt-aになっているのは、これを単にHomeにすると表示行移動になってしまうからで、gtkrcと連携して論理行移動できるようにしている dotfiles/.gtkrc-2.0 at 98aede78a0dc2c30f24d34e1452498d0d1f7fe85 · k0kubun/dotfiles · GitHub。これをgtkrcだけでやると、例えばC-kがGitHubに奪われるので、一度Altつきにリマップすることでそれを回避している。
*5:ちゃんと現象と原因を分析できてないので書くのは控えておく
*6:当時の記事と違い、今はデザインはオリジナルになっている
*7:1Passwordは既に買い切りのライセンスを持っている
2016年にやったこと
クックパッドで働くのは4年目、社会人としては2年目になった。2015年にやったことと同じフォーマットでまとめておく。
発表
今年は6本発表した。去年RubyKaigi前後にいろいろ集中してて死にかけたので、2か月に1回というのが僕にとってはちょうど良いペースだと思う。
RubyConf 2016
今年は海外のカンファレンスで登壇してきたというのが一番大きいと思う。英語は一応どうにかなったけど、うまい表現ができずもどかしいことがあるのでもうちょっとマシにしたい。あとこの成果で初めてクックパッドの業務にmrubyが導入されたように思う。
RubyKaigi 2016
100%クックパッドの業務時間で作ったOSSを題材に、今年は1人でRubyKaigiに登壇した。Barbeque自体はまだまだ改善点があるものの、ECSを活用してジョブ単位のオートスケールができ、マルチテナントで運用コストが低いシステムを作って実際に導入されるところまで持っていけたのはよかった。
Cookpad TechConf 2016
今年から弊社も社の技術カンファレンスをやるようになったので、アルバイト時代からずっとやりたいと思っていた仕事とその成果について話した。クックパッドの開発基盤グループにいると、難しい問題のデバッグや高速化にじっくり取り組めるのが楽しいと思う。
Rails Upgrade Casual Talks
大変ありがたいことに、発表しませんかというお誘いを初めていただいた。Rails 5が出る前だったので、cookpad.comのRails 4.1→4.2の話をした。
How to safely upgrade Rails // Speaker Deck
TokyuRuby会議10
Rails 5が出たのに合わせて、僕が送っていたパッチの紹介をした。東急は高速で喋っても誰にも怒られないのが楽しい。
My patches for Rails 5 // Speaker Deck
Roppongi.rb #2
toshimaruさんにお誘いいただいてMItamaeについて話した。何かOSSを作って、便利さを発表して、いろんな人に使ってもらう、という体験はとても楽しいので今後も続けたい。
MItamae Hacking Guide // Speaker Deck
ホッテントリ
ブログは1ヵ月に1記事くらい書くのを意識しているけど、はてなブログが11記事、Qiitaが6記事という感じだった。「発表」と重複があるけどブクマを貰えたのは以下の通り。
いまだに400 users越えたことないので何かもっとバーンて感じの成果欲しい。
OSS活動
今年リリースしたOSS
Starだけ見ると去年に比べるとウーンという感じ。mitamaeを使ってくださっているみなさまありがとうございます。
Star | リポジトリ |
---|---|
★65 | k0kubun/mitamae |
★64 | cookpad/barbeque |
★48 | k0kubun/xkremap |
★46 | k0kubun/itamae-go |
今年は↑でmruby, Docker, Go, Xlibあたりを触っていて、他にhescapeでSIMDプログラミングで少し遊んだのと、もうちょっとC言語に強くなるためにCでCコンパイラを実装するのを途中までやり、そこでLLVMも触った。
今年活発にメンテしていた既存OSS
Star | リポジトリ |
---|---|
★558 | k0kubun/md2key |
★407 | k0kubun/Nocturn |
md2keyは、ずっと欲しかったけど実装できなかったnested listが作れたのが大きい。あとプルリをいただいて、シーケンス図、表、発表者ノートなどがサポートされた。 Nocturnはデザインを変えReact/Redux化してから300くらいStarが増えた。既存の設計を真似たことでメンテが楽になった。
毎年新しいプロダクトをリリースしていきたいと思っているけど、既存のものを改善していくのも大切にしたい。
contribution
今年はmrubyを触り始めていろいろ踏んだのでmruby周りにいろいろ貢献した気がする。RubyとかRailsはもうそこまで不満がないけど、mrubyの方はまだまだやれることがたくさんありそう。mruby本体にも1回だけ貢献できた。
@k0kubun さんがmrubyにfreeze実装してくれた。圧倒的仕事の速さ
— Yukihiro Matsumoto (@yukihiro_matz) 2016年12月12日
ポッドキャスト
timakinさんに誘われてboot.fmというポッドキャストを始めた。4話配信済み。2人でやっていても、ネタと収録する時間とゲストを呼ぶ人脈とコミュ力がなくてかなり大変で、miyagawaさんはすごい!!!!という気持ちになる。一方、自分がホストをやると、話したいことを自由に話せる楽しさがある。
2017年は
- Ruby以外で手になじむ言語を増やしたい
- 今後もコードを書き続けたいが、このままだとRuby以外で仕事できなくなり失職しそう
- 業務で使って困ることがないレベルまで英語の語彙や表現力を向上したい
- ドキュメント読むのとOSS活動をする時に使うし、いつか海外でも働けるようにしたい
- 執筆活動をしたい
- というかやってるんだけど、ちゃんと出すところまで持っていけるようにしたい
私生活と両立して楽しくやれればいいなと思っています。来年もろしくお願いします。
Linux向けの最強のキーリマッパーを作った
X Window Systemで動作するキーリマッパー「xremap」を作った
- 2017/1/9追記: xkremap→xremapにリネームしました
- 2021/12/21: Rust化に伴いアーキテクチャを刷新し、より多くの機能と環境がサポートされました: Linux用キーリマッパーxremapをRustで書き直した - k0kubun's blog
僕はKarabiner用のRuby DSLを作ったりそれを使って大量の設定を既述する程度にはKarabinerのヘビーユーザーなんだけど、デスクトップ環境にLinuxを使い始めてからもう1年以上経つ今でもLinux環境で使えるKarabiner並にリッチなキーリマッパーを見つけられずずっと不便していたので、ユースケースを満たす最低限のものを自分で作った。
ちなみにX用であって別にLinuxの何かに依存しているわけではないので、タイトルは釣りである。
これは何
RubyのDSLかつシンプルなキーの指定方法によりキーリマップを設定することができる。例えば、以下の設定ファイルを書いてxremapに渡す*1とターミナルやEmacsの外でもEmacsライクなキーバインドが使えるようになる。
remap 'C-b', to: 'Left' remap 'C-f', to: 'Right' remap 'C-p', to: 'Up' remap 'C-n', to: 'Down' remap 'C-a', to: 'Home' remap 'C-e', to: 'End' remap 'C-k', to: ['Shift-End', 'Ctrl-x']
また、xbindkeys等のツールより優れている点はアプリケーション*2ごとのキーバインドを設定できるところにある。普段Emacsバインディングを使っていると、Slackが割りあてるC-k
とコンフリクトするわけだけど、例えば以下のように書くとSlackでのみ下記の設定を適用し問題を回避することができる。
window class_only: 'slack' do remap 'Alt-n', to: 'Ctrl-k' end
あと、任意のキーからシェルを起動することができるので、ランチャーとしても使える。
remap 'C-o', to: execute('nocturn') remap 'C-u', to: execute('google-chrome-stable') remap 'C-h', to: execute('urxvt')
補足だけど、ある単一のキーを別のキーにリマップするみたいなことはXmodmapとかでやったほうがいいと思う。その方が多分速いので。僕はErgoDoxのファームウェアでそういうリマップはできるので不要なんだけど、xremapはEmacsバインディングみたいな何らかのキーの組み合わせをキーの組み合わせやシーケンスに変換したい時に使う。
なぜ作ったのか
GitHub等でキーバインドが奪われるし、その度にJavaScriptを読みたくない
GitHubというサイトはC-k
, C-b
を奪ってくる。社員は誰もEmacsを使ったことがないに違いない。
僕はいままでEmacsバインディングはinclude "/usr/share/themes/Emacs/gtk-2.0-key/gtkrc"
によって設定していたんだけど、これだと普通にブラウザに奪われるため、user.jsを書く必要があって面倒だった。
xremapを使うとXのルートウィンドウレベルでキー入力イベントをフックしてリマップするので、例えばGitHubのコメント欄とかでブラウザにキーバインドが奪われない点が便利。
rbindkeysがRuby >= 2.2で動かない & wineを使うとSEGVする
類似のツールにrbindkeysというものがあり、というかほぼ要件を満たしていたので長い間使っていた。が、上述したようなランチャーの用途には使えず別のツールで解決していたのとか、単純に不安定なのとか、DSLが複雑などの理由でずっと自分向けの奴を作りたいと思っていた。仕様も内部実装も仕組みも全て僕の好みに変えたrbindkeysがxremapといえる。いままでお世話になりました。
rbindkeysと比較して、xremapは下記のような違いがある。
- キーイベントの取得やリマップにLinux Input Subsystemを使わないので、Linuxじゃなくても(多分)動く & rootじゃなくても実行できる
- キーボードを抜き差ししてもそのまま使える
- DSLの違いにより、キーの指定がシンプルに書ける
C-k
とかのリマップの挙動が安定している
あと、この場合別にRubyでもmrubyでもどっちでもいいなあとは思ったんだけど、最近慣れてきたmrubyを採用している点も異なる。
macOSと違ってCommandキーがないから色々コンフリクトするのを解決したい
コピーやペーストがC-c
, C-v
などControlに割りあてられているため、例えばEmacsのC-f
とブラウザの検索のC-f
が被ってしまっていた*3。
アプリケーションごとにキーバインドを変えられる程度にはリッチかつ十分に安定したキーリマッパーがあると、macOSみたいにCommandキー相当のキーを作ることができる。会社で貸与されてるノートPCがMacBookなので今でもmacOSは使うのだけど、できれば複数の環境の差異をなくしたいというのがあった。
気持ち
デスクトップ環境でLinuxを使っている人はNocturnとxremapをよろしくお願いします。
*1:systemdとかで起動するのがよい xremap/xremap.service at 6e8e1f21285ecedfa7ac88d703ad80d25a2699dd · k0kubun/xremap · GitHub
*2:正確にはウィンドウのclass
*3:gtkrcによる設定だと、テキスト入力欄かどうかで挙動が変わっていたが、検索とかは常に使えて欲しかった
RubyConf 2016 で話してきた & MItamae v1.0.0をリリースした
RubyConf 2016で登壇してきた
2016/11/10〜11/12にアメリカのオハイオ州シンシナティでRubyConfというイベントがあって、Ruby DSLによって設定できるCLIツールをRubyインタプリタやgemの存在に依存しないシングルバイナリとして実装するための知見を「Evaluate Ruby Without Ruby」というタイトルで発表してきた。
発表資料
発表動画
RubyConfってどうなの
RubyConfはRubyKaigi並に規模が大きいもののあまりRubyのDeepな部分には期待できないカンファレンスなんだけど、当時行ったことがなかったアメリカに行ってみたいという思いがあって去年も参加していた。あと、RubyKaigiとは違った層の海外のエンジニアと話せる *1 のも良い点だと思う。
去年はRubyKaigi 2015で話したものと同じ内容のCFPをRubyConfに出してリジェクトされ悔しい思いをしたが、今年はRubyKaigi 2016で話したものと今回の新作トークの2つのCFPを出したら新作の方が通って話せることになったので、今回は海外で登壇するという目的もあった。
海外で登壇した感想
英語むずい。
僕は基本的に発表スクリプトを書かないで発表するんだけど、英語の勉強が不十分なので、英語で話すことに脳のリソースがかなりもっていかれるのと緊張でスライドに書いてあること以外に何を話そうと思っていたのか忘れてしまい、発表練習していた時に比べ発表時間が短くなった。慣れが必要なのでまたやりたい。
一方、英語ネイティブの人たちを相手に英語でトークをするという点での精神的障壁に関しては、過去のRubyConfやRailsConfの動画を見ているとそこまで流暢でない英語を話す人もいたので開き直ったら意外と大丈夫だった。やっていきがあれば何でもできる。
MItamae v1.0.0をリリースしました
上記の発表でモチベーションや実装方法を紹介しているMItamaeはItamaeという構成管理ツールの別実装なんだけど、RubyConfから一週間以上経った今、本家の機能のうちMItamaeにいれようと思っていた機能が一通り揃ったのでv1.0.0をリリースした。ついでに使われてるmrubyも最新にしてある。
初めて知った人向けに書いておくと、MItamaeはitamae ssh
などItamaeの全ての機能を置き替えるものではなく、ツールの特性や用途は少し異なる。MItamaeについて日本語で紹介している記事はこちら:
Itamaeのmruby実装「MItamae」が大体いい感じになった話 - k0kubun's blog。
現在の導入実績について
社内での導入はWIPなんだけど、既に社外での利用事例がある模様。ありがとうございます。
packerのビルドのためにmitamaeが投入されてた。
— FUJI Goro (@__gfx__) 2016年11月14日
お気持ち
というわけで機能も揃って導入実績も増えてきたMItamaeをよろしくお願いします。
mitamaeを使ってみたまえ
— k0kubun (@k0kubun) 2016年11月18日