BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ アーティクル 「Groovy & Grails eXchange 2011」in London 参加レポート(1/3)

「Groovy & Grails eXchange 2011」in London 参加レポート(1/3)

 「Groovy & Grails eXchange 2011」が、2011年12月8日~2011年12月9日の2日間、 ロンドンのSkills Matter eXchangeにて開催されました。初回開催の2007年から今年で通算5回目の開催となります。 
このカンファレンスには興味深い歴史があります。2007年に行われた「Grails eXchange 2007」を皮切りに、米国版の同カンファレンス「2GX (Groovy/Grails Exchangeの略)」、そしてSpringSource社によるG2One社 (Groovy/Grailsの開発会社)買収後に、SpringSource主催のカンファレンス「SpringOne」と合同開催となった「SpringOne2gx」へとGroovy/Grailsの成長の起源と呼ぶに相応しいカンファレンスでもあります。さらには、2007年頃からGroovy/Grails関係の開発リーダー達が毎年JavaOneに参加するなど、欧米で活発な活動を始めるきっかけにもなっています。

 「Groovy & Grails eXchange」は毎年年末に開催され、その内容は、その年に開催された他のカンファレンスでのGroovyエコシステム系セッションが、コンパクトかつブラッシュアップされたものとなっています。カンファレンスの運営は、ユーザグループの本家とも言える英国のGGUG (Groovy Grails Users Group)が行っており、全体を通して親しみやすいカンファレンスであるのも特徴です。

 今回の「Groovy & Grails eXchange 2011」は、2トラックを2日間、合計23件のGroovy関連技術のセッションが行われました。公式サイトはこちらです。
http://skillsmatter.com/event/groovy-grails/groovy-grails-exchange-2011
中心となるプログラミング言語「Groovy」を始め、Web開発エコシステム「Grails」、最近人気急上昇中のビルドフレームワーク「Gradle」、テストツール「Spock」「Geb」等盛りだくさんの内容を、コンパクトに2日間にまとめあげ、中心となるコミッタの方々と一緒にコーディングができる「Hackergarten」もありながら、しかも低価格(早割だと日本円で10,000円程度)で受講可能です。

 本稿では、「Groovy & Grails eXchange 2011」への参加報告を、大きく項目を分け数回に渡って紹介します。内容が複雑に交差する場合があるので、紹介順が変更になる場合もありますが、項目は次のようになります。

  1. Groovy - 「Groovy最前線!」
    最新リリースバージョンGroovy1.8系と次期バージョンGroovy2.0の新機能、メタプログラミングやGroovy周辺技術に関するセッションを紹介します。
  2. Grails - 「進化し続けるWeb開発エコシステム!」
    Grails2.0の最新情報を中心に、Grailsや、Grailsとクラウドに関連するセッションを紹介します。
  3. Griffon -「Grailsの良さをデスクトップに!」
    GrailsライクなデスクトップアプリケーションフレームワークGriffonに関するセッションを紹介します。
  4. Gradle - 「次世代ビルドシステムの大本命!」
    Spring や Hibernate などのフレームワークも採用する次世代ビルドツール Gradle に関するセッションを紹介します。
  5. テストツール - 「Groovy DSL でノイズのないテストを!」
    Groovy ベースのテストフレームワークである Spock, Betamax の概要や、 Grails における生産性の高い機能テストの実施方法など、テストに関連するセッションを紹介します。



Groovy - 「Groovy最前線!」

Groovy & Grails eXchange 2011はGroovyのプロジェクトリーダであるGuillaume Laforge氏によるGroovy最新情報を紹介するキーノートセッションから始まりました。本記事ではこのキーノートセッションで紹介されたGroovyの最新情報を中心に、その他のGroovyセッションを紹介していきます。

Groovy1.8最新情報

Groovy1.8ではさまざまな新機能の追加や改善が行われています。またいくつかの点でのパフォーマンスも改善されました。

コマンドチェーンによるDSLの改善

