おそらくはそれさえも平凡な日々

お知らせ

日頃お世話になっている皆様へのお知らせです。なるべく多くの方に直接お伝えしたかったのですが、この場でのお伝えになってしまった方には申し訳ありません。

はてなを退職します。4/17(水)が最終出社でした。所属は5/31(金)までです。

ずっとはてなで働きたいと思っていましたし、この絶好のタイミングで辞めてしまうのは勿体無いという気持ちもあります。ただ、次の挑戦に関して時間的な制約もあったため退職させてもらうことになりました。この詳細はまた別途お知らせできればと思っています。

2014年に現在のはてな東京オフィスの一人目のエンジニアとして入社し、その後、チーフエンジニアと、Mackerelのプロダクトオーナー(マネージャー)を兼務してきました。

チーフエンジニアとして組織に、Mackerelではプロダクトとビジネスに関わりました。入社当時、私一人だけだった東京オフィスのエンジニアも今では二桁になり、リリース直前で売上のなかったMackerelも今や事業の柱の一つです。組織とプロダクト両面に良いフェーズでトップレイヤーで携われるという、社内でも他にいない稀有で贅沢な体験をさせてもらいました。良い経験になりましたし成長もさせてもらいました。本当に感謝しています。

自分で退職を申し出ておきながら勝手なことを書きますが、まだ辞めたくない気持ちもありますし、まだ辞めることに実感が湧いていない部分もあります。

私はいなくなりますが、今後のはてなのエンジニア組織やMackerelに関しては心配していませんし、むしろ楽しみにしています。

チーフエンジニア陣には、はてな新卒から順調にキャリアを重ねてきた id:shiba_yu36 や、中途で経験豊富な id:onk が加わり、人が入れ替わりつつもスターエンジニア揃いの盤石な体制になっています。

Mackerelも順調に成長し、チームも拡大しています。開発チームはディレクターの id:daiksy 及びテックリードの id:astj のもと成熟したスクラムチームを形成していますし、ビジネスチームも完全に立ち上がり、開発チームと同じくらいの人数になりました。特に日本でおそらく一人目のCREである id:a-know はプロダクトに対する情熱と理解度が高い頼もしい存在です。

まだまだビジネスと開発の垣根のないスタートアップ感も維持しています。会社としても注力プロダクトであるため大きな支援もしてもらっています。ですので、はてなもMackerelもまだまだ面白いフェーズですし、エンジニアも積極的に採用しています。

社長の id:chris4403 さんは「はてなを長く働ける会社にしたい」ということをおっしゃっています。これはなかなか今のWeb業界からすると珍しい、チャレンジングな目標だと思います。だからこそ私自身もずっと働きたいと思っていました。

はてなは良い会社です。採用は厳選していて、善人しかいないので、性善説前提で動ける良さがあります。制度や福利厚生も配慮があってスタッフが働きやすい環境を整えようとしているし、今後もしていくでしょう。フリーランチの甲斐もあってか、社員同士の気心がしれていて仲がよく気持ちよく働けるのも良い点です。色々、次の会社の組織文化を形成していく上で見習いたいと思っています。

憧れの会社であるはてなで働けて幸せでしたし、今後も憧れの会社であり続けてほしいと思っています。Mackerelも僕の手を離れますが、今後どのようなプロダクトになっていくか楽しみにしています。

ウィッシュリスト

依存ライブラリのLICENSE同梱のためのgocreditsというツールを作った

https://github.com/Songmu/gocredits

Goのプロジェクトの依存ライブラリのLICENSEを抽出して、CREDITSという単一ファイルに書き出してくれるツールを作りました。もともとのアイデアは同僚の id:tarao によるものです。Go Modulesを使っているプロジェクトで以下のようにすれば、CREDITSファイルを書き出してくれます。出力されたCREDITSファイルは実行バイナリを配布する時に有用でしょう。

% gocredits -w .

Goは実行バイナリを簡単に配布できるので便利ですが、ソフトウェアを配布するときは、依存ライブラリのLICENSEを考慮する必要があります。具体的には恐らく依存ライブラリのライセンスのコピーを同梱する必要がありそうです。リンクだけではだめでコピーを含めた方が良さそうです。

例えば、MITライセンスには以下の記述があります。

The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

BSDライセンスにも以下の記述があります。

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

Goの場合、例えサードーパーティライブラリを使ってないとしても、Goの標準モジュールのライセンスの同梱が必要です。以下のissueでも議論されていて「ちゃんと同梱しましょう」と書かれている。

https://github.com/golang/go/issues/19893

