Agile2012 の記事まとめ

自分じゃかけないので、人のをまとめて紹介するという苦しい作戦。

Agile2012のサイト

Agile2012 :: Home

EMZERO

サマリ、すげー!!! 俺がまとめる必要一切ないんだけど、せっかくなので続ける。

Agile2012 まとめ | ManasLink ONLINE

インフィニティソリューションズ

http://www.infinity-solutions.jp/blog/2012/08/21/scaling-up-excellence/

会社のアジャイル推進を手伝って気づいたこと

XP祭り2012で A-2 アジャイルコーチ・ラウンドテーブル に参加することになりました。

私が何者か自分自身でも良く分からないのだから、参加される方はなおさらですよね。
なので、今までをふりかえりながら、気づいたことをまとめてみました。
※ 内容は突然変わる可能性があります。ごめんなさい。

あなたは何をしてるんですか?

  • 社内のアジャイル開発の推進に協力してます
    • いくつかプロジェクトの支援をしました
    • アジャイルの導入部分の教育の開催に協力しました
    • 親会社のガイド作成に協力しました
    • アジャイルに適した仕事をもらうための企画を考えてます
      • 価値創造契約とか、サービス型開発とかできると良いですけども…
  • 社内のコミュニティを立ち上げました
  • グループ会社のコミュニティのリーダです
    • 会社を行脚して、アジャイルに興味のある人とお話をしました

実は、官公庁の部署に所属しているんですが、そちらの仕事はしていません。
社外では、

  • AgileJapanの実行委員です
  • Shinagawa Redmineのスタッフです(かなり幽霊ですが)

のようなところに顔を出しています。
アジャイルマインド勉強会にはひじょーにお世話になったんですが、が、が。

界隈ではベンダが糾弾されることが多いのですが(今はそうでもない?)、すごい人たちだっているんだぞーってのを紹介できればなぁと思ってます。

官公庁の人がなぜ全社の活動やってるんですか?

社内のコミュニティを作ってあれこれ活動をしてたら、スタッフの人ともつながりができて、
そのつながりの延長上で推進活動に協力することになりました。

私の場合は、

  • 社内のコミュニティを作るときに、改善活動を推進している部署の人に相談してみた
  • 人に恵まれて( @ とか )コミュニティが活発になり、上記の部署の人が応援してくれた
  • もちょっと長くやってたら、上記の部署の人が、社長と対談を企画してくれた

みたいな感じでつながりができました。(あれ? こっちから企画の話を持っていったのかな??)

コネができた後は、ある意味芋づるみたいな感じです。
アジャイルって名前がつくからあいつらに相談してみよう」みたいな。

ただ、名前のほうが先に売れて、実力が追いつかない(現在進行形)ので困ってます。

会社で活動してみての気づきは?

目的は何でもいいので、続けてみることが大事と思います

私の場合は「アジャイルの話をする場所ができたらいいなー」でした。
そんな目的でも3年くらいやってると、何か見てくれる人もいるみたいです。

もともとアジャイルに興味をもったのも「わー、アジャイルやるとドキュメントいらないんだ」だったので、物凄く不純です。
が、人と運に恵まれて、更生しつつあります。(反動で原理派になることもありますが)

人が多いことが大企業の強みなので、上手くつながりを広げたほうが良さそうです

広げる方法は良く分かりません。とりあえず、相談には安請け合いしてました。

なんですが、一番の問題は、同じ興味を持っている人を探すのが大変なこと。
事業部の中でも難しいんですが、それを超えるとなるとかなり厳しいです。

私がやったことは

  • ノウフーのリストでアジャイルっぽいキーワードを使ってる人に絨毯爆撃する
  • コミュニティを作った後、来た相談には安請け合いする

くらいです。


後、「必死でわたふたしている」姿が母性本能をくすぐって、
手伝ってくれる人があらわれることがあります。そういうのを使うのも手だと思います。


