Java Day Tokyo 2014に参加してきました

勉強会はブログに参加記事を書くまでが勉強会だと以前習ったので、昨日参加してきたJava Day Tokyoの感想とか書いときます。

Java SE 8がちょうどでたばかりということもあって、今回はほとんどのセッションがJava8祭りでした。

https://oj-events.jp/public/application/add/170

当日の雰囲気とかはToggeterにまとめられてるのでこちらを。

http://togetter.com/li/670503

基調講演

午前中はOracle本社メンバーによる基調講演。Javaといえばサーバサイド!って印象が強いのですが、今回はJavaMEの話をはじめIoTに注力してることをかなりアピールされて、少し意外でした。 Javaといえば元々組み込み用として始まったわけで、それ故にこその "Write once, run anywhere"を掲げてたと思うのですが、原点回帰というか、ここにきてようやく実ったのかなという印象でした。

実際、デモの中でDukePadでもPCでもアーム型のロボットでもチェスを打つというコードをJavaで実装してたのは面白かったですね。あと、デモでまいんどすとーむやらチェスゲームのDukeが可愛かったのですが公開されてないのかな...

他にも気になったこととしては2016年に出来るであろうJavaEE8ではJAX-RS/MVCが登場予定とのこと。 これで、最近ようやくマイナスがゼロになったJSFとおさらばできます。あれはURLを大事にする近代的なWebサイトを素直に作れないので><

あとは忘れてはいけないのはJava SE8の日本語が出来ました!

Java SE 8日本語ドキュメントの公開 http://docs.oracle.com/javase/jp/8/

これは普及させるためには非常に心強いですね。このスピード感でできてくるのは意味では勢いを感じる象徴的なものに見えます。 他にもコミュニティについてもかなり言及されていてJava Magazine 日本版についても話されてました。

あとNECのロボットとか国内での事例紹介もありましたね。対話型のロボットで現在導入パートナーを探し中とのこと。

講演は全般的に英語でしたが、まあゆっくり喋られてたので、通訳聞かなくてもある程度中身が分かる感じでした。

Java SE 8時代のJava EE 7アプリケーション開発

続いて寺田さんのセッション。 まずはJava EE7 のWebSocketでマインドストームをリモート操作。曰く、組み込みのナレッジが無くても使い慣れたJavaでかなり簡単にキャッチアップ出来たとのこと。 ハードウェア自体の高機能化の恩恵も多分にあると思いますがJavaMEとかでフットプリントが小さくなって、普通に書ける範囲が広がったのはいいことですよね。なんか試したくなる。

その後はJava EE7とJava SE8を組み合わせてのConcurrency Utilities for Java EE(JSR-236)の使い方について。 Future.getが同期なのは知らなかったです。これは確かに嵌りそう... そして、 大事なことは「Java SE8ではCallable禁止」とのことでみなさんCompletableFutureを使いましょう! Java EE7とJava SE 8って組み合わせは新しいもの好きには堪らない選択肢だと思うので罠とかは今のうちに確認しときたいですね。

Java SE 8におけるHotSpotの進化

デイビッド・バックによるセッション。 Java SE 8になってHotSpotがどう変わったかのお話です。言語仕様ではなくVM仕様なので、厳密にはJava8ではなくOracle Java, OepnJDKの最新版に関する話、という理解が正しいですね。

ラムダ式とか言語周りが注目されることが多いですが、今回はJVM周りもプロジェクトHotRokitの本格稼働の一つとしてかなり手が入っているでなにげに一番気になってたセッションです。

まずはやはり気になるPermGenの廃止について。 PermGenは通常のヒープとは違いJavaのstaticのメンバーやクラス情報などJavaの静的な情報を格納する場所でした。 しかし、チューニングがそれなりに難しく、パフォーマンス劣化やOutOfMemoryErrorの原因となっていました。

というPermGenのデメリットを上げた上で、とは言えメリットはと次のスライドをめくったところで白紙w そして「....あったけ?」というコメントに会場が爆笑に包まれましたw

でJava8からPermGenが廃止されてMetaspaceへ。基本的な役割は変わらないのですが、ポイントはヒープではなくネイティブメモリ管理になったこと。 つまり、GCの対象ではなくVMの都合で状況に応じて伸縮出来るようになりました。元々ヒープとは特性が違うものだったので、これは言われてみれば妥当な気がしますね。 クラスローダ単位の管理になっていてHigh Water Mark(HWM)を指定することでクリーニングするタイミングもある程度指定できるようです。 とはいえ、特性が変わっただけでメモリ枯渇自体はありえるのでOutOfMemoryError自体が完全に無くなるわけでもないようです。 この辺のチューニングポイントは多少変わりそうなので、負荷試験とかをして実運用までに情報を集めたいところです。

他の話としては、フォールスシェアリング回避や64bitメモリアドレスを可能なら32bitに圧縮するCompressed Oopsや、C1(-Client)とC2(-server)を従来のように指定するのではなく上手く切り替えて良いとこ取りをするTiered Compilation、AESの性能改善など中々聞けない話がたくさん聞けて大満足です。

また、Java7から導入されたinvokeDynamic(indy)がJava8では大幅強化されているようです。 これは、Java7では初回なので正しく動くことを重要視していたのと、Java8でラムダ式やNashornで積極的に利用してる事もあってかなりチューニングが施されているようです。 ちなみにラムダ式Indyで実装されてるのはこの時初めて知りました。てっきり内部クラスかと...

