第十七回 #渋谷java を開催しました

10月1日(土)に弊社オフィスで第十七回 #渋谷javaを開催しました。

f:id:takezoe:20161002164458j:plain

今回は以下の皆さんに発表していただきました。

  • セッション枠(20分)
    • ayato_p 「Clojureで状態管理をするためには」
    • shimamoto 「doobieの紹介」
    • Shunsuke Tadokoro 「平成生まれの楽しい!文字コード入門 知っておきたいUnicode Emoji編👍」
  • 通常枠(10分)
    • komiya_atsushi 「High-performance Jackson」
    • Naoki Takezoe 「Macro in Scala
    • tkob 「単体テストのための外部DSL
    • k.hasunuma 「JLSの神話 if-else文 編」

当日の様子や皆さんの発表内容については以下のtogetterまとめをご覧いただければと思います。

togetter.com

今回は発表者がなかなか集まらず*1、弊社の社員を動員したこともあり、セッション枠がClojureScala → 絵文字*2、通常枠でもScalaのマクロの紹介をさせていただいたりといつにも増してJava成分薄めで、これはもはや勉強会の名前を「渋谷java系」とか「渋谷java的」などに変えたほうがよいのではないかという話が出ました。

Java界隈の方はもちろん、ClojureScala以外のJVM言語に関するネタでも構いませんので是非発表枠への応募もよろしくお願いいたします!

*1:いつも発表していただいているayato_pさん、k.hasunumaさんありがとうございます!

*2:絵文字ライブラリの紹介でちょっとだけJavaが出てきましたがw

第十七回 #渋谷java でScalaのマクロの紹介をしました

最近Scalaのライブラリを作っていて自分でマクロを書く機会があったのでScalaのマクロを簡単に紹介をしてみました。発表資料はこちらです。

www.slideshare.net

Lispはプログラム=データ構造なのでデータを操作する感覚でマクロを書くことができるのですが、Scalaではなかなか厳しいものがあります。Quillのようにマクロを活用したライブラリも出てきていますが、複雑なマクロは書くのもメンテするのもかなり大変ですし、scala.metaやマクロアノテーションなど将来的にどうなるのか不透明な部分があり、がっつり使うのは躊躇われる部分もあります。

Scalaでいきなり実用的なマクロを書こうとするとかなりハードルが高いので、マクロを学ぶことが目的なのであればまずLispを触ってみるのがよいかもしれません。ちなみに個人的にマクロに限らずLispには学びがたくさんあるので仕事で使うかどうかは別として全てのプログラマLispを学ぶべきであると思っています。

GitBucket 4.5をリリースしました

Scalaで実装されたオープンソースのGitサーバ、GitBucket 4.5をリリースしました。

https://github.com/takezoe/gitbucket/releases/tag/4.5

テキストエリアにもファイルのドロップが可能に

イシューやWikiにファイルを添付する際、これまではテキストエリア下部の細いバーの部分にしかドロップできなかったのですが、テキストエリアの領域にもドロップできるようになりました。

f:id:takezoe:20160922115427p:plain

ダッシュボードで表示するイシュー、プルリクエストを選択可能に

ダッシュボードでは元々イシューやプルリクエストに対して以下の3種類のビューが提供されていました。

  • 自分が作成したもの
  • 自分がアサインされているもの
  • 自分が言及しているもの

しかしUI変更に伴って最近のバージョンでは自分が作成したものの一覧しか参照できないようになっていました。GitBucket 4.5では後者の2つの一覧も参照できるよう、表示を切り替えるためのスイッチを復活させました。

f:id:takezoe:20160922115828p:plain

HikariCPの設定が可能に

GitBucketは内部的にコネクションプーリングのためにHikariCPを使用しているのですが、これまではデフォルトの設定で動作するのみでユーザがHikariCPの設定を行うことができませんでした。GitBucket 4.5からはGITBUCKET_HOME/database.confでHikariCPの設定を行うことができるようになっています。

database.confはデフォルトでは以下のような内容でGitBucketの初回起動時に自動生成されますので、必要な項目のコメントを外して値を変更することでHikariCPの設定を行うことができます。設定の変更後はGitBucketの再起動が必要になります。

db {
  url = "jdbc:h2:${DatabaseHome};MVCC=true"
  user = "sa"
  password = "sa"
#  connectionTimeout = 30000
#  idleTimeout = 600000
#  maxLifetime = 1800000
#  minimumIdle = 10
#  maximumPoolSize = 10
}

クッキーのセキュリティ改善

セッションを維持するためのJSESSIONIDクッキーにhttp-only属性が付与されるようになりました。また、baseUrlの設定がhttps://xxxx隣っている場合はsecure属性も付与されるようになりました。

コミット数をコミット履歴ボタンに表示

