コペンハーゲンのGR8Conf EU 2013でGroovyServとImproxプラグインを紹介してきた

https://pbs.twimg.com/media/BLDRxqACQAE4lf1.jpg

5/22-24にデンマークはコペンハーゲンで開催されたGR8Conf EU 2013というGroovy系のカンファレンスで、GroovyServImproxプラグインを紹介してきました。

右の写真はコペンハーゲンの定番がっかり観光スポットの「人魚の像」ですね。 がっかり感が軽減されている一枚を選びました。 まあ、どこの観光地にもがっかりスポットはつきものです。 札幌の時計台にくらべれば人魚はだいぶ良かったんじゃないでしょうか。

GR8Conf EUは今年で5周年だそうです。コペンハーゲンがオリジナルですが、「GR8Conf」ブランドのカンファレンスは別ロケーションでも何度か開かれていて、USは今年も7月にありますしほぼレギュラー化してるようですね。他に覚えているところではオーストラリアでも開催されてました。日本でも開きたいですね。

さて、自分の発表ですが、本日動画が公開され(てしまっ)たので、スライドと動画のリンクを張っておきます。 つたない英語ですがよければご笑覧ください。

当方の深刻な英語力不足にともない今回は不本意ながら「最初に言い訳」メソッドで乗り切りましたが、やっぱりせっかくやるからには「ネイティブ&インタラクティブ」方式を目指したいですね。 最後、質疑がなくて寂しい感じにみえますが、たぶんみなさん気を遣ってくれた感じで、セッション後に数名の方と技術的な話もしましたからね? *1

他の錚々たるスピーカのみなさんの動画も随時公開されていくはずなので、興味がある方はTwitter@gr8confをフォローしておくと良いと思います。

そうそう、今度の6/21のJGGUG主催GワークショップZで、G*ワークショップZ Jun 2013 - GR8Conf報告&ライブコーディング&GroovyServ/Improxをやります。 ご興味があれば是非是非ご参加ください。

*1:どちらかというと「お前の英語は悪くない」「問題ないよ」「グレートだったぞ」みたいな慰めにきてくれた人の方が多かったですけど。

GrailsからMirageを使うサンプルがあったので試してみた

Mirageという2-way SQLが利用できる素敵なO/RマッパをGrailsで使ってみたというブログがあったので、サンプルコードを落として試してみました。

developmentモードでMySQL使うようになってたので、H2に変更してrun-appして試してみました。

確かにMirageでDB操作できている!

のですが、更新ボタン2回目を押すとuniqueエラーになるのでおかしいなと思ってみてみたら、insert.sqlファイル内に書いてあるINSERT文でIDがハードコードされてるのでそりゃ2回目は失敗しますね。idを省略して自動払い出しを期待して実行してみると、実行毎にレコードが追加できます。素晴らしい。

という感じで、コードを色々見ていたところ、気になる点が色々あったので、forkして自分好みに修正してみました。 コネクション・データソース・トランザクションまわりのための準備が煩雑だったので、その辺を重点的に頑張ってみました。これ、以外と難しくて一応うまく動いてるようだけどもそんなに自信ないです。たぶん大丈夫だと思うんだけど。 あと、テストもSpockで追加したり、もちろんimproxプラグインも追加したりして、かなり好き放題いじってます。 Grailsのバージョンも最新の2.2.2にあげちゃいました。

コミットログに日本語でゆるいコメントを残してるので何をしていったかはコミットログ参照のこと。コミットログとdiffみたらだいたい何やったか理解できるんじゃないかと。

HibernateのネイティブSQLやGroovy-SQLを使う方法で間に合うことも多いですが、2-way SQLを外部ファイルで指定できるのはSeasarの追っかけ的には嬉しいので、チャンスがあったら使ってみようかなぁ。GrailsConnectionProviderの件とかもあるのでプラグイン化も検討してみようかしら。

参考URL

GrailsのGORMにおける各種関連とmappingによる名前変更のサンプル

Grailsのドキュメントを翻訳する上で、英文読んでも何を言ってるか分からないので、サンプル書いて試してみた記録です。

