Hatena::ブログ(Diary)

じゅんいち☆かとうの技術日誌 このページをアンテナに追加 RSSフィード Twitter


はてなブログに引っ越しました。

2012-06-27

[] リトライハンドラを書いてみた(Scala版)

Scalaでもリトライハンドラ*1が欲しくなったので、このブログを参考に作ってみた。

Ruby の retry-handler が激しく便利そうなので Java で実装してみた - YoshioriのBlog

試行錯誤してたら、id:xuwei がforkしてくれていた!→ https://gist.github.com/2996927

参考になりました。

allCatchのほうがよさげだったので、結局以下のような感じになった。

例えばこんな使い方ができます。ConnectExceptionもしくはIOExceptionが発生した場合は3秒間隔で3回までリトライができます(第三引数には関数も渡せます)。リトライ上限回数をオーバーした場合はRetryExceptionがスローされます。retryが成功した場合はちゃんと戻り値を取得できる。これは便利です!

import RetryUtil._

try {
  val xml = retry(3, 3000, classOf[ConnectException], classOf[IOException] ) {
    val url = new URL("http://localhost/")
    println("start")
    val conn = url.openConnection
    val result = XML.load(conn.getInputStream)
    println("end")
    result
  }
} catch {
  case e: RetryException =>
    e.throwables.foreach(_.printStackTrace())
}

*1Scalaの場合はこの名称が適切かどうかわからんが…。

2012-04-05

[] JavaOne Tokyo 2012 : Community Panel Discussion に登壇しました。

昨日はみなさんおつかれさまでした。

私は二日目の Community Panel Discussion で日本Scalaユーザーズグループ代表*1ということで登壇しました。ありがとうございました!

*1:本当の代表は水島代表(仮)です

2012-03-22

[][] Play2.0アプリデーモン化する方法

commons-daemonを使ったら、NettyServerをちゃんとLinuxデーモン化できた。

https://gist.github.com/2156447

2012-02-24

[] WEB+DB PRESS Vol.67 で記事を書きました

今回もJavaスレッドに関連する記事です。前回はメモリモデルに関連す話題でしたが、今回J2SE 5.0から使えるConcurrency Utilitiesについて解説してみました。店頭で見つけたら手にとって見てくださし。

そして次回の締め切りが、、迫り来る!

2011-12-24

[] WEB+DB PRESS Vol.66 で記事を書きました

12月23日発売のWEB+DB PRESS Vol.66で連載4回目の記事を書きました。

タイトルは「再考するJava【第4回】並行処理におけるスレッドセーフの心得」です。

マルチスレッドは難しく広範囲な話題なので書くのが非常に難しいのですが、今回はスレッドセーフに絞って書いてみました。*1スレッドというとスレッドの起動や停止、スレッドプールとかに目がいきがちなのですが、それよりもスレッドセーフを実現するために何を気をつけるべきか、そういう根本的な概念に目を向けることも重要だと思いこの記事を書きました。

この記事を糸口にしていただき、並行処理に関する良書や文献などを読む機会が増えるとよいと思います。

ということで、よろしくお願いします。

*1:というかスレッドセーフといっても主にメモリモデルから視点で書いています。本当は契約プログラミングの視点を加えたかったのですが、紙幅が足りませんでした...あしからず

2011-12-08

[] JIRAで謎い黒魔術!!!

http://atnd.org/events/22899

@に絡まれたので、しょうがなく我が家秘伝のJIRA黒魔術をざっくり公開します。。。

JIRAはワークフローを柔軟に扱えることが一つの魅力です。

たとえば、ストーリチケットを作成するときに、ストーリポイントは必須だよね。ストーリチケットだからね。でも、ストーリポイントを必須項目にするとストーリポイントが決まっていない状況では起票できないし、必須でなくしてしまうと未入力のままの可能性がある。

思いついたときに起票して、ストーリポイントも入力漏れを防ぐにはどうしたらよいか。

ワークフローをいじる

簡単です。チケットが開始状態になるまでは未入力だけど、開始するときには必須ってワークフローを書けばいいのです。

ワークフローを超ざっくり説明すると、、、ワークフローには、オープン、開始、処理中、解決、クローズとかの"状態"があります。それと各状態から状態に移動するための"遷移"と概念があります。この時点でだいぶ難しいw 絵にしてみた。こんな感じ。

f:id:j5ik2o:20111208191312p:image

