valid,invalid

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

レビュー待ちの Pull Request 一覧を Slack に定期的に通知する

review 待ちの Pull Request 一覧を Slack に定期的に通知する仕組みを作ってみた。

完成品

以下の画像は朝11時 JST に自分のチームのレビュー待ちリストを表示している様。Slack の絵文字で「いまレビューしてますよ〜」「merged!」みたいな表現をするのはエンジニアしぐさだ。

f:id:ohbarye:20170826221056p:plain

private repo だと味気ない(かつ業務情報なのでモザイクだらけだ)が、public repo の PR だと Slack が自動的に展開してくれるのでよりファビュラスに見える。

2017-08-11 11 15 31

仕組み

3行で書くと…

  • review-waiting-list-bot という Slack bot が Heroku にデプロイされている*1
  • メンションされると GitHub API を叩いてプルリクエストを収集し、まとめて Slack に post する
  • 定期的に実行する仕組みは Slack のリマインダーを使う

review-waiting-list-bot

github.com

Node.js 製の Slack botフレームワークには前回作った KPT-bot 同様、 Botkit を使っている。

async / await を試してみたかったので Node version 8 にした。残念ながら Botkit が Promise に対応しておらずコールバックを色々書くハメになる*2のだが、GitHubAPI をコールするところはうまくまとめられる。

bot をコールする際に author, owner, repo を指定することができる。-repo のような表記で除外条件(exclusive)を指定することもできる。詳細は README#Usage を参照。

Slack Reminder

bot 側で定期的に post する仕組みも作れるのだがやらなかった。設定を持たないといけなくなる=ステートレスでなくなるし、Slack に慣れているチームなら reminder 機能を充分に使いこなしてくれるからだ。

ちなみに、毎朝11時にリマインドする場合は以下のようなコマンドになる。タイムゾーンはリマインダ作成者の設定に依存するようなので注意。

/remind #channel-name "@review-bot ls author:org/my-team owner:org -repo:design" every weekday at 11am

詳細は Set a reminder – Slack Help Center 参照。

反応

開発者間のミーティングで紹介↓した後、

f:id:ohbarye:20170826225525p:plain

社内の幾つかのチームで使ってくれているようだ。Slack で定期的に呼んでいるチームもあれば daily meeting の最後に手動で呼び出して情報を同期しているチームもある。

フィリピンの同僚から Pull Request を貰ったり、チームでなく個人の活動を拾い上げたりもした。

f:id:ohbarye:20170826224603p:plain

所感

開発者だけでなく Product Manager にも喜ばれたのが意外だった。開発の進捗を把握する一助になるとか。

なんにせよ思ったより使われて良かった*3というのと、社内にユーザーがいるとフィードバックがすぐに貰えてドーパミンが出ますね。

*1:free dyno でも worker プロセスが眠らずに働いているのでいつでもメンションに反応する

*2:https://github.com/howdyai/botkit/pull/278 で試みられたがずっと放置された末に author の心が折れたようだ

*3:前作の KPT-bot が思ったほど奮わなかったのでひとしお

Rails の form 内で disabled された submit ボタンを再度 enable する

form を submit する時に disabled されるボタンを re-enable するには $.rails.enableFormElements($form) を使う。

二重サブミット防止

まず、data 属性に disable_with を設定するとクリック時にボタンが disabled になり、二重 submit 防止になる。ラベルも disabled_with で指定したメッセージに置き換わる。

<%= form_for @user do |f| %>
  <%= f.submit 'Submit', data: { disable_with: 'Submitting...' } %>
<% end %>

re-enable

submit 後に画面ごとリロードするような処理ならよいのだが、submit イベントをオリジナルの処理でハンドリングしたときは disabled されたボタンを自前で元に戻してやらないといけない。

$.rails.enableFormElements($form) がそれをやってくれる。

$form = $($.rails.formSubmitSelector)

$form.on 'submit', (e) =>
  e.preventDefault()

  $.post(url, data)
    .done(navigateToNextPage)
    .fail (xhr) =>
      showAlert(xhr)
      $.rails.enableFormElements($form)

Controller spec で render_to_string の結果が empty string になる

View でちょっと頑張る必要があり Controller から render_to_string で文字列を得てから JSON に突っ込むようなエンドポイントがあるとする。

# controller/books_controller.rb