UIの更新以降、リポジトリビューアからコミット数の表示が消えてしまっていましたが、今回のバージョンからコミット履歴ボタンにコミット数を表示するようにしました。

f:id:takezoe:20160929104333p:plain

バイルブラウザでの表示の改善

UIのAdminLTEへの移行時にモバイルブラウザへの対応が完全にできておらず、サイドメニューを利用できないといった不都合があったのですが、これらの不都合を改修したうえでモバイルブラウザでの表示を全体的に見直しました。

f:id:takezoe:20160922120811p:plain

f:id:takezoe:20160922120820p:plain

また、モバイルビューでもファイル検索ボタンとコミット履歴ボタンを表示するようにしました。

f:id:takezoe:20160929104412p:plain

この他にも様々な改善やバグフィックスを行っています。詳細についてはIssueの一覧をご覧ください。

Akka Typedを試してみる

MEAPが開始してから丸4年、Akka in Actionがようやく完成したそうです。

完成版のPDFをパラ見していたところ、最後の16章にこれから入る予定の新機能の解説があり、その中でAkka Typedが取り上げられていたので少し試してみました。

Akka TypedはAkkaのアクターが返すメッセージを型安全に扱うためのものです。

まずはAkka Typedを使わずに普通にアクターを実装してみます。以下は受信したメッセージに反応して送信元にメッセージを返却する簡単なアクターです。

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

object Hello {
  final case class HelloMessage(name: String)
  final case class HelloResult(message: String)

  class HelloActor extends Actor {
    def receive = {
      case HelloMessage(name) => sender ! HelloResult(s"Hello $name!")
    }
  }
}

implicit val timeout = Timeout(5 seconds)

val system = ActorSystem("system")
val actor = system.actorOf(Props[Hello.HelloActor])
val f: Future[Any] = actor ? Hello.HelloMessage("Naoki")

f.mapTo[Hello.HelloResult].foreach { result =>
  println(result.message)
}

アクターに?で問い合わせた結果の型がFuture[Any]になっており、mapToで返却されるメッセージの型にキャストしています。この部分を型安全にしようというのがAkka Typedです。

同じ処理をAkka Typedで書き直してみます。

import akka.typed._
import akka.typed.ScalaDSL._
import akka.typed.AskPattern._
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

object TypedHello {
  final case class HelloMessage(name: String, replyTo: ActorRef[HelloResult])
  final case class HelloResult(message: String)

  val helloBahavior = ContextAware[HelloMessage] { ctx =>
    Static {
      case HelloMessage(name, replyTo) => replyTo ! HelloResult(s"Hello $name!")
    }
  }
}

implicit val timeout = Timeout(5 seconds)

val system: ActorSystem[TypedHello.HelloMessage] = ActorSystem("system", Props(TypedHello.helloBahavior))
val f: Future[Hello.HelloResult] = system ? (TypedHello.HelloMessage("Naoki", _: ActorRef[TypedHello.HelloResult]))

f.foreach { result =>
  println(result.message)
}

ちょっとわかりにくいんですが、アクターの中で行っていた処理はContextAwareの中で行うようになっており、送信メッセージに返信先の型付きActorRefを持たせ、その返信先アクターに対してメッセージを送信するようになっています。ActorSystemActorRef?メソッドなどはAkka標準のものではなくAkka Typedが提供するものを使用することで型安全になるようになっています。

個人的には効果の割に修正が多くてちょっと厳しいかなという気がします。Akka in Actionにも「型安全のメリットは大きいので将来的にAkka Typedが重要なモジュールになる可能性はあるけど、今後大きく変更する可能性があるからまだプロダクションで使うべきではない」というようなことが書かれていました。

Akka in Action

Akka in Action

16章にはAkka Typedの他にAkka Streams、Akka HTTP、Akka Distributed Dataがちょっとずつですが紹介されています。

しかしこの本、完成するまで4年かかったのか…。4年…。

Scalaでコンパイル時にSQLをバリデーションするマクロを作ってみた

以前からscala-jdbcというScala用のシンプルなJDBCラッパーを作っています。

github.com

このscala-jdbcコンパイル時にSQLのバリデーションを行うためのマクロを追加してみました。

たとえば以下のように少し間違ったSQLカラム名の後ろに余計なカンマが付いている)を記述したとします。

sqlc("SELECT USER_ID, FROM USER")

するとコンパイル時に以下のようなエラーが報告されます。

[error] /Users/takezoe/gitwork/scala-jdbc/src/test/scala/com/github/takezoe/scala/jdbc/validation/SqlValidationSpec.scala:30: Encountered " <S_IDENTIFIER> "USER "" at line 1, column 40.
[error] Was expecting one of:
...
[error]     
[error]     sqlc("SELECT USER_NAME, FROM USER")
[error]         ^

