Scrum Gathering Tokyo 2011 Day2 (#sgt2011) に参加してきた

Scrum Gathering Tokyo 2011 Day 2 に参加してきた。

スタッフの皆様、参加者の皆様、お疲れさまでした!ありがとうございました!
すごく楽しく色々と気づきがあり、充実した1日でした!

今回は以下に参加した。

スクラムアジャイルは書籍で勉強した程度で実践ゼロ状態なので、初心者向けワークショップを選んだ。

内容は他の方がまとめられているので、

自分が感じたことやきづいたことをとりとめもなくつらつらと書いてみる。

スクラムの心

  • アジャイルで語られる文脈はアジャイルだけのものではない
    • PMBOKで扱っているものも多い
  • アジャイルは特別なものではなく普通にいい組織の状態
  • アジャイルはゴールではなくツール、名詞ではなく形容詞、アジャイルにやるのではなく「アジャイルにやる」を意識する
  • 「自分の行動で環境が変化しなくなると無気力になる」あるあるすぎる
  • 目的が分かっているかの質問として、石切のたとえは非常にいい、わかりやすい、ためしてみたい
  • みんなコミュニケーションへの問題意識が強い模様
  • チームのヨコのコミュニケーションがよくなるとチームが活性化するような気がする
  • やっぱり楽しく仕事したい
  • IT屋さん?は仕事に情熱を燃やす人は少ないのかな?
    • システムが対象とする部分に興味/関心が少ない?
  • WBS思考でやっていたチームをどうやって自己組織的チームにするか
    • 自分でタスクを決められない人もいる
    • そういうメンバに対しても対応しなければならない

ユーザーストーリー:ファーストジェネレーション

  • ユーザストーリにどんなことを書けばいいかなんとなくわかった
  • 3幕構成は役に立ちそう
    • 設定と結末は変わりにくいので固めておくと良いとのこと
  • 完了条件(Test内容)を一緒に実例で書くといい
  • 物語がありません問題はタイプを見極める
  • リーンとパターンで解決できる対象は異なる(リーン:Complicated/かたいもの, パターン:Complex/やわらかいもの)

個人的に少々消化不良気味。
スライドも公開されたので復習しよう。

スクラムプロジェクト逆計画ゲーム

  • プロジェクトの全てのコストをプロダクト作成にかけているわけではない
    • 問題や障害を取り除くのに当然ながらコストがいる
    • 準備にも当然コストはかかる
    • プロジェクトが始まる前にこれらを推し量れるのか
      • リスク係数っぽいものをかけるとかをよくやる?
      • やってみてからコストも期間も足りませんのでくださいっていうわけにもいかんよな
  • POのコストの払い出しの判断が難しい
    • プロジェクトを期限までに終わらせるには、払わざるを得ない状況?
  • 実際の現場では問題や障害を取り除くアクションをだせて実行出来るか?ふりかえりで議論する?
  • POからメンバへのフィードバックが少なかった
    • 進捗やコストの状況説明などがあってもよかったかも
    • POの役割を理解出来ていない
  • プロジェクトダッシュボードがとてもわかりやすい

まとめ

  • スクラム入門の第一歩は踏み込めた
  • チームを変える、意識を変えるってことは継続して自分でアクションを起こしていかなければならない
  • そのためにスクラムを使っていきたいと感じた
  • スクラムアジャイルをチームのみんなに知ってもらいたいので、とりあえずアジャイルサムライを職場に持っていく、同志を見つける
  • すくすくスクラムに参加してみたい、もっとスクラムを知りたい

初めてPull Requestをマージしてみた

ずいぶん前に redmine_importer プラグインを github でフォークしてごにょごにょしてたところに Pull Request がきた。
しかもRedmine本の著者の前田さんだー!すごい人から Pull Request がきて緊張するw

入門Redmine 第2版 Linux/Windows対応

入門Redmine 第2版 Linux/Windows対応

で、はじめて Pull Request をマージしてみた。

A-Liaison BLOG: github で pull request をされたとき・するときの手順 などを参考にしつつやってみる。
まずは、Pull Request を受け取るブランチを作る。

$ git checkout -b pull_request_i18n_fix_for_redmine_1.2

で、github からの pull request 通知メールに書かれていたコマンドを実行してみた。

$ git pull https://github.com/farend/redmine_importer i18n_fix_for_redmine_1.2
remote: Counting objects: 23, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 12 (delta 7), reused 12 (delta 7)
Unpacking objects: 100% (12/12), done.
From https://github.com/farend/redmine_importer
 * branch            i18n_fix_for_redmine_1.2 -> FETCH_HEAD
Updating 94216f7..cc694e5
Fast-forward
 app/views/importer/match.html.erb  |    2 +-
 app/views/importer/result.html.erb |    6 +++---
 config/locales/en.yml              |   10 +++++-----
 config/locales/ja.yml              |   10 +++++-----
 config/locales/zh.yml              |    6 +++---
 5 files changed, 17 insertions(+), 17 deletions(-)

マージされたのかな?logを見てみる。

$ git log -n 1
commit cc694e5558f05cf6be736d2f9c8231478adceb2e
Author: MAEDA Go
Date:   Wed Oct 5 09:43:48 2011 +0900

    fix for Redmine 1.2: removed deprecated "%d" and "%s" format strings.

おー、マージされてる!きちんと修正されて、動作するのも確認した。感謝!
で、Pull したコードを master にマージする。

$ git checkout master
Switched to branch 'master'
$ git merge pull_request_i18n_fix_for_redmine_1.2
Updating 94216f7..cc694e5
Fast-forward
 app/views/importer/match.html.erb  |    2 +-
 app/views/importer/result.html.erb |    6 +++---
 config/locales/en.yml              |   10 +++++-----
 config/locales/ja.yml              |   10 +++++-----
 config/locales/zh.yml              |    6 +++---
 5 files changed, 17 insertions(+), 17 deletions(-)

そのまま、github へ push!

$ git push origin master
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:daicham/redmine_importer.git
   94216f7..cc694e5  master -> master

まとめ

  • Pull Request きたらどうすればいいかわかった
    • といっても、普通に Pull するだけだった
  • マージ用のブランチ作成はしたほうがいい、トピックブランチのように扱えばいい
  • Pull Request くるとなぜかうれしい感じがする
  • せっかくだから、wikiにプラグインの説明書こう

Heroku で Play! をためしてみる

今回は Heroku で Play! を動かすところまでやってみる。

以下を参考にやってみる。以下は scala でためしてるけど今回は素(?)でやる。

Play! のインストール

適当な場所に解凍すればよいみたい。それと play コマンドにパスを通す。
最新版の 1.2.3 を使用した。

$ wget http://download.playframework.org/releases/play-1.2.3.zip
$ unzip play-1.2.3.zip && mv play-1.2.3 ~/Library/Java/
$ sudo ln -s ~/Library/Java/play-1.2.3/play /usr/local/bin/play
$ play
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.3, http://www.playframework.org
~
~ Usage: play cmd [app_path] [--options]
~ 
~ with,  new      Create a new application
~        run      Run the application in the current shell
~        help     Show play help
~

起動確認OK。

Play! プロジェクトの作成

以下のコマンドで作成。ラクチン。

$ play new heroku_play
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.3, http://www.playframework.org
~
~ The new application will be created in /users/daicham/Work/heroku_play
~ What is the application name? [heroku_play] 
~
~ OK, the application is created.
~ Start it with : play run heroku_play
~ Have fun!
~

以下のようなファイルが生成された。Rails そっくり。

$ tree -a heroku_play/ 
heroku_play/
├── app
│   ├── controllers
│   │   └── Application.java
│   ├── models
│   └── views
│       ├── Application
│       │   └── index.html
│       ├── errors
│       │   ├── 404.html
│       │   └── 500.html
│       └── main.html
├── conf
│   ├── application.conf
│   ├── dependencies.yml
│   ├── messages
│   └── routes
├── lib
├── public
│   ├── images
│   │   └── favicon.png
│   ├── javascripts
│   │   └── jquery-1.5.2.min.js
│   └── stylesheets
│       └── main.css
└── test
    ├── Application.test.html
    ├── ApplicationTest.java
    ├── BasicTest.java
    └── data.yml

Play! を動かしてみる

そのまま Play! を起動してみる。

$ cd heroku_play
$ play run
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.3, http://www.playframework.org
~
~ Ctrl+C to stop
~ 
Listening for transport dt_socket at address: 8000
18:15:29,026 INFO  ~ Starting /heroku_play
18:15:29,962 WARN  ~ You're running Play! in DEV mode
18:15:30,109 INFO  ~ Listening for HTTP on port 9000 (Waiting a first request to start) ...
Debugger failed to attach: handshake failed - connection prematurally closed
18:16:08,016 INFO  ~ Application 'heroku_play' is now started !
Debugger failed to attach: handshake failed - connection prematurally closed

http://localhost:9090 にアクセスしてWelcomeページが表示されたのを確認。
どうやらデフォルトは開発モード(DEV mode)らしい。このへんも Rails に似てる。
んー、Debugger failed とでているがよくわからなかったので今回はスルーする。

heroku へデプロイ

これまでどおり、Git にコミットして、heroku の cedar を作成して push する。
.gitignore には以下を追加した。Play!のチュートリアルに書いてあった。

/tmp
/modules
/lib
/test-result
/logs

で、 heroku open で確認してみると、"Your application is ready!" とだけ表示された。ウェルカムページがでないなぁ。
heroku logs でログを確認。すると以下のように起動しているっぽい。

Starting process with command `play run --http.port=49805 --%prod -Dprecompiled=true`

"--%prod" はproduction環境を意味しているのか。そういえば Procfile 作ってないけど動いてるなぁ。まぁいいか。
ローカルでもこのオプションをつけて起動してたら同じメッセージになった。
手順がまずかったわけではないのね。とりあえずそういう挙動をするということにしておく。

まとめ

  • Play! はインストールもプロジェクト作成も実行も簡単。イイカンジ。
  • heroku へのデプロイはもういい加減なれてきた。

というわけで、ためすほどの内容ではなかったけど一応 heroku で動いた。
Play! 楽しそうなので今度は Play! のチュートリアルをやってみるかな。

    • -

追記
Getting Started with Play! on Heroku | Heroku Dev Center によると Procfile は準備するように書いてあるのでホントはあったほうがよさそう。

Getting Started with Spring MVC Hibernate on Heroku/Cedar をためしてみてる

昨日に引き続きjavaでherokuと戯れてみる。
今回は Getting Started with Spring MVC Hibernate on Heroku | Heroku Dev Center をやってみる。

Prerequisites

java,maven.git,heroku client, foreman が必要とのこと。これらは昨日のエントリでいれたのでOK。
あと、ローカルでのテストのためにPostgresが必要とのこと。このあたりを参考にした。

$ sudo port install postgresql90
$ sudo port install postgresql90-server

9/12に9.1がリリースされてるが、MacPortsだとまだALPHA RELEASEっぽいので9.0にした。
データ領域を作成。

$ sudo mkdir -p /opt/local/var/db/postgresql90/defaultdb
$ sudo chown postgres:postgres /opt/local/var/db/postgresql90/defaultdb
$ sudo su postgres -c '/opt/local/lib/postgresql90/bin/initdb -D /opt/local/var/db/postgresql90/defaultdb'

で、起動。

$ sudo su postgres -c '/opt/local/lib/postgresql90/bin/postgres -D /opt/local/var/db/postgresql90/defaultdb'

Create a Spring MVC Hibernate app

Spring MVC Hivernate アプリは Spring Roo を使うととても簡単につくれるよ!
っぽいことが書かれている。SpringもHibernateもきちんとさわったことないので Option2 でいくことにする。
ちなみに Option1 はサンプルコードを git clone せよとのこと。

Option 2. Create the App Using Spring Roo

Spring Roo をインストールせよ。とのことなのでインストールしてみる。
Community Downloads | SpringSource.orgにLastest GA release 1.1.5.RELEASE というのがあるのでこれをDL。
このあたりをみると解凍して bin/roo.sh をPATHに追加すればいいっぽい。
今回は bin/roo.sh のシンボリックリンクを /usr/local/bin においてみた。

$ sudo ln -s ~/Library/Java/spring-roo-1.1.5.RELEASE/bin/roo.sh /usr/local/bin/roo

roo を実行するとこんなかんじ。rooのプロンプトが現れる。exitで抜けられる。

$ roo
    ____  ____  ____  
   / __ \/ __ \/ __ \ 
  / /_/ / / / / / / / 
 / _, _/ /_/ / /_/ /  
/_/ |_|\____/\____/    1.1.5.RELEASE [rev d3a68c3]


Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
                                                                        
At this time you have not authorized Spring Roo to download an index of
available add-ons. This will reduce Spring Roo features available to you.
Please type 'download status' and press ENTER for further information.

roo>

さて、roo がインストールできたところでアプリケーションを作成していく。
まず、今回のアプリは petclinic らしいのでアプリのディレクトリを作成する。

$ mkdir petclinic && cd petclinic

で、roo でアプリを生成せよとのこと。以下を実行。

$ roo script --file clinic.roo

大量のログとともにアプリのファイルを生成してるっぽい。
実行後のディレクトリ構造はこんな感じ。

$ tree -a
.
├── log.roo
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── springsource
    │   │           └── petclinic
    │   │               ├── domain
    │   │               │   ├── AbstractPerson.java
    │   │               │   ├── AbstractPerson_Roo_Configurable.aj
    │   │               │   ├── AbstractPerson_Roo_Entity.aj
    │   │               │   ├── AbstractPerson_Roo_JavaBean.aj
    │   │               │   ├── AbstractPerson_Roo_ToString.aj
    │   │               │   ├── Owner.java
    │   │               │   ├── Owner_Roo_Configurable.aj
    │   │               │   ├── Owner_Roo_Entity.aj
    │   │               │   ├── Owner_Roo_JavaBean.aj
    │   │               │   ├── Owner_Roo_ToString.aj
    │   │               │   ├── Pet.java
    │   │               │   ├── Pet_Roo_Configurable.aj
    │   │               │   ├── Pet_Roo_Entity.aj
    │   │               │   ├── Pet_Roo_Finder.aj
    │   │               │   ├── Pet_Roo_JavaBean.aj
    │   │               │   ├── Pet_Roo_ToString.aj
    │   │               │   ├── Vet.java
    │   │               │   ├── Vet_Roo_Configurable.aj
    │   │               │   ├── Vet_Roo_Entity.aj
    │   │               │   ├── Vet_Roo_JavaBean.aj
    │   │               │   ├── Vet_Roo_ToString.aj
    │   │               │   ├── Visit.java
    │   │               │   ├── Visit_Roo_Configurable.aj
    │   │               │   ├── Visit_Roo_Entity.aj
    │   │               │   ├── Visit_Roo_Finder.aj
    │   │               │   ├── Visit_Roo_JavaBean.aj
    │   │               │   └── Visit_Roo_ToString.aj
    │   │               ├── reference
    │   │               │   ├── PetType.java
    │   │               │   └── Specialty.java
    │   │               └── web
    │   │                   ├── ApplicationConversionServiceFactoryBean.java
    │   │                   ├── ApplicationConversionServiceFactoryBean_Roo_ConversionService.aj
    │   │                   ├── OwnerController.java
    │   │                   ├── OwnerController_Roo_Controller.aj
    │   │                   ├── PetController.java
    │   │                   ├── PetController_Roo_Controller.aj
    │   │                   ├── PetController_Roo_Controller_Finder.aj
    │   │                   ├── VetController.java
    │   │                   ├── VetController_Roo_Controller.aj
    │   │                   ├── VisitController.java
    │   │                   ├── VisitController_Roo_Controller.aj
    │   │                   └── VisitController_Roo_Controller_Finder.aj
    │   ├── resources
    │   │   ├── META-INF
    │   │   │   ├── persistence.xml
    │   │   │   └── spring
    │   │   │       ├── applicationContext.xml
    │   │   │       └── database.properties
    │   │   └── log4j.properties
    │   └── webapp
    │       ├── WEB-INF
    │       │   ├── classes
    │       │   │   ├── alt.properties
    │       │   │   └── standard.properties
    │       │   ├── i18n
    │       │   │   ├── application.properties
    │       │   │   ├── messages.properties
    │       │   │   ├── messages_de.properties
    │       │   │   └── messages_es.properties
    │       │   ├── layouts
    │       │   │   ├── default.jspx
    │       │   │   └── layouts.xml
    │       │   ├── spring
    │       │   │   └── webmvc-config.xml
    │       │   ├── tags
    │       │   │   ├── form
    │       │   │   │   ├── create.tagx
    │       │   │   │   ├── dependency.tagx
    │       │   │   │   ├── fields
    │       │   │   │   │   ├── checkbox.tagx
    │       │   │   │   │   ├── column.tagx
    │       │   │   │   │   ├── datetime.tagx
    │       │   │   │   │   ├── display.tagx
    │       │   │   │   │   ├── editor.tagx
    │       │   │   │   │   ├── input.tagx
    │       │   │   │   │   ├── reference.tagx
    │       │   │   │   │   ├── select.tagx
    │       │   │   │   │   ├── simple.tagx
    │       │   │   │   │   ├── table.tagx
    │       │   │   │   │   └── textarea.tagx
    │       │   │   │   ├── find.tagx
    │       │   │   │   ├── list.tagx
    │       │   │   │   ├── show.tagx
    │       │   │   │   └── update.tagx
    │       │   │   ├── menu
    │       │   │   │   ├── category.tagx
    │       │   │   │   ├── item.tagx
    │       │   │   │   └── menu.tagx
    │       │   │   └── util
    │       │   │       ├── language.tagx
    │       │   │       ├── load-scripts.tagx
    │       │   │       ├── pagination.tagx
    │       │   │       ├── panel.tagx
    │       │   │       ├── placeholder.tagx
    │       │   │       └── theme.tagx
    │       │   ├── views
    │       │   │   ├── dataAccessFailure.jspx
    │       │   │   ├── footer.jspx
    │       │   │   ├── header.jspx
    │       │   │   ├── index-template.jspx
    │       │   │   ├── index.jspx
    │       │   │   ├── menu.jspx
    │       │   │   ├── owners
    │       │   │   │   ├── create.jspx
    │       │   │   │   ├── list.jspx
    │       │   │   │   ├── show.jspx
    │       │   │   │   ├── update.jspx
    │       │   │   │   └── views.xml
    │       │   │   ├── pets
    │       │   │   │   ├── create.jspx
    │       │   │   │   ├── findPetsByNameAndWeight.jspx
    │       │   │   │   ├── findPetsByOwner.jspx
    │       │   │   │   ├── findPetsBySendRemindersAndWeightLessThan.jspx
    │       │   │   │   ├── findPetsByTypeAndNameLike.jspx
    │       │   │   │   ├── list.jspx
    │       │   │   │   ├── show.jspx
    │       │   │   │   ├── update.jspx
    │       │   │   │   └── views.xml
    │       │   │   ├── resourceNotFound.jspx
    │       │   │   ├── uncaughtException.jspx
    │       │   │   ├── vets
    │       │   │   │   ├── create.jspx
    │       │   │   │   ├── list.jspx
    │       │   │   │   ├── show.jspx
    │       │   │   │   ├── update.jspx
    │       │   │   │   └── views.xml
    │       │   │   ├── views.xml
    │       │   │   └── visits
    │       │   │       ├── create.jspx
    │       │   │       ├── findVisitsByDescriptionAndVisitDate.jspx
    │       │   │       ├── findVisitsByDescriptionLike.jspx
    │       │   │       ├── findVisitsByVisitDateBetween.jspx
    │       │   │       ├── list.jspx
    │       │   │       ├── show.jspx
    │       │   │       ├── update.jspx
    │       │   │       └── views.xml
    │       │   └── web.xml
    │       ├── images
    │       │   ├── add.png
    │       │   ├── banner-graphic.png
    │       │   ├── create.png
    │       │   ├── de.png
    │       │   ├── delete.png
    │       │   ├── en.png
    │       │   ├── es.png
    │       │   ├── favicon.ico
    │       │   ├── list.png
    │       │   ├── resultset_first.png
    │       │   ├── resultset_last.png
    │       │   ├── resultset_next.png
    │       │   ├── resultset_previous.png
    │       │   ├── show.png
    │       │   ├── springsource-logo.png
    │       │   └── update.png
    │       ├── selenium
    │       │   ├── test-owner.xhtml
    │       │   ├── test-pet.xhtml
    │       │   ├── test-suite.xhtml
    │       │   ├── test-vet.xhtml
    │       │   └── test-visit.xhtml
    │       └── styles
    │           ├── alt.css
    │           └── standard.css
    └── test
        ├── java
        │   └── com
        │       └── springsource
        │           └── petclinic
        │               └── domain
        │                   ├── OwnerDataOnDemand.java
        │                   ├── OwnerDataOnDemand_Roo_Configurable.aj
        │                   ├── OwnerDataOnDemand_Roo_DataOnDemand.aj
        │                   ├── OwnerIntegrationTest.java
        │                   ├── OwnerIntegrationTest_Roo_Configurable.aj
        │                   ├── OwnerIntegrationTest_Roo_IntegrationTest.aj
        │                   ├── PetDataOnDemand.java
        │                   ├── PetDataOnDemand_Roo_Configurable.aj
        │                   ├── PetDataOnDemand_Roo_DataOnDemand.aj
        │                   ├── PetIntegrationTest.java
        │                   ├── PetIntegrationTest_Roo_Configurable.aj
        │                   ├── PetIntegrationTest_Roo_IntegrationTest.aj
        │                   ├── VetDataOnDemand.java
        │                   ├── VetDataOnDemand_Roo_Configurable.aj
        │                   ├── VetDataOnDemand_Roo_DataOnDemand.aj
        │                   ├── VetIntegrationTest.java
        │                   ├── VetIntegrationTest_Roo_Configurable.aj
        │                   ├── VetIntegrationTest_Roo_IntegrationTest.aj
        │                   ├── VisitDataOnDemand.java
        │                   ├── VisitDataOnDemand_Roo_Configurable.aj
        │                   ├── VisitDataOnDemand_Roo_DataOnDemand.aj
        │                   ├── VisitIntegrationTest.java
        │                   ├── VisitIntegrationTest_Roo_Configurable.aj
        │                   └── VisitIntegrationTest_Roo_IntegrationTest.aj
        └── resources

かなりのファイル数があるな・・・でもpom.xmlがあったりmavenのディレクトリ構造と同じだったりするのでなんとなくわかるな。

デフォルトのDBがHypersonicのインメモリDBらしい。production環境と同じDB使うほうが絶対いいよといっているっぽいので postgres にスイッチする。

$ roo persistence setup --provider HIBERNATE --database POSTGRES
    ____  ____  ____  
   / __ \/ __ \/ __ \ 
  / /_/ / / / / / / / 
 / _, _/ /_/ / /_/ /  
/_/ |_|\____/\____/    1.1.5.RELEASE [rev d3a68c3]


Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
Updated SRC_MAIN_RESOURCES/META-INF/spring/database.properties
Please update your database details in src/main/resources/META-INF/spring/database.properties.
Updated ROOT/pom.xml [removed dependency org.hsqldb:hsqldb:1.8.0.10; added dependency postgresql:postgresql:8.4-702.jdbc3]
Updated SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Updated SRC_MAIN_RESOURCES/META-INF/persistence.xml
                                                                        
At this time you have not authorized Spring Roo to download an index of
available add-ons. This will reduce Spring Roo features available to you.
Please type 'download status' and press ENTER for further information.

ちょっと脱線だが、最後の3行はよく見かけるので言われるとおり download status を実行し、指示に従い了承っぽいことをした。どうやらリソースをダウンロードするには必要なようだ。

で、roo で生成したファイルを git にコミットする。

$ git init
$ echo target > .gitignore
$ git add .
$ git commit -m "init"

Modify Database Configuration

roo で生成したファイルにはDBへの接続情報が書かれているが、ハードコードされているらしい。(ここらしい→ src/main/resources/META-INF/spring/database.properties)
ハードコードはイクナイので環境変数から読み込むようにしよう。っぽいことが書かれている。
環境変数名は"DATABASE_URL"の模様。で、この変数のフォーマットはこんなかんじ。

postgres://user:password@hostname/path

で、そのために src/main/resources/META-INF/spring/applicationContext.xml を編集する。以下の bean 定義を追加と、

<bean class="java.net.URI" id="dbUrl">
    <constructor-arg value="${DATABASE_URL}"/>
</bean>

以下のように id="dataSource" 要素内の property 定義を書き換える。

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="url" value="#{ 'jdbc:postgresql://' + @dbUrl.getHost() + @dbUrl.getPath() }"/>
    <property name="username" value="#{ @dbUrl.getUserInfo().split(':')[0] }"/>
    <property name="password" value="#{ @dbUrl.getUserInfo().split(':')[1] }"/>
    ...

で、実行するために環境変数"DATABASE_URL"がいるので定義する。

export DATABASE_URL=postgres://scott:tiger@localhost/myapp

Add Jetty Runner

Jettyで実行するために、Jetty-runner のライブラリを target ディレクトリに置く必要があるっぽい。
それを実現するために、maven-dependency-plugin を使う模様。
以下を pom.xml 内の plugins セクションの最後に追加する。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>copy</goal></goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>org.mortbay.jetty</groupId>
                        <artifactId>jetty-runner</artifactId>
                        <version>7.4.5.v20110725</version>
                        <destFileName>jetty-runner.jar</destFileName>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

Declare Process Types With Foreman/Procfile

昨日のエントリとほぼ同じ。Procfileを用意する。
が、違うところは jetty-runner で war ファイルを渡しているところか。これで webアプリを jetty 上で動かせるということか。

web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war

Run Your App Locally

Build Your App

では、ビルドしてみよう。

$ mvn package

んー、ビルドでエラーがでるな。どうやらテストでエラーな模様。Postgresの標準出力に以下のようなログが多数。

FATAL: role "scott" does not exist

Postgres のユーザとか一切作ってないからっぽい。postgres が起動している状態で以下を行った。

$ /opt/local/lib/postgres90/bin/psql -U postgres
postgres=# create user scott;
postgres=# \password scott
Enter new password: 
Enter it again: 
postgres=# \q

もっかい動かしてみると以下のログに変わった。

FATAL: database "myapp" does not exist

どうやら、databaseをつくっていないからっぽい。で、以下を行った。

$ /opt/local/lib/postgresql90/bin/createdb -U postgres myapp

で、もっかい mvn package やったらテスト通った!ビルド成功!

Start Your App With Foreman/Procfile

起動してみる。

$ foreman start

で、 http://localhost:5000 へアクセス。おー、Rooの画面が表示された!

Test it

画面からデータも登録できたっぽい。いいかんじ。

Deploy to Heroku/Cedar

さぁ、herokuへデプロイ。
まず、これまでの変更をコミット。

$ git add .
$ git commit -m "Ready to deploy"

herokuのCedarスタックも作成する。

$ heroku create --stack cedar

heroku へデプロイ!

$ git push heroku master

ビルドも成功!

$ heroku open

で、画面も確認できたしデータも登録できた!

まとめ

  • 久しぶりに postgres さわったので思い出すのにたいへんだった。かなり時間かかったな・・・
  • roo はよくわからん。おぼえるのたいへんそうかも。。。
  • アプリの起動は java コマンドを起動できればなんでもいいみたい。前みたいに組み込みでなくてもいいのね。
  • そういえば hibernate はほとんどみかけなかったな・・。DBのスキーマ作成とかはいいかんじでやってくれてるのだろうか?rails でいう db:migrate 的なこともしてないのになぁ。

と、本題とは関係ないところでえらくはまってしまった。
今度は addons あたりを調べてみようか。

Getting Started with Java on Heroku/Cedar をためしてみる

先日HerokuでJavaが対応されたのと、さっそくためしてみてるブログに触発されたので実際にやってみる。

とりあえず、Getting Started with Java on Heroku | Heroku Dev Centerをやってみる。
環境はMBA(SnowLeopard)。

Prerequisites

mavenとOpenJDK6とHerokuアカウントが必要な模様。

OpenJDK6

はじめから入っているのはJDK6(Apple)のはず。

$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03-384-10M3425)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02-384, mixed mode)