その"遷移"を可能にする"条件"や遷移時に"検証"を行うことができます。"条件"はその名の通りその条件が有効でない時は、その先の状態に遷移できません。"検証"はその先の状態に遷移する際に呼び出され、検証に失敗した場合は警告表示と次の状態に遷移しません。

Script Runnerプラグインを使う

今回は、チケット作成直後の状態(オープン)から開始状態に遷移するStart Progressという"遷移"の"検証"に独自の条件を追加するのがよいです。

このような拡張を追加する際にはJIRAのプラグインを自作するというのもあるのですが、今回はもっと手軽にワークフローを制御できるScript Runnerを紹介します。

いきなりコードから説明。

ストーリチケットはIDが7番です。*1

ストーリポイントってカスタムフィールドなんでそれもカスタムフィールドの編集画面からパラメータを取得して、フィールドを取得します。フィールドのオブジェクトまでとれれば値の取得は簡単です。このルールの場合は、null以外と0以上を両方をチェックしています*2。"条件"も"検証"も戻り値としてはbooleanを返すだけでよいです。

import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.fields.CustomField

CustomFieldManager customFieldManager = ComponentManager.getInstance().getCustomFieldManager()           
if (issue.getIssueTypeObject().getId() == "7"){
  CustomField customField = customFieldManager.getCustomFieldObject(10003)
  BigDecimal sp = customField.getValue(issue)
  return (sp != null && sp.floatValue() > 0)
}
true

また、ストーリチケット以外でかつサブタスクがないチケットは、開始する前に初期見積を必ず入れておきたい場合は以下のようなバリデータを書きます。意外と簡単に掛けてしまいます。これで初期見積も入力漏れのまま開始されることはないわけです。

if (issue.getIssueTypeObject().getId() != "7" && issue.getSubTaskObjects().size() == 0){
  Long orgEst = issue.getOriginalEstimate() 
  return (orgEst != null && orgEst.intValue() > 0)
}
true

JIRAでデバッグできる

どうやってデバッグするの?Eclipseとか用意するの?って疑問あると思うんですが、以下のような画面を辿っていくとConditionTesterという画面があるのでそこでチケットIDとGroovyスクリプトと入力してテストすることができます。

f:id:j5ik2o:20111208054619p:image:w360

f:id:j5ik2o:20111208054618p:image:w360

f:id:j5ik2o:20111208054617p:image:w360

f:id:j5ik2o:20111208055356p:image:w360

スクリプトをワークフローに追加する

テストが完了したスクリプトはワークフローの編集画面で"条件"もしくは"検証"に追加することができます。登録の際にエラーメッセージを登録できます。

f:id:j5ik2o:20111208054859p:image:w360

動作確認してみる

試しにストーリポイントが未入力なチケットを開始状態にしてみる。

なんということでしょう。ストーリポイントが未入力または0の場合はバリデーションエラーが起きました。思った通りのバリデータを書けるではありませんか。これでいろいろ幸せでになります はぁと!

f:id:j5ik2o:20111208083855p:image:w360

その他のワークフロー関係のおすすめ設定

インストールしたデフォルトだと次のような状態になっています。

  • 一つ目はサブタスクが解決になっていないのに親タスクを閉じれてしまう
  • 二つ目は課題リンクでブロックされるチケットがあるのに閉じれてしまう

最初のサブタスクの方は、In ProgressなどからResolvedに遷移するResolve Issueの条件に追加すれば、サブタスクが解決しないと親タスクも解決できないにようになります。これは簡単ですね。

f:id:j5ik2o:20111208062036p:image:w360

二つ目のブロックされる課題リンクがあるはちょっと複雑です。

JIRA Workflow Toolboxを手動でインストール。atlassian-jira/WEB-INF/lib にこのプラグインJARファイルをインストールするタイプのものです。

これもResolve Issueの条件に追加すればよいです。

f:id:j5ik2o:20111208083417p:image:w360

条件はこんな感じ。ブロックする課題が解決もしくはクローズになっていないとチケットが解決にできないように設定します。

f:id:j5ik2o:20111208083158p:image:w360

f:id:j5ik2o:20111208061333p:image:w360

明日は@です!

*1:番号は課題タイプの編集画面パラメータを見れば確認できます

*2http://docs.atlassian.com/jira/ このあたりにJavadocがあるので見てみてください

2011-12-06

[] パラレルコレクションの性能測定

