2018年を振り返って

今年は仕事を淡々とこなしつつ、自分の技術の方向性に悩みながらも、ずいぶんとだらけてしまった一年だったと思います。技術面での成長に伸び悩んでいます。

Mackerelのコードの整理や改善は無限にやることがあるのですが、平日夜や休日をそれで潰す生活をしていると、頭の切り替えがうまく行かなくなり仕事中に集中できなくなってしまいました。フロントエンドはかなりコードの整理が進み、SPA化できたのはよかったですね。コンテナ周りはチョットワカルと言えるようになりたいですね。

春先にバイナリエディタをリリースしました。まだ実装したい機能はたくさんありますが、リリースしたら燃え尽きてしまってあまりコードを触れていません。Goを書き続ける良い遊び場なので、今後もきちんと開発を続けていきたいですね。

バイナリエディタの後は特に何かを作ることもなく、また新しい技術を学ぶこともなく、のんびり過ごしてしまいました。以前は仕事から帰ってからも3〜4時間コードを書くことができましたが、夏頃に小指の痛みがひどくなり、夕食をとってからベッドでだらだら過ごす日が多くなりました。好きなYouTuberを見つけたのも今年のことでした。

プログラミング以外の趣味を持たなければ人生が薄っぺらいまま終わってしまうのではないかという危機感をいだき、12月に入ってから思い切ってピアノを購入しました。音楽は良いものですね。最近は毎日最低でも二時間は練習時間に取れていると思います。小学生の頃にピアノを習っていましたが、中学受験のために辞めて以来なので、実に十数年のブランクがあります。基礎練習が大事だというのは嫌というほど知っているので、単調な練習曲を5回10回と繰り返しながら、指を動かす感覚を取り戻しているところです。実家から教本を何冊かもらって帰るつもりです。ショパンが大好きなので弾けるようになるといいですね。

ウェザーニュースLiVEを頻繁に見るようになったのも今年に入ってからです。個性的なキャスターがみな魅力的で、番組の内容は聞き続けても飽きません。声も個性的なので今では聞くだけで誰かすぐわかるようになりました。SOLiVE24時代をリアルタイムに楽しめなかったのがすごく残念です。

ルービックキューブも今年に入ってから始めました。昔から日本配色のキューブを持っていましたが、会社で流行したタイミングでMoYuのGTS2Mを買いました。興味は次第に多次元・多面体キューブに移っていき、LanLanやYuXinのキューブを集めて遊んでいます。未だにGreg's Multi Cubeの解き方がわかっていません。commutatorとconjugateは回し方を整理するのには便利ですが、新しいキューブを解くのは私にはまだ難しいです。

Vim本体の最新パッチを追う情熱は持てなくなり辞めてしまいました。今年はプラグインも作れてないですね。最近入れたプラグインの中ではtraces.vimはかなり便利なプラグインだと思います。lightline.vimは3300スターを超えて、今もなお増え続けています。つい先日vim-winfixのバグを直したので、こういう小粒便利プラグインの紹介でも書いてみようかなと考えています。git系のプラグインはなかなか手になじまないことが多いので自分で作ろうかなと考え始めています。

今年もたくさんのアニメを見ました。中でも『多田くんは恋をしない』『はるかなレシーブ』『色づく世界の明日から』『やがて君になる』は印象に強く残っています。来年は『マギアレコード』『フルーツバスケット 新』『ストライクウィッチーズ 501』そして『PSYCHO-PASS 劇場版』に期待しています。

今後もブラウザ、言語処理系、機械学習という三分野を深掘りしていきたいという気持ちは変わっていません。仕事と趣味そして休息のバランスを取りながら来年も頑張っていきましょう。

風野あさぎ「あいかわらずが続くのって、つらくないですか」

色づく世界の明日から 第八話

Mackerelのグラフを端末で描画するコマンドmkrgを作りました

Mackerelのグラフを端末で見れたらいいなと思ったので作ってみました。

github.com

使い方

 $ go get -u github.com/itchyny/mkrg/cmd/mkrg
 $ mkrg

コマンドを叩くと、そのホストのメトリックを取ってきてグラフを表示します。 f:id:itchyny:20181014233825p:plain 何も考えずにコマンドを叩けば、システムメトリックのグラフを表示してくれます。 私はiTerm2を使っているので、とりあえずiTerm2では画像を表示できるようにしています。それ以外の端末では点字を使って頑張って表示します。 f:id:itchyny:20181017235153p:plain