メソッド呼び出し時のドットと括弧が省略できるようになり、コマンドチェーンを利用することでDSLの実装が容易になりました。
Groovy1.7まではコマンドチェーンを利用しても次のような記述しかできかできませんでした。

turn(left).then(right)

Groovy1.8からはメソッド呼び出し時のドットと括弧が省略できるようになったため、DSLとして次のように記述できるようになりました。

turn left then right

この改善によってDSLをゼロから実装するのではなく、コマンドチェーンを上手く組み合わせることによってDSLを定義することが可能になります。次のようなチェーンを実装することで上記のDSLが実行可能になります。

def (left, right) = ['left', 'right']
def turn = {
   println "Turn $it"
   [then: { println "Then $it"}]
}

turn left then right

実行時パフォーマンスの改善

プリミティブ型に対する操作のパフォーマンスが改善されました。フィボナッチ数列のサンプルではパフォーマンスがGroovy1.7系よりも13倍速になるなど、Javaに近いパフォーマンスを出せるようになっています。他にもいくつかのメソッド呼び出しでリフレクションを使わずに直接メソッドを呼び出すようにすることでパフォーマンスの改善が行われました。

GParsをバンドル

Groovyの並行処理フレームワークであるGParsがGroovyのディストリビューションにバンドルされるようになりました。GParsではactorやfork/join、MapReduceなど、分散処理を行うための機能を提供しています。

クロージャの拡張

Groovy1.8ではクロージャに様々な拡張が施されました。

アノテーションのパラメータとして利用する

アノテーションのパラメータとしてクロージャを利用できるようになりました。すでにこの機能を利用したプロダクトとしてGContractsがあります。GContractsは契約プログラミングを提供するライブラリです。GContractsでは次のようにアノテーションに契約を記述することで、契約プログラミングを実現することができます。

import org.gcontracts.annotations.*

// 常にスピードは0以上
@Invariant({ speed() >= 0 })
class Rocket {

    // このメソッドを呼び出すにはスタートしている必要がある
    @Requires({ isStarted() })
    // このメソッドを呼び出した後は、スピードが上がっている
    @Ensures({ old.speed < speed })
    def accelerate() { ... }

    boolean isStarted() { ... }
    def speed() { ... }
}

クロージャの合成

クロージャを合成することでそれぞれのクロージャをかけ合わせたクロージャを生成することが可能になりました。

def plus2 = { it + 2 }
def times3 = { it * 3 }

def times3plus2 = plus2 << times3
assert times3plus2(3) == 11
assert times3plus2(4) == plus2(times3(4))

トランポリン

Groovy1.8で追加されたクロージャのトランポリンは、再帰する処理のクロージャを実行時にループに変えてしまう機能です。
例えば、次のような再帰を使って階乗を求めるコードがあります。

def factorial
factorial = { int n, BigInteger accu = 1G ->
    if (n < 2) return accu
    factorial(n-1, n*accu)
}

小さい値の階乗を求めようとした場合はこの実装でも問題ありませんが、大きな値の階乗を求めようとした場合、再帰が深くなりすぎてStackOverflowErrorが発生してしまいます。このような場合、次のようにトランポリンを利用することで再帰のようなコードでも実行時にはループとして実行されるようになります。

def factorial
factorial = { int n, BigInteger accu = 1G ->
    if (n < 2) return accu
    factorial.trampoline(n-1, n*accu)
}.trampoline()

メモ化

メモ化とはクロージャの実行結果をキャッシュしておく仕組みです。処理に時間がかかるクロージャが複数回呼ばれた場合、パラメータが同じであればキャシュされた結果が返されるようになります。メモ化の使い方は次のようになります。

def plus = { a, b ->
    sleep 1000;
    a + b
}.memoize()

plus(1, 2) // 1秒スリープしてから結果が返される
plus(1, 2) // すぐに結果が返される

1回目のクロージャ実行は1秒スリープした後で結果が返されますが、同じパラメータで2回目を呼び出した場合には、キャッシュされた1回目の結果が返されます。メモ化にはmemoize()の他にmemoizeAtLeast()/memoizeAtMost()/memoizeBetween()などのメソッドがあり、それぞれを利用することでキャッシュサイズを変更することが可能になります。