なので、OpenJDKをMacPortsでインストール。

$ sudo port install openjdk6

1時間くらいかかったような・・・
で、バージョンを確認してみた。

$ /opt/local/share/java/openjdk6/bin/java -version
openjdk version "1.6.0"
OpenJDK Runtime Environment (build 1.6.0-b20)
OpenJDK 64-Bit Server VM (build 17.0-b16, mixed mode)

OK。PATHとJAVA_HOMEを設定しておく。

Maven

インストールした覚えがないので、はじめからはいってたっぽい。

$ mvn -v
Apache Maven 3.0.3 (r1075438; 2011-03-01 02:31:09+0900)
Maven home: /usr/share/maven
Java version: 1.6.0, vendor: Sun Microsystems Inc.
Java home: /opt/local/share/java/openjdk6/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "darwin", version: "10.8.0", arch: "amd64", family: "unix"

ちなみにOpenJDKいれるまえは以下のような出力だった。

$ mvn -v
Apache Maven 3.0.3 (r1075438; 2011-03-01 02:31:09+0900)
Maven home: /usr/share/maven
Java version: 1.6.0_26, vendor: Apple Inc.
Java home: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
Default locale: ja_JP, platform encoding: SJIS
OS name: "mac os x", version: "10.6.8", arch: "x86_64", family: "mac"