あとjcmdがネットワーク越しでも使えるようになったのも地味に便利ですね。まあ、運用環境と開発環境でjcmdが使うようなACLって普通開けないってのも有るのですが...

Javaアプリケーション開発におけるテストとTDDの実践

@t_wadaさん、@nekopさん、@shuji_w6eさんによるTDD談義。TDDというよりテスト談義かな。 自分が聞いた中では、というか多分今日のセッションで唯一かもしれないJava8関係ないセッションでした。

各メンバーがどうやってテストをしているかの話が主にされて、その中であったcmtest-db を使うとJUnit4に上手く統合されるようなので今度試してみたいですね。 Arquallianは私もちょこちょこ使っていて、EJBのテストには本当に便利! とはいえ、結構使いこ直してない所も多いし、Weblogicだと組み込みで動かないみたいだからどうしようかなとも思ってたんだけど、今回仕切りに本物のモジュールで、という話も強調されてたし、また試さないトナー。動画で撮影とか知らない機能もあったし。

総じて言われてたように感じたのは

  • システムテストでモックに拘り過ぎず本物のモジュールを使うこと
  • カバレッジは目安。テストの点数でもなければ完全でもない
  • それはTDDじゃない、とか「テスト書かないとかそれ@t_wadaの前でも言えんの?」とか原理主義的なことを言わない。自分を助けてくれるかを考える

とかですね。この辺の話はうちのチームだとプログラマが多いのでぜひ色々共有したいところです。

Lambda式とストリームAPI、並列処理の詳細

Stuart MarksによるストリームAPIとかの話。 目玉だけあって、Lambda式やストリームAPIは各所ですでに語られまくってる事もあって、聞き取れた範囲ではあまり新鮮味のある内容もなかったけれど、スライドにサンプルがいっぱい書いてあったので後で見なおしてみると色々発見があるかも。 元々自分がRubyScala、JSやLISPなどmap/reduce/filterがある言語を結構使ってるので、ようやく頭で翻訳せずに使えるようになったか、という以上でも実はなかったりする。

とはいえ、twitterとか見てるとストリームAPIの使い方はわかったけど、業務でどう使うかわからんって話があって、これは私も他の言語でこの辺の概念を学んだ時には感じたことなんで、今度記事とか書いてみようと思う。

Java Day Tech Night

Oracle本社の中の人に質問ある人どうぞコーナー。 勝手にLT枠だと思ってましたがちょっと違いました。そして、ハッキリ言ってグダグダでしたw 通訳挟んでるしテンポやコミュニケーションロスの問題もあるしね。

とはいえ、かなり色んな話が聞けました。Lambda式が内部クラスではなくIndyで実装されてるから初回のコストはともかく2回目以降は通常のメソッドとほぼ変わらない。詳しくはJavaOneの資料見ろ、とか。 Lombokは標準に取り込まれないの? 的な話は試しに使って見てたけど、余計な問題で困ることが多いから別の方法を模索中だけど決定案も無い、というかEJBとかJavaEE系は意図的にgetter/setterとpublic fieldを区別せず動くように作ってあるからそっち使え、とか。 あとLambada式内での例外の取り扱いもやっぱり決定案ないから気をつけろだとか、OpenJDKに協力するならまずはML登録だ!とか。

他にもInterfaceにメソッド実装持てるようになったけど、フィールドてないから片手落ちじゃね? って話にはScalaと違って互換性を大事にしてるからそんなにダイナミックな変更は出来ない。という感じの回答も参考になりました。 とはいえ、基本的にはMix-inをするためのTrait的な用途は想定してないって話だと思うんだけど、こんな感じで書けばフィールドを直接持てなくても、困らないので個人的にはガシガシmix-inに使っていく所存。

そして、JavaEE7でまともに動くのwildflyだけじゃない! 私達はJavaEE7を信じて乗っていいの? 他の言語や非標準FWに行っちゃうよ? という問いには結構ぐだぐだした返しがw まあ、禁断の質問ですからね。標準作る立場としては色いろあるだろうけど、せめてGlassFishWeblogicはお膝元だからもうちょっと頑張って欲しいってのも有りますねー。早く運用で使いたいし!

まとめ

搭乗予定だった飛行機が30分遅れて、危うく間に合わないかとも思ったのですが無事基調講演から参加出来ました。 実のところ行くかどうかは少し迷ってたのですが、Java熱が自分の中でも高まってきたので、いくつかJava8の機能を試して記事書いてみたくなりまし、なにより楽しかったです!

来年もぜひ行きたいですね。

それでは、Happy Hacking!

Androidのエンドツーエンドテストの自動化も Cucumber から Turnip へ

以前はAndroidのATDDにはCabash-Androidを入れてたのだけど、やっぱ時代はCucumberからTurnipだよねってことで、AndroidなTurnip環境を作ったので構築メモ。

ちなみに出来たものはこちらへ。

github - koduki/turnip_with_android_example

インストール

まずはこの辺参考にGenymotionを入れる。 別にGenymotionじゃなくて実機とかでも問題無いと思うけど、開発とかCIとかにはGenymotionが速くて便利。

インストールしたらデバックモードを有効にする。

Android 4.2以上はデフォルトでは開発者向けオプションがないらしいので

  • 「設定」=>「端末情報」=>「ビルド番号」を7回タップすると「設定」に開発者向けオプションが表示される
  • デバッグモード」をonにする

続いてappiumをnpm経由で入れる。

sudo npm install -g appium
sudo npm install wd

これで、実行環境の準備は完了。最後にTurnipの環境を作る。

まずはインストール用のディレクトリを作成.

