Tokyo Rubykaigi 01 t-wada

85
それRubyでも やりたい ライブラリ移植と機能拡張のためのパターンランゲージ 和田 卓人 (a.k.a id:t-wada) Aug, 21, 2008 @TokyoRubyKaigi 01

description

 

Transcript of Tokyo Rubykaigi 01 t-wada

Page 1: Tokyo Rubykaigi 01 t-wada

それRubyでもやりたい

ライブラリ移植と機能拡張のためのパターンランゲージ

和田 卓人 (a.k.a id:t-wada)

Aug, 21, 2008 @TokyoRubyKaigi 01

Page 2: Tokyo Rubykaigi 01 t-wada
Page 3: Tokyo Rubykaigi 01 t-wada

多様性

Page 4: Tokyo Rubykaigi 01 t-wada

RegionalRubyKaigiに光あれ

Page 5: Tokyo Rubykaigi 01 t-wada

続け!

Page 6: Tokyo Rubykaigi 01 t-wada

自己紹介名前: 和田 卓人 (わだ たくと)

メール: [email protected]

ブログ: http://d.hatena.ne.jp/t-wada

Twitter: t_wada

Wassr: twada

Page 7: Tokyo Rubykaigi 01 t-wada

自己紹介タワーズ・クエスト株式会社 プログラマ 兼 取締役社長

Page 8: Tokyo Rubykaigi 01 t-wada

これまで書いたものWEB + DB PRESSvol.35 「実演! テスト駆動開発」vol.37 「実演! リファクタリング」vol.42 「現場で使えるREST」LifeHacks PRESSオープンソースマガジン(リレーコラム)他いろいろ

Page 9: Tokyo Rubykaigi 01 t-wada

gihyoコラボ企画『[動画で解説]和田卓人の“テスト駆動開発”講座』http://gihyo.jp/dev/serial/01/tdd/全20回すべて動画付き解説ニコニコ動画でも見れます

WEB+DB過去記事の特設サイトや動画

Page 10: Tokyo Rubykaigi 01 t-wada

デブサミ• デベロッパーテスティング・ライブ - 自信を持ってコードを書

くための心・技・体 -

• 【徹底討論】テストなんていらない?!-テストを、どこまでやるべきか?

• そしてデブサミ 2009 へ

• テストトラックのコンテンツ委員になりました

Page 11: Tokyo Rubykaigi 01 t-wada

よろしくおねがいします

Page 12: Tokyo Rubykaigi 01 t-wada

Agenda

•移植した中身のこと•移植する方法のこと•Q & A

Page 13: Tokyo Rubykaigi 01 t-wada

第一部移植した中身のこと

Page 14: Tokyo Rubykaigi 01 t-wada

背景

Page 15: Tokyo Rubykaigi 01 t-wada

始めに問題意識ありき•複雑な テーブル構造•既にレールに乗れない•多くのテーブルを JOIN しなければならない要件

Page 16: Tokyo Rubykaigi 01 t-wada

餅は餅屋

•CASE句•UNION ALL•RDBMS固有の関数

Page 17: Tokyo Rubykaigi 01 t-wada

SQL書きたい

Page 18: Tokyo Rubykaigi 01 t-wada

S2Dao•80:20•2WaySQL•手書きのSQL をサポート•SQL を知っていれば書ける

Page 19: Tokyo Rubykaigi 01 t-wada

2 Way SQL

Page 20: Tokyo Rubykaigi 01 t-wada

代入コメント(1)

Page 21: Tokyo Rubykaigi 01 t-wada

SELECT *FROM empWHERE job = /*ctx[:job]*/'CLERK'AND deptno = /*ctx[:deptno]*/20

外部SQL

Page 22: Tokyo Rubykaigi 01 t-wada

SELECT *FROM empWHERE job = /*ctx[:job]*/'CLERK'AND deptno = /*ctx[:deptno]*/20

からくり

Page 23: Tokyo Rubykaigi 01 t-wada

SELECT *FROM empWHERE job = /*ctx[:job]*/'CLERK'AND deptno = /*ctx[:deptno]*/20

Given

Page 24: Tokyo Rubykaigi 01 t-wada

ctx[:job] = 'MANAGER'ctx[:deptno] = 30

When

Page 25: Tokyo Rubykaigi 01 t-wada

SELECT *FROM empWHERE job = ?AND deptno = ?

Then

と、 ['MANAGER', 30]

Page 26: Tokyo Rubykaigi 01 t-wada

代入コメント(2)

Page 27: Tokyo Rubykaigi 01 t-wada

SELECT *FROM empWHERE job = /*ctx[:job]*/'CLERK'AND id IN /*ctx[:ids]*/(10,11)

Given

Page 28: Tokyo Rubykaigi 01 t-wada

ctx[:job] = 'MANAGER'ctx[:ids] = [30,40,50]

When

Page 29: Tokyo Rubykaigi 01 t-wada

SELECT *FROM empWHERE job = ?AND ids IN (?, ?, ?)