んー、OS nameやencodingが違うのはなぜ・・・?まぁ、とりあえずほっとくか。

Heroku アカウント

Heroku | Loginからアカウント作成する。

Local Workstation Setup

HerokuのコマンドラインクライアントとGitをインストールしなさい、もしこれまでHeroku使ったりしてたらスキップしてとのこと。
以前HerokuでRubyをためしたときにインストールしたのがコマンドラインクライアントと同じなのかな。

$ gem list heroku

*** LOCAL GEMS ***

heroku (2.6.1)

とりあえずherokuコマンドつかえるので、今回はスキップする。
ちなみに、インストーラを起動して、何がインストールされるのかなと確認したら、

  • Foreman
  • Git
  • Heroku Client

がインストールされる模様。Foremanは・・・インストールされてないっぽい。コマンドにもgemにもない。とりえあえずそのままいってみる。
Gitは以前インストールしたのでこれを使う。ただし、バージョンは 1.7.6.1になってる。

Write Your App

サンプルコードを準備する

用意されているサンプルコードを src/main/java/HelloWorld.javaに作成する。

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.*;

public class HelloWorld extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.getWriter().print("Hello from Java!\n");
    }

    public static void main(String[] args) throws Exception{
        Server server = new Server(Integer.valueOf(System.getenv("PORT")));
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);
        context.addServlet(new ServletHolder(new HelloWorld()),"/*");
        server.start();
        server.join();   
    }
}

