Groovy 2.5.0で追加されたgroovy.transform.AutoFinalを試してみた

最新のGroovy 2.5.0から、groovy.transform.AutoFinalというAST変換が追加されていたらしい。

ついさっきPaul King氏のツイートを目にして初めて知った。

気になったので早速試してみた。

まずは@AutoFinalなし。

class Person {
    String firstName
    String lastName

    Person(String firstName, String lastName) {
        lastName = lastName.toUpperCase() // あえてパラメータに再代入する(普通はこんなことしちゃダメ)
        this.firstName = firstName
        this.lastName = lastName
    }

    String toString() {
        "$firstName $lastName"
    }
}

def p = new Person("Nobunaga", "Oda")
assert p.toString() == "Nobunaga ODA"

普通に実行できる。

で、クラスに@AutoFinalアノテーションをつけてみる。

import groovy.transform.*

@AutoFinal // <--- これを追加しただけ
class Person {
    String firstName
    final String lastName

    Person(String firstName, String lastName) {
        lastName = lastName.toUpperCase() // あえてパラメータに再代入する(普通はこんなことしちゃダメ)
        this.firstName = firstName
        this.lastName = lastName
    }

    String toString() {
        "$firstName $lastName"
    }
}

def p = new Person("Nobunaga", "Oda")
assert p.toString() == "Nobunaga ODA"

これを実行しようとすると、

1 compilation error:
The parameter [lastName] is declared final but is reassigned

と、コンパイルエラーになった。

というように、@AutoFinalをつけると、AST変換によって全てのコンストラクタ引数、メソッド引数、クロージャ引数に暗黙のfinalが付与されて、コンパイルチェックされるようになる。

これはいいかもしれない。

(おまけ) プロパティのfinal化=不変化

なお、

import groovy.transform.*

@AutoFinal
class Person {
    String firstName
    String lastName

    Person(String firstName, String lastName) {
        //lastName = lastName.toUpperCase() // このエラーは今は興味ないのでコメントアウト
        this.firstName = firstName
        this.lastName = lastName
    }

    String toString() {
        "$firstName $lastName"
    }
}

def p = new Person("Nobunaga", "Oda")
assert p.toString() == "Nobunaga Oda"

// プロパティは再代入可能
p.firstName = "Nobunari"
assert p.toString() == "Nobunari Oda"

は普通に実行できる。つまりプロパティは再代入可能なままなので注意。

プロパティを再代入不可能にするには、groovy.transform.Immutableという前からあるAST変換を使えばOK。 簡単に不変オブジェクトにできる。

import groovy.transform.*

@Immutable
class Person {
    String firstName
    String lastName

    // @Immutableを使った場合は、Mapを受け取るコンストラクタと
    // プロパティ定義順にしたがって全部受け取るコンストラクタが自動生成される。
    // 明示的なコンストラクタを実装するとエラーになる。
    // Error during ImmutableBase processing. Explicit constructors not allowed for class: Person
    //
    //Person(String firstName, String lastName) {
    //    //lastName = lastName.toUpperCase() // このエラーは今は興味ないのでコメントアウト
    //    this.firstName = firstName
    //    this.lastName = lastName
    //}

    String toString() {
        "$firstName $lastName"
    }
}

def p = new Person("Nobunaga", "Oda")
assert p.toString() == "Nobunaga Oda"

// プロパティは再代入不可能になる
p.firstName = "Nobunari"
assert p.toString() == "Nobunari Oda"
groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: firstName for class: Person

コンパイルエラーではなく、実行時に例外が発生する点がちょっと違う。

Gaiden Filters/Extensions活用のススメ

はじめに

久しぶりのブログ記事です。 この記事は、G* Advent Calendarの13日目として書いています。 昨日はきょんさんによるGroovyのAST変換事情で、明日もきょんさんの予定です。

Gaidenとは?

数年前にGaidenというドキュメント作成ツールひっそりとリリースして、弊社の社内ではそこそこ活用していたりします。

特徴は、↓という感じです。

  • Markdownでソースを執筆する
  • Sphinxライクな複数ページのHTMLドキュメントを生成できる
  • Gaidenラッパーという仕組みで自動インストールできるので、Javaさえあればすぐにビルドできる
  • Gaiden Extensionという仕組みで、自由にシンタックスを拡張できる *1

Gaiden自体のホームページもGaidenで生成しています。 ちなみに、拙作のGroovyServのホームページも同じくGaiden製です。

Markdownの記述力って低いんでしょ?

確かにGFM(Github Flavored Markdown)でさえも相当シンプルなので、そこそこの分量のドキュメントを執筆するにはMarkdownの記述力だと不足ガチかもしれません。 その点、Asciidocはかなり機能がリッチなので、昨今、人気が高まってきている感じがあります。

しかし、個人的にはMarkdownのプレーンテキストフレンドリなシンプルさが好きなので、なんとかMarkdownで書きたいわけです。

そこで、Gaiden Filtersの出番です。

Gaiden Filters

簡単にいうと、簡単なGroovyコードを書くだけで、自由にシンタックスを増やしたり拡張したりし放題できる仕組みです。

以下の3つのタイミングで自由に介入して、自由にテキストが置換できます。

  • before: Markdownソースのテキスト
  • after: Markdownソースから変換されたHTML断片のテキスト
  • afterTemplate: テンプレートを使ってレンダリングされた最終的なHTMLのテキスト

サンプル: バージョンを設定ファイルに外だしして、ビルド時に置換する

config.groovyに、以下のように記述するだけです。 beforeに代入したクロージャの戻り値のテキストが次のフェーズ(この場合はMarkdowのレンダリング)に渡されます。

// in config.groovy
...

version = "1.0.0"

// Filters
filters = {
    expandVersion {
        before = { text ->
            text.replaceAll(/(?m)<VERSION>/, version)
        }
    }
}

あとは、Markdownで以下のようにVERSIONという文字を使ってドキュメントを書きます。

