從領域驅動設計看Tennis Kata(上)
Feb. 25 12:39~14:00
▲Eiffel正在修練睡夢讀書法Kata
Tennis Kata
Kata,中文翻譯成套路。在敏捷開發領域中,kata指「被設計用來練習特定技巧(特別是程式設計)的題目與參考答案。」
最近Teddy在修改【軟體重構入門實作班】與【單元測試這樣學就會了實作班】教材內容,花點了時間重新練習了幾個kata。今天想從DDD(domain-driven design;領域驅動設計)的觀點,談一個經常被練習的題目:Tennis Kata。
Tennis Kata有兩個版本,一個用來練習TDD,另一個用來練習Refactoring。透過TDD方式撰寫或直接重構已完成的網球比賽計分程式,分別學習這兩種技能。
一個完整的網球比賽分成:
- 比賽(Match)
- 盤(Set)
- 局(Game)
一場比賽有若干盤,一盤有若干局。詳細說明可參考維基百科。為了簡化起見,Tennis Kata只計算局(Game)的結果。關於局的計分方式,維基百科的解釋如下:
網球每局的記分方法:從0至3分分別為「零」(love)、「十五」(fifteen)、「三十」(thirty)和「四十」(forty)。記分時,發球手的得分在前。因此「30比0」的意思是,發球手贏得2分,而接球手還未得分。
當雙方運動員都得到了3分時,一般叫「平局」(deuce)而非「40比40」。在出現平局後一名球手再得一分,被稱為「占先」(advantage),而不再記分。如果在占先的情況下失去一分,就再度回到平局;如占先後再得一分,就贏得一局。
今天先談Tennis TDD Kata,明天再談重構。
***
Tennis TDD Kata
網路上有很多Tennis TDD Kata的範例,Google搜尋時Teddy找了第一筆資料來參考。
作者把用TDD完成Tennis Kata的主要過程記錄下來,但是讀到最後完成的程式,Teddy覺得下列的IsDeuce函數的邏輯好像怪怪的。
▲節錄自Day29 TDD套路經典!? Tennis Game!
如果第一個比賽選手的分數大於等於3,IsDeuce回傳true。但根據網球比賽的規則,deuce有兩個條件:
- 雙方選手的分數都是3分,或
- 超過3分之後,在這一局比賽結束前,如果再度平手,也稱為deuce
那為什麼這段程式會寫成判斷 _firstPlayerScore >= 3 ,連是否平手都沒判斷?
繼續往前閱讀文章,Teddy發現作者在判斷是否為deuce的時候,production code長成下面這樣。
▲節錄自Day29 TDD套路經典!? Tennis Game!
接著作者用extract method重構,把 _firstPlayerScore >= 3 放到IsDeuce函數,所以造成isDeuce的邏輯變成_firstPlayerScore >= 3。
***
和DDD有什麼關係?
DDD強調domain model和ubiquitous language(在限定領域中開發人員與利害關係人一致性使用的語言或是術語),幫助開發人員在系統重構時找出重構目標、重新分派物件責任,最後利用重構逐步將ubiquitous language實作在程式碼中(ubiquitous language in code)。上面這個例子,測試案例雖然都通過,程式也可以動,但是並沒有完全做到ubiquitous language in code。因為deuce的定義,包含在Tennis的ubiquitous language裡面,也就是前面提到的:
- 雙方選手的分數都是3分,或
- 超過3分之後,在這一局比賽結束前,如果再度平手,也稱為deuce
而上面的程式範例並沒有正確表達這個邏輯。
***
重構的錯誤
就算不考慮ubiquitous language的觀點,直接把_firstPlayerScore >= 3用extract method改成IsDuece也不洽當。為什麼,再看一次作者原本的程式碼:
▲節錄自Day29 TDD套路經典!? Tennis Game!
這個程式碼有兩個if,結構為:
if (_firstPlayerScore == _secondPalyerScore) {
if (_firstPlayerScore >= 3) {
return “Deuce”;
}
}
也就是說,deuce的條件必須兩個if同時成立。原本作者的程式邏輯是對的,反倒是重構之後沒注意到if (_firstPlayerScore >= 3)其實是存在另一個 if之下,直接extract method反倒讓程式碼與領域知識不一致。
如果可以把程式改成下面這樣,isDeuce就符合deuce在Tennis領域的定義,應該比較落實ubiquitous language in code的精神。
***
讓程式碼說實話
程式設計師應該大多認同,程式是寫給人看的,不是寫給電腦看的。落實ubiquitous language in code,你的程式碼就會說人話,而且是實話,不是謊話。
如此一來,可以避免程式碼和領域知識不一致。程式比較容易理解,開發人員也比較敢修改程式。這也是一種擁抱改變,讓軟體變軟的方法。
***
友藏內心獨白:說實話很重要。
沒有留言:
張貼留言