Jettyの組み込みWebサーバを使っているっぽい。こんなふうに書くんだなぁ。

mavenのpom.xmlを準備する

依存ライブラリを解決するために用意されているpom.xmlを書く。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>helloworld</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>7.4.5.v20110725</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.1.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals><goal>assemble</goal></goals>
                        <configuration>
                            <assembleDirectory>target</assembleDirectory>
                            <generateRepository>false</generateRepository>
                            <programs>
                                <program>
                                    <mainClass>HelloWorld</mainClass>
                                    <name>webapp</name>
                                </program>
                            </programs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

依存ライブラリはjettyとservlet-apiのみ。
あと、appassembler-maven-pluginというのを使うらしい。

.gitignoreにtargetを追加

mavenでビルドすると成果物がtargetディレクトリに作成されるのでここをgitの管理外にする。

ここまでやってディレクトリ構造はこんな感じ。

$ tree -a
.
├── .gitignore
├── pom.xml
└── src
    └── main
        └── java
            └── HelloWorld.java

Build Your App

ローカルでビルドする。といってもmavenなのでこれだけ。

$ mvn install

BUILD SUCCESSがでればOK。
ビルド後のディレクトリ構成はこんな感じ。

$ tree -a
.
├── .gitignore
├── pom.xml
├── src
│&#160;&#160; └── main
│&#160;&#160;     └── java
│&#160;&#160;         └── HelloWorld.java
└── target
    ├── bin
    │&#160;&#160; ├── webapp
    │&#160;&#160; └── webapp.bat
    ├── classes
    │&#160;&#160; └── HelloWorld.class
    ├── helloworld-1.0-SNAPSHOT.jar
    ├── maven-archiver
    │&#160;&#160; └── pom.properties
    └── surefire