このドキュメントのバージョンはVERSIONです。

これでgaiden buildを実行すると、生成されたHTMLドキュメントでは

このドキュメントのバージョンは1.0.0です。

と、バージョン番号が展開されます。 とてもわかりやすいですね。

Gaiden Extensions

Gaiden Filtersが相当便利なので、ドキュメントプロジェクトごとに色々フィルタ実装を追加しまくっていると、汎用性の高いフィルタができたりして、他のドキュメントプロジェクトでも同じフィルタを利用したくなってきます。

config.groovyのフィルタ実装をコピペしてもよいのですが、そこで一歩進んで、再利用可能なモジュールであるGaiden Extensions形式にしてみましょう。

と言っても大したものではなくて、config.groovyと必要なリソースを特定のディレクトリに放り込んだだけの構造です。

先ほどのサンプルのように他のリソースが不要なら、次のようにとてもシンプルな構造になります。

extensions/
└── expandVersion
    └── config.groovy
// in extensions/expandVersion/config.groovy
filters = {
    expandVersion {
        before = { text ->
            text.replaceAll(/(?m)<VERSION>/, version)
        }
    }
}

先ほどのサンプルからだと、以下の3手順で移行できます。

  1. extensions/expandVersionディレクトリを生成する。
  2. 直下のconfig.groovyextensions/expandVersion配下にコピーする。
  3. extensions/expandVersion/config.groovyを編集して、必要なfilters以外のソースをすべて削除する。

Gaidenはexntensionsディレクトリ配下の各ディレクトリの中のconfig.groovyも順番に評価してくれるので、先ほどと全く同じように動作します。

Gaiden ExntensionsでAdmonitionを実現してみる

さて、再利用性の高いオレオレシンタックスの作り方がわかったところで、Asciidocの素敵機能のひとつである Admonition (アドモニション)をGaiden Extensionsで実現してみましょう。

Admonitionの例

こういうヤツです。

Markdownの良いところはプレーンテキストとしてみてもそこそこ良い感じに読める、という点なので、そこは譲れません。 つまり、プレーンテキストでも良い感じに読めるような特殊なシンタックスを決めて、それをGaiden Filtersの仕組みでAdmonition表現に置換するようなGaiden Extensionsを作る必要があります。

ここでは、以下のようなシンタックスを導入してみます。

 > **NOTE**: This is title!
 >
 > This is an admonition with title.

いかがでしょうか。 個人的にはそんなに醜くないし、普通のMarkdownとしてレンダリングされた結果としても割と良い感じなのではないかと思いますが、最終的には個人の主観にお任せします。

あとは、これをビルドすると上の画像のようなレンダリング結果が得られるように置換ロジックを書けばOKです。

で、できあがったGaiden Extensionsが、こちらのGaiden Extension: Admonitionになります。

filterの実装はこんな感じです。

filters = {
    admonition {
        before = { text ->
            def converter = { all, type, title, lines ->
                def header = title ? """<div class="admonition-caption">$title</div>""" : ""
                return """<div class="admonition admonition-${type.toLowerCase()}">
                         |  <div class="admonition-icon">
                         |    <i class="fa"></i>
                         |  </div>
                         |  <div class="admonition-content" markdown="1">
                         |    $header
                         |    ${lines.replaceAll(/(?m)^\s*>\s*?/, '')}
                         |  </div>
                         |</div>""".stripMargin()
            }
            text.
                replaceAll(/(?ms)^> \*\*(NOTE|TIP|WARNING|IMPORTANT)\*\*(?::(.*?))?$(.*?)(?:^$|> ----)/, converter). // block
                replaceAll(/(?ms)^\*\*(NOTE|TIP|WARNING|IMPORTANT)\*\*:()(.*?)$/, converter) // inline
        }
    }
}

なお、CSSファイルもassetsとして追加してあります。

extensions/admonition
├── assets
│   └── css
│       └── admonition.css
└── config.groovy

NOTEだけではなく、

Admonitionの例

Admonitionの例

Admonitionの例

など複数種類に対応してたり、一行でシンプルに書いたり、タイトルをつけたり、などそこそこリッチな感じです。 詳しくはREADMEを読んでいただければ、使い方やサポートするシンタックスなどがわかるかと思います。

個人的には、これを大変便利に色々なドキュメントプロジェクトで使いまくってます。

おわりに

オレオレシンタックスを増やしたら、学習コストやメンテナンスコストが大変なのでは、という懸念もあるでしょうが、あーあー聞こえない聞こえない。 ではなく、まあ節度を持って活用すれば良いんじゃないでしょうか。

というわけで、巷では非常にレアなGaiden活用テクニックをお送りしました。

参考リンク

*1:なお、現在のバージョンではWindowsのGaidenラッパーによるインストール時にファイルパーミッション関連のエラーが発生してしまいますが、インストール自体は成功してるはずなのでエラーにめげずにもう一度Gaidenコマンドを実行すると動くんじゃないかと思います。たぶん。

JavaOne 2017 レポート 10/6 Day-6 帰国日&総括

さて、帰国日。 JavaOne 2017レポートも今回で完結です。

観光ウォーキング

今回の往復空路は羽田発着JAL便。 出発は16:05 SFO発なので、飛行機の時間まで結構時間があります。 ホテルのチェックアウトリミットは12:00ですが、ギリギリまで引きこもってるのも勿体無いですし、今回は全然観光してなかったので、チャイナタウン経由のフィッシャーマンズワーフ往復ウォーキングを強行してみました。

ユニオンスクエアの横、ケーブルカーの通る道路を北に向かいます。

f:id:nobeans:20171006105249j:plain:h300 f:id:nobeans:20171006110256j:plain:h300

チャイナタウン。時々道端にウ○コがあるので注意が必要。

f:id:nobeans:20171006110739j:plain:w300 f:id:nobeans:20171006111109j:plain:w300

途中にある公園にある綺麗な建物。

f:id:nobeans:20171006111836j:plain:w300 f:id:nobeans:20171006111805j:plain:h300