Then [ 'MANAGER', 30, 40, 50 ]

Page 30: Tokyo Rubykaigi 01 t-wada

IF コメント

Page 31: Tokyo Rubykaigi 01 t-wada

SELECT * FROM empWHERE job = /*ctx[:job]*/'CLERK' /*IF ctx[:age]*/AND age > /*ctx[:age]*/20/*END*/

Given

Page 32: Tokyo Rubykaigi 01 t-wada

ctx[:job] = 'MANAGER'ctx[:age] = 30

When

Page 33: Tokyo Rubykaigi 01 t-wada

SELECT * FROM empWHERE job = ? AND age > ?

Then

と、 ['MANAGER', 30]

Page 34: Tokyo Rubykaigi 01 t-wada

SELECT * FROM empWHERE job = /*ctx[:job]*/'CLERK' /*IF ctx[:age]*/AND age > /*ctx[:age]*/20/*END*/

Given

Page 35: Tokyo Rubykaigi 01 t-wada

ctx[:job] = 'MANAGER'ctx[:age] = nil

When

Page 36: Tokyo Rubykaigi 01 t-wada

SELECT * FROM empWHERE job = /*ctx[:job]*/'CLERK' /*IF ctx[:age]*/AND age > /*ctx[:age]*/20/*END*/

Then

Page 37: Tokyo Rubykaigi 01 t-wada

SELECT * FROM empWHERE job = ?

Then

と、 ['MANAGER']

Page 38: Tokyo Rubykaigi 01 t-wada

BEGINコメント

Page 39: Tokyo Rubykaigi 01 t-wada

SELECT * FROM emp/*BEGIN*/WHERE /*IF ctx[:job]*/ job = /*ctx[:job]*/'CLERK'/*END*/ /*IF ctx[:age]*/AND age > /*ctx[:age]*/25/*END*//*END*/

Given

Page 40: Tokyo Rubykaigi 01 t-wada

ctx[:job] = nilctx[:age] = 35

When

Page 41: Tokyo Rubykaigi 01 t-wada

SELECT * FROM emp/*BEGIN*/WHERE /*IF ctx[:job]*/ job = /*ctx[:job]*/'CLERK'/*END*/ /*IF ctx[:age]*/AND age > /*ctx[:age]*/25/*END*//*END*/

Then

Page 42: Tokyo Rubykaigi 01 t-wada

SELECT * FROM empWHERE age > ?

Then

と、 [35]

Page 43: Tokyo Rubykaigi 01 t-wada

SELECT * FROM emp/*BEGIN*/WHERE /*IF ctx[:job]*/ job = /*ctx[:job]*/'CLERK'/*END*/ /*IF ctx[:age]*/AND age > /*ctx[:age]*/25/*END*//*END*/

Given

Page 44: Tokyo Rubykaigi 01 t-wada

ctx[:job] = nilctx[:age] = nil

When

Page 45: Tokyo Rubykaigi 01 t-wada

SELECT * FROM emp/*BEGIN*/WHERE /*IF ctx[:job]*/ job = /*ctx[:job]*/'CLERK'/*END*/ /*IF ctx[:age]*/AND age > /*ctx[:age]*/25/*END*//*END*/

Then

Page 46: Tokyo Rubykaigi 01 t-wada

SELECT * FROM emp

Then

と、 [ ]

Page 47: Tokyo Rubykaigi 01 t-wada

第一部完

Page 48: Tokyo Rubykaigi 01 t-wada

第二部移植する方法のこと

Page 49: Tokyo Rubykaigi 01 t-wada

検討

Page 50: Tokyo Rubykaigi 01 t-wada

本当に移植すべきか?•定番ライブラリではダメか•代替案はないのか•早急に結論を出す前に、定番を調べるべし

Page 51: Tokyo Rubykaigi 01 t-wada

全部移植すべきか?

•対象ライブラリの美点は何か•既にあるライブラリでも実現できることは何か

Page 52: Tokyo Rubykaigi 01 t-wada

移植

Page 53: Tokyo Rubykaigi 01 t-wada

最初に確認すること

•対象コードのテストはあるか•対象機能(の美点)は切り出し可能か

Page 54: Tokyo Rubykaigi 01 t-wada

テストが無い場合

• 残念ながら、レガシーコードです

• 本日は詳細は割愛

• WEwLC 読書会を行っています

• http://groups.google.co.jp/group/legacy-code

Page 55: Tokyo Rubykaigi 01 t-wada

大原則:一度に複数を相手にしない

Page 56: Tokyo Rubykaigi 01 t-wada

動作する、きれいなコードへ

きれい

汚い

(すぐには)動かない 動作する

二つの道がある

Page 57: Tokyo Rubykaigi 01 t-wada

逐語訳的移植

Context 言語間で移植しようとしている

Force ともかくまず動くところまで持っていきたい

Solution 設計や名前を変えずに、まず言語間の移植のみに集中する

