2007年7月28日土曜日

第1回 grails code reading 終了!

第1回 grails code reading は 20 名以上の参加者を迎えて, 無事終了しました. 参加者の皆さん, 有り難うございました. みんな終電近くまで飲んでいたのですが, 無事帰れたでしょうか?



内容は



  • 自己紹介


  • これからどうするか?


  • 時間が余ったので山田のソフトウェア・シンポジウム 2007 での grails チュートリアルの超短縮版再演.

という感じでした.



で, 決まったことは


  • 今後メイリング・リストには http://groups.google.co.jp/group/grails-ja を使うので, 参加 (希望) 者はこれに登録する


  • 次回はここに山本さんがアップロードしてくれた groovy-little-book を読みながら, groovy の基礎体力を付けるので, 目を通してくる


  • 次回は 8/24 (金) 19:30 から, 場所は第1回と同じく CIJ 横浜本社

これからがようやく本番だね. 第1回は来られなかったという人も次回からの参加, ぜんぜん無問題です. 次回もよろしくー.

2007年7月18日水曜日

jbpm の馬鹿

jbpm の jpdl に相当するプロセス記述言語を builder を使って DSL として書けるようにしようとしていたのだが, 何と jpdl の一部は org.jbpm.graph の API として公開されていないことが判明 (例えば Decision の expression は XML として読み込ませることしかできず, プログラム的に設定することができない). orz.



jpdl を構築しようと思ったら XML を通すしかないわけだ.



中途半端な API は公開しないように > jbpm



2007年7月14日土曜日

IntelliJ IDEA を使う

eclipse で grails を扱うにはどうにももどかしい. ほとんど emacs でやってきたけどちょっと限界っぽい.



ので IntelliJ IDEA を使ってみることにした.



本体 (Selena と呼ばれる version 7 の未公式リリース) をここから, groovy/grails プラグインをここから持ってくる (JetBrains にあるものよりこっちの方が新しかった).



JetGroovy プラグインは IntelliJ IDEA を展開したフォルダの plugins の下に展開する. この辺は eclipse と同じ.



さて IDEA を立ち上げてみる. まずは



  • File | Settings ... の IDE Settings の


    • Groovy/Grails から Groovy と Grails のインストール場所を設定して (grails の開発だけならば, groovy の設定は多分要らないだろう),




    • General から File Encoding の Default encoding を UTF-8 にして,




  • 再起動する

じゃあ次はプロジェクトを作ってみる.


  • File | New Project ... して,


  • JavaVM を指定したりなどしてウィザードを進めていくと,


  • 最後の方でモジュール・タイプを指定するところがあるので Grails Application を指定する


  • "% grails run-app" が行われてプロジェクトができあがる

素晴らしい. 走らせるためには


  • Run | Edit Configuration ... して,


  • "+" をポチッとして,


  • Configuration Type に Run Application あるいは Run Test を設定すると,


  • IDEA の run または debug で "% grails run-app または test-app" が IDEA 内部で走るようになる

素晴らしい. ドメイン・クラスを追加してみる.


  • プロジェクトを右クリックして New | Groovy | Grails Domain Class,


  • ドメイン名 (例えば book) を入力すると,


  • ドメイン・クラス Book.groovy が生成されて, エディタに表示される.


  • ついでになぜか BookController.groovy も静的に (つまり各 action 込みで) 生成されちゃうのがうっとうしいけど.


    • これに関しては File | Settings ... | IDE Settings | Files Templates で JavaEE | Groovy と来れば, テンプレートを変更できる. この生成は grails のものじゃなくて, IntelliJ 側でやっていたのね...



少なくとも MacOSX 版では日本語もちゃんと使える. 何より, ちゃんとブレーク・ポイントを置ける (めちゃくちゃ時間かかるけどね) !



コード補完は大して効かない (これは仕方ない. ワード補完すれば多少は楽). emacs 風キー・バインディングも eclipse に較べていまいちの感がある.



