最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Clean Code 無瑕的程式碼 第17章 程式碼的氣味和啟發(fā)

2021-06-25 23:16 作者:tkchenhaha  | 我要投稿

?? ?第十七章作者用歸納法整理出一連串程式碼注意事項。

註解 (Comments)

C1:不適當?shù)馁Y訊 (InAppropriate Information)

註解應該寫程式碼相關的資訊。

不應該記錄要存放在別地方的資訊,例如歷史修改、修改日期。

C2:廢棄的註解 (Obsolete Comment)

程式會一直修改,會產(chǎn)生過時的廢棄註解。發(fā)現(xiàn)過時的廢棄註解要儘快移除,避免受到廢棄註解誤導。

C3:多餘的註解 (Redundant Comment)

直接看程式碼能夠表達的意圖,就可以不用再寫多餘的註解。

C4:寫得不好的註解 (Poorly Written Comment)

好的註解要正確簡潔有力。

C5:被註解掉的程式碼 (Commented-Out Code)

變成註解的程式碼可以直接刪除,因為有程式碼控管軟體。?

開發(fā)環(huán)境 (Environment)

E1:需要多個步驟以建立專案或系統(tǒng) (Build Requires More Than One Step)

一個指令就可以建立系統(tǒng)。

E2:需要多個步驟以進行測試 (Tests Require More Than One Step)

一個指令可完成一個測試。

函式 (Functions)

F1:過多的參數(shù) (Too Many Arguments)

函式的參數(shù)越少越好,儘量不要讓參數(shù)超過三個以上。

F2:輸出型參數(shù) (Output Arguments)

讀者預期參數(shù)是輸入,輸出型參數(shù)會影響可讀性,物件狀態(tài)可取代輸出型參數(shù)。

F3:旗標參數(shù) (Flag Arguments)

出現(xiàn)Boolean參數(shù)表示函式做了超過一件的任務。Boolean參數(shù)應該被移除。

F4:被遺棄的函式 (Dead Function)

不再被呼叫的函式應該被移除。

一般狀況 (General)

G1:同份原始檔存在多種語言 (Multiple Languages in One Source File)

儘量做到一個檔案只存在一種程式語言。

G2:明顯該有的行為未被實現(xiàn) (Obvious Behavior Is Unimplemented)

程式碼能夠達成原有的意圖,讀者不用查看底層的程式碼。

G3:在邊界上的不正確行為 (Incorrect Behavior at the Boundaries)

撰寫測試程式測試所有邊界條件,而不是依靠直覺。

G4:無視安全規(guī)範 (Overridden Safeties)

車諾比核災事件是人禍,電廠管理員無視安全規(guī)範。

有出現(xiàn)測試錯誤就要解決,不能假裝沒有出現(xiàn)。

G5:重複的程式碼 (Duplication)

出現(xiàn)重複的程式碼表示表示發(fā)生未進行抽象的情形。

由「為什麼 “abstraction”不應該譯為“抽象化”」談正名

這篇文章寫得好,abstraction不應該翻譯成為抽象化,萃取、提煉與歸納比較適合。

switch/case 與 if/else 在不同的模組一直出現(xiàn),應該用多型的方式來代替重複狀況。

設計模式模版方法(TEMPLATE METHOD)與策略模式(STRATEGY)可以取代重複的程式碼。

G6:在錯誤抽象層次上的程式碼 (Code at Wrong Level of Abstraction)

「高層次一般概念」與「低層次細節(jié)概念」是重要的工作。所有的低層次概念都放在衍生類別,所有的高層次概念都放在基底類別。

常數(shù)、變數(shù)或工具函式與細節(jié)有關,應該只出現(xiàn)在衍生類別。

範例程式碼:

public interface Stack{

????Object pop() throws EmptyyException;

????void push(Object o) throws FullException;

????double percentFull();

????………………….

}

?percentFull()處於不對的抽象層次,算是細節(jié), percentFull()最好放在衍生介面BoundedStack。

G7:基底類別相依於其衍生類別 (Base Classes Depending on Their Derivatives)

高層次基底類別,可以獨立於低層次衍生類別概念之外,基底類別不應該知道衍生類別的資訊。

有限狀態(tài)機的實作會出現(xiàn)例外,基底類別與衍生類別兩者強烈耦合,一起佈署至相同的jar檔案。

通常將基底類別與衍生類別佈署在不同的jar檔案,一次變動不用演變成為整體的變動。

G8:過多的資訊 (Too Much Information)

降低耦合度,模組介面越少越好,類別擁有的方法越少越好,一個函數(shù)知道的變數(shù)越少越好。

G9:被遺棄的程式碼 (Dead Code)

永遠不會被執(zhí)行的程式碼要立刻刪除。

G10:垂直分隔 (Vertical Separation)

變數(shù)和函式應該定義在靠近被使用的地方。

區(qū)域變數(shù)應該在第一次被使用的位置上方進行宣告。

私有函式應該在第一次被使用的位置下方進行定義。

G11:不一致性 (Inconsistency)

變數(shù)名稱、物件名稱與函數(shù)名稱要有一致性,讓程式碼容易閱讀修改。

