| @Mac/iPhone

Touch Bar
Touch Bar

リモートワーク中心の世の中なので Slack の Status で離席していることやミーティング中であることが分かると便利なはず。というわけで自分はなるべく Slack の Status を更新するようにしているが、 Slack アプリ内での Status の更新は面倒くさい。メニューを押して絵文字選んでひと言アップデートを入力とか毎度やってられない。ボタン一発で Status を更新したい。

MacBook Pro の Touch Bar は評判が悪い。自分もあまり便利だと思わないのだけど、一つだけ便利な使い方があって、それがこの Slack の Status アップデートボタンを配置するというもの。 Touch Bar に配置されたボタンを押すだけで食事中であることや退勤済であることを Slack の Status として表示できるようになる。めっちゃ便利。

なお、オリジナルのアイディアとソースコードは 9m さんのものです。

必要なもの

準備

1. Slack の API Token を発行する

2. 9m さんの gist を clone し、手元で動かせるようにする

$ ghq clone https://gist.github.com/af5894ced5cc1ac38bfd2687cad7c780.git slack_status
$ cd clack_status
$ bundle install
$ echo "SLACK_TOKEN=XXXX" > .env
$ bundle exec app.rb "🍺" "退勤しました"

ちゃんと設定できてれば以下のようになる。

コマンドラインから Slack Status をアップデートしている様子
コマンドラインから Slack Status をアップデートしている様子

3. Automator を開き、クイックアクションを設定

新規作成で「クイックアクション」を選ぶ。

Automator を開き「クイックアクション」を新規作成
Automator を開き「クイックアクション」を新規作成

アクションの中からシェルスクリプトを選ぶ。

シェルスクリプトを選ぶ
シェルスクリプトを選ぶ

実行したい処理をシェルスクリプトで書く。

実行したい処理をシェルスクリプトとして記載
実行したい処理をシェルスクリプトとして記載

自分は以下のようにしている。

export PATH="~/.rbenv/shims:$PATH"
export LC_ALL=ja_JP.UTF-8
export LANG=ja_JP.UTF-8
cd /Users/morygonzalez/src/gist.github.com/slack_status
bundle exec ruby app.rb "🚽" "放尿 or 脱糞中です"

なお、赤枠で囲った「ワークフローが受け取る項目」は「入力なし」にしておかないとちゃんと動かないので注意。

入力なしを選択
入力なしを選択

設定完了したら名前を付けて保存する。自分の場合は Slack トイレ などのような名前にしている。この作業を追加したいコマンドの数だけ繰り返す。

4. キーボードショートカットの割り当て

システム環境設定 -> キーボード -> ショートカット -> サービス の順に進む。正しく Automator でアクションを設定できていれば「サービス」の一覧に表示されるので、割り当てたいショートカットキーを割り当てる。

ショートカットの設定
ショートカットの設定

5. BetterTouchTool で Touch Bar をカスタマイズする

タッチバーに表示されるボタンのアイコンとラベル文字を選び、タップしたときにショートカットキーが実行されるようにする。

BetterTouchTool で Touch Bar をカスタマイズ
BetterTouchTool で Touch Bar をカスタマイズ

こうすることで Touch Bar から Automator のクイックアクションが実行され、めでたく Slack の Status がアップデートされるようになる。

ちなみに自分の Touch Bar はこんな感じ。

Touch Bar の様子
Touch Bar の様子

ほこりをかぶってる Touch Bar を是非有効活用してあげてください。

Touch Bar がないパソコンを使っている人向けの情報

Touch Bar のない Mac を使っている人はこのやり方を使えないので Slack の Google Calendar 連携機能を使うと良いと思う。設定に Status Sync という項目があるのでこいつを On にすると、 Google Calendar で予定が入っている時間になると Slack の Status を自動で更新してくれる。

Google Calender の Status Sync
Google Calender の Status Sync

会議中であることくらいしか共有できないので Touch Bar にいろんなボタンを配置するのに比べたら不便だけど、カレンダーに予定を入れておくだけで Slack の Status を更新できるようになるのは便利。

今後の課題

良くありがちなのが「仕事中」の Status のまま退勤してしまうというやつ。夜中や週末も仕事している異常な人になってしまう。スマートフォンからも同様にめっちゃ手軽に Slack の Status をアップデートしたいけどまだソリューションを見つけられていない。情報お持ちの方いたら教えてください。

| @技術/プログラミング

7 年間眠っていたブランチを起こして、 Lokka の ActiveRecord 化に取り組み始めた。元のブランチは hrysd さんが取り組んでいたやつだ。

