天天看點

為什麼保持代碼整潔如此重要?

對于代碼整潔,沒有唯一的或者嚴格的定義,而且可能無法正式地衡量怎樣才算代碼整潔,是以你不能在代碼倉庫上運作一個可以告訴你代碼是好是壞、可維護性如何的工具。當然,你可以運作檢查器、代碼校驗器、靜态分析器等工具。這些工具會給你很大的幫助。它們是必需的,但光有這些還遠遠不夠。代碼整潔與否不是機器或腳本能說了算的(到目前為止),而是作為專業人員的我們才能決定的。

為什麼保持代碼整潔如此重要?

幾十年來,我們沿用“程式設計語言”這個術語,并将其視為把我們的想法傳達給計算機的語言,可以讓計算機運作我們的程式。但是我們錯了,這僅僅是部分事實。程式設計語言背後的“真正語言”是将我們的想法傳達給其他開發人員的語言。

這才是代碼整潔的真正本質所在。它取決于其他開發人員是否能夠讀取和維護代碼。作為專業人士,我們是唯一能夠判斷這一點的人。想想看,作為開發人員,我們閱讀代碼的時間比實際編寫代碼的時間要多得多。每當我們想要更改或添加新功能,首先必須閱讀需要修改或擴充的代碼的所有上下文内容。程式設計語言(Python)就是開發人員實作互相溝通的語言。

為什麼保持代碼整潔如此重要,原因有很多。大多數原因與可維護性、減少技術債務、有效配合靈活開發以及管理一個成功的項目的想法有關。

我們想探讨的第一個想法是關于靈活開發和持續傳遞的。如果希望項目能夠以穩定和可預測的速度不斷成功地傳遞特性,那麼必須有一個良好且可維護的代碼庫。

假設你正駕駛着一輛汽車行駛在去往某個目的地的道路上,而且想要在某個時間點之前到達那裡。你必須預估自己到達目的地的時間,這樣才能告知正在等你的人。如果汽車不出故障,道路十分平坦,那麼你的預估不大可能有太大的偏差;相反,如果道路被破壞,你必須下車把石頭移開,或者要避開裂縫,抑或每隔幾千米就必須停下來檢查一下發動機等,那麼你不太可能确定什麼時候到達(或者你是否能到達)。這個比喻明确易懂,這裡的道路可以了解為代碼。如果希望以穩定、恒定和可預測的速度向前推進項目,那麼代碼應該是可維護和可讀的。

技術債務是指因妥協或所做出的不良決策而導緻的軟體問題。在某種程度上,我們可以從兩個方面考慮技術債務問題。一是從過去到現在,如果我們目前面臨的問題是由之前編寫的錯誤代碼造成的,那會怎樣?二是從現在到将來,如果我們決定現在就走捷徑,而不是花時間去尋找合适的解決方案,那麼未來又會為自己帶來什麼麻煩?

“債務”這個詞用得恰如其分。這是一筆債務,因為在未來代碼将比現在更難以修改。産生的成本就是債務的利息。産生的技術債務意味着,明天修改代碼比今天更困難,成本更高,而且後天的成本會更昂貴,等等。

一旦團隊不能按時傳遞一些東西,并且不得不停下來去修複和重構代碼,代碼就要付出技術債務的代價。

技術債務最糟糕的一點是它代表了一個長期和根本的問題。這不是什麼值得高度警覺的東西。相反,這是一個悄無聲息的問題,這個問題分散在整個項目的各個部分,在某一天,在某一個特定的時間,這個問題會“醒來”,并成為項目推進的阻礙。

1 代碼格式化在代碼整潔中的作用

代碼整潔是指根據一些标準(例如,PEP-8或由項目規範定義的自定義标準)進行的代碼格式化和結構化嗎?并非如此。

代碼整潔遠遠不止編碼标準、格式化、美化工具和其他有關代碼布局的檢查這些内容。代碼整潔是關于實作高品質的軟體和建立一個健壯、可維護和避免技術債務的系統的。一段代碼或整個軟體元件可以百分之百符合PEP-8(或任何其他準則)标準,但仍可能無法滿足上述要求。