後半はスタッフの方とつながりができたので、どの業務はどの部署がやってて、
あの辺だと誰に聞けば良いよ。というアドバイスがもらえて、とても助かりました。
(私の探し方が下手なだけか)
どこで何を誰がやっているのか良く分からなかったので、その辺を把握しているスタッフの人とつながったときはとても助かりました。

新しい技術、ツール、手法で、痛い経験をした人も多いです

痛い経験をしたら、警戒するのも当たり前なので、その辺は汲み取ってあげましょう。
相手も同じ人間です。
どうしようもない場合は、まぁ…。

策定したときの想いと現場の運用がずれてしまうことがあります

大きいゆえに、ひずみも大きくなるんだと思います。
元々の想いを調べてみると、目的は同じだったり、共感するところも多かったりします。

社内で広がっていくであろうアジャイルがそうならないよう、できることはあるのかなーと思ったりすることもあります。

動かないときはテコでも動きませんが、動き始めるといろんな所が一遍に動き始めます

わーすごいなぁ。とかのんびりしてると、置いてかれます…。
いつ動き始めるのかは私には良く分からなかったので、
とにかくできることはどんどん準備してた方が良いみたいです。

SIをやっているベンダの場合、「お客様の声」が何よりの推進力です

お客様に「アジャイルでお願い」といってもらうことができれば、
上司への説明や、関係部署への調整など、時間がかかる作業をスキップすることができます。
界隈で有名なとある方が実践したテクニックです。

SIよりも、製品(パッケージ)開発のほうが早いんじゃないのかなと思っていたんですが、
あちらはあちらでいろんなしがらみがあるらしく。

何でもいいので形に残したほうが良いみたいです

大きな会社じゃなくてもそうですが。
私はそれを怠ったので、こういう場で何やってるのか非常に説明しづらいです。
とりあえず、人とのつながりはできたけど…。みたいな寂しい話になります。

以下のような事に困りました
  • 目標が「話せる場」がほしいだったので、ある程度増えて話ができるようになったら、ひと段落してしまった
  • 知識を吸収するのが楽しくて、イロイロ顔を出したのは良いんだけども、途中で何がしたいのか良く分からなくなった
  • もともと仕事を抱え込むタイプだったので、グループ会社のコミュニティでやることが多くなった時に、パンクした
  • 目標?から減算して「足りないなぁ」と考えがちで、自分のモチベーションを自分で落とした(多分他人のも落としてると思う)
                  • -

とりあえず、ここまで。

  • 2012/08/27 「人が多いことが大企業の強み…」の説明を書き変え。困ったところを追記。

【19日目】 まっさらな状態から 90分で Windows に Redmine をインストール!

Redmine Advent Calendar jp 2011 : ATND の19日目です。
18日目は Redmineでのタスクの進捗報告について - いぬおせろ です。

えー、最初はテキストエリアを拡張する方法でも書こうかと
思っていたのですが、

  • ruby 入ってない
  • gem 入ってない

ってことをつぶやいたら cointoss1973 さんが、

天の助け!!

Windows7Redmine 1.3.0 を動かすまでの流れです。

ruby のインストール

http://www.garbagecollect.jp/ruby/mswin32/ja/download/release.html からダウンロード。

適当なフォルダに解凍しましょう。

gem のインストール

Download RubyGems | RubyGems.org | your community gem host からダウンロード。

やっぱり適当なフォルダに解凍します。
コマンドプロンプトを開いて、

set PATH=%PATH%;[rubyを解凍したフォルダ]\bin
cd [gemを解凍したフォルダ]
ruby setup.rb

zlib.dll のインストール

http://jarp.does.notwork.org/win32/zlib-1.1.4-1-mswin32.zip からダウンロード。
bin フォルダにある zlib.dll を [rubyを解凍したフォルダ]\bin にコピーします。

iconv.dll のインストール

http://www.garbagecollect.jp/ruby/mswin32/ja/documents/install.html にあるリンクからダウンロード。
lib フォルダにある iconv.dll を [rubyを解凍したフォルダ]\bin にコピーします。

