程式者的胡言亂語

pageicon 星期二 二月 26, 2008

砍掉重練真的會比較好嗎?

「砍掉重練」這個詞,最近十分的流行,但就我所接觸到的時間點,大概是在十幾年前我們還在玩MUD的時候,就時常可以聽到了。MUDMulti User Dimension)大致上和現在的線上遊戲差不多,只不過它是文字模式的線上角色扮演遊戲,所有場景的呈現,人物動作的描述,甚至玩家控制人物行為的方法,都是透過文字來辦到。

既然是RPG遊戲,當然免不了有練功升級的過程。各家MUD在升級或職業系統的設計不同,有些MUD在升級過程中,玩家必須要進行一些角色能力方向上的選擇,例如想朝魔法師職能方向發展,那麼過程中就必須要對一些魔法師需要的能力多加增強。有時候,在這個過程中,如果做錯了一些決定,就會導致所訓練出來的角色,已經昇到了最高等級,但能力卻不如自己預期。所以,很多玩家就會忍痛「砍掉重練」,重新再出發練一個新的角色出來。這砍掉重練的想法,基本上還是出自於對現況的不滿意,但又想追求完美的想法。其實,除了玩RPG的玩家外,程式員也是屬於特愛砍掉重練的族群-尤其是那種上進、對自己有期許的程式員。

在這麼多年來的軟體開發生涯中,實在看過太多砍掉重練的例子,這其中當然包括我自己。為什麼程式員們會決定把辛辛苦苦寫成的程式全數廢掉,然後重新再開始打造一個新的呢?據我的觀察,原因大致有下列數種:(1)撰碼風格不佳(2)過多重覆累贅的程式碼(3)程式架構疊床架屋(4)架構設計不夠通用(5)所運用的技術跟不上潮流(5)有太多隱藏在深處的臭蟲未爆彈。

覺得自己程式的風格不佳,引發想要砍掉重練之念頭,是初期程式員時常會有的症狀。尤其是那種原先不講究撰碼風格(包括程式編排、命名慣例),但突然領會到撰碼風格其實很重要的程式碼,特別容易在體驗到好的程式風格之後,把自己的程式全部砍掉重練。對於有經驗的程式員來說,這種症狀只能算是偶發的,通常只有在經歷過一段較長的時間後,所使用的撰碼風格已有所改變,使得新式的風格與舊式的風格產生不一致的情況,自律愈嚴的程式員,愈是難忍受這種風格的不一致,於是便會興趣重頭練過的念頭。

過多重覆累贅的程式碼通常是起因於開發時為了縮短時程,直接將程式碼由系統中的某處,直接抄寫或抄寫後施以小幅度修改,放到系統的另一處。我們在談到「物件導向程式設計中常見的錯誤」時,便有提到這是所謂「相似或重複的程式碼(duplicated code)」的毛病。這個毛病多半是因為貪圖一時之快,未能保持時時進行重構(refactoring)的態度,一個偷懶,這些相似或重複的程式碼,就又偷偷的在系統中蔓延。如果原先就對這個毛病的後果一無所知,那倒也不打緊,如果是對它所可能引發的問題十分清楚的程式員,發現問題已經病入膏肓,又不是一時三刻的重構可以解決的,就很有可能會想要全盤放棄重新來過。

程式架構疊床架屋,是許多系統隨著時間及需求的不斷調整,時常會造成的問題。這種情況在所難免,因為對系統需求的預測,本來就很難在初次分析之際,就通盤掌握,許多需求在開發過程或甚至系統上線後,才會一一發掘。但如果原先架構設計的方向或範圍和新需求不符,而且又沒有在納入新需求時,以漸進的方式的調整系統架構,便很容易造成持續在不夠穩固的基礎上添磚加瓦,最後蓋出了一棟危樓。

架構設計不夠通用的這個原因,和「程式架構疊床架屋」這個問題相關。會查覺到架構設計不夠通用,就是因為開發端陸續接收到新的需求,或者變更的請求,但卻發現系統現行的設計,不容易滿足這些新的需求。倘若勉強為之,就得疊床架屋的蓋上去。為了徹底解決問題,程式員就會想把重要的架構元件整個改頭換面,以根絕問題。

至於「所運用的技術跟不上潮流」,是觸動許多喜歡吸收科技新知的程式員決定砍掉重練的常見原因。例如,自己原先使用EJBEnterprise JavaBean)的技術,但在像Hibernate之類的技術出現之後,發現到它具有諸般的好處,於是自己舊有的系統,頓時處處看起來不順眼,好像問題百出一般。所以,這種「技術更新狂熱者」時常會耗費大量的時間,保持自己程式碼所用的技術,永遠處於世界技術的潮流上。砍掉重練,也就成了家常便飯。

最後一個常見的原因就是系統有太多隱藏在深處的臭蟲未爆彈。系統經過一段時間的測試,甚至是正式產品化發行或上線之後,仍然不定時在不確定的情況下,會有讓人惱人的臭蟲發生。因為系統規模已經頗為龐大,要從中再挖掘出造成系統問題的臭蟲,實在是難上加難。在這種情況下,想要程式員不去期待重寫會更好的心情,真的也不容易。