然而,不注意代碼的結構會有一些危險。鑒于此,我們先來分析不良代碼結構的問題以及如何解決這些問題,然後介紹如何為Python項目配置和使用工具,以便自動檢查和糾正問題。

綜上所述,我們可以說代碼整潔與PEP-8或編碼風格沒有任何關系。代碼整潔的意義遠不止于此,除了可維護性和軟體的品質,它還意味着更有意義的東西。不過,正如你将看到的,要實作高效工作,正确地格式化代碼非常重要。

2 在項目中遵循編碼風格準則

編碼準則是項目在品質标準下開發時必須考慮的最低要求。在本節中,我們将探讨其背後的原因。接下來我們開始探讨如何通過工具自動在項目中遵循編碼風格準則。

在試圖考慮在代碼布局中找到某種好的特性時,我們首先想到的就是一緻性。我們希望代碼能夠具有一緻的結構,以便更易閱讀和了解。如果代碼不正确或者結構不一緻,并且團隊中的每個人都以自己的方式做事,那麼最終得到的将是需要額外努力和集中精力才能正确了解的代碼。這樣的代碼很容易引起誤解,并且由此引發的漏洞或微小的錯誤很可能被忽略。

上述情況是我們想要避免的。我們想要的是一眼就能讀懂和了解的代碼。

如果開發團隊的成員都同意采用标準化的方式編寫代碼,那麼所得到的代碼看起來會更加熟悉。這樣,你就能快速識别模式,并且記住這些模式,進而能更容易地了解内容和檢測錯誤。例如,當某些代碼出錯時,你可能會在你熟悉的模式中看到一些奇怪的東西——它們會吸引你的注意,再仔細觀察,就很可能發現錯誤!

正如經典著作Code Complete中所述的,在名為Perception in Chess(1973年)的論文中對此進行了有趣的分析,該論文提到了一項實驗,以确定不同的人如何了解或記憶不同的棋局。該實驗針對不同級别的棋手(新手、中級棋手和象棋高手)以及棋盤上不同位置的棋局來進行統計。他們發現,當棋子的位置是随機的時候,新手能和象棋高手表現得一樣好。因為這隻是一個記憶練習,任何人都可以發揮出合理的水準。但當棋子的位置遵循一個可能發生在一場真正對弈中的一些邏輯順序(或者,遵守某種一緻性,堅持某種模式時)時,那麼象棋高手們的表現比其他人要好得多了。

現在我們想象一下,同樣的情況也适用于軟體開發。作為Python方面的軟體工程師專家,我們就好比上述例子中的象棋高手。如果代碼的結構是随機的,沒有遵循任何邏輯或者沒有遵循任何标準,我們就會像一個新手開發人員一樣,很難發現錯誤;如果我們習慣以結構化的方式閱讀代碼,并且通過遵循這種模式學會從代碼中快速獲得想法,就會在項目開發中比其他開發人員更有優勢。

就Python而言,你應該遵循的編碼風格是PEP-8。你可以對其進行擴充或采用其中的一部分,以适應正在參與的項目的某種特殊性(如行的長度、字元串的注釋等)。不過,我們建議,無論你使用最原始版本的PEP-8規範還是對它進行擴充,都應該堅持使用,而不是從頭開始嘗試另一個不同的标準。

這是因為PEP-8充分考慮了Python文法的許多特殊性(通常不适用于其他語言),并且它是由對Python文法做出貢獻的核心Python開發人員建立的。是以,我們認為其他标準其實很難與PEP-8相提并論,更不用說超越它了。

尤其是,在處理代碼時,PEP-8還有一些不錯的改進特性。

(1)可進行grep。這就是在代碼中對内容進行grep的能力,即在某些檔案(以及這些檔案的某個部分)中搜尋所要查找的特定字元串。PEP-8引入的特性之一是區分将值指派寫入變量的方式和傳遞給函數的關鍵字參數的方式。

為了更好地了解這一點,我們用一個示例加以闡釋。假設我們正在進行調試,需要找到名為location的參數值的傳遞位置。我們可以運作以下grep指令,獲悉要查找内容所在的檔案和行号。

