DBFlute on Scala パイロット版

DBFlute Scala」でググるとヒットするし、
1.0.x系がひと段落したので、しっかり紹介しておこうかと。

実はこんなのあります。1.0.5Kで使えます。

// DBFlute on Scala
http://dbflute.seasar.org/ja/tutorial/onscala.html

あくまでパイロット版

ポリシーのところに、
「1.0.xはパイロット版、1.1から本気」とあるように。
試しに作ってみたという感じです。
とはいえ、一通りの機能がちゃんと動きます。

というか、別に全てをScalaにしたわけではなく、
DBFluteランタイムはJavaのものをそのまま使って、
自動生成されるクラスがScalaになって、
Javaとの連携をしてくれるというようなもの。

だから、Java版の安定したコアロジックがそのまま
Scalaのインターフェースで利用できるという感じです。

dbflute-scala-exampleあります。
自動生成済みでH2 Database利用なのですぐに試せます。
 -> dbflute-scala-example| Github

未熟ながらScalaっぽさの追求

o 検索されるEntityとListはImmutable
o NotNull制約のないカラムはOption型
o カリー化を使ってオプション引数うまいこと
o 自分でnewしてsetとかしない

などなど、できる限りScalaの流儀に近づけています。
って、実際に近づいてるかどうかわからないですけど、
そこはまあパイロット版ということで、これからこれから。

また、DIコンテナは Google Guice を前提にしていますが、
あまりDIするという文化ではなさそうなので、
Behaviorはどこでも取得できるようにしています。
(なので、Guiceは内部コンテナ的な扱いで)
// 一件検索 (会員IDが1番で、会員ステータスも取得)
val member = DBFlutist.memberBhv.selectEntity { cb =>
  cb.setupSelect_MemberStatus
  cb.query.setMemberId_Equal(1)
}

// 検索結果のEntity
// Option型のforeach使ってみたけど、こういう風に使うもん?
member.foreach { mb => // 会員: Option[Member] (Immutable)
  ... = mb.memberId // *会員ID : Int
  ... = mb.memberName // *会員名称 : String
  ... = mb.memberAccount // *会員アカウント : String
  ... = mb.birthdate // 生年月日 : Option[LocalDate]
  ... = mb.formalizedDatetime // 正式会員日時 : Option[LocalDateTime]
  if (mb.isMemberStatusCode_Formalized) { // 区分値判定
    ...
  }
  // 会員ステータス: Option
  ... = mb.memberStatus.map(_.memberStatusName)
  ...
}

but CBはわりとそのまま

ただ、ConditionBeanはわりとそのままです。
もちろん、
「Scalaになるだけで素敵になる部分」がありますし、
「あんすこどっと」(_.)ができるだけ使えるような配慮をしたり、
Java版よりかは良くなっていますが、全体的にはそのまま。

これは、ConditionBeanの特徴とScalaのお作法の間で
いまいち折り合いがつかない感じがあって。。。

「リレーションを辿る、逆にそれ以外できない」
っていう ConditionBean の最大の特徴をキープしつつ、
「Immutableでなければならない」
という規約を満たすアイディアが浮かばなかったからです。

jfluteのScalaの勉強不足か、将来のScalaなら何かできるか、
DBFluteのやり方を見直してちょっと形を変えるべきか、
それを見極める時間がちょっとないので、
「中途半端な変更」よりかは、ひとまず「Javaと見た目同じ」
というのをキープするようにしました。

ただ、new MemberCB() はないだろうということで、
「Callback限定Mutable」で cb を扱うようにしてみました。
// リスト検索
// o 会員ステータス、会員サービスとラービスランクを取得
// o 'S'で始まる正式会員、200円以上の(支払済)購入したことのある会員
// o 若い順に並べて生年月日が不明の会員は後ろへ、同じものはIDで並べる
val memberList = DBFlutist.memberBhv.selectList { cb =>
  cb.setupSelect_MemberStatus
  cb.setupSelect_MemberServiceAsOne.withServiceRank

  cb.query.setMemberName_PrefixSearch("S")
  cb.query.setMemberStatusCode_Equal_Formalized

  cb.query.existsPurchaseList { purchaseCB =>
    purchaseCB.query.setPurchasePrice_GreaterEqual(200)
    purchaseCB.query.setPaymentCompleteFlg_Equal_True
  }

  cb.query.addOrderBy_Birthdate_Desc.withNullsLast
  cb.query.addOrderBy_MemberId_Asc
}