class BooksController
  # GET /book/:id
  def show
    @book = Books.find! params[:id]
    render json: { 
      book: render_to_string(:show),
      meta: @book.meta,
    }
  end
end
# view/books/show.erb

<%= extremely_decorate @book %>
<%= other_info %>

(※ 単純化すると View でやることではないのだが、現実はもっと込み入っている…)

このエンドポイントの controller spec として以下のようなテストを書くと render_to_string の結果が empty string になる。

# spec/controller/books_controller_spec.rb

describe '#show' do
  it 'returns expected JSON' do
    subject
    response_json = JSON.parse(response.body)
    expect(response_json['book']).to eq "decorated book expression"
    # got: "" で落ちる
  end
end

controller spec では通常 view を render しないので render_views を呼ぶ必要がある。

# spec/controller/books_controller_spec.rb

describe '#show' do
  render_views

  it 'returns expected JSON' do
    subject
    response_json = JSON.parse(response.body)
    expect(response_json['book']).to eq "decorated book expression"
    # It passes!
  end
end

呼ぶ位置が少し気持ち悪い気がする。

rbenv: yarn: command not found

手元の mac で突然 yarn コマンドがエラーを吐くようになった。何をしたか思い出せない…。

$ yarn
rbenv: yarn: command not found

うーん?と思いつつどこを参照しているか確認する。

$ which yarn
/Users/ohbarye/.rbenv/shims/yarn

なんで yarn がここに入っているのかわからないので消してみる。

$ rm /Users/ohbarye/.rbenv/shims/yarn

$ which yarn
/usr/local/bin/yarn

$ yarn -v
yarn install v0.27.5
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.35s.

動いた。完

行ってよかった builderscon 2017 Tokyo

builderscon - Discover Something Newに前夜祭から最終日まで参加してきた。

感想

行く前から「絶対これを聞く!!」というような目当てがあるわけではなかったが、来てみれば発表のジャンルも幅広いし、著名な海外スピーカーも来るし(同時通訳つき)、何も見つけずに帰る方が難しぞこれはという感じで楽しめた。

前夜祭のアルコール、1日目〜2日目のコーヒーやジュース飲み放題、弁当支給(どうしても日吉の飯屋行きたかったので食べなかったけど)のホスピタリティ、そして会場:慶應義塾協生館がとても綺麗でトイレ事情も完璧。環境面でも言うことなし。ノベルティのトートバッグも格好いい(余ってたので2つ入手した)。

“Discover something new” というコンセプトも良いなァと思いつつ、当事者意識や質問が湧いてくるのは “知っている領域の延長” だったりする。なので理論上は勉強すればするほど楽しめる!!

聞いた講演

各日ごとに残したメモをそのまま公開している。

特に印象に残った講演

前夜祭全般

書くことはできませんが、最高でした。特に最初のトーク「オンプレミスデータセンター撤退! - 大人のビルコン 〜撤退技術スペシャル〜(1)」が一番のお気に入り。

前夜祭通して思ったのは、成功事例の紹介も大事だが失敗した話や苦労している話も同等かそれ以上に大事だということ。失敗談を語る勉強会みたいなのはもっと増えてもいいかもしれない。(現在進行系の話や事件直後の問題は公にできないかもしれないという問題はある…)

Desktop Apps with JavaScript

Slack 社 @felixrieseberg 氏によるデスクトップアプリ開発入門的なお話。

Electron をもともと知っている人からするとあまり刺激的ではなかったかもしれないが、個人的には「こんなに簡単にたちあがるのかァ」という発見があったので良かった。デモ慣れしててすごいなぁと思った。

Electron に関しては触らずに放置していた負い目も合ったので家に帰って実際に手を動かして試してみた。

QAタイムでは Electron 絡みでなく Slack 社に関する質問をしてよいものだろうか…ともぞもぞしてたら終わってしまってちょっと後悔。

マイクロチームでの高速な新規開発を支える開発・分析基盤

グッと来たところは以下です。

データドリブンってこういうことか…。

いらないと思われる機能をガシガシ消したい引き算の気持ちは常にあるのだが、プロダクトの引き算をするのにも裏付け・論理が大事なのでその辺にも強くなっていきたい。

RDBアンチパターンリファクタリング

ベストスピーカーを受賞したトーク。会場の空気が前のめりというか、あまりの話の深さに会場全体が集中している感じだったのでこれは取るだろうな〜となんとなく思ったりしていた。

