社内LTでゲームフレームワークPhaserについて話をしました

久しぶりのエントリになってしまいました。内容はどうあれアウトプットも大事にしていきたいのですが、ここ最近は社内のBacklogに閉じてしまっているのが悩ましいところです。

さて先日、社内でLT大会がありました。
テーマに縛りがなかったため、色んな話があって盛り上がり、面白かったです。

そこで自分はゲームフレームワークPhaserフェイザー)について話しました。
持ち時間は5分間なので、簡単に紹介して面白いよー、って話だったんで、内容は薄めです。そもそも最近ちょっと手を出しただけなので、深いことを話す知識は持ち合わせていないのですが…。

スライドは以下のURLで公開してます(実際に使ったものから少し修正を加えています)。

http://tq-jappy.github.io/slides/phaser.html

今回、新しい試みとして、プレゼンのスライド自体もPhaserを使って作りました(動作確認はChromeでのみ行っています)。

簡単な操作メモ。

ページ 操作 内容
全体 [←]キー 前のスライド
[→]キー 次のスライド
P.6 アニメーション [H][J][K][L]キー ガイコツが歩きます
(viのキーバインドと同じです)
[Z]キー かぼちゃの回転速度を上げる
(押す度に高速回転します)
[X]キー かぼちゃの回転速度をリセット
P.7 物理エンジン [Z]キー 物理エンジンを適用

※ スライド中の画像は公式のロゴ以外、ぴぽや倉庫様のものを使わせていただきました。

Phaser自体がHTMLとJavaScriptさえあれば動く環境なので、スライドもHTMLとJavaScriptで作っておくと、スライドとデモをシームレスに見せることができ、なおかつ、いつでも誰でもデモをその場で試せるのがポイントですね。
かなり昔のRuby会議で星一さんがStar Rubyについて話をした時に、スライドをご自身のゲームライブラリであるStar Rubyで作っていて、面白い手法だなぁと思っていたので、一度やってみたいと思っていたのでした。

ただ、急ぎで作ったのでバグが結構あります。

時間内に話さなかったことをQA形式にて。

Q. UnityとかCocos2d-xとかenchant.jsにしなかったのはなぜ?
A. 各サイトをざっと見て、Phaserが一番楽しそうだったので。また、UnityやCocos2d-xは日本語でもいっぱい情報があり、聴講者に知っている人がほとんどいなそうなものを紹介したかった、という意図もあります。

Q. UnityとかCocos2d-xとかenchant.jsとは何が違うの?
A. そこまで詳しくないので変に比較はできないですが、以前Pygameを触っていた時と比べると、Phaserの場合、複雑なゲームにも対応できる豊富なAPIを備えている一方で、初学者が楽しくゲーム開発するためのハードルも低いのが強みなのかなぁと思います。

「実戦での Scala ~ 6つの事例から知る Scala の勘所~」に参加してきた #jissenscala

スマートニュース様にて開催された「実戦での Scala 〜 6つの事例から知る Scala の勘所〜 - 実戦での Scala | Doorkeeper」に参加してきました。
簡単にですが、感想を書きたいと思います。

私とScala

いきなり「お前なんでここに来たんだ」という感じですが、実は私、Scalaは一行も書いたことがありません…。

Javaは仕事で使ってきたので、"Better Java"として(?)のScalaの最新動向をキャッチアップしたいという思いで、一線で活躍されている方々の生の知見を吸収すべく、参加した次第。

おかげで、今日の勉強会を通して、Scalaを勉強したいという意欲が沸々と高まってきたので、これから色々と学んでいきたいと思いました。まずはコップ本と逆引きレシピを購入するところからですね。

勉強会まとめ

細かいメモはしていましたが、複数人のスピーカーの方が共通して話していたので印象に残った部分に絞ってまとめました。

1. Scalaを学ぶ上でのポイント

大きいものは以下の2つなのかなと。

  • Future
  • Option

他にもいっぱいあるとは思うのですが、特にこの2つはきちんと身につけないとならないんだろうなぁと感じました。
並列処理を書く上で、forの内側でFutureを作るとパラレルのつもりがシリアルになってしまうなど、色々とハマリポイントもある事がわかり、参考になりました。

2. twirl

ScalaデファクトとなっているPlayのテンプレートエンジンです(読み方は皆さん悩まれてました)。ほとんどのお話の中で話題に挙がった印象。

「サーバサイドは堅く、フロントエンドは柔らかく(by 竹添さん)」とか、最近のSPA風なアーキテクチャからすると、テンプレートエンジンの出番ってどうなのかな?という気もしますが、静的型付けでコンパイラによってチェックされるというのはやはりメリットらしいです。
反面、デザイナー、HTMLコーダからすると辛い面もあるとのこと。

3. Scala勉強会

Scala技術者は少ないので、毎日30分のScala勉強会をしているという話も印象に残りました。