↓ここに反映される予定。

生成されたスキーマPostgreSQLにて確認してあります。 異なるDBMSなら異なるスキーマになることもあるかも知れません。Hibernateのみぞ知る。

多対1/1対1関連(単方向)

基本

ドメインクラス

class Person {

    String firstName
    Address address

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
    }
}
class Address {

    String number
    String postCode

    static mapping = {
        postCode type: 'text'
    }
}

生成されたスキーマ

              Table "public.people"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 address_id | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:
    "people_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)

             Table "public.address"
  Column   |          Type          | Modifiers
-----------+------------------------+-----------
 id        | bigint                 | not null
 version   | bigint                 | not null
 number    | character varying(255) | not null
 post_code | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "people" CONSTRAINT "fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)

Person上のaddressカラムのマッピングを変更してみる

ドメインクラス

class Person {

    String firstName
    Address address

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
        address column: 'Person_Address_Id' // コレの効果は...?
    }
}
class Address {

    String number
    String postCode

    static mapping = {
        postCode type: 'text'
    }
}

生成されたスキーマ

                 Table "public.people"
      Column       |          Type          | Modifiers
-------------------+------------------------+-----------
 id                | bigint                 | not null
 version           | bigint                 | not null
 person_address_id | bigint                 | not null  <-------- ココが変わった!!!
 first_name        | character varying(255) | not null
Indexes:
    "people_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fkc4e2328fec329d0d" FOREIGN KEY (person_address_id) REFERENCES address(id)

             Table "public.address"
  Column   |          Type          | Modifiers
-----------+------------------------+-----------
 id        | bigint                 | not null
 version   | bigint                 | not null
 number    | character varying(255) | not null
 post_code | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "people" CONSTRAINT "fkc4e2328fec329d0d" FOREIGN KEY (person_address_id) REFERENCES address(id)

多対1/1対1関連(双方向)

基本

ドメインクラス

class Person {

    String firstName
    Address address

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
    }
}
class Address {

    String number
    String postCode

    static belongsTo = [person:Person]

    static mapping = {
        postCode type: 'text'
    }
}

生成されたスキーマ

単方向の場合とスキーマは同じ。

              Table "public.people"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 address_id | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:
    "people_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)

             Table "public.address"
  Column   |          Type          | Modifiers
-----------+------------------------+-----------
 id        | bigint                 | not null
 version   | bigint                 | not null
 number    | character varying(255) | not null
 post_code | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Referenced by:    TABLE "people" CONSTRAINT "fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)

Person上のaddressカラムのマッピングを変更してみる

単方向の場合とスキーマは同じなので、後は...わかりますね?

1対多関連(単方向)

基本

ドメインクラス

class Person {

    String firstName

    static hasMany = [addresses: Address]

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
    }
}
class Address {

    String number
    String postCode

    static mapping = {
        postCode type: 'text'
    }
}

生成されたスキーマ

              Table "public.people"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:
    "people_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "people_address" CONSTRAINT "fk3af1764434f4e10e" FOREIGN KEY (person_addresses_id) REFERENCES people(id)

             Table "public.address"
  Column   |          Type          | Modifiers
-----------+------------------------+-----------
 id        | bigint                 | not null
 version   | bigint                 | not null
 number    | character varying(255) | not null
 post_code | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "people_address" CONSTRAINT "fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)

      Table "public.people_address"
       Column        |  Type  | Modifiers
---------------------+--------+-----------
 person_addresses_id | bigint |
 address_id          | bigint |
Foreign-key constraints:
    "fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
    "fk3af1764434f4e10e" FOREIGN KEY (person_addresses_id) REFERENCES people(id)

Person上のaddressesカラムのマッピングを変更してみる

ドメインクラス

class Person {

    String firstName

    static hasMany = [addresses: Address]

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
        addresses column: 'Person_Address_Id' // コレの効果は...?
    }
}
class Address {

    String number
    String postCode

    static mapping = {
        postCode type: 'text'
    }
}