Mackerel サーバ監視[実践]入門

Mackerel サーバ監視[実践]入門

似たような目的のコマンドとしては、同僚の作ったmkr-graphというコマンドがあります。 medium.com

実装

Mackerelは各種APIを揃えていて、中でもメトリックを取得するAPIを使うと、時系列データを引くことができます。 Mackerelのweb画面を見ながら必要なメトリックを調べて、データを引っ張ってきて、グラフに表示すれば完成です。

iTerm2での画像の表示は以下のページを見れば分かります。画像データをbase64で出力するだけなので、とても簡単です。 www.iterm2.com

一応Sixel用の実装も用意してますが動作は見てません。

点字文字コードですが、Braille Patterns - Wikipediaを読めばわかるように、\u2800をベースにして各点に対してビットを立てれば狙ったパターンの文字コードを得ることができます。ユニコードできちんと並んでいて助かります。

言語はGoを使っています。便利な言語です。

みんなのGo言語[現場で使える実践テクニック]

みんなのGo言語[現場で使える実践テクニック]

今後

一昨日から作りはじめてシュッと動いてくれてわりと満足しています。カスタムメトリックのグラフやロールグラフ、サービスメトリックのグラフなんかも表示できると楽しいかもしれません。

個人的には、iTerm2の画像を表示するAPIがすごい単純だということがわかったのが一番の収穫でした。

宣伝

はてなではシステムのメトリクスを見るのが好きなエンジニアを募集しています。

はてな・ペパボ技術大会 #4 〜DevOps〜 @京都 で登壇しました

先日 6/23 に技術イベント「はてな・ペパボ技術大会 #4 〜DevOps〜 @京都」で登壇・トークセッションに参加しました。

hatena.connpass.com

普段の業務でDevOpsという言葉を使うことはありません。 しかし、DevOpsのあり方を見直した結果が現状の体制や仕事のフローであったり、あるいはこれからやろうとしていることにつながっているのだと思います。 技術の進歩によりDockerやGraphQLといった、レイヤー間の共通言語が発達する中で、ソフトウェア間あるいはチーム間が疎結合になっていくことはよいです。 一方でそういう技術で解決できない場面も残っていくのだろうなと思います。

技術の進歩により、調達やスケールアウト・オートスケールは人がやることではなくなってきています。Devがインフラを触れるようになっていくとよさそう (これは技術の進歩もあるけれど、それができる人が残っていくというのもある) なのと同様に、Opsもオペレーションツールを作ったり、あるいはLinuxの深い知識とコーディング力を生かしてミドルウェアを自前で作ったりできる人が生き残っていくという時代はもうすでに始まっている気がします。

トークセッションではふわっとした質問が飛び交う中、うまく喋れたのか不安でした。 弊社のチームはペパボさんのチームの大きさにまではなっていないので、今後会社が成長していくと色々な課題が出てくるだろうなと思いました。 アドリブの受け答えがあまり得意ではないのでなんとかしていきたい。

思ったより学生さんが来ていて、聞いてみるとあまり話が分からなかったと言っていました。 確かにチームでソフトウェアを開発・運用する経験ってなかなか学生だとできないし、チームでの働き方をある程度知っている上で話してしまったかもしれないですね。 はてなのエンジニアがどういうふうに働いているかを体験したい学生さんは、とりあえずインターンに応募してください。 developer.hatenastaff.com

来ていただいた人に何らかの示唆を与えられていたら幸いです。雨の中お越しいただいてありがとうございました。

ペパボの皆様、京都に来ていただいてありがとうございました。これからもよろしくおねがいします。

バイナリエディタを作りました!

バイナリエディタを作りました。

インストールは

go get -u github.com/itchyny/bed/cmd/bed

でできると思います。

f:id:itchyny:20180409220855p:plain

なぜ作ったのか

私は昔からファイルフォーマットに興味があり、画像ファイルやPDFファイルのフォーマットを調べるのが好きでした。 最近も圧縮ファイルのフォーマットを趣味で調べたりしています。 コンパイラ技術にも興味があり、ゆくゆくは実行ファイルを生成したりしたいなという思いもあります。