Page 58: Tokyo Rubykaigi 01 t-wada

逐語訳的テスト移植

Context テストコードを移植しようとしている

Force 安全に移植したいが、テストのテストは存在しない

Solution テストの設計や語彙を変えずに、まず言語間の移植に集中

Page 59: Tokyo Rubykaigi 01 t-wada

変えないもの•xUnit という共通語彙•設計•クラスやメソッドの名前•クラス構造 (interface除く)

Page 60: Tokyo Rubykaigi 01 t-wada

変えたもの•言語間の違い•静的型付けから動的型付けへ•予約語•xUnit の方言

Page 61: Tokyo Rubykaigi 01 t-wada

Java コードpublic void testNext() throws Exception { String sql = "SELECT * FROM emp"; SqlTokenizer tokenizer = new SqlTokenizerImpl(sql); assertEquals("1", SqlTokenizer.SQL, tokenizer.next()); assertEquals("2", sql, tokenizer.getToken()); assertEquals("3", SqlTokenizer.EOF, tokenizer.next()); assertEquals("4", null, tokenizer.getToken());}

Page 62: Tokyo Rubykaigi 01 t-wada

Ruby コードdef testNext sql = "SELECT * FROM emp" tokenizer = SqlTokenizer.new(sql) assert_equal(SqlTokenizer::SQL, tokenizer.go_next(), "1") assert_equal(sql, tokenizer.getToken(), "2") assert_equal(SqlTokenizer::EOF, tokenizer.go_next(), "3") assert_nil(tokenizer.getToken(), "4")end

Page 63: Tokyo Rubykaigi 01 t-wada

PTSCTCPWPort The Simplest Case That Could Possibly Work

Context 逐語訳的テスト移植を終えた

Force グリーンが見たいが、レッドになるテストが多すぎる

Solution 最も単純なテストケースから実装し、それ以外は pending

Page 64: Tokyo Rubykaigi 01 t-wada

Context 移行元コードに不明点がある

Force 不明点をおいたまま先に進めたくない

Solution 移行元コードの現在の振る舞いを自動テストに落とし込む

Characterization Test

Page 65: Tokyo Rubykaigi 01 t-wada

洗練

Page 66: Tokyo Rubykaigi 01 t-wada

TDDのサイクル1. テストを書き2. そのテストを実行して失敗させ(Red)3. 目的のコードを書き4. 1で書いたテストを成功させ(Green)5. テストが通るままでリファクタリングを行う(Refactor)

6. 1~5を繰り返す

Page 67: Tokyo Rubykaigi 01 t-wada

TDDとコード

きれい

汚い

(すぐには)動かない 動作する

Red

Green

Refactoring

Page 68: Tokyo Rubykaigi 01 t-wada

TDDと黄金の回転

きれい

汚い

(すぐには)動かない 動作する

Red

Green

Refactoring

Page 69: Tokyo Rubykaigi 01 t-wada

実装のテストから仕様のテストへ

Context 移植の最初のステップが終わったので、内部を改善したい

Force 実装内部を思う存分変更したい

Solution ホワイトボックステストをブラックボックステストに変換

Page 70: Tokyo Rubykaigi 01 t-wada

例えば、RSpec を使ってみる

Page 71: Tokyo Rubykaigi 01 t-wada

郷に入っては郷に従え

Context 逐語訳的移植を終えた

Force コードをきれいにしたい

Solution 移植対象言語のイディオム、ベストプラクティスで書き換える

Page 72: Tokyo Rubykaigi 01 t-wada

王道を知る

Context 逐語訳的移植を終えた

Force コードをきれいにしたい

Solution設計の王道を調べ、移植対象言語に実装が存在したら使用を検

討する

Page 73: Tokyo Rubykaigi 01 t-wada

パーサジェネレータracc

Page 74: Tokyo Rubykaigi 01 t-wada

ご存知、な (ry

ごめんなさいごめんなさい

Page 75: Tokyo Rubykaigi 01 t-wada

raccデカルチャー

ごめんなさいごめんなさい

Page 76: Tokyo Rubykaigi 01 t-wada

割愛ごめんなさいごめんなさい

Page 77: Tokyo Rubykaigi 01 t-wada

そして移植の最後に

Page 78: Tokyo Rubykaigi 01 t-wada

恩返し

Page 79: Tokyo Rubykaigi 01 t-wada

第二部完

Page 80: Tokyo Rubykaigi 01 t-wada

Q & A

Page 81: Tokyo Rubykaigi 01 t-wada

おわりに

Page 82: Tokyo Rubykaigi 01 t-wada

大原則:一度に複数を相手にしない

Page 83: Tokyo Rubykaigi 01 t-wada

TDDと黄金の回転

きれい

汚い

(すぐには)動かない 動作する

Red

Green

Refactoring

Page 84: Tokyo Rubykaigi 01 t-wada

続け!

Page 85: Tokyo Rubykaigi 01 t-wada

ご清聴ありがとうございました