HBFav が iOS 8 でクラッシュする問題について

HBFav をお使いいただきありがとうございます。

現在のバージョン 2.6.1 は、iOS 7 から iOS 8 にアップグレードするとアプリ起動後、記事一覧を読み込んだところでクラッシュしてしまいます。

クラッシュの原因を修正したバージョン 2.7.1 を先週には App Store にアップロードしたのですが、まだ審査待ちでリリースできていません。申し訳ございません。今しばらくお待ち下さい。

質問: Go の変数初期化に伴う条件分岐をもっと良い感じに書きたい

Go にはスクリプト言語でいうところの variable = a || b のような構文や三項演算子がないようなので、

var accessKeyId, secretAccessKey string
if config["aws_access_key_id"] == "" {
	accessKeyId = os.Getenv("AWS_ACCESS_KEY_ID")
	secretAccessKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
} else {
	accessKeyId = config["aws_access_key_id"]
	secretAccessKey = config["aws_secret_access_key"]
}

とか

var url string
var err error

if len(os.Args) == 1 {
	url, err = gozo.SendCapture()
} else {
	url, err = gozo.SendFile(os.Args[1])
}

こんな感じのコードを毎回書くことになるんだけど、本当は

accessKeyId = config["aws_access_key_id"] || os.Getenv("AWS_ACCESS_KEY_ID")
secretAccessKey = config["aws_secret_access_key"] || os.Getenv("AWS_SECRET_ACCESS_KEY")

とか

url, err := len(os.Args) == 1 ? gozo.SendCapture() : gozo.SendFile(os.Args[1])

みたいに書けたらいいと思ってますができません。それは諦めるとしてもちっとまともに書きたいんですがみなさんどうしてるんでしょうか。

追記

Reverse Proxy がなぜ必要か

フロントエンジニアに知ってもらいたいリバースプロキシの重要性 | RickyNews この記事が目に入って読んでみた。なるほど、昨今は Reverse Proxy は便利な L7 ルーター的なものとして認識されているのだな、と思った。URL の Rewrite や、VirtualHost 云々。確かに Reverse Proxy の便利な側面ではある一方、それらは Nginx などの Reverse Proxy でなければ実装が不可能かと言えばそんなことはないものでもある。

自分は Reverse Proxy はもうすこしサーバー/インフラ的な側面でその役割を捉えている。今更何をというものでもあるが、昼休みがてら時間があるので簡単に書いてみよう。

Reverse Proxy はWebシステム全体のリソース最適化のためのパーツ

Reverse Proxy のインフラ的な視点での役割は「Webシステム全体の系におけるリソース全体最適のための部品」である。なんのこっちゃ・・・ごめん、石投げないで。

改めて Reverse Proxy は

としたときに

  • フロントエンドで裁けるものはフロントエンドで
  • バックエンドでなければ処理できないものだけバックエンドで処理する

ようにし「全体のリソース効率を上げましょう」というためのものである。

マルチプロセスモデルと並行処理性能

最近はいろいろな実装があるので一概には言えないのだが、Webアプリケーションによるバックエンドのアプリケーションサーバーでは、特にスクリプト言語においては、それはマルチプロセスモデルを採用していることがほとんどだ。マルチプロセスモデルでは、1リクエストを1プロセスが担当することになる。従って、1システムで20プロセスが起動していたとすると同時に処理できる並行処理数は最大で20リクエストということになる。

ご存知のようにアプリケーションサーバーはメモリを大量に消費する。メモリ使用量という文脈で「重い」と言える。そのため、32GB とかどんなに潤沢にメモリが確保できる状況でも、せいぜい最大プロセス数は、すなわち並行処理性能は 50 とか 100 とかそのぐらいである。

Web システムが応答しなければいけないのは、例えば /login に来た1リクエストに対してその画面が含む画像、JavaScriptCSS その他大量のアセットを含む。Reverse Proxy を導入していないシステムではこれらのすべてにアプリケーションサーバーが応答しなければならない。ここが問題。本来アプリケーションサーバーは、動的なリクエストを処理するために用意されているものであるにも関わらず、動的でないコンテンツにまで応答しなければならない・・・というので、先にみたように貴重なアプリケーションサーバープロセスが、どうでもいい静的ファイルのリクエストなどにも消費されてしまう、のである。

Reverse Proxy で得意なものは得意な人が応答するようにする

そこで Reverse Proxy を入れて、(ネットワーク的に) アプリケーションサーバーの手前に配置する。そして静的ファイルなど、アプリケーションサーバーを介さずに応答できるものは Reverse Proxy が直接クライアントに応答し、アプリケーションサーバーでなければ応答できないリクエストのみアプリケーションサーバーに転送する。