libeay32.dll, ssleay32.dll のインストール

openssl-0.9.8e_WIN32.zip からダウンロード。
bin フォルダにある dll を [rubyを解凍したフォルダ]\bin にコピーします。

ここまできたら、あとは RedmineInstall - Redmine を見ながら進めればいいはず?

rails のインストール

gem install rails -v=2.3.14

rack のインストール

gem install rack -v=1.1.1

Redmine のインストール [New!!]

大事な大事な Redmine のインストールを忘れてました。 @ さんツッコミありがとうございます。

http://rubyforge.org/frs/?group_id=1850 からお好きなバージョンをダウンロード。
適当なフォルダに解凍しましょう。

データベースの設定

今回は sqlite3 を使います。
config/database.yml.example をコピーして config/database.yml を作成。

production:
  adapter: sqlite3
  database: db/production.sqlite3

development:
  adapter: sqlite3
  database: db/development.sqlite3

セッションストア秘密鍵の生成

rake generate_session_store

で、エラー!!!!

NOTE: Gem.source_index is deprecated, use Specification. It will be removed on o
r after 2011-11-01.
Gem.source_index called from D:/Development/redmine-1.3.0/config/../vendor/rails
/railties/lib/rails/gem_dependency.rb:21.
rake aborted!
uninitialized constant Gem::SyckDefaultKey

(See full trace by running task with --trace)

こ、これはキツイ。
もぞもぞググる先生とやっていると以下の記事が見つかりました。

Redmineをバージョンアップしようとしてrake db:migrateしたら、rake aborted! (uninitialized constant ActiveSupport::Dependencies::Mutex) - id:rx7(@namikawa)の技術メモ - 技術日記

これに違いない!

gem のダウングレード 1.8.12 -> 1.3.7

かなり落ちるんだなぁ。

gem install rubygems-update -v=1.3.7
update_rubygems

再度 セッションストア秘密鍵の生成

rake generate_session_store

成功。後25分!!

データベースのマイグレーション

rake db:migrate RAILS_ENV=production

失敗。 sqlite3 がないって…。

sqlite3-ruby のインストール

gem install sqlite3-ruby

再度、データベースのマイグレーション

rake db:migrate RAILS_ENV=production

成功!!
(ちなみに RAILS_ENV=production rake db:migrate だと失敗します。Windows だから?)

デフォルトデータのロード

rake redmine:load_default_data RAILS_ENV=production

言語を聞いてくるので、日本語 "ja" を入力します。

Redmine 起動!!

ruby script/server webrick -e production

localhost:3000 にアクセス

画面出ましたー!(タブの多さが混乱を如実に…)

というわけで、約90分による Redmine インストールでした。

次は @ さんです。よろしくお願いします!

【4日目】Redmine - チケットのフィルタに独自の項目を入れ込む方法

Redmine Advent Calendar jp 2011 : ATND 4日目です。

現行のRedmineだともっとスマートに書けるかもしれません。
良い実装をご存知のかた、ぜひ、教えてください :D

Hudson プラグインが入れ込んだもの

Hudson Plugin をインストールすると、チケットのフィルタに

  • Hudson(ジョブ名)
  • Hudson(ビルド番号)

という、見慣れない項目が登場します。これがそうですね。

フィルタを管理しているのはどこ?

Query クラスが親玉です。狙いどころは以下。

avalable_filters
フィルタで利用できる項目の一覧を返します。
sql_for_field
フィルタの項目に応じてSQL(WHERE句の条件)を作成します。

available_filters でジョブ番号とビルド番号を項目に追加して、
sql_for_field で追加した項目に応じたSQLを作成できるようにすれば良い訳です。

奥義! alias_method_chain!

時間がないのでいきなり奥義。

上記の Query#available_filters, Query#sql_for_field は新しい項目を追加できるように設計されていません。
また、Query クラスを入れ替えることもできないので、Queryクラスを継承してメソッドをオーバーライドする戦法も取れません。

手詰まり… orz

