碁峰資訊

在重構逐漸被接受多年之後的今天,程式設計環境針對重構這件事,還是很缺乏自動化支援,這點實在很讓人難以理解。但好吧。希望你已經很習慣一次只邁出一小步,一點一滴持續不斷的進行軟體設計。整理可以說就是重構的入門之道。

我們將會討論如何把整理這件事,納入到個人開發工作流程中:

• 什麼時候要開始做整理?

• 什麼時候要停止做整理?

• 如何把整理、改變程式碼結構、改變系統行為這三件事結合起來?

我們一開始可以先來討論一下,整理這件事,如何與「拉取請求」(PR;pull request)和「程式碼審查」(code review)這兩個工作流程互相搭配起來。

把整理工作切分出來

我們暫時假設,你在寫程式的時候,採用的是拉取請求(PR)/程式碼審查的開發模式。你會把整理這件事,放在哪個位置呢?

下面就是一個「追著尾巴跑」(tail chasing)的醜陋做法:

1. 我把整理工作與行為上的改變混在一起。

2. 審查者向我抱怨,說我的PR拖得太長了。

3. 我把整理工作切分出來,讓它擁有自己的PR,然後把它放在行為改變的前面(這種情況居多)或後面。

4. 審查者向我抱怨說,這種整理類PR根本就沒意義。

5. 回到1。

整理這件事總要有個地方去做,要不然就是完全不做。究竟應該在哪裡做呢?直接跳到結論的話,就是:放到獨立的PR中,然後每個PR所做的整理盡量越少越好。

我們就來深入探討一下其中的取捨。剛開始學習如何做整理的人,好像都會經歷好幾個可預期的不同階段。在第一個階段,我們只懂得做出各種改變,而且一開始這一大堆的改變,並沒有什麼特別的區別。

假設我們正在修正一個if語句,修到一半發現有個名稱錯了,於是就順手把它修正過來,然後再回頭繼續修正這個if語句。在這個階段,改變就只是改變而已。

學會整理的做法之後,感覺就好像顯微鏡底下的圖片焦點變清楚了。其中有一些改變,改變的是程式的行為屬性,也就是程式執行過程中可以觀察到的一些改變。另外還有一些改變,改變的是程式的結構。像這樣的改變,只有直接去查看程式碼才能看得出來。

在這個階段,我們對行為上的改變和結構上的改變,還沒有什麼特別的想法和做法—我們只是意識到,可以把改變分成兩種而已。

經過一段時間之後,我們就可以開始察覺出一些共通的流程。如果先把程式碼切成一塊一塊的,接下來經常就可以提取出一些具有解釋效果的輔助函式,再接下來我們就會更容易去做出行為上的改變。如此一來程式設計這件事,就變得更像是下一盤西洋棋,你可能在好幾步之前,就可以猜出整盤棋大概會怎麼發展了。

請注意,這時候我們還只是用了一個很大的PR,把所有改變全都包在一起。目前我們還只是處在「追著尾巴跑」這個循環的第1步而已。我們所做的每個行動都有其目的,要不是為了做出某個簡單的改變,要不就是為了更容易做出改變。不過,把所有這些全都混在一起,實在有點亂。審查者會抱怨,也是很正常的事。

於是,我們開始嘗試把改變區分成兩種獨立的PR。一系列的整理(甚至只是一次小小的整理),會被放進一個獨立的PR。行為上的改變,也會放進一個獨立的PR。每次在「整理」和「行為改變」之間進行切換時,我們都會開一個新的 PR。

PR應該如何整併或拆分,這也是一件需要權衡取捨的事情。你可以從動機的角度來思考。一個比較大的、包羅萬象的PR,可以呈現出比較完整的情況,但對審查者來說,其中所包含的改變可能太多了,這樣就很難提供真正有用的回饋意見。比較小的PR則可以讓回饋意見限縮在比較小的範圍,但是也有可能讓審查者陷入瑣碎的枝末細節中。

審查過程如果拖得比較長,也會影響到大家的動機。如果程式碼審查的速度很快,就等於是鼓勵你多去建立一些更小的PR。這種更有針對性的PR也會鼓勵審查者加快審查。同樣的道理,這個循環也可能反過來:比較慢的審查速度,只會鼓勵PR變得更大,而更大的PR,也會拖慢後續的審查。