Reverse Proxy は、(アプリケーションサーバーがマルチプロセスモデルであるのと対照的に) 昨今の場合 Nginx のようにシングルプロセス・イベントドリブンなアーキテクチャの実装のものを用いる。このアーキテクチャは、どんなに大量のリクエストが来てもプロセス数は増やさずにコンテキストスイッチングのみ (CPU 的な意味のコンテキストスイッチングではなく、イベントの意味での。具体的には select や epoll に類するシステムコール) で並行処理性能を稼ぐところが利点。そのためメモリ使用量の文脈では「軽い」。

この「重い」アプリケーションサーバーと「軽い」Reverse Proxy を組み合わせてそれぞれ自分が得意なものだけ担当することで、システム全体の系でみたときにリソース効率を全体最適させましょう・・・というのがインフラ視点で Reverse Proxy を導入したい一番の理由である。

Reverse Proxy はネットワーク的に遅いクライアントや、KeepAlive リクエスト、あるいは大きなファイルをアップロードしてくるクライアントなど「あまり仕事はしないけどネットワーク接続の維持は要求される」されるような側面でも役に立つ。それらは Reverse Proxy 側で処理しておき、アプリケーションサーバーには本当に必要なときだけにしかリクエストを転送しない・・・ たとえば遅いクライアントのHTTPリクエストがすべて着信してから転送、KeepAlive はフロントだけ有効にしておきバックエンドは応答が終わったらそく切断、アップロードファイルは終わるまでフロント側でバッファリング・・・などである。

この役割分担が、更に得意なものは得意なところで、というリソース全体最適化に寄与する。

四方山

この辺が Reverse Proxy に求められる役割の主軸で、L7 的な便利機能・・・ URL の Rewrite とかフロントエンド側でのアクセス制御というのはあくまで副次的な要素に過ぎない・・・というのがインフラ視点での認識ではある。まあ、フロントエンドエンジニアリングからしたらその視点が逆転する、というのはわからなくもない。

ちなみに最近は Amazon の CloudFront など CDN を比較的カジュアルに使えるようになったので、静的ファイルの配信に関しては CDN だけで賄ってしまうという力業を使う例も増えてる気もする。個人的には、その副次的な用途の魅力も大きいので、CDN に使うにしても Rerverse Proxy あったほうがいいよとは思うけど。

・・・書いてるうちにだんだんドヤ顔になってきてしまった。すみません。自分の知識がある程度正しいという思い込みを前提に、きちんとこの辺の背景事情を続く世代に継承していけたらとも思うところです。

ちなみに、この辺は『サーバー/インフラを支える技術』という(とっても)素晴らしい本に詳しく書かれているのでこちらを読むと良いと思う。

インフラの継続的デリバリー

事前に断っておくがここでいう「インフラ」はレイヤ的には OS より上の話。

少し前に GitHub 時代のデプロイ戦略 - naoyaのはてなダイアリー で、GitHub を介したデプロイを実践しているということを紹介した。普段の開発を Pull Request ベースでやっているので、デプロイもまた Pull Request を契機に実行させると色々捗る、という話。

このプラクティスの対象領域をインフラにまで拡大してみました、というのが今回の話。

DNS レコードを Pull Request を merge した契機に自動で更新

AWS を利用している場合、ドメインの管理も Amazon Route 53 を使うといろいろと都合がいい。

Route 53 での DNS レコードの更新はこれまでブラウザから操作していた。これだと誰がいつ作業したかわからないし履歴もトラックしづらい。また変更確定前に事前レビューするのにも向いてない。

そこで roadworker を使う。roadworker は Route 53 の DNS レコード設定を rubyDSL で書けるようにするツール。裏では Route 53 と API で通信する。

roadworker を使うと、以下のようにレコードを Ruby のファイルで書ける。(GitHub から引用)

hosted_zone "winebarrel.jp." do
  rrset "winebarrel.jp.", "A" do
    ttl 300
    resource_records(
      "127.0.0.1",
      "127.0.0.2"
    )
  end

  rrset "winebarrel.jp.", "MX" do
    ttl 300
    resource_records(
      "10 mx.winebarrel.jp",
      "10 mx2.winebarrel.jp"
    )
  end
end

こうして「DNSレコードの現在の状態」がコードになったので、あとはいつも通り Git と GitHub のフローに乗せることができる。ファイルの更新には Pull Request を使い、コードレビューする。万歳。

