自宅仕事環境(2016/05)

f:id:tototoshi:20160523214129j:plain

PC

MacBook Pro (Early 2013)

主にScalaコンパイルするのに使用する。

キーボード

昔はLite使ってたけどProにしたら戻れなくなった。矢印キーないのは意外と慣れる。

トラックボール

ケンジントン 【正規品・5年保証付き 】 ExpertMouse(OpticalBlack)(USB/PS2) 64325

ケンジントン 【正規品・5年保証付き 】 ExpertMouse(OpticalBlack)(USB/PS2) 64325

10年使ってる。ボールの触り心地が良い。

モニタ

BenQ 21.5インチワイド スタンダードモニター (Full HD/VAパネル) GW2255HM

BenQ 21.5インチワイド スタンダードモニター (Full HD/VAパネル) GW2255HM

安い

モニタアーム

グリーンハウス 液晶ディスプレイアーム 4軸 クランプ式 GH-AMC03

グリーンハウス 液晶ディスプレイアーム 4軸 クランプ式 GH-AMC03

サンワサプライ ノートパソコンアーム CR-LANPC1

サンワサプライ ノートパソコンアーム CR-LANPC1

モニターアームを使った方が机がすっきりする。

椅子

前の職場で使っていたのが良かったなあと、似たようなものを選んだ。

ScalaMatsuri2016に行ってきた

「Steps to master the Play source code」というタイトルで発表させていただきました。 Play個別のセッションがなかったことと、どうせ関数型っぽいのが多いんだろうなと思って申し込みました。Playの初級者向けのPlayのソースコードの全体像とその変遷についての話です。

1日目は自分の出番もあったためにあまり落ち着いて見て回れませんでした。2日目のアンカンファレンスをその分楽しみました。Async Testing in ScalaTest 3.0,Scala.js Compile Pipeline,Freer Monad Extensive Effect in Scalaあたりが特に面白かったです。

Async Testing in ScalaTest 3.0はScalaTestの作者によるScalaTestにAsyncなAPIを追加したいという話でしたが、質疑応答が非常に濃く、Asyncつれーな!って感じでした。

Scala.js Compile PipelineはScala.jsコンパイラの内部的な話でしたが、いかにScala.jsがガチを思い知らされるものでした。使わないけどね!

Freer Monad Extensive Effect in Scalaはおなじみねこはる先生のセッションでしたが、なぜかScala.jsコンパイラの人がツボだったらしく終始爆笑していました。私はなるほどわからんと聞いてましたが、となりでりりろじさんが解説してくれたので助かりました。使わないと思うけどね!あとどうやらFreer Monad Extensive Effect in ScalaのウラではScalaプログラマの年収について語り合う闇のセッションがあったようですね。こわいこわい。

ScalaMatsuri全体を通しては、同時通訳のクオリティが高かったため、英語セッションも存分に楽しめる満足度の高いカンファレンスでした。1日目の昼、夜、2日目の朝、昼と食糧(うまい)の配給があり、お菓子も飲み物も無限に湧いてきて、年収が低い私もお腹いっぱいです。食糧だけでなく衣類、Tシャツやスピーカー特典のパーカーも配給されましたので、全裸で行っても楽しめたのではないかと思います。

というわけで非常に楽しいカンファレンスでした。スタッフ、スポンサーの皆様ありがとうございました。

PlayのWebCommandsの使い方

Playのドキュメントを見るときに、公式サイトに行かなくても手元で http://localhost:9000/@documentation というURLにアクセスすればドキュメントサイトが見えるということはご存知でしょうか?

これにはWebCommandsという仕組みで動いていて、ドキュメントのほかにもEvolutionsの実行ページの表示などにも使われています。 普通のアプリケーションを作る分には必要ないですが、開発用のライブラリにWeb UIをつけたいときなどは便利です。

例えば、/@hello, /@hello/:name というパスにアクセスすると反応するWebCommandは次のような具合です。

package controllers

import javax.inject.{Provider, Singleton, Inject}

import play.api._
import play.api.inject.{Binding, Module}
import play.api.mvc._
import play.core.{HandleWebCommandSupport, WebCommands}


// 処理本体
class HelloWebCommandHandler extends HandleWebCommandSupport {
  def handleWebCommand(request: play.api.mvc.RequestHeader, buildLink: play.core.BuildLink, path: java.io.File): Option[play.api.mvc.Result] = {
    val pathPattern = """/@hello/([a-zA-Z0-9_]+)""".r
    request.path match {
      case """/@hello""" => Some(Results.Ok("Hello!"))
      case pathPattern(name) => Some(Results.Ok("Hello, " + name + "!"))
      case _ => None
    }
  }
}