そこで登場するのが alias_method_chain です。

Query.class_eval do
  alias_method_chain :available_filters, :redmine_hudson
end

のように書いておくと(ここちょっと自信ない)、

  • available_filers を available_filters_with_redmine_hudson でオーバーライドする
  • 元のメソッドは available_filters_without_redmine_hudson で呼び出すことができる

ようになります。
これを使ってあれこれすれば、フィルタに項目を追加することができるのですが……。

時間がなくなったので今日はここまで。2回目があれば続きを!

redmine のテストを Cucumber と Selenium2.0 WebDriver を使って firefox と IE の2つのブラウザでやってみる

というわけで次は cucumber と組み合わせてみる。

構成

redmine <--> firefox <--> selenium <--> capybara <--> cucumber

になるのかな?

準備するもの

さっきの続きなので、追加したものだけ。

Selenium陣営

rails, cucumber-rails は雛形作りたいためだけのもの…。

Redmine陣営

特になし。

Capybara 使った cucuber の雛形を持ってくる

Railsアプリを準備
> rails new test-app
Gemfile に cucumber-rails, capybara を追加

group test に突っ込んだ。

group :test do
  # Pretty printed test output
  gem 'turn', :require => false
  gem 'cucumber-rails'
  gem 'capybara'
end
雛形を作る
> cd test-app
> ruby script/rails generate cucumber:install --capybara

雛形だけがほしかったので、
test-app\features にあるファイルとフォルダを、どこぞにコピーする。

+ using-cucumber
  + step_definitions
    + web_steps.rb
  + support
    + env.rb
    + paths.rb
    + selectors.rb

動くようにコードを改変

rails アプリの中で動かすならこれでいいのだけれど、
今回は外から rails のテストをするので、改変しないとエラーが出て動かない。
※ 多分ちゃんとやり方があるに違いない。

env.rb

# -*- encoding: utf-8 -*-
require "Capybara"
require "Capybara/cucumber"
require 'test/unit/assertions'
World(Test::Unit::Assertions)

Capybara.app_host = "http://127.0.0.1:3000"
Capybara.default_driver = :selenium
Capybara.javascript_driver = :selenium
Capybara.default_wait_time = 2
Capybara.add_selector(:name) do
  xpath { |name| XPath.descendant[XPath.attr(:name) == name.to_s] }
  match { |value| value.is_a?(Symbol) }
end
Capybara.add_selector(:class_name) do
  xpath { |class_name| XPath.descendant[XPath.attr(:class) == class_name.to_s] }
  match { |value| value.is_a?(Symbol) }
end

feature をもくもくと書く

web_steps.rb も成長させる
できあがった feature はこんな感じ。

redmine_walpurugis_night.feature

Feature: redmine_walpurgis_nights
  In order to extend life of universe
  As Incubator
  wants more energy.

  Scenario: Register new issue
    Given I go to toppage
    When  I follow "ログイン"
     And  I fill in "username" with "qb"
	 And  I fill in "password" with "homuhomu"
	 And  I press "login"
    
	When  I select "Walpurgis Night"
	 And  I follow "New issue"
	
	When  I select "Feature" from "issue_tracker_id"
     And  I fill in "issue_subject" with "As Incubator, I want magical girl."
	 And  I fill in "issue_description" with "foobaa"
	 And  I select "High" from "issue_priority_id"
	 And  I select "qb incubator" from "issue_assigned_to_id"
	 And  I press "commit"
	 
	When  I follow "Issues"
	Then  I should see following data at the head of issue list:
	  |tracker|status|priority|subject                           |assigned_to |
	  |Feature|New   |High    |As Incubator, I want magical girl.|qb incubator|
詰まったところ。
  • テーブルを見つけて、目的の値を取り出す(WebDriver と同じような操作で大丈夫だった)

初めての人がつまづきそうなところは、まとめたほうがいいかもなー。