更に、Route 53 への設定の適用すなわち roadworker の実行は CircleCI に任せる。Pull Request が master に merge されたら自動で roadwork コマンドを実行するようにする。テストフェーズで dry run するようにすれば、万が一 Ruby コードが壊れていてもそれを検知できる。

dependencies:
  pre:
    - bundle install:
        timeout: 600

test:
  post:
    - bundle exec roadwork --dry-run --apply

deployment:
  master:
    branch: master
    commands:
      - bundle exec roadwork --apply

実行を CircleCI に任せれば (Git にファイルの更新履歴が残るだけでなく) 実行履歴のログも残せるし、ステータスを Slack に通知するのも簡単。

DNS レコードを書き換える、というと「えーと、どうやるんだっけ? インフラ担当お願い」ということになりがちだが、これで、前例に倣って Pull Request を投げて merge するだけですべてが実行される、ということになった。

以上は最近 KAIZEN platform Inc. に入社した glidenote さんのお仕事である。グッジョブ

Chef の適用も CircleCI 経由で、そして ChatOps

アプリケーションのデプロイを Pull Request をマージするタイミングで実行するという考え方を DNS 変更にも適用したのが先の例。同様に「もう Chef でのインフラの変更も全部同じようにやっちゃえよ」ということで mdoi がやったった。

(ここでは簡易的に master に merge したらと書いているけど、実際にはデプロイ用のブランチが別にあったりとちょっと設計は異なる)

Chef のクックブックのサーバーへの適用には knife-solo を使っているが、それを CircleCI に実行させる。CircleCI には ssh秘密鍵をセキュアに渡せる仕組みがあるので、認証周りの心配も特に必要ない。CircleCI に実行を任せることで、毎回の実行ログをそのまま残せるのは先の DNS の例に同じくで、とても良い。

インフラに実際にコードを適用するのは、クックブック変更 Pull Request の merge 契機だとさすがにアグレッシブすぎるので、冒頭でも紹介した以前の記事に同じく、デプロイ用の Pull Request を使う方法を採用している。インフラに最新のクックブックを適用したいな、と思ったら deployment/qa-proxy など、デプロイ用のブランチに Pull Request を作って merge する。すると CircleCI が動き出して対象システムに Chef 適用を始める。

ここまで来たら、例によって ChatOps。

インフラへの変更適用もチャットからやってしまえばよい。これで、複数の担当者が同時にインフラに適用する、なんてことも自然と防ぐことができる。

インフラを自動で更新なんていうとえらくリスクの高いことをやっているように聞こえるが、実際には手元で knife solo していたのを CircleCI に実行させているだけであり、このプロセスに移行することによるリスクの増化はない。

「Merge pull request」ボタンに作用を集約させる

こうして、システム構成の変更などの作用を PullRequest + CircleCI によるオペレーションに集約させる、というのはなかなか良いプラクティスである。

単に Pull Request を送って変更しましょうね、だけでも十分に恩恵はあるのだけど、実際に何かしらの変更実行のトリガが「Merge pull Request ボタンを押す」というボタンに紐づけられると意識しなくても自然と Pull Request を送っておこうという考え方になる。DNS に変更を加えたい → Pull Request をマージしたら (※ 実際には master に変更があったら) 変更処理が自動で行われる → じゃ、プルリク作るか、という具合。

こうして結果的に、何をやるにも緑のボタンを押すだけ、すなわちワンクリップデプロイの仕組みが構築できた。Infrastructure as Code を推し進めて、インフラも CI して、ワンクリックデプロイ ─ 継続的デリバリーの実践である。

BigQuery と Google の Big Data Stack 2.0

先日、有志で集まって「BigQuery Analytics」という書籍の読書会をやった。その名の通り Google BigQuery について書かれた洋書。

BigQuery を最近仕事で使い始めたのだが、BigQuery が開発された背景とかアーキテクチャーとかあまり調べもせずに使い始めたので今更ながらその辺のインプットを増やして以降と思った次第。

それで、読書会の第1回目は書籍の中でも Overview に相当するところを中心に読み合わせていった。それだけでもなかなかに面白かったので少しブログにでも書いてみようかなと思う。

BigQuery の話そのものも面白いが、個人的には Google のインフラが書籍『Google を支える技術』で解説されたものが "Big Data Stack 1.0" だとして、BigQuery は Big Data Stack 2.0 の上に構築されており、更に Google 内部ではとっくに Big Data Stack 3.0 に移行してる (しつつある?) みたいな話に強く興味を持った。(まあ、3.0 は論文にも何にも発表されてないので、そういうニュアンスのみしか嗅ぎ取れないのではあるが)

Google BigQuery

