iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Software Development

程式淨化計畫:痛苦是重構的起源!系列 第 27

Clean Code - Chapter 2 Meaningful Names - Part 1

  • 分享至 

  • xImage
  •  

以下是讀完 Clean code 第二章節(part 1)的筆記:

Introduction

  • 從函數、變數、到部署檔案都是命名

Use Intention-Revealing Names(名副其實的英文)

  • 如果一個變數需要註解來解釋, 並不是[名副其實]
  • 比如時間相關的命名
int d; // elapsed time in days
  • 該命名有意義的
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
  • 以下是一段函數
public List<int[]> getThem()
{
	List<int[]> list1 = new ArrayList<int[]>();
	for (int[] x : theList)
			if (x[0] == 4)
				list1.add(x);
	return list1;
}

  • 在於這段程式碼的模糊度
    • theList是什麼類型的東西?
    • theList裡面的x[0]是什麼意思?
    • 數值4的意義?
    • 我如何使用返回的list?
  • 當以上這些問題的答案沒出現在程式碼中, 那就是它們該出現的.
  • 如果將上述程式碼, 改成掃雷遊戲的棋盤, 於是重新命名
public List<int[]> getFlaggedCells()
{
	List<int[]> flaggedCells = new ArrayList<int[]>();
	for (int[] cell : gameBoard)
		if (cell[STATUS_VALUE] == FLAGGED)
			flaggedCells.add(cell);
	return flaggedCells;
}
  • 這段已經改得很明確知道, 每個函數、變數意義, 遇到內部int[]的容器, 再包裝成一個Cell類別
public List<Cell> getFlaggedCells()
{
	List<Cell> flaggedCells = new ArrayList<Cell>();
	for (Cell cell : gameBoard)
		if (cell.isFlagged())
			flaggedCells.add(cell);
	return flaggedCells;
}

Avoid Disinformation

  • 比如別用跟OS平台相關的專有詞
  • 別用accountList來稱為一組帳號
    • 除非是真的List類型
  • List本身有特殊意思,所以容器不是List的話,會造成誤用
    • 作者建議, 即使是List類型, 也別在命名中寫出容器名稱
  • 建議改成accountGroup, bounchOfAccounts, accounts等

  • 另一個是區分模組行為,太相近的時候, 這種狀況要提防
    • XYZControllerForEfficientHandlingOfString
    • XYZControllerForEfficientStorageOfStrings

  • 命名要保持前後同樣概念, 前後不一就是誤導

  • 不要用i和O做命名, 容易和數字1與0誤導

Make Meaningful Distinctions

  • 比如同個scope內, 宣告class和kclass…
  • 另一種是數字序列的命名
public static void copyChars(char a1[], char a2[]) 
{
	for (int i = 0; i < a1.length; i++)
	{
		a2[i] = a1[i];
	}
}
  • 這程式碼難以看出意義, 改成source和destination比較好

  • 另一種稱為廢話(Noise words)
    • 比如有個Product類別, 然後又有ProductInfo與ProductData類別….
  • 認為a和the當前綴詞, 區分不一樣scope的變數是可以的
    • 比如同一個scope有apple, 又另一個theApple, 是不允許的
  • 別命名出在一個明顯範圍的廢話
    • 在class變數命名Variable
    • 在表格設計Table
    • NameString, 明顯Name就是字串還加上string
    • Customer和CustomerObject怎區分?
  • 以下誰知道該呼叫什麼函數?
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
  • 以下是無法區分的案例
    • moneyAmount vs money
    • customerInfo vs customer
    • accountData vs account
    • theMessage vs message

Use Pronounceable Names

  • 以下是自創複合字的讀音和較好的命名
    • generation date, year, month, day, hour, minute, and second…..
class DtaRcrd102 {
	private Date genymdhms;
	private Date modymdhms;
	private final String pszqint = "102";
	/* ... */
}

class Customer {
	private Date generationTimestamp;
	private Date modificationTimestamp;
	private final String recordId = "102";
	/* ... */
};

Use Searchable Names

  • 有些常數寫死在邏輯,不好搜索,而是要用有意義的命名來搜索
    • 如下方案例
for (int j=0; j<34; j++) 
{
	s += (t[j]*4)/5;
}

int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j=0; j < NUMBER_OF_TASKS; j++) 
{
	int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
	int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
	sum += realTaskWeeks;
}
  • 名稱的長短與scope大小成正比

Avoid Encodings

Hungarian Notation

  • 現在IDE很強, 用HN只會誤導讀者

Member Prefixes

  • 還在用m_開頭那種…
  • 仍是IDE都透過顏色改變就能分辨
public class Part {
	private String m_dsc; // The textual description
	void setName(String name) 
	{
		m_dsc = name;
	}
}

public class Part {
	String description;
	void setDescription(String description) 
	{
		this.description = description;
	}
}

Interfaces and Implementations

  • 比如IShapeFactory與ShapeFactory
    • 對作者來講, 不要有I開頭這種的廢話
  • 如果一定要區分編碼, 則對實作編碼
    • ShapeFactoryImp
    • CShapeFactory
  • 覺得這個是Java的關係, 實際上C#還是以I開頭做說明

上一篇
Clean Code - Chapter 12 Emergence(嶄露頭角)
下一篇
Clean Code - Chapter 2 Meaningful Names - Part 2
系列文
程式淨化計畫:痛苦是重構的起源!31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言