生成されたスキーマ

              Table "public.people"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:    "people_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "people_address" CONSTRAINT "fk3af17644e3b329fc" FOREIGN KEY (person_address_id) REFERENCES people(id)

             Table "public.address"
  Column   |          Type          | Modifiers
-----------+------------------------+-----------
 id        | bigint                 | not null
 version   | bigint                 | not null
 number    | character varying(255) | not null
 post_code | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "people_address" CONSTRAINT "fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)

     Table "public.people_address"
      Column       |  Type  | Modifiers
-------------------+--------+-----------
 person_address_id | bigint |              <-------- ココが変わった!!!
 address_id        | bigint |
Foreign-key constraints:
    "fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
    "fk3af17644e3b329fc" FOREIGN KEY (person_address_id) REFERENCES people(id)

関連テーブル自体を指定する

ドメインクラス

class Person {
    String firstName

    static hasMany = [addresses: Address]

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
        addresses joinTable: [name: 'Person_Addresses',
                              key: 'Person_Id',
                              column: 'Address_Id'] // コレの効果は...?
    }
}
class Address {

    String number
    String postCode

    static mapping = {
        postCode type: 'text'
    }
}

生成されたスキーマ

              Table "public.people"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:
    "people_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "person_addresses" CONSTRAINT "fk8aeab389671fd1" FOREIGN KEY (person_id) REFERENCES people(id)

             Table "public.address"
  Column   |          Type          | Modifiers
-----------+------------------------+-----------
 id        | bigint                 | not null
 version   | bigint                 | not null
 number    | character varying(255) | not null
 post_code | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "person_addresses" CONSTRAINT "fk8aeab382efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)

 Table "public.person_addresses"   <-------- ココが変わった!!!
   Column   |  Type  | Modifiers
------------+--------+-----------
 person_id  | bigint | not null    <-------- ココが変わった!!!
 address_id | bigint |
Foreign-key constraints:
    "fk8aeab382efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
    "fk8aeab389671fd1" FOREIGN KEY (person_id) REFERENCES people(id)

1対多関連(双方向)

基本

ドメインクラス

class Person {

    String firstName

    static hasMany = [addresses: Address]

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
        addresses cascade: "all-delete-orphan"
    }
}
class Address {

    String number
    String postCode

    static belongsTo = [person:Person]

    static mapping = {
        postCode type: 'text'
    }
}

生成されたスキーマ

関連テーブルなしに、子テーブル側に親へのIDを保持するスキーマとなる。 「双方向」であるため、晴れて子から親を参照してもOKになるので、関連テーブルを導入するまでもなく、単に親 のIDを持つスキーマ構造が採用できる、ということと推測するが...。

              Table "public.people"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:
    "people_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "address" CONSTRAINT "fkbb979bf49671fd1" FOREIGN KEY (person_id) REFERENCES people(id)

             Table "public.address"
  Column   |          Type          | Modifiers
-----------+------------------------+-----------
 id        | bigint                 | not null
 version   | bigint                 | not null
 number    | character varying(255) | not null
 person_id | bigint                 | not null
 post_code | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fkbb979bf49671fd1" FOREIGN KEY (person_id) REFERENCES people(id)

Person上のaddressesカラムのマッピングを変更してみる

ドメインクラス

class Person {

    String firstName

    static hasMany = [addresses: Address]

    static mapping = {
        table 'people'
        firstName column: 'First_Name'
        addresses cascade: "all-delete-orphan",
                  column: 'Person_Address_Id' // こっちに書いても効かない(エラーにならず単に無視された)
    }
}
class Address {

    String number
    String postCode

    static belongsTo = [person:Person]

    static mapping = {
        postCode type: 'text'
        person column: "my_person_id" // コレの効果は...?
    }
}

生成されたスキーマ

hoge=# \d people              Table "public.people"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:
    "people_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "address" CONSTRAINT "fkbb979bf4576400fe" FOREIGN KEY (my_person_id) REFERENCES people(id)

hoge=# \d address
              Table "public.address"
    Column    |          Type          | Modifiers
