Spring MVC と Thymeleaf 2.x と Value Object

Spring Boot 1.2.4を前提にしています。 Value Object をどうにかして不変にしたいなと思いがんばる話です。
がんばりたくない人はお帰り下さい。

Value Objectへのデータバインド

Spring MVCではStringのコンストラクタ1つだけを持つオブジェクトにリクエストパラメータを自動バインドしてくれる。 これを利用してフォームの値をオブジェクトにバインドしようとするものの…

//Value Object 普段はBeanValidationとか付けるけど省略
public class Price {
     private final BigDecimal value;

     public Price(String value) {
          this.value = BigDecimal.valueOf(value);
     }
     
     public String getValue() {...}
}

//Formにバインドする商品登録オブジェクト。商品名とかは省略
public class ItemRegisterRequest {
     Price price;

     public Price getPrice() {...}
     public void setPrice(Price price) {...}
}

//Controllerは省略…

バインドするForm

<form th:object="${parchase}">
      <input type="text" th:field="*{price}"/>
</form>

これだとパラメータのバインドは上手く行くものの *{price}がPriceオブジェクトのtoString結果を出力してしまう。 なので、

<form th:object="${parchase}">
      <input type="text" name="price" th:value="*{price.value}"/>
</form>

として、nameと、valueを分けるはめになる。
微妙かと思ったけどこれはこれでもしかしたらわかりやすいのではと…(思いたい

あと、データソース層にMyBatisを使ってると、結局Value Objectのメンバ変数のfinalを外す ことになって…コンパイラがチェックしてくれるレベルの不変性は失われてしまう。(また別に書く

論理的に不変ならまぁ及第点か

ドメイン駆動設計

というか今のところの雑で感覚的な理解をメモ

そのソフトウェアを使って行われる活動の特殊性を見つけに行く。
この特殊性はその活動の存続理由であるような重要なもの。
その活動ならではと言えるようなもの。

この特殊性を煮詰め強調する形でアーキテクチャや、モデルに投影する。

そしてそれをもっとミクロな部分にも適用していく。
例えば汎用的な標準型であるBigDecimalをラップしたそのドメイン固有の数値型を宣言する。
その型にBigDecimalにはないそのドメインならではの特殊性を盛り込んで行く。
さらに汎用的なコレクション型をラップしたそのドメイン固有のコレクション型を宣言し、その特殊性を盛り込む。
そのドメイン複数のコンテキストがあるならコンテキストごとの固有型を宣言しそのコンテキストの特殊性を盛り込む。

そうして出来上がった個々の型を、良質なAPIとして機能させることで ビジネスとの乖離を防ぎつつ開発を加速させる。

SQLアンチパターン・レトロスペクティブ関西・リターンに参加して来ました

http://devlove-kansai.doorkeeper.jp/events/3022

初めに、会場を提供していただいた楽天さん、DevLOVE関西の運営に携わられたみなさんありがとうございました。

SQLアンチパターンの監訳者である和田さん親子(親子!ってのがすごいな)に来ていただいて 直接話しができるという事と、典型的なSI系の仕事に従事している自分でもドヤァできる話題だという事で参加を決めたのですが、予想以上の収穫があったように思います。

SQLアンチパターン

SQLアンチパターン

最初は和田卓人さんによる各パターンの解説から始まり、グループに分かれてアンチパターンの内、実際に自分達が経験したものについてディスカッションを行った後、共有というのを2セット行いました。その後26番目のパターンを考え、大質問タイムでは和田卓人さんにそれぞれ出たパターンに対してコメントしていただき、和田省二さんによるモデリング技法の講義に発展したりとすごかった。

最初のディスカッション(5人)

なかなか話がまとまりませんでしたが、一番盛り上がったのは「23章ディプロマティックイミュニティ」で、「DDLVCSリポジトリに入っているのに、DBを直接GUIツールでいじってしまう事があった」や「アプリケーションとDBのライフサイクルの違いが原因なのでは?」、「DBAが特権を持ってて手出しできない事もあるよねー。」と言った話が次々と出て来ました。 その時はどうすればよかったのかという話ができませんでしたが、これは本当に本に書いてある通りで継続的デリバリー等のベストプラクティスに乗っかるしかないなぁと思いました。 5章EAVの所ではNoSQLの話になり、「RDB」ってなくなるの?てきな話題が出たけど 住み分けが進むんじゃないかという結論にいたりかけたところで、和田卓人さん登場 「うんうん」と頷いておられた。 これで少し人見知りである私のテンションが若干上がった気がする(笑)

2回目のディスカッション(3人)

割りとまとまった話ができた。私は…。ここでは私が「10章サーティーワンフレーバー」の関して 一人で盛り上がってしまった感があり若干申し訳なかったり…

列に登録できる値を制限したいという目的に対してその値を別テーブルに切り出し、 参照整合性制約つけたらいいよって話なのですが「テーブル増えるやん」「そもそもテーブル増やす事に対する心理障壁でかいよな」とか「テーブルに切り出して変更されたら怖いやんとか」「画面のコンボボックスに表示する選択肢取るのにDBアクセスするのはめんどいやん」とかそんな感じでした。

26番目のパターン

私のテーブルでは、「リサイクルクエリ」というパターンができました。

  • 見つけ方は見たらわかります(やる前にわかれ
  • クエリを再利用するのが目的
  • 生のSQLをSELECT、FROM、WHEREでバラバラに分解して無理やり構造化してしまい、可読性が犠牲に
  • 解決策はORMのクエリビルダを使うなりしましょうということでした。  (後の和田卓人さんから頂いたコメントではチームでちゃんとルールを決めて それに基づいた構造化をしましょうとの事でした。)

和田省二さんによるリソースとイベントの見分け方の解説

自分が割と詳しく知っているドメイン領域に適用しやすいはなしだったので かなり勉強になった。

  • 「Entityを見つけたら、必ずResource/Eventに分けましょう」
  • Event - 時間の進みに従い発生するもの。過去の記録。
  • Resource - もの。未来の為に登録しておき、発生日時、消滅日時といった期間を持っている事が多い。
  • 多対多の関係で定義する交差テーブルはEntityになる
  • 交差テーブルでも多対多、多対1、1対多、1対1と多重度はビジネス要件により様々ある
  • 多重度重要

懇親会

色んな踏み絵がいっぱいで怖い懇親会ではあったが 世代を超えた交流!ができた。 後半は正直かなリ酔っていてみなさんに失礼な事をしていなかったか心配だ…

以上!

OpenJDK7でGroovyConsoleが起動しない

メモ

以下からOpenJDK7をダウンロード
http://code.google.com/p/openjdk-osx-build/downloads/detail?name=OpenJDK-OSX-1.7-universal-20110810.dmg&can=2&q=

GroovyはHomebrewで最新の1.8.1を入れた。
で、GroovyConsoleを叩くと…

Caused by: java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener

なんでやねん…

wgetでbasic認証

レ◯パレスのネット環境へのログインがいちいちbasic認証でめんどくさい、
そしてスクリプトでなんとかしようとしてGroovyで書いてたけど
ログイン時に実行するには起動が遅い…
ということでwgetにしました。(というかこれが一番楽だった…)

wget --http-user={userid} --http-passwd={passwd} {url}

Javaにチェック例外なんていらない気がするんだが

ほとんどの場合、例外をキャッチするかどうかなんて使う側の要件による。IO関連とかとか、システムリソースを使うにしても基本的に

try{
    //リソースを使う
} finally {
    //リソースを開放する。
}

でおkだし。
キャッチしてもどうしようもない例外は

Thread.setDefaultUncaughtExceptionHandler(
    new UncaughtExcepitonHandler() {
        public void uncaughtException(Thread t,Throwable e) {
           //ログ出力
        }
    }
);

とかしてれば十分だ。
それでも例外設計の難しさはなくならないけど。

NetBeansでSSH公開鍵認証(NetBeans 6.1)

会社のCVSサーバをSSH経由で公開して、プロジェクトを自宅と共有している。
NetBeansは単体ではSSH2の公開鍵認証に対応していないので外部ツールを利用した接続になる。
外部ツールは元々puttyを使っていたのでそのままplink.exeを利用する(事前にplink.exeのパスを通すか、フルパスを記述)。
独立した設定項目はなく、プロジェクトのチェックアウト、もしくはリポジトリへのインポートを行う際に設定するしか方法は見当たらなかった。以下の例はチェックアウトを選択した場合

  1. [メニュー]->[バージョン管理]->[CVS]->[チェックアウト]を選択。
  2. CVSルート::ext:[username]@[hostname]:[repository path]
  3. 外部シェルを使用を選択
  4. シェルコマンド:plink.exe -l [username] -i [puttyの秘密鍵ファイル]

eclipseからの乗り換え組みなので、ssh接続のサポートが薄いのが結構痛い。

追記

パスフレーズの設定をしている場合は、pagentの常駐が必須になる。