残りの宿題

  • コードを github にあげる
  • akephalos を使ってみる
  • SeleniumIDE の formatter として cucumber(capybara) を作る
    • アル程度、定型にしちゃえば何とかできるじゃないのかな? と思ったり。これないと不便でしょうがない。

redmine のテストを Selenium2.0 WebDriver を使って firefox と IE の2つのブラウザでやってみる

概要

某ベンダ系アジャイルコミュニティの合宿で Selenium を使ったテストをやってみたので、
復習がてら Windows XP SP3上でタイトルのことをやってみたりする。

テストの内容
  • ログイン
  • チケット作成
  • チケット一覧で作成したチケットを確認
  • ログアウト

まで。

構成

redmine <--> firefox(IE) <--> selenium(webdriver) <--> test::unit
こんな感じ?
selenium と webdriver のところが怪しい。

なぜ Selenium(WebDriver) なの?

なんで WebDriver なの?という説明が Selenium 2.0 と WebDriver — Selenium 日本語ドキュメント にあった。

  • Mult-browser testing including improved functionality for browsers not well-supported by Selenium-1.0.
  • Handling multiple frames, multiple browser windows, popups, and alerts.
  • Page navigation.
  • Drag-and-drop.
  • AJAX-based UI elements.
  • 複数のブラウザを使ったテスト
  • ドラッグ&ドロップのテスト
  • AJAX 使ったところのテスト
  • 複数のフレーム、ウィンドウ、ポップアップ、アラートのテスト
  • Page navigation.(ってふつーにできそうだけど何かあるのかな?)

準備物

Redmine 陣営

各自、適当にインストールする。
selenium-webdriver と cucumber を 1.8.7 に同居させられなかったので Selenium 陣営は 1.9.2 を選択…。

プロジェクト "Walpurgis Night" と ユーザ "qb" をあらかじめ作っておく。
諸般の事情により、とりあえず英語。

操作を記録して、Test::Unit ファイルに吐き出す

firefox -> ツール -> Selenium IDE を選択。
以下の操作を行う。赤い●のボタンを押すと記録開始、も一回押すと記録終了。

  • ログイン
  • チケット作成
  • チケット一覧を表示
  • ログアウト
記録した操作を実行して動くか確かめる

メニュー -> アクション -> 現在のテストケースを実行。

念のため、記録した操作を保存する

メニュー -> テストケースを保存。

記録した操作を Test::Unit に吐き出す

これは便利だなぁ!
メニュー -> テストケースをエクスポート -> Ruby Test::Unit(WebDriver)
ここで、 テストスイート にしちゃうとエラーが出るので注意。

Test::Unit を使って保存した操作を再現する

1.9のおまじないと、rubygems をインポートする
# -*- encoding: utf-8 -*-
require "rubygems"
タイムアウト?の時間を2秒にする
  @driver.manage.timeouts.implicit_wait = 2
URLを変更する(何のためって言えばいいのだろう)
  @driver.get "http://127.0.0.1:3000"
Option を選択するところは自動出力してくれないので自力で書く

select - How do I set a an option as selected using selenium-webdriver (selenium 2.0) client in ruby - Stack Overflow を参考に。
メソッドに抜き出しておいてもよさそう。

実行する

無事チケットができてたらOK

ruby \path\to\testcase.rb

結果を検証する

ちゃんと希望通りの内容になっているのか検証をする。
手抜きをして、

  • チケット一覧で目的のタイトルのチケットがあること
    • 該当するチケットのトラッカー、優先度、担当者が期待通りであること
    • チケット番号は動的に変わってしまうからチェックなし

のみ検証してみる。

検証するために必要な操作
  • チケット一覧(テーブル)を見つける
  • 見つけたテーブルの一番上にあるデータを取り出す
  • タイトル、トラッカー、優先度、担当者の値を取り出し、チェックする

ができないといけない。ふぅ。
ここで Web Developer の出番な訳ですよ!

Web Driver を使って要素の情報を取り出す

使い方は(後で書くかも)
情報 -> 要素の情報を表示する が使えると思う。