フィッシャーマンズワーフ到着。アシカや遊園地のあるPier 31から、

f:id:nobeans:20171006113546j:plain:w300 f:id:nobeans:20171006113742j:plain:w300

西の方に歩いて行って、

f:id:nobeans:20171006115305j:plain:w300

お昼はIN-N-OUTで。 激混みでしたが、なんとかゲット。チーズバーガー美味しいです。

f:id:nobeans:20171006122002j:plain:w300

IN-N-OUTの待ち時間でだいぶ時間を消費したので急いで戻ります。 なんか上の方を指さしてる家族連れがいたので、つられて見たら飛行機パラシュート部隊らしき何かがクルクルしてました。1

f:id:nobeans:20171006123543j:plain:h300

歩いた軌跡はこちら。

f:id:nobeans:20171020225707j:plain:w300

現地に溶け込むスキル高い方とのご挨拶

ホテルに戻ってスーツケースを受け取って空港へ向かおうとホテルを出たところで、通りの反対側で上下スウェット姿でタバコを吸っている現地の人に「ナカノサーーン」と声をかけられましたが、よくみたら寺田さんだったのでおつかれさまのハグをしてお別れしました。

一発逆転のコイン消費行

アメリカのコインですが、種類も多いし、大きさと価値が比例してないし、数字が書いてないやつもあるし、書いてても小さくてみづらいしで、いつみても全く使える気がしません。 今回の滞在ではクレジットカードをメインに使いましたが、どうしても現金が必要な場面では紙幣を使っていたので、やはりそれなりに小銭ができてしまいます。

最終日の朝に少しは消費してみようと、スタバで朝食買うときにコインを出してみましたが、$8.50 (うろ覚え)に対して、紙幣で$8と5セントコインを出してみましたが($8.05)当然たりず2、店員のお姉さんに「この中から選んでくれ」とコインを一通り出してみたら、よりによって一枚だけ紛れ込んでいた1ドルコイン3をピックアップされてしまいました($9.05)。 お釣りは55セント。これがジャラジャラとコインで帰ってきます。 使うどころかむしろ増えました。なぜだ。

次のコイン消費チャンスは、クリッパー(SUICA的なやつ)への帰りのBART代チャージ。 しかし、BARTの券売機が史上稀に見るひどいUIなのと、後ろに並ぶ人たちのプレッシャに耐えかねて、適当に入れてチャージしたら、なんとお釣りで大量のコインがジャラジャラと出てきてしまいました。 実は焦って1枚多めに1ドル紙幣を入れてしまったのですが、チャージ指定した金額をさっ引いた額が全部小銭で帰ってくるというミラクル。ジャックポットかよ。 合計1ドル以上のクォータ(25セント)コイン+αがジャラジャラと釣り銭口に溢れ出して泣きそうです。 財布もパンパンです。

もうダメかと諦めてましたが、飛行機のチェックインが早く終わり、ふと見ると保安ゲートの前にコーヒー屋さんがあります。

f:id:nobeans:20171006143108j:plain:w300

ここで可能な限りコインでコーヒを買えれば勝つる。 正直なところ店員さんにとっては迷惑な話ですが、レジも空いてたし、先に「全部コインで払ってもいいですか?」と聞いたら笑顔でOKしてくれたので大丈夫なはず。 結論としては、手持ちのコインをほぼ全部つかってコーヒー一杯の購入に成功しました。

f:id:nobeans:20171006142533j:plain:h300

最後まで残ったdimeという謎コインは店員さんへの感謝を込めてレジのビンに入れて、晴れて全てのコインを消費しました! なお、あとで調べたらdime=10セントでした。何度調べても覚えられない。

総括

さて、今回のJavaOne全体をざっくりまとめてみます。

技術

気になったキーワード

  • Jigsaw
    • Java 9の目玉ですし、既存プロダクトのマイグレーション方法とか気になりますし(そして結構面倒そう)
  • Project Amber
    • パターンマッチっぽいシンタックスとか、またベイパーウェア的な感じかと思いきや普通に18.3から一部入ってくるっぽいしヤバい
  • Graal
    • 日本語情報早よ
  • TestContainers
    • docker-compose使ってテスト環境作ることが多いですが、今の「先に手動でdocker-compose upしてからテスト」みたいなやり方を全部テスト側からコントロールできるっぽいので便利そう。
  • Microservices/Container/Kubernetes
    • とりあえずこの辺に関するセッション数はかなり多かったし人気だったし、やたらと単語が登場したので今ホットらしい(今頃かよ的なツッコミもあるとは思うけども)

Groovy/Grails

今年はGrailsのセッションはありませんでした。 というか、Webアプリケーションフレームワーク自体のセッションがほとんどないです。 見かけたのはVaadinぐらいかな? ふつーのWebアプリフレームワークについては、もう一通り落ち着いた感じがしますね。

Groovyの方は、タイトルに冠したセッションは3つで、そのうち2つ聞きましたが、セッション内容については前日までのレポートの通りです。

一方、Kotlinをタイトルに冠したセッション数は9件で、ALT Java言語系ではダントツだった気がします4。 セッション的には、Kotlin >>>> Scala >= Groovy 的なイメージ。 Android勢の基盤を確固たるものにしつつ、この勢いでどこまでいけるのか健闘を祈っております。

今回は大山さん・櫻庭さんとご一緒させていただくことが多くて、美味しい食事が楽しめました。 一人でレストランとかバーとかにいくのが難しいハート弱い系なので、大変助かりました。 あと、色々ごちそうさまでした。 なお、今回ビールについては、IPAを中心に攻めましたが、いずれもたいへん美味しかったです。

英語

6年ぶりのJavaOneは相変わらず楽しかったですが、自分の英語力のアレさ加減に打ちのめされて帰るという定番コースは今年も覆せませんでした。 以前よりも聞く方はだいぶマシになってきたなぁという実感はありますが5、ある一線を越えないと五十歩百歩感が否めないというか、「英語聞けますよ枠」に行くにはまだまだ努力が必要です。 しゃべる方はむしろ全然練習してないのでまあボロボロです。 頑張ろう。

