![]() |
VOOZH | about |
一個系統的疊代開發可能持續運行5年至10年甚至是20年。相比之下,某行代碼甚至某個設計的生命周期則要短很多,只有幾個月或者幾天,甚至當你為了解決一個問題疊代測試不同方案時它們的生命周期只有幾分鐘。
一些代碼的確比其他代碼更重要
通過研究代碼隨時間發生的變化,Michael Feathers發現了代碼生命線。通常,每個系統都有許多一次寫成不再修改的代碼。但是,有一小部分代碼,包括最重要最有用的代碼,卻被經常被修改,重構或者重寫數次。
隨著對一個系統或者一類問題或者一個架構方案的深入了解,你應該能夠更加輕易的知道或者預測到哪些代碼會不停的變化哪些代碼不會,換句話說,就是哪些代碼比較重要哪些代碼不重要。
是否應該努力去寫完美代碼?
大家都知道,我們應該寫乾淨的代碼,保持代碼的一致性、易讀性,並且儘可能地簡單。
但是一些人走了極端,儘自己的最大努力,去寫儘可能優雅的、接近完美的代碼,痴迷於重構斟酌代碼的每一個細節。
但是,如果這些代碼不是一次寫成不再修改,反而是一直不斷的變化,那麼,努力去寫完美代碼或者努力進行完美的設計豈不是浪費時間?
「你不可能寫出完美的代碼。你難道為此倍受打擊麼?顯然不該。應該將它作為一個生活中的公理,去擁抱它,慶祝它,因為完美的代碼是不存在的。在計算機短暫的歷史中,沒有任何人曾經寫出過哪怕一段完美無缺的代碼。顯然,你也不太可能成為第一個寫出完美代碼的人。除非你接受這個事實,否則你會一直浪費時間和精力去追逐一個不能實現的夢想!」——Andrew Hunt《程式設計師修煉之道:從初級到高級》
只寫一次的代碼首要不是美觀和優雅,而是正確運行,而且易讀易懂,因為在系統的整個生命周期中,這些代碼雖然不再修改,但是可能需要閱讀很多次。不一定非要緊湊,乾淨即可。在這些代碼中,一定程度上的拷貝和粘貼等操作是可以接受的。這些代碼不需要反覆斟酌,除非你需要修改它,否則即使周圍代碼都在變,也不需要對這些代碼重構。對於這些代碼,沒必要花費過多額外的時間。
對於那些一直需要修改的代碼呢?苦苦思索代碼的風格和最優雅的方案是在浪費時間,因為,這些代碼可能在隨後的幾天或者幾周就會被修改甚至重寫。同樣地,每次修改都痴迷於代碼的重構,或者重構那些不需要修改的代碼試圖使其變得更好也是沒有必要的。代碼永遠都可以變得更好,但是這不應該是最重要的方面。
真正重要的是代碼是否實現了想要的功能?代碼是否正確運行?是否有用?是否高效?能否處理錯誤和損壞的數據而不會崩潰,至少也要安全的失效?調試是否方便?修改起來是否簡單且安全?這些不是美觀的組成部分,而是實際中衡量代碼是否正確的標準。
務實地進行編碼和重構
精益開發的核心思想是:不要把時間浪費到不重要的事情上。應該用這個原則指導我們如何編寫代碼,如何重構代碼,如何進行代碼審查以及如何進行代碼測試。
為了完成工作,只進行必要的代碼重構,Martin Fowler稱之為機會主義重構(或理解為清理,童子軍規則)和有預備的重構。這足以使代碼修改起來更加簡單和安全。如果你不是在修改代碼,代碼看起來是什麼樣子,真的無關緊要。
在代碼審查中只關注真正重要的部分,這些代碼是否正確?是否是防禦性的代碼?是否安全?你能否理解它的思路?修改起來是否安全?
不要糾結於代碼的風格(除非代碼風格誤導了你對代碼的理解),把格式化代碼的工作交給IDE。沒有必要去爭論這些代碼能否「更加面向對象」。只要它有道理,至於是使用這用模式還是別的模式,並不重要。同樣,至於你是否喜歡,也不重要,儘管你可以用更好的方式完成它,除非你是在教對平台或者語言不熟悉的新手,需要在代碼審查中完成監督工作。
測試用例的編寫很重要,需要覆蓋到主要的執行路徑和重要的異常情況。測試用例能夠用最少的工作量給你儘可能多的信息和信心,具體是採用大而全的測試還是小而精的測試則無關緊要。至於是在寫代碼之前寫測試用例還是在寫代碼之後寫測試用例也不重要,只要測試用例有效即可。
不僅僅是關於代碼
在軟體領域裡,建築師和工程師的概念從來都不適用,我們不是設計建造屹立數年或者數百年大橋或者摩天大樓,我們構建的是更加具有可塑性的、更加抽象的,同時生命周期也更加短暫的東西。軟體之所以稱為「軟體」,就是因為編寫代碼就是為了修改。
「經過五年的使用和修改,很多情況下,一個成功的軟體源碼和最初的樣子已經面目全非了,但是一個成功的建築經過五年,基本沒有任何變化。」——《可持續軟體開發》
我們應該將代碼視為工作的一個臨時假象:
有時在重要的事情面前,我們陷入了對代碼的迷戀。我們經常遭受這樣的誤解,在產出的產品中代碼是最有價值的東西,儘管它實際上是對一個問題的理解,或者是對設計的一種實現甚至是顧客的反饋。——Dan Grover《編碼與創造性破壞》
疊代開發教會我們不斷的嘗試和檢查嘗試的結果——是否解決了問題,如果沒有解決問題,如何去改進?我們正在構建的軟體是永遠做不完的。儘管設計和編碼是正確的,那也可能只是一時正確,一旦需求發生變化,就會被更加適合的設計和編碼替代。
我們需要寫好的代碼:易懂,能夠正確運行,有安全保障的代碼。我們需要對它進行重構和代碼審查,並且編寫有效的測試用例。但是要記住,其中的一些代碼或者全部代碼可能很快就被丟掉,或者再也不會被讀到甚至從來就不會被用到。我們需要意識到,我們的一部分工作可能要被浪費掉並且對此進行優化。只做哪些需要被完成的事情,不要浪費時間試圖去編寫完美代碼。