時間がかかるからこそ戦略を立ててやっていかないといけない…というのは業務でもひどく実感しているところがあり、それが以下の質問だった。

RDBアンチパターン リファクタリングについて話をしてベストスピーカー賞を取ってきた #builderscon - そーだいなるらくがき帳にも書いていただいて大感謝というほかない。早速試してみないと。

僕はMongoDBを本番で採用したことが無いけどFDWというPostgreSQLの機能がありますよってのをご紹介しました。FDWは要は他のDBのテーブルをPostgreSQL自身のテーブルのように見させる機能です。MySQLやOracleDBもあって便利なのでぜひ遊んでみて、試してみてほしいです。

Factory Class

Kickstarter で資金調達してキーボードを作ってる Jesse さんの話。

生産を依頼する工場選定に関する話題がメインだったのだが、中国工場の裏話が実話ナックルズというか、まぁとにかく"闇"という趣だった。

前日の講演 “Desktop Apps with JavaScript” で質問できなかったのをちょっと後悔していたのでこのトークでは英語で質問してみた。「中国での工場選定の他に、プログラミングやデザインでの課題はあったか?」という質問の答えが「プログラミングは本業で20年もやってるから大丈夫、助けてくれる人も多いし」という感じで強かった。

英語で質問するのはそんなに難しくなくても自分はリスニングに難ありなので回答を100%理解するのはあきらめて聞くのは同時通訳の方に頼ったりした。

帰り道で rebuld.fm に出演していた回を見つけたので今度聞いてみる。

rebuild.fm

ランチ

日吉の学生街がめちゃ懐かしかったので、申し訳ないながらも弁当をいただかずに外食した。

ハマトラ。竹炭入りの麺が黒い。昔はこってりした家系によく行っていたが今となってはあっさり塩そばを好むようになってしまった

f:id:ohbarye:20170806204724j:plain

とんかつ和栗。学生の時は無かった気がする。蒲田の有名店「檍」系らしい。林SPFポークは塩で食べるのがおすすめらしくカウンターに4種類もの塩が置いてあり、塩派にはたまらない

f:id:ohbarye:20170806204733j:plain

キャンパス

懐かしくて死にそうだった、次回も日吉だと個人的には嬉しい

f:id:ohbarye:20170806205422j:plain f:id:ohbarye:20170806205400j:plain f:id:ohbarye:20170806205413j:plain

最後に

ディズニーランド的なアレか…

builderscon 2017 - day 2 メモ

builderscon 2017 - day 1 メモ - valid,invalid に続いて2日目のメモ。まとめや感想はあとで。

※ 内容については間違っている可能性あり。


小さく育てるコンパイラ

  • コンパイラは実装量が多い
  • まずは既存言語のサブセット->自分が欲しい機能を足す->オレオレ構文に置き換えていく
  • なぜ構文が最後?どういう構文が良いかは動かさないとわからない。まずは動くものを作るのが大事
  • 既存言語は既に動いているので実装は絶対にできる。パーサの実装をまずは流用できる
  • MinCamlベース(小さい実装なので参考にしやすい)でLLVM
  • 今回欲しかった多相型

OSSの引き継ぎ方

  • Rubyの状況:2013年頃に初期の開発者がRustとかGoに行ったりしてしまった
  • 利用者としてできること contribute, fork, re-implementation, take over
  • 引き継ぎの始まり
    • イシュー/Email/DMで「引き継ぎたいんですけど」と言うと結構引き継がせてくれる。twitterはダメ
    • READMEで募集してるのもよく見る
    • 作者じゃないのに pull request にコメントしまくったりすると「お前やれよ」となったりする
  • rake
    • Jimが他界してしまって放置されることになった
    • これもhsbtさんが引き継いだ
    • まずhoeからbundlerへ。標準ボイラープレートを使って、テストや開発が簡単にできるようになっていれば参入障壁が下がる
    • 1.9のサポートを切ったらbreaking changeで色々なライブラリやツールから苦情が…
    • migration path をちゃんと用意すればよかった。うざいぐらいwarningだしたりとか
  • psych
    • Ruby側を変更するとJRuby側が壊れたりするのでCI入れたかったがownerしか設定できない
    • aaron からownershipもらうためにカンファレンスで直接はなした
    • セキュリティイシューも何回か踏んでいる。詳しい人が身近にいると便利
  • 「リリースすること」がとても大事
    • リリース権も一緒に渡したほうがよい
  • rubygems/rubygemsrubygems.orgではない)
    • 2015年にPMがいない状態でどうやっていくのか不明瞭になった
    • RubyTogetherという組織が引き継ぐことになった
    • その組織のbundlerチームが入って元々のコミッターが全員リムーブされた
    • ruby本体の変更を取り込んでもらうのが超大変