バイナリファイルをエディットするにはバイナリエディタが必要となるわけですが、自分の手に馴染むUIを持つエディタがありませんでした。 私は実はVimというエディタが好きなので、Vimのようなインターフェースを持ち、ターミナルの中で動くエディタを探したのですが、なかなかありません。 bviはかなりイメージに近く、かなり参考にさせていただきましたが、画面分割がないことやキーマッピングの挙動など細かいことが気になりました。 歴史あるソフトウェアなので敬意は抱いていますが、それは同時に自分で書き直したくなるのに十分な理由でした。

いつかはテキストエディタを自分で作ってみたいという思いがありますが、自分のワークフローが依存しているものが大きくて、なかなか実装し始めるまでのハードルが高いと感じています。 特にシンタックスハイライトなどの既存の資産をどう取り込むか、あるいは自前で実装するかといったことは悩ましい課題です。

一方で、バイナリエディタを作るのはとても簡単です。 テキストエディタよりも難しい点といえば、ファイル全体を読み込むのはよくなくて、例えば16GiBくらいの大きなファイルも読み書きできる必要はありますが、逆にここさえクリアしてしまえば、後は地道にUIを作るだけとなります。 少なくとも、ファイル構造を解析したり逆アセンブラ機能を作るまではそんなに難しくありません (まだこれは実装していないのでどれくらい難しいかはわかりません)。

最後に、自分の力を試したいという思いがありました。 UIを持つcliツールを作るのはよい勉強になります。 実際、いかにコアロジックとUI部分を疎結合に実装するか、端末への描画部分の実装、分割ウィンドウの管理やundo/redoの実装など、様々なことを学ぶことができました。

実装や学んだことと考えたこと

今回バイナリエディタを実装するにあたって学んだことや考えたことを書いておきます。

バッファの表現

バイナリエディタは、メモリーに乗らないような大きなファイルを高速に読み込んで表示する必要があります。 ファイルの内容は、部分的に読みながら表示しなくてはいけません。 画面はユーザーが上下にスクロールしたりいきなり最後に飛んだりします。 こういう時には、ファイルポインタを特定の位置に移動する lseek がとても重要です。 現在の表示領域からファイルの絶対位置を計算して lseek し、必要な分だけ read して表示すれば終わりです。

エディタとしては、任意の場所に書き込めなくてはなりません。 一部を消して保存したいこともあるでしょう。 これらの操作をできるように、 bed の実装ではどの範囲はファイルで、どの範囲は入力されたバイト列かを保持するようにしています。 コードで示すと次のような感じです。

type Buffer struct {
    rrs   []readerRange
    index int64
}

type readerRange struct {
    r    io.ReadSeeker
    min  int64
    max  int64
    diff int64
}

バイト列をファイルポインタと同じように ReadSeek できるようにしておき、ファイルから読む範囲とバイト列から読む範囲を同じように扱えるようにしておきます。 diff によって、エディタから見えるオフセットとファイルのオフセットの差を保持しておきます。 範囲の境界がわかればよいので max だけあれば十分ですが、両方持たせたほうが様々なコードが書きやすいので上記のように実装しています。

例えば1バイト挿入する場合、 readerRange を前後に分割して後ろの diff を一つ減らし、間にバイト列の readerRange を挿し込むのです。 削除する時もやはり前後に分割し、後ろの diff を増やしたり、範囲の境界を表す minmax を減らしたりすれば実装できます。

ファイルポインタや入力されたバイト列を完全に管理するのは少し大変です。 しかし、これらをきちんと実装しさえすれば、編集した部分だけ他の色をつけて表示したり、別々の巨大なファイルを結合したり、大きなファイルを半分に割って前後を入れ替えるのも容易に実装できます。 また、undo/redoBuffer ごと保存していけば難しくありません。

なお bed ではスレッドセーフのために、 pread 相当 (Go言語のReadAt interface) を用いており、上記の io.ReadSeeker の部分は io.ReaderAt と io.Seeker をあわせた独自の interface によって実装しています。 なので、上記で lseek が大事だよと書きましたが、実はファイルの内容を読み込むという用途では使われていません *1Seek して Read するという操作はスレッドセーフではないため、ファイル先頭からの絶対位置を指定して (whenceがio.SeekStart) 読み込みたい場合は ReadAt を用いるほうがよいと思います。