% mkdir turnip_with_android_example/
% cd turnip_with_android_example
% mkdir spec/
% mkdir spec/acceptance/
% mkdir spec/steps/

続いて

% $EDITOR Gemfile

中身は下記の通り。

source "https://www.rubygems.org"
 
gem 'rspec'
gem 'selenium-webdriver'
gem 'turnip

Turnip用にfeatureを取り込めるように.rspecに下記を記載

% $EDITOR .rspec

中身は下記の通り。

-r turnip
% $EDITOR spec/spec_helper.rb
require 'bundler/setup'
require 'selenium-webdriver'

Dir.glob("spec/steps/**/*steps.rb") { |f| load f, true }

これで必要なファイルが出来たので、Bundlerで依存ライブラリをインストールする

% bundle install --path vendor/bundle

シナリオの作成

さて、ようやく準備が整ったところでシナリオの作成。

開発中のアプリとかをテストするのが本来だけど、サンプルとしてのポータビリティを加味して、デフォルトで入っている[Settting]を対象にテストを書いてみる。

まずはfeatureファイルを作成。

% $EDITOR spec/acceptance/settings.feature
Feature: 設定画面
  Scenario: 端末情報を表示する
    Given テスト対象は "android" 端末
    When "About phone" をタップする
    Then Android Version は "4.2.2" が表示されていること

一旦この時点で実行してみる。bundlerで環境作ってるのでbundler経由でrspecを実行するのがポイント

% bundle exec rspec

stepファイルが無いので下記のようなエラーが出るはずです。

設定画面
  端末情報を表示する
    テスト対象は "android" 端末 -> "About phone" をタップする -> Android Version は "4.2.2" が表示されていること (PENDING: No such step: 'テスト対象は "android" 端末')

Pending:
  設定画面 端末情報を表示する テスト対象は "android" 端末 -> "About phone" をタップする -> Android Version は "4.2.2" が表示されていること
    # No such step: 'テスト対象は "android" 端末'
    # ./spec/acceptance/settings.feature:3

続いてstepファイルを記述。中身は下記の通り。

# coding: utf-8

module SettingsStep
  step 'テスト対象は :device 端末' do |device|
    @device = device
  end

  step ':target をタップする' do |target|
    about = find_first_element('//text[@text="' + target + '"]')
    about.click
  end

  step 'Android Version は :expected が表示されていること' do |expected|
    version_setting = find_first_element('//list/linear[4]/relative')
    version_value = version_setting.find_element(:xpath, '//text[2]')

    expect(version_value.text).to eq(expected)
  end

  def find_first_element xpath
    #flick the screen until find the target item
    while driver.find_elements(:xpath, xpath).count == 0
      begin
        driver.execute_script 'mobile: flick', :startY => 0.9, :endY => 0.1
      rescue
      end
    end

    driver.find_elements(:xpath, xpath).first 
  end

  def driver
    case @device
    when 'android'
      desired_caps = {
            'browserName' => 'android',
            'platform' => 'linux',
            'version' => '4.1',
            'app-activity'=> '.Settings',
            'app-package'=> 'com.android.settings'
        }
      server_url = "http://127.0.0.1:4723/wd/hub"

      @driver ||= Selenium::WebDriver.for(:remote, :desired_capabilities => desired_caps, :url => server_url)
      @driver.manage.timeouts.implicit_wait = 3
    end
    @driver
  end

  def cleanup
    if @driver
      driver.quit
      @driver = nil
    end
  end
end

RSpec.configure do |conf|
  conf.include SettingsStep
  conf.after(:each) do
    cleanup
  end
end

基本的にはただのrsepcですね。1点注意としてはfind_first_elementの中でやってるみたいに画面上に表示されてない項目を出すためにスクロールする必要があります。 これ分からなくて、最初嵌った...

これを実行すると、下記の用にGreenな結果になる。

% bundle exec rspec

設定画面
  端末情報を表示する
    テスト対象は "android" 端末 -> "About phone" をタップする -> Android Version は "4.2.2" が表示されていること

Finished in 9.14 seconds
1 example, 0 failures

まとめ

とりあえずAndroidでturnipな環境が完成。割と便利そう。 ただ、構築が少し面倒なところも。npmとgem使うので、そっち系の親和性があってかつAnrdoidでJavaも書くぜーってエンジニアが居ないと、使うのはともかく導入に手間取るかなーという印象でした。国内情報少ないしね><

あと、cucumberの時もそうだったけど、Firebugとかに相当するDOMインスペクタが無いとstep書くのがちとしんどいのよね。 でも動画でそれっぽいものがappiumある的なことを言ってたので、調べてみようかな。

なんにしても後はテストをひたすら書くだけじゃー!! それではHappy Hacking!

参考

Macで複数バージョのJavaを切り替えたい

JDK8でたよーって、ことで色々触っている今日このごろ。 やっぱラムダ式とか使えるようになって大分普通になった感じ。

で、ここで問題になるのがまだ全面的にJava8に移行したわけでもないのでJava7とどう共存して環境を切り替えるか。たぶん、Java使っている人の9割9分9毛くらいはIDE使ってると思うので、そこはほぼ問題無し。 ※ 以前eclipseが重たいという理由でメモ帳使ってる業のモノが居ましたが...

ただ、mvnコマンド打つときとか、アプリを起動するときとか色々環境変数レベルで変更したいケースもしばしば有ります。Linuxなんかだったらalternative-javaでサクッと変えれるし、最近のLL系だったらこの辺を支援するツールがだいたいある。rvmとかそれ系。