Google BigQuery は、一言でいうと「超でかいデータをSQLで数秒で解析できるクラウドサービス」。

例えば fluentd なんかで毎日ログを送りつけておいて、溜まった 数百GB とか数TB、あるいは数PB とかになったデータに SQL を投げるとちゃんと結果が返ってくる、そういうもの。いわゆるビッグデータ基盤である。裏側では当然分散処理が行われていて、Google の持つ大量のコンピュータとディスク、それから高速なネットワークによってそれが処理されている。

もっと知りたいという方は Googleの虎の子「BigQuery」をFluentdユーザーが使わない理由がなくなった理由 #gcpja - Qiita あたりを参照すべし。

なぜ大きなデータを秒単位で処理できるかというと、それがまさに BigQuery Analytics の本題なのだがざっくりは

  • SQL は高度に並列化できる言語 (基本、シーケンシャルに処理するしね)
  • RDBMS のようにインデックスを作るわけではなく、基本フルスキャンする
  • そのフルスキャンに伴う I/O を分散処理するために大量の HDD を用意して、それを大量のサーバーに接続してクラスタリング (もちろん、スケールアウトの発想で)
  • データをそのクラスタ内でカラムナー形式で保持しつつ分散させて保存しておき、SQL が来たらそれを並列処理化して I/O を散らす

みたいな感じである。より詳しくは・・・とそこが書籍の本題でありその理解は今後の読書会を通じて行われる予定、といって誤魔化す。

こういうアーキテクチャになってるので、BigQuery に対するクエリのレスポンス速度はデータサイズに比例しない。例えば 100GB のデータに対して 3sec かかったクエリが、対象が 1TB になっても 5sec で収まるとか、そういう特性を持っている。

Google BigQuery の製品ポジション / MPP の盛り上がり

この、SQL を並列分散処理してビッグデータを数秒で解析しましょう、という製品は何も BigQuery だけではない。

OSS の実装であれば Facebook が開発して OSS になった Presto、それから Cloudera Impala などがある。この辺は、Hadoop クラスタにアドオンする形で利用すると、Hadoop クラスタに溜め込んだデータを SQL 並列処理できるようになってる。クラウドサービスでいえば (自分は詳しくないし、結構特性には違うらしいが) Amazon Redshift なども同様のカテゴリのサービスのようだ。それから、以前にこのブログでも紹介した TreasureData はもともと Hive + Hadoop を基礎にしたサービスだったがその後 Presto をアドオンすることで同カテゴリのサービスにバージョンアップしている。

この辺の話は Hadoop Conference Japan 2014 での tagomoris さんの発表スライド Batch processing and Stream processing by SQL が詳しい。

資料の内容を軽くサマリする。

SQL ベースのビッグデータ解析基盤は大きく分類すると

  • Large Batch
  • Short Batch
  • Stream Processing

の3に分類される。それぞれ

  • Large Batch : 安定して巨大なデータをバッチ処理できるが、実行時オーバーヘッド大きい (そのためちょいちょいクエリを変えては投げる目的 ・・・ アドホッック クエリには向いてない)
  • Short Batch : Large Batch の安定性と規模性を多少犠牲にしつつ、実行時オーバーヘッドが数秒 (つまりアドホック クエリに向いている)
  • Stream Processing : ストリームに流れるデータをリアルタイム処理。バッチではない

というもの。対応する代表的な実装は

  • Large Batch ・・・ Hive + Hadoop
  • Short Batch ・・・ Presto / Impala etc.
  • Stream Processing ・・・ Twitter Storm / Norikra

などとなってる。この Short Batch のユースケースに含まれる実装は昨今 MPP (Massively Parallel Processing) 系クエリエンジンと呼ばれていて、ビッグデータ界隈では今もっともホットなトピック・・・であると、Hadoop Conference に出てみて自分はそう感じた。

そして、Google の BigQuery は元々 Google 内部で開発された Dremel というクエリエンジンが基になっている。その Dremel がまさにこの MPP 系クエリエンジンに相当する類で、BigQuery はそれにストレージを加えて公開サービスにしたものだと現時点では理解している。(BigQuery は背後にそびえるクラスタ群が超大規模なので、Short Batch に分類されるとはいえ Large Batch も包含するようなサービスではある。)

OSS 系の流れからいくと、Hadooop + Hive で SQLビッグデータを解析するというソリューションが盛り上がったが、MapReduce はタスク起動時のオーバーヘッドが大きくアドホッククエリの分析には向いてない、そこをカバーするために Presto や Impala が出てきてみたいな流れだと思う。

Big Data Stack 2.0