この辺りは、スマホアプリの世界だとちゃんとしていて、ライセンス表示画面をちゃんと設けていたり、そのためのライブラリも揃っています。他にもChromeだとabout:creditsにアクセスすると、依存ライブラリのライセンス一覧を表示できたりします。

Goの世界だとあまりそういうツールがなさそうだったので、以前 id:tarao がfireworqを公開時に、ライセンス一覧をCREDITSという名前のファイルに書き出すスクリプトを作っていました。これは、glide.lockから依存を抽出して、vendor配下からLICENSEを集めてきています。

gocreditsはここからアイデアを拝借しつつ、Go Modulesに対応させたものです。$GOPATH/pkg/mod 以下から依存を取り出すようにしていますが、Go Moduleに非互換変更が入った場合動かなくなるかも知れません。なのでAlpha Qualityです。

Goで実行バイナリを配布する場合、アーカイブにこのCREDITSファイルを同梱すると良いのではないでしょうか。なんと、goxzはデフォルトでこのファイルの同梱に対応しています。

既に個人のツールでは使い始めています。是非ご利用ください。OSSのLICENSE周りにそこまで詳しいわけではないので何かあればご指摘ください。ゆくゆくは依存ライブラリのLICENSEの不備だったり、非互換検出などもおこなえるようになると嬉しいと考えています。

最近のGo Modulesプラクティス ~ ghqユーザーの場合も添えて

最近Go Modulesを使っていて、だいたいプラクティスが定まってきたのでまとめてみる。

個人的な結論

2つのモード

$GOPATH/src にプロジェクトを置いていると、今(Go 1.12)の標準動作はGOPATHモードになる。これは、$GOPATH/src 以下からサードパーティパッケージを読み込むこれまでのGoと同様の動作になるということ。

それ以外の場所では go mod コマンドを使ってGo Modulesを利用することができる。これをmodule-awareモードという。go.modgo.sum を使って依存ライブラリを管理する方式になる。これらのファイルはgo mod コマンドが大体いい感じに生成してくれるので別にファイルが増えて煩雑になるということはない。

module-awareモードの場合$GOPATH/pkg/mod 以下にパッケージのバージョンごとの実体が置かれるので、そこを眺めるとイメージが掴めるかも知れない。ただ、この位置は変更になる可能性があるし、そもそも普通に go mod を利用する上では意識する必要はない。

この、GOPATHモードとmodule-awareモードの切り替わりはデフォルト挙動であり、 $GO111MODULE 環境変数を変更することで変更可能。また次のGo 1.13からは、一律module-awareモードになる。

Go Modules所感

普通に使い物になるし、vendorディレクトリとか使わなくていいので便利。積極的に使っていきましょう。その場合一律Go 1.12以降を使うことが望ましいとは思います。

使い方は、最近オフィシャルブログに Using Go Modules と言う記事が上がっていて、これがイメージを掴むためには良いと思います。

https://blog.golang.org/using-go-modules

依存定義のための go.mod とロックのための go.sum という依存管理システムに良くある2ファイル構成です。ただ、goコマンドがことある事にそれらを更新するのでそこは少し驚くかも知れません。

多くが自動生成されるため、覚えることは余りありませんが、網羅的な情報は公式のWikiにまとまっています。

https://github.com/golang/go/wiki/Modules

別に $GOPATH/src からプロジェクトを動かす必要はない

$GOPATH 以下だと、前述の通りデフォルトでは go modが動かないが、明示的に $GO111MODULE=on するだけで動くようになる。どうせ次のGo 1.13では、$GOPAH/src だろうがなんだろうがデフォルトでgo modが動く。チュートリアルとかでは $GOPATH の外でやることが案内されてるけど、そっちのほうがチュートリアル的には混乱がなく明確なのでそうしているだけで、別に出なくてもいいという理解をしている。

それに、現在移行期であることから、ツールチェイン類がまだmodule-awareモードに対応しておらず、GOPATHモードの方が嬉しい局面もある。具体的にはgoimportsなど。なので、逆に積極的にGOPATHから出る理由もないと考えています。

今のところは、開発時はGOPATHモードで良くて、CI/CD周りは、Go Modulesに寄せるのが良いと考えている。今は、Makefileに export GO111MODULE=on ってべた書きしている。Dockerfileとかにも書くといいと思う。

https://github.com/Songmu/godzil/blob/master/Makefile#L8

ハマりどころや課題など

masterのHEADと最新のタグに乖離があるときに困る

