2009-08-30 53 views
4

的TDD圈:測試 - >代碼 - >重構,我們應該什麼時候開始重構?

"Write failing Test" -> "Write Code to fit a Test" -> "Refactor" 

在「編碼」步驟中,我們假定編寫代碼儘可能簡單,只是爲了解決一個失敗的測試。在真正需要之前,我們不應該編寫複雜的代碼。

下一步是重構。我們應該重構剛剛寫的代碼嗎?我認爲沒有真正的意義,因爲只要測試通過,我們應該對代碼感到滿意。

可能重構活動應該被某些東西強加,比如代碼寫入是由失敗的測試引起的。這裏是一些可能的因素:

  1. 下一個測試寫入需要在系統(重構)的一些變化
  2. 性能差。我們需要在不破壞功能的情況下對其進行改進
  3. 代碼審查顯示編寫的代碼很難理解。

您看到啓動重構的其他原因是什麼?

而且,這是正確的方案:

"Write failing Test" -> "Code" -> "Refactor" -> "Write failing Test" 

或者可能是它應被視爲

"Write failing Test" -> "Code/Refactor" -> "Write failing Test" 
+ 
"External factor (like bad performance)" -> "Refactor". 

回答

5

TDD是一個很好的工具,讓你跟蹤任務。這個問題:

「寫入失敗的測試」 - > 「代碼/重構」 - > 「寫入失敗的測試」

你求婚,是它可以很容易地成爲:

「寫失敗的測試」 - > 「重構」 - > 「編碼」 - > 「寫入失敗的測試」

或再

「寫入失敗的測試」 - > 「重構」 - > 「重構」 - > 「重構」 - > 「編碼」 - > 「寫入失敗的測試」

這是要避免的。通過在實施之初進行重構,您就沉迷於投機發展,而沒有實現編碼會議的目標。輕鬆切入切線並構建不一定需要的東西。如果您的功能正在運行並且測試通過,那麼確定何時適合停止重構是非常容易的。你可以隨時停下來,因爲你的測試已經過去了。

此外,當您的測試不是綠色時,您不想重構。

一對夫婦的其他小點:

  1. 我想大多數的文學有一個稍微不同的定義什麼是重構。這不是「對系統的某些改變」或性能改進,而是不會改變行爲但改進設計的特定改變。如果您接受該定義,那麼性能改進並不能真正符合要求:它們是需要進行自己的驗收測試的正常開發任務。我通常會試圖將這些視爲面向最終用戶的故事,這些故事的好處是明確的。合理?

  2. 我認爲你是對的,TDD實踐並沒有具體解決在代碼評審過程中發現的設計問題。 (請參閱反思和配對編程以獲得其他解決方案。)這些往往是更大的跨層次問題,並且需要一段時間才能定期清理。這可能是一個單獨的項目,但我個人總是喜歡將其作爲另一個「真實」故事的一部分。上次我做到了這一點,我們發現我們有一個問題,但最終等了幾個星期,直到我們有一個相關的故事來處理它。我們首先遵循TDD實施新功能的做法 - 儘管我們知道這是錯誤的。但是,我們真的明白髮生了什麼,爲什麼它很混亂,然後在重構階段花費比平常更長的時間。工作得很好。

+0

我只想強調'Refactor-> Refactor-> Refactor'節會導致無限制的變化,這會吸收大量的開發時間。還要注意,在每**代碼更改之後,您應該再次運行測試,無論該代碼更改是新功能還是僅重構。 – quamrana

+0

考慮我們編寫了一個應用程序,並且現在它允許我們列出任務併發布新任務。但要通過測試,就足以擁有全球任務列表。當然,客戶希望「任務能夠堅持下去」。我可以決定一個好的做法是實施IRepository。我需要現有的代碼來使用它。所以我重構了確保他們調用IRepository的方法。這次重構是由新的用戶故事引起的。總之,我試圖弄清楚的是 - 我們可以使用用戶故事/測試來驅動代碼編寫,還是重構本身?你怎麼看? – alex2k8

+0

我們正在從TDD轉移一點,所以我會盡量縮短。 *重構*的定義(在TDD世界中)是在測試結果爲綠色之前,您不會開始重構,除非它們是綠色(再次/靜止),否則您不會完成重構。所以他們是一個有用的工具,但他們不能真正「驅動」重構。 我對用戶故事實踐中的INVEST很有紀律。我總是試圖重構必要的重構成爲用戶故事的一部分,就像你上面所做的一樣。我永遠不會有一個故事「重構成IRepository」,但我會把它作爲一個有價值的面向用戶的功能的組成部分。 – ndp

1

嗯...我通常認爲這些種類的「外部」的重構與分離TDD週期本身。在使用TDD完成XYZ功能後,應該有一套健康的測試來防止通過重構引入錯誤(假設代碼覆蓋率最佳等)。無論如何,性能瓶頸和難以理解的代碼通常會出現,所以在那個時候進行重構將是理想的,我想。您可以提高性能,使代碼更易於理解,並在使用測試時執行其他需要執行的操作,以確保不會將錯誤引入系統。

所以要回答你的問題,我不認爲外部重構適合TDD模式,雖然標識符(如果你願意的話,代碼味道)絕對是跟蹤你開發代碼的項目。

+0

如果我們排除「外部」重構......您認爲TDD是否將重構作爲一個單獨的步驟,或者它將成爲「重構代碼」?僅在新的測試不能在不改變現有代碼的情況下實施的情況下重構。 – alex2k8

+0

那麼,模式第三步的想法就是在測試通過後讓代碼更好。而且由於測試已經到位,這可以安全地完成。就重構而言,爲了能夠編寫下一個測試,編譯器本身就是失敗測試的一個方面。你編寫測試代碼,看它「失敗」(即不編譯),然後重構代碼以使其編譯。 – Scott

9

你可以在測試通過的同時寫出一些非常難看的代碼;現在重構不是因爲它不工作,而是不可維護。這就是個案例。

在編寫代碼以適應多個測試之後,您可以開始拍攝更大的圖片 - 這些代碼片段之間是否有重疊,您可以在哪裏分解出一些重複內容?

+0

嗯。使感覺。 – alex2k8

+0

另請注意,重構是在代碼「有異味」時完成的,而不是在代碼複審時不工作或僅在代碼複審後進行。所以寫了一段代碼,讓測試通過,感覺到這種氣味 - 重構。 –

1

除了需要提高性能所引發的重構以外,我通常會注意到,在編寫代碼來通過測試時,我可以共享代碼或者更好,更優雅的方式來完成某些任務。此時,您完成了通過測試的代碼,確保所有測試都通過了,然後返回並重新進行重構。這可能涉及或不涉及您編寫的確切代碼,很可能是這樣,但它可能是您在編寫新代碼時注意到的。

有時我會注意到可以重構的東西,但是決定我現在正在處理的東西更重要。到那時,我會注意到這個問題以後再重構。最終,重構將變得或者比下一個特性更重要,它將在紅/綠/重構週期的重構階段完成。在這種情況下,這可能與我剛纔的工作無關。

1

在主要發佈之前,除了一兩個星期之外還有什麼不好的時間重構?

+0

嘿嘿,我想這導致了另一個模型:[重構] - >測試 - > [重構] - >代碼 - > [重構] – alex2k8

+1

重構沒有不好的時間,因爲你要再次運行你的測試到證明在做出改變之前你沒有破壞任何東西。 它唯一的不好,如果你只是重構,並且從不增加當前項目所需的新功能。 – quamrana

+0

假設你的測試真正涵蓋了一切。我更願意將重大的重構留在發佈週期的開始。我認爲風險較小。 –