valid,invalid

関心を持てる事柄について

webpackerを導入したRailsアプリケーションをDeisにデプロイする

webpackerを導入したRailsアプリケーションが手元ではちゃんと動いておりテストもパスした、あとはデプロイだけだ〜という段階で失敗した。

解決策

新しめの Ruby アプリケーション用の buildpack が使われるよう、BUILDPACK_URL を正しく指定する。具体的には以下のように環境変数を与える。

deis config:set BUILDPACK_URL='https://github.com/heroku/heroku-buildpack-ruby'
# 特定のバージョンを指定する場合
deis config:set BUILDPACK_URL='https://github.com/heroku/heroku-buildpack-ruby#v170'

経緯メモ

2時間ぐらい試行錯誤したメモ。

Gem::GemNotFoundException

デプロイ失敗、Gem::GemNotFoundException に出くわす。

2017-11-16T16:01:50UTC app-name[web.1]: /usr/lib/ruby/1.9.1/rubygems.rb:308:in `bin_path': can't find gem bundler (>= 0) (Gem::GemNotFoundException)
2017-11-16T16:01:50UTC app-name[web.1]:    from /app/bin/bundle:3:in `<main>'```

Rails | `bin_path': can't find gem bundler に対処する - Qiita に書かれているように bundler を install し直せばよいのか?と思ったが、ruby 1.9.1 というのがそもそもおかしいと気付く。

Deis's app detection system is not smart

Slack の過去ログを Gem::GemNotFoundException で検索したら過去に似たような事例があり、どうやらpackage.json が ルートディレクトリにあると Deis が Node.js アプリケーションだと判定するらしいとわかる。

deis のコードでいうとこのへん。たしかにこのへんでダウンロードした buildpacks をループで回して最初にマッチしたものを選択しているだけなので nodejs > ruby の優先順になりそうだ。

git rm package.json

過去ログでは deploy 直前に git rm package.json してから push するというワークアラウンドで回避していたので一旦それを試してみる。

remote: [1G[1G       Webpacker requires Node.js >= 6.0.0 and you are using 0.10.30[K
remote: [1G[1G       Please upgrade Node.js https://nodejs.org/en/download/[K

heroku-buildpack-ruby が使われるようになったはよいが、違う理由で失敗した。Node.js バージョンが古いので webpacker が使えないようだ。

ここで使っている Node.js バージョンは buildpack 側で指定しているもので、そもそも Deis が preinstall している buildpack のバージョンがやや古めと SRE メンバーに教えてもらった。

Set BUILDPACK_URL

v150を指定しているCHANGELOG によると webpacker をサポートし始めたのは v155 から。

冒頭に述べたように環境変数 BUILDPACK_URL があればそれを使うようになっているとのことなので指定した。

2時間ぐらいかけて遂にデプロイできた。 👏

Heroku では起きない

余談だが Heroku ではデフォルトで最新の buildpack が使われるはずなのでこうした問題は起きないはず。

また、buildpack のアップデート時に非互換のでかい変更がブッ込まれるのはそうそう無い印象なので一旦はバージョン固定なしで運用してみる。


所感

インフラとして使っているのにも関わらず Deis のコードを読むのは初めてで新鮮。PaaS のコードが読めるって凄いことだな、と思うなど。

ラストワンマイルはいつも大変。

Trade-off Sliders アプリ作った

先週に会社でトレードオフスライダーを使った議論を初めて行ったところ、とても良い体験になったので、今度機会があったときに即席で使えるようなスライダーアプリを作ってみた。

URL: https://ohbarye.github.io/trade-off-sliders/

Code: https://github.com/ohbarye/trade-off-sliders

trade

最近フロントエンド開発を忘れ気味なので思い出そうと React で書いた。思い出せたような、こんな感じだったっけ、というような…

また、ついでに material-ui の version 1 がようやく出そうということで beta 版を触ってみた。0.x 時代と非互換な変更がかなり多いうえ、ドキュメントもまだまだ整備中という感じだったのでプロダクションで使っている人は大変そう。個人的に何より困ったのが、今回まさに使いたかった Slider コンポーネントが beta 版リリース時点ではスコープアウトしていて使えないということだった。当面は rc-slider を使ってくれやというのでしぶしぶ従った。

create-react-app で作ったアプリをシュッと GitHub pages にデプロイしよう、と思っていたら公式 README では gh-pages (npm ライブラリ) を使ったやり方が紹介されていた。 一回設定を終えれば npm run deploy コマンドだけで勝手に gh-pages ブランチにデプロイしてくれて git 操作すら不要で結構よかった。

最近知った GitHub の便利機能3つ

はい、3つです。

  1. スクリーンショットをローカルに保存せずに貼り付ける
  2. 表をダイレクトに貼り付ける
  3. Viewer から色々アクションを起こす

スクリーンショットをローカルに保存せずに貼り付ける

Mac のショートカットでクリップボードに保存したスクリーンショットをそのまま issue や PR に貼り付けられて便利。

sc

使えるショートカットは以下の通り

対象 コマンド
画面全体 Command + Shift + Control + 3
マウス選択の範囲 Command + Shit + Control + 4
選択したウィンドウ Commadn + Shift + Control + 4 + space 、対象ウィンドウをクリック

表をダイレクトに貼り付ける

spreadsheet や Excel などからクリップボードにコピーした表形式のデータをそのまま issue や PR に貼り付けられて便利。

spread

Viewer から色々アクションを起こす

特に Copy permalink が良い。permalink を貼るとコードスニペットを展開してくれるようになったのでなお良い。

link

now = ohbarye.hired_at.since 2.years

「転職が成功か失敗か決まるのは(退職|転職)エントリを書いた時じゃない、入社から半年経ってからだ」とうそぶきつつ大した振り返りもせず早2年…

というわけで Quipper に転職してちょうど2年が経過したので自身のことを中心に振り返ってみる。

2年前

思えばよく採用されたな…と思う、タイミングが良かった。現在は採用のハードルが上がっているので今の Quipper に2年前の俺が応募したら不採用になるだろうなと思う。これはチームの成長の証左でもあるので良いことだ。

転職まで

当時の俺はSIer (システムインテグレーター) に勤務する新卒3年目の SE (システムエンジニア) で、1年目はちょっとした Java の研修というトンネルを抜けるとそこはテスト仕様書と人力テストの国…。技術力を高めたいと主張して色々仕事を振ってもらってもコードを書く時間は半分も無かった。日曜プログラマとしてたまにコードは書いていたが自分の業務を少し助けるものか、ちょっとしたおもちゃを作ってばかりだった。原点…と呼べるかすら危ういこの環境、とても狭い世界で、小さなプログラムと大量の仕様書を書いていた。

学校という環境設計の中で生きていけないという諦念とともに教員の道を辞した人生をどこかで清算したいと思っており、こうした信念と実にマッチした Quipper と比肩する候補はその時は存在しなかった。今も存在しないかもしれない。

採用が決まってから

これまでの自分のスキルが全く通用しない世界に飛び込むのだと思ってとにかく焦った。

あまりに焦ったので「入社までに何を勉強すれば良いでしょうか」と正直に聞いた。その時に刺身さんが返してくれた内容は「これは報いないといけない」という思いともによく覚えている。

2015年の8月は業務をさっさと終わらせて家に帰ってはアドバイスに従って Quipper で使う予定のテクノロジーと英語をほぼ毎日勉強し、何かしら形にしておきたいとブログを書いていた。完全に忘れていたが2015夏タグが付けてあったので今でも読み返せる。

転職直後

絶対プルリクキメ太郎と気張っていった初日、"予習"の甲斐あってかなんとかキメられた。最初のpull requestが"要らなくなった機能の削除"だったのは不思議な気持ちだった。それまでコードをちゃんと消すチームでの開発をほとんどしてこなかったのだ。

このとき、GitHub flow も pull request ベースの開発もCIも staging app も何もかもが新しかった。

詳細は割愛するが入社してから暫くは受験サプリというプロダクトを Quipper のコードベース上に migrate する大掛かりな移行プロジェクトをやった。日本の web engineer は当時5人のみで、終わるかどうかとてもあやしい量のタスクがあった。2015年末頃には振り返れば炎上と言って差し支えないほど働いていた。

前職のデスマーチ案件よりは稼働時間は少なかったのと、とにかくコードを書くことだけに集中できたので当時はそれほど苦に感じなかった。土日に出勤してテスト項目をひたすら消化していた頃に比べれば何もかもが遥かに良かった。ただ、もう一度やれと言われたらやりたくはない。

このプロジェクトが終わってからは一度も休日出勤はしていない(はず)。

それから

あっさり2年が経ってしまった。

チームは数倍の大きさになり、その中で俺は今年度は Engineering Manager という役割を担うことになった。Quipper の Engineering Manager は世間一般でいうテックリードとも(プロジェクト|プロダクト)マネージャーとも違うところにあって、卓越した技術力とかずば抜けたマネジメント能力が求められるものではないと考えている。組織やプロダクトといった大きい主語の実存に対して物言いたい人が集まっている立場の気がする。

そう、Engineering Manager という役割につき、チームに貢献するメンバーとして一人前の自覚はありながらも、いちエンジニアとして俺はどんな奴なんだ?どうありたいんだ?と今でも問い続けている。

先月にメキシコの Engineering Manager が日本に訪れた際に俺のキャリアについて聞かれることがあった。その時に「実のところ俺が “real engineer” としてのキャリアをスタートしたのは Quipper に入ってから。つまりまだほんの2年前なんだ」という話をした。

いったい何が “real engineer” なのかは言った俺にもわからないのだが、確かに言えるのは前職の俺は “SE” であってエンジニア*1ではなかったということだ。今は自分が信じるエンジニア像に少しは近づいた…はず。

エンジニアとしてどう変わったか

この2年間は、かつて担当していた小さな業務システムでは深く考えなくてもそれなりにやれていたことを何回も何倍も真剣に見つめ直したし、数え切れないほど新しいことも獲得した。例えば…

チーム開発の基礎。GitHub flow とレビュー。レビューしてもらいやすい pull request とそうでないものの差異。誰かと一緒にあるいはチームでコードを書くということ。コードレビュー会。可読性。リファレンスの貼り方。Excel方眼紙ではないドキュメンテーション

パフォーマンスのこと。N + 1 クエリがサービスに及ぼす影響、防ぐ方法、万一混入した場合でも見つけられるようなパフォーマンスモニタリング。データベースの特性とそれに応じた実装。富豪的計算をしすぎない。

キャッシュ。強いキャッシュと弱いキャッシュ、それぞれの実現方法。データの更新頻度、転送量の削減。

Single Page Applicationのこと。Backbone.js + Marionette.js に始まってReact.jsへの変化・移行。メリットとデメリット、選ぶべきときとそうでないとき。

デザイン。ユーザー目線とは。ビジュアルではなく体験にこだわること。どうやってデザイナーと協業するか。

API設計。SPAのバックエンドとして見た時の、REST・RPCそれぞれのメリット、デメリット。ステートレス。ページング。あるいはネイティブアプリのバックエンドAPI設計。後方互換性。

外部システムとの連携インタフェース設計。冪等性とリトライのこと。大量データの捌き方。

テスト。ユニットテストやフィーチャーテストがいかに開発に安心感を与えるか。E2Eテストの重要性と難しさ。テストは実装の最初の再利用、つまりテストが書きにくければ設計が悪いということ。

リリース。小さく繰り返すことの重要性。ユーザーの驚きを減らす。バグはすぐ直す。でかすぎる feature branch は作らない。コードの変更なしに feature toggle できると理想的。

データ分析。BigQuery や TreasureData のこと。イベント設計に失敗すると分析が活きない。イベントトラッキングの発火タイミングのコントロールに気をつける。データがあって初めて見えるユーザー像もある。A/Bテストの設計と実装、振り返り。

アーキテクチャ。複数アプリケーション、複数データベースがいかに複雑か。アプリケーション間の依存関係の整理がいかに大事か。web サーバとアプリケーションサーバでできること・できないこと。

採用のこと。自分たちのことをよく知らないとできない。短時間で候補者のことを最もよく知るための質問とは。コードテストの評価の仕方。

グローバル。英語。相変わらず今でも手こずっている。ハチャメチャでもひどい発音でも通じるが、それは相手の善意によってコミュニケーションが成り立っているから。リモートだからこそ気にすべきコミュニケーションのやりかた。マーケットの特性。localization、internationalization。

カスタマーサポート。日々ユーザーと直に接しているメンバーからプロダクトへのフィードバック。使いづらい機能やバグをリリースしてしまったときのゴメンナサイ感。

受託ではなく自社のプロダクトをやっていくということ。ユーザーフィードバックのありがたさとつらさ。競合への意識。

思いつきで書きなぐっただけでもこれだけのことを2年前の自分はほとんど知らなかった。

生活の変化

裁量労働制になり10時どころか11時出社も危うい体となってしまったがライフスタイルを自由に構築できるので、妻と京橋でランチしたり早く帰ってジムに行ったり銭湯に行ったり出社前に家で英会話レッスンを受けたり走ったり自宅近くでランチしたりできる。

福利厚生・給与

書籍購入やカンファレンス参加費を社費でまかなってもらえる。それぐらい当たり前、という風潮があるが前職ではまったくもって当たり前でなかったのでありがたい。

ダメ元で頼んだら会社に懸垂台と卓球台を置いてもらえたのもありがたい。

給与は転職時の1.8倍ぐらいになったのであまり不満はないが良ければもう一度1.8倍してほしい。

これから

勤続年数でいえば今のチームでは相対的に古株ぽくなってしまった。もろもろ聞かれたり答えたりするのは全然構わないのだが、ドメイン知識以外のところでもっと勝負したいとかいう気持ちがある。1つの技術や言語に精通している感覚が未だ持てていないことに強い課題意識を感じる。

Be the worst の精神を忘れたくない、技術系のコミュニティから刺激を受けたいという思いもある。直近では勉強会やカンファレンスでの登壇や週1~2での副業を積極的にやってみるというのも卑近な方法だろうか。

今年度になるまではサービスの基盤を作るためにやらなければならない山積みの仕事を終えた今、ようやくエンジニアとしてやりたいことを提案したり挑戦したりするフェーズが来ているなと感じている。だからこそインプットとアウトプットにこれまで貪欲になろうとしているのかもしれない。

中期的には日本国外に居住したり、教育以外の事業領域も体験してみたい。だが、最終的にはやはり最強の教育サービスを作ってみたい。

結論

冒頭で"転職が成功か失敗か"という表現をしたけれども、実際にはその2択ではなく「成功ぽい」「失敗ぽい」というようなグレーゾーンが大半を占めるはず。

俺にとってはどうだったのか諸々考えてみたけれど、2年前に戻ってやり直せるとしても同じ転職を選ぶんじゃないかなぁ…。これは限りなく成功に近い転職と言えるだろうか?

*1:ここでは"エンジニアリングに関する専門的な技術を持った実践者"という意味

"kill N + 1 queries" Tシャツ作った

絶対に殺すという強く熱い"想い"を"カタチ"に。

仕上がり予想図

f:id:ohbarye:20170910153032p:plain

ロゴ

白黒両方作って試してみた。

f:id:ohbarye:20170910153028p:plain

反転していると見づらい。

f:id:ohbarye:20170910153035p:plain


加工代や送料込みで4,000円弱かかった。前は2,000円ぐらいで作れた気がしたのだが気のせいか?

(追記) 9/16に届いた。

automaildoc gem でメール一覧と文面を自動生成する

RSpec からメール一覧を自動生成する gem を書いてみた。

github.com

使い方

gem を install したのちコマンドラインから AUTOMAILDOC=1 rspec を走らせるとメールを一覧表示するHTMLを生成する。

https://user-images.githubusercontent.com/1811616/29994112-c6dacbc6-9002-11e7-812f-a346d415d6c4.gif

名前も設計もほとんど autodoc を参考にしている。

背景・課題

「法務・ブランドチェックが入るのでメールを確認したい」

「新たに送信するメールの文面考えるので類似メールの文面見られますか?」

「この前もらったメール文面のプレミアムユーザー版だとどうなりますか?」

プロダクトマネージャーやビジネスサイド、カスタマーサポートなどのステークホルダーからのこうした問合せには、開発者がコードや I18n の翻訳ファイルを見たりしつつ都度回答してきた。

しかしA/BテストやCS要望のために少なくない頻度で内容がアップデートされたり、日々の開発で気づかないうちにメールが増えたり減ったりするし、同じメールでもコンテキストに応じて変わる内容を追従できていなかったりと諸々問題がありそうだった。

この課題に対する解決策として同僚の yuya-takeyama さんが autodoc みたいに RSpec から自動生成したら便利なのではというアイディアを出し、tanaka51 さんが 20 percent policy 的な時間でプロトタイプを作ってくれていた。7月に tanaka51 さんが退職されて以降この課題が放置されていたのだが再度「メール一覧見たい」という要望を受けた際にこれを思い出してガッと gem 化してみた。

HTMLメールがきちんと表示されない問題があるが近日中に直す。version 0.1.3 で表示されるようにした。

現状

会社のレポジトリに automaildoc を突っ込んで「こんなのできますがどうですかね」と [RFC] ラベル付き pull request を投げてみたところ「やってみましょう」と即マージされた。ありがたい。

課題

生成されたHTMLをどう共有するか

秘匿性の高いものはまた別のやり方が必要だが、/doc/mails/toc.htmlGitHub pages で公開するのが最も簡単そう。

定期的に更新する仕組み

全部コマンドラインで完結するので Jenkins などで定期的に生成して pull request を自動で push すると良さそう。

個々の開発をフックにするなら Git hook が使えそう。pre-commit hook で変更されたファイルをチェックし、 mail spec や翻訳ファイルに変更があれば rspec を走らせてドキュメントを自動生成する…と書いていて思ったが結構面倒くさそう。

mail ごとの rspec を書かないといけない

ツールに合わせた開発はしたくない。が、request spec と違って mail spec 自体に込み入ったロジックや fixture を用意するケースはほとんどなく、もともとさらっと書いてあれば導入の費用対効果は悪く無さそう。

感想

運用やめたら「automaildoc やめた」という記事を書きます。

Gem の install / uninstall フックの使い方

Git hook を手軽に管理できる huskyRuby 版が欲しいかもと思い最近 rusky という gem を作っている。

github.com

gem install 時に Git hook スクリプトを自動生成し、uninstall 時には勝手に消してくれる感じにしたい。そんなわけで gem のインストールフックの使い方を学んだ。

知ったこと

走らせたいフックを rubygems_plugin.rb というファイルに定義する。rubygems_plugin の話は Plugins - RubyGems Guides あたりに書いてある。

# lib/rubygems_plugin.rb
require 'rubygems'

Gem.post_install do |installer|
  # whatever you want
end

Gem.pre_install do |uninstaller|
  # whatever you want
end

使えるフックは module Gem - Documentation for Ruby 2.4.0 あたりを参考にする。

これらのフックを gem_name.gemspec ファイルに書いても動くようだが、一部環境では動かないようだ。

ハマっていた問題

こんな Gemfile を書いて色々テストしていた。

# test-repo/Gemfile
source 'https://rubygems.org'

# it doesn't work
gem 'rusky'

# it works
# gem 'rusky', path: '/Users/ohbarye/.ghq/github.com/ohbarye/rusky'

# it works
# gem 'rusky', github: 'ohbarye/rusky'

同僚の松島さんに使用例を教えてもらった

見比べて何が足りないかと思えば rubygems_plugin.rb 内で require 'rubygems' していなかったのが原因らしかった。足して見たところうまく動いた。とはいえ、うーん、require しないとこのへんで定義してるメソッドが読まれない?Gem class のこととかよくわかっていない。また、なぜ path や github オプションの指定ではうまく動くのかもわかっていないので時間あるときにコードを追いたい。

現状

手元のテスト用レポジトリでは上記のどの Gemfile の書き方でもうまく動いているようだ。