G12:雜亂的程式 (Clutter)?

沒有用的建構函數(shù)、不會被使用的變數(shù)、不會被呼叫的函數(shù)、沒有意義的註解都應該被移除。

G13:人為的耦合 (Artifucial Coupling)

人為的耦合沒有直接目的的兩個模組之間加上了耦合。

不相依的程式不應該被人為耦合,例如enums不應該包含在特定類別,會強迫整個程式知道這些特定類別。

無特殊用途的static函式宣告在特定的類別,有可能會產(chǎn)生人為的耦合。

G14:特色留戀 (Feature Envy)

類別的方法應該只對同一個類別裡的變數(shù)和函數(shù)感興趣。?

public class HourlyPayCalculator{

????public Money calculateWeeklyPay(HourlyEmployee e){

????????int tenthRate = e.getTenthRate().getPennies();

????????……………..?????

????}

}

calculateWeeklyPay 方法操作的資料,從物件HourlyEmployee 取出,代表calculateWeeklyPay 方法希望自己就在HourlyEmployee 類別裡面。特色留戀會將類別內(nèi)部的資料,暴露給另一個類別。

有時候特色留戀是必要之惡,作者舉一個例子。?

reportHour方法留戀 HourlyEmployee 類別,但我們也不想讓HourlyEmployee 類別了解時間報告格式。將時間格式移入HourlyEmployee 類別,會出現(xiàn)耦合的情況。

G15:選擇型參數(shù) (Selector Arguments)

函數(shù)要避免使用boolean 型態(tài)、列舉、整數(shù)輸入?yún)?shù),可用來選擇函式行為的參數(shù)型態(tài)。

G16:模糊的意圖 (Obscured Intent)

跨行的表達式、匈牙利命名法、魔術數(shù)字都會模糊作者的意圖。

G17:錯置的職責 (Misplaced Responsibility)

程式碼應該放在讀者自然認為應該存在的地方。例如PI 常數(shù)應該放在三角函數(shù)被宣告的地方。

G18:不適當?shù)撵o態(tài)宣告 (InAppropriate Static)

Math.max(double a, double b) 適合靜態(tài)方法,因為不會改變。

HourlyPayCalculator.calculatePay(employee, overtimeRate) 不適合宣告為靜態(tài)方法,因為可能會用到多型。

G19:使用具解釋性的變數(shù) (Use Explanatory Variables)

命名有意義的暫存性變數(shù),可以增加程式的可讀性。

例如?

string key = match.group(1);

string value = match.group(2);

key 與 value 就容易讓讀者了解在做查詢的工作

G20:函數(shù)名稱要說到做到 (Function Names Should Say What They Do)

從函數(shù)名稱就要能夠看出函數(shù)要做什麼。

G21:瞭解演算法 (Understand the Algorithm)

瞭解演算法才能寫出正確的程式。

G22:讓邏輯相依變成實體相依 (Make Logical Dependencies Physical)?

只看字面上說明一定不懂,可看17-1 作者的範例說明。

private final int PGAE_SIZE = 55? 這行 PGAE_SIZE 產(chǎn)生邏輯相依。

HourlyReporter 類別不需要知道頁面大小??稍?HourlyReporterFormatter 類別裡建立 getMaxPageSize這個新方法,將邏輯相依轉為實體相依。

G23:用多型取代If/Else 或 Switch/Case (Prefer Polymorphism to If/Else or Switch/Case )

這段內(nèi)容要對照第六章看。

大部分人使用Switch/Case 式因為Switch/Case 比較簡單,不一定Switch/Case 真的適合這種情況,在使用Switch/Case 之前要先考慮多型的解法。

函式變化比型態(tài)變化更強烈的情況相對而言少很多。

選擇的型態(tài)不應該有超過一個以上的switch。 唯一的switch可建立多型物件來取代Switch敘述。

G24:遵循標準的慣例 (Follow Standard Conventions)

每個團隊理應遵循同一個程式碼開發(fā)標準規(guī)範。

G25:用有名稱的常數(shù)取代魔術數(shù)字 (Replace Magic Numbers with Named Constants)

用有名稱的常數(shù)增加程式的可讀性,魔術數(shù)字無法表達常數(shù)的意圖。

G26:要精確 (Be Precise)

作者講述程式注重的細節(jié),例如如果有傳null ,就要有檢查null的機制。如果有同步更新,就要有某種鎖定機制。

G27:結構勝於常規(guī) (Structure over Convention)

?「具有強制決策設計特性的結構」勝過「慣例」。例如有良好列舉命名的switch/case,不如有抽象方法的基底類別。

G28:封裝條件判斷 (Encapsulate Conditionals)

看範例可知函數(shù)提取可以增加程式的可讀性。

if(timer.hasExpired()&&!timer.isRecurrent()) 寫法較差

if(shouldBeDeleted(timer))? 寫法較佳

G29:避免否定的條件判斷 (Avoid Negative Conditionals)

盡可能使用肯定的條件判斷。

G30:函式應該只做一件事 (Functions Should Do One Thing)

函式應該只做一件事。

G31:隱藏時序耦合 (Hidden Temporal Couplings)

看範例可懂