それで、冒頭の Big Data Stack 2.0 である。BigQuery は Google の Big Data Stack 2.0 の上に構築されている、らしい。書籍によれば。

そもそも Big Data Stack 1.0 とは、GFS, MapReduce, BigTable などの「Google を支える技術」のことである。MapReduce などが論文で発表されたのが 2004 年とかだった。あれから 10 年経った結果、Google 内部は書籍を読む限りは Big Data Stack 2.0 にまで進化している 。(そして現在進行系では 3.0 に至っているようなこともチラホラ見える。)

その Big Data Stack 2.0 の主要コンポーネントは以下である。説明文は読書会で hakobera さんがサマリしてくれたテキストから引用する。

  • Colossus
  • Megastore
    • Paxos アルゴリズムにより、複数データセンターでの一貫性のある Read/Write を実現した NoSQL DB。Bigtable 上に構築されている。
  • Spanner
    • Megastore + データに地域制約(どのデータセンターに所属するか)を付与することができる。
  • FlumeJava
  • Dremel
    • 分散 SQL クエリエンジン。BigQuery の核となるアーキテクチャ。ストレージに依存しない。

これらの実装は概ね Big Data Stack 1.0 の上に構築されているらしい。そしてこれも hakobera さんテキストからの引用なのだが

  • Big Data Stack 1.0 は、Datacenter を1つのサーバとして扱う技術群
  • Big Data Stack 2.0 は、複数 Datacenter を1つのサーバとして扱う技術群

という風に (乱暴には) まとめられる。こうして世界に分散しているデータセンターを、プログラマからみた場合は 1つのサーバーとして扱えるような形で抽象化したのが Google の Big Data Stack 2.0 だそうだ。

ご存知のように Big Data Stack 1.0 をリファレンスにでてきた OSSHadoopHDFS、HBase 等々だったように、この Big Data Stack 2.0 を参考にしたと思われる OSS 実装も当然出てきていて、それらが Apache Crunch や Presto、Impala ・・・というのが昨今の状況。Google が論文などでそのあらましを発表するころには、Google 内部は次の世代の実装に移行しているというのが過去のパターンなので、そこから Google 内部はもはや Big Data Stack 3.0 なのでは? と推測される ─ といった具合である。

自分はこの分野を見てまわるのはそれこそ Google を支える技術から初期の Hadoop ぐらい、Big Data Stack 1.0 の頃で止まっていたので、それからしばらく時間が経ってこんな状況になっていたとは、改めて Google はすごい企業だという感想を抱くにいたったのは当然のこと、とても面白く読めた。ずっとこの分野を追っていた人にとっては何を今更という話なのかもしれないが、面白さあまってブログにまとめるイマココである。

ま、人の会社の話なんだけどね。Google の威を借る naoya。

8/30 の YAPC::Asia では、BigQuery Analytics をもう少し読み進めた後のサマリと、実際に BigQuery をプロダクションで利用してみてのユースケースや感想などを含めて発表できたらと思っている。

急ぎで書いたので誤字脱字や乱暴な解説がいつも以上に多いと思うが、ご勘弁を。

余談

ちなみにこの辺をみて『Google を支える技術II』の出版が待たれる! と声を大にして言おうとおもったら『サーバー/インフラを支える技術』もなんとかしろ、という神の声が聞こえてきた。編集さん、アジェンダなかなか書かなくてごめんなさい・・・。

追記

BigQuery について、#gcpja で話しました。スライドを以下に公開しています。

Deploy to Heroku / Webアプリケーションのポータビリティ再び

Heroku の新機能で Heroku Button が出た。

見るよりも、触る方が早い。以下のボタンを押すと md2inao をあなたの Heroku アカウントにデプロイして、動かすことができる。

Deploy

ボタンを押すと以下のような画面が出て、Deploy to Free を押すと直ちにデプロイが始まる。

GitHub からソースコードが Heroku にデプロイされて、Web アプリケーションが動く。

ご満悦。

このボタンを README.md に置いておけば、Webアプリケーションを自分で動かしたいなと思ったユーザーが、自分自身の環境で好きな時にそれをデプロイして使うことができる。

すなわち、Heroku Button で、URI を介した Web アプリケーションの交換が可能になった。

Heroku Button

Heroku Button を有効にするための前提は割とシンプルで

  • GitHub にソースを置く
  • Heroku にデプロイできる形式で構成しておく ( Ruby なら Gemfile とか Rack とか Procfile とかそういう話 )
  • app.json を書く
  • デプロイボタンを設置

というもの。app.json

{
  "name": "md2inao",
  "env": {
    "BUILDPACK_URL": "https://github.com/naoya/heroku-buildpack-perl.git#cpanm-with-psgi"
  }
}

