shibuya jvm groovy 20150418
TRANSCRIPT
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.1
2015年 4月 18日JGGUG/NTTソフトウェア株式会社
上原潤二
今さら始めよう Groovy
渋谷JVM
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
わたくしは上原潤二(@uehaj) NTTソフトウェア(株)Grails推進室 JGGUG運営委員
書籍: プログラミングGROOVY(技術評論社) Grails徹底入門(翔泳社)
ブログ「Grな日々」
2
ElmとRust推してます
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
お品がきGroovyってどんな言語? Groovyの思想 Groovyはどう役立つのか? 今どきのGroovy
3
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyってどんな言語?(1)文法はJavaのほぼ上位互換 真のクロージャを持ち簡潔な記述を旨とする
型システム・型チェック Groovy 1.8までは実行時型チェックのみ、 Groovy 2.0からは静的型チェック・静的コンパイル →Javaに準じた静的なコードも吐ける
5
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyってどんな言語?(2)実行
Groovy コードはJava バイトコード(クラス)に常にコンパイルされて実行される ラッパーや特殊なコンテキストやインタプリタ無し
ライブラリ 独自の体系はもたず、 Java 標準 API を基本として Groovy 独自のクラスやメソッドを追加
6
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.7
2003 2004 2005 2006 2007 2008
1.51.0 1.1Groovy 1.0b4
JSR化
Groovy 1.0b10 JSR EA
JSR-6 1.6-rc
JSR化
2009 2010 2011 2012 2013 2014 2015
→G2One
Groovy 1.7
Groovy 1.8
Groovy 2.0
Static Compilation
Groovy 2.4
Android Support
→SpringSource
→VMWare→Pivotal
7月
Grails 0.3
Spock 0.1Gradle 0.7
Grails 3.0
Groovyの歴史
JGGUG開始
AST変換indy
今のGroovy基本
Groovy 2.5
Apache ASF
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
最近の話題Pivotal社がスポンサーを降板(~2015/3末) Groovy/Grailsコア開発メンバーの直接雇用終了
codehaus閉鎖もあり、GroovyはASF傘下のインキュベータープロジェクトに
8
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
こんな感じのやりとり(想像です)
9
ぼくと契約して、ASFプロジェクトになってよ!
きゅうべえ、いや(Apache)インキュベーター!!!
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Java7コード例(WordCount)
10
import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; public class WordCount7 { public static void main(String[] args) throws IOException { try (FileReader fis = new FileReader(args[0]); BufferedReader br = new BufferedReader(fis)) { Map<String, Integer> map = new HashMap<>(); String line; while ((line = br.readLine()) != null) { for (String it: line.split("\\W+")) { map.put(it, (map.get(it)==null) ? 1 : (map.get(it) + 1)); } } List<Map.Entry<String, Integer>> entrySetList = new ArrayList<>(map.entrySet()); Comparator<Map.Entry<String, Integer>> comp = new Comparator<Map.Entry<String, Integer>>(){
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return o1.getValue() -‐ o2.getValue(); } }; Collections.sort(entrySetList, comp); for (Map.Entry<String, Integer> entry: entrySetList) { System.out.println(entry.getValue() + ":"+entry.getKey()); } } } } System.out.println(entry.getValue() + ":"+entry.getKey()); } } } }
def words = new File(args[0]).text.split(/\W+/) words.countBy{it}.entrySet().sort{it.value}.each { println "${it.value}: ${it.key}" }
Groovyコード例(WordCount)
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Java7コード例(Immutable)
11
public final class Punter { private final String first; private final String last; public Punter(String first, String last) { this.first = first; this.last = last; } public String getFirst() { return first; } public String getLast() { return last; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((first == null) ? 0 : first.hashCode()); result = prime * result + ((last == null) ? 0 : last.hashCode()); return result; } @Override public boolean equals(Object obj) {
if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Punter other = (Punter) obj; if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false; if (last == null) { if (other.last != null) return false; } else if (!last.equals(other.last)) return false; return true; } @Override public String toString() { return "Punter(first:" + first + ", last:" + last + ")"; } }
@Immutable final class Punter { String first, last }
Groovyコード例(Immutable)
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyコードの実行
12
JVM
2011
Javaソース
.classファイル
javacコマンド
javaコマンド
標準クラスローダ
Javaクラス
Groovyコード
groovyコマンド
Groovyクラスローダ (オンメモリ実行時コンパイラ)
JavaクラスJavaクラス
.classファイル
groovycコマンド
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Javaコードの実行
13
JVM
Javaソース
.classファイル
javacコマンド
javaコマンド
標準クラスローダ
Javaクラス
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyコードの実行
146
JVM
標準クラスローダ
Groovyコード
groovyコマンド
Groovyクラスローダ (オンメモリ実行時コンパイラ)
JavaクラスJavaクラス
.classファイル
groovycコマンド
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
GDKGroovyのために拡張されたJava API Collection#each(), Iterator#groupBy().. File#getText(), File#renameTo()… String#execute(), String#tr(), ..
15
"ls".execute() 'こんにちは'.tr('あ-ん', ‘ア-ン') new File("tmp.txt") << "hello\n"
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
GDKメソッド群
16
クラス GDK追加メソッド数java.lang.CharSequenc 93java.io.File 88java.nio.file.Path 86java.lang.Iterable 84java.lang.Object 77java.util.List 72java.lang.Object[] 63java.util.Map 58java.util.Iterator 54java.util.Collection 48
: :Total 1352
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyの設計思想「Javaを置き換えない」 Javaとの併用・共存・補完が存在意義そのもの。 GroovyはJavaクラスファイルを別ルート・別記法で読み込ませるためのクラスローダーであり、ライブラリの一種でもある。
JavaのAPIやライブラリはGroovyにとって必要悪ではない。 Javaライブラリは直接もしくは、Groovyラッピング・拡張し使用
RxGroovy/RxJava, ..
18
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
JRuby想定ユーザタイプ別Groovy乗り換えガイド
JRuby想定ユーザA:しょうがなくJVMを使う必要にせまられたrubiest。
JRuby想定ユーザB:Java APIもJVMも大好きだがJavaの文法だけは嫌い。
JRuby想定ユーザC:RubyのライブラリをJVM上で使いたいだけの人
Java APIはなるべく呼びません。Javaは必要悪! Groovyとの競合の余地ゼロ。
Groovyと思いきり競合 あなたはGroovyを使えばもっと幸せになれるかも。
Groovyとの競合の余地ゼロ。
Grails, Gradle、Spockなど、DSLを実装するツールやFWを通じて利用
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyの主な用途2つ
21
①DSLを実装するための言語
②Javaスクリプティング!
Javaプログラマの日常の仕事をGroovyで
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.22
Grails, Gradle、Spockなど、DSLを実装するツールやFWを通じて利用
①DSLを実装するための言語
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
ファクト: DSL実装言語としてのGroovy
Spock Gradle Grails Geb Jenkins MarkupTemplateEngine/MarkupBuilder
23
テストコード記述用DSL
Webアプリ記述用DSL
ビルド手順記述用DSL
Selenium2制御用DSL
HTML代替DSL
ワークフロー定義DSL、CLI
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Spockによるテストコード
24
パラメータのバリエーションを表形式で記述(|はビットOR演算子)
表の1行がそれぞれ別のテストケース(テストメソッド)として実行されたかのように結果が表示される。
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Why Groovy DSL? Groovy「Java開発者向けのDSL」に最適
Groovyのシンタックスやセマンティクスが「優れている」必要はない Java開発者にとって素直にわかればよく、意表をつく何かが無い方が良い
加えて、 「中括弧言語」としての十分な表現力 高速コンパイル、トライアンドエラーのしやすさ 動的型
25
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
動的型とDSL「本質的に動的」な対象のDSLモデリングには、動的型が自然な記述に寄与
26
def slurper = new JsonSlurper() def result = slurper.parseText('{"person":{"name":"Guillaume","age":33,"pets":["dog","cat"]}}')
assert result.person.name == "Guillaume" assert result.person.age == 33 assert result.person.pets.size() == 2 assert result.person.pets[0] == "dog" assert result.person.pets[1] == "cat"
html { head { meta(charset:'utf-‐8') title('Page title') } }
JSONを対象とした処理 HTMLマークアップ
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Why DSL?
27
加えて、実装⾔言語の都合(⽂文法・意味)をただ受け⼊入れるのではなく、あるべき記法を追求する
ドメインモデルを書き下すのに、既存⾔言語の⽂文法や実装都合の範囲内で、クラス名とか⼯工夫する
よりよいドメインモデルを探求するため。
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyの柔軟性:日本語DSL
28
まず 100 の 平方根 を 表示する
そして 1 と 2 と 3 のうち、 奇数 それぞれに 対して { それ -‐>
二倍にした それ を 表示する }
それはそれとして "abc" を 表示する
ついでに 1 から 100 のうち、 二の倍数.かつ(三の倍数) を 表示する
最後に 1 から 100 のうち、 二の倍数.かつ(三の倍数) それぞれに 対して { それ -‐>
とりあえず それ + "は6の倍数です" を 表示する }
// 10.0 // 2,6 // "abc" // [6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]
http://uehaj.hatenablog.com/entry/20100919/1284906117
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyの柔軟性:リスト(モナド)内包表記
29
@Grab("org.jggug.kobo:groovy-‐comprehension:0.3") import groovyx.comprehension.keyword.select // ピタゴラス数を求める assert select { a: 1..10 b: 1..a c: a..a+b a**2 + b**2 == c**2 // auto guard yield("(a=$a,b=$b,c=$c)") } == ["(a=4,b=3,c=5)", "(a=8,b=6,c=10)"]
https://github.com/uehaj/groovy-comprehension
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyの柔軟性:型クラスもどき
30
interface Monoid<T> { def T mappend(T t1, T t2); def T mempty(); } import static Functions.* class Functions { static <T> T mappend(T t1, T t2, Monoid<T> dict=Parameter.IMPLICIT) { dict.mappend(t1,t2) } static <T> T mempty(Monoid<T> dict=Parameter.IMPLICIT) { dict.mempty() } }` def instance_Monoid_java$lang$String_ = new Monoid<String>() { @Override String mappend(String i1, String i2) { i1+i2 } @Override String mempty() { "" } } String s = mempty() assert s == "" assert mappend("a","b") == "ab"}
https://github.com/uehaj/groovyz
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Groovyの柔軟性:LispBuilder
31
def env = new Env() env.eval{progn ${defun; average; ${x; y} ${div; ${add; x; y}; $2}} ${defun; abs; ${x} ${IF; ${lt; x; $0}; ${mul; x; $(-‐1)}; x}} ${defun; improve; ${y; x} ${average; y; ${div; x; y}}}
${defun; good_enoughp; ${y; x} ${le; ${abs; ${sub; ${mul; y; y}; x}}; $(0.000001)}}
${defun; sqrt_iter; ${y; x} ${IF; ${good_enoughp; y; x} y ${sqrt_iter; ${improve; y; x} x}}}
${defun; sqrt; ${x} ${sqrt_iter; $(1.0); x}}}
assert env.eval{sqrt; $(3.0)} == 1.73205081
http://uehaj.hatenablog.com/entry/20090706/1246836836
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
リアルワールドGroovy/GrailsGradle: Androidの標準ビルドシステム利用多数(「gradle」にマッチするgithubリポジトリ数 1701427) Netflixでの大規模で多彩な活用 国内最大級オンラインマガジンサービスはGrails New York Times Getting Groovy With Reactive Android(Android Groovy+RxJava)http://open.blogs.nytimes.com/2014/08/18/getting-groovy-with-reactive-android/
32
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
リアルワールドGrailsNTTソフトウェア株式会社では、GrailsをWebアプリ開発の標準フレームワークとして位置付けています
33
特に投資・自社製品で活用 一般向け商用保守サービス 社内開発プロジェクトでのGrails/Groovy採用数推移
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.34
Javaプログラマの日常の仕事をGroovyで
②Javaスクリプティング!
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Java開発のお供に(1)キーが”java”ではじまるシステムプロパティを一覧表示 groovysh(REPL)起動
もしくは
35
% groovysh Groovy Shell (2.4.0-‐beta-‐4, JVM: 1.8.0_25) Type ':help' or ':h' for help. -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐groovy:000> System.properties.keySet().grep { it.startsWith('java') } ===> [java.runtime.name, java.vm.version, java.vm.vendor, …..
% groovy -‐e "println System.properties.keySet().grep { it.startsWith('java') }"
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Java開発のお供に(2)GDKメソッド数をGroovyのドキュメントサイトからクラス別に集計する(Slide#15を作成)
36
Map count = [:].withDefault{[]} //集計用マップ new URL("http://docs.groovy-‐lang.org/latest/html/groovy-‐jdk/index-‐all.html").text .eachMatch($/<b>(.*)</b></a> -‐ Method in [^ ]* ([^<]*)<a [^>]*>([^<]*)/$) { g0, k, v1, v2 -‐> count[v1+v2] << k } count.entrySet().sort{-‐it.value.size()}.each { println "${it.key}\t${it.value.size()}" } println "total="+count.entrySet().inject(0){total,item-‐>total+item.value.size()}
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
最近(Groovy 2.3~2.4)の機能追加Groovy 最新版2.4.3(2015/4現在) 2.3
Traitの導入 マークアップテンプレートエンジン 型推論の改善
2.4 Android対応 イミュータブルソート・ユニーク(Collection.{toSorted, toUnique})
38http://uehaj.hatenablog.com/entry/2015/04/10/173816
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
Trait「実装を持てるインターフェース」 Scalaのそれにごく近い スタッカブルトレイト 、@SelfTypeアノテーション…
状態が持てる: Java8デフォルトメソッドとの違い 動的トレイト注入 プロキシオブジェクトを介するので、finalクラスにも注入可
Grails 3で積極的に活用されている!
39
spring bootベースの軽量FWに
Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.
マークアップテンプレートエンジンHTMLを簡潔なGroovyプログラムとして書けるhamlっぽいテンプレート
40
html { head { title “タイトル" } body { h1 "タイトル" ul { (1..10).each { li it } } } }
<html> <head> <title>タイトル</title> </head><body> <h1>タイトル</h1><ul> <li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li> </ul> </body> </html>
Spring MVC 4のGroovyMarkupView、Grails/Groovyサイトを生成する静的サイトジェネレータで使用 機能: i18n/レイアウト/インクルード/型チェック