如果你可以做出讓人很放心的整理,懂得用小小的步驟去進行整理,而且會用絕對安全的方式進行整理,這樣我就會鼓勵你去嘗試,讓這種整理類的PR不再需要進行審查。這樣就可以進一步降低延遲的影響,從而激勵大家多去提交一些比較小的整理類PR。

連鎖效應

整理就像洋芋片。你吃了一片,就想再吃一片。控制住想要做整理的衝動,其實是一個很關鍵的整理技巧。你才剛剛整理過;還應該再多整理一下嗎?這其實要看情況。

你想要踏出多大的步伐,由你自己決定,不過我還是要鼓勵你,整理時盡量保持小小的步伐。然後盡可能去優化每一步。表面上來看,你好像在奔跑,但你知道自己其實就像蜈蚣一樣,實際上是邁出了許多小小的步伐。

整理就像是下一盤棋,你多多少少都可以預見接下來幾步的發展。我們就來看看各種整理的做法,如何進一步帶動其他整理的做法:

 守衛語句  一旦你採用守衛語句的寫法,判斷條件可能就會變簡單,讓你可以提取出某個具有解釋效果的輔助函式,或是提取出某些具有解釋效果的變數。

 沒用到的死程式碼   一旦刪除掉一堆亂七八糟的死程式碼,也許你就可以看得出來,如何根據閱讀順序或內聚順序,來重新排列程式碼。

 用同樣的寫法做同樣的事   如果你確實可以做到,同樣的工作都用同樣的程式碼來實現,不同的工作就用不同的程式碼來實現,這樣你就可以把一些邏輯意義上平行對等的程式碼,按照閱讀順序來進行分組。舉個例子,有一次我在處理一個檔案,其中包含了好幾個Web入口點。由於程式碼看起來都很相似,所以我很自然就把它們分組放在檔案的最前面,變成了其餘程式碼的一個目錄。

 舊的實作方式搭配新介面  一旦你有了一個閃亮的新介面,你一定想好好善用它。如果你沒有好用的自動重構工具,去針對所有呼叫到新介面的地方進行轉換,你就只好一個一個進行人工轉換。這是我們第一次見識到所謂的扇出(fanout)的威力—一個整理動作,導致了更多的整理需求,而每個整理需求,又會導致更多的整理需求。

 閱讀順序  建立好閱讀順序之後,你可能就會看到一些機會,可以讓同樣的事,全都採用同樣的寫法。因為之前各個元素相隔的距離比較遠,以至於你看不到其中的相似之處。

 內聚順序  根據內聚順序把元素放到一起之後,下一步或許就可以考慮把它們提取到一個子元素中。舉例來說,你可以建立一個輔助物件(helper object),不過這樣的做法,已經超出整理的範疇了。話雖如此,但如果你在整理過程中很自在、很有自信,你很自然就可以看出更大規模的設計變更做法,進一步讓行為上的改變變得更加容易。

你可能會開始把許多整理做法串聯起來,對程式碼結構做出比較大的改變。請務必小心留意,不要做出太多、太快的改變。一連串成功的整理,抵不過一次有問題的、成本昂貴的整理。這就像是在練習每個音階的音符,請好好練習怎麼做好整理這件事。等你能夠輕鬆俐落處理好各種不同的音符,你就能編寫出美妙的旋律了。(本文摘錄整理自《先整理一下?|個人層面的軟體設計考量》,碁峰資訊出版提供)

圖片來源_碁峰資訊

 書名  先整理一下?|個人層面的軟體設計考量(Tidy First?: A Personal Exercise in Empirical Software Design)

Kent Beck/著;藍子軒/譯

碁峰資訊出版

定價:480元

圖片來源_Kent Beck

 作者簡介 

Kent Beck

Kent Beck 是「極限程式設計」(Extreme Programming)的創建者,同時也是軟體模式的先驅、JUnit的共同作者、測試驅動開發(Test-Driven Development)的重新發現者,以及3X: Explore/Expand/Extract(探索/擴展/提取)的觀察家。他也是《敏捷宣言(Agile Manifesto)的第一位簽署者(按照字母順序)。Kent住在加州舊金山,擔任Mechanical Orchard的首席科學家,他經常會傳授一些技能,協助極客們能夠在這個世界上感覺到更加安心。

熱門新聞

Advertisement