$ grep -nr "location=" .
./core.py:13: location=current_location,      

現在,我們想知道這個變量在哪裡被配置設定這個值,則可以運作以下指令。

$ grep -nr "location =" .
./core.py:10: current_location = get_location()      

PEP-8建立了這樣一種約定,即當通過關鍵字向函數傳遞參數時,不使用空格,但在配置設定變量時使用空格。是以,我們可以調整搜尋條件(第一次搜尋時等号兩側沒有空格,第二次搜尋時等号兩側都有一個空格),進而提高搜尋效率。這是遵守約定的好處之一。

(2)一緻性。如果代碼看起來有一種統一的格式,閱讀起來就會容易得多。這對于新加入項目的人來說尤為重要,如果你希望有新的開發人員加入項目,或者為團隊聘用新的(可能經驗不足的)程式員,那麼他們勢必要熟悉代碼(甚至可能由多個代碼倉庫組成)。如果代碼格式、文檔、命名約定等在所有代碼倉庫的所有檔案中都是相同的,那麼他們的工作将變得更加輕松。

(3)代碼品質。以結構化的方式檢視代碼,你一下子就能更熟練地了解它(就像在Perception in Chess中所說的那樣),并且更容易發現程式的漏洞和錯誤。除此之外,檢查代碼品質的工具也會提示潛在的錯誤。對代碼的靜态分析可能有助于降低每行代碼的錯誤率。

為什麼保持代碼整潔如此重要?

這是一本關于Python軟體工程原理方面的書。

關于軟體工程的書有很多,關于Python的可用資源也有很多,但要将這兩者結合起來,還有許多工作要做。本書正是嘗試在這二者之間架起一座橋梁。

要想在一本書中涵蓋關于軟體工程的所有主題是不現實的,因為軟體工程的領域十分廣泛,而且針對某個特定的主題會有專門的圖書去介紹。本書重點介紹Python軟體工程的主要實踐和原則,旨在幫助讀者編寫更易于維護的代碼,同時教讀者利用Python的特性來編寫代碼。

章節提要

第1章 簡介、代碼格式和工具,介紹搭建Python開發環境所需的主要工具、Python開發人員在開始使用該語言時需要了解的基本知識,以及維護項目中代碼可讀性的一些指導原則,如用于靜态分析、文檔、類型檢查和代碼格式化的工具。

第2章 Python風格代碼,介紹Python中的第一個習慣用法——我們在後續章節中将繼續使用它。本章還會介紹一些Python的獨有特性,以及如何使用它們,并且開始圍繞“Python風格代碼如何能夠讓代碼品質更高”展開論述。

第3章 好代碼的一般特征,回顧軟體工程的一般原則,以期幫助讀者編寫可維護的代碼。本章就這個話題展開讨論,并利用Python語言中的工具應用這些原則。

第4章 SOLID原則,介紹面向對象軟體設計的SOLID原則。SOLID是軟體工程領域的行業術語,即SRP、OCP、LSP、ISP和DIP。本章會展示這5項原則在Python中的應用。可以說,鑒于Python語言的性質,并非所有方法都完全适用。

第5章 用裝飾器改進代碼,介紹Python的最大特性之一——裝飾器。在了解如何建立裝飾器(用于函數和類)之後,我們将其用于代碼重用、責任分離和建立更細粒度的函數。

第6章 用描述符從對象中擷取更多資訊,探讨Python中的描述符,它把面向對象設計提升到了一個新的層次。盡管這更多隻是一個與架構和工具相關的特性,但我們可以看到如何用描述符提高代碼的可讀性,以及如何重用代碼。

第7章 使用生成器,說明生成器可能是Python的最佳特性。事實上,疊代是Python的核心元件,這讓我們認為它引申出了一種新的程式設計範式。一般來說,通過使用生成器和疊代器,我們可以考慮編寫程式的方式。基于從生成器中吸取的知識,我們将進一步了解Python中的協同程式以及異步程式設計的基本知識。

第8章 單元測試和重構,讨論單元測試在任何所謂“可維護的代碼庫”中的重要性。本章回顧了單元測試的重要性,并探究了單元測試的主要架構(unittest和pytest)。