(何でもそうですが)何かを身につけるにはそれなりの学習コストが必要なんですね。というわけで、自分も始業前の30分はScalaの勉強に充てようかなと思った次第。

4. JavaからScala, LLからScala

Scalaの学習にあたり、JavaからではなくLLから入った人の方が案外すんなり身につくみたいな話がちょっと意外で印象に残りました。

実際はその人の素養やバックグラウンドが大きく影響しているとは思いますが、今日、色々と話を聴き、関数型言語パラダイムをしっかりと意識して勉強していくことが大事なんだろうなと感じました。

おわりに

感想は中身が薄くてアレなのですが、とても有用な勉強会となりました。業務アプリを作るならScalaはベストな選択(by 村石さん)みたいな話もあったので、自分もScalaを使いこなせるようになりたいなぁと思いました。

イベントの提供に関わった方、スピーカーの方、参加された方、会場提供いただいたスマートニュース様、ありがとうございました。

Jenkins Workflow Pluginを使ってGradleマルチプロジェクトのワークフローを組んでみた(WIP)

先日のJenkinsユーザ・カンファレンスの講演を受けて、Jenkins Workflow Pluginがすごく便利そうだったので、早速試してみました。

想定するプロジェクト構成

基本的にはGradleの階層型マルチプロジェクト構成で、その他にドキュメントのビルド(Sphinx)とCoffeeScript, Sassのコンパイル用のプロジェクトがあります。
ファイル構成を簡略化するとこんな感じです。

root/
  build.gradle
  settings.gradle
  common/
    build.gradle
  sub1/
    build.gradle
  sub2/
    build.gradle
  doc/
    Makefile
  ui/
    Gruntfile.coffee
    package.json

各プロジェクトの概要は、

  • root
    • rootプロジェクト
  • common
    • sub1, sub2の共通クラス
  • sub1
    • サブプロジェクトその1(commonに依存)
  • sub2
    • サブプロジェクトその2(commonに依存)
  • doc
    • ドキュメントビルド用プロジェクト(Sphinx関連のファイルが置いてある)
    • Javaプロジェクトではない。
  • ui

パッケージのための成果物はcommon+sub2で1つで1つ, common+sub2+doc+uiで計2つ。

現行のジョブの流れと課題

というわけで、それぞれのプロジェクトのビルドを1つのジョブにマッピングさせて、以下のようなパイプラインを組んでいます。

f:id:jappy:20150112230334p:plain

チェックアウトはパイプラインの最初の1回だけ行います。
そのため、パイプラインの先頭でチェックアウトしてきたソースコード類を他のジョブに引き継ぐために、Clone Workspace SCM Pluginを利用しています。

これはこれで運用は周りますが、設定のメンテナンスという観点で、以下のような課題がありました(一部は対策済み)。

  • 似たようなジョブがたくさんできる(common1-build, sub1-build, sub2-build)
  • Jenkinsのビューでジョブ一覧を見た時にパイプラインの状況が分かりにくい。
  • ジョブ間にまたがった同じ処理の設定が面倒。
  • 【Gradle特有の問題】sub1, sub2のビルドの際に、依存プロジェクト(common)に変更がなくても常に再ビルドされてしまう。
    • (原因)UP-TO-DATEとするかどうかは、デフォルトではファイルのフルパスで判断しているから、らしい(どこかで見た気がするけど曖昧…)。
    • 依存プロジェクトのビルドがすぐ終わるような場合はあまり気になりませんが、やはり同じプロジェクトのビルドはパイプライン中で1回だけで済ませるべきなので、-a オプションをつけて依存プロジェクトのビルドは後続ジョブでスキップするような回避をしています。

Jenkins Workflow Plugin

そこでJenkins Workflow Pluginを試しました。といっても、今は、このパイプラインを置き換えるというよりも、このプラグインで同等のことが実現できるかどうかの実験段階ですが。

インストール

いつも通りのプラグインの管理画面で「Workflow: Aggregator」をチェックしてインストールします。"Jenkins Workflow"でページ検索してもhitしないので注意。 その後Jenkinsを再起動してインストール完了。

Workflow Jobを作成

試しに以下のようなワークフロースクリプトを組んでみて、(とりあえずパッケージングの手前まで)動くことが確認できました。

なお、上記のパイプラインと完全に一致しているわけではないので注意。

node('java') {
    git url: "http://gitbucket-server:8080/git/hoge/root.git", branch: "develop"
    buildSubproject('common')
    archive excludes: '.git/**/*', includes: '**/*'
    
    parallel(sub1: {
        buildSubproject('sub1')
    }, sub2: {
        buildSubproject('sub2')
    }, doc: {
        dir('doc') {
            sh "make html"
        }
    })
 
    step([$class: 'ArtifactArchiver', artifacts: 'doc/_build/html/**/*'])
    step([$class: 'JUnitResultArchiver', testResults: '**/build/test-results/TEST-*.xml'])
}
 