その他

今回、JavaOneのレジストレーション後にもらえるオマケが、毎年恒例のリュック&Tシャツ、の2つだけでなんだか寂しい感じです。 JavaOneとして独立した会場&野外ラウンジがないとか、食事と一緒にドリンクがつかないとか、コーヒーとドリンクが午後1回の配給だとか、無限ビールが一晩だけとか、経費削減感がそこかしこに感じられて若干不安な気持ちが頭をもたげます。 ただ、ランチの味は以前の記憶よりもマシになってる感じがしました。 サンドイッチ系はパンがごつくてつらいこと以外は味は普通に楽しめた気がします6。 なんとなく。

さいごに

というわけで、総評として大変楽しいJavaOneでした。 また来年も行きたい!

f:id:nobeans:20171006152734j:plain:w300


  1. skrbさん情報により訂正

  2. $8.5(0)になるかと錯乱してました。

  3. 1ドル紙幣が存在するくせになんで1ドルコインが存在するのか…。

  4. なお、"Scala"をタイトルに含むセッションは5件。ちなみに"Gradle"は6件。

  5. 相対的に以前がどんだけ酷かったかという話もありますが。

  6. ただし、最終日に食べたキムチ入りの謎のロール状食物は食べられなくはないものの味はアレでした。

JavaOne 2017 レポート 10/5 Day-5 千秋楽はMariottホテルで

いよいよ正真正銘JavaOne最終日です。

会場もMoscone WestからMariottホテルに場所を移して、なんとなくもう終わるんだよ感が漂ってきます。

今年は最終日のランチチケットがついてなかったので、参加者同士で「コスト削減でランチ配給もないのか!」などとぼやいていたら、単にチケットのモギリがなくなっただけでブツはきちんと配給されました。 なお、味はいつも通り。

Java Community Keynote

今年のテーマは「Community Keynote Reloaded」。 要するに「Matrix Reloaded」1 になぞらえて、各地のコミュニティの人たちで寸劇を披露しつつ普段の活動を紹介する、みたいな流れです。

なんだかんだで毎年来日されてる親日家のStephen Chin氏がディレクター的な役柄で、JOnsenのSebastian Daschner氏がNEO役になって話が進みます。

f:id:nobeans:20171005094219j:plain:w300 f:id:nobeans:20171005094557j:plain:w300

グリーンバックのクロマキー合成でバイクを乗り回してみたり、

f:id:nobeans:20171005100826j:plain:w300

日本オラクルの伊藤さんが日本古来より伝わるSpirits of Jigsawの教えを説いてみたり、

f:id:nobeans:20171005101141j:plain:w300

javajoのカラテマスターよこなさんがカラテキックを教えたり2

f:id:nobeans:20171005101446j:plain:w300

マスターオブマスター(?)のskrbさんのマスター感が半端なかったり、

f:id:nobeans:20171005102336j:plain:w300

と、想像していたよりも楽しめました。よかったよかった。

A RESTful Java Framework for Asynchronous High-Speed Ingest

サーバ側の処理が結局DBへの更新系処理がボトルネックになってスケールしない問題を、NIOのSelector APIとステートマシンアルゴリズムを使って、非同期かつノンブロッキング処理として解決してみたよ、みたいなセッション。

  • Selector APIが超重要らしい。
  • ノンブロッキングなAsyncJDBCDriverがまだないのがつらいけど、次のJDKに入る(??)

Java 8: The Good, the Bad, and the Ugly

https://www.slideshare.net/BrianVermeer/java-8-the-good-the-bad-and-the-ugly-jbcnconf-2017

Java 8のラムダとかストリームとか良し悪し、ワークアラウンド的なノウハウなどを紹介するセッション。 資料もスタイリッシュっぽいし、話も軽快そうだし、割と実践的な内容だった気がします。

ただ、隣の人が「半ケツかよ!」というぐらいこっちのイスの座面を占有するわ、そこからさらに足を広げるわ、定期的に足の上下運動をするわで、セッション内容が全く頭にはいらず無念。

まあ、資料を読めばいいかと。

Vectors with Values on the JVM

Project Panama / Valhalla系の低レイヤのセッション。 へーとかふーんとか聞いてましたが、メモを取ったり説明するほど理解できてません。 とりあえず、リンクだけ貼ってお茶を濁します。

Changes to the JDK Release Model

物議を醸しているリリース/サポート話ですね。 きしださんをはじめ他の方がまとめてくださってるのでまとまった情報としてはそちらをご参照ください。

あと、個人的にTwitterに流したツイートを載せておきます。

本日のディナー

最終日のディナーはもちろん、日本人参加者によるJavaOneの締めとして毎年恒例になっている、通称「蟹One」です。

f:id:nobeans:20171005221121j:plain:h300

日本的な蟹料理に慣れ親しんだ人間として、蟹への冒涜かと憤ってしまう勢いで油まみれにこってり炒められた蟹を、手を油だらけにしながら一人一杯いただきます。 手がありえないほど油だらけでベタベタになるのでビールはほぼ進まないけれども、これ以上ないぐらいビールのお供的な味である、というダブルバインドに苛まれながら、ひたすら蟹を貪ります。 油が冷えたら負けなので、ヤケドに留意しつつ熱々のうちにただひたすらに貪るのがポイントです。

f:id:nobeans:20171005200325j:plain:h300 f:id:nobeans:20171005193047j:plain:w300

これにて全日程終了です。

f:id:nobeans:20171005184955j:plain:h300


  1. なお、昨年はスターウォーズだったそうです。

  2. カラテマスターなのになぜかカンフー着を着用してるのはよくある残念な誤解なのか安価なカラテ道着の入手が難しかったのか。

JavaOne 2017 レポート 10/4 Day-4 Moscone会場最終日