こういう JSON ファイル。app.json Schema を見るといろいろパラメータを指定できるけれども、シンプルなアプリならほとんど記述は要らない。md2inao は Perl 製で、buildpack が必要なのでそれだけ環境変数で指定した。

Deploy to Heroku ボタンのリンク先は https://heroku.com/deploy だが、このエンドポイントを叩くとリファラ (もしくはクエリパラメタの template に指定された URL) にある app.json を読み取り、ソースコードをデプロイする。

Pull Request と Heroku Button

Heroku Button が面白いのは、ソースコードのレポジトリを GitHub を前提にしている点。

app.json に明示的にレポジトリURL を書かない場合、app.json の URL はリファラから動的に決定される。GitHub の場合は Pull Request やコミットハッシュ毎に URL が付く。なので README.md にデプロイボタンを置いて app.json のレポジトリURLを空にしておけば、それだけで第三者が (master だけでなく) 任意のブランチの任意のコミットを選んで Heroku にデプロイできるようになる。

以下は、サンプルアプリケーションのあるコミットをデプロイした例。ハッシュ値が付いてるのがわかる。

よって Pull Request ベースで Web 開発をしてるときに、ちょっとこの Pull Request の動作確認をしたいなと思ったら、その Pull Request のブランチの Heroku Button をおしてデプロイして動作させるということが可能になっている。

app.json があったら、Pull Request のスレッドに自動的に Heroku Button が表示されるとかそういう改修を、GitHub (やどっかのサービス) がやってくれることを期待したい。

Immutable Infrastructure / Webアプリケーションのポータビリティ

半年ほど前に ポータブルなWebアプリケーション - naoyaのはてなダイアリー に、Immutable / Disposable Infrastructure の概念によって Web アプリケーションがポータブルになり、結果的に、Web アプリケーションが交換できるようになるのではないかという話を書いた。

Heroku Button を見て、そういえばそんなことを書いたな、ということを思い出した。

ご存知の通り、Heroku のバックエンドはコンテナベースの仮想化環境よって設計されていて、コードを push するたびに古いコンテナは廃棄されて新しいコンテナにアプリケーションがデプロイされる。Immutable Infrastructure そのものである。

常に廃棄されることを前提に Web アプリケーションを構成するには、Web アプリケーションに含まれる外部ライブラリなどの各種依存関係なが宣言的に明記されていなければならない。そのために Gemfile や Procfile などがある。この辺りのプラクティスは The Tweleve-Factor App などにまとまっている。

結果的に、Immutable であるという制約が Web アプリケーションの実行環境にポータビリティを与える・・・というのが先のエントリで書いたこと。この辺の話は Immutable Infrastructureが開発プロセスに与える影響 というカンファレンス発表でも話した。

Heroku Button は、その典型的なユースケースだと言える。

Docker や Docker Hub などの普及が進むと、次は Heroku という特定ベンダのインフラ環境に縛られない、同様のユースケースが実現されていくのは間違いない。

というわけで Heroku Button はとってもクール、である。

Sqwiggle が良いという話、またはリモートでアジャイル開発をどう進めるか

KAIZEN platform Inc. は、新しい働き方をいろいろ試してみようという会社でそのひとつにリモートワークがある。リモートワークの良さあるいは良くないところについては、以前に Rebuild.fm の ep.32 でも話した。

ちかごろは、オンラインミーティングのための道具、情報共有のための道具もクラウドサービスがたくさんあるので、その辺を使って工夫すれば一昔前に比べてだいぶリモートワークも現実的になってきている。実際、KAIZEN には大阪からリモートワークしている人とか、最近リモートワークを前提に都内から鎌倉に引っ越したメンバーなんかもいる。

リモートワークとアジャイル開発

HipChat、Google Hangout や Qiita Team なんかを使うことで、日常の会話、ミーティングや情報共有についてはもともと特に困ったこともあまりなかった。特に Qiita Team での情報共有はチームビルディングにおいて重要な一幕だった・・・という話も Rebuild でしたっけかな。

ただ、アジャイル開発という文脈でいったときに「どうするべ?」ということが幾つかあった。

その際たるものが「全員同席」。まあ全員同席はアジャイルで必ずやらなければいけないこと (・・・そもそも必ずやらなきゃいけないことなんてないとは思うんだけど)、ではないのだけど、リモートワークだとどうしてもその辺りのコミュニケーションが希薄になりがちで、チームビルディングという観点では課題だなと思っていた。

