越境する開発 〜分散する開発現場への挑戦〜 に参加してきました

2/1(土) に 越境する開発 〜分散する開発現場への挑戦〜 - DevLOVE四国 | Doorkeeper に参加してきました。
当日の流れはこんな感じ。

  • はじめに
  • 自己紹介 & 開発現場での悩みごと共有
  • 「越境する開発 〜分散する開発の現場〜」(市谷聡啓さん)
  • 「"地方エンジニア"という考え方はすでに終わっている」(わたし
  • 「ダイヤモンドクロスで生まれたWEBアプリケーション」(岩井克之さん)

前日に行われた アジャイル型開発におけるプラクティス活用リファレンスガイドの勘所と活用方法 で松山に来られていた市谷さん、本橋さんもいらっしゃるという、いつもの愛媛の勉強会より豪華な感じで開催されました。
参加者のほとんどは顔見知りということで終止アットホームな雰囲気で進んでいきました。

#agile459 アジャイル型開発におけるプラクティス活用リファレンスガイドの勘所と活用方法 - Togetter

はじめに

今後も増え続けるであろう開発現場が物理的に分散するスタイルについて、どのようにデザインするのが良いのか、どのように乗り越えていけるかをみんなで考えよう、という勉強会の主旨を市谷さんから説明されました。

自己紹介 & 開発現場での悩みごと共有

一人一人自己紹介をしました。
基本的にはみんな顔見知りだったので「最近太ってきちゃって大変」とか「ここまでチャリで来ました」とか開発現場とは関係ない話があったり(笑) と、楽しい雰囲気で進みました。

「越境する開発 〜分散する開発の現場〜」(市谷聡啓さん)

続いては市谷さんの発表、実際に市谷さんがやられた分散開発の事例を元に、うまくいかなかった点を整理し、どうすればもっとうまくやれたんだろう?ということをみんなでディスカッションしました。
結構オフレコなことが多くて詳細についてはあまり触れられないんですが、みんなから色んな視点で意見が出ました。
そんな中で私が印象に残っているのは「物理的に現場が分散するとコミュニケーションはどうしても弱くなってしまう」がそこをどう乗り越えるか?という議論です。

私なりの答えは こんな感じでリモート勤務やってます - ITエンジニアとして生きる でも少し触れていますが、コミュニケーションに割くリソースを最小化して開発リソースを最大化する、動くものを早く完成させて動くものベースで会話をすることによって1回1回を密度の濃いコミュニケーションにする、というものです。
これは私が分散開発を実践していく中で色々試し、失敗して学び、それを通して辿り着いたものなのでこれも1つの解だとは思っています。

ただこの議論の中で「普段コミュニケーションで埋めているものは何だろう?」という問いがあってですね、、、この問いに対する回答を明文化出来れば、ひょっとしたら前述の私なりの答えよりもっとうまいやり方とかに辿り着けるかも?という想いが沸いて個人的にとても興味をそそられたのです。
またいつか色んな方々とこのテーマについて話してみたいですね。

「"地方エンジニア"という考え方はすでに終わっている」(わたし)

続いては私の発表、これから「地方」という考え方が終わりゆくものになっていく、その時代を生き抜いていくためには信頼を得る仕事力が大事である、という話をさせて頂きました。

「ダイヤモンドクロスで生まれたWEBアプリケーション」(岩井克之さん)

ラストは岩井さん、松山のコワーキングスペースである ダイヤモンドクロス のニーズから生まれたクラウド型給与計算アプリについてのお話でした。
http://ncpartwork.nextcode.jp/#/service

普段忙しくてずっと手付かずだった機能を今回の発表が決まってから導入したそうです。
これからも機能追加を依頼したい場合は、まずどこかの勉強会での発表を依頼するとスムーズに追加してもらえるかもしれません(笑)

おしまい

とても濃い時間を過ごせた勉強会でした。
参加者のみなさんにはそれぞれの世界観があって、みんなで議論するのがとても楽しかったです。
また普段なかなかお会い出来ない市谷さん、本橋さんら東京でご活躍される方々と議論し合えるのもとても嬉しく思いました。
これからも愛媛、盛り上がっていきますよ〜!!

こんな感じでリモート勤務やってます

久しぶりのリモート勤務ネタです。
最近ちょこちょこ「リモート勤務ってどんな感じですか?」という質問を受けることがあって、いい機会なのでまとめてみました。

こんな感じで受託開発やってます

ハートレイルズでは大きく以下の2パターンで受託開発しています。

  1. 顧客との窓口になるメンバーが1人いて、そのメンバーがオンサイト顧客代理となる
  2. 開発メンバー自身が顧客とやりとりをする

前者はオンサイト顧客代理が開発メンバーにクラウド上(GitHub や Bitbucket)でタスクを割り当てて仕事を進めるスタイルです。トラックナンバー1になりがちですが、いい意味で情報を精査出来るので小さめのプロジェクトには向いていると思います。
またオンサイト顧客代理も顧客先に常駐しているわけではなく、顧客先を訪問するのはせいぜい隔週1回くらいですので労働集約的にはなりません。
顧客と開発フローを話し合ってお互い離れていても円滑に仕事が出来るような体制を敷いています。

後者は開発メンバーがクラウド上で直接顧客とやり取りします。
やり取りする方法は前者と似ていて、クラウド上で顧客とタスクを渡し合いながら仕事を進めます。
情報がクラウド上に集約されてトラックナンバーも増やせるというメリットはありますが、開発メンバーからは顧客の表情が見えないので、知らず知らずに信頼貯金を減らしてしまうようなことをしてしまうリスクはあるかもしれません。
また矢面に立つメンバーが情報を噛み砕いてくれるということは無いので、クラウド上に集約された情報を自ら追って内容を整理したり、どの辺りがプロジェクトのボトルネックになりそうかといったことを推測していくスキルが開発メンバーに求められるように思います。

こんな感じでチーム開発やってます

http://wazanova.jp/items/675

ハートレイルズでもここで紹介されている Github と似たような形で、基本的に「pull request/chat を中心にコミュニケーションは非同期スタイル」を採用しています。
これは開発メンバーが仕事に打ち込む時間や裁量を最大化出来るというメリットがある反面、管理側からは仕事が見えにくいというデメリットもあります。(しばらく開発メンバーからアウトプットが出て来ないときは管理者から「何やってますか?」という chat が飛んだりします。)

私がその解決策として実践しているのは、単純ですが「作業を分割すること」で、私の場合だと大体「2時間〜1日」くらいの単位で分割してなるべく毎日成果が出せるように心がけています。
そうすることで管理側から仕事も見えやすくなりますし、アウトプットの単位が小さいのでレビュー範囲も小さく、フィードバックも素早くもらえます。
この「作業を分割して毎日成果が出せるようにすること」はリモート勤務を実践する上で最も大事なことではないかと思っています。

ちょっと付け足し

リモートチームは物理的にロケーションが離れているので、同じ現場にいるように議論や確認、意見交換は不可能です。
慣れてくれば高いレベルでそういうことも実現出来るかもしれませんが、同じ現場にいる時と大差なく、というのは難しいように思います。
そんな中でどうやって成果を出すのか・・・???

ハートレイルズでは、コミュニケーションに割くリソースを最小化して、開発リソース(個々の開発者の裁量)を最大化することによって成果の最大化を目指しているように思います。
もちろん全く指示を受けないわけではないですが、設計・開発における大部分について裁量を頂いています。
そのかわり個々人にはプロフェッショナルな自覚や責任、スキルが求められますし、何より「任せたらやってくれる!」という信頼関係がなければなりません。
そういった各々が自立した集団でないとリモートチームは機能しないように感じますし、そういったレベルをしきい値として求められているような気がしています。

まとめ

今回はどんな感じでリモート勤務しているのかを書いてみました。
色々求められるスキルやら何やら書きましたが、一番大事なのは信頼して裁量を与えられているその仕事に最大限応えようとするマインドではないかと思います。
そのマインドがあればスキルは後からついてくるのかなと。
これからもこのマインドを大事に、もっとスキルを磨いてより良いエンジニアを目指して頑張ってゆこうと思う今日この頃でした。

ExceptionNotifier.notify_exception で処理されない3つの Exception

exception_notification v4.0.0 の話です。
GitHub - smartinez87/exception_notification at v4.0.0

v4.0.0から通知処理をバックグラウンド実行する、以下のようなコードが書けるようになりました。

begin
  some code...
rescue => e
  ExceptionNotifier.notify_exception(e)
end

これは便利なのですが、1点認識しておかないといけないことがあります。
ExceptionNotifier では以下の3つの Exception についてはデフォルトで処理しないようにハードコードされています。

もしこれらを処理したいのであればモンキーパッチ的な対応やら何やら施す必要があります。

【修正】
http://smartinez87.github.io/exception_notification/#ignore-exceptions/ignore_exceptions
ここにあるように ignore_exceptions オプションを利用して、例えば下記のような定義をすればモンキーパッチ的な対応をしなくても3つのExceptionを処理対象とすることが出来るようですね。

Whatever::Application.config.middleware.use ExceptionNotification::Rack,
  :ignore_exceptions => '',
  :email => {
    :email_prefix         => "[Whatever] ",
    :sender_address       => %{"notifier" <notifier@example.com>},
    :exception_recipients => %w{exceptions@example.com}
  }

ELB の Cross-Zone Load Balancing という機能

旧来のELB

旧来のELBの有名な話で、マルチAZで均等にリクエストを振り分けるためには各AZに配置するインスタンス数を同数とする必要がありました。
これはELBがAZ毎にLBを置き、その配下のインスタンスにしかリクエストを転送できないアーキテクチャとなっていたためです。

この性質はオートスケールと組み合わせて考えた場合に困ります。
なぜならオートスケール時はAZ間で足並みそろえてスケールされるわけではないため、例えば以下のような設定とした場合、一方のAZでは1台のインスタンス、他方のAZでは5台のインスタンスという状態が発生し得るからです。

<ELBとオートスケール設定>

Cross-Zone Load Balancing という機能

これまで前述の事項は避けようがなかったのですが、それを解決してくれる「Cross-Zone Load Balancing」という機能が2013年11月にリリースされました。
Elastic Load Balancing Announces Cross-Zone Load Balancing

アーキテクチャとしてはこれまで同様にAZ毎にLBが置かれるようですが、Cross-Zone Load Balancing を有効化すると各LBがAZを跨いでリクエストを転送できるようにしてくれるようです。
したがって、AZ単位ではなく、ELB配下のインスタンス単位でリクエストを均等に振り分けることが出来るようになるため、AZ間でインスタンス数を合わる必要がなくなり、オートスケール時も懸念する必要がなくなりました。
ナイスな機能ですね。


ちなみに Cross-Zone Load Balancing は CLI で有効化できるようです。(現時点ではまだマネージメントコンソールは未対応。。。)
Configure Cross-Zone Load Balancing for Your Classic Load Balancer - Elastic Load Balancing

定数を環境変数から取得したい、かつデフォルト値を定義したい

▼文字列を取得したい場合

LOCALE = ENV['LOCALE'] || 'ja'

▼数値を取得したい場合

MAX_COUNT = (c = ENV["MAX_COUNT"].to_i) > 0 ? c : 30
TIMEOUT = (t = ENV["TIMEOUT"].to_f) > 0 ? t : 0.5

nil.to_i は「0」nil.to_f は「0.0」 であるため、文字列を取得したい場合と同じように書くとデフォルト値が採用されない。

MAX_COUNT = ENV["MAX_COUNT"].to_i || 30    # 環境変数が定義されていない場合「MAX_COUNT:0」となる
TIMEOUT = ENV["TIMEOUT"].to_f || 0.5       # 環境変数が定義されていない場合「TIMEOUT:0.0」となる


【2012/12/12 追記】
コメント頂きました。
数値を取得したい場合はこちらの方が良い気がする。

MAX_COUNT = (ENV["MAX_COUNT"] || 30).to_i
TIMEOUT = (ENV["TIMEOUT"] || 0.5).to_f

RDSのクエリ調査

RDSのクエリ調査を実施する際にすべきこと。

(1)RDSの設定

  • general_log:1 ・・・全てのクエリをログに残す
  • slow_query_log:1 ・・・スロークエリ(時間のかかっているクエリをログに残す)
  • long_query_time:1 ・・・スロークエリの時間(秒)

(2)設定確認

  • show global variables like 'general_log';
  • show global variables like 'slow_query_log';
  • show global variables like 'long_query_time';

(3)全クエリの確認

  • select * from mysql.general_log;

(4)スロークエリの確認

  • select * from mysql.slow_log;

ゆるふわ.rb の第1回目を開催しました

ゆるふわ.rb の第1回目を開催しました。
ゆるふわ.rb in 大洲 〜新鮮な刺身と共に〜 - ゆるふわ.rb | Doorkeeper

ゆるふわ.rb というのは私が発起人となった四国初のRubyコミュニティです。
その名の通り、ゆる〜くRubyについて語り合う場としたいという想いで立ち上げました。
あとはプログラミングの原点である「プログラムしたものが動くって楽しい♪」ということを実感出来る場にしたいとも思っています。
今後もそういう方向性でやっていこうと思っていますので、興味がある方は都合の合う時に訪れてみてください。

それではここからは当日のお話を。

会場は調理室

実は今回の勉強会は調理室で実施しました。
刺身を捌きたいからというのもあったんですが、調理室でやるのって前例もなさそうだし面白いかも?というノリでそうしました。
参加者のみなさんにはもちろん黙ってたんですが、入ってくるなり「調理室で勉強会って新しいねw」という反応を頂いて掴みはOKって感じでした。
学生時代の調理実習みたいで面白かったですよ。

微妙に名前が間違ってましたがw(正しくは「ゆるふわ.rb」です!><)

ウェルカムドリンクと自己紹介

まずはみなさんが和むようにウェルカムドリンクを用意しました。
ウェルカムドリンクと言ってもお酒ではなくみそ汁ですけどw

みそ汁を飲んでぽかぽかしながら参加者のみなさんに自己紹介頂きました。
とりあえずバリバリのRubyマスターはいなくてホッとしました。(私自身Ruby歴は浅いのでいきなり達人が現れたらどうしようかとビビってましたw)
そんな感じでゆるりとスタートしました。

たった100行のGUIプログラムをひも解く

次はShoes(Shoes! The easiest little GUI toolkit, for Ruby.)というGUIツールキットを利用して書かれた100行のタイピングゲームについて語り合いました。
はじめに作成者の私が全体構成やらなんやらプログラムについて説明し、以降はコードを見てもらったり動かしてみてもらったり参加者のみなさんに自由にいじってもらいました。

プログラムはこんな感じです。(githubにもあげてます。GitHub - yurufuwarb/typing

# -*- coding: utf-8 -*-
require 'csv'

#----------------------------------------
# タイピング定義
#----------------------------------------
definitions_ja = []
definitions_roma = []

CSV.foreach('definitions.csv') do |row|
  definitions_ja << row[0]
  definitions_roma << row[1]
end

#----------------------------------------
# タイピング
#----------------------------------------
TITLE = "たった100行のタイピングゲーム"
Shoes.app(title: TITLE, width: 900,resizable: false) do
  background white

  # ランダムに円を描く
  fill rgb(0, 0.6, 0.9, 0.1)
  stroke rgb(0, 0.6, 0.9)
  strokewidth 0.25
  140.times do
    oval( left:   (-5..self.width).rand,
          top:    (-5..self.height).rand,
          radius: (25..50).rand)
  end

  # 入力フィールド
  @line = edit_line(width: 0, height: 0)

  # ゲーム開始確認
  exit if !confirm('Are you ready?')

  # 正解タイプ数、ミスタイプ数
  good = 0
  mistake = 0

  stack :margin => 0.1 do
    background white
    @line.focus
    index = Random.rand definitions_ja.length

    stack :margin => 12 do
      ja = subtitle(strong(definitions_ja[index]),:font => "MS Gothic")
      roma = tagline(definitions_roma[index], :font =>"Arial Black")

      @line.change do |input|
        if input.text.downcase == roma.text[0].downcase
          good += 1
          roma.text = roma.text[1..roma.text.length]
        else
          mistake += 1
        end

        input.text = ""

        if roma.text.length == 0
          index = Random.rand definitions_ja.length
          ja.text = definitions_ja[index]
          roma.text = definitions_roma[index]
        end
      end
    end
  end

  stack :margin => 0.1 do
    caption(strong("制限時間"),:font => "MS Gothic")
    p = progress :width => 1.0
    a = animate(5) do |i|
      p.fraction = (i % 100) / 100.0
      next if i < 100

      # アニメーション終了
      a.stop

      # タイピング結果画面
      dialog(title: TITLE, width: 500, resizable: false) do
        background white

        # ランダムに円を描く
        fill rgb(0, 0.6, 0.9, 0.1)
        stroke rgb(0, 0.6, 0.9)
        strokewidth 0.25
        60.times do
          oval( left:   (-5..self.width).rand,
                top:    (-5..self.height).rand,
                radius: (25..50).rand)
        end

        stack :margin => 0.1 do
          score = good * 3
          ratio = (good.to_f / (good + mistake).to_f) * 100
          rank = "C"
          if score >= 360 && ratio >= 99.5
            rank = "SS"
          elsif score >= 330 && ratio >= 98
            rank = "S"
          elsif score >= 300 && ratio >= 96.5
            rank = "A"
          elsif score >= 270 && ratio >= 94
            rank = "B"
          end

          subtitle(strong("得点        :#{score}"),:font => "MS Gothic")
          subtitle(strong("ランク      :#{rank}"),:font => "MS Gothic")
          subtitle(strong("正解タイプ数:#{good}"),:font => "MS Gothic")
          subtitle(strong("ミスタイプ数:#{mistake}"),:font => "MS Gothic")
          subtitle(strong("正解率      :#{ratio.round(1)}"),:font => "MS Gothic")
        end

        stack :margin_left => '30%' do
          button "おしまい" do
            exit
          end
        end

      end   # dialog(...) do
    end     # animate(...) do
  end
end

今回初めてShoesを触ったんですが、すごく手軽に&直感的にプログラム出来て感触が良かったです。

えっ?刺身でビアバッシュ??

次はメインの(?)ビアバッシュ、鯛とカンパチをつまみにビール・日本酒を頂きました。
(私はここで飲み過ぎたようで翌日の昼過ぎまで身動きが取れない状態となってしまいました・・・)

そして私が旗ふりすることなくいつの間にか始まった Ruby Warrior (Ruby Warrior - Popular Free Ruby Programming Tutorial Game)、気が付いたらペアプロっぽくなっていました。
ちなみにコーディングしている人はシラフ、教えている人は酔っぱらいですw


チェックアウト

最後にみんなで片付けをして、来たときよりも美しく!して撤収しました。

今回は手作り感満載の第1回目でしたが、楽しい場としたいという私の想いは実現出来たかなと思っています。
参加して頂いたみなさんにも嬉しいご意見をたくさん頂きました。
これからも構えないで参加出来るゆるい勉強会、プログラミングの楽しさを実感出来る勉強会を目指してやっていきたいと思います。