けど eclipse よりストレスはだいぶ少ない. この plugin を提供しているのは IntelliJ 本体を作っているのと同じ JetBrains だし. IntelliJ 自体は eclipse のようななんでもありとは違うけど, 玄人筋の評価は割と高い.



これに $250 (Personal Edition) あるいは $500 (Enterprise Edition) 払うか? 払ってもいいかな...



# とりあえず 30 日間は使えます.

# こういう変態な言語の開発環境は最終的には自分 (groovy/grails) 自身で書くしかないのかも.

2007年7月6日金曜日

grails に関する五つの誤解

grails に関する5つの誤解を grails の中心的開発者のひとり, Graeme Rocher が自分の blog に書いている. 特に grails は業務系で実際に使われることを目指しているのであって, Rails のクローンではない, というのがおもな主張だ.

Graeme の書いた「Grails に関する五つの誤解」を大急ぎで, およそのあらましだけを訳しておく.



1) JRuby on Rails があれば Grails なんて要らないじゃん.



だから Grails のゴールは Rails とはぜんぜん違うんだって. Grails のゴールは実績のある Java コンポーネント (Hibernate, Spring, ...) を統合して, DRY (同じコトは二度しない) の原則に従って使いやすくすること. 焦点は Java にある. Rails とは違って, あらゆる J2EE コンテナで動かせる.



2) じゃあ Java でいいじゃん, Groovy なんかじゃなくて.



だから Groovy は Java の替わりをしようとしているんじゃないって. Java は複雑なロジックや低レベルなアルゴリズムを書くのにはいいけど, 高レベルのところは Groovy で書いた方が絶対にいい. 両方が共生することによって新しい力が生まれる.



3) なんでエンタプライズ系には Rails より Grails がいいの?



理由はいっぱいあるけど, 最大の理由は Hibernate & Spring だな. それに較べると Rails は EJB2 っぽい. ActiveRecord とかに縛られちゃうでしょ. ドメイン・モデルの存在も大きい.



4) Groovy/Grails は Ruby/Rails に較べれば信頼性の低い競争相手じゃないか?



確かに Groovy/Grails は新しくて, ユーザ・ベースも少ない. でも Groovy/Grails はものすごく信頼性が高いフレームワーク上に作られている. もう一つはどこで戦うかということだ. Groovy/Grails には二つのゴールがあって, その一つは Java コミュニティが作ってきたプラットホーム, 技術, ツールを活かして, 簡単でエレガントで DRY な Web フレームワークを作ること. もうひとつは Java で Web アプリケーションを作るときの敷居を低くしたいということ. 相反する要求だけど, 今のところうまくやっていると思う. 今は個人や小さい会社が中心だけど, これからはもっと大規模開発にも適応していくだろう.



5) Sun は Ruby をバックアップしているぜ?



確かに Sun は JRuby が動くように手助けしている. でも僕の答えはこうだ. 最高のものは滅多に Sun から出てこない.

2007年7月4日水曜日

Project Zero?

何だか知らないけど, IBM も Groovy 使って何かしようとしているようすだぜ.



http://www.projectzero.org/



ったく, 油断も隙もありゃしねぇや.

第 1 回 grails コード・リーディング

grails は groovy という Java VM の上で動く動的オブジェクト言語を用いた, アジャイルな Web アプリケーション開発環境です.



http://grails.codehaus.org/

http://groovy.codehaus.org/



その名前から想像されるとおり, それぞれ Rails, Ruby に強くインスパイアされています. が, Rails/Ruby とは異なる特徴もあり, 大変興味深いところです.



でも Rails/Ruby がなぜか大変もてはやされているのに対して, grails/groovy について日本語ではあまり情報もないのが現状です.



まぁまだ 0.5.6 ですからね. 今年 10 月予定の 1.0 リリース時にはきっとたいへん盛り上がることでしょう.



そこでとりあえず月一回くらいのペースで grails のコード・リーディングを始めることにしました.



grails は使っているだけだと単に超高生産性な Web アプリ開発ツールなわけですが, その中身がなかなか面白いし, 使っているとだんだん plugin などを作りたくなってくるわけです.