翌日の最終日(Day-5)はMariottホテルの会議室がセッション会場となるので、Moscone Westに通うのはこの日が最後です。 そろそろ終わりもみえてきて、並行して会場撤収なども始まるので、この辺りからだんだん寂しい雰囲気が漂い始めます。

f:id:nobeans:20171004183037j:plain:w300

Polyglot Adventures for the Modern Java Developers

モダンなJava開発プロジェクトを進めるために色々な言語を適材適所で使おう、という言語/ツールの紹介セッション。

  • どの言語がベストというのはない。それぞれが特定の領域で強みを持っている、というだけ
    • だから、適材適所で臆せずに混ぜ込んで使おう
  • Setup-as-code
  • Build-as-code
    • Mavenは良い。ただし、Gradleは100倍速い(?)
      • Gradleはとても柔軟で、なんでもビルドできる
      • 色々な言語を混ぜ込んだプロジェクトでもビルドが簡単
  • Main-as-code
    • メイン言語としてはJavaで間違いない
    • ただし、Kotlinもメイン言語として考慮に値する (まさかのKotlin推し)
      • ScalaとかClojureとかじゃなくて、なぜKotlin?
        • Java開発者が学びやすい
        • バランスが良い
        • null安全性、シンタックスシュガー、etc.
        • JDK 6互換性
        • ライブラリサイズが小さい
        • IDE/ツールサポートが良い
  • Frontend-as-code
    • JavaScript一択
      • TypeScript or (ECMAScript2015 + Babel)
      • node + npm + webbpack
  • Test-as-code
    • unit/integrationテストには、Groovy/Spock
      • パラメタライズドテストが強力で読みやすい
    • 負荷テストには、Scala/Gatling
      • CLIで実行して、クールなHTMLレポートが出力できる
  • Pipeline-as-code
    • Jenkins 2からJenkinsfileにGroovy DSLでかけるようになった便利になった
  • Infrastructure-as-code
  • Documentation-as-code
    • Asciidoc + AsciidoctorJ + Gradle
  • Architecture-as-code
    • Structurizr
    • QAvalidator
      • バリデーションできる(?)
  • Presentation-as-code
  • 「色々な言語やツールを使おうとすると学習コストがーという人がいるけど、実際やってみたら確かにそういう面もあるけど、トータルでハッピーでしたよ」

How Languages Influence Each Other: Reflections on 14 Years of Apache Groovy

f:id:nobeans:20171004104215j:plain:w300

我らがGroovyのProject Lead(Apache配下になってからは正確にはPMC Chair)であるGuillaume Laforge氏による、Groovyが誕生してから14年間における、他の言語との影響の相互作用について紹介するセッション。 なお、あくまでセッションメモなのでそれは事実と違う!などクレームはご遠慮ください。

  • Groovy
  • Groovyが他の言語から受けた影響
    • Smalltalkから
      • (初期の)クロージャの引数宣言部の区切り
        • 最初Smalltalkと同じくパイプ記号だったが、{ a = 1 | 2 | a * 23 }と書いた時に、1 | 22 | a * 23のどっちがビット演算子でどっちが引数宣言部区切りなのか区別できないので、現在の->に変えた。
      • 名前付きパラメータ
      • メソッド呼び出しのカッコを省略できる
      • コレクション操作のメソッド名 collect / inject
    • Pythonから
      • リストやマップの[], [a: 1]というリテラル記法
  • Groovyから他の言語に与えた影響
    • Trailing Closure to Swift, Kotlin
      • 最後のクロージャ引数がカッコの外に出してかけるやつ
      • Groovyでは特に名前がなかったけど、Swiftで「Trailing Closures」という名前がついたので今後そう呼ぶことにする(!?)
    • Range to Swift
      • Range自体は元々Rubyにあったけど、1..3(=1,2,3)、1...3(=1,2)の後者の記法を、Groovyでは1..<3と直感的にわかりやすくした。この記法がSwiftへ
    • Spaceship演算子(<=>) to PHP, Ceylon, Ruby
    • 色々 to Kotlin
      • クロージャ文法
      • クロージャの暗黙変数it
      • Builderのコンセプト
        • クロージャDSLを書いてメソッドミッシングをトリガとして情報を構築するやつ
      • AST変換 (@Immutable, @Delegate, @Lazy)
      • メソッドを使った演算子オーバロード
        • +plus()のシンタックシュガーであり、plus()をオーバロードして挙動を変えられる、というやつ
      • セミコロンが省略できる
      • nullセーフ演算子(?.)
      • エルビス演算子(?:)
        • gccでは3項演算子の第2項が省略できる、というのが元祖だけど、演算子化して「エルビス」って言い出したのはGroovyが最初
      • asを使った別名インポート
  • 言語同士はインスパイアしあう関係にある
    • パーフェクトな言語はない
    • でもみんな改善し続けてるよ
  • Q&A
    • Q: Groovyのswitchは、Java 7でやっと対応したString以外にもなんでもマッチングできて便利だけど、あれが各言語でのパターンマッチングに影響を与えたのかな?
      • A: わかりません。ちなみに、Groovyでもここ10年くらいパターンマッチング実現しようと頑張ってるけど、全然完成してないです。
    • Q: GroovyのJava 8シンタックスへの追随はいつになる?
      • A: ちょうど新しいパーサ(Parrot)を入れた2.6-alphaを出したところだけど、これが正式リリースされたら、Java 8のラムダ記法もクロージャとしてパースできるようになる予定。
    • Q: Project Amberとかで、6ヶ月ごとに新しいシンタックス出てきたら追随大変じゃない?
      • A: わかりません。まあ、新しいシンタックスへの対応はすぐには難しいかもだけど、動かすこと自体はできるんじゃないかと(よく聞き取れず)
    • Q: データサイエンス分野ではPythonが大人気だけど、なんでGroovyはその分野で使われないの?
      • A: (よく聞き取れず)
    • Q: Jigsaw対応はどうなってるの?
      • A: これはかなりの難題です。Jigsaw対応第一弾は2.6としてリリース予定ですが、一応動くけど警告が出る、という段階です。完全な対応にはGroovy自体のモジュール構成を破壊的に変更しないといけません。なので、メジャーアップデートとなる3.0での完全対応を目指すことになるでしょう。その辺も含めて今まさに検討&対応中です。