しかし、MacOSJavaが合わさるときその道はないのです。。。 まあ、需要か。orz

無いなら作れが世の基本なので、とりあえず作ってみました。と言っても全面的に下記の記事のやり方をaliasコマンドで実行するだけど。

OSXでJavaのバージョンを切り替える

そんなこんなで出来たものは下記。

github - Alternative-Java for Mac

使い方

使い方という程でもないのですが、適当なディレクトリに上記のスクリプトをcloneして、下記の様なaliasを設定します。.zshrc.mineとか.bashrcとかその辺に追加すると良いかと。

  alias alt-java='source {YOUR_INSTALL_PATH}/alternative-java-for-mac/alternative-java-for-mac.sh'

引数にバージョン付ける感じでサクサク変えれます。

% alt-java               
Missing arguments.
Usage: alternative-java.sh [1.6|1.7|1.8]

% alt-java 1.7
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)

% alt-java 1.8
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)

% alt-java 1.9
Unknown Java version.
Usage: alternative-java.sh [1.6|1.7|1.8]

これで色々と捗るぜ! じゅるり。

とはいえ、これはグローバルは変えないので、あくまで実行したターミナルというかシェルだけに影響が限定されます。

個人的には開発や検証で使う想定なのでこの機能で十分だし、rvmとか本物のaltanativeみたく本気は出さなくていいよね。

それではHappy Hacking!

オカルトから科学へ - SonarQubeで静的コード解析を始めよう

ちなみに、タイトルは半分釣りというか、個人に依存したオカルトから、誰がやっても同じになる科学的な方法論をもっと入れてこう、って意図です。

もちろん、そういった部分を全部なくすのでは無くうまく組み合わせるのが大事。魔術と科学が交わるときには何かが起こるのです!(これが言いたかっただけ)

なんで静的コード解析?

チームやプロジェクトでコードレビューをしていますか?

多くの開発プロセスではコードレビューまたはペアプロが実施されていると思います。しかし、人の目で見てるだけでは不十分であり非効率です。

人間によるレビューは経験や勘、あるいはレビューアの好みに依存してしまう部分があります。 そのため、違う人がやれば違う結果になることはしばしば有ります。

また、そういった自体を防ぐためにレビューチェックシートを使う場合もあるでしょう。その場合の多くは退屈な作業を人がやることになります。 数が増えれば増えるほどミスをする可能性も増えてきます。

そんな時に役立つのがFindBugsやPMD, StyleCopなどの静的コード解析ツールです。 これらをIDEやJenkinsなどのCI環境に入れることで、ツールによる差異はありますが概ね下記の点を見つけることが出来ます。

  • 命名規則やインデントなどのスタイルが適切か
  • 一般的にバグの原因になり易い危険なコードはないか
  • コードクローンなど品質の問題になりやすいコードはないか

という感じで色々と見つけてくれます。正直、この手のツールと同じ土俵で人間が勝負するのは無理です。精度で負けます。

なので、誰でも出来る部分は科学の産物たる機械にまかせて、人間にしか出来ない観点でレビューをするのがベストです。導入することで以下の効果が期待できます。

  • レビューアに依存しない定量的なレビュー
  • コード量やレビューアの忙しさに依存せずに素早く確実にレビュー結果を得られる

個人的にはサーバサイドにレポートが出せてグラフィカルに内容を共有出来るSonarQube(旧名Sonar)を使ってるので、その紹介と導入方法を共有したいと思います。

SonarQubeとは?

まずは、ざっくりしたSonarQubeの紹介です。

かつてはSonarと言われるものでFindbugなどJavaのコード解析ラッパーから始まったツールです。

f:id:pascal256:20140211132149j:plain

Pluginを利用することでC#PHP, JavaScriptAndroidなど多くの環境をサポートします。詳細は公式参照(Plugin Library - SonarQube - Codehaus)

Sonarの気に入ってるところとしては

  • グラフィカルで分かりやすいUI。複数のツールのメトリクスを集約して見れる
  • タイムラインでメトリクスの増減を見れる
  • 導入が簡単。また、個々の開発メンバーが導入する必要は無いので、負担が少ない
  • プラグインやRESTベースのAPIで拡張可能

があります。特にタイムラインで見れるので、コードメトリクスがどう変化していったかを追うことができるので、すでに運用しているコードにも適用しやすいのが便利でした。

Sonarのインストール

インストールはかなり簡単です。

wget http://dist.sonar.codehaus.org/sonarqube-4.1.1.zip
unzip ~/Downloads/sonarqube-4.1.1.zip
cd sonarqube-4.1.1/
./bin/macosx-universal-64/sonar.sh start

起動したら

http://localhost:9000/

にアクセス。これで完了。ね、簡単でしょ?

本格的に使うにはDBをMySQLに変えるとか、Apacheと連携させるとかすると良いと思いますけど、まずは動かすだけならこれで大丈夫。

Sonarの使い方

JavaMaven環境を作ってるならゴールをsonar:sonarにするだけです。ブランチ名の指定とかしたいので、普段は以下のようなオプションにしています。

これをJenkinsに登録するだけで、定期的にSonarのレポートが作られるようになります。

# デフォルト名
mvn sonar:sonar -D.sonar.forceAnalysis=true -Dsonar.host.url=http://localhost:9000/

# ブランチ名とか指定したいとき
mvn sonar:sonar -D.sonar.forceAnalysis=true -Dsonar.host.url=http://localhost:9000/ -Dsonar.branch=branch-name

Sonarを使った開発プロセス