現在の master の内容を取り込むのが大変だった。 active-record ブランチでは ActiveRecord 化と同時に様々な改良・改変が行われていて、 master の内容と思い切りコンフリクトするものがあったりして、コンフリクトの解消作業はかなり大変だった。

active-record の大きな変更点は以下。

  1. カスタムパーマリンク機能の削除
  2. 「もっと読む」機能の削除
  3. カテゴリーをネストさせる機能の削除
  4. ユーザー認証方法の変更(カラムの追加)

このうち 1 と 2 は削除された機能を復活させた。自分が使っていてなくなると困るし、特にカスタムパーマリンクは既存サイトでこの機能を使っているところがデッドリンクだらけになって散々な目に遭ってしまう。 4 に関しても、 master の認証方法と互換性を持たせないと既存ユーザーがログインできなくなるので古い認証方法でもログインできるようにした。

3 に関しては WordPress との互換性を考えると必要かもしれないが、自分で使ってなくてユースケースが思い浮かばないのでいらないかなという感じがする。そもそも Lokka は WordPress キラーとなるべく Fjord 社内で作られ始めたと認識しているが、 WordPress は相変わらず元気だし Lokka の利用状況的にも WordPress alternative を目指す必要はないと思う。

そのほか、 rake db:delete が動かなかったのを直したり bundle update をしてぶっ壊れたところを直したり、デフォルト以外のテーマが ActiveRecord 化してなかったのを対応させたり( dm-pagination から kaminari へ移行)して ActiveRecord 5 で概ね動くところまで持ってくることができた。

ActiveRecord は良くできていて、 DataMapper だと難しかった JOIN した上での集計クエリなどが書きやすい。ドキュメントが山ほどあるのもよい。 DataMapper は情報が少ないのが一番つらかった。一方で DataMapper だと気にする必要がなかった N+1 問題を自分で解決する必要がある。 View でうかつに参照するテーブルのデータを増やすと N+1 問題が発生して途端にパフォーマンスが劣化する。

また、誰がどんな DB で利用するかわからない状況で db/schema.rb を git で追跡してよいものかというのもひかっかる。 ActiveRecord を使う以上、 migration と schema.rb からは逃げられないのだが、 MySQL で使う人も PostgreSQL で使う人も SQLite で使う人もいて、それぞれの DB でマイグレーションを実行するごとに異なる schema.rb が吐き出されるので git で追跡すべきではないのではないかと思う。どんなデータベースで利用されるかを意識せずに開発できる、という点では DataMapper の方が CMS 開発向きだったと思う。

以前の Lokka であればあまり Ruby 知らない人でもとりあえず git clone して自分の好みのテーマを追加して Heroku に push すれば動かせたが、 ActiveRecord 化することで N+1 問題など Rails に強くないと触りにくい感じになってしまった。ただ、 Sass は Ruby を捨てて C に移行したし、 Slim なんかも JavaScript フロントエンド技術の盛り上がりの陰で開発は停滞している。こういう時勢になってくるとフロントエンドに強いマークアップエンジニア兼ウェブデザイナー的な人が Ruby 製の CMS を使う動機はなくなってしまう。 CMS を使ったサイト構築でも Sass や Slim を使って HTML コーディングの生産性を上げ、 Heroku を使って簡単に deploy できる、というのが komagata さん達が最初に想定してた Lokka のユースケースだと思うけど、 JavaScript によるフロントエンド技術が強力になりすぎて、生産性の高いフロントサイド開発のために Ruby を経由する必要がなくなってしまった。


これから Lokka はどうあるべきなのだろうか。モダンなフロントエンドフレームワークは強力だ。否が応でも JAMStack に対応していくしかないだろうと思う。つまり Sinatra で作るのは API (と管理画面)だけになり、フロントエンドは React や Vue.js で作るべきだろう。ちょっとしたサイトを JAMStack で構築したいが、 API に良いのがない、とはいえ Rails は使いたくない、というケースで Lokka を使うという感じだろうか。ただ、いまは Firebase なんかもあるのでそもそも API を自前で持つ必要はないのかもしれない。どのみちかなりニッチなユースケースになるだろう。

ちなみにこのブログの Archive ページは中途半端ながら React で作っていて割といい感じに動いている。 ActiveRecord 化が済んだら React でサイト全体を作り直してみたい。

| @技術/プログラミング