Scala Advent Calendar jp 2011 6日目 いきます。

STMの話にしようと思ったのですが、いろいろまだ調査中なんでまた後日ということで、今回はパラレルコレクションでいきます。すでにあちこちのブログで扱っているネタなので目新しさはないですが...

パラレルコレクションは2.9から使える新機能です。

早速 使い方。通常のコレクションの要素を2倍する処理は次のように記述します。

List(1,2,3).map(_ * 2)

一方、パラレルコレクションではparメソッドを使います。

List(1,2,3).par.map(_ * 2)

scala.collection.immutable.List#parはParSeq[A]型の戻り値を返します。ParSeq#mapを呼び出すだけでmapを並行に処理できるわけです*1。本来並行処理を実装する場合は、スレッドの起動や待機、スレッドプールとタスクの管理など複雑な制御が伴いますが、パラレルコレクションの場合はparメソッドを呼ぶだけ並行処理を記述できます。

実際のテストプログラム。Benchのmainメソッドがエントリポイントです。引数に応じて通常のコレクションでの処理と、パラレルコレクションでの処理を呼び分けます。

package parallel
import scala.collection.immutable.NumericRange

// プログラム本体
object Bench {

  // nまでの階乗を計算するメソッド
  def fac(n: BigInt) =
    NumericRange(BigInt(1), n, BigInt(1)).
      foldLeft(BigInt(1)) { (cur, next) =>
        cur * next
      }

  def main(args: Array[String]): Unit = {
    import parallel.BenchUtil._
    args match {
      case Array("N") =>
        bench(50, "normal") {
          (1 to 2000).map { x => fac(x) }
        }
      case Array("P") =>
        bench(50, "parallel") {
          (1 to 2000).par.map { x => fac(x) }
        }
    }
  }

}

BenchUtil#benchメソッドは計測した結果をソートして、前後20%ずつ削除した値だけを利用して平均値標準偏差、最大最小値を計算。

package parallel
import scala.compat.Platform

// ベンチマーク用ユーティリティクラス
object BenchUtil {

  private def avg(xs: List[BigDecimal]): BigDecimal =
    xs.sum / xs.size

  private def std(xs: List[BigDecimal]): BigDecimal = {
    val a = avg(xs)
    Math.sqrt((xs.foldLeft(BigDecimal(0))((s, c) => s + (c - a) * (c + a)) / xs.size).toDouble)
  }

  private def median(xs: List[BigDecimal]) = xs.toSet.toList.sortWith(_ < _) match {
    case n :: Nil => n
    case xs if xs.size % 2 != 0 => xs(xs.size / 2)
    case xs if xs.size % 2 == 0 => {
      val a = xs(xs.size / 2 - 1)
      val b = xs(xs.size / 2)
      (a + b) / 2
    }
    case _ => throw new RuntimeException
  }

  private def mode(xs: List[BigDecimal]): BigDecimal =
    xs.foldLeft(Map[BigDecimal, Int]().withDefaultValue(0)) { (map, key) => map + (key -> (map(key) + 1)) } maxBy (_._2) _1

  def bench(n: Int, msg:String)(f: => Unit) {
    val times = for (i <- List.range(1, n + 1, 1)) yield {
      Platform.collectGarbage
      val start = System.nanoTime
      f
      val stop = System.nanoTime
      BigDecimal(stop - start) / 1000 / 1000
    }
    val truncate = n / 5
    val result = times.sortWith(_ < _).view(truncate, n - truncate).toList
    if (result.size > 0) {
      println("%s, threadId = %d, n = %d, avg = %11.2f, std = %11.2f, median = %11.2f, mode = %11.2f, min = %11.2f, max = %11.2f".
        format(msg, Thread.currentThread.getId, result.size, avg(result), std(result), median(result), mode(result), result.min, result.max))
    }
  }
}

結果は次のとおり。私の環境ではパラレルコレクションを使った処理の方が3倍ぐらい高速になりました。もっとコアが多いマシンでテストしたいところだけど、個人ではこれが限界。

動作環境: MacBook Pro 15インチ Corei7 2GHz(物理コアは4つ。仮想コアとして8つ) 
単位はmsec
normal  , threadId = 1, n = 30, avg = 3177.07, std = 10.39, median = 3179.97, mode = 3184.39, min = 3155.66, max = 3191.19
parallel, threadId = 1, n = 30, avg = 1110.68, std = 27.62, median = 1113.52, mode = 1081.60, min = 1065.08, max = 1157.97