target/binディレクトリがある。これがappassemblerで作成されるのか、へー。どうやらCLASSPATHに依存ライブラリも設定してくれるっぽい、ほー。うまく使うと便利そうだなぁ。

Declare Process Types With Foreman/Procfile

ビルドしたアプリを起動するのにProcfileというファイルが必要な模様。内容は1行のみ。

web: sh target/bin/webapp

どうやら、target/bin/webapp (以下ラッパースクリプト)を起動させるコマンドのようだ。

ラッパースクリプトを使うには、あらかじめ REPO 変数を定義しておく必要があるっぽい。ので定義しておく。

$ export REPO=$HOME/.m2/repository

ここまででディレクトリ構造はこんな感じ。Procfileが追加されただけ。

$ tree -a
.
├── .gitignore
├── Procfile
├── pom.xml
├── src
│&#160;&#160; └── main
│&#160;&#160;     └── java
│&#160;&#160;         └── HelloWorld.java
└── target
    ├── bin
    │&#160;&#160; ├── webapp
    │&#160;&#160; └── webapp.bat
    ├── classes
    │&#160;&#160; └── HelloWorld.class
    ├── helloworld-1.0-SNAPSHOT.jar
    ├── maven-archiver
    │&#160;&#160; └── pom.properties
    └── surefire

