41
Slide # 渋谷 JVM Copyright(C) 2015 NTT Software Corporation All rights reserved. 1 2015年 4月 18 JGGUG/NTTソフトウェア株式会社 上原潤二 今さら始めよう Groovy 渋谷JVM

Shibuya JVM Groovy 20150418

  • Upload
    -

  • View
    2.893

  • Download
    6

Embed Size (px)

Citation preview

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.4

Groovyって どんな言語?

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.17

Groovyの 思想

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との競合の余地ゼロ。

Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.20

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.37

今どきのGroovy

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/レイアウト/インクルード/型チェック

Slide # 渋谷JVM Copyright(C) 2015 NTT Software Corporation All rights reserved.

まとめGroovyはJava開発者の能力を高めるツール

用途: Javaスクリプティング DSL・ユビキタス言語 対象領域の問題に対して、最小完全な記述を求めることが本質。そのための記法を追求

41