やりかたは色いろあると思いますが、うちでは主に以下のようなやり方を実践しています。

  1. 開発開始時にmasterより開発ブランチを作成
  2. 各開発ブランチをJenkinsに登録しCI環境に登録毎時でブランチ専用のSonar画面を作成
  3. 開発メンバーは随時、Sonarの画面を確認。問題が上がれば修正
  4. 開発完了時にレビューアはSonarの指摘が無いことを確認した上で、レビューを行い開発メンバにFBする
  5. FBの修正及び再レビューが終われば、リリースブランチにマージ

開発の規模感としては並行して5から10案件程度は動いており、同じ数だけ開発ブランチがあります。これより大きい規模の開発だと、また違った方法論が必要な気がしますが、同程度以下ならある程度同じようなプロセスでいけると思います。

この運用でポイントとなるのは、3のSonarの画面を見て問題があれば修正する、という部分です。

まず、基本的なサイクルとしては指摘を見て修正すれば良いのですが、ルールベースで指摘しているという仕組み上の問題で、設計上は問題なかったりする指摘やら誤検知がそこそこがあります。

これをレビューアなど適切に判断出来る人にエスカレーションした上で、問題なしのチェック等を入れます。そうすると指摘上から消えるので、この部分の指摘は無視して良いとか人間が毎回判断する必要はありません。

残念ながらこの設定がブランチで共有出来ないので、現在は新規でブランチを作る度に手動でコピーしています。 この辺、良い方法があったら、ぜひ教えて下さい。

また、新規コードから適用してるなら指摘を全部0にすれば良いので簡単ですが、すでに運用段階に入ってる場合など、過去の指摘を全て直すのは現実的ではありません。

この場合は、masterの指摘数と比較して、今回の開発等で増えないことを指標とすると良いです。もちろん、たまたま修正が可能だったから減るって分には良いことなので褒める文化に。

Sonarはそれに適した機能があってTimeMachineで比較することが出来る。これを使うことで運用中のコードであっても、適用していくことが比較的簡単に出来ます。

f:id:pascal256:20140211132258j:plain

いずれにしても"指摘を増やさない"という運用が大事で、例外は原則認めてはいけない。そうしないとみんな守らなくなるからね。元のルールが厳しすぎるとかなら適度にカスタマイズすればいいし、うちもそうしてる。

あと、Issuee以外のDuplicationsとかComplexityは今はルールにしてない。この辺のルールを入れると縛りが強くなりすぎる気がしたので、あくまで開発者の参考レベル。

そして、怒る人重要。指摘を増やした状態で4や5にプロセスが行ってしまった場合は、きちんと怒る。必要に応じてマネージャとかもCCにして、全体周知して怒る。嫌われ役になっちゃいがちだけど、最初はみんな慣れてないから、ついやっちゃうし、新規メンバーもしてしまいがちなので、文化としてやっちゃダメなこと、とみんなが認識しきれるまでは、きちんと怒り役の人が居た方がうまく回るかな。

プラグインAPI

拡張性の高さもSonarの良いところです。単に対応している言語やテストツールを増やすだけではなく、PDF出力をはじめレポート類も充実しています。

Plugin Library - SonarQube - Codehaus

また、RESTベースのAPIで簡単に情報を取得したりも出来るので、独自のツールやExcelへの連携も簡単です。

たとえば、プロジェクト毎のIssuesとコードカバレッジの一覧は以下のURL。

http://localhost:9000/api/resources?metrics=coverage,violations,blocker_violations,critical_violations,major_violations,minor_violations,info_violations

f:id:pascal256:20140211132325j:plain

APIのドキュメントはこちら(Web Service API - SonarQube - Codehaus)を参考。

うちではこれを使って複数のブランチのタイムラインを1画面で見れるツールを作っています。コード品質が急激に悪くなったチームとかあれば、プロジェクト進捗にも影響するだろうから警戒する必要がありますし。

こういった拡張がさくっと書けるのは良いところです。

まとめ

色々書いてみましたが、この手のツールは単純に入れるだけじゃなくて、運用プロセスを作って文化まで昇格することが大事です。

とりあえず、勝手に導入して技術的な課題をクリアしたら現場メンバに周知。ある程度みんなが慣れたらマネージャとか偉い人系もレポートラインに加えて、進めるのが個人的には好きです。許可を取る前にやってしまえモデル。

導入も簡単だし、まずは入れてみて、自分たちの開発プロセスに合うかどうかを確認してみるのもいいと思います。

実際うちでは入れる前に比べて劇的にコード品質がマシになって、ヒューマンレビューではくだらないこと指摘せずに具体的なレビューに集中できるようになったし、効果があるケースも多いんじゃないかと。

それでは、Happy Hcking!

参考:

Javaを使うメリットはありますか? はい、それはもちろんあるに決まってます!

/.Jに聞け:Javaを使うメリットは? | スラッシュドット・ジャパン デベロッパー

え、ありますよね? Webアプリに限っても。 というか、上げてるデメリットが現代的じゃないなぁ...

個人的には少数精鋭チームを作れてないならJavaはかなり有りな選択だと思っています。

Java使ってるメンバーがスキルが低いのではなく、LL系で高品質なものを作るのにスキルが必要で、例えスキルがあっても多人数開発にはあまり向かない、という意図

というわけで、自分が思うLL系言語ではなく、JavaでWebアプリを開発するメリットを書いてみます。

静的型づけ言語

HaskellとかOCamlとかScalaとか、その辺の超強力な型付け言語から見ると弱いですが、多くのLLと違い静的型付けな事が特徴です。