DataMapper のドキュメントを見たくてググったが出てくるのは Stack Overflow ばかりで公式サイトが検索結果に出てこない。 GitHub の DataMapper のリポジトリ( Archive されている)経由で見に行ってみると、なんと ROM ( Ruby Object Mapper ) のページにリダイレクトされた。

ROM は Hanami で使われる ORM で、 DataMapper よりもさらに ActiveRecord と使い心地が異なる。

Qiita の以下の記事を読むと使い方のイメージが湧く。

軽くてシンプルなのだろうがだいぶ特殊だ。

Lokka の使い手は少なくとも Heroku が使える人で、そういう人ならば ActiveRecord の方が Rails の本やドキュメントで学びやすいはずだ。というわけで早めに、真剣に ActiveRecord への移行を考えなければならない。

| @技術/プログラミング

lokka/lokka 、 Pull Request を出す度に Hound CI のチェックが走って bot にコードレビューでぼこぼこにされるので、この bot を黙らせるべくガチャガチャやってた。 Hound CI のチェックルールは Rubocop に準拠しているようで、 2011 年からある Rack アプリを Rubocop のチェックにかけるのは面白かった。

Lokka 、意外と Hacky なコードが多く、条件式内での代入とか、ヨーダ記法とか、後置の until とか、スコープが広い一文字変数とか、めっちゃ長いメソッドとか、 if 文のネスト、代入したものの使われてない変数なんかを修正した。 method_missing はカスタムフィールドを定義できるという Lokka の仕様上根絶できなかったけど、 .rubocop.yml に最低限の除外ルールを追加して Rubocop のチェックはパスするようにできた。

Lokka 、 ORM が ActiveRecord じゃないことが問題だと思ってたけど、真の問題は lib/lokka/helpers/{helers,render_helper}.rb にビジネスロジックが詰め込まれてることだと思った。しかもこのあたりのコードの可読性がよくなく、触るのが怖い感じの複雑なやつが多い。この辺のコードをもうちょいクラス化して分割し、ユニットテストも手厚くしていかないと ORM を変えても F/E を今風にしてもウェブアプリケーションとして生存していくことは厳しいと思う。

前に進んでいくためにも Rubocop のチェックを入れる&パスさせるのはプラスになると思う。 頑張ってメンテしていくぞ。

追記

この辺のコードをもうちょいクラス化して分割し

と書いたけど、 Rails と違って手軽にサクッと作れるのが Sinatra の良い所なわけではあって、仕事で作る Rails アプリのノリでクラスやファイルを分割したりするのは違うのかもしれないと思った。 Rails で作られたオープソースの CMS やブログツールに長生きし続けるものがないのも、 Rails の場合、個人が偶発的に始めてメンテ出来るようなものになりにくいからかも知れない。

とはいえヘルパーがビジネスロジックを所持しているのはテスタビリティやメンテナビリティが良くないので Lokka と心中する覚悟でやっていくぞ!!!、!

| @技術/プログラミング

Pinboard にブックマークしたらはてなブックマークに同期するやつを作った。

なんで Pinboard を使うのか、どうしてはてブに一本化しないのかというと、洋物のサービスを使うときに Pinboard の方が使いやすいから。 IFTTT に Pinboard 連携機能はあってもはてブ連携機能はないし、 Delibar や Reeder や ReadKit も Pinboard には対応しているけどはてブには対応してない。あと Pinboard は広告出ないしホッテントリ的なものもないので気がついたら Amazon で買い物してたとかホッテントリの海に溺れてた、ということも起こらない。とはいえはてブのコメントでキャッキャッウフフはしたい。なのでブックマークするときは両方にしたい。パソコンの Chrome からブックマークするときは Taberareloo でクロスポストできるのだけど、最近 iPhone からブックマークすることが増えて(iPhone 進化し過ぎて仕事するときしかパホコン使わなくなった) Pinboard とはてブにそれぞれブックマークするのがだるかった。そういうわけで Pinboard をメインにしつつはてブに同期を試みた。

はてなスタッフの aereal さんが作ってるはてブ API 用の gem (aereal/hatena-bookmark-restful: A client library for Hatena::Bookmark RESTful API)あって使わせてもらったのだけど、これはそのままだと使えない。タグが複数あるケースに対応してない& User-Agent を送らないので API 側から 401 Unauthorized が返ってくる。なので雑にモンキーパッチした。

はてなブックマークの API は tag を 10 個まで設定できるけど、以下のように Request Body が Encode されるのを期待しているっぽい。

"comment=&tags=ruby&tags=http&url=https%3A%2F%2Fgithub.com%2Flostisland%2Ffaraday"

