「頑張ろうとしてる」とは、どういうことかというと
「とりあえず方法思いついたけど、これで本当にうまくやっていけるかなぁ?と半信半疑なので、意見を伺いたい状態」
ということ。
scalikejdbcのコミット数2位なのに、今までそもそもDBを普通に使うアプリを(仕事でも趣味でも)あまり書かないとか、仕事でDB扱うものでも、すでにDBのライブラリ選定済みで途中からチームにjoinのパターンが多くて、個人的にscalikejdbcを普通のユーザーとしてほとんど使ったことがないわけです。
それで、最近新しいプロジェクトで、ライブラリ(やその他プロジェクトの構成)とかを自由に選べる機会ができそうなので、標題のとおり、scalikejdbcとflywayと組み合わせて頑張ってみようとしている話を書きます。
まず前提の説明とか
- skinnyとか使わずにscalikejdbcだけを直で使うなら、code generatorのsbt plugin使わないとボイラープレート自分で書かないといけなくなるので、やはり使いたい
- その際に、生成したコードは直接いじらない。という方針にしたい
- 直接いじると、テーブル定義変えたあとは、そのコードを重複してメンテする必要がでてくるので
- それは本来想定されているscalikejdbcのcode generatorの使い方ではない(少なくとも瀬良さんはそう言ってた気がする)
- メソッドの追加や削除もできないので、不便も生じる
- scalikejdbcのmapper generatorをメンテするおじさんになってる(自分のscalikejdbcへの貢献の半分くらいはそれ)ので、いざとなればpull reqすればいいか*1
- やっぱり無理が出てきたら「生成したコードは直接いじらない」を諦めるか、code generator自体を独自のものを作って組み込んでしまう?
- flyway使うのは、すごく深い理由があるわけでもない
- それしか知らなかった。あと自分も少しは触ったことある、チームメンバーも触ったことがある人がいて、少しは慣れてる、など
- playのevolutionや、tototoshiさんが作ってるplay-flywayプラグインはたぶん使わない
- flyway自体は、jarを落としてきて直接使うこともできるけど、jarをgitに直接入れるのは嫌なので、(flyway公式が出してる)sbt plugin使うことにした
- sbtのコマンド経由で呼び出しやすいようにしてるだけで、大したことしてなさそう
- https://github.com/flyway/flyway/blob/flyway-3.1/flyway-sbt/src/main/scala/org/flywaydb/sbt/FlywayPlugin.scala
- http://flywaydb.org/documentation/sbt/
という感じなのです。
続いて、具体的に自分がやろうとしている、というかやってみてサンプルまで作ってみたやつの説明
- 生成したコードはいじらない、という方針だが、いつコード生成するのか?
- sbtのsourceGeneratorを使って、コンパイルの度にDBに接続したら遅くなりそうだし、そもそもDBがないとコンパイルすらできなくなるのは、ありえなそうなので却下
- じゃあ結局手動でscalikejdbcGenAllなどのコマンド打つ?そして、その生成したコードは(いじらないけど)gitには登録する、しかなさそう
- でもせめて、それをやり忘れた場合に「生成したコードとflywayのスキーマの定義が食い違っていた」としても、CIの段階でチェックして失敗にしたい
- なのでCI環境で
- 一時的なテスト用Databaseを作成
- そこにflyway適用
- scalikejdbcGenAllForceを実行
- 一時的なテスト用Databaseは必要なくなったので削除
- 同じコードが生成されるので、gitの差分がでないはず!というのをチェック(CI環境にpushする前に適切にscalikejdbcのコマンド実行して、生成されたコードがgitに登録済みなら、という意味で)
までやってみたのが、以下のサンプルリポジトリのやつです
https://github.com/xuwei-k/scalikejdbc-flyway-sbt-example
playやscalikejdbcやflywayに限らず、というかScalaに限らなくてもいいですけど、こういうのみんなどうしてるんですかね・・・。
scalikejdbcのgeneratorがそもそもこういう使われ方をあまり想定してないので、少なくともscalikejdbcでここまでやってる人いないだろうなぁ。
上記のチェックの仕組み作るのわりと面倒なので
「project/Build.scalaに、このあたり https://github.com/scalikejdbc/scalikejdbc/blob/2.2.4/scalikejdbc-mapper-generator-core/src/main/scala/scalikejdbc/mapper/Table.scala のclass直接定義して、このあたりのKey https://github.com/scalikejdbc/scalikejdbc/blob/2.2.4/scalikejdbc-mapper-generator/src/main/scala/scalikejdbc/mapper/SbtKeys.scala#L31-L32 経由で渡してしまえば?」
という案も出してみましたが、それほどチームメンバーの反応よくなかった?し、結局色々トレードオフで難しいですね。
もう少しその代案を詳しく説明すると
- Build.scalaに直接定義書けば、flywayのsqlのファイルと2つメンテはしないといけなくなる
- Build.scalaにテーブル定義(をScalaで)書くということは、つまりコード生成する際に、DB自体を全く使わない、ということ
- これもまた、scalikejdbcのgeneratorの本来の使い方ではない*2
- けど「直接生成されたファイルをいじる方針」にするよりは、だいぶコード少ないというか、メンテコストは低い、と思う
- この方法だと「わざわざ一時的なテスト用Databaseを作成して、scalikejdbcのコマンド実行して、チェック」という一連の作業は必要なくなる
といった感じでしょうか?
とりあえず、なにか感想とか意見あればください。
追記:
その後のtwitter上での反応 http://togetter.com/li/792281
*1:この方針でやるのに微妙に不都合あったので、すでにいくつかpull reqした
*2:これができるように、ある意味自分が無理やり拡張ポイント作った https://github.com/scalikejdbc/scalikejdbc/pull/370