valid,invalid

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

Cybozu Meetup で聞いた各社の技術ブログ運用の話と、Quipper のブログ再開について

Cybozu Meetup で聞いた採用文脈でのブログ運用の話と、Quipper のブログ再開の話です。*1

Quipper のブログ再開

所属する Quipper でも最近プロダクトチームのブログを再開しました。

quipper.hatenablog.com

自分も早速記事を書き、本日公開されました。

quipper.hatenablog.com

目的は中長期的な採用活動の活性化

目的は中長期的な採用活動の活性化です。具体的には、中高生向け教育事業という性質柄「Quipper が何をやっているか」が候補者(エンジニア)にとって分かり辛いという課題の解消と、エンジニアブランディングイメージの構築を目指します。

続けていくための方針

再開するにあたってどのように運用するのが望ましいかを社内で議論し、おおむね以下のような方針を定めました。

  • blog は当番制で書く
  • blog 書くのは必ず業務の範囲として行う
  • blog 書いたことをチームやマネージャがきちんと評価する
  • blog の内容チェックは GitHub の pull request や google documents などで行う
  • 可能な限り定量的に効果測定する
  • 半永久的に続けていく
    • 死んだブログを見ると悲しい
    • 死んだブログを見ると「この会社大丈夫かな?」と思う
  • エンジニア主導で行う、広報や人事主導で行わない

過去に更新が止まってしまった最大の理由は「当時の採用計画を達成したから」でした。もともと採用目的で開始し、長期的に続ける算段も元よりなかったのでそこに一種の潔さはありました。

しかしこのたび採用活動を再開するにあたり、ブログ等を通じてエンジニア界の耳目を再び弊社に集めていくのはなかなか短期決戦とはいかなさそうだという感触があります。それなりの"存在感-プレゼンス-"を保つには、やはり続けていかないといけない。続けるためには"善意-ボランティア-"ベースではなく継続的に運用できる仕組みづくりが重要だと考えました。

そこで比較的ブログの"存在感"があり、さらにはブログ運用が採用にも繋がっているという各社の話を聞いてみると、どうやらこの方針に関してはほとんど一致しているようで追認された心持ちです。

各社の取り組み

以下は Cybozu Meetup で聞いた採用文脈でのブログ運用の話のまとめメモです。登壇者が壇上で語っていた内容なのでオフレコなものは無いと思いますが聞き間違い、誤った内容があれば訂正させていただきます。