Go Modulesは、そのパッケージのリポジトリにv1.2.3のようなsemverタグが打たれている場合は、masterのHEADではなく最新のsemverタグを取得する。これは良い仕様だと思う。

ただ、HEADと最新のタグの乖離が激しいときは困ることになる。実際、 github.com/octokit/go-octokit でめちゃくちゃハマった。このライブラリの場合、最新のv0.4.0タグとHEADで依存パッケージまでことなるので、普通に go get すると意図しない依存が書き出されて困ってしまった。

以下のように go get で指定するパッケージに @master を付与することで強制的にHEADに依存させることができるのでそれで凌いだ。

% GO111MODULE=on go get github.com/octokit/go-octokit@master

今後はライブラリ系のパッケージもsemverタグを付けていくのが望ましい。僕はビルドを提供したいツール類だけリリース時にタグを打っていたけど、ライブラリ系もちゃんと打っていきたい。godzilを作り始めた背景もそれ。

ちなみに、 go-octokitghch内部で使っているのですが、どうもメンテが止まっており、hub コマンド内部でも使われなくなってしまったので、go-github に乗り換えるのが良いかなーと思っています。

ツール類を go get すると go.mod が書き換わってしまう

module-awareモードの時に go get をすると、それがツール類であっても無条件に go.mod 及び go.sum を書き換えてしまう。例えば以下のように golint を入れたい場合とかに困る。

% go get golang.org/x/lint/golint

これは今のところ以下のように強制的にmodule-awareモードを切ることで凌いでいる。

% GO111MODULE=off go get golang/x/lint/golint

https://github.com/Songmu/godzil/blob/master/Makefile#L16

議論はされていて、 go get -b <pkg>@<version> のように -b オプションを設けるのが有力のようです。

https://github.com/golang/go/issues/30515

依存先モジュールの編集をしたい場合に困る

バグ修正だったり挙動確認の為にログを差し込んだりとかのために依存先を変更したくなること、なんだかんだであると思います。

GOPATHモードの場合、依存先のコードを書きかえて動作を確認して、そのままシームレスにpull requestを送ったりもできて便利なのですが、module-awareモードの場合はそうもいきません。

これも以下で議論されていますが、go.modを一時的に書き換えてreplaceディレクティブを使う方法や、go mod vendor でvendorを書き出してしまってそれを編集するなどのワークアラウンドが話されています。

https://github.com/golang/go/issues/27542

根本解決に関しては、優先度が下げられていて、方針も決まっていません。go.mod.local を認識させる案も提案されていますが、個人的にはそれはあまり良い方法だとは思わないし、採用もされないだろうなと思っています。

これに関しては、GOPATHモードの方がやりやすさがあるので、今のところ個人的に開発時にGOPATHモードを利用したいモチベーションの一つにもなっています。

上記issueでも議論されていますが、mini CPANのようなローカルモジュールindexとしての $GOPATH/src のわかりやすさが損なわれることについての対応策は今後の課題になりそうです。

完全な依存ツリーを作るために go mod tidy を使う

僕も最近まで勘違いしていたのですが、 go mod tidy は環境に関わらない完全な依存ツリーを構築するためのものと捉えたほうが良さそうです。「綺麗にする」「余計なものを消す」というイメージで使われていそうですが「整頓する」というのがイメージとしては正しそうです。

例えば、開発環境とは異なる特定OSのみ、例えばwindowsだけで利用されるパッケージを go.mod に追加するには go mod tidy を実行するだけです。go buildgo get は、 GOOS、GOARCH、ビルドタグなどを見てしまうのでgo.modへの最低限の依存の書き出ししかしませんが、go mod tidy の場合は、それらを見ることなしに、つまり全てのgoファイルを読み込んで依存ツリーを構築してくれるようです。

これは少し分かりづらい挙動ですが、仕様であり明確にドキュメントされるべきだと以下で述べられています。

https://github.com/golang/go/issues/27633#issuecomment-420545604

go getgo build では go.modにtest dependencyが追加されず、go test しないと追加されないことや、それなのに go mod tidy では追加されてしまうことを不思議に思っていたのですが、先程書いたように、 go getgo build ではその環境での実行に必要な必要最低限の依存抽出しかせず、 go mod tidy ではgoファイルの絞り込みを行わず全ての環境での依存を抽出してくれる仕様であるためだということがわかりました。

ghqを使っている場合

すでに書いたように $GOPATH/src から無理に出る必要はないのでこれまで通り ghq を使えば良いでしょう。逆に、Go 1.13以降は go get の挙動が完全に変わってしまうため、これまでと同様の配置ルールでリポジトリ管理したい場合は、 ghq get をより活用することになると思われる。