node('nodejs') {
    unarchive mapping: ['ui/' : '.']
    dir('ui') {
        sh 'npm install'
        sh 'grunt ci'
    }
    step([$class: 'ArtifactArchiver', artifacts: 'ui/build/**/*'])
}
 
def buildSubproject(name) {
   sh "chmod +x ./gradlew"
   sh "./gradlew --daemon ${name}:clean ${name}:build"
}

ちょっと補足。

  • GitリポジトリはGitBucketを使っています。
  • 開発環境の都合で、Java用プロジェクトと、Coffee/Sassビルド用プロジェクトはそれぞれ別スレーブ( java ラベル付きスレーブと nodejs ラベル付きスレーブ)になっています。
  • Coffee/SassのビルドはタスクランナーとしてGruntを使っています。 grunt ci はCI用のカスタムタスクの実行です。

所感&分かったこと

  • プラグインで拡張されているようなビルド処理やビルド後の処理などがどうなるのか気になっていたのですが、現状では完全には対応できるわけではないみたいですね。 ※ 公式のCOMPATIBILITY参照。
    • ビルド手順は sh を使えば大体のものが対応できそうだけど、ビルド後の処理(通知や静的解析結果の集計など)は苦しい気がしました。
    • スクリプト中で build(jobname) とすると別のジョブのビルドができるので、うまく組み合わせるとか、になりそう。
  • ビルドでの成果物のコピーは archiveunarchive で簡単にできる。
    • unarchive でのマッチングルールは、 archive のものと一致していなくてもよい。 archive includes: '*.txt' に対して unarchive mapping: ['a.txt' : '.'] とやってもコピー可。
    • archive excludes: '.git/**/*', includes: '**/*' のようにワークスペース全体を成果物としてしまえば、Clone Workspace SCMプラグイン相当のことができる。
    • 異なるスレーブ間でも archiveunarchive でコピー可。
    • build(jobname) でビルドしたジョブの成果物をワークフロージョブ内で unarchive でコピーすることはさすがにできない模様。
  • GitHubやGitBucketのHookを使ってこのワークフロージョブを走らせる、といったことはできない?
    • ワークフロージョブのトリガールールの設定はかなりシンプルでした。
    • ただ、ワークフロージョブとしてできなくても、トリガー専用ジョブ(フリースタイル・ジョブ)とワークフロージョブの2つに分けてつなげば回避できそうです。
  • Snippet Generatorがとても便利でした。
  • stageとかはチェックポイントは使いこなしていないので、要調査。
  • 昨日のレポートでも書いたのですが、解消できなかった疑問として、あるリビジョンでワークフローを流している途中に、別のリビジョンでワークフローを並行して流すことはできるのかどうか、検証する必要がありそうです。
    • ワークスペースが共通なので、Jenkinsの仕組み的に多分できなそうな気はしますが。

というわけで、カンファレンスで受けた印象通りに、すばらしいプラグインだと感じました。
このプラグインの適用事例が増えて、色んなワークフロースクリプト(のテンプレート or サンプル)が公開されてくることに期待したいです。

Jenkins ユーザ・カンファレンス 2015 東京に参加してきた。 #jenkinsja #juc2015

今年もマイペースに更新していきますので、よろしくお願いします。
今年は参加したイベントのレポートを忘れずに書くことを目標にしたいと思います。ということで早速、今年最初の参加イベントである「Jenkins ユーザ・カンファレンス 2015 東京」についての参加レポートです。
2012年の夏頃に開かれた前回に引き続いての参加でした。

概要

  • 日時
    • 2015/01/11 (日)
  • 場所
    • 法政大学 市ヶ谷キャンパス 外濠校舎
  • 参加セッション
    • 基調講演: Jenkinsプロジェクトの現状とワークフロー
    • はてなにおける継続的デプロイメントの現状とDockerの導入
    • JenkinsとPuppet+ServerspecでインフラCI

※ 諸事情により残りのセッションとLTは参加できず。。

■ 募集時の事前アンケート結果

到着して間もなく、基調講演の開始が12時30分からになるからとのアナウンスが。
どうやらconpassの開始時刻の案内が13:00になっていたみたいで、そのことを考慮してとの措置とのことでした。

私はホームページの情報しか見ていなかったので、本来の開始時刻少し前に到着し、無事に最初から聴くことができました。
基調講演開始までの空いた時間のつなぎと、基調講演の頭で、イベント募集時の事前アンケート結果について紹介がありました(後で資料は公開されるとのこと)