例えば、ちょっとした仕様の確認とか、あるいは雑談のために Google Hangout を使ってオンラインミーティングしようとすると HipChat で以下の様なやりとりが行われたりする。

naoya 「@ngs ちょっと確認したいことあるんだけど Hangout いい?」
ngs「なんでしょう」
naoya「あのモジュールのあそこの実装なんだけど」
ngs「あー、あそこは @funami がよく知ってます」
naoya「なるほど、じゃあ @funami も Hangout」
naoya「@funami さんーん」
naoya「・・・いないね」
ngs「いないですね」
funami 「あ、ごめん、チャットみてなかった」
naoya 「おうおう、じゃ Hangout はじめましょ」
ngs 「url どこですかー」
naoya 「ちょっと待ってね・・・はいこれ」
funami 「なんか You're not allowed っていわれる」
naoya 「あれれ」

これで 10分 かかる。経験がある人はわかると思うが、これ、実際はなかなかにイライラする。誰が悪いわけでもないのでそのイライラをぶつける先もない。

これがリモートワークでなければ、その場でいるかどうか確認してその場でちゃちゃっと話合って終われるんだけど、リモートだとなかなかそうもいかない。そしてこの 10 分がめんどくさいので、チャット上でやりとりして実際には10分話せば終わることを30分も1時間もかけてやりとりしたりする、なんてことになりがちである。(結果的にテキストで記録が残る、というところはよいのだけど)

Sqwiggle

そんな折り、たまたま 8 Helpful Online Tools To Keep Your Company On Track という記事を読んだ。これは Buffer を作ってる人たちがどうやってリモートワークしてるかという話。Buffer はなかなか面白い働き方をしているらしい。

この中で紹介されていた Sqwiggle というツールが、まさに先の問題解決をしてくれた。あるいは、今後してくれそう。

Sqwiggle を起動すると、カメラが有効になってこんな感じで Sqwiggle を立ち上げてるチームメンバーが一覧になる。

Sqwiggle は常にストリームをしてるわけじゃなくて、定期的に画像のスナップショットをサーバーに送ってる。そのスナップショットがときどき更新されて、この一覧がでる。

この一覧にいるメンバーと口頭で何か話したいことがあると思ったらどうするか。相手の写真をタップするだけ。すると、その瞬間からセッションが始まる。セッションをはじめるよという呼びかけみたいなのは一切なくって、タップしたら音がなって、いきなり相手と会話が始められる状態になる。

常時カメラで相手の状況が映し出されてるので、相手がいる/いないの確認がいらないし、Hangout を始める時の招待とか url のやりとりとかそういうのも一切必要ない。会話の途中で、その会話にもう一人追加したいとおもったらその人もタップすれば3人での会話になる。

使用感としては Hangout でのミーティングは会議室に移動してよいしょで会議を始める感じで、Sqwiggle は隣にいる同僚にちょっとちょっと、と話しかけるような感じに近い。

最初 Sqwiggle を使い始めたときは、常時カメラで写されてるということでプライバシーのこととか、割り込みしやすいというのでリモートワークの利点がとかいろいろ心配していたけどその辺は実際やってみると普段はほとんど気にならない。まあ、自分は Sqwiggle を ON にしてるのを忘れて画面の前で着替えをしたことがあるが、致命傷にはならなかったw そのうち放送事故が起こるかも知れないが、まあそれはそうなったらそのときだ。

どちらかといえば、リモートワークにありがちな、自己管理できなくてついついさぼってしまうみたいな問題をも Sqwiggle は解決してくれるところが非常によい。周りに誰かいる、というような感覚でリモートワークに望めるので適度な緊張感が得られる。怠惰な自分には、それがとてもありがたい。

Daily Standup やスプリント計画、KPT

こんな感じで全員同席で進めていってるときのチーム感は Sqwiggle によって結構解消されつつある。

KAIZEN のワークフローだとリリースデプロイの直前 QA なんかで頻繁にエンジニア同士でも確認事項が発生するのだけど、普段チャットでやってるところ、次回はその辺も Sqwiggle を駆使してコミュニケーションを厚めにやってみようかなんて話をしている。

