程式碼可讀性是軟體開發中重要的一環,影響著開發效率、維護成本和團隊協作。良好的程式碼可讀性不僅能讓程式更容易理解,還能減少錯誤發生的機率。提升程式碼可讀性的方法有很多,包含程式碼格式、註解、命名規範、程式碼結構等。本文將探討如何透過這些技巧,讓程式碼更清晰、更易懂,並以實際案例說明如何應用這些技巧。程式碼格式方面,應保持一致的縮排、換行和空格使用,並善用多行表示式來避免程式碼過於冗長。清晰的命名規範也很重要,變數和函式名稱應該具有描述性,能夠清楚地表達其用途。此外,適當的註解可以幫助理解程式碼的邏輯和意圖,但過多的註解反而會增加閱讀負擔,因此需要權衡註解的數量和必要性。
自我說明程式碼的重要性
撰寫易於理解的程式碼是軟體開發中的重要環節。良好的程式碼不僅能提高開發效率,還能減少維護成本並提升團隊協作能力。
程式碼格式與可讀性
在撰寫程式碼時,適當的格式安排能大幅提升可讀性。以下列舉幾種常見的寫法:
多行表示式的處理
# Method 1
netSalary = jobIncome + hobbyIncome + stockDividends + (rents - utilities) - personalLivingExpenses - mortgagePayments - medicalExpenses
print(netSalary)
# Method 2
netSalary = (jobIncome +
hobbyIncome +
stockDividends +
(rents - utilities) -
personalLivingExpenses -
mortgagePayments -
medicalExpenses)
print(netSalary)
# Method 3
netSalary = (jobIncome
+ hobbyIncome
+ stockDividends
+ (rents - utilities)
- personalLivingExpenses
- mortgagePayments
- medicalExpenses)
print(netSalary)
內容解密:
- 多行表示式的優點:將長表示式拆分為多行可以提高可讀性,特別是在涉及多個運算元時。
- 運算元的位置:在程式碼中,通常在運算元前換行(Method 3),這樣可以清晰地看出接下來的運算。
- 一致性:選擇一種風格並在整個專案中保持一致,有助於團隊協作。
外部檔案的重要性
在程式碼頂部新增外部檔案,可以提供有關程式的重要資訊。以下是一個範例:
"""
+===============+=====-========*========-======+===========+
|| CIRCLE DETECTION ||
|| by M. Stueben (October 8, 2017) ||
|| Artificial Intelligence; Mr. Stueben, ||
|| Periods 1, 2, and 7 ||
|| ||
|| Description: This program detects a circle (radius ||
|| and center) in a 512x512 gray-scale ||
|| image of a circle and 500 random points ||
|| (aka snow, noise). ||
|| It then draws a new circle in red over the ||
|| initial circle. The circles almost match. ||
|| Algorithms: Gaussian smoothing, Sobel operator/filter, ||
|| Canny edge detection, and a vote accumulator- ||
|| matrix equal to the size of the image. ||
|| Downloads: None ||
|| Language: Python Ver. 3.3 ||
|| Graphics: Tkinter Graphics ||
+==========================================================+
"""
內容解密:
- 檔案結構:清晰的檔案結構有助於快速瞭解程式的功能和實作細節。
- 必要資訊:包含程式標題、作者、日期、課程資訊、使用的演算法和程式語言等。
- 註解規範:使用一致的註解風格,有助於提高程式碼的可讀性和維護性。
小型程式碼慣例
在日常程式設計中,一些小的慣例可以提高程式碼的可讀性。例如:
# 間距的使用
ANN = inputs, w, h, v # 無間距
ANN = inputs, w, h, v # 有間距
y = 2 * (x + y) # 推薦寫法
y = 2*(x + y) # 也可接受
# 三角形面積計算
def triangleArea(x1, y1, x2, y2, x3, y3): # vertices
return abs((x1-x3)*(y2-y3) - (x2-x3)*(y1-y3))/2
內容解密:
- 間距規範:適當的間距可以提高程式碼的可讀性,例如在運算元前後新增空格。
- 函式定義:函式引數之間的間距應保持一致。
- PEP 0008 指引:遵循 Python 的官方風格指引(PEP 0008),有助於撰寫規範化的程式碼。
多重陳述句的處理
在某些情況下,將多個陳述句放在同一行是可接受的,但須確保邏輯清晰。
# Method 1 (acceptable, but discouraged in Python)
a = 1; b = 2; c = 3; d = 4
# Method 2 (common in Python)
a, b, c, d = 1, 2, 3, 4
# Method 3 (bulky, but most readable)
a = 1
b = 2
c = 3
d = 4
內容解密:
- 不同寫法的比較:不同的寫法各有優缺點,需根據實際情況選擇最合適的方式。
- 可讀性優先:在保證程式正確性的前提下,應優先考慮可讀性。
清晰與意外的程式碼
有些程式碼雖然不符傳統寫法,但仍然清晰易懂。例如:
for x in dataSet:
if -10 <= x < 0: print('Case I'); continue
if 0 <= x < 10: print('Case II'); continue
if 10 <= x < 20: print('Case III'); continue
print(x)
內容解密:
- 垂直對齊:適當的垂直對齊可以提高程式碼的可讀性。
- 清單解析:雖然某些寫法可能被視為不規範,但只要清晰易懂,仍然是可接受的。
綜上所述,撰寫自我說明的程式碼需要綜合考慮格式、檔案、命名和邏輯結構等多個方面。遵循一致的程式設計規範和風格指引,可以有效提高程式碼的可讀性和維護性。
逐步精煉:提升程式碼可讀性的關鍵
在軟體開發的過程中,如何撰寫出易於理解和維護的程式碼一直是開發者關注的重點。Rudolf Flesch 在其著作《The Art of Readable Writing》中提到,只有故事才是真正可讀的。這句話對於程式設計同樣適用,因為好的程式碼應該像在講一個清晰的故事,讓讀者能夠輕鬆理解程式的功能和設計意圖。
自我描述的程式碼與逐步精煉
自我描述的程式碼(Self-Documenting Code)是一種能夠透過其結構和命名清晰地表達其功能和邏輯的程式碼。實作這種程式碼的一種有效方法是使用逐步精煉(Step-Wise Refinement),這是一種由頂向下的設計方法,也被稱為結構化程式設計。
逐步精煉的核心概念
主函式包含具有描述性的函式呼叫:主函式中包含一系列具有描述性的函式呼叫,例如
enterData()、computeData()和printData()。這些函式呼叫形成了一個大綱,概述了程式的主要步驟和功能。def main(): matrix = createSudoku() matrix = solveTheSudoku(matrix) printVerification(matrix) root.mainloop() # Required for Tk graphics.子函式進一步細化:每個被呼叫的函式可能進一步包含更多的子函式呼叫,這些子函式同樣具有描述性的名稱。這種層層遞進的結構使得程式的邏輯變得清晰,易於理解。
最終實作具體的電腦指令:雖然逐步精煉鼓勵使用抽象的函式呼叫來描述程式邏輯,但最終還是需要實作具體的電腦指令。這種方法的目標是透過選擇具有描述性的函式名稱,使得讀者能夠在不閱讀大量程式碼或註解的情況下理解程式的設計。
由頂向下與由底向上的設計
由頂向下的設計:這種方法從整體出發,將大問題分解為小問題,每一步都盡可能地清晰和簡單。它有助於保持程式碼的結構清晰,易於理解和維護。
由底向上的設計:這種方法則是從具體的實作細節開始,逐步構建出整個系統。它類別似於一種「流意識」的程式設計方式,適合於小型程式的開發。
無論採用哪種設計方法,重要的是讓程式碼能夠以由頂向下的方式被閱讀,這樣可以方便在不同層次上進行程式驗證,並且使審閱者(甚至是作者自己在未來某個時候)更容易理解程式。
例項分析
以下是一個實際的例子,展示瞭如何透過逐步精煉來改進 main 函式:
原始版本:
def main():
image = list(readPixelColorsFromImageFile(IMAGE_FILE_NAME='e:\\lena_rgb_p3.ppm'))
displayImageInWindow(image, False)
saveTheImageGrayScaleNumbersToFile(image, GRAY_SCALE_NUMBERS_FILE_NAME='e:\\grayScale.ppm')
image = extractTheImageGrayScaleNumbersFromFile(GRAY_SCALE_NUMBERS_FILE_NAME='e:\\grayScale.ppm')
displayImageInWindow(image, False)
image = smoothTheImage(image, NUMBER_OF_TIMES_TO_SMOOTH_IMAGE=4)
saveTheImageGrayScaleNumbersToFile(image, GRAY_SCALE_NUMBERS_FILE_NAME='e:\\smoothed.ppm')
# ... 其他操作
改進後的版本:
def main():
imageFileName = 'g:\\lena_rgb_p3.ppm'
grayScaleNumbersFileName = convertColorFileToGrayScaleFile(imageFileName)
smoothedFileName = extractSmoothAndSaveImage(grayScaleNumbersFileName)
# ... 繼續其他步驟
內容解密:
- 抽取主要步驟:改進後的
main函式透過呼叫具有描述性的函式(如convertColorFileToGrayScaleFile和extractSmoothAndSaveImage),使得整個處理流程一目瞭然。 - 簡化主函式邏輯:原始版本中的
main函式過於冗長,包含多個步驟的實作細節。改進後的版本將這些細節封裝到不同的函式中,使得main函式變得更加簡潔。 - 提高可讀性和可維護性:透過逐步精煉,程式碼變得更容易理解和維護。如果需要修改某個步驟的實作細節,可以直接定位到對應的函式進行修改,而不會影響到其他部分。
程式碼重構與註解的藝術
在軟體開發過程中,程式碼的可讀性和可維護性是至關重要的。良好的程式碼結構和適當的註解可以大大提高程式的可理解性,減少維護成本。本文將探討如何透過重構和註解來提升程式碼的品質。
增量式開發
增量式開發(Incremental Development)是一種軟體開發方法論,主張透過逐步迭代來完成專案。首先實作一個簡化的版本,接著在這個基礎上不斷新增功能,直到完成最終版本。這種方法的好處在於能夠持續獲得一個可執行的程式,從而減少專案後期的壓力和不確定性。
增量式開發的優點
- 能夠持續獲得一個可執行的程式,給予開發者信心和成就感。
- 減少專案後期的壓力和不確定性。
- 早期獲得使用者反饋,有助於改善程式的使用者和介面設計。
自我說明程式碼
自我說明程式碼(Self-documenting Code)是指透過程式碼本身就能清晰地表達其功能和邏輯,無需過多的註解。這種程式碼風格有助於減少註解的數量,使程式更簡潔易讀。
範例:檢查字串是否全為母音
def is_all_vowels(stng):
for ch in stng.lower():
if ch not in ['a', 'e', 'i', 'o', 'u']:
return False
return True
內容解密:
is_all_vowels函式檢查輸入字串stng是否全部由母音組成。- 將輸入字串轉換為小寫,以確保檢查不區分大小寫。
- 遍歷字串中的每個字元,如果發現非母音字元,立即傳回
False。 - 若遍歷完成後未發現非母音字元,則傳回
True。
註解的使用
雖然自我說明程式碼可以減少對註解的依賴,但在某些情況下,適當的註解仍然是必要的。註解可以用來解釋複雜的邏輯、提供背景資訊或標明程式碼的組織結構。
範例:輸出八皇后棋盤
def print_board(board): # Example: board = [3,5,7,2,0,6,4,1]
print("###################")
for col in board:
s = ['- '] * len(board) # build a list of strings with no 'Q '
s[col] = 'Q ' # insert 'Q 's in the correct places
print('# ' + ''.join(s) + "#") # make the list into one string.
print("###################")
內容解密:
print_board函式根據輸入的board清單輸出一個代表八皇后問題解法的棋盤。board清單中的每個元素代表皇后在對應列中的位置。- 使用迴圈遍歷
board,為每一列建立一個包含 ‘Q’ 和 ‘-’ 的字串,以表示皇后的位置和其他格子。 - 將建立好的字串輸出,形成棋盤的視覺表示。
撰寫有效的註解
有效的註解應該清晰、簡潔,並提供額外的資訊。註解不應該重複程式碼已經表達的內容,而應該用於解釋為什麼要這樣做,或提供額外的背景資訊。
原則
- 使用完整的句子撰寫註解,以提高可讀性。
- 將註解與相關程式碼放在一起,以便於理解。
- 使用註解來解釋複雜的邏輯或演算法。
- 提供範例以幫助理解函式或類別的使用方法。
停止編碼,理解後再繼續
在編寫程式碼時,遇到疑惑或不確定的情況,應立即停止編碼,待理解清楚後再繼續。這是因為編寫程式碼不僅是寫出能夠執行的程式碼,更重要的是寫出可維護、可理解的程式碼。
為什麼需要停止編碼?
當你開始感到困惑時,代表你可能對程式碼的某些部分尚未完全理解。這時繼續編碼可能會導致更多問題的堆積,使程式碼變得更加難以維護和除錯。
如何實踐停止編碼?
- 理解需求:在開始編碼前,確保你完全理解了需求和任務目標。
- 設計和規劃:花時間設計和規劃你的程式碼結構和邏輯。
- 逐步實作:將大任務分解為小任務,逐步實作和測試。
- 暫停和反思:遇到疑惑時,暫停編碼,反思和研究相關知識或尋求幫助。
例子:旅行商問題
在處理像旅行商問題(TSP)這樣複雜的問題時,正確的資料結構選擇至關重要。TSP的資料可以用一個包含xy座標的列表來表示。建議使用列表的列表,而不是元組的列表,並且在每個元素的起始位置新增一個id。例如:
city = [[id, x-value, y-value], [id, x-value, y-value], ..., [id, x-value, y-value]]
內容解密:
- 使用列表而非元組是因為列表是可變的,可以在後續過程中修改其內容。
- 新增id是為了可能在後續過程中給予每個xy座標某種屬性,如存取狀態等。
註解和檔案字串的重要性
雖然有人認為註解是多餘的,但適當的註解和檔案字串對於程式碼的可讀性和可維護性至關重要。特別是在處理複雜邏輯或遞迴函式時,註解可以幫助開發者理解程式碼的意圖。