// 以下DIのためのお決まりのコード
@Singleton
class HelloWebCommand @Inject() (webCommand: WebCommands) {
  webCommand.addHandler(new HelloWebCommandHandler())
}

class HelloWebCommandModule extends Module {
  override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = {
    Seq(bind[HelloWebCommand].toSelf.eagerly)
  }
}

DIのbindのためのコードが多くて目がやられますが、HelloWebCommandHandlerというのが処理本体です。 簡単ですね。パスにマッチしたらなにか結果をOptionにくるんで返せばいいわけです。 あとはモジュールをapplication.confで登録すれば動きます。

play.modules.enabled += "controllers.HelloWebCommandModule"

以上、scalamatsuri前の小ネタでした。

アプリケーションに合ったExecutionContextを使う

scalaではFutureなどの裏側ではExecutionContextが動いています。ということはExecutionContextの使い方がいまいちだとFuture周りで問題が起きることになります。

よく起きる問題の1つとして、標準のExecutionContextがいまいちだった、というのがあると思います。 標準のExecutionContextはダメというか、適さないパターンがあるのですが、あまりよく考慮されずに使われてしまう印象があります。 まあ悪いのはコンパイラの親切すぎるエラーメッセージでしょう。

scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> Future { 1 + 1 }
<console>:9: error: Cannot find an implicit ExecutionContext. You might pass
an (implicit ec: ExecutionContext) parameter to your method
or import scala.concurrent.ExecutionContext.Implicits.global.
              Future { 1 + 1 }
                     ^

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> Future { 1 + 1 }
res2: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@2bbaf4f0

scala> res2.foreach(println)
2

このようにScalaでFutureを使おうとすると、ExecutionContextがないからimport scala.concurrent.ExecutionContext.Implicits.globalをどうとか言われるので、とりあえず使っとくかーみたいな気分になっちゃいます。

標準のExecutionContextの特徴

まず、標準のExecutionContextはスレッド数がそんなに多くありません。2.11では最大でもコア数分のスレッドしか立ち上がりません。 それではデッドロックが起きやすいので2.12ではコア数+256までとなっているようですが、用途によってはもっと増やしたいですね。

それから、標準のExecutionContextはForkJoinPoolを使って実装されています。ForkJoinPoolは

It is designed for work that can be broken into smaller pieces recursively

https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html

とのことで、parallel collectionとかには向いてそうだけどWebアプリケーションとかには向かなそうですね(ダメってこともないだろうけど)。 みなさんの用途には合ってるでしょうか?

アプリケーションに合ったExecutionContextを使う

標準のExecutionContextをやみくもに使うのはやめて、アプリケーションに合ったExecutionContextを使いましょう。 作り方はExecutionContext.fromExecutor, ExecutionContext.fromExecutorServiceを使えばjava.util.concurrentで作ったExecutor/ExecutorServiceを元にExecutionContextを作る、で大抵事足りる気がします。

Futureを使う時にJavaのExecutorServiceを利用する - CLOVER

フレームワークを使っている場合はフレームワークが独自のスレッドプールを用意していることがあります。 Playの場合はakkaのスレッドプールを利用していて、import play.api.libs.concurrent.Execution.Implicits._ することで有効になります。 それから、ドキュメントのスレッドプールについての箇所は必読です。

ライブラリのコードに標準のExecutionContextを含めない

Futureなどを用いたライブラリを作るときは、標準のExecutionContextをハードコードしないように注意してください。 ExecutionContextはメソッドの引数経由で渡すなど、なんらかの形で利用者が調整できるようにしましょう。

まとめ

ScalaではFutureなどのおかげで気軽に非同期処理などが利用されますが、その裏にはスレッドプールであるExecutionContextがいます。 しかし、ExecutionContextはimplicitパラメータとして暗黙のうちに引き回されるため、よくも悪くもあまり意識されません。困ったもんですね。

ExecutionContextついてはその実装を見てみることも参考になりますが、やはりJavaのスレッド周りの知識が不可欠です。 Scalaを始めたけれどJavaはよく分からないという人はjava.util.concurrent(便利)の使い方を学んでおくと雰囲気がつかめるかなと思いました。