これは型というメタ情報を言語仕様に明確に取り込んでいるということです。以下のメリットがあります。

  • 人間が読みやすい
  • コンピュータが読みやすい

動的型付けだと何が入ってるか不明のオブジェクトがあります。

メソッドの引数に入る値がフリーダムだったり、逆に戻り値がintだったりオブジェクトだったり。

型をインターフェースに定義することで、この辺りは非常に読みやすくなります。曖昧な書き方をすれば、コンパイラが指摘しますし。

初期のJavaだと記事で上げられてるデメリットにある通り、キャストが増えて結局型安全じゃないケースも多々有りましたが、Java5以降はGenericsがあるので、ほぼキャストに出くわすことは無いでしょう。

他にもJavadocを書くときに型情報を記載してなくても自動的に入れてくれるという地味に便利な機能もあります。

パフォーマンスも付け加えたくなりますが、JITが優秀なら型の有る無しが決定差にならないらしいですし、それ以外のメリットに注目してみました。

IDEが強力

EclipseNetBeans, IntelliJと言ったIDEが結構強力。 静的型付ということもあって、リファクタリング機能も強力にサポートしてるし、コードアシストも素早くかつ正確に動作します。

リファクタリング機能が安心して使えると、トライ&エラーの開発がしやすくなるので開発スピードもグッとアップしますね。

gitやsvnといったバージョン管理、GlassFishやJettyなどのアプリケーションコンテナ、antやmavenやgradleといったビルドツールとの連携/統合もバッチリ。

IDEとアプリケーションコンテナを連携してホットデプロイすれば、コンパイルが必要という点もほぼ意識することはないかと思います。

IDEなんて嫌だ! vimemacsが使いたい! って人も居るでしょうけど、統一した環境をサクっと作れるのは開発現場には有用なことだと思います。

静的解析が強力

Javaは静的型付け言語なのでコンピュータが読みやすいという特徴と、長年開発の第一線で利用されてきたこと、そしてアカデミックな研究に使われることも多いという理由で静的解析ツールが豊富です。

コード品質を保ち、コードレビューのコストを減らすことが出来るのでとりあえず入れといたほうが良いレベルの仕組みです。なぜなら、コードの綺麗さは中長期的な生産性のために必須な要素だからです。

とはいえ、レビューをきちんとするのはコスト的に辛くてやってない、ってケースは結構あるんじゃないでしょうか?

JavaだとFindbugやPMDをはじめ様々な解析ツールが揃っていて、最低限のコード品質を保つのが非常に簡単です。コードクローンや命名規約ミス、危険な代入などレビューチェックシートで見つかる程度のことは見つけてくれます。

また、Veracodeとかの商用製品だとセキュリティ観点でも静的解析を行いSQLインジェクションXSS, CSRFの疑い等を検出してくれます。

もちろん、RubyPHPにもそういったものは有りますが、一日の長がありJavaのレベルまでは達していない認識です。

コーディング規約の方言が少ない

Javaは全面的にSun時代のコーディング規約をベースとしたものが使われていてコーディング規約に関してJavaエンジニア全員がある程度共通の認識を持っています。

そのため、モジュールごとにCamelCaseだったりSNAKEだったりしないです。もちろん完全に方言というか、それぞれの規約が無いわけではありませんが、 かなり小さいので、厳密なルール無くてもある程度統一でき、宗教戦争も起きにくいです。

それなりに高い生産性

めんどくさい言語、冗長な言語として評判なJavaですが、そこまで生産性の悪い言語ではありません。

オブジェクト指向言語としての基本的な機能は揃えており、標準クラスライブラリもどんどん強化されています。 例えば、元記事で言及されいているデメリットですが

  • キャスト(1.5以降はGenericsがあるので通常不要)
  • 正規表現(1.4からできる)
  • 連想配列処理
  • 文字列フォーマット(1.5からできる)

連想配列リテラルじゃないので少し冗長なことくらいしか今は残っていません。

加えて1.7ではFilesでファイル処理が簡単になり、1.8からは待望の関数オブジェクトとStreamAPI、型推論、そして日付周りのライブラリ改修が入ります。

この辺が導入されれば、言語機能としても大きくLL系と見劣りすることはないでしょう。 また、リフレクションやAPTで基本的メタプログラミングを行うことも可能です。

加えて、JavaEEやSpringを使えば、Webアプリケーションを組むのはさほど難しく無いかと思います。

高い上位互換

Javaは言語としての安定性が非常に高いです。

バージョンアップにより非互換の言語仕様の変更が入ることはほぼ無く、リビルドすらしなくても結構そのまま動くことは多いです。 一方、LLでWebでよく使われるPHPRubyは結構ひどいです(直近のバージョンアップは比較的マシですが)。当たり前のようにAPI等が統廃合されます。

自分たちの書いたコードだけではなく、FWやライブラリが影響を受ける場合もあり、おいそれとは上げれなくなります。 なら上げなければいい、とか言われそうですが、世の中にはセキュリティアップデートというものが有ります。適度に最新化しないと致命的なセキュリティを放置することになってしまいます。

こういった点は、4,5年以上の運用には非常に重要です。

モニタリングのしやすさ

.NET系もそうらしいですが、JMXによるオンライン監視やスレッドダンプやメモリダンプ、GCログといったリソースモニタリングや障害調査のための仕組みが非常に強力です。

プロファイラもVisualVMやJava Mission Controlなど強力なものがデフォルトでついています。