ちなみにアジャイル開発、というかスクラムでいくと他のプラクティスをどう実践してるかというと、以下の感じである。

  • Daily Standup は、毎朝時間を決めて固定の Hangout URL に集まるようにしている。Sqwiggle は残念ながら大人数でのリモートチャットをサポートしてないのと、議事録用のスクリーンシェアができないため。時間になると Hangout にみんな集まってきてちゃちゃっとその日のやることを共有して、議事メモがすぐに Qiita Team に上がる。
  • スプリント計画は、実は厳密にはあまりやってない。やってるのはタイムボックスを決めて、2週間毎に前後のプロジェクト進行をスプリント単位で確認するくらい。自分の経験上、受託開発とかもうちょっとカチっとした開発では QCD における Delivery ・・・ つまりはスケジュールの優先度が非常に高いので見積もり精度を上げるためにもスプリント計画を厚めにやるんだけど、365日開発し続ける SaaS 系サービスだとこの辺はゆるくやってるくらいが丁度いいと思ってる。がっつりやりすぎて疲れてしまうことより、ゆるくても長く続けて常にタイムボックスを意識して進められるくらいが良いかなと思う。
  • 一方、KPT は日時を決めてしっかりやっている。スクラムマスターがその日までにオンライン上で KPT を集めておいて、その時間帯に Hangout で集まってミーティングをする。アジャイル開発においては、定期的に開発プロジェクトを見直し自分たちのやり方が間違っていないか、おかしなところがあったらそこをどう直していくかということが何よりも大切で、KPT はそのための良い機会になっている。

人の問題と、技術の問題

顧問として携わりはじめた昨年夏ぐらいから時間が経って、改めてみてみるといろんなプロセスが改善されて (KAIZEN だけに。) 安定した開発ができるようになってきたと思う。

当初は、まずはいろいろ教科書通りにやってみようということでスプリント計画そのほかをみっちりやったりもしてたが、やっぱりこれは違うねと感じたところは KPT で Problem にあげて、やらないことはやらない、緩く崩すところは崩すということをしながら今のスタイルに落ち着いている。

ところで昨晩から「ピープルウェア」という本を読んでいる。ソフトウェア開発の名著なんだけど、今ままで読んだことがなくて、たまたま知り合いのブログで感想があがってたのをきっかけに読み始めた。これの第一章から早速なかなか面白いことが書いてある。

実際のところ、ソフトウェア開発上の問題の多くは、技術的というよりは社会学的なものである

さもありなん。

技術の問題というのは、案外正解を導きやすい。コンピュータは、こうしたらこうなるというのにちゃんと答えを出してくれるし、どちらのやり方が良いかというのに結論を出しやすい。

一方、人間の問題は、そのやり方が本当に正しいのかどうかが見極めにくい。ものによっては半年とか一年後くらいになってようやく結果がわかることなんていうのも多い。時間が経過しすぎてどのアクションがその結果に繋がったのかという因果関係がはっきりしないことも多い。

だから、ソフトウェア開発の人間はついつい (解決の道筋が見えやすい) 技術的な問題にばかりフォーカスしがち、というようなことがピープルウェアには書いてあって、そうだよねえと思いながら読んでいる。

Daily Standup をリモートでどうやるかとか、リモートでも気軽に雑談できるような環境を整えることにリソースを割き続けるとか、そういうことは社会学的な問題だと思っている。一方、先日書いたような GitHub を使ったデプロイフローなんかは社会学的側面もありつつ基本は技術的な問題である。

人の問題が解決されてチームが良い状態になると、今度は技術の問題がボトルネックになる。せっかく迅速に開発してるのにリリース作業や QA に時間がかかりすぎる、とか。実際 KAIZEN では一時期リリースの品質に問題があったのでコミュニケーションを取って QA をしっかりやるようになったのだが、そうしたところ今度は人手での作業が多すぎてつらい感じになったので、E2E テストを書いて全部自動化することによってそのボトルネックを解消した、なんて典型例があった。

逆に技術的な問題ばかりを解決しても、コミュニケーションがボトルネックになって、だれそれの了解が得られないからリリースできないとかそういうことが起こる。

人と技術の問題を両面からバランスよく解きほぐしていくのが、昨今のソフトウェア開発におけるチームビルディングのコツなんではないか、と思っている。

追記

ちなみにリモートワークと書くと時折誤解を招くので、捕捉しておく。

リモートとはいっても、100% リモートワークしましょうということではなくて写真にも映ってる通りオフィスはある。オフィスに行くか行かないかは自分で決めるようになっている。対面でしたほうがよいミーティングがある日はオフィスにいくしそうでないなら自宅、あるいはカフェかどこかでやる。いい大人なんで、その辺は自分たちで判断しましょうね、お互い信頼してれば大丈夫だよね、ってな感じの仕組みになっている。

もちろん対面でやった方が早いと思うことはたくさんあるけど、本当にそれは対面じゃないとできないのかというところをまずは疑ってみないことには、新しい働き方を追求するということはできない。結果的にそれで会議を減らす、非同期に作業することができれば全体の効率が上がるわけで、そこで思考停止しない・・・ということが大切だと思う。