DIについてあれこれ

Dependency Injectionとはコンポーネント間の依存関係をプログラムのソースコードから排除し、外部の設定ファイルなどで注入できるようにするソフトウェアパターンである

ってwikipedia先生が言ってました。

Scalaにおける最適なDependency Injectionの方法を考察する 〜なぜドワンゴアカウントシステムの生産性は高いのか〜 - Qiita を読んでいろいろ考えたので、なんで今さらって感じのことを書きます。

ScalaでDIというとDIコンテナとかCake PatternとかReader Monadとかって話になっちゃうんですが、これらはいかにかっこよくDIするかの話であって、別にこういった道具やパターンを使わなくてもDIは可能という話です。

Constructor Injection

簡単な例で考えます。今ここにUserRepositoryにべったり依存しているUserServiceがあります。

class UserRepository {
  def findAll = ???
}

class UserService {
  val userRepository = new UserRepository
  def getAllUser = userRepository.findAll
}

UserServiceの中でUserRepositoryをnewしているので良くない。UserServiceのテストするのにUserRepositoryのこと考えてテストしなきゃいけなくてめんどくさい。なので

class UserRepository {
  def findAll = ???
}

class UserService(userRepository: UserRepository) {
  def getAllUser = userRepository.findAll
}

というように、UserRepositoryを外から与えるようにしよう。こうすればUserRepositoryの代わりにMockUserRepositoryを使ったりして楽にテストができますね。ちなみにこれはconstructorから注入してるからconstructor injection。

ところでUserRepositoryをnewしてUserServiceに与えるのって誰がやるんだって話になりますが、手動でやるんですね。だからこれは手動DIと呼ぶことにしましょう。

DIを手動じゃなくて自動でやりたくなったらDIコンテナを使い始めます。DIコンテナの何が便利かっていうと手動でやっていたUserRepositoryをnewしてUserServiceにつっこむというのを勝手にやってくれるということです。かっこよく言うとオブジェクトのライフサイクル管理を任せられる、といったところでしょうか。これはこれでとても便利です。

ところでScalaではCake PatternとかでDIできるからDIコンテナなんて不要、と言う煽りをよく見るんですが、おかしいですよね。JavaだろうとPHPだろうとDIコンテナがなくてもDIできるし、DIコンテナがやってくれる仕事はCake Patternではやってくれません。

PlayでのDI

PlayではDIコンテナとしてGuiceを使っていますが、DIコンテナありきで話が進んだわけではありません。constructor injectionベースで疎結合にやっていこうぜという話が出発点でした。PlayはGuiceを使ってる、っていうのは正しいけれど、気持ちはconstructor injectionなのです。なんかそういう話を前に書いてました。

tototoshi.hatenablog.com

Minimal Cake

で、Scalaにおける最適なDependency Injectionの方法を考察する 〜なぜドワンゴアカウントシステムの生産性は高いのか〜 - QiitaのMinimal Cakeの話です。

Minimal CakeはCake Patternに制約を設けたデザインパターンとして紹介されていますが、なんかピンと来ませんでした。

でも作者の方のコメントはピンと来ました。

Scala - Minimal Cake Pattern のお作法 - Qiita

しばらくの間は Minimal Cake Pattern のメリットが明らかでなかったので、コンストラクタによる注入パターンも書かれ続けていました。しかし依存先モジュールが多いクラスが生まれてくると、だんだん Minimal Cake Pattern の便利さが分かってきました。コンストラクタでは引数の順番を気にしなければいけないのに、Minimal Cake Pattern だと MixIn の継承順序はどうでもいいのです。依存先クラスが10個以上あるクラスに対して正しい順番でコンストラクタ引数を与えるのは苦行でしかありませんでした 。

Scala界隈の一連のワイワイガヤガヤは忘れましょう。ただInjectionの仕方を工夫したと考えたほうがスムーズに頭に入る気がします。

以上とりとめのない話でした

scala用のfixtureライブラリ作った

昔作ったscalikejdbcのfixtureプラグイン、これ別にPlayのプラグインにすることはなかったなーとちょっと思ってたんですが、最近実際困りはじめたので、Playに依存しないfixtureライブラリが欲しくなったので作りました。

https://github.com/tototoshi/scala-fixture

依存しているライブラリはないので、SlickのプロジェクトでもScalikejdbcのプロジェクトでも使えます。

インストールは

libraryDependencies += "com.github.tototoshi" %% "scala-fixture" % "0.1.0"

