JavaOne2014 4日目メモ (10/1)

サンフランシスコ市街地のスーパーに水を買いにいったら、キャベツ太郎が売ってたので思わず写真を撮る。2.49ドル、日本でいうとポッキーよりも高級なお菓子になっている。

f:id:n_agetsuma:20141006190933p:plain,w400

以下のようなセッションに参加。

Everything You Wanted to Know About Writing Async, Concurrent HTTP Apps in Java [CON3712]

非同期でかつノンブロッキングI/Oを行うHTTPクライアントをどうやって書くか紹介するセッション。

非同期およびノンブロッキングに関する振り返り

  • 非同期
    • I/O中のスレッドはブロックされるが、完了前に応答を返してくれるので別の仕事が並行でできる
    • javaではFutureが帰ってくるような実装で実現
  • ノンブロッキング
    • I/O中にスレッドをブロックしない。selectorに登録し、データ利用可能時に通知をもらうモデル
    • javaではNIOパッケージで実装できる

今のところの実現手段

いろんなREST APIから情報を持ってきて組み立てるシステムでは、毎回同期でかつブロックして待ってたら遅いので、非同期かつノンブロッキングが比較的簡単に実装できるのはとても大切。

Principles of Evolutionary Architecture [CON4580]

継続的にアーキテクチャを進化させていく上での原理・原則を紹介するセッション。

進化するアーキテクチャの原則
  • 最終責任時点 (last responsible moment)
    • その時点で集まる最大限の情報を集め、複雑性による技術的負債は最小限に
    • 優先度を重視して、早めに決断する
  • 発展的なアーキテクトと開発
    • データのライフサイクルとオーナーを明確にする
    • 軽量なツールとドキュメント
    • ソフトウェアの内部品質は変更が容易かどうかで評価すべき
  • ポステルの法則
    • 送信側は慎重に、受信側は寛容に。バリデーションは必要な範囲で。
  • 設計に対するテスタビリティ
    • テスタビリティを向上させることで、より最適な設計に近づく
    • メッセージングシステムは、あくまで通信のために使い、ビジネスロジックとしては使わない
    • 振る舞いや性能だけでなく、規約もテストする
  • コンウェイの法則
    • それぞれの組織がデザインするシステムは、その組織間のコミュニケーション構造を反映する
    • コミュニケーションの欠落は、複雑な統合に繋がる
    • 製品は組織と同じ形になるので、変えたければ組織か製品自体を変える
実現のためのテクニック
  • データベースリファクタリング
    • 大きな変更を小さく分割して、バージョン管理もする
  • 継続的デリバリー
    • デプロイって作業は本来退屈じゃなきゃいけない!
  • システムインタフェース規約のテスト
    • 個々のシステムが独立して作業できるようなインタフェース規約
    • ポステルの法則も意識しながら
    • 古来よりアーキテクトが持つ役割の一つ

今後の仕事で判断に迷ったときの参考にしようと思う。

Plugging into the Java Compiler [CON4265]

Googleが作ってるValueObject実装のAutoValue、Squireが作ってるDIの実装daggerと、それぞれの技術の基となっているアノテーションプロセッサの話

AutoValue
  • イミュータブルなValueObjectのコード記述を簡潔にすることが目的
    • コンストラクタ/equals()/toString()/hashCode()を各クラス毎に書くのは冗長
    • @AutoValueを付与して、アノテーションプロセッサによりソースを生成
    • 抽象クラスにAutoValue_を付与したクラスのソースが生成される

pom.xmlには以下を追加

<dependency>
    <groupId>com.google.auto.value</groupId>
    <artifactId>auto-value</artifactId>
    <version>1.0-rc1</version>
    <scope>provided</scope>
</dependency>

@AutoValueを付与する

@AuthValue public abstract class Address {
    public abstract String streetAddress();
    public abstract int postCode();

    public static  Address create (String atreetAddress, int postCode) {
        return new AutoValue_Address(streetAddress, postCode);
    }
}

ValueObject生成時にはcreateメソッドを実行する

Address a = Address.create("some address", "xxx-xxxx");

lombokの@Value異なり、AutoValueではコンパイラの処理に割り込んでバイトコードを追加したりなんてことはせずに、シンプルにソースコードを生成する。実際にNetBeansで試してみると、以下のようにソースファイルが出てくる。
f:id:n_agetsuma:20141006172730p:plain

