官术网_书友最值得收藏!

1.2 代碼質量目標

如果我們購買一輛轎車,質量或許是我們考慮的主要因素之一。我們希望這輛轎車:

安全;

能正常使用;

不出故障;

表現可以預測——當我們踩下制動器,車子應該慢下來。

如果我們問某人,是什么造就了一輛高質量的汽車?最可能得到的答案就是“精良的制造”。這意味著優秀的設計,在投產前進行安全性和可靠性測試,并正確組裝。軟件也大抵如此:要制作出高質量的軟件,就必須確保它“制造精良”。這就是代碼質量的全部含義。

“代碼質量”這個詞有時可能會讓人聯想到,對一些不重要的瑣事提出的近乎吹毛求疵的建議。毫無疑問,你時常會遇到這種建議,但它們并不是代碼質量的真正含義。代碼質量很大程度上出于對實際情況的考量,它有時與細節有關,有時又關乎大局,但目標都是一樣的:創造更好的軟件。

盡管如此,代碼質量仍然是我們很難確切定義的一個概念。有時候,我們看到某些代碼時可能會想“看起來很不舒服”,其他時候則可能偶然看到一段“看起來非常棒”的代碼。代碼為何引起這種反應,原因并不總是一目了然,有時候只是我們的本能反應,并沒有確切的理由。

定義代碼質量高低,本來就是主觀的,更多的是出于判斷。為了做出更客觀的評判,我個人認為有益的做法是后退一步,考慮一下編寫代碼時真正試圖實現的目標。在我看來,幫助我實現這些目標的代碼就是高質量的,而產生阻礙作用的代碼就是低質量的。

我在編寫代碼的時候要實現的4個高層目標如下:

代碼應該正常工作;

代碼應該持續正常工作;

代碼應該適應不斷變化的需求;

代碼不應該重復別人做過的工作。

后面的內容將更加詳細地介紹這4個目標。

1.2.1 代碼應該正常工作

這個目標顯而易見,或許不需要說明,但我無論如何都要做一番解釋。我們編寫代碼的目的是試圖解決某個問題,例如實現某個功能、修復缺陷或執行某項任務。代碼的主要目標是能夠正常工作——它應該解決我們打算讓它解決的問題。這意味著,代碼是沒有缺陷的,因為缺陷很可能阻止代碼正常工作和全面解決問題。

確定代碼“正常工作”的含義是,我們必須了解所有需求。例如,如果我們要解決的問題對性能(如延遲和CPU占用率)很敏感,確保代碼有合適的性能就應該歸入“正常工作”的范疇,因為這是需求的一部分。用戶隱私和安全性等其他重要考慮因素也適用這一原則。

1.2.2 代碼應該持續正常工作

代碼的工作可能非常短暫。今天,它可能正常工作,但我們如何確保明天或者一年之內它都能正常工作?這樣的擔心看起來好像莫名其妙,為什么代碼會突然停止工作?要點在于,代碼并不是與世隔絕的,如果我們不多加小心,它很容易因為周圍事物的變化而崩潰。

代碼很可能依賴于其他代碼,而這些代碼會被修改、更新和更換。

任何新功能需求都意味著要對代碼進行修改。

我們試圖解決的問題也可能隨時間的推移而發展:消費者的偏好、業務需求和技術考慮都可能變化。

如果代碼在今天能夠正常工作,明天卻因為上述因素變化而出現問題,那么它沒有太大的用處。創建當下可以正常工作的代碼往往很容易,但創建一直能正常工作的代碼就要難得多。確保代碼持續工作是軟件工程師面對的問題之一,也是在編程各階段都要考慮的問題。以事后諸葛亮的眼光去考慮它,或者認為只要以后增加一些測試就能實現這個目標,往往都不是很有效。

1.2.3 代碼應該適應不斷變化的需求

很少有只編寫一次、永遠不用再修改的代碼。一款軟件的持續開發可能跨越幾個月、幾年,甚至幾十年。在整個過程中,需求都在改變:

業務狀況變化;

消費者偏好變化;

設想失效;

新功能持續增加。

決定在代碼適應性上投入多少精力,可能是很難權衡的問題。一方面,我們深知軟件需求將隨時間推移而發展(極少看到反例)。另一方面,我們往往不能確定它們究竟會如何發展。對一段代碼或者一款軟件,幾乎不可能準確預測出它在以后的一段時間內將如何變化。然而,我們不能僅因為不能確定軟件如何發展,就完全忽視軟件會發展的事實。為了說明這一點,我們來考慮兩種極端的情況。

方案 A——我們試圖準確預測未來的需求可能會如何演變,并設計支持所有潛在變化的代碼。我們可能要花幾天或者幾周的時間來描繪出代碼和軟件所有可能的演變路徑。然后,我們必須小心翼翼地考慮縮寫代碼的每個細節,確保它支持所有未來可能出現的需求。這將嚴重拖慢我們的工作,本來3個月就可以完成的軟件,現在可能要花上一年甚至更長的時間。最終,這些時間也可能是浪費的,因為競爭對手將比我們提前幾個月進入市場,我們對未來的預測很可能完全是錯誤的。