改めて個人的な結論

課題についてはGitHub issueを探せば大体議論が出てくるので便利。必要なやつを適宜追いかけておけばよいでしょう。

ということで使っていきましょう。

Devel::KYTProfが大幅にパワーアップしたぞ!

ということで、Devel::KYTProf 0.9991をリリースしました。

https://metacpan.org/pod/Devel::KYTProf

YAPC::Tokyoのfujiwaraさんの「Perlでも分散トレーシングしたい」というトークでDevel::KYTProfに褒められが発生していて、AWS X-Rayという現代のテクノロジーでDevel::KYTProfがパワーアップして華麗に復活するの面白いなーとか思ったので、ちょっと古かった点とかissueとかをカンファレンス駆動で一気に直した。やっぱカンファレンス翌日のhack day欲しくなりますね。

そこから少し間が空いてしまったのですが、onishiさんにコラボとcomaint付けてもらってリリースした次第。以下変更点など。

DBI Profilerを改善

https://github.com/onishi/perl5-devel-kytprof/pull/16

今回の目玉。

DBIのクエリ呼び出しを網羅してフックするのは実はかなり大変で、Devel::KYTProfも不十分だという積年の課題がありましたが、この度めでたく解決しました。

具体的には do, selectall_arrayref, selectrow_arrayref, selectrow_array辺りをMySQLでフックできてなかったのを対応しています。内部的にはDBIx::Tracerを使うようにしたので、以前よりわずかにオーバーヘッドがあるかもしれません。

それと同時にadd_prof の引数の末尾に $sampler_sub を渡せるようになりました。これはメソッド実行前に処理され、プロファイルをおこなうかどうかの真偽値を返すためのsubrefを渡せるものです。偽値を返した場合、メソッドが直ちに実行され、プロファイルは行われないようになっています。ただ、これはDBI Profiler改善のために無理やりつけた機能感が否めないため、今のところEXPERIMENTALな機能だと考えています。

Profilerをパッケージ定義できるように

https://github.com/onishi/perl5-devel-kytprof/pull/14

これも結構便利です。

すでに、Devel::KYTProf::Logger::XRay のようにLoggerは独自のパッケージに差し替え可能になっていますが、Profilerもユーザーが独自のパッケージを定義できるようになりました。

"Devel::KYTProf::Profiler::" . $target_pkg と言った名前空間でパッケージ定義します。例えば、組み込みの DBI だと Devel::KYTProf::Profier::DBI という具合です。

Profilerパッケージの作成は簡単で、そのパッケージに apply という関数を定義しておくだけです。これを、 Devel::KYTProf->apply_prof('DBI') のようにすれば読み込みができます。詳しくは組み込みのProfierの実装を見ればイメージが沸くでしょう。

組み込みのProfierは、 DBI, LWP::UserAgent, Cache::Memcached::Fast, MogileFS::Client, Furl::HTTP を提供しています。これらは今のところ全て自動で読み込まれますが、流石にMogileFSとかどうなのかと言う感じなので、変更する可能性はあります。

ということで、独自のProfilerを追加できるようになったので、是非作成してCPANizeして活用してみてください。Devel::KYTProf::Profiler::Redis::Fastとかあると良さそうですね!Redisは組み込みで欲しいくらいですが。

組み込みProfilerの自動読み込みをオフれるように

() 付きでuseすれば、何も組み込みProfilerを読み込まないようになりました。

use Devel::KYTProf ();
Devel::KYTProf->apply_prof('DBI');
Devel::KYTProf->apply_prof('Furl::HTTP');

などとすれば使いたいProfilerだけを選択的に読み込むことができます。

UNIVERSAL::require から Module::Load

https://github.com/onishi/perl5-devel-kytprof/pull/13

UNIVERSAL::require は一世を風靡しましたが、今はModule::Loadを使う方が良かろう、ということでスイッチしました。

Devel::KYTProf::Logger::XRay とかと組み合わせてトレーシング用途で本番で使うとなると、UNIVERSALにrequireが生えているのはやはりちょっと怖いので、というのもあります。

ただ、 Devel::KYTProfuse UNIVERSAL::require; されていることを期待しているコードを書いている場合は動かなくなる場合があるかも知れないのでその場合は別途明示的にコード内で、 use UNIVERSAL::require; してください。

Class::Data::Inheritance から Class::Data::Lite

https://github.com/onishi/perl5-devel-kytprof/pull/15