目についた結果のメモだけ。

  • 使用言語
    • Javaが頭一つ(二つくらい?)抜けていた(まぁ納得)。
    • 後はJavaScript, C, C++, C#, Ruby, Pythonあたりが続く。
    • Groovyは選択肢になかったが、実際の利用者はもっと多いと予測される。
  • Jenkinsの利用経験
    • 6割強が初心者、3割強が中級者、残り1%がエキスパートといった分布。
  • Jenkinsの用途
    • ビルドに使っている人の数とデプロイに使っている人の数にあまり差がなかった(CDも当たり前になっている?)

■ 基調講演 Jenkinsプロジェクトの現状とワークフロー

Jenkinsの現状

  • 前年比で大幅に伸びている(インストール数、スレーブ数、ジョブ数)

DotCI

https://github.com/groupon/DotCi

Jenkinsのロードマップ

  • UIの刷新(互換性を保ちつつ)
    • レスポンシブデザイン
  • 継続的デリバリー
    • 典型的なデプロイの流れ: Repository -> Jenkins -> S3/Artifactory等 -> デプロイ先サーバ
    • いつ何がデプロイされたのかをJenkinsが把握するために、デプロイ先サーバからJenkinsにファイル指紋をトラックバックする。
  • Docker
    • Docker内のコンテナ(クリーンなスレーブ)でビルド
    • docker run -p 8080:8080 jenkins
  • 受け入れテスト & ハーネス
  • 通信のNIO化
  • Maven2ジョブの高速化

Jenkins Workflow Plugin

http://jenkins-ci.org/content/workflow-plugin-10

  • 最近1.0がリリースされた。川口さんが個々最近で力を入れて取り組んでいたプロジェクトとのこと。
  • モチベーション
    • 複雑な継続デリバリーチェインに対応する
      • ブルー・グリーンデプロイメント
      • 要所要所で人間の判断が必要な処理(スキーマの変更の確認をDBAが行う、など)に対するフローの中断、確認、再開
      • 分岐や並列実行
    • 似たようなジョブがたくさんできてしまう問題
      • ジョブ(の設定)を再利用できるようにする
  • プラグイン
    • Groovyを土台にしたDSLでワークフローを定義する
    • プラグインの状態をセーブポイント(チェックポイント)を設定しておくことで、最初からやり直さずに再実行することができる。
    • Jenkinsの再起動をしても実行中のジョブがエラー終了せずに、再起動後に継続して実行されていること(デモ)
  • 実装技術
    • カスタムGroovyインタプリタを実装
    • 継続渡し方式(CPS: Continuation Passing Style)
    • Jenkinsサーバ上でGitリポジトリを作っている → デプロイ・アンデプロイなどで成果物の再利用ができる)

はてなにおける継続的デプロイメントの現状とDockerの導入

  • Jenkinsの利用ケース
  • Chef
    • Jenkins環境の構築もChefで
  • Jenkinsを使う時の方針
    • 設定を複雑にしない(秘伝のタレ問題)
    • ジョブの設定としては、 script/jenkins.sh を実行するだけ、くらいのシンプルなもの。
  • チャットツール
    • IRCからSlackに乗り換えた
  • タスク管理ツール
    • Trello
  • 開発と本番で自分がどちらのアプリを見ているか勘違いしないようにするための工夫としてfavionを変えている。

ブランチモデル

  • master, staging, devel, feature branch(随時)
  • develブランチは常にリリース可能な状態に保つ
  • 開発中にプルリクを立てるかは任意、ただしレビュー時は必須
  • レビュー後にdevelへマージする
    • コンフリクトがあるとGH;Eからボタン一発でマージできないので、コンフリクトが解消されていることが強制される。
  • pushされる度にテストを実行し、GH;Eに通知(通知としては弱いのでXFD等も使ってみたい、とのこと)

Docker

  • 環境を分離する
  • イメージ作成時にブランチ名を対応させておく
  • イメージのビルドに時間がかかる(30分以上)
    • apt-get, perlのインストール, 等
    • 解決策(キャッシュの活用)
      • コマンドはデフォルトでキャッシュされる。
      • COPYすると効かない。

質疑応答

  • 開発時のDBは確認用のDBがあってDockerコンテナ内からは全てそれを参照している。
  • スキーマの変更は、既存のものとの互換性を保つようにして更新するようにしている。

■ JenkinsとPuppet+ServerspecでインフラCI

GMOペパボ株式会社の常松さん(@tnmt)の発表。資料は以下。

質疑応答

  • 商用ソフトなど対話型インストールが必要なソフトへの対応について
    • ウィザードでのインストールでも、やっていることは設定ファイル等の成果物の生成・配置なので、成果物を配置することでインストール後の状態と見なす。
  • Serverspecでテストを書く時はどれくらい突っ込んだテストを書く
    • 絶対に逃せない仕様から確実にテストしていき、徐々に膨らませていく。
  • Serverspecで全てのインフラのテストは可能?
    • 大体はできるが、他の機能との連携などはできない(苦手?)なものもある。
  • サーバ群としてのテストは自動化しているか?ロードバランシングやDBのフェールオーバなど。
    • Serverspecはあくまで単体のテストに使い、それらはロードバランサの死活監視などでやるのがベター。