Cookpad Developer's Blog

  • エンジニア外村さんが中心になって回している?(運用の中心が誰かはわからず)
  • blog は採用効果あり、と断言。理由は応募のキッカケとして blog を挙げる人の割合の多さ (OSS への言及と並ぶ)
  • blog は AIDCA メンタルモデルの AID あたりに効いてくる (以下の図は Cybozu Meetup // Speaker Deck より引用) image
  • 1人あたり1エントリ/年かく。アウトプット・情報共有の良い機会になる。1年仕事をしていて blog に書くことがない、というのは危機感にも繋がる
  • blog は当番制でないと回らない
    • いっぱい書きたい人・ネタの鮮度を気にする人などが当番制に反対したが、当時のCTOの判断で当番制に押し切る
    • 実際、任意にすると書く人が偏る。記事も書く人の興味ある分野に偏る
    • 当番制にした2014年から記事の数が爆増した。立候補制では絶対届かない数字
    • 書きたい人はいくらでも書けばいい
  • (エンジニアに限定したくない、デザイナーやプロダクトマネージャも参加させたいから「Developer's Blog」にしたと言っていた気がする…?)

Cybozu Inside Out

  • 「コネクト支援部」というエンジニアと人事の混合組織が運用
  • もともと当番制で回していた
  • いっぱい書きたい人・ネタの鮮度を気にする人が当番制に反対し、当番制をやめてしまった
  • 結果、イベントレポートが多めになってしまった
    • 実際イベントをいっぱい開催しているのでそのアピールにはなっているが、技術力あるというブランディングになっていないのが課題

Recruit Technologies メンバーズブログ

  • blog は採用活動としてはうまく活用できていない
  • 立候補制
  • 書く人が少なくて困っている?
  • 広報の人が運用を担当している?
    • 広報の人は技術の記事を書けないので、イベントレポートが多くなりがち
    • 技術記事書いてください!という依頼が古川さんに集中してしまう

Cyber Agent Developer's Blog

  • キラキラしている
  • blog のデザインも実装も社内でやっている?

CA社のブログの話はあまり聞けなかった


*1:書き終えたあとに会社ブログに書く内容かも?と自問したものの、前者に関しては完全に個人的なメモを載せているだけなので個人ブログが良いと判断

Roppongi.jsで『エンジニアも気にしたい色のアクセシビリティ』についてLTをしてきました

第3回 Roppongi.js に参加し、『エンジニアも気にしたい色のアクセシビリティ』というタイトルでLTをしました。

スライドのタイトルを575にしたかったものの「エンジニア アクセシビリティ 気にしよう」のような駄作しか生まれなかったために断念しました。

リンク付きの原稿はこちら https://ohbarye.github.io/slides/2018/roppongi.js-3/

スライド

今回は reveal.js を初めて使ってみたので「ワイは"東京者-オシャレ-"や〜!!」という気持ちで臨んだものの、"同じタイプのスライド使い"がいっぱいいて椅子から転げ落ちそうになりました。

やっぱり"東京-Roppongi-"ってすげぇ…っ…!!

所感

このへんは自分の意識の低さもあるが、これまでで厳密にアクセシビリティにこだわるプロダクトを開発した経験がないのでどうにかしたいと思うところ。

染色体

時間の都合で言及できなかった、男性の色覚障害者の割合が多い理由です。

Roppongi.js

初参加でした。

  • テーマが多岐にわたっていて面白かった
  • 自分のようなサーバサイドエンジニアでも楽しめた
  • 一方、もはや JavaScript というくくりだけでは共通認識を持った集団を形成するのは難しそうだなと感じた
  • 懇親会
    • GraphQL 実戦投入話などをして"波"の高まりを感じた
    • Web を拡張する次の一手としての VR としての面白さについて語れてよかった
    • ピザがおいしかった

また参加したいと思います(月並み)

Rails のフロントエンドのレベル上げ

第15回 Meguro.rb に参加し、『フロントエンドのレベル上げ 〜Rails エンジニアが Webpacker を使う場合〜』というタイトルでLTをしました。

お気付きの通りスライドと本記事のタイトルが違いますが、スライドのタイトルを575にし忘れるという痛恨のミスがあり、せめてこの記事はと思い575にしました。

リンク付きの原稿はこちら slides/2018/meguro.rb-15 at master · ohbarye/slides · GitHub

言い足りないことと反省

スライド中で触れている業務で取り組んだフロントエンド改善の取り組みには半年近く要しており、これを10分にまとめるのはなかなか難しいと感じつつ資料を作成していた。

あまり触れなかったけど話そうと思えば話せるトピックはざっと考えただけでこれだけ↓ある。包括的に語るには30分枠かそれ以上になってしまう…ので機会があれば長枠でもう一度話してみたい。

  • プロダクトの特性
  • 負債返却に取り組む時間をどのように捻出するか (技術的負債を抱えながら突っ走る -日々15分の改善活動- - valid,invalid)
  • 新しい技術を導入する際にチームでどのように合意を得ていくか
  • 巨大な変更を入れるときのレビューのやり方 (レビュー会のすすめ - valid,invalid)
  • Webpacker を使う際の具体的な tips や注意点、またはステップバイステップで使う方法の詳細
  • webpack-dev-server もシュッと立ち上がる開発環境
  • Partial single page application パターンで実装するときに気をつけること
    • なんでも盛り込むと bundle size のコスパが悪くなる
    • webpack-bundle-analyzer でのチューニングした話
    • preact などの軽量ライブラリに切り替えるか検証したがやめた話
    • polyfill
  • form 用ライブラリ formikyup について
    • redux-form との比較
  • フロントエンド周りの OSS 探索を楽しんでいる話
  • 得た知識で node.js, yarn などにコントリビュートするまでの話

各々、プレゼンテーションの中で少しずつ触れたものの、全体としてはまとまりを欠いてしまったかもしれない。実際に時間オーバーしてしまったのも反省。10分枠ではせめて1つか2つぐらいのトピックにフォーカスしないといけない。


Meguro.rb

初参加でした。

  • アットホーム。リブセンス社の会場がちょうどよい感じだった
  • 大学生が来ていて感心した(おっさんくさくなってしまった)
  • 料理がおいしかった

また参加したいと思います(月並み)

Generative Art を始めて7日間、作品を毎日公開した記録

pandora_black

ゴールデンウィーク(以下、GW)の途中で以下の記事を読んで Generative Art (ジェネレーティブアート - Wikipedia)*1 なるものを知り、試しに触ってみたら面白かった。

dev.to にも My first step in learning Generative Art という記事を書いてみたら反応がそこそこあって嬉しかったので GW が終わるまでの7日間で毎日絵を書いて投稿してみることにした。

開発環境

Processing という言語と開発環境があるのだが慣れている JavaScript で書きたかったので p5.js を利用した。

p5.js Web Editor または OpenProcessing - Algorithmic Designs Created with Processing の web 上のインタラクティブエディタを使って描いた。Auto-refresh を有効にすると見た目の確認がすぐできて便利…だがコードでミスって無限ループや OOM に出くわすとブラウザが固まってしまい、作業内容が失われるという"痛み"を何度か味わった。

感想

HTML Canvas を触ったことあるので最初の描き始めるハードルはそれほど高くなく、line で線が引ける、rect で四角形が描ける、なるほど完全に理解した〜〜〜と思ったものの作品例を見た瞬間に「は???」ってなった。

とはいえとにかく手を動かさないと何も身につかないと思ってとにかく描いてみたらこれが楽しかった。

業務で書くコードと異なり、 Generative Art には正解もなければ自分が良いと認めるまで終わりもない。出来上がった幾つかのパターンを見比べてどちらがより良いかでずっと悩んだりする。無限に時間が吸われていきながらコーディングの楽しみを再び思い出した気がした。

流石に毎日の投稿を続けるのは厳しいが Generative Art は今後も続けていきたい。

作ったもの

全て ohbarye - OpenProcessing で公開している。

day 1

何も考えずに reference を読みながら出てきたものをコピペしていた。書けた時は「すげー!!!楽しー!!!」という感じでテンションがアップライジングしていたのだが、今になって見返すとなんだコレ…という気持ち。

day 2

現実に存在する何らかのモチーフを再現できるようになりたい、と思って作った。あまりこだわらなかった色合いがやはり良くない。

day 3

day 2 とは対称的に抽象的なイメージを絵に落とし込みたいと考えた。テーマは「糸」なので糸車的でありながらよくわからない現実には存在しない物体を描いてみた。清涼感ある色合いが気に入っている。

day 4

day 2 と同様に現実に存在する何かをもっと綺麗に描いてみたかった。curveVertex を使った曲線がちょうど花びらのようになったのと、noStroke にしたときの儚い感じは良く出来たと思う。

day 5

これは day 1 の次に気に入らないやつ…。「知らない言語を聞いたときの気持ち」を表現するという斜め上のところに飛び込んだが、何が描きたいか途中でよくわからなくなってしまった。

day 6

この日は明確に 2D noise を使った波で絵を描こう!と決めていた。ただの波だとチュートリアルのコピペで終わってしまうので大地を伝うような波、大地の断面図であるかのような波に見えるような動きを付けてみた。

このあたりからコードが複雑になってきており、あとで読み返すのが辛くなりそうだ。

day 7

実は http://evanyou.me/ の稲妻みたいなデザインにインスパイアされ、コードもかなり参考にした。

パンドラの箱」というモチーフが若干中二臭いが、躍動感・残像の雰囲気・ビビッドなカラーリングなどを総合的に見て、今のところ一番気に入っているかもしれない。

余談だが、パンドラの箱はもともとは水瓶だったのが箱として誤って伝わったらしいと描いている途中に調べて知った。

*1:カタカナだとジェネラティブ・ジェネレーティブ・ジェネレイティブなどで表記揺れするので英語に統一したい。Creative Coding

GitHub GraphQL API v4 を JavaScript から利用する

TL;DR

  • 開発している Slack bot で発生する N+1 問題を解消するために GitHub GraphQL API v4 を利用した
  • クライアントサイド(今回は JavaScript)側から使ってみただけだが、かなり開発体験が良かった

背景: review-waiting-list-bot について

review-waiting-list-bot という Slack bot を開発し、今もメンテナンスしている。

ざっくり言うと以下のように動いていた

  1. GitHub REST API v3 の Search API を叩く
  2. ユーザーの入力した条件に応じてフィルタリングする
  3. 結果を整形する
  4. Slack に通知する

詳細は以下の記事を参照

ohbarye.hatenablog.jp

今回はこのプロセスのうちの 1 を、 GitHub GraphQL API v4 を使ってややスマートにできたという話をする。

requested reviewer でフィルタしたい

GitHub issue に requested reviewer でフィルタしたいという要望*1が来た。requested reviewer は pull request page の以下の UI から設定できる情報のことだ。

f:id:ohbarye:20180504120941p:plain

フィルタの追加は過去にもやった*2ので最初は簡単だと思ったのだが、Search API の返すフィールドに requested reviewer の情報が含まれておらずどうしたものかと少し悩んだ。この情報を取得するための Review Requests API もあるのだがこのエンドポイントを pull request ごとに呼び出すと bot の処理がたいへん重くなってしまう(クライアントサイドの N+1 問題)*3

これが GraphQL だと1リクエストでバシッと必要な情報だけ取得できたりするのだろうかと思い至り、まずは https://developer.github.com/v4/explorer/:title) で試しにクエリを書き始めてみた。するとあっさり必要な情報だけを expose するクエリが書けてしまった。

f:id:ohbarye:20180504121849p:plain

赤い四角で囲んだ箇所が欲しかった情報だ。

JavaScript から GraphQL API を利用する

クエリが書けた、つまりやりたいことが GraphQL を使って実装できるとわかった。あとはこのクエリを JavaScript、正確に言うと Node.js のコードとして埋め込むだけだ。

GraphQL API の呼び出し方は 4 simple ways to call a GraphQL API – Apollo GraphQL を参考にした。HTTP クライアントは promisify したかった & 使ったことあるというだけで axios にしたので実質何でも良い。

骨子は以下のようになった。

const axios = require("axios")

const client = axios.create({
  baseURL: 'https://api.github.com/',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': `Bearer ${process.env.GITHUB_AUTH_TOKEN}`,
  },
})

const query = `
  query {
    search(first:100, query:"type:pr author:ohbarye state:open", type: ISSUE) {
      nodes {
        ... on PullRequest {
          title,
          url,
          author {
            login,
          },
          labels(first:100) {
            nodes {
              name,
            },
          },
          reviewRequests(first:100) {
            nodes {
              requestedReviewer {
                ... on User {
                  login
                }
                ... on Team {
                  name
                }
              }
            }
          }
        }
      }
    }
  }`

const response = await this.client.post('graphql', { query })
console.log(response.data) // This results below

/*
{
  "data": {
    "search": {
      "nodes": [
        {
          "title": "Enable to fetch pull requests by specifying assignee",
          "url": "https://github.com/ohbarye/review-waiting-list-bot/pull/26",
          "author": {
            "login": "ohbarye"
          },
          "labels": {
            "nodes": [
              {
                "name": "enhancement"
              }
            ]
          }
        }
      ]
    }
  }
}
*/

response の中身も graphiql 上で確認できているので統合もスムーズにできた。

(実際には GraphQL の導入requested reviewer によるフィルタ機能の追加は別PRにした)

残課題

  • ページング
    • pageInfo.hasNextPagepageInfo.(start|end)Cursor を使って実装できることはわかるが、配列要素がネストしている場合が謎
    • クライアント側の実装がハチャメチャに複雑にならないか?
  • エラー処理
  • フィールドを区切るカンマは不要?
  • クエリ内のダブルクォーテーションの中にダブルクォーテーションをさらに埋め込むことはできない?

感想

  • 今回の実装で受けられた恩恵は一般的に語られているものの再確認であり、"真髄"に迫るような感じではなかった
    • N+1 を解消できた
    • 必要なフィールドのみにアクセスすることでレスポンスの content size を減らせた
  • とはいえ API が返却するリソースのモデル定義を容易に、かつインタラクティブに確認できるのはクライアントを実装するうえでかなり良い開発体験だった
  • 雰囲気でやっているのでベストプラクティス的なものを知りたい
  • サーバサイドの実装はまったくわからない

*1:https://github.com/ohbarye/review-waiting-list-bot/issues/32

*2:正確にはやってもらったtomoima525/support label by tomoima525 · Pull Request #23 · ohbarye/review-waiting-list-bot · GitHub

*3:worker 処理なのでタイムアウトなどの心配はないのだが Slack で bot を呼び出してから応答が遅くなるのは決して良くない

babel-eslint を使って非標準仕様でも lint できるようにする

Parsing error on ESLint

review-waiting-list-bot の実装中に以下のようなオブジェクトの分割代入するコードを書いたら eslint で parse error が起きるようになってしまった。

const { authors, ...conditions } = { authors: [], owner: '', repo: '' }
$ eslint .

/Users/ohbarye/.ghq/github.com/ohbarye/review-waiting-list-bot/src/App.js
  19:21  error  Parsing error: Unexpected token ..

✖ 1 problem (1 error, 0 warnings)

error Command failed with exit code 1.

Object Rest/Spread Properties はまだ stage 3 (2018-04-30 時点)。

また、標準化プロセスの中途にある仕様はこうなるのが正しいとのこと。

github.com

babel-eslint

stage n の仕様を利用したい場合は babel-eslint を使う模様。

devDependency として追加して

yarn add -D babel-eslint

.eslintrc.json に以下の行を追加する。

# .eslintrc.json
{
  "parser": "babel-eslint",
  ...
}

これで eslint コマンドが通るようになった。

環境

  • yarn v1.6.0
  • Node v8.3.0
  • eslint v4.4.1
  • babel-eslint v8.2.3

技術的負債を抱えながら突っ走る -日々15分の改善活動-

開発しているシステムが大規模かつ老朽化しかけていることもあり、最近は負債の返却を念頭に置いて普段の開発をしている。

前提として、個人的には負債を返す頻度は多いほど良い*1と考えている。

この立場に立つときに生まれる問い、「では、日々の開発のスピードを落とさずに頻度を上げるためにどうすれば良いか?」の1つの答えとして「まずは15分向き合ってみる」というのを実践している*2。その実践に関するメモが本記事である。

TL;DR

  • たった15分でも日々負債に向き合ってみると良い
    • 全体像も見えない、どれだけ時間をとられるかわからないものならなお良い
    • ここでいう負債には技術的負債だけでなく使われていないが残存している機能など(便宜的にプロダクト負債と呼んでみる)も含む
  • 全体像が不明瞭で手も付けづらい何かが頭の片隅にあること自体が精神衛生上よくない
  • 一方、わずかづつでも改善に向かっているという実感を個人ないしチームで得られるというのは精神衛生上とても良い

「技術的負債」は少しでも解決に近づける

実感として15分で解消できるものは意外と多い

技術的負債への取り組みは完全解決に至らなくても少しでも解決に近づけるだけで価値がある

  • 複雑な問題を複数の小さい問題に分解する
  • なぜ難しいかを言語化する
  • 解決への道筋を立てる

手に入った情報に対して他の人が議論を重ねたり代案を出したりしてさらに前進することもしばしばある。

「プロダクト負債」はステークホルダーに先手を打つ

技術的負債は基本的には非開発者からは見えないのに対してプロダクト負債は"見える"もの。つまりステークホルダーへの確認・コミュニケーションが高確率で発生する。そのため15分で何もかも片付くようなケースはあまりない。許可より謝罪*3という美しい言葉で攻めていきたいが信頼貯金を失うのは長期的に見て得策ではない

なのでイシュートラッカーやチャットで非同期にディスカッションするなど、手を動かす前に15分で合意を得るための先回りをしておくと後で物事がスムーズに進む。

多少強引なやり方としては「この機能の使用率n%なので消します。反対意見があれば何日までに返事ください。反対なければ進めます」というのもある。これはチームの文化・意思決定プロセスによっては良くないかもしれない。

なぜ15分?

正直15分でも1ポモドーロ25分でも何分でも良い。大事なのは「1日の間に捻出できる」「息抜きとして使える」「何も成果が出なくても許せる」程度の時間ということ。

Fail fast, fail cheap, and fail smart損失の限定らへんの考え方から影響を受けている。

これが1時間2時間ともなると同日のメインタスクの計画・見積もりに影響が出てくる。影響が出てくると周囲に「今日ちょっとこの負債見ますね、なぜなら…」みたいに都度ことわっていく必要が出てくる。マイクロマネジメントされているわけではないので裁量の範囲で片付けてもよいが、チームメンバーが何に時間を使っているかわからないというのは嫌なものだ(そのメンバーのタスクが遅れるならなおさら)。

どれから手をつければいいか?

コスパが良い・NPVの高い投資をするのが理想的だが15分の取り組みであればあまり意識しなくても良いと思う。「負債返却プロジェクト」みたいな大掛かりなものであれば慎重に吟味する必要はある。

負債を辛いと感じたら普段からメモしておく。何度もメモしたくなるタイミングがあるならその問題に取り組むことはきっと費用対効果が高い。また、普段から課題発見を意識しておくと質の良い課題を発見するスキルを向上するトレーニングになると思う。


技術的負債との戦い方は幾度となくどこでも語られたことと思うが、結局のところ少なからず個人やチーム、ないしは会社の状況なりのやり方を模索することになる。自分も今まさに模索フェーズなのでその現状を経験知としてダンプすることに価値があると考える。

また、今のチームではこの15分とは別に "Quality Budget" という、メインタスクとは別の改善活動に充てる予算(=時間)を設けている。2週間に一度、チームメンバー全員が丸1日を改善に使って良いというこの試みはこの4月にスタートしたばかりなので、いずれ振り返りを書く。

*1:技術的負債とどうやって戦うか - Qiita

*2:クックパッド社の朝Lint活動などで知られるように、考え方としては目新しいものではない

*3:許可より謝罪 : けんすう日記