これは個人的な趣味ですが、 Class::Data::Inheritable が Inheritableである必要とか、@ISA 変更する必要とか無いよなーとかそういうのを思ったので、 Class::Data::Lite というのを新たに作って、そちらに切り替えました。つまり、Class::Accessor::Lite と同じような動機です。多少は効率良くなっているかも知れません。久々の新作CPANizeです。

https://metacpan.org/pod/Class::Data::Lite

まとめ

ということで是非お使いください。結構中身をゴリッといじったので、0.9991というバージョンで出しています。今後、多少非互換修正も加える可能性もありますが、様子を見てversion 1を出したいと考えています。

godzilというGoのオーサリングツールを作っている

https://github.com/Songmu/godzil

Goのモジュール作成と、リリースをサクッとできる君が欲しくて作っている。作りかけだけど、すでに便利に使ってはいます。インターフェースは結構変わる可能性はあります。名前の通りかなりMinillaインスパイアです。

モチベーションとしては以下。

今のところの使いかた

モジュールの作成

% godzil new github.com/Songmu/oreore

scaffoldingされて、git init && git add . される。あとは適当にremoteリポジトリを登録して開発してください。今のところGitHub or GHEで開発する前提になってます。

リリース

% godzil release

semver形式でリリースバージョンを聞かれるので入力します。以下のことをやってくれます。

逆にツールのビルドはおこなわないのでそこは適宜別の仕組みを利用する形です。リリースフックの仕組みなどは用意するかも知れません。

今後の展望

まだ、僕のオレオレツール感が強いのですが、試しに使って意見をいただけると嬉しいです。以下の機能追加などを考えています。

余談

前のエントリで、取り上げたstatikは、実はこのgodzilで使いたかったというのがあります。ちなみに、godzil内部で使っているScaffoding用のライブラリで gokoku というものも作っています。

https://github.com/Songmu/gokoku

あるファイルツリーを元に、それ配下のファイルをGoのテンプレートに見立てて、一律指定位置に書き出してくれるものです。

そのために gokoku.Tmpl っていうtypeを定義しています。今後は gokoku.Hojo というのも定義したいですね。…はい。

Goのバイナリへのファイル同梱はstatikで決まり

https://github.com/rakyll/statik

Goのバイナリにファイルを同梱するという誰もが欲しいはずのものがなかなか決定版がなく、go-bindataがメンテを終了し、go-assetsもいまいちメンテが滞っているので、statikを使うことにしました。作者のrakyllさんも実績のある方なので大丈夫でしょう。

statikも少しpull requestの取り込みが滞っていたのですが、試しにpull requestを送ってみたらちゃんと取り込まれたので大丈夫そう。

https://github.com/rakyll/statik/pull/61

元々、ファイル単体を取得する分には問題なかったのですが、ファイルシステムとして走査しようとするとうまく辿れない問題があり、このpull requestで修正しました。ですのでより安心して使えるでしょう。

http.FileSystem インターフェース

こういう、ファイルを同梱するやつは http.FileSystem インターフェースを満たすのがセオリーでstatikもそうなっています。ただ、 http.FileSystem.Open() での単体ファイル取り出しは実装されているものの、ディレクトリ走査のための http.File.ReadDir() が正しく実装されているものが案外少なかったりします。

ちなみに、go-assetsも、正しく実装されていなかったので、一応pull requestを投げてはいます。

https://github.com/jessevdk/go-assets/pull/9

おそらく、ファイル単体を引ければ十分で、ディレクトリを走査して使うケースがあまりないため正しく実装されていないことが多いのでしょう。

statikの良いところ

mTimeを固定する-mオプションがある

mTimeを固定できるため、ビルドのたびに差分がでたりしない

// Code generated... コメントを付けてくれる

https://golang.org/s/generatedcode のルールに則って、自動生成ファイルとして認識してもらえる。

内部データが単なるzipである

データサイズが小さくできるし、ライブラリ側が更新されたとしてもアセットデータの再作成が必要ない。データがシンプルかつ将来に渡って不変で良いというのは、見事な設計。

statik/fs.Walk() が便利

filepath.Walk() と似たようなインターフェースで、 http.FileSystem を走査できる statik/fs.Walk() が定義されておりこれが便利です。僕の場合これが使いたかったので、今回pull requestを送った次第。

http.FileSystem インターフェースが正しく実装されている

今回の修正で正しく実装されました。

ということで

Goでのファイル同梱には statik をメインで使っていこうと思います。決定版になってほしい!

YAPC::Tokyo 2019で報恩謝徳の話をしてベストスピーカーを頂きました