■ 感想

基調講演 Jenkinsプロジェクトの現状とワークフロー

  • ビルドだけに限らずデプロイまでJenkinsで行っている人が多かったので、Capistrano以外を使った方法など、色んな事例がありそうなので聞いてみたいと思った。
  • Jenkins Workflow Pluginはすごい便利そう。
    • 実プロジェクトでデプロイメントパイプラインを組んでいて、10個近いジョブがチェインされているので、このプラグインを使って組み直してみたい。
  • (ちょっとした疑問1)一つのジョブに集約される分、ジョブの実行時間は長くなりそうだけど、頻繁なコミットの度にデプロイを行っているようなケースで同一ジョブをうまく多重実行できる?
  • (ちょっとした疑問2)既存プラグインで拡張されたビルド処理とかも記述できる?まぁ sh が使えれば何ともでなりそうではあるけど…。
  • 実際に使う場合、ワークフロースクリプトが秘伝のタレ化しないように注意しないとならなそう。
    • バージョン管理とレビュー必須?

はてなにおける継続的デプロイメントの現状とDockerの導入

  • 会場が超満員で、関心の強さを感じた。
  • ブランチモデルとかは、世の流れに数年遅れて、SubversionからGitへのシフト中でもあるため、参考になった。
  • DockerでのインフラCIとかはうまく仕組みが作れるとすごい便利そうだなと思い、一時期取り組んでいたけど、保留中なのできちんと形にしたい…。

JenkinsとPuppet+ServerspecでインフラCI

  • 最近Dockerが流行りなのか、Vagrant聞くことが少なくなったなぁと感じてたけど、実機の環境に近いのは完全仮想化であるVirtualBoxとのことで、その事例が聴けてよかった。
  • 仕事ではChef+Vagrant+ServerspecでインフラCIっぽいことをしているので、それと比較しながら聴けた。こっちも後でブログにまとめたい。

全体通して

すでに業務でのJenkinsとの付き合いは5年以上(Hudson時代から)となり、Jenkinsは開発に欠かせないツールになっています。
Jenkinsのバージョンアップ自体は1ヶ月に1, 2回くらいのペースで行っているのですが、新しいプラグインなどは最近キャッチアップできてなかったので、とても刺激になりました。
イベントの資料は最近は(大変ありがたいことに)後からでも見ることができますが、生で聞くとやはりモチベーションアップになりますね。
あとはChef, Puppet, Docker関連の話が多かったのも印象。単なるビルドやテストを越えてJenkinsは色んなことに使えるので、もっと色々な仕事をJenkinsに任せられるよう、模索したいと思います。

スタッフ、発表者、参加者の方々、おつかれさまでした。とても参考になるイベントでした。ありがとうございました。

Java SE 8とJava EE 7によるアプリケーションのモダナイゼーション~中間ふりかえり~ #javaee

はじめに

この記事は、「Java EE Advent Calendar 2014」の5日目の記事となります。
昨日は、@kazuhira_rさんの「JCacheの実装とキャッシュ管理のご紹介」でした。
明日は、@susumuisさんの「ねこ踏んじゃった系エントリ:Tomcatいじめたら意外と強かったこと」です。

このエントリは、9月にこのブログで前置きしておいた、既存のアプリケーション(Java SE 6、Java EE 5、JBoss AS 5.1.0.GA)のバージョンアップについてまとめたものです。

このプロジェクト、正直なところ、11月に終わっている予定だったのですが、諸々の事情により、まだ完了しておりません…。本来であればこのAdvent Calendarもドヤ顔で報告する算段だったのですが。
というわけで、中間ふりかえりという形で、ハマった点や新しいJavaを使ってみた所感などをまとめてみたいと思います。

以下のトピックスでお送りします(Java EEと関係ないものも混ざっていますが、このタイミングでブログに書いておかないと、ずっと書かなそうなので…)

なお、Java EEサーバとしてはWildFly 8.1.0.Finalを想定しています(今は8.2.0.Finalにバージョンアップしてますが)。

IDE(Eclipse)周りのトラブル

そもそもNetBeansIntelliJ IDEAを使わずにEclipseを使う時点で茨の道だったのかもしれないですが、とにかくEclipseを使いました。バージョンは、Java SE 8がサポートされていることがMUSTなので、必然的に4.4以上です。

「さぁ開発するぞ!」と思って、build.gradle に諸々の依存関係を追加して開発し始めたら、エディタ機能(コードアシスト)が致命的に重たく、とても開発できる状態にはなりませんでした。
原因は当時の最新のLombokのバージョン(1.14.6)の不具合でした。1.12.6にダウングレードしたら解消されました。なお、この不具合も現在は解決しているようなので、今は最新のバージョンを使いましょう。

