scalikejdbcのcode generatorとflywayのsbt pluginを組み合わせて頑張ろうとしてる話

「頑張ろうとしてる」とは、どういうことかというと
「とりあえず方法思いついたけど、これで本当にうまくやっていけるかなぁ?と半信半疑なので、意見を伺いたい状態」
ということ。


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プラグインはたぶん使わない
    • playにべったり依存するならいいけど、ドメインの定義(?)のあたりは、play本体に依存しないようにしたい。sbtのモジュール分けたい。など
  • flyway自体は、jarを落としてきて直接使うこともできるけど、jarをgitに直接入れるのは嫌なので、(flyway公式が出してる)sbt plugin使うことにした

という感じなのです。
続いて、具体的に自分がやろうとしている、というかやってみてサンプルまで作ってみたやつの説明

  • 生成したコードはいじらない、という方針だが、いつコード生成するのか?
  • 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