從軟體開發生產力的角度來看,基本上「砍掉重練」是不正確的態度。既有的程式碼(legacy code)有時看來是負擔,但其實也是耗費許多資源才得以產生的。這些程式碼昔日都是花費程式員的力量撰寫、測試人員的力量去測試、再修正錯誤而得的。砍掉重練的話,等於是這些在程式碼的投資幾乎都付諸流水,全新再來過。這不僅意謂著程式得全新重寫,而且還得重新測試並予以修正。事實上,重新把程式寫過,並不會在重新來過的過程中降低太多錯誤發生的機會。事實上,發生臭蟲的比例應該還是差不多。而舊有程式碼存在的最大價值,便是在於這些程式碼都是經過某種程度的測試,具備相當品質的。測試及修正程式碼的成本時常是撰寫程式碼的數倍,放棄相對穩定的舊有程式碼,所付出的代價不可不謂沉重。

撰碼風格不佳」及「過多重覆累贅的程式碼」這兩項想要砍掉重練的理由,都是利用重構技巧可以解決的問題。基本上,對舊有程式碼的健康觀念,應該是漸進且持續的導正。企圖全面翻新,不代表現在存在的問題,就一定可以獲得解決。全面翻新最常發生的事,就是舊問題仍然會再度上演。何況,每個人的功力總是隨著時間一直在精進,愈是處於進步狀態的程式碼,每隔一段時間,就會對自己過去的程式碼不滿意,想要重新寫過。但這卻無疑的是優秀程式員的一大心魔。優秀的程式員,會盡力的想維持自己作品的完美性,但為了這形式的完美性,常常卻又得以生產力為代價,從工程的角度,實在一點也不划算。可用的程式碼比漂亮的程式碼來得實際可靠多了。

此外,像架構設計不夠通用這樣的問題,倘若真的是架構不夠通用,那麼就很有可能不見得是重構可以解決。因為倘若在系統發展完成某個階段後,才發現需要更通用的架構,單是從既有的架構著手重構,要修正的幅度可能很大,不見得可行。這時候,砍掉重練似乎就成了比較合理的選項。但是,有很多時候,需要一個「更通用的架構」的需求,其實並沒有被確切的檢驗。有時,只是一種「過度工程化(over-engineering)」的心理因素做祟。某些時候,我們還沒有面臨到的確需要一個更通用的架構,提前動手重新打造反而不理想了。

至於「技術更新狂熱者」總是喜歡在自己開發的系統運用所有新技術,更是浪費生產力的想法。一來新技術不夠成熟,運用時所遭遇到的問題,也許你是全世界第一個碰到的,沒有人能夠幫忙,耗去的時間恐怕更多。二來,新技術不代表就是符合需求的技術,任何一種技術只要能符合需求,就是可以用的技術。新的技術一定有瞄準它想要解決的問題,但是舊的技術大多數時候一樣能夠滿足現有的需求。純粹只是基於昇級或嚐鮮的想法而砍掉重練,實在是對生產力的一大傷害,最後獲得的好處又常常微乎其微。

最後,如果你的系統中有太多隱藏在深處的臭蟲未爆彈,但是又缺乏耐心或時間一一的把它們找出來,衡量得失厲害,還是需要在適當的時間點(例如產品的大改版或重大的里程碑),把重要的元件砍掉重練。砍掉重練並非完全不行,只是因為它會犧牲掉生產力,所以只有在我們所犧牲的生產力和時間評估起來划算時,我們才這麼做。否則,盡量利用重構技巧來導正你的系統,會是比較合理的態度。

Blogged with Flock

迴響:

如果程式架構不大, 砍掉重練其實並不會花費很多時間.

我目前將砍掉重練這件事定位成.
1. 中等程式員晉級資深程式員的作業
2. Code Review
3. 加強原先架構中不足的部份.

很多 Code 其實是會從原來的 Code 搬過來的, 只是籍由砍掉重練, 重新檢視一下原來的程式而己 :)

由...發表 richliu on 二月 27, 2008 at 12:30 上午 CST #

大部分的內容同意。但是還是有不同意的部份。

那種非得要砍掉重練得部份絕對是存在的。尤其是在兩種不同結構的程式語言間轉換得時候。

最有名的例子,就是從ASP轉換到ASP.net。雖然ASP的程式碼可以在.net的環境之下運作,可是要維護ASP的code跟.net的code實在是令人感到一件痛苦的事情,尤其是銜接工作會隨著新增需求的增加而越來越龐大,最後到了不可收拾的地步。

長痛不如短痛,有時候我是抱持著這樣的想法的。

由...發表 Derek Hsu on 二月 27, 2008 at 07:05 下午 CST #

@Derek Hsu
我想我沒有排除需要砍掉重練的情況, 很多情況重做反而更理想. 關鍵仍舊在於做什麼事之前都要去評估划得來划不來. 程式員的天性多半傾向重做, 不論是不是確實需要重做, 因為大家都不想面對自己慘痛的過去和歷史的遺產 :)

由...發表 Qing on 二月 28, 2008 at 03:22 下午 CST #

發表迴響:
  • HTML 語法: 關閉
把對母乳媽媽的感謝與支持傳出去

« 三月 2010
星期日星期一星期二星期三星期四星期五星期六
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   
       
今日

Search this blog

Links

Weblog menu

Today's referrers

Feeds