別の問題として、Eclipseを4.4.1にアップデートした途端に、Gradle IDE Pluginがエラーを吐く問題にも遭遇しました。バグを踏んだのとトピックが起票されたのが半日も差がなく、タイムリーな問題でした。
いくつかワークアラウンドが提示されていましたが、当時はGradleのNightly Build版を使うようにして解消しました。こちらも今は解消されているみたいです。

JBoss Seam 2.2.2.FinalからJSF 2.2 + CDI 1.1への移行ポイント

対象のアプリはJBoss Seam 2.2.2.Finalで作られていたので、これをJSF 2.2 + CDI 1.1に移行しました。

Seamは個人的にはすごい使いやすいフレームワークであり、Java EE 5ベースであっても、以下のようなアノテーションの対応によってスムーズに移行できると思います。

Seam CDI
@Name @Named
@Scope(ScopeType) @RequestScoped, @ViewScoped, @SesssionScoped, @ApplicationScoped等
@In @Inject
@Out @Inject
※ スコープで対応
@Create @PostConstruct
@Logger @Inject
きしださんの記事を参考にロガープロデューサを作っておく
@RequestParameter @Inject
Qiitaに書いた拙作のようにプロデューサを作っておく
@Begin,@End Conversationを@Injectして会話スコープの作法に習う

英語の記事ですが、Migration from JBoss Seam 2.2 to Java EE 7が丁寧に書かれていると思います。

いくつかはプロデューサを作って対応していますが、それ以外に作った便利なプロデューサとしてはFacesContextやDataSource用のプロデューサがあります。
FacesContextプロデューサを作っておくと、毎回 FacesContext.getCurrentInstance() を呼ぶのに比べて、ちょっとだけコードがスッキリします。
DataSouceプロデューサは mappedName が変わった時の修正範囲が最小化してくれます。

アプリケーションの開発ルールとして、ビュー(xhtml)とバッキングBeanは1:1に対応づけるようにし、バッキングBeanは原則ViewScopedにしました。 ログインユーザ情報を保持するSessionScopedのCDIオブジェクトや、アプリ全体で利用するSelectItemのリストを返すようなApplicationScopedのCDIオブジェクトなんかは、バッキングBeanと別パッケージにまとめておきました。

JSFはまだ使いこなせておらず、 @PostConstruct メソッド内でセットした FacesMessage が画面に表示されなかった点などでハマりました。原因と解決はここを参考にしました。

Java SE 8の使いどころ(依存ライブラリの対応状況、新クラス)

どこか(Twitter?)で見たのですが、Java EE 7はJava SE 7の仕様をベースにしているようです(記憶違いならすみません)。
そのため、Java SE 8で追加されたAPIをフルに使って開発するぜ!と意気込んでも、ハマったりします。

アプリのコードをJava SE 8式で書いても、そもそもJava SE 8に対応しているライブラリはまだ少ないので、Date and Time APIからjava.util.Dateへ変換するユーティリティを書く必要があったりで、悩ましいところです。

ハマった例を挙げると、インタフェースのデフォルトメソッド内でOptionalを使っていると、デプロイに失敗しました。Optionalが悪いかどうかはイマイチ自信がないのですが、Optionalを使わないように書き換えたところ、少なくともデプロイは成功したので、現状はそのように回避しています
*1

他には、JAX-RSJSONオブジェクトを返す際、オブジェクトの型がOptional, OptionalInt, LocalDateTimeだったりすると、期待するエンコード結果にならなかったりしました。その辺は先日Qiitaにまとめておきました。

逆にスムーズにJava SE 8で書き換えできるような箇所は、匿名クラスをラムダで書き直したり、単純なループをStream APIに書き直したり、といった点です。

二重ループだったり、以下のようにある日付からある日付までをループするような処理は、ちょっと苦しくなります。

LocalDate from = LocalDate.of(2014, 2, 10);
LocalDate to = LocalDate.of(2014, 3, 3);
 
for (LocalDate d = from; d.isBefore(to); d = d.plusDays(1)) {
    System.out.println(d);
}

ちなみに上記のループは、以下のようにStream APIで書いてみました。無限に生成されるストリームに歯止めをかけるのが、 limit() しかない(?)ので、期間が何日あるかを求めて、 limit() に与えています。

long days = Math.max(0, ChronoUnit.DAYS.between(from, to));
Stream.iterate(from, (d) -> d.plusDays(1))
    .limit(days)
    .forEach(System.out::println);

その他、OptionalifEmpty() がなかったり、プリミティブ型の OptionalIntmap() がなかったり、細かい所でもどかしさを感じたりしました。

ユニットテスト

Advent Calendarの2日目に@irofさんがユニットテストについて触れていますが、モックフレームワークとして、EasyMockを引き続き使っています。

