[Note] The Clean Coder

Category Tech

過了幾年又重新看過這本書才慢慢能感受到裡面說的
Uncle Bob 的書真的每個階段看都會有很不一樣的感覺
很值得買回來收 xD

Clean Coder

幾年前第一次看這本書的時候
寫程式大多只是交作業,頂多就跟其他的同學一起交大一點的作業或開發一些小專案
能不要被雷(或不要雷別人)就很不錯了
當時記錄下的摘要也就沒什麼內容([Book] Clean Coder
到了現在。加減算是做過稍微大一點的專案,也帶過一些小專案
重新看過這本書,就慢慢理解了一點 Uncle Bob 想說的

關於本書

  • 什麼是軟體專業人士?
  • 軟體專業人士如何行事?
  • 軟體專業人士如何處理衝突,「應對」緊湊的開發進度表?如何和不切實際的管理人員打交道?
  • 軟體專業人士何時應該說「不」?怎麼說?
  • 軟體專業人士如何「應對」壓力?

第一章:專業主義

擔當責任

  • 專業人士如果犯了錯,只好自己收拾殘局

    • 專業主義就代表著「擔當責任」
  • 你說的沒錯。軟體發展太複雜了,不可能沒什麼Bug。但很不幸,這個理由並不能為你開脫。人體太複雜了,不可能完全理解,但醫生仍誓言不傷害病人。如果他們不拿人體的複雜性做託辭,我們又怎麼能拿上述理由,開脫自已的責任呢?

    • 程式難免出現 bug ,但這不意味著你不用對他們負責;沒人能寫出完美的軟體,但這不代表你不用對不完美負責。
    • 每次 QA 找出問題時,或者更糟糕的是「用戶找出問題」時,你都該震驚羞愧,並決心以此為戒。

自動化測試

  • 寫一些隨時都能執行的「單元測試」,然後盡可能地多執行
  • 要測試多少程式碼呢? → 當然是全部!全部都要測!
  • 但有些程式碼不是很難測嗎?
    • 沒錯。但之所以難測,是因為設計時沒考慮如何測試
    • 唯一的解決辦法就是要設計「易於測試的程式碼」

結構

  • 想證明軟體易於修改,唯一的辦法就是「做些實際的修改」
    • 如果發現這些修改不如想像中簡單,就應該改進設計,讓後續的改變更簡單

職業道德

  • 你應該計畫每週的60小時中
    • 40小時給雇主
    • 20小時給自己 (大約每天 3 小時)
      • 不為雇主工作,為自己的職業發展工作

了解你的領域

  • 每個專業軟體發展人員至少必須精通的事項
    • Design patterns
      • GOF
      • POSA
    • Design principles
      • SOLID
    • Methods
      • XP
      • Scrum
      • Lean
      • Kanban
      • Waterflow
      • 結構化分析
      • 結構化設計
      • and etc.
    • Disciplines
      • TDD
      • 物件導向設計
      • 結構化程式設計
      • CI
      • Pair Programming
    • Artifacts
      • UML
      • DFD (Data Flow Diagram)
      • 結構圖
      • Petri net
      • 狀態遷移圖表
      • 流程圖
      • 決策表

學習

  • 自我學習
    • 讀書, 關注 blog, tweets, 參加 conference, 訪問用戶群, 參與讀書會 and etc.
  • 協作
  • 輔導
    • 專業人士會「視輔導新人為己任」,他們不會放任未經輔導的新手胡打亂撞

了解業務領域

  • 如果撰寫財務系統,你就該對財務領域有所了解
    • 你未必要成為該領域的專家,但你仍需要勤勉,付出相當的努力來認識業務領域。
  • 最不專業的做法是,只簡單地按照規格說明來撰寫程式碼,但卻對於那些業務為什麼需要做那樣的規格定義不求甚解。相反的,你應該對該領域有所瞭解,能辨別、執行規格說明書的錯誤

第二章:説「不」

Do or do not ! There is no try!
—— Yoda

  • 專業人士敢於說明真相而不屈從於權勢。專業人士有勇氣對他們的經理說「不」。
    • 難道不該照你老闆說的去做嗎?
      • 不該。只要你是一名專業人士,那就不該
      • 奴隸沒有權利說「不」。勞工或許也對說「不」有所顧慮。但是專業人士應該懂得說「不」
  • 你的經理要求你在明天之前完成登入頁面,這就是他在追求和捍衛的一個目標,那是他的工作職責。如果你明知第二天之前不可能完成登入頁面,嘴上卻說「好的,我會試試看」,那麼便是你失職了。這時候,唯一盡責的方式便是說「不,這不可能」
    • 可能得最好結果是你和你的經理共同追求的目標。最關鍵的是要找到那個「共同目標」,而這往往有賴於「協商」。
  • 「為什麼」重要嗎?
    • 如果你的主管恰好有「技術背景」和「好脾氣」去傾聽理解,這些解釋也許有用
    • 另一種狀況是,主管會不認同這樣的結論或做法不對,可能會說出不用做完整的測試和程式碼審核
      • 有時候,提供太多細節,只會變成一個口令一個動作的管理方式。

第三章:説「是」

  • 作出承諾包含三步驟
    1. 口頭上說自己將會去做
    2. 心裡認真對待自己所做出的能諾
    3. 真的付諸行動去做

識別「缺乏承諾」的徵兆

  • need / should
    • 我們需要把這工作做完
    • 我需要減肥
    • 有人應當負責去推動這件事
  • hope / wish
    • 希望明天我能完成這個任務
    • 希望改天我們能見宴嗎
    • 但願我有時間做這件事
    • 但願電腦更快點
  • Let's (而不是「讓我」)
    • 讓我們回頭見
    • 讓我們把這工作做完

真正的承諾聽起來是怎樣的

  • 我將在...之前...
    • e.g., 我將在星期二之前完成這個任務
    • 你對自己會做某件事做了清晰的事實陳述,而且還明確說明了完成期限
  • 之所以沒成功,是因為我寄望於某某人去做這件事
    • 你只能承諾自己能完全掌控的事
    • 如果最終目標依賴於他人,那麼你就應該採取些具體行動以接近最終目標
  • 之所以沒成功,是因為有些時候我真的無能為力
    • 如果你無法兌現承諾,那麼最重要的就是「儘早向你承諾對象發聲預警,越快越好,越早越好」。
    • 如果你不儘早告訴他人可能的問題,就錯失了讓他們幫你兌現能諾的機會。

第四章:寫程式

做好準備

寫程式是件累人的事,你必須做到

  1. 讓程式碼能正常工作。理解當前要解決的問題和如何解決,並且確保程式碼忠實的依循解決方案
  2. 幫客戶解決問題
    • 很多時候,客戶提出的需求其實並不能真正解決他們自己的問題。這有賴於你去發現這些問題並與客戶交流,以確保能滿足客戶的真實需求
  3. 程式碼必須和現有系統整合,並妥善管理好各種相依關係,不能讓系統僵化
    • 寫程式時必須遵循穩工程原則
  4. 其他的程式設計師必須能讀懂你的程式碼

    • 這包括寫好註解、精心淬煉程式碼,這可能是程式設計師最難精通的一項。
  5. 感到疲勞或心煩意亂,千萬別寫程式

    • 奉獻精神和職業素養更主要的意義在於「遵守紀律原則」而非成為「長時間的工作狂」
    • 要確保自己已經幾睡眠、健康和生活方式調整到最佳狀態,這樣才能做到每天的8小時工作時間內全力以赴

創意輸入

  • 「創意輸出」依賴於「創意出入」 → 廣泛閱讀

保持節奏、知道何時應該離開一會

  • 軟體開發是一場馬拉松,不是短跑衝刺
  • 沒解決這個問題不能回家
    • 噢不,你可以回家,而且是應該回家!
    • 創意和智力來自於大腦的高速運轉,當你感到疲勞時,它們就不翼而飛了

進度延遲

  • 即使是最優秀的程式設計師、最敬業的員工,也不能避免碰到延遲
    • 管理延遲的要訣就是早期檢測和保持透明
    • 根據目標定期衡量進度,使用三個考慮到各種因素的期限,不要把預估和期望混淆在一起
      • 樂觀預估, 常態預估, 悲觀預估
  • 不要經受不住誘惑盲目衝刺
    • 你無法更快的寫完程式碼。試圖這麼做,最終只會讓自己變得更慢,同時也只能製造出一堆混亂,讓其他人也慢下來

交付失敗

  • 程式設計師所能表現的不專業中,最糟糕的就是,明知道還沒有完成任務卻宣稱已經完成
  • 明確定義「完成」
    • 最好的方法是讓業務分析師和測試人員建立一套自動化的驗收測試,只有完全通過這些驗收測試,開發任務才能算已經完成

幫助

  • 作為專業人士,你要以能隨時幫助別人為榮
    • 你的工作不可能重要到你不能花一丁點時間來幫助別人
    • 這並不是說你不需要獨處的時間 → 直接、禮貌的讓人知道某個時間區段不希望受到干擾,其餘的時段敞開大門樂於幫助他人
  • 要學會如何請求幫助
  • 輔導
    • 花時間親自輔導手底下的年輕程式設計師,是資深程式設計師的「專業職責所在」
    • 同樣的道理,向資深導師尋求輔導,也是年輕程式設計師的「專業職責」

第五章:測試驅動開發

TDD 的三大法則

  1. 在撰寫一個單元測試(測試失敗的單元測試)前,不可撰寫任何產品程式
  2. 只撰寫剛好無法通過的單元測試,不能編譯也算無法通過
  3. 只撰寫剛好能通過當前測試失敗的產品程式

TDD 的優勢

  1. 確定性
  2. 缺陷注入率
  3. 勇氣
    • 擁有一套值得信賴的測試,便可完全打消對修改程式碼的全部恐懼。當看見糟糕的程式碼時,就可以放手整理
  4. 文件
    • 單元測試就是文件。他們描述了系統的最底層設計細節
  5. 設計
    • 基於測試先行的需要,會迫使你去思考什麼才是好的設計
    • 與採用測試先行方式編寫的測試程式碼比起來,後寫的測試在深度和捕捉錯誤的靈敏度方面要遜色很多

第六章:練習

自身經驗的拓展

  • 老闆通常只會限定一種語言、一種平台,以及程式設計師工作目標的專業領域。這樣會導致經驗不夠豐富的程式設計師,其領域和思維都被侷限
    • 程式設計師發現,面對這個行業的週期性變化造成的新局面,自己並沒有做好準備
  • 保持不落伍的一種方法是為 open source project 貢獻程式碼
    • 嘗試對自己不習慣的語言、平台、領域做出貢獻

第七章:驗收測試

  • 定義驗收測試
    • 「業務方與開發方合作編寫的測試」,其目的在於確認需求已經完成了
  • 「完成」意味著
    1. 所有程式碼都寫完了
    2. 所有的測試都通過了
    3. QA 和需求方已經認可

測試的協商與被動推進

身為專業開發人員,「與撰寫測試的人協商並改進測試」是你的職責。絕不能被動接受測試,更不能對自己說:「噢,測試就是這麼要求的,我又得這麼做。」

層級 對象
單元測試 系統內部 呼叫特定類別方法
驗收測試 系統外部 通常在 API 或 UI 層級進行

結論

細節交流是件麻煩事。尤其開發方和業務方交流關於程式的細節時,更是如此。通常,各方握手言歡,以為其他人都明白自己的意思。雙方以為取得了共識,然後帶著截然不同的想法離開,這種事屢見不顯。
要解決開發方和業務方的溝通問題,我 (Uncle Bob) 所知道的唯一有效辦法是「編寫自動化的驗收測試」。

第八章:測試策略

職位 測試面向
業務人員 正常路徑測試 (happy-pathtest)
QA 包含極端狀況 (corner)、邊界條件 (boundary)的異常路徑測試(unhappy-path)

自動化測試金字塔

測試 覆蓋率 測試介面
人工探索式測試 ~5%
系統測試 ~10% gui
整合測試 ~20% api
元件測試 ~50% api
單元測試 ~100%
  • 單元測試
    • 目的: 在最低層次上定義系統
      • 先寫測試,在寫程式碼
      • 這些應該作為 CI 的一部分執行,以確保程式設計師的程式碼意圖沒有遭到破壞
  • 元件測試
    • 需要使用合適的 mocking 或 test-doubling,解開「系統和其他元件」的耦合
    • 由 QA 和業務人員編寫,開發人員提供輔助
  • 整合測試
    • 目的: 確認系統架構層面結構正確
    • 只對元件很多的較大型系統才具有意義
    • 由系統架構師或 lead designers 來編寫
  • 系統測試
    • 針對「整個整合完畢的系統」來執行的自動化測試
    • 不會直接測試業務規則,而是測試系統是否以正確組裝完畢
    • 應包含產能測試和性能測試
    • 由系統架構師和 technical leads 來編寫
  • 人工探索式測試
    • 目的: 驗證預期行為時,探索系統預期以外的行為

第九章:時間管理

會議

關於會議,有兩條真理

  1. 會議是必須的
  2. 會議浪費了大量的時間

離席

  • 仔細管理自己的時間是你的責任。如果你發現參加某個會議是在浪費時間,就應當想個禮貌的辦法出來
    • 顯然,你不該大喊「這會議真讓人厭煩」,沒有必要採取粗魯的辦法。可以選個適當時機來問問大家,你的出席是否必要。你可以解釋說,自己抽不出更多的時間用於這場會議,問問有沒有辦法加快討論,或者另選時間
    • 繼續參加對你沒有太多意義的會議,是不專業的行為

爭論 / 反對

  • 如果觀點無法在短時間(5 ~ 30 分鐘)內達成一致,就永遠無法達成一致
    • 唯一的解決方法是「去取得資料,讓資料來說話」
  • 「既然其他人想要這樣做,就這麼做吧」這可能是非專業的行為中最糟糕的了,千萬千萬不要這麼做
    • 如果你同意了,就必須拿出行動來

專注力 Manna

  • 專注力是稀有的資源
    • 如果你用光了自己的專注力 Manna,必須花一個小時或更多時間做不需要專注力的事情來補充它
  • 專業開發人員會安排好他們的睡眠,保證清晨有飽滿的專注力 Manna 去上班
  • 肌肉專注力有助於改善新制專注力,而不僅僅是簡單恢復
    • 定期訓練肌肉專注力,可以提升心智專注力的上限

要避免的行為

  • 優先順序錯亂
    • 無論什麼原因,我們都可以找到辦法逃避真正的工作。提高某項任務的優先順序,之後就有藉口延後真正急迫的任務
    • 專業開發人員會評估每項任務的優先順序,排除個人的喜好和需求,按照真實的緊急程度來執行任務

死胡同

  • 專業開發人員不會執著於不容放棄也無法繞開的 idea。他們會保持開放的頭腦來聽取其他建議,所以即便走到盡頭,他們仍然有選擇

第10章:預估

  • 承諾 v.s. 預估
    • 承諾是必須做到的
    • 預估是一種「猜測」,不帶任何承諾的色彩。之所以要預估,是因為不知道要花多少時間

PERT (Program Evaluation and Review Technique)

  • 三元分析法
    • O: Optimistic Estimate
      • 一切都很順利的完成時間
    • N: Nominal Estimate
      • 一般來說的完成時間
    • P: Pessimistic Estimate
      • 遇到各種意外地完成時間
    • $ \mu = \frac{O+4N+P}{6} $
      • 任務期望完成的時間
    • $ \sigma = \frac{P-O}{6} $
      • 任務完成機率分布的標準差

大數法則

  • 把大任務分成許多小任務,分開預估再加總,結果會比單獨評估大任務要精確得多

第11章:壓力

避免壓力

承諾

  • 避免對「沒有把握達成最後期限的工作」做出「承諾」
    • 業務方總是期望能夠拿到這些承諾,因為他們想消除風險。我們要做的就是日風險量會,必將他們陳述給業務方,這樣他們就能做好相對的準備。
  • 有時,有人會代我們做出承諾
    • 出於責任感,我們必須主動協助找到方法來兌現這些承諾,但是一定不能接受這些承諾

危機中的紀律

  • 如果在危機中你改變了行為,就說明你並不是真的相信常規行為中的紀律
    • 如果在平時你會注意程式碼整潔,但在危機時刻,你卻會產出髒亂的程式碼,就說明你並不真正相信混亂會導致速度下降

應對壓力

  • 不要驚慌失措
  • 溝通
    • 讓你的團隊或主管知道你身陷困境。告訴他們你為走出困境置地的最佳計畫。請求他們的支援與指引。避免製造意料之外的詫異
  • 依靠你的紀律原則
    • 依靠那些你已經知道確實有效的東西 - 你平時遵守的紀律
  • 尋求幫助
    • Pair Programming

第12章:協作

  • 專業程式設計師的主要職責是滿足雇主的需求
    • 這意味著要含你的經理們、業務分析師們、測試工程師們和其他團隊成員有良好的協作,並且深刻理解業務項目
    • 你需要理解「手上正在撰寫的程式碼,其業務價值是什麼」,了解雇用你的企業將如何從你的工作中獲得回報
  • 「需要長時間努力思考一個問題」、「任務極為簡單、和另一個人一起工作變成一種浪費」時單獨工作是正確的
    • 但一般來說和其他人緊密協作、大部分時間採取 Pair Programming 是最好的作法
  • 程式設計意味著「與人協作」
    • 我們需要和業務人員一起工作,我們之間也需要互相合作

第13章:團隊與專案

  • 形成有凝聚力的團隊是需要時間的
    • 可能需要6個月,甚至是1年
    • 團隊成員首先要建立關係。他們需要學習如何互相協作,需要瞭解彼此的癖好、強項、弱項,最終才能凝聚成團隊
  • 有凝聚力的團隊通常有12名成員,多可以有20人,最少可以只有3人
    • e.g., 12名
      • 7名程式設計師
      • 2名測試人員: 編寫「自動化測試」確認程式正確性
      • 2名分析師: 開發「需求」,為需求編寫「自動化測試」確認業務價值正確
      • 1名專案經理: 跟蹤團隊的「進度」,確保成員理解「專案時間表」和「優先順序」
  • 團隊比專案更難建置
    • 組織穩健的團隊,讓團隊在一個又一個專案中整體移動、共同工作是較好的做法
    • 團隊有了凝聚力,但卻因為專案結束了便將這樣的團隊解散,是極為荒謬可笑的做法

第14章:輔導、學徒期與工藝典範

  • 學校能夠傳授的是電腦程式設計的理論
    • 但學校並不會、也無法傳授作為一名程式設計工匠所需要掌握的原則、實踐和技能
      • 這些東西只有經由師徒個體間多年的細心監督和輔導才能獲得

Appendix A: 工具

  • Source code control
    • e.g., git
  • IDE / Editor
    • e.g., vi, emacs, IntelliJ, TextMate
  • 問題追蹤
    • e.g., Pivotal Tracker, Lighthouse, wiki, Board (To-Do/ Doing/ Done)
  • CI
    • e.g., Jenkins
  • 單元測試工具
    1. 快速便捷的執行測試
    2. 在通過或失敗要有清楚的視覺提示
    3. 對於測試進度也要有清楚的視覺提示
    4. 避免 test cases 之間的彼此通訊
    5. 讓編寫測試變得容易
  • 元件測試工具
    • 理想的情況是「業務分析師和QA」能夠使用這些工具來編寫規約
    • e.g, FitNesse, RobotFX, Cucumber
  • 整合測試工具
    • e.g., Selenium, Watir
  • UML / MDA