Treasure Data に入社しました

3月から Treasure Data で働いています。入社初日からタスクをアサインされ、RailsAPIの開発をやりました。

なぜ Treasure Data に転職したのか

前職もやりたいことができて優秀な同僚に囲まれ文句ない環境だったのですが、アルバイト入社から数えるともう3年半が経っていたし、入社前にイメージしていたような仕事も大体経験できていました。

そのままいても良かったのですが、ある程度の間隔で新しいことに挑戦しないと成長は止まってしまうと思っているので職場ごと変えることも考え始め、以下のような観点から Treasure Data に転職することに決めました。

  • エンジニアがユーザーになる仕事をしてみたい
    • 僕は開発者が使うツールを作るのが好きで、技術を売っている会社の方がそういうものを作る機会が増えそう
    • 正直あまりエンジニアリング以外に興味がないので、一般の人を対象にしたサービスを作っている会社より、エンジニアがユーザーな方が会社のビジネスに興味が持てる
  • 前職だとあまりやらなそうなことに挑戦する選択肢が増えそう *1
    • 分散システムやミドルウェアの開発、Javaを使ったバックエンドシステムの開発など
  • アメリカ (シリコンバレー) で働くチャンスを増やしたい*2
    • 上記を踏まえて今後のキャリアを考えると、日本にいるよりはアメリカにいた方が楽しい人生が送れそう*3なので、チャンスがあれば移住したい

その他、転職先に求めていたこと

市場調査のため転職ドラフトに登録していた時にいろんな企業様から声をかけていただいたきとてもありがたかったのですが、上記に加え下記のようなことを考慮し決めさせていただきました。

  • 自分が興味があったり得意な分野で尊敬できる人が多くいる
    • 今までは大体RubyRails、あとたまにインフラという感じで触っていて、そのどれでも自分よりすごい人がいる
  • 積極的にOSS活動や外部への発信をしている
    • 流石に全部オープンにするべきとは思ってないけど、何かすごい成果を出せたら社外に自慢する機会がないとモチベーションが維持しにくいと思っていて、そうしている人が多い会社の方がきっと楽しく仕事をしてるんだろうなと思う
  • 待遇が良い
    • 技術的な成長だけが人生じゃないし、総合的に見て幸せになるにはやっぱりお金も必要

気持ち

偉そうなことをいっぱい書いていますが、まだまだとても経験の浅い身ですので、早く成果を出して同僚の方に認めていただけるようがんばります。

*1:最初は僕がある程度得意であり人手も不足しているRailsアプリ(API)の開発をやります

*2:僕が働いているのは東京オフィスだけど、本社はMountain Viewにある

*3:技術で商売をしている会社は日本よりはシリコンバレーの方が多いよね、という話

Hamlを3倍速くした

Hamlコミッターになった

RubyKaigi 2015で「Hamlは遅いしメンテされてないので使わない方がいい」と言ったところ、じゃあ自分でメンテして速くしろということになりコミッターになった*1

当時から2年ごしなのは、当時のHamlのオーナーがあまりアクティブではなく最近a_matsudaさんがオーナーになったため。

HamlのTemple化・高速化を行った

Templeというのは、テンプレートエンジンをパイプライン的に構築するためのフレームワークで、テンプレートエンジン用の中間表現とその最適化エンジンを持つ。実装をTempleベースにすると、SlimHamlitに使われているような中間表現を使った最適化を適用しやすくなる。

コミット権をもらったので、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での結果)

f:id:k0kubun:20170227151723p:plain:w540

まあまあ縮まったけどまだ遅いですねという感じ。やっていくぞ。

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&#x000A;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と同じごく普通の挙動にした。そこは後方互換性のない変更になってしまうが、流石にこれで困る人はいない気がしている。

github.com

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デスクトップを使っている。

  • 趣味で作ったスペックが高めの自作PCmacOSが入れられない *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は綺麗かつまあまあ軽快なのでおすすめ。

使っているGNOME拡張 macOS風にするためにいくつかGNOME拡張をいれている。

  • Dash to dock: Dockを出しっぱなしにする
  • GNOME Shell Frippery: 日付と時刻を右端に出す
  • Panel osd: 通知の表示位置を右上にする