http://songmu.github.io/slides/yapc-tokyo-2019/#0

「技術力が無い人間がエモに逃げてはいけない」という個人的ポリシーを持っていて、あまりエモい話は登壇ではしないようにしてきたんだけど、今回は「報恩謝徳」がテーマということで、思いっきりエモい話をしてやろうということで申し込んだ。このテーマならベストスピーカー狙えるだろうとも思っていました。

しかし、トーク採択していただいたものの、実は40分のところを20分にしてくれないかという打診があり承諾していました。僕は比較的運営から近い位置にいるのでそういう打診をしやすかったのかも知れず、そういう相談をしてもらえるのは嬉しいし、登壇者が増えるのも良いことだとも思い快諾しました。

とは言え20分にまとめるのは難儀でした。登壇は多少は慣れているつもりですが、今回はかなり難産で、資料作りに苦労しました。

プレゼン作る時は、話したいことをまずは書き出しまくって、アウトラインに収束させてからスライドに起こすのだけど、今回はテーマがテーマなので話したいことが多すぎて爆発してしまって、そもそもアウトラインに収束させられずに苦労した。ベストスピーカーを狙っていた気負いも合ったのでしょう。

もっと話したいとか、感謝を述べたいこと、面白いエピソードとかいろいろあったのですが泣く泣く削りました。

社内的には広報チェック通したほうがいいんですが、今回は事前に広報の担当者に「今回人生の話しようと思ってるんですけど、全然資料できなくて困ってるんで広報チェック回せそうにありません」と断っておいて「いいですよ」とは言われていました。本当は良くないんだけど!

スライドも当初はKeynoteに起こす予定だったけど、これは間に合わんな、ということでいつも使ってるMarkdonwからスライド生成する自作のプレゼンツール(Perl製!)を使うことに。だから逆に勢いよく話せたのかも知れない。

ベストスピーカーを狙ってるんだったら前日とかに宣伝エントリなりツイートなりしたほうがいいんだけど、最後の最後まで内容も収束させられないし全然自信も持てなかったのでそういうこともできなかった。

前夜祭後に @tokuhiromと@xaicronと飲みに行って全員が「スライドできてねー」って話してて、まあなんというかいつものYAPCの光景と言う感じで逆に落ち着いてプレゼンストーリーも見えてきた。この時「そんむーさん自分が意識高くないと思ってるなら相当重症ですよ」ってxaicronに言われたのが面白くて妙に印象に残っている。

xaicronはその後徹夜で資料作ったらしいけど、僕は早朝に起きて、会場で仕上げをしてなんとなく話せるかな、という手応えを感じたのは以下のツイート時点。

正直ベストスピーカーは諦めていて、資料は殴り書きみたいなアウトラインの域を超えてなかったので、まあこれを20分で話しきれたら御の字だろうと思っていた。

とは言え、トークの冒頭で「他のスピーカーの方は慎み深い方が多いか、言ってる人少ないんですけど、ベストスピーカー投票お願いしますね」という軽口を叩けるくらいには自信を持って話すことはできた。話し終わったあとも、少し時間オーバーしちゃったけど、話せてよかったという満足感はありました。

その時点でもベストスピーカーは取れるとは思ってなかったんだけど、YAPCの運営でもあり同僚でもあるpapixが悪くて、ベストスピーカーの発表前に社内のSlackでなにか良いことが起こったことを仄めかす発言をして「これはもしかしたらベストスピーカー取ったかも知れないぞ」とか頭によぎってしまった。

これでベストスピーカーだったら泣いてしまうかも知れないけど壇上で泣かないようにしないとな、とか思ったらその時点でなんだか泣けてきてしまって、いや仄めかしたのはベストスピーカーの話じゃないかも知れないし、別の同僚のスピーカーの話かもしれないからこれで泣いてたら馬鹿だな、とか色々思いを巡らせていたら、果たして本当にベストスピーカーであり、結局壇上でめちゃくちゃ泣いてしまった。人間揺さぶられると弱い。

ということで、多くの同僚やコミュニティの仲間達の前で泣いてしまったのだけど、温かく受け止めていただいたのは本当にありがたかったです。

YAPC自体は盛り上がっててよかった。若い人も結構話してたし、ベストLTもベストスピーカー賞も3位までPerlの話だったのも個人的には良かったと感じています。結構仕事が忙しかったのでフルで楽しめるか微妙だったんだけど、結局誘惑に負けて前夜祭からフルで楽しんでしまった。楽しめてよかった。YAPCが相変わらず僕にとってのモチベーションの源泉の場の一つでもあるのだなとも感じた日でした。あとはtokuhiromのキーノートの最後のスライドに写真を載せてもらえていたのは密かに結構嬉しかった。