で、foremanで起動するのでインストールせよとのこと。

$ sudo gem install foreman

そして、foreman起動。

$ foreman start
02:49:23 web.1     | started with pid 77595
02:49:24 web.1     | 2011-09-14 02:49:24.508:INFO::jetty-7.4.5.v20110725
02:49:24 web.1     | 2011-09-14 02:49:24.640:INFO::started o.e.j.s.ServletContextHandler{/,null}
02:49:24 web.1     | 2011-09-14 02:49:24.689:INFO::Started SelectChannelConnector@0.0.0.0:5000 STARTING

で、http://localhost:5000/ にアクセス。Hello from Java!のメッセージを確認。OK。

foreman ってなにー?と思ったので調べてみたら以下がわかりやすかった。

どうやら、Procfileに記述した複数のプロセスを管理してくれるらしい。ログはコンソールにまとめて表示してくれるらしい。便利。

Store Your App in Git

herokuにデプロイするために、Gitのローカルリポジトリを作成しコミット。

$ git init
$ git add .
$ git commit -m "init"

Deploy to Heroku/Cedar

いよいよherokuにデプロイ。
まずは、Cedarスタックを作成。

$ heroku create --stack cedar

アプリのURLとherokuのgitのURLが表示される。
また、herokuのリモートリポジトリもローカルリポジトリに登録されるので、そのままherokuへpushしてデプロイ。