AutoValueを使うとあくまでソースを生成しているだけなので、仮にAutoValue自体にバグがあってもすぐわかる。lombokで得る効率よりも、バイトコード生成の黒魔術感への不安が勝るプロジェクトで使えそう。

dagger
  • AutoValueと同様にアノテーションプロセッサによるコード生成により静的にDIの解決を行う
  • なぜDIをアノテーションプロセッサで行うか?
    • 性能 : リフレクションを使わないので早い
    • 開発容易性 : 実行時ではなく、コンパイル時に依存性解決エラーがわかる
    • 設計の明瞭性 : コードをみれば依存性解決結果がわかる。DIコンテナによる連結は"magic map"でわかりにくい
  • 現在のリリースは1.xで、現在2.0の開発中

dagger1.0のコード例についてはマニュアルが詳しい。

アノテーションプロセッサでできること/できないこと
  • できる
    • アノテーションを読んで、ソースやメタファイル(XML, META-INF/services)などが出力可能
    • 間違ってたら、コンパイル時に指摘される。実行時まで引き延ばさない。
  • できない
    • 既存のクラス自体を変更することはできない
    • ソースを吐くのは、あくまで別のクラスとして出力が必要
  • アノテーションプロセッサの良いところ
    • エラーチェックが早い段階でできる
    • ランタイム時にリフレクション等の処理をしないので、性能が挙がる
    • 見れるソースコードが出力できる。黒魔術にならない

JJUG 2013 Springで@kimuchi583さんから紹介のあったType annotationの話と組み合わせて考えても、これからの品質・生産性向上ツールアノテーションを読み込んで何かするのが軽量で使いやすいと思った。

Debt and Deprecation [CON6377]

Java Day Tokyo 2014やJJUG CCC 2014 Springでもラムダ式やストリームAPIについて講演されたStuart Marksさんが、Dr.Deprecator(非推奨博士?)として登場。

内容はJavaの『@Deprecated - 非推奨API』に関する振り返りと、現在複数の意味合いを持つDeprecatedを新しい言葉に置き換える提案を紹介するセッション。

今までの非推奨の振り返り
  • javadocタグとして@deprecatedが登場したのはJDK1.1まで遡る
  • JDK1.1において古いAPIに取ってかわる、多くの新しいAPIが盛り込まれた
  • 古いAPIから新しいAPIへの移行を促進するために非推奨は誕生した
既存の『非推奨』の使い方
  • 一口に非推奨と言っても、それぞれ趣旨が異なる
    • APIの実行によりエラーを招く (Thread.stopなど)
    • 設計上の欠陥 (java.util.Dateの多くのメソッド)
    • philosophical (理念?) の変更 (JDK5からSystem.getenvが非推奨でなくなった)
非推奨を新しい言葉を使って再カテゴライズする提案

陳腐化(Obsolescence)したAPIは現在の非推奨API以外(例 Vector)にもたくさんある。非推奨と一つに丸めてしまうのではなく、適切な用語を再定義してカテゴライズする。

  • Condemned : 将来のリリースで削除や無効化するもの
  • Dangerous : バグやデータ損失を招くAPIであるもの
  • Superseded : 危険ではなく、削除される予定もないが、新しいコードでは新機能に置き換えた方が良いもの
  • Unimplemented : 実装されてないことを示す。UnsupportedOperationExceptionをランタイム例外としていきなり返さずに、ドキュメント上でわかりやすくする

例えば、Superseded(廃止)として現状は非推奨になっていないが、VectorやHashTableなどの古いコレクションクラスや、java.util.Timer/TimerTask(タスクが長時間かすると次の実行がずれるシングルスレッドモデルなので、ScheduledThreadPoolExecutorに置き換えた方が良い)がある。

Java9で削除検討中のAPI
  • java9でのjigsaw導入に伴い、java.beansモジュールと相互依存があるAPI
    • java.util.logging.LogManagerのaddPropertyChangeListener/removePropertyChangeListener
    • java.util.jar.Pack200.Packer/Unpackerの同上メソッド

これら提案はあくまで将来に向けたアイディアであり、Java9に向けて具体的な話はないが、ユーザとしてはすごく嬉しい提案。特にUnsupportedOperationExceptionは相当イラっとくるので、@Unimplementedによるコンパイル時警告が欲しい。