--------------+------------------------+-----------
 id           | bigint                 | not null
 version      | bigint                 | not null
 number       | character varying(255) | not null
 my_person_id | bigint                 | not null <-------- ココが変わった!!!
 post_code    | text                   | not null
Indexes:
    "address_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fkbb979bf4576400fe" FOREIGN KEY (my_person_id) REFERENCES people(id)

多対多関連(双方向)

基本

ドメインクラス

class Group {

    String name

    static hasMany = [people: Person]

    static mapping = {
       table 'my_group' // PostgreSQLでは'group'テーブルを作成しようとするとエラーになる
    }
}
class Person {
    String firstName

    static hasMany = [groups: Group]
    static belongsTo = Group
}

生成されたスキーマ

           Table "public.my_group"
 Column  |          Type          | Modifiers
---------+------------------------+-----------
 id      | bigint                 | not null
 version | bigint                 | not null
 name    | character varying(255) | not null
Indexes:    "my_group_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "my_group_people" CONSTRAINT "fk7525b002f314e043" FOREIGN KEY (group_id) REFERENCES my_group(id)

              Table "public.person"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not nullIndexes:
    "person_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "my_group_people" CONSTRAINT "fk7525b0029671fd1" FOREIGN KEY (person_id) REFERENCES person(id)

 Table "public.my_group_people"
  Column   |  Type  | Modifiers
-----------+--------+-----------
 group_id  | bigint | not null
 person_id | bigint | not null
Indexes:
    "my_group_people_pkey" PRIMARY KEY, btree (group_id, person_id)
Foreign-key constraints:
    "fk7525b0029671fd1" FOREIGN KEY (person_id) REFERENCES person(id)
    "fk7525b002f314e043" FOREIGN KEY (group_id) REFERENCES my_group(id)

外部キーカラム名を変更する

ドメインクラス

class Group {

    String name

    static hasMany = [people: Person]

    static mapping = {
       table 'my_group'
       people column: 'Group_Person_Id' // コレの効果は...?
    }
}
class Person {
    String firstName

    static hasMany = [groups: Group]
    static belongsTo = Group

    static mapping = {
       groups column: 'Group_Group_Id' // コレの効果は...?
    }
}

生成されたスキーマ

           Table "public.my_group"
 Column  |          Type          | Modifiers
---------+------------------------+-----------
 id      | bigint                 | not null
 version | bigint                 | not null name    | character varying(255) | not null
Indexes:
    "my_group_pkey" PRIMARY KEY, btree (id)Referenced by:
    TABLE "my_group_people" CONSTRAINT "fk7525b0027e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)

              Table "public.person"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:
    "person_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "my_group_people" CONSTRAINT "fk7525b00253631627" FOREIGN KEY (group_group_id) REFERENCES person(id)

    Table "public.my_group_people"
     Column      |  Type  | Modifiers
-----------------+--------+-----------
 group_person_id | bigint | not null <-------- ココが変わった!!!
 group_group_id  | bigint | not null <-------- ココが変わった!!!
Indexes:
    "my_group_people_pkey" PRIMARY KEY, btree (group_person_id, group_group_id)
Foreign-key constraints:
    "fk7525b00253631627" FOREIGN KEY (group_group_id) REFERENCES person(id)
    "fk7525b0027e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)

関連テーブル名を指定する

ドメインクラス

class Group {

    String name

    static hasMany = [people: Person]

    static mapping = {
       table 'my_group'
       people column: 'Group_Person_Id',
              joinTable: 'PERSON_GROUP_ASSOCIATIONS' // コレの効果は...?
    }
}
class Person {
    String firstName

    static hasMany = [groups: Group]
    static belongsTo = Group

    static mapping = {
       groups column: 'Group_Group_Id',
              joinTable: 'PERSON_GROUP_ASSOCIATIONS' // コレの効果は...?
    }
}

生成されたスキーマ

           Table "public.my_group"
 Column  |          Type          | Modifiers
---------+------------------------+-----------
 id      | bigint                 | not null
 version | bigint                 | not null
 name    | character varying(255) | not null