Factory Class

  • もともとはプログラマ
  • キーボードを作るのにそんな大変じゃないだろうと思っていた、一ヶ月ぐらいとか
  • 最初のプロトタイプに興味を持ってくれた人がいてkickstarterで300$ 50個売ろうと考えた
  • 2000個作ることになっていきなり大変になった
  • いろんな工場を回った、台湾、中国、日本(高かった)
  • 結果、Shenzhenで良い会社を見つけたのだがチームの営業員がやめてしまった
  • その会社の連絡がぜんぜんこなくなり、9ヶ月たって辞めた営業からキャンセルになったと連絡
  • その1ヶ月後に有名な企業から新しいキーボードが出た…何か裏側であったのかも
  • 反省としては、その工場からすると自分たちは最小顧客だったということ
  • 中国の起業とやりとりするときは非常に対面やマナーが大事

質問

  • 工場選定以外でプログラミングやデザインの問題はなかったか?
    • プログラミングは自分の領域なのであまり辛いことはなかったし、いろいろ助けてくれる人もいた
    • デザインについては外の人に頼んだりして結構うまくやってくれた
  • テストについて
    • 落下テスト、電気系統のテスト

The Evolution of PHP at Slack HQ

  • HHVM + Hack
  • SlackのDAUは半分が北米、次いでUK, JPの順
  • 急成長の中で大きいチームでも使えるようにする苦労
  • Jan 2017 Enterprise Grid リリースで大チームにも対応
  • 少チームでも大人数チームでも同じ体験をしてもらう必要がある
  • PHPを使っていると驚かれるが、世の中のスタートアップが使ってきたものである
  • Slack のリードプログラマfacebook出身でHHVMのエキスパートでもある
  • PHPは…正直ダメな子です
  • 2015年、SlackはOOPしてなかった…
  • 大きいチームで使われることになってパフォーマンスの問題が出てきたときの答えがHHVM
  • hack
    • バックグラウンドで走る静的型チェッカー。ただしPHPの特色である開発のスピードは落とさない
    • 後方互換姓あり
  • Route53によるカナリアリリースでパフォーマンス改善を確認できた
  • あるときHHVMのバグがあって大顧客のPixarに迷惑をかけたことがあった
    • パッチをあてられるような勉強も必要
  • レスポンスタイムが半分ぐらいに

builderscon 2017 - day 1 メモ

以下、所感混じりのメモ。まとめや感想はあとで書く。

※ 内容については間違っている可能性あり。


Desktop Apps with JavaScript

マイクロチームでの高速な新規開発を支える開発・分析基盤

  • LUCRA
  • gunosy で得られた知見を使って記事のグルーピングを機械学習でやる
  • 最初から分析できる環境が欲しかった
  • うまくいったポイント
    • やるやらないの切り分け
    • Gunosy の基盤の強さ、gunosy はGoの使用歴がかなり長い
  • やるやら基準
    • アプリのコンセプトを検証する
    • 大事なのは記事が見られて、検証・運用可能な基盤をつくること
    • やらないこと:Android、リファクタ、フォロー、お気に入り
  • gunosy/go という共有資産があり、OpsWorksでデプロイすればAPIサーバがすぐできる
  • 記事分類・生成に必要なAPI
    • クローラー、カテゴリ分類器、タブジェネレーター(特定カテゴリの記事一覧を生成する)
  • 2段階キャッシュ(ローカル、リモート)
  • マイクロアーキテクチャをやりすぎない
  • 分析
    • 大量のログを取得している、トップビューだけで10以上
    • 分析環境はRedash
    • 運用開発問わずチーム全員が分析用SQLを書く
    • Slack にKPIを通知
  • 分析結果の理由

    • ブランドイメージを追求したいからと言って、根拠なく「ファッション」「コスメ」を推すという意思決定は絶対にしない(データで確信が持てない施策は極力許さない)
    • 高いCTRやRRが期待できるプッシュ、機能通知しかやらない
  • ログ設計を最初からうまくやるには?

    • Gunosy にはもともと似たようなアプリがあり、ある程度ログの型が決まっているのでだいぶやりやすい
  • プロダクトとログの乖離
    • 開発者も分析基盤に触るが、専任のチームがいる。CSの博士号を持っていたり英語論文を読みまくったりするかなり高度な人たちが分析に責任を持っている。また、彼らの提案を受け入れる土壌がチームにある