Graal VM: High-Performance Polyglot Runtime

Graal(グラール)というHotspotの代替的な(?)実行環境の説明セッション。 JavaOneで初めてGraalという単語自体を認識した程度の情弱なのですが、なんだか一部の日本人参加者的に要注目らしいので、急遽聴講してみました。 そのうちJJUGとかで他の参加者の人から詳しい日本語情報が出てくるようなので正座してお待ちしております。

  • Graal=Polyglotからinteroperableな実行環境
  • Streamを使ったベンチマーク
    • mapを1つ使ったコード
      • Hotspot: 40ns
      • Graal: 11ns
    • mapをさらに2つ追加すると
      • Hotspot: 200ns
      • Graal: 11ns (!!!!!)
  • npm, ruby, node, scalaとかもサポート
  • ineroperableなので、JavaScriptからJavaやRなども呼べる
    • Rを呼ぶ場合、初回は裏でRプロセスを起動するので遅いけど、2回目以降は速くなる
  • JavaScriptの場合、Chromeの開発者ツールでDebugできる
    • (仕組みよくわからず)
  • Visulal VMが同梱されてる
  • SubstrateVM
    • Javaをプリコンパイルして動かせる
    • Hotspotではなく、svmというVM上で実行する
    • メモリフットプリントが小さい&超速い
  • すでにTwitterでは本番運用に投入してる
    • Finagle/Thrift

Testing Containers with TestContainers: There and Back Again

Dockerなどを使ってインテグレーションテストをする場合に便利なTestContainersというライブラリを紹介するセッション。 興味のあるセッションが見つからず苦し紛れで選択してみました。 が、昼ごはん食べながら気を抜いて聞いてた&あまり興味持ってなかった&「テストとは〜」みたいな前置き話が長くて小難しく聞こえた、のでメモはあまり取ってません。

  • development, production, integration-testで環境が違うの大変
  • そこでDocker!
  • でも、内部ポートが毎回違うとか大変なことがある(?)
  • そこでTestContainers
    • (コンテナのAPIを隠蔽したライブラリっぽい雰囲気)
    • (コンテナクラスを使って、コンテナの設定/挙動や相互作用をコントロールできるようだ)
    • (docker-composeであまり困ってないけど)
  • Spockサポートはこれから (?)
    • (と思ったら誤解だったらしく、すでに普通にSpockで使えますよ、とTwitterで教えてもらいました)

TestContainers: Integration Testing Without the Hassle

https://www.slideshare.net/arhan/javaone-2017-testcontainers-integration-testing-without-the-hassle

なぜか2連続でTestContainersのセッションがあったのですが、ついうっかり聴講しました。 内容的には重複しているというか、むしろこっちの方がわかりやすくて、こっちだけでよかった感があります。 おかげでだいぶ理解できた気がします。

  • ユニットテストだけではなく、インテグレーションテストも重要だよね
    • (文脈的に、インテグレーションテスト=NWやノード構成を含めた環境上でのシステムテストを指しているっぽい雰囲気)
  • でも、インテグレーションテストには問題もある
    • 時間がかかる
    • セットアップが大変
  • インテグレーションテストに求められる6つのこと
    • Reproducible environment
    • Both for development and CI
    • Isolated
    • As real as possible
    • Cross-platform
    • Easy to set up, use & maintain
  • そこで、docker&docker-compose!
    • but
      • サーバのポート番号がdocker-compose.ymlにハードコードされる
      • テスト実行時に別途起動しないといけない
  • そこで、TestContainers!
    • 複数のコンテナをプログラマティックにコントロールd家いるので、片方が死んでいるときのテスト、とか色々環境を変えつつテストできる
    • 外部のdocker-compose.ymlをそのまま使うこともできるし、APIからプログラマティックに設定もできる
  • 挙動イメージ
    • インストール済みのdocker環境を見つけて、
    • docker-composeを使ってコンテナを起動して、
    • テストを実行して、
    • テスト終了時にコンテナも終了する
  • ポート番号問題の解決
    • コンテナの内部ポートをexposeするポート番号は空いているところを自動的に使ってくれる
    • Container#getMappedPort()で実際にexposeされたポート番号が取れる
  • MockServerContainerを使うと任意のサーバのモックを実装できる
  • Javaagentのバイトコード変換で色々できる
    • JettyHandlerに介入して、独自ヘッダを入れるようにしたり
  • Q&A
    • Q: コンテナの起動コストは?
      • A: どのイメージを使うかによります。
    • Q: docker in dockerの環境で使える?
      • A: yes. ドキュメントに書いてます。

Jump-start Your Microservices Development with Java EE

とりあえずJava EE系の何かを聞いてみようぐらいのモチベーションで入ってみました。 混んでいた&集中力が低下していたので、内容はあまり頭に入っていない&メモがありません。

どうやら、EclipseのMicroProfileに関する紹介セッションだった雰囲気。

Best Practices for Developing and Deploying Java Application with Docker

https://www.slideshare.net/EricSmalling1/best-practices-for-developing-deploying-java-applications-with-docker

開発時や本番運用でDockerコンテナ上でJavaアプリケーションを実行する場合のベストプラクティスを紹介するセッション。 具体的なパラメータは参考になるところもありましたが、あまり目新しいものはなかったので、メモは省略。

Building and Testing Java 9 Applications with Gradle

Cedric氏による2つ目のGradleセッション。 Jigsaw対応のプロダクトをGradleでビルドする方法の説明です。

