practice: refactor with tests

21
Practice: Refactor with Tests http://tech.manic.tw 2013/05/14 Ruby Tuesday@Taipei 13515星期三

Upload: manic-chuang

Post on 06-Jul-2015

543 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Practice: Refactor with Tests

Practice: Refactor with Testshttp://tech.manic.tw

2013/05/14 Ruby Tuesday@Taipei

13年5月15⽇日星期三

Page 2: Practice: Refactor with Tests

About Me

• Manic Chuang

• http://www.facebook.com/manic.chuang

• http://tech.manic.tw

• PIXNET

• Rails / PHP

13年5月15⽇日星期三

Page 3: Practice: Refactor with Tests

⼤大綱

• 簡單介紹:Refactor 與 Testing

• 重點:在實務上導⼊入 Refactor 與 Testing 的經驗談

13年5月15⽇日星期三

Page 4: Practice: Refactor with Tests

Refactor

• To restructure software by applying a series of refactorings without changing its observable behavior.

• 在不改變程式外在⾏行為的情況下改進程式內部的架構

13年5月15⽇日星期三

Page 5: Practice: Refactor with Tests

Benefit?

• 程式更好維護• 和測試結合 -- 讓你的開發流程更安⼼心

• ⼀一個有良好架構以及測試的專案對於新 Feature 的接受度遠⾼高於那些所謂“年久失修”的專案

13年5月15⽇日星期三

Page 7: Practice: Refactor with Tests

Tests

• “重構之前,⾸首先檢查⾃自⼰己是否有⼀一套可靠的測試機制。這些測試必須有⾃自我檢驗 (self-checking) 能⼒力”

• 如果你在重構時沒有包含測試,不只是這個重構可能會引來更多的 Bug 的問題 ﹣ 你可能會過度追求完美,導致不知如何停⼿手。

13年5月15⽇日星期三

Page 8: Practice: Refactor with Tests

It’s hard to begin.

• Refactor code 就是改動程式碼,改動就有可能出錯,⽽而沒有⼈人希望⼀一個正常運⾏行的 production site 因為改爛 code ⽽而 crash 掉

• 為了不出錯,要準備好相對應的測試,以確保程式碼不會出錯。

• 由以上兩點來講那就是會花上許多時間• ⽽而這個花上許多時間的結果並不是實作了⼀一個新功能

13年5月15⽇日星期三

Page 9: Practice: Refactor with Tests

Refactor 的兩⼤大難關

• I was refactoring code that no one had asked me to work on 我在重構⼀一段沒⼈人叫我去改的程式碼

• I found it too hard to put tests in place, so I did it without them. Which, naturally, broke some things我發現實在太難加上測試了,所以我就沒測它,然後就有東⻄西爛掉了

Reference: How do you stop yourself from refactoring working but awful code?

13年5月15⽇日星期三

Page 10: Practice: Refactor with Tests

Change your situation

• 為了要加上這個新的 Feature,我們原本的程式碼架構需要配合做出⼀一些調整...

• When you need to refactor code you are supposed to work on, have tests in place, but they don't have to be automated.我需要重構這段程式碼,因為很難寫⾃自動化測試碼,所以我找⼈人來做QA

13年5月15⽇日星期三

Page 11: Practice: Refactor with Tests

Situation

• ⼀一個牽涉到⾦金流交易的網站,它現在有了BUG,必須要儘快修復。

• 同時有新的⼤大 Feature 要上

• 網站當時就很趕⼯工上來的,⽽而且經過上線後連續幾個月的⼩小 Feature 增/減,程式碼架構越來越複雜

• 時間當然有夠趕

13年5月15⽇日星期三

Page 12: Practice: Refactor with Tests

⽼老闆要求上線時不能再有這些BUG,⼀一個BUG的損失要你賠⼀一千萬(誤)

13年5月15⽇日星期三

Page 13: Practice: Refactor with Tests

溝通

• Staging Server:要求經過⾜足夠⼈人⼯工測試後再上到 production server.

• “如果你發現⾃自⼰己需要為程式添加⼀一個特性,⽽而程式碼結構使你無法很⽅方便地那麼做,那麼就先重構那個程式,使特性的添加⽐比較容易進⾏行,然後再添加特性。”

13年5月15⽇日星期三

Page 14: Practice: Refactor with Tests

步驟

• 共識:QA 是為了確保團隊能夠⼀一起擔負責任。如果今天有了BUG不是程式設計師⼀一個⼈人的錯誤。

• 讓 Refactor 同時帶著⼀一些新的東⻄西:“我弄了⼀一個新的寫法程式碼會變好維護⼀一點,⿇麻煩幫忙驗收⼀一下” 這句話是不是哪裡怪怪的?

13年5月15⽇日星期三

Page 15: Practice: Refactor with Tests

Questions

• 我們怎麼確認這個 Refactor Pattern 適合我們現在的狀況?

• 要如何確認是否過度或是不⾜足?

13年5月15⽇日星期三

Page 16: Practice: Refactor with Tests

Example: AuctionService

• 商品有起標⾦金額,使⽤用者下標後所增加⾦金額為1元(可設定,範圍為1~10)

• 使⽤用者每下⼀一次標需要耗⽤用點數1點(可設定,範圍為1~10)

• 在商品結標前,若有競標者下標,計時器將⾃自設定時間開始重新倒數(25秒預設)

• 使⽤用者每下⼀一次標有20%機率可以獲得回饋1點

13年5月15⽇日星期三

Page 17: Practice: Refactor with Tests

Extract Service Objects

• The action is complex

• The action reaches across multiple models

• The action interacts with an external service

• The action is not a core concern of the underlying model

• There are multiple ways of performing the action

13年5月15⽇日星期三

Page 18: Practice: Refactor with Tests

Refactor: AuctionServiceclass Auction

def bid_by(user) return false unless user.can_bid?(self)

user.consume_points

self.update_price_and_time

self.set_winner(user)

user.save_weekly_bid_count

user.check_if_lucky_bid

self.auction_logs.create endend

class AuctionService

def initialize(auction, user) @user = user @auction = auction end

def bid! return false unless user_can_bid?

consume_user_points update_auction_price_and_time set_auction_winner set_user_weekly_bid_count check_user_if_lucky_bid generate_logs endend

13年5月15⽇日星期三

Page 19: Practice: Refactor with Tests

Compare

• auction.bid_by(user) 也可以寫為 user.bid(auction),讓⼈人困惑。

• 原本被拆分為兩個 model 上的測試,現在全部集中在 AuctionService 這個 model 上了

• 只要看 AuctionService 的測試內容就可以完整明⽩白此規格的要求

• 原本 model 帶著許多只有在特定時候才會⽤用到的 method,拆出去後這兩個 model 都變“輕”許多

13年5月15⽇日星期三

Page 20: Practice: Refactor with Tests

How Tests help you Refactor

• 最基本的幫助:你可以不⽤用擔⼼心改錯程式碼• ⼀一個好的測試規格可以幫助你找到 Bad Smell

• 不⽤用硬是想著要⾃自動化測試。Any effective test is better than no test at all.

13年5月15⽇日星期三

Page 21: Practice: Refactor with Tests

Thank you.

13年5月15⽇日星期三