Homebrewで自作ツールを簡単にインストール可能にする

まとめを先に

用語

これらは自前で簡単に作ることができます。公式リポジトリに頑張ってpull requestを送ることもできますが、個人的なものであれば気軽に自前で作ってしまうことがおすすめです。

tapリポジトリの作成

前項で書いたとおり"homebrew-"プレフィクスを付けて命名すればOKです。僕の場合homebrew-tapという名前で作っています。

https://github.com/Songmu/homebrew-tap/

このリポジトリ上のディレクトリ直下、もしくは Formula/ ディレクトリ配下にFormulaを配置します。上記のリポジトリの場合、Formula/ 以下に配置しています。現状7個のツールを登録しています。

このtapを利用したい場合は"homebrew-"プレフィクスを除いた形で以下のように登録します。

% brew tap Songmu/tap

また、以下の様にダイレクトにtapの登録とツールのインストールをおこなうことも可能です。

% brew install Songmu/tap/maltmill

Formulaの作成

FormulaはrubyのDSLファイルです。他のツールのFormulaを参考に見よう見まねで書くこともできますが、ここでは maltmill というツールの紹介をします。

https://github.com/Songmu/maltmill

実は1年以上前に作っていて、作りかけ気味なのですが、使い物にはなるし、実際活用しているので紹介することにしました。

コンセプトとしては、GitHub Releasesに登録しているアーカイブから簡単にFormulaを新規作成したり、更新したりすることができるものです。

インストール

# brew
% brew install Songmu/tap/maltmill
# go get
% go get github.com/Songmu/maltmill/cmd/maltmill

Formulaの新規作成

前提として、GitHub Releasesにアーカイブがアップロードされている必要があります。例えば、以下のようにすれば、ghqのFormulaが作成されます。

% maltmill new -w motemen/ghq

この場合、Formulaはghq.rbというファイル名で作成されます。適宜調整して、tapリポジトリにcommitしてください。

Formulaの更新

GitHub Releasesに新しいリリースが登録されている場合、以下のようにFormulaファイルを指定することで更新することができます。

% maltmill -w Formula/ghq.rb

これは、versionとアーカイブurlの取得と書き換え、アーカイブのsha256の再計算とその書き換えも自動でおこなってくれます。あとは更新内容を確認して、リポジトリにcommitするだけです。それで新しいバージョンをbrewでインストールすることが可能になります。

まとめ

まだ荒削りな部分もありますが、是非ご利用ください。mackerel-agentも以下でtapを公開していますが、maltmillに乗り換えていければいいな、と思っています。

https://github.com/mackerelio/homebrew-mackerel-agent

命名は、ビール醸造関連が良いなと思って、ビール製造工程の最初に麦芽を挽くのに使うMalt Millからつけました。

horenso v0.9.0でより便利になりました

https://github.com/Songmu/horenso

v0.9.0なので、version 1を出す前のRC的な気持ちでいます。アップデートは以下のとおりです。

設定ファイル(yaml形式)サポート

設定ファイルは環境変数 $HORENSO_CONFIG にファイルパスを指定します。設定項目は大体コマンドラインオプションに対応していて以下のような具合です。

noticer: /path/to/basic-noticer
reporter:
- /path/to/basic-reporter

こういうのを保存しておいて、crontabに以下のように記述します。

HORENSO_CONFIG=/path/to/horenso.yaml
11 * * * * horenso          -- /path/to/your-batch1 ...
23 2 * * * horenso -t daily -- /path/to/your-batch2 ...
23 2 1 * * horenso -t monthly -r 'additional-reporter' -- /path/to/your-batch3 ...

従来は、README.mdに書いてある通り、ラップするシェルスクリプトを書くのが一つのパターンでしたが、この設定ファイルの場合もっと見通しがよくなります。

またジョブによっては追加のレポーターを指定したいなどもあると思いますが、それに関して個別に追加することも可能です。上の additional-reporter と指定してある様な形です。個別指定した場合であっても、設定ファイルに記載のnoticer及びreporterは動作します。

このあたりドキュメントまだなのでversion 1までには書きます…。

ログファイル指定オプション(--log/-l)

ログをファイルに出力することが可能になりました。--log=%Y%m%d.log となど指定します。strftimeフォーマットが利用可能なのもポイントです。

verboseログを出せるように(--verbose/-v/-vv)