方案 B——我們完全無視需求可能演變的事實。我們編寫恰好滿足現行需求的代碼,不在代碼適應性上做任何努力。軟件中到處都是不可靠的假設,各個子問題的解決方案都捆綁在一起,成為一大堆無法區分的代碼。我們在3個月內就投放了軟件的第一個版本,但初始用戶的反饋說明,如果我們想要取得成功,就必須改良其中的一些功能,并添加新功能。對需求的改變并不大,但因為我們編寫代碼時沒有考慮適應性,唯一的選擇就是扔掉全部代碼,從頭再來一遍。我們必須再花3個月重寫軟件,如果需求再次改變,此后還得再花3個月重寫。到我們完成滿足用戶需求的軟件時,競爭對手再一次打敗了我們。

方案A和方案B是兩個極端,兩者的結果都很不好,它們也都不是制作軟件的有效方法。相反,我們需要找到一種介于兩個極端的方法。從方案A到方案B的整個譜系中,哪里才是最優的并沒有唯一的答案,這取決于我們所開發的項目,以及我們所在單位的文化。

幸運的是,我們可以采用一些普適技術,在不確定未來變化的情況下確保代碼的適應性。本書將介紹許多此類技術。

1.2.4 代碼不應該重復別人做過的工作

在我們編寫代碼解決問題時,通常會將一個大問題分解為多個較小的子問題。例如,我們打算編寫加載圖像文件,將其轉換為灰階圖像,然后保存的代碼,那么需要解決的子問題如下:

從文件中加載一些數據;

將這些數據解析為某種圖像格式;

將圖像轉換為灰階圖像;

將圖像轉換為數據;

將數據存回文件。

這些問題中的許多已被其他人解決,例如,從文件中加載一些數據可能是由編程語言內置方法完成的。我們不用自己編寫與文件系統進行低層通信的代碼。同樣,我們也許可以從現有的庫中調用代碼,將數據解析為圖像。

如果我們自己編寫與文件系統進行低層通信的代碼,或者將一些數據解析為圖像,實際上就是在重復別人做過的工作。最好的方式是利用現有解決方案而不是重寫一遍。這樣做的理由有多個方面。

節約時間和精力——如果我們利用編程語言內置方法加載文件,可能只要幾行代碼、花費幾分鐘。相反,自己編寫代碼完成這一工作可能需要閱讀許多關于文件系統的標準文檔,編寫成千上萬行代碼。我們可能要幾天甚至幾周的時間才能完成這項工作。

降低出現程序缺陷的可能性——如果現有的代碼能解決指定問題,它應該已經全面測試過。這些代碼很有可能已在外界使用過,因此代碼包含缺陷的可能性已經降低,即使有缺陷,人們可能已經發現并修復過。

利用現有專業知識——維護圖像解析代碼的團隊很可能是由圖像編程專業人士組成的。如果JPEG編程技術出現了新版本,他們很可能對此十分了解,并更新相應的代碼。通過重用他們的代碼,我們就可以從他們的專業能力和未來的更新中獲益。

使代碼更容易理解——如果完成某項工作有標準化的方法,我們就有理由認為,其他工程師此前也知道這種方法。大部工程師可能在某個時間閱讀了一份文件,立刻意識到完成這項工作的(編程語言內置)方法,并理解這種方法的功能。如果我們編寫自定義邏輯來完成工作,其他工程師就不會熟悉,不能一下子就知道它的功能。

“不應該重復別人做過的工作”這一概念在兩個方向上都適用。如果其他工程師已編寫了解決某個子問題的代碼,那么我們應該調用這些代碼,而不是自己編寫代碼來解決。同樣,如果我們編寫了解決一個子問題的代碼,那么應該以某種方法構造代碼,以便其他工程師能輕松地重用它們,而無須重復工作。

由于同一類子問題往往反復出現,因此人們很快就會意識到在不同工程師和團隊之間共享代碼的好處。

主站蜘蛛池模板: 新津县| 甘肃省| 桃江县| 鹤峰县| 武川县| 遂宁市| 贡山| 乌兰浩特市| 衡东县| 巴林右旗| 商河县| 白玉县| 沙雅县| 门头沟区| 讷河市| 罗源县| 栖霞市| 东辽县| 甘肃省| 安仁县| 句容市| 鄯善县| 揭西县| 东海县| 综艺| 陈巴尔虎旗| 安达市| 莱州市| 浦江县| 泰兴市| 青铜峡市| 田林县| 揭阳市| 左贡县| 霍邱县| 黔西| 远安县| 五寨县| 梁平县| 山东| 缙云县|