最近だとFlightRecorderやENdoSnipeなど運用時に低負荷でプロファイラ級の情報を取得できるものもあります。GCのタイミングからホットメソッドまで分かるでの、問題発生時の切り分けがずいぶん楽になります。

LLでも使えるNew Relicとかも登場しており、Javaだけの特徴ではないですが、それらを含めた運用ノウハウの蓄積はまだ勝ってると思います。

まとめ

色々書きましたが、下記の2点にメリットを集約できると思います

  • 言語機能や開発環境によりコード品質や生産性の底上げがしやすいため人の確保が比較的容易
  • 言語の安定性やモニタリングなど運用時に都合の良い部分が多い

別段Javaが最高の言語だとはちっとも思いません。ScalaとかRubyとかの方が普通に好きです。

Javaのデメリットも多くあり、ScalaRubyほどの生産性はないですし、Haskellほどの安全性もありません。C++のようなパフォーマンスもないです。 メモリをよく食いますし、インメモリセッションレプリケーションを使うなら尚更GCには気をつけねばなりません。バランサ設定をスティッキーにする必要があるのも面倒です。

とはいえ、仕事で中長期的に使うなら、先に上げた2つのメリットは捨てがたいものなので、個人的にはまだまだJavaという選択肢「も」ありだな~、と思っています。

それではHappy Hacking!

参考:

ちょっとだけ追記

想像以上にブクマもらってびっくりな今日このごろです。

で、コメントとか見てて、ちょっと補足した方がいいな、と感じたこともあったので少し追記します。

それはJavaじゃなくてJVMの特徴

障害情報、モニタリング系とかはそうですね。だから私も個人的にはScala押しです。ただ、JVMの機能を使えること「も」Javaの特徴なので、メリットして評価項目には入るかと思います。

逆に、RubyScalaもGroovyも言語の安定性/静的解析ツールの品質という点ではまだJavaに及んでないと感じてるので、単純置き換えできるものじゃないかな、と。

そのメリットは◯◯言語使ったほうが得られる。

そうかもしれないです。少なくともJavaが常に最適解になるわけでは決して無いです。 当たり前ですが適材適所あります。手持ちの札(人、モノ、金、時間)によっても同じシステム要件でも変わるでしょう。

C#なんかは言語的には同じ方向でかつJavaより機能的なので、代替候補としては最有力ですね。 ただ、個人的にはWindowsサーバの適切な運用ノウハウを持って無いので、Web系とかには採用したくないです。とはいえ、海外では一般的ですし、Azureも出たので国内でも良い選択になるかもですね。

その上で、この記事自体が「Java使うメリットはあるの?」という問い対する回答なので、頭ごなしな否定を(しかも古い情報で)してほしくないなぁ、という意図なので記載したメリットを他の言語で受けれない、という意味では全く無いです。

言語毎、ユースケース毎に採用を判断するための様々な特徴があるので、他言語で似たような観点の記事を書いてみたいですし、別の人が書いたいろんな言語や環境の記事を見てみたいですねー。

あなたの職業は何? RPG風のエンジニアの分類を作ってみた

ひとくちにエンジニアと言っても、いろんなタイプの人が居て、性格に応じたロールがある。 たとえば「◯◯さんはやたら設計に拘って動きが遅いけどバグは出さない」とか「◯◯さんは手が早いけど、よくバグも作りこむ」とか「◯◯さんはいつもCIと叫んでる」とか。

こういったそれぞれの性格のメンバーが自分にあったロールをこなすことによって、良い開発プロセス/運用プロセスってのは出来ていくと思う。

そういったロールを自分なりに分類してDQ風の職業にマッピングしてみた。 というのも以前飲み会でDQ風にエンジニアのスキルマップを作ってる人がいて、なんか面白そうだったから真似してみただけなんだけどw

偉大なる先達の「プログラマの区分」よりも、抽象度を上げてるので、プログラマだけじゃなくて、インフラ屋さんとかもそれなりに当てはまるはず。

僧侶と魔法使いの区分が分かりづらいけど、 イメージとしては品質を上げるための活動と生産性を上げるための活動の違いかな。もっとも、それらは密接に相関があって切り分けしづらいのだけど。

あと、複数の職業を兼任してるとかは普通にあるとおもう。

職業

戦士
  • 戦闘(開発/運用)の要
  • 重厚な設計、検証された方法を好む
  • 守りは固いが、素早さは低め
武道家
  • 戦闘(開発/運用)の要
  • 軽量な設計、新しい方法を好む
  • 素早さは高いが、守りは低め
僧侶
  • 品質を維持するための魔法を使う
  • レビューやテスト、静的コード解析やCI/CDを好む
  • 盗賊と連携することでより強力な魔法を使うことができる
魔法使い
  • 強力な魔法を操り、戦士や武道家を支援する
  • フレームワークや共通ライブラリを弄ることが多い
  • 盗賊と連携することでより強力な魔法を使うことができる
盗賊
  • 他所のベスト・プラクティスを盗んでくる
  • 基本的に他の職業と兼任してることが多い
  • 外部のイベントによく参加している
商人
  • お金の計算が得意。外部からの調達も行う
  • ROIにもとづき自分たちが"しないこと"を計算できる
  • 限られたリソースを最適なところに投入するために重要な職業

 振り返り

さて、せっかく作ってみたので自己分析をしてみる。

武道家(lv 6), 盗賊(lv 5), 魔法使い(lv 4), 僧侶(lv 3)

Lv 10を一つの基準にするとだいたいこんな感じかな?  いろんな職業についてるので職業技能はそれなりに持ってるんだけど、それぞれのレベルは低いイメージ。