CPU負荷は具体的な数値はとってませんが、パラレルの方はちゃんと全部使っている感じ。

通常のコレクション

f:id:j5ik2o:20111206085518p:image

パラレルコレクション

f:id:j5ik2o:20111206085516p:image

使い込んでみないと具体的にどういうところで使えるかわかりませんが、動画のエンコードとか面白そうかなと思ったりしています。

あわせて読みたい

Scala 並列コレクション メモ(Hishidama's Scala parallel collections Memo)

scala2.9のparallel collection の benchmark をしてみた - scalaとか・・・

Scalaの並列コレクションで実際に並列化されているメソッドを調べてみた - chimerastのエレガント指向プログラミング日記

*1:当然mapに渡す関数副作用がないことが前提

2011-10-22

[] WEB+DB PRESS Vol.65 で記事を書きました

10月22日発売のWEB+DB PRESS Vol.65で連載3回目の記事を書きました。

タイトルは「再考するJava【第3回】Java SE 7 新機能のポイント 〜言語仕様の小さな拡張&NIO.2 ファイルシステムインターフェイス〜」です。Java SE 7の新機能*1を紹介する記事を書きました。

try-with-resources構文は、一度使い始めると便利すぎて、後戻りできないですねw ダイヤモンドオペレータも、例外のマルチキャッチも便利です!

それと、水島さん、櫻庭さん、なぎせさんに、レビューをしていただきました。物書きってのは本当に難しいですね。おかげで勉強になりました。本当にありがとうございました!

書店に立ち寄ったらぜひ見てみてください。Java SE 7を知ってもらうよい機会になればと思っています。

あと、特集の「インフラの基礎知識」はみんな読むべきだなと思いました。

ということで、よろしくお願いします。

追記:

Eclipse 3.7.1でJava SE 7に正式に対応しています。

http://download.eclipse.org/eclipse/downloads/drops/R-3.7.1-201109091335/index.php

*1:全部紹介できなかったので一部のみということで、言語仕様の小さな拡張&NIO.2 ファイルシステムインターフェイスに絞って解説しています

2011-08-21

転職先が決まりました

転職活動を始めました - じゅんいち☆かとうの技術日誌

の結果発表の時が来ました。ということで、転職先が決まりました。

「バリューパックでセットで転職をできればいいねぇー」なんていってましたが、結局 別々の会社に転職することになりました。まぁ、別々の会社に行っても、お互いに触発しあえる存在というのは変わらないので。

そして、私は23日から 株式会社ドワンゴ の社員になります。java-jaの人たちから声を掛けてもらったのがきっかけです。

当初は、分散処理系や研究開発系の業務を想定していましたが、技術を使って、なんか面白いこと、変わったこと、インパクトがあることをやってみたいという思いがあり、決断した次第です。

そもそも書ききれないと思いますが

@,@,@,@,@,@,@,

@,@ のみなさんには、私の細かい質問に答えていただきました。ありがとうございました。

ドワンゴ社を検討する上で、この本をさらっと読みましたが、これが面白い。シンパシーを感じるところが多かった。

いわゆる、奇人、変人、天才がいる会社らしい。他にこういう会社は知らないので面白いんじゃないかなと。技術レベルが高い会社なので、自重せずに済みそうです。そして、Scala厨を増やす計画も徐々に進めます。

今回、お声がけいただいた企業様や関係者の皆様、本当にありがとうございました。今後ともよろしくお願い致します。そして、ドワンゴ社員のみなさん どうかよろしくお願いします!

あわせて読みたい

ソフトウェア開発者、完売いたしました - 都元ダイスケ IT-PRESS

2011-08-20

[] WEB+DB PRESS Vol.64で記事を書きました

8月24日発売のWEB+DB PRESS Vol.64で連載2回目の記事を書きました。

タイトルは「再考するJava【第2回】プロジェクト自動生成ツールの再考 maven-archetype&Spring Roo」です。今回の記事はツールの使い方がメインなんで、難しい部分は少ないと思います。Spring Rooアドオンの作り方などにも触れていますが、浅く広くで感覚を掴んでもらうような内容なので、十分に理解できると思います。

他にも面白そうな特集が。個人的には特集3の「かな漢字変換をどのように実現するか 作って学ぶ日本語入力」が楽しそうです。

ということで、よろしくお願いします。