Indexes:    "my_group_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "person_group_associations" CONSTRAINT "fk9dd6e6fc7e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)

              Table "public.person"
   Column   |          Type          | Modifiers
------------+------------------------+-----------
 id         | bigint                 | not null
 version    | bigint                 | not null
 first_name | character varying(255) | not null
Indexes:    "person_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "person_group_associations" CONSTRAINT "fk9dd6e6fc53631627" FOREIGN KEY (group_group_id) REFERENCES person(id)

Table "public.person_group_associations" <-------- ココが変わった!!!
     Column      |  Type  | Modifiers
-----------------+--------+-----------
 group_group_id  | bigint | not null
 group_person_id | bigint | not null
Indexes:
    "person_group_associations_pkey" PRIMARY KEY, btree (group_person_id, group_group_id)
Foreign-key constraints:
    "fk9dd6e6fc53631627" FOREIGN KEY (group_group_id) REFERENCES person(id)
    "fk9dd6e6fc7e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)

GExcelAPI 0.3 リリースしました #gexcelapi

GExcelAPI 0.3をリリースしました。

Change Log、といえるかどうか

変更点としては、以下の2点。

これだけ?

はい、これだけです。

でも、Java7対応重要です。ですよね?

オレオレMavenリポジトリの移転

あと、今後の使うときの注意点として大事なのが、オレオレMavenリポジトリの移転です。 今までMavenリポジトリとしてGitHubのrawモードを使った疑似リポジトリを使っていましたが、今回からCloudBeesのリポジトリを使うようにしてみました。 既存の0.1、0.2もなんとなくそっちにコピーしてありますので、ひとまず今後はCloudBeesをお使いください*1

release (stableバージョン)
    https://repository-kobo.forge.cloudbees.com/release
snapshot (SNAPSHOTバージョン)
    https://repository-kobo.forge.cloudbees.com/snapshot

ごくシンプルなサンプルコードはこんな感じ:

@GrabResolver(name="kobo", root="https://repository-kobo.forge.cloudbees.com/release")
@Grab("org.jggug.kobo:gexcelapi:0.3")
import org.jggug.kobo.gexcelapi.GExcel

def book = GExcel.open(args[0])

assert book.sheets[0].A1.value == "Sheet1-A1"

機能的に網羅したサンプルコードはテストコードを参照のこと:

CellRange#toHtml()の対応状況?

あと、以前に紹介した実験的機能としてのCellRange#toHtml()は以前の通り実験的機能としての位置づけでそのまま含まれています。 シンプルではないシートの場合にまともに動かないことも多いかもしれませんが、実験的と言うことでご了承ください。 なお、パッチ等は大歓迎です。 というか、Windows上のExcelを使う機会が大変少なくなっている昨今なので、むしろコミッタ募集です。

*1:そのうちまた変わるかもしれませんが

IntelliJ IDEAの細かすぎてわかりづらいGroovyサポート:メソッドシグネチャのホバー表示

メソッドコール部分をホバーするとAPIドキュメントを表示してくれるのはIDEとして普通のことだけど、 Groovyのような言語ではメソッドシグネチャで型を明示指定してないことが良くあります。 そういう場合でも、呼出先で使われるプロパティやメソッドなどを使ってどんなオブジェクトを期待しているか、可能な限りわかりやすく表示してくれる。

と、言葉で書いても何を言ってるかわからないだろうから、例を書くと

def hoge(foo, bar, String baz) {
    foo.name = ""
    println foo.value
    bar.toString()
    baz.toString()
}

def zzzz() {
    hoge()
}

というメソッドがあるときに、zzzzのhoge()の上でカーソルをホバーしてみると(自分の環境だとCommand押しながらホバーでした)....

String hoge (foo.[name, value], bar.toString(), String baz)

と表示されます。

わかります?

  • fooはnameとvalueというプロパティが使われてるので、そういうオブジェクト渡せよ
  • barはtoString()メソッドが呼ばれてるので、そういうオブジェクト渡せよ
  • bazはString型のインスタンス渡せよ

ということが分かります。

