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をいじるコードを書いてしまいがちなので注意が必要です。 (それ以前にテストしにくいからやめたほうが良いですね)
設定ファイルを読み込むところは局所化して、必要な設定はコンストラクタ経由で渡すとかそういう手間のかけ方をするのが良いでしょう。
まとめ
Play2.4のプラグインシステムにある欠陥について
私の理解が正しければ、Play2.4のプラグインシステムにはプラグインの起動順が制御できないという大きな欠陥があります。Play2.3以前はplay.pluginsファイルに優先度を記述するというイケてない感が漂うやり方ではありましたが、問題なく制御することができていました。
Play2.4からはプラグインをDIコンポーネントとして記述するようになりました。play.pluginsファイルはなくなり、優先度ではなくコード中に記述してあるコンポーネント間の依存関係を利用して起動順が結果的にうまくいくようになっています。
ただし全てのプラグインがコードを介して依存しているわけではありません。例えばflyway-playのようなデータベースマイグレーションを行うライブラリはscalikejdbc-fixtureのようにデータベースフィクスチャプラグインよりも先に起動する必要がありますが、コード上で依存させるわけにはいきません。flyway-playではなくplay-evolutionsを使うときや、マイグレーションツールを全く使わないという選択ができなくなるためです。
Playの開発チームとしてはプラグイン間にコードにはない単純な起動順という関係があるのは間違いであるという態度を取っています。 つまりflyway-playとscalikejdbc-fixtureの実装に責任があるとの指摘を受けました。 ちょっと何を言ってるのかわかりませんが、少なくとも2.3のプラグインからの移行先としてはこのようなケースは当然考慮されるべきです。そもそも移行期間すら設けられずに行われた変更なのです。
まとめるとPlay2.4のプラグインシステムではPlay2.3で行っていたプラグインの起動順制御ができないため、プラグインの組み合わせによってはPlay2.3から2.4への移行はできません。Play2.4の重大な欠陥と言えますが、1日やりとりしてもPlay開発チームと話がかみ合っていないので、修正される見込みはないかと思います。
https://github.com/playframework/playframework/pull/4960
追記
そのあと、一応の対処法は教えてもらいましたので書いておきます。 教わった例はFixtureコンポーネントのラッパーを書いて、それをMigrationsComponentに依存させろ、というもの。
class DBFixturesComponentWrapper @Inject() (migrations: MigrationsComponent) { val dbFixturesComponent = ??? }
これはMigrationsComponentをコンストラクタで受け取ってるのでMigrationが先に起動するわけですが、FixturesComponentはDIではなく手動でインスタンス化しています。 次のようなコードにするほうが自然に見えるかもしれません。DIで起動順を制御しようとするのは結局失敗だったということです。
class DBFixturesComponentWrapper @Inject() { val migrationsComponent = ??? val dbFixturesComponent = ??? }
ビアバッシュメモ
ピザの量
- 人数÷3枚
- LまたはXL(3000-3500円くらい)
- クアトロ3種類
飲み物
- カクヤス
- ビール、人数×1.5本 (350ml缶)
- お茶、お茶、炭酸、非炭酸
- 当日注文だと冷えてないので前日までに注文できると良い。
お金
- 最初に集める。
- 1人1000円だと足りない。1500円だとおつりがめんどくさい。よって2000円。
- 2000円だとちょっと多いかもしれないので学生や発表者をひいきする。
- 注文の量を増やすなら酒じゃなくて食べ物にしたほうが余らない。
その他
- 紙皿、紙コップ、ウェットティッシュ
- http://d.hatena.ne.jp/hyoshiok/20081017
Typesafe が社名変えたがってる話
mixi 社はいつモンスターストライク社に変わるんだろうという冗談を言っていたら、なんと Typesaefe 社が社名を変えたいと言い始めました。最初エイプリルフール的なものかと思いましたが、冗談じゃないようです。冗談じゃないよ。
May 18, 2015 | What’s in a name? | Typesafe
自分は Typesafe 社の人間ではないし、人様の会社の社名変更に口を出すとかも変な話ですが、open process だ、意見をくれと言われたらそりゃ嫌って言うよ、だってめんどくさいもん!!
実際typesafeの社名とか全く興味ないしopen processとか言ってるけど反対多くても変えるんでしょ。自由に変えてもらってもいいけど、自分としてはめんどくさいだけでメリットないから意見ないかって聞かれたらそりゃ反対って言うよ、って感じ。
— Toshiyuki Takahashi (@tototoshi) 2015, 5月 21
具体的に何がめんどうか、については瀬良さんのツイートをご覧ください。
Renaming #typesafename will be a burden to Scala community, e.g. ivy repo, groupId and out-dated docs. Please put OSS community first.
— Kazuhiro Sera (@seratch) 2015, 5月 20
↓ というわけで便利なボタンを設置しました。ご利用ください。
WEB+DB Press 86 に PHP での画像処理についての記事を書きました
4/23 発売の WEB+DB Press Vol.86 に PHP での画像処理についての記事を書きました。 画像をこねくり回すという内容ではなく、Web アプリで画像を扱うときに気にするべきことを広く浅くカバーしようという内容です。基本的な Imagick (imagemagick) の使い方から、有名な最適化 Tips、それからジョブキューを活用した負荷対策や、サムネイルの動的生成などについて実際に pixiv で使われている技術をベースに解説しています。PHP に限らずこれから画像を扱うシステムを作ろうとしているけれど、ちょっと自信がないなあという人にはおすすめの内容です。是非手に取ってみてください。
- 作者: 結城洋志,沖元謙治,足永拓郎,林健太郎,大竹智也,内田誠悟,伊藤直也,中山裕司,hiroki.o,泉水翔吾,佐藤太一,高橋俊幸,西尾泰和,舘野祐一,中島聡,橋本翔,はまちや2,竹原,麻植泰輔,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2015/04/23
- メディア: 大型本
- この商品を含むブログを見る