カリー化の改善

Groovyのカリー化ではクロージャのcurry()メソッドを使用して、クロージャの引数を左側から(第1引数から)固定したクロージャを生成することができます。

def add = { a, b -> a + b}
def add2 = add.curry(2)
assert add(2, 3) == add2(3)

Groovy1.8では次のように引数の右側改善されたカリー化は、次のように右側の引数から固定したり、任意の場所の引数を固定することができるようになりました。

// 右側の引数を固定
def divide = { a, b -> a / b }
def halver = divide.rcurry(2)
assert halver(8) == 4

// 第2引数を固定
def joinWithSeparator = { one, sep, two -> one + sep + two }
def joinWithComma = joinWithSeparator.ncurry(1, ', ')
assert joinWithComma('a', 'b') == 'a, b'

JSONのサポート

JSONを扱うためのクラスが追加されました。JSONの読み込みやJSONの構築の他に、JSON形式の文字列を整形して出力するためのクラスも追加されています。

JSONの読み込み

import groovy.json.*

def jsonText = '''{
    "name": "Guillaume",
    "age": 34,
    "pets": ["Hector", "Felix"]
}'''
def json = new JsonSlurper().parseText(jsonText)

assert json.name == 'Guillaume'
assert json.age == 34

JSONの構築

import groovy.json.*

def json = new JsonBuilder()

json.person {
    name "Guillaume"
    age 34
    pets "Hector", "Felix"
}

println json.toString()

JSON文字列の整形

import groovy.json.*

def jsonText = '{"name": "Guillaume", "age": 34, "pets": ["Hector", "Felix"]}'
println JsonOutput.prettyPrint(jsonText)

新しいAST変換アノテーションの追加

多くのAST変換アノテーションが追加されました。AST変換アノテーションを利用することで、実行時に抽象構文木(AST)を変換したバイトコードが生成され、プログラムの一部を変換することができます。例えばロガーをインジェクションするための@Logアノテーションは次のように使われます。

import groovy.util.logging.*

@Log
class Car {
    Car() {
        log.info 'Car constructed'
}
}

@LogアノテーションによるAST変換では、単にロガーがインジェクションされるだけではなく、次のようにログレベルによるチェックも行われるコードに変換されます。 

if (log.isLoggable(Level.INFO)) {
    log.info 'Car constructed'
}

@Logアノテーションは、java.util.loggingパッケージのロガーを使用しますが、Commons LoggingやLog4Jなどの他のロギングライブラリ用のAST変換も用意されています。
Groovy1.8では他にもequals()メソッドやhashCode()メソッドを生成するためのアノテーションなど新しいAST変換アノテーションが20個ほど追加されました。

Groovy2.0最新情報

JDK7との調整

Project Coinの対応

Groovyではswitch文の条件判定でStringを利用できるなど、Project Coinの仕様をすでに実装している部分もありますが、Groovy2.0ではアンダースコア付き数値リテラルや、例外のマルチキャッチの対応が入るなどJDK7との調整が行われています。

InvokeDynamicの対応

JDK7の(Groovyにとって)大きな機能であるInvokeDynamicの対応も進められています。現在、Groovyのリポジトリ上ではindyブランチと呼ばれるブランチが切られInvokeDynamicへの対応が行われています。

静的型チェック

これまで、Groovyは多くのことを実行時に行うようにしてきました。しかし、Javaライブラリを使ったスクリプティングを行うときなどは、typoや不正な型などのエラーをコンパイル時に検出できる方がメリットがあります。これを実現するために、Groovy2.0ではgrumpyと呼ばれる静的型チェック機能を追加しようとしています。

void method() {}

@TypeChecked test() {
    metthhooood()
    def name = 'Guillaume'
    println naamme
}

Groovyのモジュール化