[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識

[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識

いい本です

レイアウト分割

bed は Vim と同じようにウィンドウを分割することができます。 f:id:itchyny:20180409222052p:plain

これは二分木のような構造体で実装されています。

type Horizontal struct {
    Top    Layout
    Bottom Layout
}

type Vertical struct {
    Left   Layout
    Right  Layout
}

type Window struct {
    Index  int
    Active bool
}

木構造の葉が Window となります。 分割を行う場合は、 ActiveWindowHorizontal または Vertical で置き換えます。 これは、再帰的なアルゴリズムで実装できます。 bed の実装では、上記に加えてウィンドウの絶対位置やサイズも保持しており、描画時に利用しています。

なお、この二分木によるレイアウト分割は四畳半分割できないことが知られていますが *2、実用上は問題ないと判断しました。

パッケージ間の依存関係

エディタのコアロジックは、表示ロジックに依存させたくないし、直接触れないようにしたい。 この思いは、エディタの構想を始めた当初からありました。 実装はまだしていませんが、webインターフェースも実装し、ウェブブラウザでバイナリファイルを操作できても面白そうだと考えています。 bedコマンドの実装では、表示部分を簡単に差し替えられるようにしています *3

依存関係逆転の原則、抽象に依存させよという考え方は、とても重要だと思います。 レイヤーごとの実装して木構造のように依存させていくのは、一見「きれいな依存関係」に見えますが、モノリシックで下の実装を差し替えにくく、テストもしにくく、またどちらのレイヤーに書くべきかの判断を誤りがちです。 このことに気がつくのに何年もかかってしまいました。

bed の Editor というメインの構造体は、ウィンドウを管理する Managerコマンドラインインターフェースや補完を管理する Cmdline そして表示とキー入力のための UI に依存していますが、これらは全て interface にしています。 パッケージ間の依存関係を絶ち、コマンドの実装部分で注入しました *4。 これにより、実装の大きなパッケージがお互いに依存することなく、独立して実装を進めることができました。 コマンドラインの実装は、補完やコマンドのparseなど複雑になりがちで、うっかりメインロジックと結合していたら大変なことになっていたと思います。

パッケージ間の依存関係を描画すると次のようになります *5

f:id:itchyny:20180409220936p:plain

editorパッケージはwindow, cmdline, tuiパッケージに対して依存関係がありません。 bufferというエディタを支えるバッファを実装したパッケージも、コアロジックであるeditorから依存がない遠いところにあることがわかります。

SOLID Go Design | Dave Cheney というブログには大事なことが書かれていますので読みましょう。

All things being equal the import graph of a well designed Go program should be a wide, and relatively flat, rather than tall and narrow.

この言葉はとても共感できます。

端末インターフェース

今回、tcellというパッケージを使ってみました。 termbox-goよりも後発で、様々な改善が行われています。 SimulationScreen というスクリーンのmockがあって、描画のテストをしやすいのはよいですね。 あと、テキストのスタイルをメソッドで更新していけるのは便利です (Goに三項演算子がないからかもしれません)。

Go言語という選択

最後になってしまいましたが、実装の最初に考えることは、どの言語を使うかということです。 バイナリを不安なくきちんと扱えること、環境にできるだけ依存せず実装できること、そして開発者にインストールしてもらいやすいことあたりが必要条件でした。

Go言語のデザインや型のシステムは決して私の好みではありませんが、言語の選択を左右するのは言語デザインだけではありません。 バイナリの扱いやすさ、言語の安定性、実行速度、ポータビリティー、コードの書きやすさ、メンテナンスのしやすさ、そして言語の人気とツールのインストールされやすさ (インストール時の心理的障壁の低さ) など、総合的に考えてGo言語はとてもよい言語だと思っています。

まだ実装していませんが、今後ファイルフォーマットを解析する機能を作ろうとしています。 画像ファイルや実行ファイル (ELF・Mach-Oフォーマット) などの解析コードが標準パッケージに入っているのは、Go言語のすごいところです。 他の言語だとライブラリをがんばって探すか、自前で解析するしかないでしょう。

goroutine間でデータを共有すると、簡単にraceが起きてしまうのが悩ましいところですが、これは丁寧にロックを取ってraceが起きないようにしなくてはいけません。 go test -race で簡易なチェックをできるのはよいですね。

みんなのGo言語【現場で使える実践テクニック】

みんなのGo言語【現場で使える実践テクニック】

いい本です

まとめ

バイナリをエディットしたかったので、バイナリエディタを作りました。 作る過程で様々なことを学ぶことができました。

まだ実装したいことはたくさんあります。 diffモードやマーク、バイナリ列での検索などは実装する予定です。 実行ファイルのフォーマットを勉強して、ファイル構造を表示できるようにしたいと思っていますが、これは少し先の話になりそうです。 画像ファイルくらいから始めるかもしれません。

バイナリエディタ作りの旅は始まったばかりです。 各種ファイルフォーマットを調べながら、エディタ作りを楽しもうと思います。

宣伝

はてなでバイナリをエディットする仕事はあまりありませんが、プログラミングが好きで自分が使うものは一から作ってしまう、そんな情熱あふれるエンジニアを募集しています。

*1:ファイルの最後に飛び、ファイルサイズを取得するのに用いられています。

*2:壁をグラフの辺とみなして頂点の次数に着目します。どんな分割や分割解除を行なっても、縦方向と横方向に見て、次数が3なら1、4なら2を足したもの (すなわち分割線の端を1と数える) の中に、必ず1つは偶数があることを示せば証明できます。四畳半は3と1しかなく、偶数がないため作ることはできません。四畳半レイアウトでなくても、適当に分割を解除して全て奇数になれば作れないレイアウトです。

*3:まだ複数のインターフェースがあるわけではないので、どれだけ簡単かはやってみないとわかりませんが…

*4:Goは構造的部分型なので、抽象に依存させるために、抽象の置き場所に悩むことがないのがよいですね。

*5:汎用的なコードの依存関係の抽出ツール rexdep を作りました! ― 正規表現で依存関係を大雑把に抽出しよう! - プログラムモグモグ

2017年を振り返って

今年は仕事で関わっているプロダクトが大きな転換期を迎えて、様々な経験ができました。 ミドルウェアを自ら作り上げ、データをオンラインで移行し、運用を始めるというのはなかなか経験できないことだと思います。 サービスは以前より安定し、穏やかな年末を過ごしています。

今年は初めてカンファレンスで登壇しました。 慣れないことばかりで色々と戸惑いましたが、沢山の方に発表を聞きに来ていただいて嬉しかったです。 マネージドサービスを組み合わせて1つのソフトウェアを作り、それをサーバーレスミドルウェアとして抽象度を上げて捉えることができるようになったもの、このカンファレンスに参加してよかったことでした。

今年は19記事書きました。 特に、以下の記事は多くの方に読んでいただきました。

一年の後半にアウトプットが減速しているのは、カンファレンスの登壇に体力を使ってしまったこと、Prime VideoやAbemaTVを見ながらぼーっとする時間が増えたこと、プロダクトコードのリファクタリングに随分と入れ込んでしまったことなどが原因だと思います。

年始はコンパイラーやインタープリターに興味があり、インタープリターを書いてみたりLLVMを試したりしていたのですが、3月ぐらいには興味も薄れていきました。8月くらいまでは仕事が忙しく余裕がありませんでしたね。その後Rustを真面目に書き始め、システムコールに興味を持ち、そしてMackerelのシステムメトリックに興味が移り、go-osstatを作り始めました。最近はエディターの実装に興味を持ち、色々と調べています。ことごとくトレンドを外した感じに共感を持てますね、まぁ自分のことですが。

Vim周辺の変化で言うと、vimshellを辞めてterminalを使いだしたことくらいですが、他はほとんど変化はありませんでした。lightlineのスター数は順調に伸び、2500を突破しました。ユーザー数は増えてもissue報告はそんなに増えていないし、ほとんどが設定の仕方に関する質問なので楽なものです。

今年は投資を始めた年でした。これまで一切経済のニュースとか興味がなかったのですが、今のペースで経済が成長していくと現金で持っているのがアホらしく思えてくるので、少しずつ時間を取って勉強し始めています。まだド素人なので特に語れることはありません。

生活面、仕事面共に大きな変化はありませんでしたが、緩やかに成長できた一年だったと思います。来年は少しずつアクセルを踏んで頑張っていきましょう。

山村美和「なんでも本気でやるから楽しいんじゃん。」

ばらかもん