$ git push heroku master

pushが完了したらmavenのビルドが走った。
コマンドは以下の模様。

.maven/bin/mvn -B -Duser.home=/tmp/build_2y56vwsxf0tss -s .m2/settings.xml -DskipTests=true clean install

テストはスキップするみたい。当たり前か。

アプリのURLを叩くと、先ほどと同じメッセージが表示された!

まとめ

  • servlet は jetty などで組み込みで記述する
  • maven と git でビルド・デプロイ
  • java を起動するためのラッパースクリプトは appassembler-maven-plugin でビルド時に生成、これ他でも使えそう
  • foreman でプロセス管理、Procfileが必要
    • java アプリなんだけど gem がいる、ってことは ruby もいるってことか
  • ローカルでも問題なくうごかせそう
    • IDE 使ってたら普通に java を起動させればよさそう
    • ってことは ruby なくてもローカルならうごかせそうかな

SCM Boot Camp in Tokyo に参加してきた。

SCM Boot Camp in Tokyo に参加してきた。TDDBC in Tokyo 1.5 に続いて今月2度目のBootCamp。

@kyon_mm さんはじめ運営のみなさま、スピーカーのみなさま、参加者のみなさまお疲れさまでした。
そしてありがとうございました。楽しかったし勉強になりました!第二回あればまたいきたいです!

