give IT a try

プログラミング、リモートワーク、田舎暮らし、音楽、etc.

西脇.rb & 東灘.rb ペアプログラミング In Actionを開催しました #nshgrb

はじめに

去る2013年9月21日、西脇.rb & 東灘.rbの勉強会を開きました。
これまでは「もくもく会」をやってきたのですが、今回は初の試みとして「共通の問題をペアプログラミングで解く」というコンセプトでやってみました。


なぜペアプロにしたのか?

ペアプロを取り入れた理由の一つは時間の問題です。
最近、もくもく会も少しずつ人数が増えてきて、10人ぐらい集まるようになってきました。
すると、コードレビューの時間が延びるために、一人一人のコードをじっくりレビューできないという問題が出てきます。
ペアプロにすればレビューの回数が参加人数の2分の1になるので、コードをじっくりレビューできます。


もう一つの理由は技術や知識をより深く共有するためです。
もくもく会のコードレビューでも他の人のコードを見ることで勉強になることが多いです。
しかし、思考の過程やエディタの使いこなしなどは、そこまで詳しくわかりません。
ペアプログラミングで一緒にコードを書けば、そういったところもペアの間で共有することができます。


最後の理由は単純に「ペアプロとかもやってみたいね」という意見が参加メンバーの間で以前からちらほら挙がっていたからです。
なので、ニーズもあるようなら、ちょっと心機一転してやってみようか、ということになりました。


芝生の上で勉強会!?

あと、もう一つの新しい試みとして、今回初めて神戸方面ではなく西脇方面の会場を選んでみました。
まあ、西脇方面といっても西脇市ではなく、西脇市から南にちょっと離れた小野市というところでやったんですけどね。
(地元の人じゃないと地理関係はよくわからないと思います^^;)


うるおい交流館エクラという小野市の公共施設を借りたんですが、ここがすごく広くてきれいな会場でした!
しかもこんなに広々とした芝生があって、みんな芝生に寝転びながらコードを書きました!!


f:id:JunichiIto:20130921122209j:plain
f:id:JunichiIto:20130921122046j:plain
f:id:JunichiIto:20130921122159j:plain
f:id:JunichiIto:20130921122133j:plain
f:id:JunichiIto:20130921122123j:plain


・・・というのは冗談で、実際は会議室を借りてその中でやりました。
これは「気持ちよさそうだからここで記念写真撮ろうぜー!」と言って撮った写真です(笑)。


でも会議室も広くて安くて、プロジェクターも解像度の高い高性能なプロジェクターだったので、勉強会を開催する施設としてはかなり理想的な環境でした。


勉強会の流れ

さて、肝心の勉強会ですが、こんな流れで開催しました。

  • 問題選びとペア決め (0.5h)
  • ペアプログラミング (4h)
  • コードレビュー (1.5h)

本当は途中で問題とペアを切り替えるつもりだったんですが、みんなコーディングに時間がかかったので、結局一問だけでペアも変えずにやりました。


問題選び

問題選びは参加メンバーが一人一人問題を持ち寄って、多数決で決めました。
今回選ばれたのは僕が持ってきた「Code Breaker」という問題です。
The RSpec Bookに載っている問題なので、知っている人も多いかもしれません。

The RSpec Book (Professional Ruby Series)

The RSpec Book (Professional Ruby Series)

  • 作者: David Chelimsky,Dave Astels,Zach Dennis,角谷 信太郎,豊田 祐司,株式会社クイープ
  • 出版社/メーカー: 翔泳社
  • 発売日: 2012/02/22
  • メディア: 大型本
  • 購入: 7人 クリック: 141回
  • この商品を含むブログ (19件) を見る


簡単に説明すると、予め設定された4文字の数字を推測するゲームです。
数字と位置が合っていれば「+」、数字は合ってるけど位置が違う場合は「-」の記号を出力します。
完全に合致すれば「++++」になります。

例
| code | guess | mark | 説明
| 1234 | 1555  | +    | 1だけ合っている。位置も正しい。
| 1234 | 2555  | -    | 2だけ合っているが、位置は違う。
| 1234 | 1243  | ++-- | 4つとも数字は合っているが、4と3の位置が違う。
| 1234 | 1234  | ++++ | 完全に合致。


詳細な仕様はこちらを見るとわかると思います。

 

ペア決め

ペアは「ペアプロ経験者、Ruby熟練者」と「ペアプロ未経験者、Ruby初心者」がペアになるようにしました。
参加者は6人だったので、前者3人と後者3人がそれぞれ「グーチョキパー」を出し、同じ手を出したメンバー同士をペアにしました。


ペアプログラミング

早く終われば次の問題に移る予定だったのですが、この問題は見た目以上に難しいところがあって結局これ一題で終わりました。
1時間おきにみんなの進捗を聞いて、進捗に大きなズレが出ていないかも確認しました。