現状ではまだGradle側のJigsawサポートも限定的で、 相当なバッドノウハウを駆使しないとビルドができないようです。 正直、ややこしいわ&めんどくさいわで、相当ツラそうな感じです。 最初はメモを取ってましたが「色々大変そう」「実際に手を動かす時に資料を見ればいいか」という気持ちになり後半いい加減です。

  • Jigsaw
    • Reliable config --- "Good-bye classpath"
    • Strong encupsulation --- "Good-bye com.sun"
    • 移行時の注意
      • 2つのモジュールが同じパッケージをexportできない
      • 2つのモジュールが同じパッケージを内部パッケージとして持ってもいけない
  • GradleのJigsaw対応状況
  • Gradleを使ったプロダクトのJigsaw対応のサンプル
    • 課題
      • テストでのモジュールの依存関係が問題になる
        • loadClassしたらモジュール内のprivateなクラスもロードできる?
      • Gradleのapi/implementationコンフィギュレーションとJigsawのrequiresなどの依存性定義をうまく合わせる必要がある
    • モジュールを今のGradleでビルドするにはトリッキーなバッドノウハウが必要
    • テストはコンパイルでmainmジュールに結合(patch)するのが楽&早い
    • テスト実行時にALL-MODULE-PATH
    • (......色々面倒なことはわかった......)
  • 実験的にJigsawプラグインを作ってみた
    • クラスパスを強引にモジュールパスとして扱う(?)
  • Multi-release JAR
    • Java 8/9のそれぞれで動くJARを生成するには、さらに色々仕込みが必要
      • 1つのJARないに別のターゲットのクラスを共存できる(?)
    • (......まだまだ色々地獄だなぁという印象.....)
  • Minimal Runtime Image
    • jlinkを使って最小限の実行イメージを作る

本日のディナー

JavaOneチケットに含まれる今年のOracle主催パーティは、メジャーリーグサンフランシスコ・ジャイアンツの本拠地であるAT&Tパークでの野外ライブでした。 以前はトレジャーアイランドでしたが、昨年度からAT&Tパークになったそうです。

f:id:nobeans:20171004190328j:plain:w300 f:id:nobeans:20171004191831j:plain:w300

普通に野球の試合があるとき用の売店で、無限ホットドッグ・ナチョス・ビールが振る舞われます。

f:id:nobeans:20171004200627j:plain:h300 f:id:nobeans:20171004191641j:plain:w300

おまけ

セッションの合間に会場をうろついてたDukeを発見して初のツーショット記念写真の撮影に成功しました(photo taken by skrbさん)。

f:id:nobeans:20171004132650j:plain:w300

JavaOne 2017 レポート 10/3 Day-3 技術セッション+謎のキーノート

さて、もう10日は経っていますが、粛々と3日目のレポートです。

Refactoring Design Patterns the Functional Way (in Scala)

ちょっと最初の15分ほど遅刻してしまいました。 GoFデザインパターンをいくつかピックアップして、関数型言語として良い書き方にリファクタリングしよう!という話です。

  • 良い書き方とは?
    • 以下の4つを満たす書き方
      • No Side-effects
      • No Mutation
      • No mutable SZtate
      • Declarativity
  • GoFデザインパターンリファクタリングしよう
    • Mutable Stateを取り除くケース
      • Singleton
        • Global Access → Local化
        • Mutable State → Immutable化
      • Builder
      • Chain of Responsibility
    • Mutatorを取り除くケース
      • @tailrecとか使う(?)
    • Side Effectsを取り除く
      • Observer
        • 副作用を分離するとテストが簡単になる
    • Declarative(宣言的)なコード
      • アクションを呼ぶようなコード書かない

Immutable Collections

「不変コレクション」についてのディープ目のセッション。

まずは、Java標準APIやcommons系ライブラリ、Scala、Closureなどでの不変コレクションの現状を整理。 そのあとは、Hash Array Mapped Tries(HAMTs)というトライ木を使ったアルゴリズムで効率の良い不変コレクションを実装してみたよ、みたいな話でした。

Githubリポジトリは多分これ: https://github.com/PaulSandoz/per

Modules in One Lesson

JavaのプロジェクトリードであるMark Reinhold氏のライブコーディングセッション。

f:id:nobeans:20171003110106j:plain:w300

以下、ライブコーディングを見ながらとったメモ。

  • jlinkコマンドで必要最小限のJVMが作れる
    • --outputオプションで、bin配下に好きな名前のアプリ起動コマンドも作れる
  • 実行時例外
    • 依存先モジュールがモジュールパス上に見つからないと、FindExceptionがスローされる
    • 依存先モジュールで、使おうとしているメソッドがexportsされていない場合は、IllegalAccessExceptionがスローされる

Building from Minutes to Seconds: Maximizing Incrementality with Gradle

Groovyコミッタであり、@CompileStaticを始め数々の性能向上を実現してきた、現在はGradle, Inc.にお勤めのCedric氏のGradleセッション。

f:id:nobeans:20171003121146j:plain:w300

