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だけで十分だ!」と言う人も出てくるかもしれないですが

Scrum Regional Gatehering Tokyo 2013に参加してきた #sgt2013

若干タナボタ気味ではありましたが、会社のお金で参加してきました。ありがとう、会社の人。おかげさまで大変堪能できました。

というわけで、メモです。自分のためのメモなので、噓(はないとは思いたい)・大げさ・紛らわしい・理解誤り・仕様誤り・ケアレスミス・境界チェック漏れなどが含まれるかも知れませんが、あらかじめご了承ください。目に余るモノがあったら指摘していただければできるだけ対応します。

セッション概要: http://scrumgatheringtokyo.org/2013/?page_id=148

day 1

Keynote#1: Agile Management – Learning From Software Development - Jurgen Appelo

  • Beyond Budgeting
  • Lean Startup
  • Design Thinking
  • Management 3.0
    • Energize People (e.g. kudo box)
    • Empower Team (e.g. Authority Boards)
    • Align Constraints
    • Develop Competency (e.g. Cisco社のサッカーゲーム)
    • Grow Structure (e.g. Business Guilds)
    • Improve Everything (e.g. Happiness Index)
  • Q&A
    • managerとleaderの違い
      • managerはleadershipとgovernanceの両方が大事
        • governance: ルールを決めてそれを遵守させる
      • leadershipはいわゆる"リーダ"だけではなく、メンバ全員が持っていて良い。持っているべき
      • manager(management)というロールは必要だが、managerという職種は不要(必須ではない)
        • 全員でmanagementできるのが理想
    • 何をどうやっても、仕事をどうしても楽しめない。お金のためだけに働く人はどうしたらいい?
      • うまくいくように手伝う
      • だめなら、やめるように仕向ける(お互い納得の上で)
      • スキルではなく、マインドセットで人を雇うのが重要
        • スキルは伸ばせるが、マインドの変革は困難

