|

- 觀察問題 : 第一章.劣質程式碼帶來的劣質體驗
- 瞭解問題 : 第二章.劣質程式碼是怎麼產生的
- 研究問題 : 第三章.自我表達的程式碼
- 解決問題 : 第四章 ~ 要慢慢的讀,慢慢的瞭解了
|
1. 劣質程式碼帶來的劣質體驗 |
1.1 程式碼的"可讀性問題" |
以下這些問題都會造成閱讀上的障礙及妨礙
- 命名類的問題
- 命名缺乏統一性
- 命名沒有考慮呼叫時的情形 : 例如 車.停車 car.parkingCar
- 語言命名 : 例如使用羅馬拚音命名
- 命名用詞不當 (應該是不瞭解英文所致)
- 超長的命名
- 命名含義模糊
- 命名和行為不一致
- 否定式命名 ***
- 無意義命名
- 序號式命名
- 工程名稱為類別名稱的首碼
- 超短命名
- 匈牙利命名法 : 例 strClassmateName
-
註解類的問題
- 每步皆註解 (乾脆用中文寫程式就好了)
- 錯誤的註解
- 修改歷史記錄註解 (有版本控管之後就不必要了)
- 長方法中的分段註解 (應該要致力於縮短方法......)
- 複製名稱的註解
- 複製說明文件的註解
- 缺少註解 (try cache 忽略 exception的處理時要說明, 不然....)
- 編輯器自動產生的註解 (產生的範本,但沒實際去調整及說明內容, 有產生跟沒產生是一樣的)
-
風格類的問題
- 長方法
- 長參數列表 (參數愈少愈好)
- 長判定語句 (if x1 && x2 && x3 && x4......
- 長分支
- 魔法數字 (這個我不太懂?? 是指在程式中重覆重某個數字, 而不把它用特定的常數來表達嗎?)
- 字串直接引用 (直接使用 carName == "AUDI" || carName == "裕隆")
- 冗餘的常數定義
- 意思不明的邏輯
- 變數意思不穩定 (應該是命名的問題吧!而且也不要一個變數用在不同意思的區塊上)
- 回傳值意思不穩定 (1-100 代表,...101代表...102代表...
- 無用的方法或變數
- 詭異程式碼 (b = (--c<<a>>3)*(a++)
- 結構類的問題
- do-whild 禁用引起的重複
- switch-case 引起的長分支
- 莫名其妙的 default (switch 的)
- 被忽略的 Exception (指try catch 沒處理)
- 全域變數做為回傳值 (那就不用回傳了不是嗎?)
- 不必要的 Guard 程式碼 (為了避免null或是其他狀況, 可以在建構式或工廠類別中建立時確保)
- 巢狀過深
- 輸出型參數 (所以建立少用輸出型參數)
- 冗餘的臨時變數
- 不合理的錯誤編號
- 架構類的問題
- 闗係混亂
- 類別的循環引用 (a用了b, 然後b也用了a)會有記憶體空耗而進一步的memory leak
- 錯誤的繼承
- 不當的從屬關係
- 大雜燴類別 (例如一個類別負責UI又資料處理又邏輯處理之類的)
- 重複與類似
- 層層深入的private方法 (表示原來的code太長, 需要提取出來變成更多的private方法.)
- 墨守成規
|
1.2 程式碼的可測試性問題 |
- 難以建構測試設備(環境)
- 難以拆分做單元測試
|
1.2 程式碼的可維護性問題 |
- 需求變更難以應對
- 粘滯 (牽一髮而動全身)
- 脆弱 (一旦修改就會破壞原有結構)
- 僵硬 (程式碼間總是互相牽制,導致難以入手)
- 糾纏不清的Bug
- 難以重現的Bug
- 難以定位的Bug
- 難以修改的Bug
|
|
2. 劣質程式碼是怎麼產生的 |
- 理論知識匱乏
- Copy、Paste
- 照流程圖來寫程式 (這個倒是沒經驗過)
- 臨時對策 (這會有技術債務)
- 定式思維
- 認為動作必須是方法 (也可以用介面來處理....)
- 認為狀態只能採用整數來定義 (範例也是使用介面來處理)
- 認為switch一定要有default
- 認為Listener必須寫成匿名類別
- 認為for必須有下標 (用for each)
- 對程式語言不熟悉
- 泛型
- Regular Express (正規表示式)
- List 排序
- 列舉型別
- toString
- clone()
- 對開發環境不熟悉
- 對設計方法不瞭解
- 程式設計的習慣不佳
- 缺少 "必要" 的註解
- 迷信 IDE 自動產生的程式碼
- 命名習慣不好
- 沒有管理好程式碼的職責
- ...
- 英語能力不足 (涉及精確及說故事的本領)
- 管理人員的誤導 (coding分組導致程式碼、編碼規範的老舊或不合時宜、時間壓力急促成事、限制開發人員不能怎樣怎樣...)
|
3. 自我表達的程式碼 |
這是本書的核心概念,就是你寫的程式碼要會表達、能說故事、精簡易懂 (有時牽涉到開發者的程度、所以不要過分 design) |
4. 理論知識的補充 |
物件導向的基礎知識 |
- 封裝 : 把物件的資料和行為封裝在一起,外部透過抽象的介面存取物件,進而達到隱藏物件細節的目的。
- 介面、抽象類別 : 介面沒有成員變數、介面只能有抽象方法。但抽象類別可以有建構子、具體實作的方法,介面則沒有。類別可以實作多個介面,但只能繼承一個抽象方法
- 繼承
- 多型
|
設計的基本原則 |
- 單一職責原則
- 開放封閉原則
- Liskovq替換原則
- 介面隔離原則:一個類別對另外一個類別的依賴,應該取決於最小介面,應該將不同職責的任務分成若干個小的介面,客戶端不應該依賴於它們用不到的方法。
- 依賴倒置原則:上層不應該依賴於下層,二者都該依賴於介面,抽象不依賴於實作,實作應該依賴於抽象。
- 德摩特爾法則:最小知識原則,即一個物件對另一個物件的內部瞭解得越少越好。A、B、C...類別A會呼叫B , 但類別A不要透過類別B來呼叫C的方法...
- 不要自我重複 (DRY)
|
圈複雜度 |
是就是要減少巢狀、廻圈......
|
|
5. 熟悉程式設計的環境 |
講的是關發環境的自動化功能,VS大部份都有預設值,只針對不熟的部份說明。
儲存動作與自動格式化 |
|
快速修復 |
|
重構 |
在不改變程式碼功能的前提下,透過調整程式碼的結構來提高程式碼的可讀性、可測試性和可擴展性的一種手法。
- 修改名稱 (變數、方法、類別......等)
- 提取方法 , 將長的程式碼選起來後,直接建立成另一段方法來達到程式碼的可讀性。
|
|
6. 程式語言的學習 |
- 註記 (屬性) [Attribute]
- 利用註記來簡化的驗證模型
- 利用註記來簡化的權限驗證模型
- 反射 (reflection)
- 例外 (exception)
- checked exception 跟 unchecked exception
- exception 可以繼承再改為自己所需要的
- 用 exception 代替錯誤碼 (也就是不要發生錯誤時回傳訊息, 應該發生錯誤時 throw exception , 正常時繼續走, 用try cache 包起來)
- DAL 層拋出 exception 時應該包起來為一個自訂訊息,直接丟給前端很難讓使用者理解。
- 不要 catch 基本的 Exception
- 多重 cache
- finally
- 泛型 ()
|
7. 設計方法的學習 |
- Design Patterns 設計模式 連結
- Dependency Injection 相依性注入 連結
- Map
- 採用位元遮罩來減少類別的個數 (位元遮罩的意思是將一個數字的每一位元都常作一個開關的旗標。尚把若干個位元放在一起時,能夠表現的狀態數就多達2的n次方。)
- List 處理 Z-Order
|
|
|
|
|
|
|