「テストでは品質は上がらない」のは確かにそうなんだけど、品質を上げるためにテストは不要かというとそうではない

はじめに

という古くから伝わる名言に関して、個人的にもかなり「なるほど」という学びがあり、頭が整理されたきっかけになった記憶があります。

ただ、この名言がうっかりすると全然違う結論を導くために使われうるなぁという危うさを感じていて、久しぶりにツイッター(X)で目にしたタイミングでふと思い出したので、その気持ちを記しておきたい所存です。

どこに危うさを感じているのか

まず気になるのはこれ。

  • (A) この言説が品質テストをdisるために誤用されてはいないか

あと、ふわっと気になるのは、以下の2点です。

  • (B) テストで見つかった問題に対してどう対処(=プログラミング)するのかが重要だという話がわかっているのか
  • (C) テスト前の実装作業(=プログラミング)においてどうやってるのかが死ぬほど重要だという話がわかっているのか

個人的な解釈

元の発言の正しいお気持ちは直接伺ったことはないのでわかりませんが、個人的には次のように理解しています。

  • テストとは実装された振る舞いを観測をしつつ、期待される挙動との差分がないかをチェックすることなので、いくらどのような観測をしたところで、対象物が改善されることはない
  • テストという観測手段によって、期待とは異なる挙動が見つかった時に、それを修正する作業(=プログラミング)を通して、対象は改善される
  • (さらに追加するとすれば) 元々の実装作業として、適切なスキルを持った人が実装しているか、だったり、よりよいプラクティスを導入しているか、だったり、実装(=プログラミング)上の頑張りによってテストで観測されても問題が見つからないように品質をあらかじめ確保しておくのが重要である

それを踏まえた上での解釈上の危うさ

(A) この言説が品質テストをdisるために誤用されてはいないか

「チェックのためにテストは当然必要なんだけど、品質を上げる作業自体はプログラミングにあるんよ?」という話のはずが、「品質を上げるためにプログラミングを頑張ればテストなんて不要になるんや」と誤解されてないですよね、という話です。

これは単純に国語的な読解力に対する懸念です。

「いや、そんな解釈をする人なんて普通いないでしょ」と思いたいところですが、最近ではそういう解釈も個人ごとに色々多様性がある世の中ですし、あまり楽観的にはいられないのでは...という懸念がある、という心配性おじさんの妄想なのですが、いや意外と危うい気がしているので書いておきたいなぁ、というそういう気持ちです。 完璧に理解されているみなさまは生暖かくスルーしていただいていいんですよ...。

(B) テストで見つかった問題に対してどう対処(=プログラミング)するのかが重要だという話がわかっているのか

たとえば、見つかったバグに対してその場しのぎのワークアラウンドコードを仕込むことで指摘された事象自体は改善されたように見えるかもしれません。 しかし、そのコードがたとえば「ひどい変数/関数名を使っている」「概念上無関係な関数に意図のわかりづらいコードを追加している」とかの問題を孕んでいると、最終的なソースコードとしての品質が上がったのか?という点でかなり疑問がある結果になってしまいます。 そのバグは修正されたかもしれないけど、コードの可読性が低下して(品質的な用語でいえば)保守性が低下してしまった、という見方もありえます。

つまり、テストで発見された品質上の問題を解消するための修正作業(=プログラミング)で下手を打ったら、それは品質が向上したとは言い難い別の世界線に遷移してるだけという可能性もある、という話ですね。

(C) テスト前の実装作業(=プログラミング)においてどうやってるのかが死ぬほど重要だという話がわかっているのか

これについては、本質的にはもっとも重要な話で、基本的にこのレベルで成果物の最終的な品質が決まる、という風に個人的には思ってますが、じゃあ何をすればそこがいい感じになるのか、というのは観点が多岐に渡るので、今回はスルーします。

おわりに

というわけで、テストでは直接品質はあがらないのですが、テストで問題を見つけることで品質を上げるための修正(=プログラミング)をするチャンスは生まれますし、そこで品質を上げることができるかはその修正(=プログラミング)の内容による、という話でありつつ、そもそもテスト以前の実装フェーズでのプログラミングで品質を上げるというのが実は一番重要なんですよね、という構造になっているというその辺りの気持ちが伝わればうれしいです。

補足

元のTwitter(X)の議論は「テストコードの存在が直接品質を担保しているわけではないので、テストコードがたくさんある=品質を向上させている、ではない」「バグの検出に役立たない冗長なテストコードはむしろ害悪」という話だと思っていて、今回の記事はそこは全然否定していないというか、全面的に同意です。

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 全レポートへのリンクまとめ

JavaOne 2017 レポートのリンクをまとめておきます。

nobeans.hatenablog.com

nobeans.hatenablog.com

nobeans.hatenablog.com

nobeans.hatenablog.com

nobeans.hatenablog.com

nobeans.hatenablog.com

nobeans.hatenablog.com

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