詳細は↓でまとめられてるので、

感想をつらつらと書いてみる。

参加前の状態

今回は最近使い始めたGitで参戦。
事前知識としては、

  • 仕事ではSubversionを使用。DVCSは使っていない
  • 入門Git の Chapter5 あたりまでを読んだ
  • githubをひとりでpush/pullしたりしてあそんだ
  • fast-forward でPushできなくなる??、なんで?よくわからん

といった感じ。

入門Git

入門Git

感想

  • Gitの基本概念をある程度知っていたこともあり、説明とかそれなりについていけた
  • 複数人での共同作業によりコンフリクトさせまくってそれを解決するのが楽しかった
  • 思いのほか Git の auto-merge が賢い
  • @bleis さんのレクチャで rebase のよさを体感した!マージのコミットオブジェクトがなくなるのでツリーがキレイ! rabase きもちいいw
    • 分岐した家系図が rebase をつかうことにより1本になった、なんか手品みたいw
  • 歴史を自在に操れるようになりたいw
  • 自分の職場で Git 使うにはまだまだハードル高そう、概念を理解してもらうのに苦労しそうだな・・・
  • @bleis さんの発表にあったJenkinsとの連携いいな。あんなのやってみたい。
  • 自動テスト・TDDと組み合わせてリズムを感じてみたい!
  • 今度は mercurial もさわってみたいな

その他

  • おかし充実しててよかった(シューアイスうま!)
  • MBAの電源を忘れてしまったが、同じ席の @rainydragon さんに電源をお借りしてなんとか最後まで参加できた。感謝です!

TDD Boot Camp in Tokyo 1.5 に参加してきた。

TDD Boot Camp in Tokyo #tddbc : ATND に参加してきた。
運営のみなさま、参加者のみなさまありがとうございました&おつかれさまでした。
非常に勉強になることばかりで、しかも楽しめました!

ということで、感想をまとめてみる。

@t_wada さんの基調講演

ペアプロ

  • ペアプロで緊張した
  • @sue445 さんとペアプロさせていただきました!
    • 自分が半分以上メインでやっちゃいました、すいませんでした(^^;;
  • あまりに久しぶりにEclipseを使ったので最初とまどったw
    • 普段プロダクトコードを(書きたいけど)書けない・・orz
  • TDDはなんとなくわかってたつもりだけど、頭でっかちで最初手がうごかなかった
  • @sue445 さんにEclipseの使い方やTDDのリズムなど優しく教えてもらえて非常に勉強になった
  • なれるにしたがってなんとなくリズムを感じれたような気がした、これがBootCampか・・・
  • 黄金の回転をしっかりと認識するにはもう少し経験する必要がありそう、体にしみこませたい
  • ペアプロ意外に疲れる
  • Groovy やってるペアがいてちょっと気になった、のでプログラミングGroovyをいきおいで買ったw
  • やっぱコードを書くのは楽しい!

その他

  • ボルダリング可能な会議室(?)にびびったwこんな職場で働きたい
  • 基調講演で紹介あった書籍がある会議室(?)すごいwまんがもある
  • お昼はお弁当だったのでよかった、外でさまよわなくてすんだし、同じ席の人とも話ができたし
  • GitのLT参考になった、alias知らなかったので使ってみよう
  • 普段からコードを書いてないと、こんなにも書けなくなるのかということを実感した、これはまずい、まずは写経だ!

追記