長いメソッドだと色んなプロパティ・メソッドが列挙されすぎてすごいことになるんじゃないか!?と心配になりますが、さすがに3つめあたりで省略記法になるようです。

Object hoge (foo.[name, value, ...], bar.toString(), String baz)

インテリジェイアイデアすごい。

Groovy基礎勉強会でGrailsのリクエスト制御をライブコードリーディングしてきました #GroovyBase

全編インテリジェイアイデアを使ったライブだったので、資料成分はほとんどありません。

資料で共有する価値が若干でもありそうなのは、1ページだけだったので画像だけ貼っておきますね。

f:id:nobeans:20130309184749p:plain

ポイントとしては、

書籍『SQLアンチパターン』 #sqlap

献本御礼。
本書のレビューに参加できて大変光栄であります。

SQLアンチパターン

SQLアンチパターン

帯には『「転ばぬ先の杖」を知り、リレーショナルデータベースの進化を学ぶ!』とあって、その通りであるなぁと思いますが、個人的には「転んだ後の鞭(ムチ)」として悶絶しながら読むのが断然お勧めです。

今時のアプリケーションを開発する人はRDBMSを避けて通ることはできないはず*1。そして、今までの開発人生でどれだけのDB技術的負債を積み上げてきたことでしょう。本書では、過去のトラウマを直視させられる粒ぞろいのアンチパターンが取り上げられています。

本書におけるアンチパターンは、以下の形式で記述されています。

アンチパターン」でトラウマを抉られて悶絶しているところに、「アンチパターンを用いてもよい場合」でフォローが入り救済される、という下げて上げる式のノンストップ・ジェットコースター的なドラマティック読書が楽しめます。

目次から章タイトルだけを並べてみます。

I部 データベース論理設計のアンチパターン


1章 ジェイウォーク(信号無視)
2章 ナイーブツリー(素朴な木)
3章 IDリクワイアド(とりあえずID)
4章 キーレスエントリ(外部キー嫌い)
5章 EAV(エンティティ・アトリビュート・バリュー)
6章 ポリモーフィック関連
7章 マルチカラムアトリビュート(複数列属性)
8章 メタデータトリブル(メタデータ大増殖)


II部 データベース物理設計のアンチパターン


9章 ラウンディングエラー(丸め誤差)
10章 サーティワンフレーバー(31のフレーバー)
11章 ファントムファイル(幻のファイル)
12章 インデックスショットガン(闇雲インデックス)


III部 クエリのアンチパターン


13章 フィア・オブ・ジ・アンノウン(恐怖のunknown)
14章 アンビギュアスグループ(曖昧なグループ)
15章 ランダムセレクション
16章 プアマンズ・サーチエンジン(貧者のサーチエンジン
17章 スパゲッティクエリ
18章 インプリシットカラム(暗黙の列)


IV部 アプリケーション開発のアンチパターン


19章 リーダブルパスワード(読み取り可能パスワード)
20章 SQLインジェクション
21章 シュードキー・ニートフリーク(疑似キー潔癖症)
22章 シー・ノー・エビル(臭いものに蓋)
23章 ディプロマティック・イミュニティ(外交特権)
24章 マジックビーンズ(魔法の豆)
25章 砂の城

人によってトラウマポイントが当然違ってきますが、個人的には

  • 「4章 キーレスエントリ(外部キー嫌い)」
  • 「5章 EAV(エンティティ・アトリビュート・バリュー)」

あたりが特に悶絶度が高くて楽しめました。

あと、Grails使いとしては、「3章 IDリクワイアド(とりあえずID)」あたりも味わい深いものがありますね。Ruby on Railsの人たちも必読ではないでしょうか。

今まで読んだSQLノウハウ本の中では、以下の2つと並んでトップ3にランクインです。SQLはまだよくわからないという初学者には、まさに「転ばぬ先の杖」として素敵なガイドとなってくれることは間違いないので、安心して購入しましょう。お勧めです。

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

楽々ERDレッスン (CodeZine BOOKS)

楽々ERDレッスン (CodeZine BOOKS)

*1:そろそろ「NoSQLだけで十分だ!」と言う人も出てくるかもしれないですが