Groovyにはテンプレートエンジンや、Antスクリプティング、GroovyConsoleなどのSwingUIと多くの機能が標準で組み込まれています。しかし、常にこれらの機能が必要になるケースはあまりありません。そこでGroovy自体のモジュール化も進められています。今後は必要な機能だけを選択したGroovyが利用できるようになるでしょう。

Groovy on Android

AndroidアプリケーションをGroovyで実装するためのプロダクトであるDiscobotの紹介セッションがありました。AndroidアプリケーションはJavaで実装されていますが、Dalvik VMは通常のJava VMとは異なるため、Groovyで実装したアプリケーションを簡単に実行できず、Groovy自体にパッチを当てるなど様々なハックが行われていました。
セッションでは開発中のものを使ったデモを見ることができました。DiscobotはビルドシステムとしてGradleを採用しており、プロジェクトテンプレートの作成からAndroidエミュレータ上でのアプリケーションの実行をGradleプラグインを使ってできるようになっています。デモでは、簡単なHelloWorldアプリケーションや、Discobot Consoleと呼ばれるGroovyConsoleと同じようなアプリケーションがAndroidエミュレータ上で実行されていました。他にも、クラスパス上にあるテストクラスをスキャンし、すべてのテストをAndroidエミュレータ上で実行するというデモも紹介されました。このデモにはGroovyの開発に使われているテストケースの一部が使用されました。
カンファレンス中にはまだDiscobotはリリースされていませんでしたが、2011/12/28にGradle Discobotプラグインのバージョン1.0がリリースされました。
Discobot https://github.com/disco-bot/

Gaelyk

Gaelykとは、Google App Engine(GAE)上で動作するアプリケーションをGroovyの機能を活かして簡単に構築することができるGroovyの軽量ツールキットです。GaelykはGrailsのように多機能ではありませんが、Groovletと呼ばれるGroovyスクリプトをコントローラとして使用したり、JSPのようなGroovyテンプレートエンジンを使用するなど、GAE上で動かすアプリケーションを作成するための必要最低限の機能が提供されています。GAEではBigtableと呼ばれるデータストアを利用しますが、Gaelykではデータストアにアクセするために次のようなSQLライクなDSLを提供しています。

def entites = datastore.execute {
    select all from savedscript
    sort desc by dataCreated
    where author == params.author
    limit 10
}

以前のバージョンではデータストアのLow-Level APIを利用するような形でデータストアに対する検索をしていましたが、Groovy1.8で改善されたコマンドチェーンによるDSLの機能を使ってSQLライクなDSLをGAEのデータストアに対して利用できるようになりました。Gaelykでは他にもGAEが提供するAPIをより簡単に利用できる仕組みが標準で提供されている他に、シンプルなプラグイン機能も提供しており、様々な機能を再利用することができます。
Gaelykはとてもシンプルで簡単にWebアプリケーションが構築できるため、GAE以外のクラウドプラットフォーム上でも利用しようという試みがあります。現在、ColudFoundry版のGaelykとしてCaelyfという派生プロダクトも開発されています。
Gaelyk http://gaelyk.appspot.com/
Caelyf http://caelyf.cloudfoundry.com/

Groovyで非同期IO

Node.jsのような非同期IOを用いたイベント駆動型アプリケーションフレームワークをJVM上で実現するためのプロダクトとして開発されたVert.xが紹介されました。Vert.x自体はJavaで実装されていますが、Vert.x上で動かすアプリケーションはJavaだけではなく、JVM上で動作する他の言語で実装できるようになっています。現在はJRubyとGroovyに対応していますが、今後JavaScript/Python/Closure/Scalaに対応する予定になっています。Vert.xはNoSQLデータベースであるRedisと連携する機能も提供しています。セッションでは、HTTPリクエストを受けた数をRedisにカウントするサンプルが紹介され、10Kのクライアントからのアクセスをシミュレートしたデモが非常に高速に処理されていました。
Vert.x http://purplefox.github.com/vert.x/

この記事に星をつける

おすすめ度
スタイル

BT