しばらくバージョンアップしてなかったのですが、最新のEasyMock 3.3だと、JUnitのルールやアノテーションを使って以前のテストコードに比べて定型コードが少なくなってテストコードがすっきり書けるようになった印象です。この辺はまた別にまとめておこうかなと。

ちなみにちょっと調べて、Java EE関連のテストフレームワークとしてneedle4jとかCDI-Unitの存在を知ったのですが、使っている方がいれば評価を伺いたいところです。

その他

PicketLink

認証・認可周りのライブラリとしてPicketLinkの採用を検討しましたが、結局見送りました。理由は、現行の認証・認可の仕組みが、DBスキーマAOP等々、アプリケーションの独自実装で作り込まれていたので、あえて乗り換えるためのコストが高そうと判断したためです。

HTML5 Friendly Markup

JSF 2.2のHTML5 Friendly Markupも、使ったり使わなかったりと中途半端な状態になっています。
テンプレートを使うための <ui:composition>, <ui:include> タグやAjaxのための <f:ajax> なども含めて、あらゆるものをHTML5 Friendly Markupで書くのが辛そうだと判断したので、いっそ割り切って、使いやすい部分だけ使うことにしました。

JMS

MDBonMessage() メソッド内の処理を書く際に、 ObjectMessage から目的のオブジェクトを取得するためのAPIとして getBody(Class<T>) メソッドが追加されていたのが嬉しい修正でした。
今までは instanceof で型チェックしてキャスト、みたいなことをするしかなかったので。

ただ、型チェックしてそれぞれキャスト、みたいなことをしなくなった代わりに、型ごとにMDBを用意しなければならなくなると思うので、その辺はメッセージセレクタで振り分るのが常なんでしょうか…?

@MessageDriven(activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "java:/queue/HogeQueue"),
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "TYPE = 'A'") })
public class SampleMDB implements MessageListener {

    public void onMessage(Message message) {
        // ...
    }
}

JAX-RSのClient API

Twitterでチラッとつぶやいたのですが、接続タイムアウト、読み取りタイムアウトを設定する方法がよく分からずじまい。。

おわりに

相変わらず全然内容が整理されていないなぁと思いつつ、以上、中間ふりかえりとして、思いついた点を洗い出してみました。Java SE 8もJava EE 7も、それぞれの新機能についての解説はあるのですが、「じゃあ実際どうなの?」という事例はまだまだ少ない気がするので、参考になれば幸いです。

ここでのまとめは、実際にアプリを開発して、色々と試行錯誤した内容についての記録なので、間違いもあるかと思います。そうした点はご指摘いただけると嬉しいです。

また、こうやって大変だった点を中心にまとめると、Javaにネガティブなイメージを持ってしまうかもしれません。ただ、決してそんなことはなく、実際に開発してみて、それが軌道に乗ってくると(以前と比べて)本当にサクサク開発できるようになって、楽しいなぁと感じました*2

*1:ちなみにインタフェースのデフォルトメソッドを使っている箇所はというと、Java EEと関係ないのですが、ORMとして利用しているDoma 2のDaoインタフェースです。Doma 1からDoma 2にバージョンアップした際、委譲クラスに書いていた処理を、デフォルトメソッドとして書くように変更になったので。

*2:まぁ、一番嬉しかったのはアプリケーションサーバの起動時間が劇的に短縮された点なのですが。

Java EE 5からJava EE 7へのアップデート 〜依存関係の大掃除〜

ちょっと泥臭い話で、Java EE 5からJava EE 7へのアップデートにあたり、利用しているサードパーティ製の追加ライブラリ(依存関係)についても改めてみることにしました。せっかくJava EE 7標準で用意されているのに他の代替ライブラリを使い続けてる、みたいになっても無駄なので。

Java EEフルスタックな標準仕様と言っても、実際の開発では他のライブラリを取捨選択して開発すると思います。 他のプロジェクトでは、どういうポリシーで取捨選択し、採用に至るのかは分かりません(リーダーにお伺いを立てるとか?)が、自分のところはよくも悪くも無法地帯で、好きなものを自由に選んで採用しています*1

前置きはさておき、実際に使っているライブラリについて、検討した一覧がこちら(おかしな部分のツッコミとかは大歓迎です。)