僕は今回、Ruby歴1ヶ月という大学生、@techno_tanoCさんとペアになりました。
プログラムを組む際はRSpecを使ってテスト駆動開発(TDD)のスタイルでやったのですが、RSpecもTDDも初体験だったようで「こんな開発の仕方があるなんてすごい!」と喜んでもらえました。


一方、僕は後半から「あれ?こういうケースはどういうロジックを組めばいいんだ!?」と迷ってしまったのですが、彼が良いロジックを考えてくれたので、切り抜けることができました。
こんなふうにお互いに足りないところを保管し合えるのがペアプロのいいところですね。


他のメンバーも良い感じに話し合いながらペアプロを進めていたようで、和気あいあいとした雰囲気になっていました。


コードレビュー

ペアプログラミングが終わったら最後はコードレビューです。


みんな同じ問題を解いているので、もくもく会と違ってプログラムの仕様を説明する時間はいらず、いきなりロジックの説明から入れます。
また、ロジックもある程度似ていたので、「そこはこういう書き方ができるよ」とか「こう書いた方が良いよ」という意見も出しやすかったです。


ペアは3組みしかいないので、レビューする時間も1組あたり30分ぐらい使えて、じっくりコードを読んだり、その場でリファクタリングしたりすることもできました。


当日各ペアが書いたコードはGithubにあがっています。

 

まとめ

勉強会が終わったあとは、近くのファミリー居酒屋で懇親会を開きました。


ペアプロ形式の勉強会は初めてだったので、どんな勉強会になるのか不安なところもありましたが、思っていた以上に楽しかったとみなさん言ってくれました。
僕自身もこれはこれで、いつもの「もくもく会」とは違った面白さがあるなと感じました。


今回は参加者が6人とちょっと少なかったので、次回もペアプロ形式にしてみて、もっとたくさんのメンバーにこの面白さを味わってもらおうということになりました。
というわけで来月の勉強会も「ペアプログラミング In Action」でいきます!


お知らせ その1: 西脇.rb & 東灘.rbについて

西脇.rb & 東灘.rbは西脇~神戸方面で活動するRubyコミュニティです。
だいたい月1回のペースでRubyの勉強会を開いています。
活動の基本コンセプトは「自分の手と頭を動かしてコードを書こう」「他の人が書いたコードを読んで議論しよう」です。


興味のある方はDoorkeeperのコミュニティページからメールアドレスの登録をどうぞ。
勉強会の開催情報が毎回通知されます。

 

またFacebookページやTwitterでも情報発信していますので、良かったらこちらも「いいね!」やフォローをお願いします!

 

お知らせ その2: DevLOVE関西 ~Decision~でお話しします

西脇.rb & 東灘.rbとは無関係ですが、2013年11月16日(土)に「DevLOVE関西 ~Decision~」というイベントでソニックガーデンの倉貫さん(@kuranuki)と一緒にお話しします。
ほかにも各界の著名なエンジニアの方々のお話が聞けますので、こちらも興味のある方はご参加下さい!


お話しする内容や登壇が決まったいきさつなどはこちらのエントリーに書いてあります。

 

おまけ: Code Breakerを自分でじっくりで解いてみた

ペアプログラミング In Actionが終わったあとに、「あのロジックをもっとクールでエレガントに書いてみたい!」という思いがふつふつと沸き上がり、家に帰ってからもう一度自分なりにコードを書いてみました。


あーでもない、こーでもないとリファクタリングを繰り返したらこんなコードができあがりました。
オブジェクト指向と関数型プログラミングのエッセンスを混ぜ合わせたようなロジックです。


こんな書き方もあるよー、ということでコードを載せておきますね。

class CodeBreaker
  def initialize(secret)
    @secret = secret
  end
  
  def guess(answer)
    [@secret, answer].map(&method(:to_code_chars)).
      tap(&method(:exec_tests)).first.map(&:mark).sort.join
  end

  private

  def to_code_chars(code)
    code.to_s.chars.map {|char| CodeChar.new(char) }
  end

  def exec_tests((chars, other_chars))
    %w(zip + product -).each_slice(2) {|method_name, mark_char|
      chars.send(method_name, other_chars) {|char, other_char|
        char.test_match(other_char, mark_char) } }
  end

  class CodeChar
    attr_reader :char
    attr_accessor :mark

    def initialize(char)
      @char = char
      @mark = ''
    end

    def test_match(other, mark_char)
      mark_both(other, mark_char) if can_be_pair?(other)
    end

    def not_marked_yet?
      self.mark.empty?
    end

    private

    def can_be_pair?(other)
      same_char?(other) && [self, other].both?(&:not_marked_yet?)
    end

    def same_char?(other)
      self.char == other.char
    end

    def mark_both(other, mark_char)
      self.mark = other.mark = mark_char
    end
  end

  class ::Array
    alias_method :both?, :all?
  end
end


この問題は簡単すぎす、難しすぎず、ロジックを考えるのにちょうどいい問題です。
みなさんも是非トライしてみて下さい!