第一個範例三個函數(shù)要依序執(zhí)行才能有正確的結果。

第二個範例讓三個函數(shù)傳參數(shù),來達成正確的時間順序。

G32:不要隨意 (Don’t Be Arbitrary)

這邊談到類別的視野範圍,類別要放對位置。

G33:封裝邊界條件 (Encapsulate Boundary Conditions)

看範例就懂,第一個範例原本邊界條件 level+1 出現(xiàn)了兩次,第二個範例改成改成 int nextLevel = level +1

G34:函式內(nèi)容應該下降抽象層次一層 ( Functions Should Descend Only One Level of Abstraction)

這段內(nèi)容要與第三章對照看,每個函數(shù)都有階層,實作的部分要放在最底層。

G35:可調(diào)整的資料應放置於高階層次 (Keep Configurable Date at High Levels)

預設值或設定值要放在高階函數(shù),當做參數(shù)傳下去。

G36:避免傳遞性導覽 (Avoid Transitive Navigation)

內(nèi)容就是迪米特法則,只與朋友說話,可參考第六章的內(nèi)容。

Java?

J1:利用萬用字元來避免冗長的引入列表 (Avoid Long Import Lists by Using Wildcards)

J2:不要繼承常數(shù) (Don’t Inherit Constants)

不要在介面中寫常數(shù)讓別的類別繼承?

public interface PayrollConstants{

????public static final int TENTHS_PER_WEEK = 400;

????………..

}

應該使用靜態(tài)的引入敘述來取代。

import static PayrollConstants.*

J3:常數(shù)和列舉 (Constants versus Enums)

用列舉的方式取代常數(shù)

命名 (Names)

N1:選擇具描述性質的名稱 (Choose Descriptive Names)

變數(shù)與函數(shù)要取有意義的名稱,避免出現(xiàn)魔術數(shù)字。

N2:在適當?shù)某橄髮哟芜x擇適當?shù)拿?(Choose Names at the Appropriate Level of Abstraction)

比較兩個範例,隨著時代進步。dial 改為 connect

N3:盡可能使用標準命名法 (Use Standard Nomenclature Where Possible)

使用已有的慣例或用法來進行命名,例如有使用裝飾者模式,就應該在裝飾者類別名稱使用Decorator。

團隊通常會發(fā)明自己的命名系統(tǒng)。

N4:非模稜兩可的名稱 (Unambiguous Names)

函數(shù)名稱要能夠正確表達做什麼事

N5:較大範圍的視野使用較長的名稱 (Use Long Names for Long Scopes)

區(qū)域變數(shù)可取短的名稱,視野範圍廣的變數(shù)如全域變數(shù)可以取較長的名稱。

N6:避免編碼 (Avoid Encodings)

名稱不應該出現(xiàn)型態(tài)或事也編碼,例如 m_或 f。作者反對使用匈牙利命名法。

N7:命名應該描述可能的程式副作用 (Names Should Describe Side_Effects)

函數(shù)做多少事要反應在函數(shù)名稱。

測試(Tests)

T1:不足夠的測試 (Insufficient Tests)

測試範圍要足夠夠廣

T2:使用涵蓋率工具 (Use a Coverage Tool!)

使用涵蓋率工具發(fā)現(xiàn)哪些程式未測試。

T3:不要跳過簡單的測試 (Don’t Skip Trivial Tests)

簡單測試容易寫,不可以跳過。

T4:被忽略的測試是對模稜兩可的疑問 (An Ignored Test Is a Question about an Ambiguity)

????????

T5:測試邊界條件 (Test Boundary Conditions)

演算法有可能一般狀況運行順利,在邊界條件會出現(xiàn)錯誤。

T6:在程式錯誤附近進行詳盡的測試 (Exhaustively test Near Bugs)

錯誤往往聚集,在錯誤附近的地區(qū)要進行詳盡測試。

T7:失敗的模式是某種啟示 (Patterns of Failure Are Revealing)

用測試失敗的現(xiàn)象找出程式出問題的地方。

T8:測試涵蓋率模式可以是一種啟示 (Test Coverage Patterns Can Be Revealing)

從測試涵蓋率哪些程式執(zhí)行過,哪些沒執(zhí)行過,找出測試失敗的原因。

T9:測試要夠快速 (Tests Should Be Fast)

測試程式要夠快速。

總結

提出一個Clean Code 價值體系。



Clean Code 無瑕的程式碼 第17章 程式碼的氣味和啟發(fā)的評論 (共 條)

分享到微博請遵守國家法律
宜宾县| 八宿县| 五莲县| 临清市| 美姑县| 前郭尔| 苗栗县| 沙河市| 天等县| 南部县| 葵青区| 错那县| 阳西县| 云梦县| 进贤县| 河西区| 延长县| 蒲江县| 额济纳旗| 南昌县| 铜川市| 淮南市| 同德县| 绵竹市| 宁城县| 龙南县| 正定县| 青州市| 永宁县| 页游| 满洲里市| 江永县| 阳春市| 禹州市| 罗定市| 贞丰县| 永定县| 额尔古纳市| 吐鲁番市| 茶陵县| 凤山市|