Gradleにおけるビルド時間短縮のための4つの機能について説明。

  • なぜビルド時間を短縮するのか
    • 1分でもビルドが早くなると、人件費とかコストに直結する
  • Incremental Builds (無駄なタスク実行を避ける)
    • ソースコードが変更されてない場合はcompileタスクやtestタスクを実行する必要はない
    • input/outputを明示すると、それらで変更有無を電波できるので最小限のビルドができる
    • タスクごとにinputs/outputsを宣言しておく
    • 自前でタスククラスを実装する場合は、executeメソッドの実装でinputsをチェックしてタスクの実行/スキップを分岐する必要がある
  • Compile Avoidance (無駄なコンパイルを避ける?)
    • コンパイル時の依存関係が漏れ出す問題
      • (例)あるライブラリで実装詳細としてguavaを使っている場合、compileコンフィギューレーションにguavaを依存関係として定義して使うと...
        • 下流(=利用する側)のcompileコンフィギュレーションに、推移的にguavaが漏れ出してくる
        • ライブラリの実装詳細として依存関係の変更で、下流の依存関係が破壊されるリスクがある
      • Gradle 3.4からapi/implementationという分け方を導入した
    • 依存関係においてコンパイル/ランタイムのクラスパスは異なるセマンティクスを持つ
      • コンパイル: publicのシグネチャだけあればOK
      • ランタイム: クラス&リソースの全てが必要
      • Gradleはこの違いを表現できる
      • プロジェクトをビルドするときに無関係な変更を無視する
  • Incremental Compilation (変更があったファイルとそれに関連する部分だけをコンパイルする)
    • どうやるかはコンパイル対象の言語依存
    • Gradleは、JavaのIncremental Compilationはサポートしてる(デフォルトOFF)
      • デフォルトでONにするのはGradle 5.xぐらいになりそう
    • Q: サードパーティライブラリの定数を使っているクラスがあったとして、定数の値が変わっていたら、利用側のコンパイルも必要だと思う?
      • A: 必要。実はクラスファイルには値自体が展開されて保持されている。
        • JLSでは「コンスタントプールに入れる必要はない」と書いてあるけど、実際現状では展開されている
        • このため、Gradleでは、全てのクラスのバイトコードを解析して変更必要性を検知している(力技)
      • (以降、時間切れで割愛)
    • Annotation Processor
  • Variant-aware dependency management

Migrating to Modules

再びMark Reinholdのライブコーディング。

以下、ライブコーディングを見ながらとったメモ。

  • Automatic Modules
    • モジュール対応していないサードパーティライブラリのJARファイルなどは「Automatic Modules」として扱われる
      • JARファイルの名前規約でモジュール名が決まる
        • foo-bar.jar → foo.barモジュール
      • 依存関係上に登場する全てのモジュールをrequiresしているものとして扱う
  • エンティティやDTOなど、データバインディングフレームワークなどに使われるクラスは自モジュール外であるフレームワークから使えるようにexportsする必要がある
  • 実行時にjavaコマンドに--show-module-resolutionオプションをつけると、モジュールの解決結果が標準出力に出力される
  • jdepsが便利
    • -s/-summaryオプションをつけて実行すると、そのモジュールが必要としている他のモジュールが出力される
    • モジュール非対応のJARファイルにjdeps --generate-module-info <出力するmodule-info.javaファイルのパス> <JARファイルのパス>を実行すると、指定したファイル名でmodule-info.javaの雛形が生成される
  • インタフェースに対する実装クラスはimplパッケージなどにひとまとめにしておくと、モジュール外から隠蔽しやすい
  • requires transitive
    • requires m1;という依存関係を持つモジュールm2を、モジュールm3からrequires transitive m2;と推移的に依存しておくと、モジュールm3でrequires m2;としたときに、m3はm1とm2に依存していることになる
    • m1で提供するインタフェースをm2で実装しているようなときに、m2だけ指定すれば良いので楽 (Mavenとかの推移的依存関係みたいな感じ)

JUnit 5: New Opportunities for Testing on the JVM

JUnit 5の概要説明のセッション。

  • 挙手コーナ
    • 「テストみんな書いてる?」→ほぼ全員書いてる
    • JUnit 4?」→ほぼ全員
    • JUnit 5?」→ぽつぽつと
    • TestNG?」→なぜか笑い
    • 「Spock?」→数名
    • (他、忘れた)
  • JUnit 5はクラウドファンディングで資金を募って一から再設計&実装された
  • Java 8以上サポート (Java 7以前は未サポート)

  • JUnit 5 = Platform + Jupiter + Vintage

    • 大きく分けて3つに分かれている
      • f:id:nobeans:20171003151237j:plain:w300
      • Platform
        • テスト自体の実行エンジン
      • Jupiter
        • JUnit 5としてのテストコードを書くためのフロントエンド
      • Vintage
        • JUnit 3/4を実行するためのレガシーサポートフロントエンド
    • 独自形式のテストコードをJUnit 5 Platformで実行させるためのフロントエンドをサードパーティで提供できる構造
  • Eclipseを使ったデモ

    • Ruleはpublicフィールドに
    • Tagを使ってテストメソッドを好きに分類して、タグの種類ごとに選択式に実行できる
    • テストメソッドの引数にTestInfoを受け取れる。テスト名とかタグ名とかを動的に取り出せる
    • @TestNameでテスト名がわりに任意の文章を記述できる
      • レポートではテストメソッドの代わりにこの文章が表示される
        • 日本語テストメソッド名の制約を気にしなくてよくなった(句読点、先頭数字、とか)
      • 絵文字も対応(なぜか超盛り上がる)
    • テストクラスがネストでかける
      • フィクスチャごとにグルーピングすると便利
      • 結果レポートでもネスト構造でドリルダウン表示できる
    • Jupiterが提供するパラメタライズドテストの記法は、Spock使いとしてはやはりうーんという感想

Developer Keynote

「Live for the Code」という題目での位置付けのよくわからないキーノート。

f:id:nobeans:20171003161717j:plain:w300

Oracleクラウドを使うとこんなに簡単にサービスできますよー的な感じだったっぽい。 いわゆるスポンサー枠というか宣伝メインっぽい枠でした。 みんな大好きSlackの人が壇上に登場してました。

Automated Functional Web Testing on the JVM with Geb

CERN(欧州原子核研究機構)の人による、ブラウザを使ったテストが簡単にかけるGeb(じぇぶ)の入門的な紹介セッション。 内容的には全部知っていますが、応援の気持ちで聴講してきました。

Gebについて気になる人は、ちょうど同じ頃に公開されたこちらの記事などがおすすめです。

本日のディナー

話題沸騰(?)のメキシカンファストフード「チポトレ」のブリトーボウル(丼)にチャレンジしてみました。

f:id:nobeans:20171003200310j:plain:w300

なお、実食した結果↓

その後、Westfield(Powell Station前のショッピングモール)の4Fにあるスポーツバー的なところで、ビールと軽食をいただきました。

f:id:nobeans:20171003203412j:plain:w300