キーリマッパー: 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に標準添付のものを使っている。スクリーンショットImageMagickimport(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

かなりどうでもいい余談 今まで使った発表資料azusa colorsの色を全て使い切った。東急でやったけど、資料全体で赤とかを使うのは大分激しいのでちょっとやめた方がいいと思う。

ホッテントリ

ブログは1ヵ月に1記事くらい書くのを意識しているけど、はてなブログが11記事、Qiitaが6記事という感じだった。「発表」と重複があるけどブクマを貰えたのは以下の通り。

タイトル
1. 安心してRailsアップグレードを行うための工夫 - クックパッド開発者ブログ
2. Coffee, jQueryで書いていたElectronアプリをES6, React, Reduxで書き直した - k0kubun's blog
3. Linux向けの最強のキーリマッパーを作った - k0kubun's blog
4. Railsアプリ開発環境の高速化 // Speaker Deck
5. RubyなしでItamaeレシピを実行できる「itamae-go」を作った - k0kubun's blog
6. SSEを使ってHTMLエスケープを高速化してみた - k0kubun's blog
7. Itamaeのmruby実装「MItamae」が大体いい感じになった話 - k0kubun's blog
8. Scalable Job Queue System Built with Docker // Speaker Deck

いまだに400 users越えたことないので何かもっとバーンて感じの成果欲しい。

OSS活動

今年リリースしたOSS

Starだけ見ると去年に比べるとウーンという感じ。mitamaeを使ってくださっているみなさまありがとうございます。

Star リポジトリ
★65 k0kubun/mitamae
★64 cookpad/barbeque
★48 k0kubun/xkremap
★46 k0kubun/itamae-go

今年は↑でmruby, Docker, Go, Xlibあたりを触っていて、他にhescapeSIMDプログラミングで少し遊んだのと、もうちょっと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回だけ貢献できた。

ポッドキャスト

timakinさんに誘われてboot.fmというポッドキャストを始めた。4話配信済み。2人でやっていても、ネタと収録する時間とゲストを呼ぶ人脈とコミュ力がなくてかなり大変で、miyagawaさんはすごい!!!!という気持ちになる。一方、自分がホストをやると、話したいことを自由に話せる楽しさがある。

bootfm.github.io

2017年は

  • Ruby以外で手になじむ言語を増やしたい
    • 今後もコードを書き続けたいが、このままだとRuby以外で仕事できなくなり失職しそう
  • 業務で使って困ることがないレベルまで英語の語彙や表現力を向上したい
    • ドキュメント読むのとOSS活動をする時に使うし、いつか海外でも働けるようにしたい
  • 執筆活動をしたい
    • というかやってるんだけど、ちゃんと出すところまで持っていけるようにしたい

私生活と両立して楽しくやれればいいなと思っています。来年もろしくお願いします。

Linux向けの最強のキーリマッパーを作った

X Window Systemで動作するキーリマッパー「xremap」を作った

僕はKarabiner用のRuby DSLを作ったりそれを使って大量の設定を既述する程度にはKarabinerのヘビーユーザーなんだけど、デスクトップ環境にLinuxを使い始めてからもう1年以上経つ今でもLinux環境で使えるKarabiner並にリッチなキーリマッパーを見つけられずずっと不便していたので、ユースケースを満たす最低限のものを自分で作った。

github.com

ちなみにX用であって別にLinuxの何かに依存しているわけではないので、タイトルは釣りである。

これは何

RubyDSLかつシンプルなキーの指定方法によりキーリマップを設定することができる。例えば、以下の設定ファイルを書いて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に割りあてられているため、例えばEmacsC-fとブラウザの検索のC-fが被ってしまっていた*3

アプリケーションごとにキーバインドを変えられる程度にはリッチかつ十分に安定したキーリマッパーがあると、macOSみたいにCommandキー相当のキーを作ることができる。会社で貸与されてるノートPCがMacBookなので今でもmacOSは使うのだけど、できれば複数の環境の差異をなくしたいというのがあった。

気持ち

デスクトップ環境でLinuxを使っている人はNocturnxremapをよろしくお願いします。

*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をリリースしました

上記の発表でモチベーションや実装方法を紹介しているMItamaeItamaeという構成管理ツールの別実装なんだけど、RubyConfから一週間以上経った今、本家の機能のうちMItamaeにいれようと思っていた機能が一通り揃ったのでv1.0.0をリリースした。ついでに使われてるmrubyも最新にしてある。

初めて知った人向けに書いておくと、MItamaeはitamae sshなどItamaeの全ての機能を置き替えるものではなく、ツールの特性や用途は少し異なる。MItamaeについて日本語で紹介している記事はこちら: Itamaeのmruby実装「MItamae」が大体いい感じになった話 - k0kubun's blog

github.com

現在の導入実績について

社内での導入はWIPなんだけど、既に社外での利用事例がある模様。ありがとうございます。

qiita.com

tech.sideci.com

お気持ち

というわけで機能も揃って導入実績も増えてきたMItamaeをよろしくお願いします。

*1:実際にはRubyKaigiにも参加してるような人と話すことの方が多いけど、RubyKaigiでは見たことないがGitHubとかでは見たことある人と話すこともあったし、あとRubyKaigiと違って場の雰囲気的に英語で会話する行為へのハードルが低い

Itamaeのmruby実装「mitamae」が大体いい感じになった話

Roppongi.rb #2 で「mitamae」について話してきた

Roppongi.rb #2が "Infrastructure x Ruby" をテーマに開催され、そこで RubyなしでItamaeレシピを実行できる「itamae-go」を作った - k0kubun's blog 話と pure mrubyで実装されたItamae「itamae-mruby」を作った - k0kubun's blog 話をしてきた。

いいたかったことはスライドの通りだけど、枠が15分でいろいろ漏れた話を書いておく。

mitamaeの現状について

なんでitamae-mrubyからMItamaeに変えたの

というか一昨日までmitamaeはitamae-mrubyという名前だった。エエー。変えた理由は真面目な奴がいくつかあるんだけど、あえて不真面目な奴だけ書くと、名前が微妙なソフトウェアは流行らない気がしていて、itamae-goよりitamae-mrubyの方が筋が良いのにitamae-goの方がウケが良かったので、名前を変えてみることにした。

ちなみに僕はリネームの常習犯で、Hamlitは元々違う名前だったし、activerecord-precountは最初にrubygemsにプッシュしてから3回リネームしているし、他にもいろいろやらかしているので、mitamaeもあと2回くらい変身の可能性を残している。

原案はmrubyで何かとお世話になっているksssさんの発言なんだけど、mitamaeだと「見給え感」が強すぎるのでMItamaeということにしている。 v1.6.3 からmrubyと合わせてログやドキュメント上の表記をMItamaeからmitamaeに変更にした。*1

プラグイン機構について

github.com

resourceプラグインをサポートした。社内でItamaeになってる奴をスッとmitamaeにしようとした時に、portageとかはプラグイン化したいみたいなことを言われたのでサポートした。

で、まあmrubyを使う以上rubygemsは利用できないので考える必要があって、普通にmrbgemを使うとプラグインを組み込む度にmitamaeをコンパイルし直すという話になるのだけど、シングルバイナリで配布してる意味が薄れるので、pluginsディレクトリにmrbgemと同じディレクトリ構造 *2Rubyスクリプトを置いておくと動的にロードされるようにした。

なので、リポジトリにgit submoduleでプラグインをいれるか、最悪vendoringするというのが想定された使い方になっている。これに関してはいろんな人の意見を聞いてみたい。

来週の話

今日はItamaeを軸に話をしたけど、来週の金曜にitamae-go, mitamaeを題材にしつつmrubyを使う側を軸にRubyConfで登壇するので、興味がある人はシンシナティで僕と握手。

*1:内部クラスに使われているMItamae表記で呼んでいただいても問題ないです

*2:具体的には ./plugins/*/mrblib/**/*.rb がファイル名順に読まれます