ライブラリ 方針 備考
Joda-Time 使わない Date and Time (Java SE 8)に置き換える。
Quartz 要検討 EJBの@Schedule、Concurrency UtilitiesのManagedScheduledExecutorServiceなどで代用?
QuartzのJobStoreTX(ジョブの登録内容をDBにして永続化する仕組み)相当の仕組みがあれば…
JDBC 使う
jersey-client 使わない JAX-RS 2.0のクライアントAPIに置き換える。
Guava 要検討 使ってる用途の範囲だと、Java SE 8の新APIの部分でほぼカバーできそう。
WIldFlyのmodulesにある(=warには含めなくてよいはず)
Doma 使う 今のアプリはJPA使わずにDoma1使っているので、Doma2にアップデートして使っていきたい。
commons-lang 使う WIldflyのmodulesにある。
commons-exec 使わない Java SE 8/Java EE 7で替わりとなる新APIがあるわけではないですが、なくてもよいという所感。
commons-email 使わない JavaMailに置き換える。
commons-compress 使う
commons-beanutils 使う WildFlyのmodulesにある。
Excel操作系(POI, XLSBeans) 使う (未だにJavaExcel操作のデファクトなんでしょうか…)
JBoss Seam 2.2 使わない JSF, CDIに置き換える。
RichFaces 使わない 結局ほとんど使わずjQueryプラグインを使ってしまっているので…。
ロガー周り(SLF4j + Logback) 要検討 WildFly 8.1.0.Finalでのログ出力の王道に合わせる。

半分近くが使わないことになりそうですね。ただし、使用中のライブラリについては上記の通りですが、アップデートにあたり、Lombok、PicketLinkなどは新たに使っていく予定なので、トータルとしては同じくらいの依存関係の数になりそうです。

プレゼンテーション層にあたるSeam, RichFacesのところは、Java EE 7でどう変更するかについて、別のエントリで書いていきます。

*1:今でこそGradleでビルドしていますが、昔はIvyやMavenすら使わない生Antで、全ての依存jarをlibsフォルダに置いてバージョン管理して、みたいなことをやっていたので、それはもう面倒でした…。

Java EE 7アプリケーション開発のスタートアップ

前日のエントリで予告しておいたJava EE 7アプリケーション開発のプロジェクトひな形ですが、「結合テストとワンクリックデプロイがすぐに使えるJava EE 7開発のためのbuild.gradle」としてQiitaに投稿したので、そちらをご覧ください。

こういうベースになるビルドスクリプトがあると便利、というのは、 id:nekop さんのJava EE / ArquillianのMaven最小設定の影響をかなり受けています。

Eclipseでの開発環境

おまけで、Java EE 7での開発をEclipseで行うための環境構築についての雑多な記録です*1

インストール

  • 利用するEclipseJava EEアプリを開発するので「Eclipse IDE for Java EE Developers」を選びましょう。
  • バージョンはJava8に対応しているEclipse 4.4 Luna以上を選びましょう。
  • インストールしておくとよいプラグイン
    • JBoss Tools: EclipseWildflyを使うならほぼ必須でしょう。
    • Gradle IDE: Gradle Viewを使って、EclipseからGradleタスクを簡単に実行できるようになります。

プロジェクトの設定

プロパティの「Project Facets」で構成をカスタマイズしておきます。

設定されているバージョンはどれもJava EE 6頃のものなので、最新のものに変更します*2

f:id:jappy:20140928040509p:plain

この時、JSFのバージョンを初期値の2.0から2.2(や2.1)に変更しようとするとエラーになり、Eclipse上から変更できませんでした。そこで、(強引な手段ですが)直接プロジェクトの .settings/org.eclipse.wst.common.project.facet.core.xml を編集して対応しました。

before:

   <installed facet="jst.jsf" version="2.0"/>

after:

   <installed facet="jst.jsf" version="2.2"/>

不具合

ところで、少し前までは Eclipse 4.4.0 を使っていたのですが、JSF2.2に対応した最新のWTP(Web Tools Platform)3.5を使うために最新の4.4.1にアップデートしたところ、Gradle IDEプラグインがうまく動かなくなりました(Gradle ViewでGradleプロジェクトが読み込めずエラーになります)。

f:id:jappy:20140928041505p:plain

ちょうどこの記事を書いている前日に不具合報告が上がってました。一緒にGradle IDEプラグインもアップデートした際に問題になったので、修正されるまでは少し前のバージョンを使ったほうがいいかもしれません。

10/1追記 上記URLにいくつかワークアラウンドが上がっていますが、そのうちの1つとして紹介されているGradle (Wrapper)のバージョンを2.1からNightly Build版の2.2-20140930220016+0000に変更する策を試したところ、エラーが解消されました。非安定版ではありますが、今回は検証目的なので、このバージョンで確認を進めていきます。

参考サイト

参考サイトの例だと、アプリはMavenでビルドして、デプロイやWildflyの起動・停止は「Servers」ビューから行うようになっています。

Gradle版では「Gradle」ビューからGradleタスクとしてデプロイやWildflyの起動・停止を行うことができるので「Servers」にWildflyを追加する設定はなくてもよいかもしれません。

*1:正直なところ、EclipseJava EE 7を開発するのはパワー不足も感じるので、NetBeansIntelliJ IDEAの方が良いかなぁと思っていますが…。

*2:キャプチャ上の設定内容は多分穴があります。。