Callback限定Mutable

ConditionBeanもそうですが、更新系などは、
Mutableなオブジェクトが降ってくる Callback になっています。
恐らくここが残念なところと思われるところではないかと。

コンパニオンオブジェクトのapply()によるEntityの生成も考えましたが、
DBFlute特有の便利メソッド、区分値の設定などの補完のしやすさ、
もろもろを考えたときに、
apply()だとそのメリットがうまく表現できないなーって。

なので、とりあえずは更新専用のMutableなEntityを用意して、
ただ、自分で new するようなことはせず、
Callbackの中だけでしか取り扱えない Mutable であれば、
間違いも起きにくいかなというところで、いったんはこれを採用。

その代わり、今までのDBFluteの便利機能がまるまる利用できます。
// 会員IDが7番の会員を更新 (名前はシャビ、正式会員)
DBFlutist.memberBhv.update { mb =>
  mb.memberId = 7
  mb.memberName = "Xavi"
  mb.memberStatusCode_Formalized
  mb.versionNo = ... // 編集画面表示時に検索されたバージョン番号
}

DBFluteらしさは失わず

どこまで流儀に従って、
どこまでDBFluteらしさを強調するか?

これがまだわからない。

ただ、今までDBFluteが培ってきた
「こうだと現場がうれしいだろう」という細かい配慮。
DBFluteがよく頂く言葉でもあり、同時に生命線とも言える
「かゆいところに手が届いてるフレームワーク」
という特徴。

これを壊してしまっては、そもそもDBFluteである必要がない?
ということもあるので、ひとまず短い時間でのチャレンジ暫定実装。
というのは、Scalaには既に良いフレームワークがたくさんあるようで...

まずは、Slickと呼ばれるO/Rマッパーが、
Scalaっぽさ体現したタイプセーフなDBアクセスを実現しています。
まだ勉強中ですが、かなり気合いの入ったもののようです。
ScalikeJDBCも、人気のフレームワークのようで、
ググってブログ読んだりしてよく参考にさせて頂いています。
すんごい良くできてるなー、って感心しまくり。

もちろん、DBFluteとこれらフレームワークでは、
コンセプトが違うので簡単な指標で比較できるものではないですが...

「リレーションを辿る、逆にそれ以外できない」
ConditionBean の、単なるタイプセーフじゃない、
RDB の構造を大切にする目的ドリブンのインターフェース、
「ER図のリレーション線を辿って歩いているかのような感覚」
そういうのがないならば、別に既存のフレームワークでいいわけで。