場所は横浜になりますが, 最近オープン・ソース・ビジネスやアジャイル・プロセスにも積極的な CIJ さんにお借りします.



------

第1回 grails コード・リーディング



日時: 7/25 (水) 19:00 - (多分 2 時間くらい)

場所: CIJ (地図)

(部屋は当日 7 階受付に張り出します)

対象: grails に興味のある方ならどなたでも

目標: grails をよりよく使うためのノウハウを参加者で学習/共有する

費用: なし

準備: grails-0.5.6 のコードが読める環境があるとよろし.

(プロジェクションしますから無くても大丈夫だと思います)

当日連絡先: 045-324-0111 石田 (19:00 以降は内線 7912) または 090-6486-7624 山田携帯

------



もっともいきなり grails のコード読みに入るかどうかは, 最初に集まっていただいた時点で考えようと思います.

(最初はまず grails とは何ぞやとか, groovy のリテラシも必要でしょうし)



おおざっぱな人数が知りたいので, masaki@metabolics.co.jp まで, 「第1回 grails コード・リーディング参加希望」というようなメイルを下さい.

締め切りは特にありません.

「25日は中華街でデートの予定だったのに, いきなり振られちゃったよ」というような場合, 当日直接来ていただいても構いません.



皆様の参加をお待ちしております.



2007年7月2日月曜日

grails でワークフロー (手で書く編3)

前述した組織モデルを前提として, jbpm を使ったワークフローを実現してみる.


では, ワークフローを定義する方法を決めましょう.



例えば Meeting というワークフローを表すクラスの名前は MeetingWorkflow ということにして, まずは controllers に置くことにします (Controller という sufiix は付きませんが).



その中身はこういう感じで, 状態機械に似ています.



import jp.co.metabolics.jbpm.grails.ProcessDefinition

import org.jbpm.graph.exe.ProcessInstance

import org.jbpm.graph.exe.Token



import jp.co.metabolics.jbpm.grails.ActionHandler

import jp.co.metabolics.jbpm.grails.AssignmentHandler

import org.jbpm.graph.exe.ProcessInstance

import org.jbpm.graph.exe.ExecutionContext

import org.jbpm.taskmgmt.exe.Assignable



/*

* convention として Workflow という名前にする.
現在は grails-app/controllers に置いているが,workflows などにするかもしれない.

*/

class MeetingWorkflow implements AssignmentHandler, ActionHandler {

// 実際には def workflow (WorkflowBuilder で作成またはリソース名を表す文字列) だけ書けばよい.

// ここでは ProcessDefinition になっている.

def workflow = {

def writer = new StringWriter()

def b = new groovy.xml.MarkupBuilder(writer)

b.'process-definition'(name:'meeting') {

swimlane(name:'promoter')

swimlane(name:'participant')

b.'start-state'(name:'start') { transition(to:'propose') }

b.'end-state'(name:'end')

b.'task-node'(name:'propose') {

task(name:'propose', swimlane:'promoter')

transition(to:'confirm')

}

b.'task-node'(name:'confirm') {

task(name:'confirm', swimlane:'participant')

transition(to:'decide')

}

b.'task-node'(name:'decide') {

task(name:'decide', swimlane:'promoter')

transition(to:'end')

}

}

ProcessDefinition.parseXmlString(writer.toString())

}



// 以下は dynamic に inject される.

private processInstance

private token



MeetingWorkflow() {

processInstance = new ProcessInstance(workflow())

token = processInstance.getRootToken()

}



void execute(ExecutionContext executionContext) {

def taskName = executionContext.getToken().getName()

def meeting = executionContext.getVariable('meeting')

// これらの情報からタスクを作って, 適切な inbox に入れる

// 例えば URL. jp.co.metabolics.inbada/meeting/propose/123/...

// アプリケーション名 (context path) /ワークフロー名/タスク名/id にリダイレクトすればよい

// grails の controller の仕組みが全部使える (はず)

// taskInstance も覚えておく必要があるが (end), そのためには jbpm の DB に直接アクセスする必要がある?

}



void assign(Assignable assignable, ExecutionContext executionContext) {



}



def start = { token.signal() }

}