この様な Request パラメーターを Ruby で表現すると以下のような Hash になると思う。

params = {
  comment: '',
  tags: ['ruby', 'http'],
  url: 'https://github.com/lostisland/faraday'
}

Hash は当然のことながら同じキーを複数持つことはできないから、 tags は配列として表現される。これをこのまま Faraday (Ruby の HTTP クライアント。上述の gem でも使われてる)に渡して Request Body を生成するとエラーになってしまうのだった。

最近の Faraday には encode option が追加されて FlatParamsEncoder というのを選べるようになってた。こいつを使うと配列を value に持つ Hash をシリアライズしたときに tags=foo&tags=bar みたいな形式にしてくれる。加えて User-Agent も載せるようにもした。こんな感じ。

class Hatena::Bookmark::Restful::V1
  def create_bookmark(bookmark_params)
    res = connection.post("/#{api_version}/my/bookmark") {|req|
      req.params = bookmark_params
    }
    attrs = JSON.parse(res.body)
    bookmark = Bookmark.new_from_response(attrs)
  end

  private

  def connection
    @connection ||= Faraday.new(url: 'http://api.b.hatena.ne.jp/') do |conn|
      conn.request :url_encoded
      conn.options.params_encoder = Faraday::FlatParamsEncoder
      conn.request     :oauth, {
        consumer_key:    @credentials.consumer_key,
        consumer_secret: @credentials.consumer_secret,
        token:           @credentials.access_token,
        token_secret:    @credentials.access_token_secret
      }
      conn.headers['User-Agent'] = 'Hatena::Bookmark::Restful Client'
      conn.adapter Faraday.default_adapter
    end
  end
end

なおはてブの API はリクエストパラメーターが不正なとき 400 Bad Request を返すのではなく 401 Unauthorized を返す。のみならず User-Agent なしのリクエストに対しても 401 を返す。一方で OAuth ヘッダーが不正なときは 400 を返す。原因の切り分けがむずかしくなるので、リクエストパラメータが不正なときは 400 を返して欲しいし認証できないときは 401 を返して欲しい。

追記 2017-05-22 18:34:38

作者の aereal さんに気づいてもらってパッチを取り込んでもらったんだけど、なんかやっぱりタグありの記事をブックマークしようとするとエラーになるっぽい。相変わらず 401 Unauthorized が返ってくる…。

| @技術/プログラミング

Archives ページは部分的に React.js を使ってる。これを全部 React にして SPA 化してみたい。そのためには Server Side Rendering が必要。

Ruby で Server Side Rendering するライブラリでは react-rails が有名だけど、 Rails 以外で Server Side Rendering したい。

有名なやつでは airbnb の hypernova というのがあった。これ自体は Node.js で、 hypernova-ruby というクライアントからサーバーを呼び出して Server Side Rendering するというもの。なのでサーバー側に一個プロセスが増える。開発環境でも Node.js でプロセス起動したりしないといけない。仕事で Microservice には食傷気味になってきてるので趣味では Majestic Monolith™ で行きたい。

名前似てるけど Hyper-Ract というやつもあった。これは過激で JavaScript とか HTML を排除して Ruby で全部書こうぜという Opal が React 対応したもの。良いんだけど F/E の進化早すぎ問題に対応できなくなる気がする。数年後には CoffeeScript みたいになりそうな予感がある。スタンダードでシンプルなものを使いたい。

もう一個、スター全然付いてないしメンテナンスもされてなさそうなんだけど、 V8 で React 読み込んで出力するだけという簡単なのもあった。react-ruby-v8 という直球な名前。こんなので十分かもしれない。

| @技術/プログラミング

Pull Request 、レビューしないといけないものが貯まってしまってつらいと感じることが多かった。そういうつらみを解消するための ruboty プラグイン作った。

ruboty-cron と組み合わせて

@ruboty [GitHub の Issue のラベル名]のPull Request

という感じで job 登録しておくと、毎時決まった時間になったら Bot が Pull Request のレビューを促す。

便利。

使い方

  1. ruboty の Gemfile に gem 'ruboty-check_pr_please', github: 'morygonzalez/ruboty-check_pr_please' と追加する
    • 定期的に動かすためには ruboty-cron もいる
  2. ruboty の .env に GITHUB_ACCESS_TOKENGITHUB_REPOSITORY='owner/repo' を書く
  3. ruboty をデプロイする

開発時に苦労した点

ruboty 、 rubory とタイポしてしまうこと多くてつらかった。