今後の成長プランとして、武闘家とかのレベルをもっと上げるべきか、いっそのこと商人を採って技能を増やすべきかは悩ましいところ。

ちなみにこの職業はバランスよくパーティが構築されている必要があると思う。 一つのパーティに攻撃職、魔法系職、商人が居て、盗賊は全員がLv1以上とってるとかがバランスいい気がする。 戦士や武道家だけでパーティー組むとか縛りプレイの粋だよね?

ただ、現実はクソゲーと言う言葉があり、縛りプレイ大好きな日本人は「戦士、武道家、武道家、武道家」というパーティもよくあるとか。 今いるチームもこの構造な感じで、ギルド所属? の商人、魔法使い、僧侶が複数のパーティーをまとめて面倒見てる感じ。そして、輪をかけて盗賊が少ない。。。

デザインパターンじゃ無いけど、こういったチームメンバの傾向やロールに名前を付けることで、「盗賊が足らない」とか「戦士のスキルを磨きたい」とかチーム戦略や自分の成長プランを考えなおすのに参考になるんじゃないかと思う。

人事系の部署とかはこんな思いつきで作ったようなのじゃなくてちゃんとしたの持ってるだろうけど、自己分析ならこのくらい馴染みのある奴のが自分は好きかな。

でも、この手のロールをファンタジー系職業で表すのは定番といえば定番なので、エンジニアのスキルセットを「ツンデレ」とか「幼なじみ」とかヒロイン属性風に表すとかのが頭がおかしくて良かったかもしれない。誰か作って!

それでは、Happy Hacking!

ドキュメントからコードへ

最近「ドキュメントからコードへ」というのをキーワードに考えています。 その辺に関してつらつらと書いてみました。例のごとく英語で書いた資料より日本語の方が詳しいよ><

「ドキュメントからコードへ」って?

例えばいくつかの種類のドキュメントは下記のようにコードに置き換えることが出来ます。

詳細設計書、テスト仕様書 => 自動テスト

サーバの構成定義書 => サーバテストツール

  • serverspec

インストールマニュアル => プロビジョニングツール系

  • chef/puppet

運用手順書 => デプロイツール, JOB管理ツール, CI ツール

  • Capystrano
  • Fabric
  • Jenkins

他にも要件定義や基本設計をAlloy等で作るのもこの範疇に入るかもしれないです。 ドキュメントを自動ツール系のスクリプト定義に置き換えることが「ドキュメントからコード」となります

そもそもなんで必要?

さて、そもそもなにがうれしいんでしょうか? まず思いつくのはコスト削減。 自動化をすることで手作業でやっていたことがボタンひとつでできるようになります。 これはとてもわかり易いですね。では、本当にそれだけが価値でしょうか?

「ドキュメントからコードへ」に移行することで真に得られるもの、それは作業コストの削減ではなく信頼性です。

ここで言う信頼性は大きく分けて下記の3つです。

  • プロダクトの信頼性
  • オペレーションの信頼性
  • ドキュメントの信頼性

プロダクトの信頼性とはシステムのコードの信頼性です。 自動テストツールを入れることで、今まで目視で確認していた様々な項目を簡単に再実行することが出来ます。 これはリグレッションテストをするにあたって強力な武器です。リグレッションテストはデグレや修正の影響を把握するための基本的な方法です。 これによって、コードの品質が保てるというのは分かりやすいかと思います。

プロダクトだけではなく、オペレーションの信頼性もコード化で担保出来ます。 日常の些細な業務から、本番へのデプロイを始め、システム運用にはオペレーションがかかせません。 しかし、それを実施するのが人間であるかぎりミスを犯します。それは確率的な話なので、頻繁にやる作業ほどミスをする可能性が高いといえるでしょう。 一方、プログラムは間違えません。プログラムは書いたとおりには動くので、間違ってなければ正しく動きますし、修正すれば同じ失敗もしません。 これはプロダクトの品質にかなり大きな影響を与えます。

個人的にはもう一点重要な要素としてドキュメントの信頼性向上があります。無論ここで言ってるドキュメントとはコードです。

ドキュメントは多くの場合間違っています。理由は様々です。ドキュメントを作った時点と変わった修正が反映していない。元のドキュメントにミスがある。そもそもドキュメントを見て作っていない。 ドキュメントは容易に壊れます。ドキュメント管理が脆弱な組織では、ドキュメントを見ても結局信用ができないのでコードも見るということはよく有ります。

最後に信用できるのはコードだけ、です。その信頼性の差が何でしょうか? それは実際に動いて使われていることです。 もし、間違えていれば動かない。あるいは要件レベルでバグっていたとしても今動いているものは書いてあるとおりだ、ということが論理的に保証されます。 これは運用をするにあたって大きな安心感を与えてくれます。この1点のためだけでも、仮にドキュメントより作成コストがかかってもコードに落とすべきだと考えています。

まとめ

TDDやBDD, DevOpsで言われるインフラのコード化, Jenkinsなどによるオペレーションの自動化、様々な手法がありますが、作業手順書を無くし自動化することは単なる作業のコスト削減ではありません。 プロダクトの信頼性、オペレーションの信頼性、そしてそれらを支援するドキュメントの信頼性。これらを現実的なコストで実現できるようになります。 つまり、ここで削減してるコストは既存の作業コストではなく、今まで高くて支払えていなかった98%の信頼性を99%にするためのコストです。

作業コストの削減だと割に合わないと思ってた人がもしいましたら、信頼性向上のためという考え方でぜひ実施してみましょう!

それでは、Happy Hacking!