Keynote#2: Buy or Build: where did your agile come from - Jim Coplien

  • ((スクラム認定制度に対する壮大なDISセッション)
    • 試験パスしたから今日からあなたは今日からプロフェッショナルなスクラムマスタなの?
    • 認定されたから大丈夫、ではない
    • 実践し、考え続けるのが大事
  • "チーム" >>>>> 優秀な人×N
    • チームとして成果を出す方が大事
  • knowledgeとlearning
    • knowledge:脳内に閉じがち。必ずしも行動に結びつかない
    • learning:行動に反映される
  • Bloom's Taxonomy of Learning Domains
    • http://www.nwlink.com/~donclark/hrd/bloom.html
    • Cognitive Taxonomy (認知領域による分類)
      • 知識→理解→応用→分析→統合
      • 守 破 離
    • Affective Taxonomy(情意領域による分類)
      • 受け入れ→反応→価値付け→組織化→内面化
    • スクラム認定研修も含めて)Trainingで達成できるのは精々2段階ぐらい
      • その先は「経験」が必要
  • Scrumは訓練の道具
    • 「うまくいかないことが分かった。誰だ!誰のせいだ!お前か!」
      • ではない
      • 失敗は"情報"である
      • 情報が得られたのならカイゼンすればよい
    • みんな、どのくらいEmergency Procedure使った?
      • ((Emergency Procedureって何?状態だったので後から調べた)
        • http://jeffsutherland.com/scrumhandbook.pdf
        • If the burndown line is not tracking downwards towards completion by mid-Sprint, the team needs to execute the Scrum Emergency Procedure:
          • 1. Change the approach to the work or remove impediments to increase velocity.
          • 2. Get help by having someone outside the team take some of the backlog.
          • 3. Reduce the scope of work.
          • 4. Abort the Sprint.
        • ((いわゆる"ごめんなさい"的なアレでした)
    • "Scrumはおまえらがどんだけクソかを知るためのツール" ((※ここまで酷くは言ってない
  • ダニング-クルーガ効果
  • 日本人の珍しい特性
    • 北米人・カナダ人:簡単なテスト→やる気UP、難しいテスト→やる気DOWN
    • 日本人:簡単なテスト→やるきDOWN、難しいテスト→やる気UP
      • 逆の傾向。珍しい
    • つまり、問題があったらそれに取り組んでカイゼンしていく、という気質が元からある
  • Autonomy(自律性), Mastery(熟練), Purpose(目的)
  • Q:パターンとアジャイルは何が違う?同じ?アジャイルはなぜ成功したのか?
    • 両者は同じ
    • アジャイルの成功の一因は、残念なことに認定制度だと思う
  • Q:だいたいどのくらいのスプリントが失敗になるもの?
    • 50%(!!) そうじゃないなら、何かが間違っているか、失敗を隠しているかのどちらかだ

The secret sauce of Innovation - Laszlo Szalvay

  • (メモなし)

アンチファクトリー:アジャイルスクラムによる顧客と開発チームの至高体験 - 上田善行 Ci&T Passific

  • 組織論を話します
  • 全社的にScrumを100%採用している。150チームぐらい
  • 来歴
    • 2007 Scrumを戦略的に初採用
      • 10年ぐらいかけてCMMI5を達成していて自分達のやり方でやるつもりでいたが、某Yahooから「スクラムでお願い」と言われたので
    • 2008 全面導入(それ以前はRUPベース)
      • たった一年で全面導入するスピード感
      • 以前はRUPで380アクティビティ定義していたが、スクラム採用後はたったの32プラクティスに集約
    • 2009 生産性・品質共に向上し始める
      • 一時的に下がったが、この時期から明らかに以前よりも向上
    • 2010 リーンで、戦略デプロイメント長期経営計画
      • True North 20xx
        • 方位磁針の北は真北ではない。真の北はどこか探求する ((とかだったかな
    • ミッションステートメント
      • To develop people who continuously use their talent to discover new ways of generating value and agility to our clients, and boldly execute as no one has done before.
    • super standardlization process
      • ウォータフォールは元々フィードバックループがあったけど、色々あってなしのバージョンが広がってしまった
      • "Software Factory Pattern"
        • 顧客の要求通り、大量リソース(=人員)で、大量生産する
        • 7つの弱点
          • 標準化:要求変更は不都合なだけ
          • 役所手続き:ドキュメント(=証拠)によるコミュニケーション
          • 対立:Fix後の変更はエナジーを費やし、ストレスフルなだけ
          • コスト:当初の要求通りにいくかどうかが一番の関心事になる
          • 隠蔽:問題は報告しない。納品までに問題がどこかに消えてくれることを祈る
          • 消失:知や人間関係が失われる
          • リソース:人を"People"ではなく単なる"リソース"と見なす。そこに情熱・創造性・ビジョンはない
        • 5つの争点
          • 顧客はHappyかどうか
          • チームはHappyかどうか
          • 失敗の犯人捜しをしていないか
          • 勝つか負けるかの2択になっていないか
          • ITは顧客の価値を生み出しているか
        • 顧客とチームは次の質問に答えられる?
          • 何を開発するのか
          • なぜそれを開発するのか
          • それはどのような価値を生み出すのか
        • 全てをYesにしたい
      • どうやるか
        • 組織の真北(True North)に同意する
        • リーン・スクラムの4P(Purpose, Process, People, Power to the Edge(現場に権限を))
      • リーン・スクラム、だけでは会社として差別化できない
        • そのぐらいの会社はたくさんある
        • 真の差異
          • "価値の創出"とそれを明示・論拠できること
          • 安定化と利益
      • 価値(Value)=Benefit - Cost
        • 同じモノでもValueは買い手によって変わる
        • ストーリ単位でValueとマッピングしている
      • Situation Wall
        • 各PJごとに状況を壁に書き出す。可視化
      • A3で全ての戦略的PDCAを表す
    • 最近は、他の開発手法をしらない純粋なアジャイル世代(アジャイルエイジ)が現れている!

Workshop: Beyond certification to Kaizen with ScrumKnowsy - Jim Coplien

  • Scrum Knowsyを使ったグループワーク
  • Scrum Knowsy(スクラムノウジー)
    • http://www.scrumknowsy.com/
    • 単純なゲーム
    • スクラムのトピック(朝会、ふりかえり、カイゼン、等)を選び、提示されたキーワードから重要だと思う順に上位6つを並べる
      • スクラムの賢人(Jeff Southerland、Cope、等)達の選択と比較しながら、その差異を考えることで、スクラムについての見識をより深めていく
      • Single Play:賢人との比較のみ
      • Multi Play:チーム間で1つのトピックについて、個々人の結果を比較し合ったりできる
        • GameをHostするには有料アカウントが必要(年間$19)
  • 失敗は情報
    • Kaizenすれば良い

day 2

Keynote前説 - 平鍋健児

  • 今回のセッションは全体的に組織論が多い
    • アジャイルが広まり、既存組織とアジャイルチームの接合点が増えてきている
    • そこをどううまくやるか、というところで組織論が語られ出したのではないか

Keynote: 実践値リーダシップとアジャイル/スクラム - 野中 郁次郎

  • http://www.slideshare.net/hiranabe/phronetic-leadership-and-agile-scrum-gathering-tokyo-2013
  • 戦略と組織は切り離せない
    • 戦略は、人が考え、組織が実行する
    • 戦略マネジメント
  • 知識創造 SECIプロセス
    • S:共同化、E:表出化、C:連結化、I:内面化 のスパイラル
  • フロネシス:共通前(Common Good)の追求・拡張
  • 知ること(knowing)には、個人的なコミットメントが不可欠
    • 信念と理性、アートとサイエンスのバランスが重要
  • 知識創造
  • ((メモ:スプリントを回し(S)で、ふりかえりをして(EC)、次のスプリントを回す(IS)、と考えると、
    • ((スプリントがうまく回ることだけ最優先にするのはスパイラルのバランスが悪い
    • ((ふりかえりによる過程も等価に扱って、スパイラルになっていることが重要
    • ((なのかなと思った
    • ((「今回のスプリントはうまくいった。まる」になりがちなので。自戒。
  • 文脈(コンテキスト)
    • "聞き手"が自分の頭から取り出した想定(assumption)
    • 場(Ba)=Shared Context in Motion
  • 我々は生まれつき共感を覚えるようにできている
  • 価値命題=ユニークなコトを提供する
    • コトのためにモノを作る
    • 対象を名詞ではなく動詞で捉える
  • フロネシス=賢慮・実践知
    • 個別具体の文脈で「ちょうど(Just Right)」をみつける
    • "身体性を伴う"
    • 「文脈に即した判断」と「適時絶妙なバランス」
    • not Decision, but Judgement
  • イノベーションにはおそらく政治力が必要
  • 自律分散するリーダシップ(Distributed Leadership)
    • 善(Common Good)を作る
    • 場(Ba)を作る
    • ありのままの現実を直視する
    • 直感の本質を語る
    • 概念を実現する政治力
    • 実践知を組織化する
  • コモンセンス=常識、"共通感覚"
  • シュンペータ「組織は個を殺すぞ」
    • 野中「そうじゃないんじゃないか」
  • 基本は徒弟制度(OJT
    • 意図的に2〜3倍の負荷を与えて育てる
  • 知は内に向かうと枯渇する
  • 徳の源泉は勇気ッ
  • 賢慮・実践知リーダ=フロニモス=知的体育会系(Intellectual Muscle)
  • 実践をしながらbetterを無限に追求し続けることが重要 ((そこに黄金の回転=無限のエネルギーが生まれるッ

Panel Discussion 野中郁次郎 x 平鍋健児

  • 暗黙知はコト話で伝わるか
    • 暗黙知のバンド幅は思ったよりある気がしている
    • ドキュメントにdetailは書き切れない
    • 一緒に仕事しないと伝わりきれない
    • 身体性を伴う必要有り
    • スクラムで興味深いところ
      • ペアプロ・ふりかえり
      • スプリント中に変更がない ((メモ:共同化を推進するのかな
    • Jeff Southerlandは元軍人で100回以上パイロットとして出撃している
      • 「彼はすごくhumanな人」
    • ソフトウェアの原材料は「言葉」と「会話」
      • アレグザンダのプロセスも「対話」が重要
        • 「彼もすごくhumanな人なんじゃないか」
        • アレグザンダのパタンは建築家と大工のコミュニケーションのため、でもある
    • 現場・現物・現実
      • 現場:actual
        • 現場で汗をかく、相手の目線でとったニュアンスを含む
      • 現実:real
        • actualでattachしているところからdetachした状態がreal
  • 本田宗一郎はSuper Product Owner
  • Q:リーダ重要とのことであるが、見つけ方・育て方についてヒントを
    • 形式知も重要
      • analysisはsynthesisのインプット ((? synthesis=総合
        • syntehisを洞察するには一般教養、歴史が重要
        • ポエムは暗黙知を誘発するところがある
    • 修羅場経験も重要
      • グレーな世界でJust Rightをみつけるには、失敗の経験も必要
        • 失敗のやり過ぎは人を暗くするので注意
    • 徒弟制度・伝統も重要
      • 職人道
  • Common Goodの追求をどこでとめるか、という問題もある
    • みんながやりきったと思えるところ
    • (スコープを広げていき究極的には)"人類"として考えたとき"そうあるべきだよね"となるところ
      • と考えると、"人類"としてどうなんだっけ=歴史を学ぶことがとても重要
  • 人はコラボで生きている
  • Q:大人数でのスクラム・知識創造の方法について何かヒントを
    • 場と場をつなぐバウンダリオブジェクトというコンセプト
      • バウンダリ=チームの境界、をつなげる
      • 方法
        • 各チームのリーダの人間力でつなぐ
        • シンボルを使う(例:Steve Jobsの海賊旗、音楽)
        • インセンティブシステム
          • 時間あたりの付加価値を高めるように
        • カルチャー
          • 米軍「我々は仲間のために戦う」
        • ヒューマニズム
  • 〆の言葉
    • 平鍋
      • 「開発チームのHappy」から「顧客も含めたビジネスとしてのHappy」へ
    • 野中
      • 日本を元気にしたい
      • スクラム=西洋と東洋のインテグレーション
        • 日本の資産なのではないか
      • 最後はパッション、そして勇気が大事ッ(あとお酒)

Product Ownership 〜 NTTデータと楽天

  • 楽天 及部 @takaking22
    • 自己紹介
      • DevLove「私がScrumを辞めた理由」で話したり
      • Agile 2012に参加したり
    • 振り返ればカンバンがあった
      • カンバンの数だけ歴史がある
    • 今日は、エンジニア視点の話
    • Scrumをはじめたが、コーチが去ったら全部元に戻った...
    • ひとりカンバン(魅せる化カンバン)
      • みんなつられてやりはじめた
      • 深刻な壁不足
    • 開発が順調に回ると、価値の張るバックログアイテムが不足してきた
    • ビジネス+開発で朝礼をはじめた
      • PO、Producer、FeatureTeamの3枠含めたカンバンを使った
      • 観測の結果、ビジネス→開発にValue Streamは流れなかった
    • 要求はどこから来るのか?という疑問
    • チーム全員でJeff PattonのPO研修に参加
      • "Product Ownershipは全員が持つもの"
      • 翌日Jeffが手伝いに来てくれた
    • PO、リーダ「「(プロダクト開発って)ちゃんとやらなきゃね」」「えっ」
    • Value Streamが流れるように「価値創造カンバン」を絶賛開発中
    • まとめ
      • Product Ownershipは一緒に働くことから生まれる(のでは)
      • 育てる意識
        • 導入すればOKではない
        • 人もプロセスも育てていくつもりでやらないと続かない
      • 成功するまでやり続ければ失敗じゃない
    • 川口さんの一言
      • Common Sence 共通理解が大事
      • 相手のことが分からないながらも観察や質問をして自分事として課題を解決する
  • NTT DATA 柴山 @shibao800
    • アジャイル開発組織を運営
      • AgileProfessionalCenter
        • オンデマンドなScrum開発体制
        • ScrumのProfessionalを育成
    • 登場人物
      • 主人公:PO 菅原さん:新規テストソリューションのPO
      • POチームメンバ
      • ユーザ「悪いモノは使わない」
      • 主人公の上司「Agile開発なにそれ」
    • 数ヶ月かけて数ヶ月かけて要求機能一覧まで完成させたが...
      • 「本当にこれでいいのか。ユーザに求められてる機能なのかな」
      • Agile Professional Centerへようこそ
        • Agile Professional Centerは支援に行かない
        • Agile Professional Centerに全員連れてくる
        • できるようになったら戻ってもらう
    • Step0 事前準備
      • Jeff PattonのCSPO研修に放り込んだ
      • 「返ってよく分からなくなった」
    • Step1 POチームメンバを仲間に
      • リーンキャンバスを繰り返し作り直した
        • 最初デジタルで主人公が編集→アナログにしてチームで共有
        • 主人公の意見のみ→メンバからの意見がでてきた
        • メンバ「機能一覧を実現すればいいんでしょ」→「どうすればユーザにとって価値のあるモノができるか」
    • Step2 ユーザを仲間に
      • エクスペリエンスマップをユーザと一緒に作成
      • ユーザが積極的に問題を共有してくれるようになった
        • ユーザの周辺に意見を聞いてとりまとめたり
    • Step3 上司を仲間に
      • ペルソナを使ってユーザ増を明確に
        • あらゆる人をターゲットにしすぎてぼやけていた
        • 価値を届けるべき相手を明確に
      • ユーザストーリーマッピング
        • 誰のために、どのような機能で、どのような価値を届けるか、を時系列に並べる
      • 上司に対するスコープの説明を具体的に行い、合意を取り付けられた
    • 感想も上々
    • "Product Ownership"
    • 川口さんの一言
      • 「アナログで付箋」が重要
      • やってみせて、やってもらって、理解してもらう、重要

Agile Transformation in Big〜大組織でのアジャイル変革 谷口@agilergo

  • (事例だけで発表許可もらってない)
  • 中学ぐらい(?)からドイツ在住
    • 海外長すぎて日本語が不自由(割と本気)
  • ここ10年ぐらいAgileコーチング・コンサルティングをしている
  • ((一部自重)
    • 課題
      • 戦略プロダクト:失敗は許されない
      • プロダクト規模が大きい
      • ウォータフォールでは不可能な時間のなさ
      • アジャイル経験ほとんどなし
      • 短期間で多くのチームを立ち上げる
      • 外部の要員が多数、チームビルディング
    • チームはコンポーネント毎に分けた
      • チーム間のコミニュケーションが課題
      • 各チームから代表を集めてVirtual Team Architectureを構築した(=Scrum of Scrumのこと?)
        • チーム間での情報共有や依存関係の整理
    • ミーティング
      • いつものスクラム会議体に加えて
        • POデイリー&POウィークリー
        • SMデイリー&SMウィークリー
        • Scrum of Scrum
          • Dependencyを見つける
        • Overall Review
          • 総勢200人でミッションとかやっていることの共有
    • 組織構造の変革
      • コンポーネント毎にhorizontalなチーム構成
      • verticalなFeature Teamとして再構成
        • スキル、権限が必要
        • 全チームが同じコードベースを使う。コンフリクトが日常
        • CI重要
        • collective code ownership
        • 他のチームへの依存性(作業待ち)が少なくなる
      • Feature Teamを横断して、リードPO 、リード開発者、ビジネスアナリスト、テスタを配置
        • 全Feature Teamがリリースできることが重要
  • 大組織、アジャイルへの道の課題
    • 鉄の三角
      • 伝統的
        • 計画ドリブン
          • 固定:要求
          • 推測:コスト・タイム
      • アジャイル
        • 価値ドリブン
          • 固定:コスト、タイム
          • 推測:要求
            • のはずが要求も固定化される
            • 「品質を下げても良いから」(で、下げたら怒り出す)
    • きちんとしたDoRとDoD、複雑な検収プロセス
      • Readyの定義(DoR)
      • 完了の定義(DoD)
      • DoR、DoDをきちんと検収するためのプロセスが複雑
    • 品質の作り込み
      • テストや結合はスプリント内できちんと実行できてない
      • 技術的負債
      • コードフリーズの後にbug fixingと運用・受け入れテストをしている
        • 全体の30%の期間を書けている(?)
    • 継続的デリバリ
  • サティア チェンジモデル
    • 新しいことをすると、一時的にパフォーマンスは落ちる
  • 人々が最大のテコ
    • 人が重要
    • マインドセット
  • 支障を避けるんじゃなくて、きちんと取り除いていく
  • 成功の鍵
    • プロジェクト/プロダクトゴールに集中する
    • See the Whole
    • End-To-Endに焦点を当てる
    • 分割可能なアーキテクチャ
    • CI、品質作り込み、小さなフィードバックループ
    • チーム間コミュニケーションの推進
    • 全体的なカイゼン指向

技術トークス

  • 前説:スクラムフレームワーク。どういった技術を使っていくのかについて一人30分程度でトーク。最後にパネル。
    • 「毎回ゴミができあがる。俺たちのスクラムは失敗だ」「ゴミができてることに気づいてるならそれは成功だ。さあ改善しよう」
  • クラウド 玉川/Amazon
    • 複雑で予測不可能なシステムを構築する
    • インフラストラクチャは重荷
      • 買ったら取り返しつかない
      • 買うのに時間がかかる
      • どれくらい買えば良いのか分からない
        • キャパシティ設計?
        • 「お客さんが言ってるデータ量に30%上乗せしようか、2倍くらいにしようか」
      • 本番環境と同じの欲しい
    • Amazon自体もインフラの調達で悩んでいた
      • Amazonのトラフィック
        • 昼間は61%まで、夜は落ち込む
        • 年末のピークのために年間インフラを保守する無駄
    • 新サービスのトラフィックを予測できる?
      • ミニマムスタートだと、サービスがうまくいくとサーバが落ちる。ビジネス機会の喪失
    • 「インフラがソフトウェアになりました」
    • 2000万ユーザのNetflixのCTO「明日にでも日本に参入できる(インフラはクラウドだし)(コンテンツの法的な話がネック)」
    • どこにデプロイするかデータセンタ単位で制御可能
    • EコマースのAmazonのミッションクリティカルなサービスのために作ったので信頼性は超高い
    • クラウドの使いこなしがまだまだ浸透していない
      • 給与計算システムをクラウドに載せる→月末だけデプロイすればいいのに、ずっと起動しっぱなしで無駄
      • 仮想マシンに1つずつリリースする→1つリリースして自動反映できるのに
    • どの企業がどれだけ使っているか(トラフィック等)がみえる
      • よく使っているサービスは今伸びてるな、と分かる(インサイダ情報)
    • 誰でもクラウドが手に入るので、インフラを持っていることに競争力はない
      • 自力でクラウド作って開発者をそこに費やして肝心なサービスが手薄になっている企業と、既存クラウドを使ってサービスに集中している企業の競争力は明らかですよね
    • CDP(Cloud Design Pattern)
      • Floating IPパタン
      • Job Observerパタン
      • Wikiで公開中
      • 書籍「クラウドデザインパターン設計ガイド」
        • 日本語版ベースに、今年スペイン語、中国語、英語版など海外展開予定
  • 継続的デリバリ 和智/gxp
    • 趣味でときどき翻訳をしています
      • 継続的デリバリー、DDDとか
    • スクラム=パッケージ/フレームワーク
      • 「よし明日からスクラムをやろう!」は危険。聞いててドキドキする
      • ソフトウェアパッケージを導入するとき、いきなり明日から導入しないでしょ?
    • スクラム自体では未定義、何も教えてくれない
      • プロダクトバックログ、どうやってつくる?
        • 自分達の機能一覧と何が違うの?
      • 出荷可能な成果物、どうやってつくる?
      • エンドユーザにどうやって届ける? ↑←この辺が継続的デリバリー
      • といったことを、自分達で埋めていかないといけない
    • CIとか重要
      • クラウドなら構築しやすいんじゃないか
    • フィーチャを差し込めるアプリケーションアーキテクチャを事前に準備しておく必要がある
      • (実は自分はスクラムやっていません。大きなウォータフォール)
    • 分割したものは結合しなければならない
    • まとめ
      • スクラムは自分達の文化に合わせて運用しなければならない
        • カスタマイズというより、スクラムが語っていないスキマの所
      • 継続的デリバリとは実装された価値をスムーズにエンドユーザに届ける手法
      • 高度なガバナンスが必要
  • アジャイルテスティング〜テストの全体像を共有する〜 細谷/スクラム道関西/XPJUG-Kansai/TFSUG
    • テストの全体像をどうやって作っていくか
    • テストフェーズ=市場に不具合を流出させない最後の砦
    • 目的と手段
      • 目的:目標の品質を達成すること
      • 手段:目標の品質であることを確認可能なテストを開発する
        • 「テストを開発する」
          • しっかりとテストを分析して、計画&開発しなければならない
          • テスト実装=自動テスト or テスト仕様書(いわゆるExcel)
      • テストを実施し、欠陥を是正する
    • テストの積み上げ
      • 複雑なモノを分けて、一つずつ確認し、組合せを確認して、...という
      • 品質の高い要素で全体が構成されていることが重要
        • 個々の品質が低いと収拾が付かない
      • 小さい粒度で品質を確保し、徐々に粒度をお菊していく
    • アジャイル開発でのポイント
      • いつ、どのような品質を達成するか
        • a) スプリントでの成果物は出荷可能か判断することができる
        • b) 出荷に必要なプロセスを経て製品を出荷する
          • プロジェクトによって必要な作業量は大きく異なる
        • いつ誰からフィードバックを得るか?
          • PO、ユーザ:目的を果たせるか?新たな目的の気づき
          • 他サブシステム・HWチーム:組み合わせてみての気づき、タイミング、I/Fの矛盾
          • チーム:設計・実装からの気づき、自己評価による気づき
        • フィードバック範囲 広い1ー少ない2
        • リリース回数 少ないaー多いb
          • 1a 市場にリリースするための作業は大きい
          • 1b 市場にリリースするための作業は小さい。自動化の範囲を可能な限り広げないと実現困難
          • 2a 市場にリリースするための作業は大きい
          • 2b 頻繁にリリースするための自動化が必要。市場にリリースするためのプロセスの自動化が少なくても実施可能
      • どのような粒度でテストするか
        • テスト自動化ピラミッド(Succeeding With Agile, Mike Cohn)
          • UI→Service→Unit
        • 実践アジャイルテストのアジャイルテストの4象限
        • ソフトウェアテストの分野では、ISTQBで Test Levelという用語が定義されている
          • 系統的にまとめ、管理していくテストの活動のグループ
            • 例)コンポーネント、統合テスト、システムテスト、受け入れテスト
            • 「例に引きずられて、テストフェーズと思うと違う。粒度に関係している、と思っている」
        • コンテキストの収集
          • 「何に対して」「どんなことを」「どんな方法で」テストしたか?を収集してみた
            • 横軸:品質6特性
            • 縦軸:テストの粒度(クラス、API、画面、ユーザストーリ、システム全体、プロトコル)
            • 各セルに、自動、手動、レビュー、ー(なし)を埋める
            • ここから更にブレークダウンしていく
            • ちなみに、TDDは「機能性×クラス=自動」の枠
          • 「TDDは開発?テスト?個人的にはどちらでも良いと思ってる」
          • アジャイルテストはV字をせばめていく活動
    • 「最後の砦」の役割のテストでも、モノの品質が悪ければ、突破されたり、維持に膨大なコストがかかる
    • 「最後の砦」を「日常の風景」にするために、我々に何ができるかを考え続けたい
  • TDDとそのマインド 和田 @t_wada
    • 月末にオライリーからSQLアンチパターンでます
      • ((メモ:レビューに参加してたりします
    • 今日は楽しいかも知れませんが、みなさん現場に戻ったら...
      • 荒みきったコード、疲弊した現場、爆弾処理のようなリリース
    • なぜこうなってしまうのか
      • 複雑さへの恐れと不安
        • 開発では、やらなきゃいけないことがたくさんある
        • 書いてるコードの裏側で使っているコードたるや、莫大な行数になっていて把握は不可能
        • 不安を克服する技術の不足
    • みんなスクラムの「チーム環境」(レフトウィング)だけしかみてないことないですか?
      • ライトウィング:高速に石橋を叩いて渡る「開発環境」を忘れてない?
    • 誰がシステムを作るのか、誰がシステムを作り続けるのか
    • 恐れに対抗する技術とは?
      • 技術も磨いていかないとゴールは奪えない
      • (いつも語ってる)三本柱
        • バージョン管理
          • GitでもSubversionでお
          • Git使うことが目的じゃない
        • テスティング
          • 名詞の「テスト」じゃない
          • テストをし続けること。動詞。
        • 自動化/自働化
          • 人間は人間にしかできないことをやりましょう
          • 人間は怠惰で疲れやすい
            • 同じことを繰り返すことは苦手。あきるし
            • コンピュータは融通は利かないが繰り返しは得意
          • ユーザに価値を届けるまで自働化しましょう→継続的デリバリ
          • インフラも自働化しましょう→クラウド
    • アジャイルサムライ
    • 「テスト」にまつわる混乱
      • TDDの本質をとらえ損なわないように
      • 誰が、何のためにで分けてみると
        • Developing Testing、Customer Testing、QA Testing
    • TDDって何?
      • Kent Beck本を読んだら
      • 冒頭「我々がエンジニアとして作ろうとしてるのは、動作するきれいなコード。それがゴールである」
      • 黄金の回転ッ
      • 動かない→動くという境界を越えるところに「学び」がある
      • 汚い→きれいの境界を越えるために、リファクタリングする
        • 「動いているコードに触れるな」というタブーとの闘い
      • (中略)
      • 作りやすいコードに引きずられず、使いやすいコードになるように、まず自分でドックフーディング
      • 爆弾解体の赤青二択ではなく、命綱のあるバンジージャンプになる
        • 少なくとも自分で考えた通りに動くことを示せるようになる
          • 自分の考え自体が間違ってる可能性はあるけど
    • テストは目的ではなく手段
    • TDDはプログラミング手法
      • まずは、コードの書き方の一種ととらえた方がやや正確
        • 細谷さんはどっちでもいいとはいったし、そこまで行ければ良いけど
    • 動くコードに触れるな
      • 使われてはじめて本当の要望がでてくる
      • 動くコードに触れる手段がなければ、死あるのみ
  • パネル
    • Q:ドメインが大きくなってきた、モデルを変えるときに、テストを捨てる戦略は?どういうときにテストを捨てる?
      • 和田
        • テストが負債になる状況
        • コアなドメインを変更するときとか
        • そもそもそういうテストを作り出さないための考え方
          • まず自動リファクタリング機能や字面置換などを使って何とか既存のコードを活かせないかも検討
          • I/Fを変わっている場合は、テストが変更しなければならない
          • テストの粒度を変えて、色々な粒度のテストを作っておく
            • 細粒度のテストはばっさり捨てる
            • 荒粒度のテストを頼りに細粒度のテストを揃え直す
            • 内側を生かすか殺すかはそのときの変更次第
          • コアの変更を以下に自動化できるか夢は捨ててない
            • 大学との共同研究で、安心して捨てられるテストの判定をしたりしてるが、単純なケース以外はまだ成果が出ていない
      • 細谷
        • 作るために必要なテストと、保守/維持していくために必要なテストは目的が違う
        • 作るためのテストが保守するためのテストに移行したり、その逆とか、パターン化できるんじゃないかという妄想をしている
      • 和智(変更に強い設計とは?DDD?)
        • クラスの中を考えているテストは壊れやすい
        • モデル自体の構造を固めるテストよりも動きを固めるテストを書いた方が資産価値が高い
    • Q:製造業では、QAテストを割り込みでやらざるをえないと思うけど、スクラム的にどうやるの?
      • 細谷
        • 複数の周期のモノを入れ子にして同期する
          • ハードに引きずられる周期
          • FPGAで試せる周期
          • サブシステムの開発周期
        • などを出荷に持って行くために、トータルで出荷に持って行くためのフェーズを入れ子にしてどこかで同期を取るようにしてる
          • 短い方を、長いものに属していると見なして進めている
      • 玉川
        • (前職の大規模での経験)
        • リリーストレイン
          • 複数のチーム(トレイン)の発着タイミングをコントロールする人がアーキテクチャチームにいて、全体を見ていた
    • Q:ベンダロックインを嫌うインフラエンジニアから見ると、各種クラウドサービスの共通ラップサービスがでてくるとかなるのかとか、そういう話
      • 玉川
        • 逆に考えるんだ
        • ベンダロックインされないようにしている
        • 物理サーバとあまり変わらないように、低レイヤを意識して提供している
        • VM import/exportの提供
        • データimport/export(HDD送ってくれたら、データ突っ込んで返すよサービスとか)
    • Q:テストの自動化の限界
      • 細谷
        • 自動化は目的ではない
        • 費用対効果
        • UI等は手動でやらざるを得ない部分はある
      • 和田
        • UIを自動化することを目的にしてしまうと、テストの変更コストが、UIの変更を阻害してしまう
        • ユーザビリティや色合いは自動化しない/できない
      • 玉川
        • 人間にしかできないテストはある
        • AWSには、メカニカルタークというサービスがある
          • 人間に頼むところをAPI化する
          • ユーザビリティテストや誤字脱字のチェックをアウトソースするとか
      • 和智
        • リリースに時間がかかるとか、人がやるべきこと、必要なことなら問題ではない
    • Q:スクラムでの開発者とWFの開発者の違いは?
      • 和智
        • 自分は典型的なWF開発者
        • あまり本質的な違いはないんじゃないか
        • 無駄なことはやらないで、必要な期間を必要なだけ取ってるだけ
      • 玉川
        • 万里の長城の話「石を運んでる」「お城を作ってる」の違い
        • 価値を届けるためにやっているというメンタリティの違いでは
      • 細谷
        • プロセス的にはあまり違いはないんじゃないか
        • 小さい単位で積み上げていく、ということを共有しているかどうか
        • WFでは、大きなスパンで不具合密度でしかみれないとか
        • スクラムでは、日々共有できるかとか
      • 和田
        • 咳さん「無責任領域を持たない。守備範囲を決めない」
          • ここまでやったから後は知らない
        • 従来と比べて積極的に守備範囲を壊していけるようになってきているのでは