horensoは主体であるバッチコマンドの動作を妨げないように、標準出力や標準エラー出力にはそのバッチコマンド自体の出力のみ流し、horenso自体のログは一切出さない様になっています。

しかしそれでは、reporterやnoticerの動作確認時に困るという声もあり、それは分かるということで、--vebose オプションを追加しました。--verbose は重ねることができます。

という挙動となっています。

タイムスタンプのフォーマット変更

horenso--timestamp/-T オプションで出力への自動タイムスタンプ付与が可能ですが、このフォーマットがRFC3339の小数点以下6桁固定長に変更になりました。

この変更にあたって、Songmu/timestamper というライブラリを外に切り出しました。これは便利かつ実装も面白いので後日また別でブログを書こうと思います。

type Report struct の型情報の非互換修正

horenso コマンド自体は大きな非互換修正はありませんが、horenso.Reporter をライブラリ的に自前のreporterなどで利用している場合はビルドが通らなくなってしまうため、修正をお願いします。Reporterのフィールドからなるべくポインターを減らす対応をおこないました。

その他、コードの修正や効率化、リファクタリングも何点か実施しました。

より便利になったhorensoをぜひご利用ください。

オライリーの「入門 監視」の付録Cを執筆しました

入門 監視 ―モダンなモニタリングのためのデザインパターン

この本はPractical Monitoringの邦訳です。原著は持っており、良い本だと思っていたので、翻訳者の松浦さんが邦訳されている話を聞いたときには嬉しく思いましたし、そこで付録を執筆して欲しいという依頼もいただき、身に余る話でしたが、引き受けさせてもらいました。

そして「実践 監視SaaS」と言う内容を付録Cとして20ページほど書かせていただきました。原著が監視SaaSの活用を推奨してはいるのですが、内容的にはツールに偏らない、概念的で中立的な本であるため、監視SaaS活用に関してはもう少し具体的、実践的な話を補強して欲しいというオーダーを受け、書いたものです。

私は、Mackerel という監視SaaSのプロダクトマネージャーを務めており、それもあって依頼を頂いた形ですが、逆に、原著の中立的な良さを損なわないように公平さを心がけて執筆するのは苦労しました。とはいえ、私は、当たり前ですが、監視サービスの中ではMackerelが一番得意であるため、Mackerelも例示しながら付録を執筆する形となっています。

本書の推しポイント

付録を抜きにしても、本書は本当に良い本です。「監視はインフラエンジニアの担当領域である」や「監視は専門的な知識がない人には全くおこなうことができない」といった誤った固定概念を打ち砕いてくれる本です。私自身「アプリケーションの監視は、いわゆるインフラエンジニアより、アプリケーションを一番理解している人が監視を一番良くできる」と常々考えてきたため、この本はそれを伝えてくれている良い本です。

しかも、200ページ程度の本なのですぐ読めるでしょう。

筆者の主張が的確ながらも強めなのも面白ポイントで、個人的に良いと思った文言を以下に抜粋しておきます。

「メトリクスの履歴を保存していない(Nagios、お前のことだ) 」
「銀の弾丸はない。この本からこれだけは覚えておいてください。」
「お願いだから円グラフは使わないで」
「SLAとは、(ほとんどの場合) 願望や嘘である」
「多くのチームではアプリケーション監視が難しすぎるか、高い専門的なスキルセットを必要とすると考えているからだと私は思います。しかしありがたいことにどちらも真実ではありません」
「アプリケーションの計測を始めれば、もう病みつきになります」
「一般的に言って、何に対してであれロードアベレージに依存することは時間の無駄だと考えています。」
「ネットワークパフォーマンスの監視における最大の課題は、SNMPを使わなければならないという1点に尽きます」

その他の名言はぜひ皆様の方で見つけてください。

謝辞など

オライリーさんから報酬をいただけるような仕事ができたことは何よりの喜びです。翻訳者の松浦さんには良い機会を頂いて本当に感謝です。編集の高さんにもお世話になりました。

Practical Monitoringの原著を去年の頭に薦めてくれた、hayajoさんもありがとうございました。hayajoさんは僕が推薦して、この邦訳のレビュワーも担当されました。

付録執筆にあたっては、 kazuhoさんkyannyさんのblogから、一部文言を引用をさせてもらいました。ありがとうございます。

また、書籍「テスト駆動開発」からも引用させていただきました。t-wadaさんありがとうございました。そういえば、奇しくも、僕も付録C執筆クラスタになったことを愉快に思っています。(勝手に光栄だとも思っています)

入門 監視 ―モダンなモニタリングのためのデザインパターン
テスト駆動開発