書くべきことは状態機械と同様, ワークフローの定義 (workflow) のみです. 後は動的注入可能 (今はそうなっていませんが:-) です.



ユーザが自分の tasklist に入ったタスクを選択すると, それに対応する controller/action に飛ぶことになります.



grails でワークフロー (手で書く編2)

jpbm がとりあえず状態機械として動くことは判った. ワークフロー・エンジンとして使うためには (convention として) 組織モデルを考える必要がある. それをまずは決めておこう


組織モデル

ここでは組織モデルの作り方を決めましょう. 組織は永続してもらわないと困るので, とりあえずドメイン・クラスとして作ります (scaffold すればメンテナンス・フロントエンドができます). ただし Foo という組織は FooOrganization, Foo という組織のメンバは FooMember というクラス名にすることにします. また個人を表すドメイン・クラスは Person とします. いずれも後で楽ができることを期待した convention です.



Person.groovy の中身は例えばこんな感じになります.



class Person {

String name

String password

String email



String toString() { name }



static constraints = {

name(nullable:false, unique:true)

password(nullable:false)

email(nullable:true, email:true)

}

}


name と password が必要なこと以外は適当なプロパティがあっても構いません.



一方, 例えば Project という組織があるとしたら, ProjectOrganization.groovy という組織クラスを作ります.



class ProjectOrganization {

static belongsTo = ProjectOrganization

static hasMany = [subs:ProjectOrganization, members:ProjectMember]



ProjectOrganization zuper

String name



String toString() { name }



static constraints = {

name(nullable:false, unique:true)

zuper(nullable:true)

}

}


「組織は階層化している」「組織はメンバを持っている」のが肝です. やろうと思えばこれらは自動的に注入できるでしょう. その他のプロパティを必要に応じて追加しても構いません.



ProjectOrganization.groovy に対応して ProjectMember.groovy というメンバ・クラスを作ります.



class ProjectMember {

static roles = ['leader']

static belongsTo = [Person, ProjectOrganization]

static hasMany = [participations:Participation]



String role

Person person

ProjectOrganization project

List tasklist



static constraints = {

role(inList:roles, nullable:true)

person(nullable:false)

project(nullable:true)

}

}


roles は組織ごとに書く必要があります. また tasklist はワークフローで与えられたタスクが入るトレイになります. roles を除けば自動注入可能です. 組織と Person をつなぐ役割をしています.



テスト・コードはここには載せませんが, 使い方はまぁ自明でしょう. Person から自分がどの組織に属しているのか見えた方がいいかもしれません.



また今回は Project というような具体的な組織構造をクラス構造にハード・コードしました. 別の方法としてはもっと汎用的な組織構造だけをクラスにして, 個々の組織構造は実行時に組み立てるやり方もあります. 個々の組織構造が持つ振る舞いを組み込みたいと思ったので前者の方法を採りましたが, grails/groovy なら後から振る舞いを追加するのは可能でしたね.



さて, ようやくワークフローを定義することができます.

grails でワークフロー (手で書く編1)

grails で jbpm を使ってみる. まずは convetion over configuration の精神に則りつつ, すべて手書きしてみる. また最初は永続化は考慮しない (つまり, サーバを再起動するとすべてのワークフローはリセットされてしまう. 普通はこれでは役に立たない)


ステップは以下の通り.



  1. 状態機械として使う


  2. 組織モデルの作り方を決める


  3. ワークフローとして使う


状態機械として使う

例えば ActionItem というドメイン・クラスに対する状態機械を jbpm で動かしてみたいとしましょう. ActionItem.groovy に以下のようなコードを追加します.



// statemachine

static states = [start:'開始', notyet:'未着手', inhand:'着手済', completed:'完了', suspended:'中断', end:'終了']

// まずは永続性は考えない

private def statemachine = new ActionItemStatemachine()

// 以下は dynamic inject する