テーブルを見つけて値を取り出し、検証する

チケット一覧テーブルの一番上にある行を取り出せば良い感じ。
トラッカーの内容が Feature であることを確認するにはこんな感じ。

  @driver.find_element(:xpath, "//table[@class='list issues']/tbody/tr[1]")
  assert_equal "Feature", latest_issue.find_element(:class, "tracker").text, "tracker"
実行して確かめる
> ruby \path\to\testcase.rb
Loaded suite Redmine-WalpurgisNight
Started
.
Finished in 16.453125 seconds.

1 tests, 6 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 31656

できた!!

firefox だけじゃなくって IE でも動かしてみる

これができてこそ。setup の最初の行をちょいちょいと書き換える

@driver = Selenium::WebDriver.for :ie

ログインする時にパスワードをうんぬんのダイアログが出て最初は失敗したけど、
2回目は成功。
すげーすげー。

でも、いちいちここ切り替えるの面倒。
上手い指定の方法が思いつかないので、環境変数使うことにする。
上手く切り替わったゾ!

ここまでのコード

今度は Cucumber と組み合わせてできるかやってみよう。

# -*- encoding: utf-8 -*-
require "rubygems"
require "selenium-webdriver"
require "test/unit"

class RedmineWalpurgisNight < Test::Unit::TestCase

  def setup
    raise "Please set environment variable 'WEBDRIVER_TYPE' (ex. firefox, ie)" unless ENV["webdriver_type"]
    @driver = Selenium::WebDriver.for ENV["webdriver_type"].to_sym
    @driver.manage.timeouts.implicit_wait = 2
    @verification_errors = []
  end
  
  def teardown
    return unless @driver
    @driver.quit
    assert_equal [], @verification_errors
  end
  
  def test_redmine_walpurgis_night
    @driver.get "http://127.0.0.1:3000"
    @driver.find_element(:link, "ログイン").click
    @driver.find_element(:id, "username").clear
    @driver.find_element(:id, "username").send_keys "qb"
    @driver.find_element(:id, "password").clear
    @driver.find_element(:id, "password").send_keys "homuhomu"
    @driver.find_element(:name, "login").click
	select_option @driver.find_element(:css,'select'), "Walpurgis Night"
    @driver.find_element(:link, "New issue").click
	select_option @driver.find_element(:id,'issue_tracker_id'), "Feature"
    @driver.find_element(:id, "issue_subject").clear
    @driver.find_element(:id, "issue_subject").send_keys "As Incubator, I want magical girl."
    @driver.find_element(:id, "issue_description").clear
    @driver.find_element(:id, "issue_description").send_keys "foobaa"
	select_option @driver.find_element(:id,'issue_priority_id'), "High"
	select_option @driver.find_element(:id,'issue_assigned_to_id'), "qb incubator"
    @driver.find_element(:name, "commit").click
    @driver.find_element(:link, "Issues").click

	latest_issue = @driver.find_element(:xpath, "//table[@class='list issues']/tbody/tr[1]")
	assert_equal "Feature", latest_issue.find_element(:class, "tracker").text, "tracker"
	assert_equal "New", latest_issue.find_element(:class, "status").text, "status"
	assert_equal "High", latest_issue.find_element(:class, "priority").text, "priority"
	assert_equal "As Incubator, I want magical girl.", latest_issue.find_element(:class, "subject").text, "subject"
	assert_equal "qb incubator", latest_issue.find_element(:class, "assigned_to").text, "assignee"
	
    @driver.find_element(:link, "Sign out").click
  end
  
  def element_present?(how, what)
    @driver.find_element(how, what)
    true
  rescue Selenium::WebDriver::Error::NoSuchElementError
    false
  end
  
  def select_option(my_select, option_text)
	my_select.find_elements( :tag_name => "option" ).find do |option|
      option.text == option_text
    end.click
  end
  
  def verify(&blk)
    yield
  rescue Test::Unit::AssertionFailedError => ex
    @verification_errors << ex
  end
end