そもそものモチベーションも、DBFluteユーザーの方々が、
「Scalaやってみたいけど、DBFluteないんじゃ結局つらそっ」
と、みなが口々に言ってくれているので(^^、
Scalaへのアプローチ心をDBFluteが損なわせてもよくないので、
とりあえずまんまでも動くもの作ろう、そんなところから始まり。

実際、DBFluteを全く知らないScalaプログラマーの方々が、
DBFluteを見て使いたいと思うかと言ったら、
あまり思ってもらえるイメージはやっぱないかなーって笑。
(別にJavaの方でも似たようなものですけど)

一方で、最近、切に思うことですが...

DBFluteを好きな人の多くは、
「DB設計の得意な人、データモデルを大切にする人」

逆に言うと、そういう人が好きになってくれるんだなぁと感じているので、
興味を持ってくれる人もほんの少しはいるかも知れない!?
例えば、50人に1人、興味もってくれる人がいればうれしいなって。

なので、それはそれで「チャレンジ」ということで、
どうせやるなら、

DBFluteの不思議な魅力を表現したScala

にしてみたいなと。

DBFluteってそんな律儀だっけ?

DBFluteを長く使ってきた方々はこう思うかもしれません。

「そもそも、DBFluteってJavaの流儀に従ってる?」

そうね、そんなことないね。
Javaというか、一般の流儀、流行の流儀、
そういったものに真っ向から反発して独自路線を貫いて、
そろそろ8年が経とうとしています。
(全面的な)流れるようなインターフェースとか、
いまでも絶対やらないみたいな笑

そんなアウトローフレームワークでも、
めでたく7月に月間サイト訪問者数 5000 に達しました。
これ高いの低いのか全然わかんないんですけど、
(どうやって測っているのか?もあるでしょうから)
(ちなみに訪問数は、訪問者数のおよそ二倍強くらい)
ただ、その前からの数と比べて、そして、8月は5300と、
増えていること確かで、まだまだ右肩上がりを継続中です。

Javaの世界の流儀とかどうでもよく、
世の中の流行とかまったく気にせず、
「現場の問題を解決できるかどうか?」
「かっこわるくても安全なインターフェース」
を追求してきたフレームワークでした。

で、それこそがDBFluteの魅力でもありました。
だから、コアユーザーの方からは、

「いまさら流儀を追いかけるとか、なに言ってんの?」

って声が聞こえてきそうです(^^
まあ、That's right なのでね、
そんなに悩み過ぎてるわけじゃないですよ。

ただ、やるからには、Scalaの良い文法を最大限活かして、
その持ってる「らしさ」を強調できたら最高だなと思います。
その流儀ってのも、プログラミングにおいて良い方法であると
考えられているから流儀になっているわけでしょうから、
うまく取り入れた上での DBFlute になれれば一番なので。

まだそのアイディアがない。
でも...

フレームワークもスモールスタート!
まずは「動く」ところから

このパイロット版は、
Scalaのバージョン「2.10.4」で作られていますが、
焦って変な形で提供するのではなく、
2.11 もしくは、2.12 とかもっと先のバージョンでの
展望も見据えていきたいと。

あとね、どのみちね、やっぱりね、コンパイルがなかなか...
DBFluteも悪いんだけど、でもJavaでは難なく動くものが、
もうこれ無理だなってレベルになったりするので、
そこはちょっと時を待ちたい。。。

# 特にjflute個人にとっては、やはりコンパイルスピードは重要で...
# 自分の「ゆびの動き」を止められるので圧倒的にすきではないから。

チャレンジは続く

実は、今週末の ScalaMatsuri で、
スピーカー応募しようかと思ってました。
相変わらずの jflute 得意のKYチャレンジ!

だけど、どうしても Mutable が解決できなくって、
「ああ、まだまだこりゃだめだな」と。
まあ、豪華なセッション内容見たら、そもそも応募したところで
絶対に採用されないなという感じではありますけど笑。

って、気付いたら満員御礼のキャンセル待ち30人以上(><。
ぐはぁぁぁ...まあどのみち両日は行けなさそうだったわけだし、
やる気のある人たちに行ってもらって、ぼくはTwitter観戦。
発表される皆様、応援しています!

...
...

Java版のDBFluteを極めた現場のエンジニア(の数人)が、
Scala版のDBFluteハンズオンを予約してくれているので、
ひとまずはそこで互いに学びながら試してもらおうかなと(^^。

関数型ということで、Javaとは全く違う言語。
最初は、Good評判で有名なGitBucketのソースを落として、
正面突破リーディングしてみて「ぜんぜんわからーん」と笑。

そして「Scala逆引きレシピ」を買って、
ランチ時間にちょっとずつお勉強。
そして、DBFluteScala版への移植、
壁に立ち向かっては乗り越えるの繰り返し。

でも、DBFluteで対応するということで、
「あの機能はどう実現した、あの部分でこういう文法使った」
とかとか、
頭の中でフレームワークと言語が立体的に積み重なって、
それが辞書みたいになるんですよね。

業務で一行たりとも書いたこと無いへなちょこなわけだしね、
こういう風にすることで
「自然とScalaの今後の動向や話題に敏感になる」
っていう、jflute流の新しい言語の覚え方(^^。

// DBFluteの展望、多言語!? そして感覚と行動
http://d.hatena.ne.jp/jflute/20140428/dontthinkfeel

では、「密かに」って書いてたんですけど、
行動すると言ったからには、行動してみたよ、みたいな。