使い方はscalikejdbc-fixtureとだいたい同じ。Ups, Downs と書いてたのが、SetUp,TearDownで動くようにしてます。(念のため?Ups, Downsでも動くようにしてます)

#!SetUp
INSERT INTO users(id, name) VALUES (1, 'user1');
#!TearDown
DELETE FROM users WHERE id = 1;

あと、1000件くらいINSERTしてやるぜ!ランダムなデータ突っ込むぜ!みたいなときのためにScalaのコードでもかけるようにしました。

import java.sql.Connection
import com.github.tototoshi.fixture.FixtureScript

class MyFixtureScript extends FixtureScript {

  override def setUp(connection: Connection): Unit = {
    connection.prepareStatement("insert into users(id, name) values (3, 'user3')").execute()
  }

  override def tearDown(connection: Connection): Unit = {
    connection.prepareStatement("delete from users where id = 3").execute()
  }

}

テストコードはこんなかんじになります。 beforeでsetUp, afterでtearDownすると良いでしょう。 詳しくはREADMEを読んでください。

import org.scalatest.{ BeforeAndAfter, FunSuite }
import com.github.tototoshi.fixture._

class FixtureTest extends FunSuite with BeforeAndAfter {

  val driver = "org.h2.Driver"
  val url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"
  val username = "sa"
  val password = ""

  val fixture = Fixture(driver, url, username, password)
    .scriptLocation("db/fixtures/default")
    .scriptPackage("com.example.fixtures")
    .scripts(Seq("script1.sql", "script2.sql", "MyFixtureScript"))

  before {
    fixture.setUp()
  }

  after {
    fixture.tearDown()
  }

  test("load fixtures") {
    // write tests
  }

}

Playに依存しないコードを書く

フレームワークの便利さとコードの柔軟性とのバランスの話。

PlayにはいわゆるMVC的な機能の他にいろいろと便利っぽいモジュールが付いていますが、 実際そいつらを使っていると依存関係や柔軟性の面でちょくちょく困ることがあります。 最近何度か困ったのはプロジェクトを分割する場面です。

Playでプロジェクトをスタートするときはwebアプリケーションのプロジェクトとしてスタートするわけで、 シンプルに次のような構成をとります。

.
├── app
├── build.sbt
├── conf
├── public
├── test
└── test

しかし、だんだんプロジェクトが進むにつれて、あ、webアプリだけじゃなくてバックエンドでバッチ動かす必要あるわ、となったりします。バッチからも今までに書いたコード使いたいな。じゃあ共通コードをcoreっていうサブプロジェクトに移そうか。coreはplayには依存させたくないなあ。

こんな構成にしたい。

.
├── batch
│   └── src
├── build.sbt
├── core
│   └── src
└── web
    ├── app
    ├── conf
    ├── public
    └── test

でもこれが意外にめんどうだったりします。

今まで書いたコードがPlayに依存していると、そのコードはbatchでは使うことができません。 たとえばPlayにはwsというHTTPクライアントライブラリが付属していますが、wsはplay.api.Applicationに依存しています。つまりPlayアプリケーションが起動している状態でなければ使えません。 従って、batchでもHTTPクライアントを使いたい場合はwsではなく他のHTTPクライアントへの置き換え作業が発生します。最初っからws使わなければよかったね...

wsのほかにも

あたりは動作するためにplay.api.Applicationが必要なのでめんどうです。

(追記・捕捉)
Play2.4からはDI前提のAPIにApplicationに依存しないものもあります。
ただしモジュールレベルでは依存関係があるので、結果的にはcoreをPlayに依存させることになります。
互換性のために以前のAPIを残しているからと思われるので今後改善される可能性はありそうです。

あと、configなども

// play.api.Play.currentはplay.api.Applicationのインスタンス
play.api.Play.current.configuration.get.....

というようにplay.api.Applicationをいじるコードを書いてしまいがちなので注意が必要です。 (それ以前にテストしにくいからやめたほうが良いですね)

設定ファイルを読み込むところは局所化して、必要な設定はコンストラクタ経由で渡すとかそういう手間のかけ方をするのが良いでしょう。

まとめ

  • コードの再利用を考えるとPlayに依存したコードをかけない場面は多い
  • ws, cache, dbはPlayにべったり依存している上、それを使ったコードは再利用したい場面が多いのでほいほい使わない
  • play.api.Application, play.api.play.current をあちこちで使わない