デフォルトではSQLシンタックスのみがチェックされますが(SQLのパースにはJSqlParserを使っています)、コンパイル時のカレントディレクトリにschema.jsonというファイルを作っておくことでテーブルやカラムの存在チェックを行うこともできます。schema.jsonは以下のような感じです。

{
  "tables":[
    {
      "name": "USER",
      "columns": [
        { "name": "USER_ID" },
        { "name": "USER_NAME" },
        { "name": "COMPANY_ID" }
      ]
    },
    {
      "name": "COMPANY",
      "columns": [
        { "name": "COMPANY_ID" },
        { "name": "COMPANY_NAME" }
      ]
    }
  ]
}

なお、このマクロはまだ実験的な機能なのでscala-jdbcのSNAPSHOTバージョンでのみ提供されています。build.sbtには以下の依存関係を追加します。

resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"

libraryDependencies += "com.github.takezoe" %% "scala-jdbc" % "1.0.3-SNAPSHOT"

もし不正なバリデーション結果に遭遇した場合はGitHubIssuesでレポートをいただければと思います。

Scala関西 Summit 2016に参加します

来る10月8日(土)に大阪で開催されるScala関西 Summit 2016ですが、弊社もスポンサーとしてサポートさせていただいています。

summit.scala-kansai.org

スポンサーセッションでは「Play2+SlickだけじゃないScalaのWeb/DBフレームワーク事情」という発表をさせていただきます。

Scalaフレームワークデファクトスタンダードと言えばPlay + Slickですが、どちらも使いにくい部分や、手放しで採用できない問題があり、他のフレームワークへの移行も視野に入れています。このセッションではPlayおよびSlickの抱える問題点と、その代替となり得るフレームワークについてお話しさせていただきたいと考えています。

また、スポンサーブースではScalaで開発しているオープンソースプロダクトの展示なども行う予定ですのでお気軽にお声がけいただければと思います!

この際なのでScala逆引きレシピやScalaパズルもよろしくお願いします!!

Scala逆引きレシピ

Scala逆引きレシピ

Scalaパズル 36の罠から学ぶベストプラクティス

Scalaパズル 36の罠から学ぶベストプラクティス

OracleのDavid BuckさんによるBytecode Verification

毎週金曜日に開催している社内勉強会ですが、今週は久々の外部ゲストとしてOracleのDavid Buckさんにお越しいただきBytecode Verificationについてお話しいただきました。

f:id:takezoe:20160903121051j:plain

Buckさんは今年もサンフランシスコで開催されるJavaOne 2016で3本のセッションに登壇されるそうで、そのうちの1セッションの内容を、しかも日本語でお話しいただけるという大変貴重な機会でした。

Bytecode Verificationが必要な理由

Bytecode VerificationはJavaVMが不正なバイトコードを検出するための機能ですが、普段その存在を意識することがほとんどないのではないかと思います。しかし実際のところ、以下のように不正なバイトコードに遭遇し得るシチュエーションには様々なものがあります。

Javaは古いコンパイラコンパイルされたクラスファイルでも動作させることができるのですが、バイトコードを操作するツールやライブラリがバイトコードに仕様の相違を理解せずに操作してしまいバイトコードが壊れてしまうというケースもあるのだそうです。

結論

結論としては非常にシンプルで「Bytecode Verificationはデフォルトで有効なので無効にしないでください」とのこと。

パフォーマンス面の理由からBytecode Verificationを無効にしているオープンソースプロジェクトもありますが、現代のコンピュータではほぼ無意味なので、余計なトラブルを防ぐためにも開発環境であろうとプロダクション環境であろうとBytecode Verificationを無効にするべきではないとのことでした。

壊れたバイトコードを読み込んだ場合、Bytecode Verificationが有効であればわかりやすいエラーメッセージが出るのですが、無効になっているとVMがクラッシュしたりします。こういった場合はコアダンプを見てもクラスファイルが壊れているのかVMのバグなのかの切り分けが非常に難しく、仕事柄いろいろとご苦労されてきた苦悩がありありと伝わってきましたw

日頃Javaを使っていてもJavaVMの中身まで触れる機会は中々ないので大変勉強になりました。マニアックな話題だったとは思うのですが、学びあり、笑いありの楽しい発表でしたので、JavaOne 2016に参加される方は是非Buckさんのセッションに足を運んでみていただければと思います。

豆知識

ちなみにデフォルトでは-Xverify:remoteが有効なのですが、以下のオプションを指定できます。

デフォルトがremoteなのは元々JavaはAppletでの利用が想定されており、アプリケーションのクラスファイルはリモートサーバから読み込んで実行することが前提だった時代の名残なのだそうです。Javaの歴史を感じますね〜。