複雑なJavaScriptアプリケーションに立ち向かうためのアーキテクチャ

  • 何も考えずに作ると何が起きる?
    • DOM をコードで作ってるとか…
    • 巨大なものを一目で理解するのは不可能
  • 分割する?機能、画面、リソースなどの単位
  • Presentation Domain Separation
    • Presentation と Domain をワケましょうということしか言っていない
  • MVVM
    • MVVM で model が VM を持っても良さそうだけど…?実際にやるとDOMのテストとかがModelのテストに入ってきてつらい。オブザーバパターンで依存関係を整理したりできる
    • PDS は model 設計については何も言っていない
  • layered architecture
    • モデルを3層にする。アプリケーション、ドメイン、インフラストラクチャ
    • アプリケーション層:プレゼンテーション層との窓口
    • ドメイン層:ディレクタ的関心。ドメイン層の設計は非プログラマでも読める感じだと良い
    • インフラストラクチャ層:技術的関心。プラットフォームや外部APIに依存した実装をドメインに書くと汚くなってしまうからインフラストラクチャ層に追いやろう
    • 依存関係はP->A->D->I だけどテスタビリティが高いのはDだからそこに依存したい
  • clean architecture

    • テスタビリティの高いドメイン層を中心に依存する
    • この考え方は具体的なアーキテクチャではない
    • 実現方法は、インフラストラクチャ層をDIする、プレゼンテーション層をモデル層が監視するオブザーバパターンなど
  • 状態管理の問題

    • ドメイン層に状態が散らかりすぎる
    • CQRS(コマンドとクエリを分ける)
  • バリデーションはアプリケーション層に書いている。コマンドというクラスを作って「アプリケーションへの入力が正しいかどうか」を判定する。(モデルに持つのがよくあるパターンだけど。フォームクラスとかは?)

  • 悩んだら原則に立ち返る

RDBアンチパターンリファクタリング

  • 不適切なデータベースがコードやサービスの成長を止める
  • データベースリファクタリングおすすめ
  • データベースの不吉な匂い
    • データは生き物、どんどん追加されていく
    • 積み木と同じなので初期設計に失敗すると仕様変更ができない
  • 何をリファクタするかはシステムによる

    • シングルアプリケーション vs マルチアプリケーション
    • シングルアプリケーションのときはDBマイグレーションが活きてくる
    • マルチアプリケーションは難しい、片方は止められなかったり…
  • データベースリファクタリングはすごく長いスパンになる、だから戦う準備が大事

    1. 抽象化。データベースアクセスには永続化フレームワークをはさむ
    2. データは変化する。モニタリングして変化の影響を知る必要がある
    3. テスト。
    4. 覚悟。DB停止はありえる。エンジニア以外がサービスの停止可否を握っているなら政治力も必要
  • 手間も時間もかかるからころ検討が大事。そのデータベースに価値はあるか、費用対効果は、いつやるべきか

    • 対象選定
    • リリース時期を決める
  • 変更前・中・後すべてのテストを行う

  • DBは影響範囲が広いので切り分けできるように小さな変更を繰り返すことが大事

質問

RDBパターンでRDBでないのを聞くのは恐縮 MongoDB MongoDBをすてるマイグレーションパスについて考えている 少しずつデータシンクして切り替えていく アプリケーションもMongoに合わせたコードになってしまっている マルチアプリケーション 一度に億単位のデータ全部をmigrateするのは無理

  • JSON
  • FDW (foreign data wrappers) postgres のように mongodb を扱うことができる、テーブルのように

QR code

  • QR code はデンソーが発明
  • 仕様書もある
  • 実は16個に分割できる
  • ヘッダーに全部でいくつ、自分が何番目かを持っている – 医療用カルテで1つだけだとエラーが起こりやすいので必要だった