// states がなければ state() の結果をそのまま

public def state = { states[statemachine.state()] }

public def start = { statemachine.start() }

public def begin = { statemachine.signal('begin') }

public def done = { statemachine.signal('done') }

public def suspend = { statemachine.signal('suspend') }

public def abandon = { statemachine.signal('abandon') }

public def resume = { statemachine.signal('resume') }

public def end = { statemachine.end() }


どうやら grails はドメイン・クラスのプロパティに modifier を付けると永続化の対象としないようなので (本当か?), それを利用しています.



ここでまず states という Map を定義していますが, これは定義した状態名と人間が見る状態名のマッピングをするためのものです. これはなくてもいいかもしれませんね.



次にドメイン・クラス Foo に対する状態機械 statemachine の名前を FooStatemachine と決め打ちしています (convention).



statemachine, state, start, end はすべての状態機械に共通, begin から resume はこの状態機械が定義している状態です. いずれも動的な注入が可能でしょう.



一方, ActionItemStatemachine という状態機械クラスを作ります. 今は便宜上 controllers に置きます.



import jp.co.metabolics.jbpm.grails.ProcessDefinition

import org.jbpm.graph.exe.ProcessInstance

import org.jbpm.graph.exe.Token



class ActionItemStatemachine {

// 実際には def statemachine (WorkflowBuilder で作成またはリソース名を表す文字列) だけ書けばよい.

// ここでは ProcessDefinition になっている.

def statemachine = {

def writer = new StringWriter()

def b = new groovy.xml.MarkupBuilder(writer)

b.'process-definition'(name:'action-item-statemachine') {

b.'start-state'(name:'start') { transition(to:'notyet') }

state(name:'notyet') {

transition(name:'begin', to:'inhand')

}

state(name:'inhand') {

transition(name:'done', to:'completed')

transition(name:'suspend', to:'suspended')

}

state(name:'completed') { transition(to:'end') }

state(name:'suspended') {

transition(name:'abandon', to:'completed')

transition(name:'resume', to:'inhand')

}

b.'end-state'(name:'end')

}

ProcessDefinition.parseXmlString(writer.toString())

}



// 以下は dynamic inject される

private token



ActionItemStatemachine() {

token = (new ProcessInstance(statemachine())).getRootToken()

}



def signal = { token.signal(it) }

def start = { token.signal() }

def end = start

def state = { token.getNode().getName() }



}



最初に
jp.co.metabolics.jbpm.grails.ProcessDefinition を import していますが, これは jbpm の ProcessDefinition が 'def' というパッケージに入っているために groovy から直接読めない ('def' は groovy ではキーワード) からです.



src/java の下に以下のような内容の ProcessDefinition.java を置いています. 内容は何もない単なる wrapper です.



package jp.co.metabolics.jbpm.grails;



public class ProcessDefinition extends org.jbpm.graph.def.ProcessDefinition {

public static org.jbpm.graph.def.ProcessDefinition parseXmlString(String xml) {

return org.jbpm.graph.def.ProcessDefinition.parseXmlString(xml);

}



}




次に statemachine を定義しています. ここでは groovy の MarkupBuilder を使って, jbpm の jpdl 形式の XML を直書きです. これは例えば eclipse プラグインを使って書いたものをファイルとして読み込んでも構いません. が, いずれにしろプログラマが書くしかありません.



token, コンストラクタ, signal, start, end, state はすべての状態機械に共通なコードですから, やろうと思えば動的な注入が可能です.



さてこれを動かしてみましょう.



def ai1 = new ActionItem()

assert '開始' == ai1.state()

ai1.start()

assert '未着手' == ai1.state()

ai1.begin()

assert '着手済' == ai1.state()

ai1.suspend()

assert '中断' == ai1.state()

ai1.resume()

assert '着手済' == ai1.state()

ai1.done()

assert '完了' == ai1.state()

ai1.end()

assert '終了' == ai1.state()


OK のようです.



今度は jbpm をワークフローとして使ってみましょう. そのためにはまず組織モデルを決める必要があります.