Nutcracker

Nutcracker

《程序員修煉之道》閱讀筆記

《程序員修煉之道》#

Type: Life, Tools
author: David Thomas. Andrew Hunt

這本書的上一版《從小工到專家》其實我就早有耳聞了,但是當時覺得這個翻譯的名字很糟糕,且周圍並沒有人去推薦它,我就打消了看它的念頭。然後再今年閒暇下來發現這本書的再版,書籍的名稱也變為了《程序員修煉之道》,抱著看閒書和京東打折的契機,把它買了下來。看完兩章發現自己兩年前錯失了一部能快速獲得經驗,提高生產力的書籍。書有可前淺嘗者、有可吞食者,少數需咀嚼消化,這本書我認為就屬於需要咀嚼消化的那種書,幫助你提取一些之前成功項目的原因,也可以讓你思考生活與工作遇到同一類問題的處理方式。

務實的方法#

人生是你的#

我活著不是為了滿足你的期望,正如你不是因為我的期望而活著
—— 李小龍

軟體開發在任何職業列表中,都絕對是你自己最能掌控的職業之一。我們的技能供不應求,我們的知識不限於地域,我們可以遠程工作。我們收入頗豐。我們真的可以做到我們任何想做的事。但是總有一些原因導致開發者們拒絕改變,他們蜷縮在那裡,期盼事情會自己變好,眼睜睜地看著自己的技能過時,再去抱怨世界日新月異,工作環境糟糕。

雖然看起來作者有種何不食肉糜的感覺,但其實在現如今的行業劃分裡,軟體開發確實是最能自己掌握的職業之一。互聯網上基本上有你所需要的所有資料,而且即使你只會一種程式語言,今年你可以做金融,明年就可以無縫做購物,後年可以跑去做車載,你的職業經驗仍然大部分適用。職業環境並不會對你的事業有很大的限制,能限制的只有你自己。

我的源碼被貓吃了#

如果你面臨供應商幫不上忙這樣的風險,就應該制定一個應急方案。如果磁碟掛起 —— 你所有的源碼都在裡面,這就是你的錯。跟你的老闆說 “我的源碼都被貓吃了” 解決不了問題

團隊信任#

你的團隊需要你能信賴和依賴你 —— 你也應該同樣地放心依賴他們每個人

  • 不必直接掌控事情的各個方面
  • 表達你的思想,說出你的想法。締造一個以信任為基礎的健康環境

承擔責任#

在承接需求或任務前,你必須分析超出你控制範圍的風險情況,如果責任的倫理內涵過於含糊,或是面對無法實現的情況,亦或是風險過大,你都有權不承擔責任。在這個階段就及時把問題拋出,重新評估任務的可行性或是明確風險情況的責任人

在決定對一個結果承擔責任時,要明白你將承接相關的義務。當你犯了錯誤,或是做出了錯誤的判斷,誠實地承認它,並嘗試給出選擇

給出選擇,而非藉口 給出選擇並非要求你一定像上文例子裡一樣,做事都有 plan B,即使在世界末日都能從兜裡掏一台時空穿梭器。而是你跑過去告訴他們壞消息前,最好能解釋下做些什麼才能挽回局面。隊友和領導都很樂於與這種人公事,他們在這種場景下能以更低的成本去參與到新問題和新需求的處理中

軟體的熵#

雖然軟體開發不受絕大多數物理法則的約束,但我們無法躲避來自熵增加的重擊。是一個物理學術語,它定義了一個系統的 “無序” 總量。不幸的是,熱力學法則決定了宇宙中的熵會趨向最大化。而軟體開發因為各種 Bug 的修復,需求的新增和補充,軟體的複雜度和無序化也在逐步增加,本小節主要是探討如何避免軟體的熵的增加

  • “破窗效應”—— 制定了規則就要需要嚴格遵守,例如 Code Review、Code Lint 軟體架構等,這些規則都是為了保持軟體的可讀性以及降低程式的複雜性,既然制定了就要好好遵守,而非流於表面。窗戶一旦開始破裂,運轉良好的系統會迅速惡化。
  • “領頭羊效應”—— 在必要的時候,主動承擔責任,做推動變革的催化劑。
  • “溫水煮青蛙”—— 留意大局,持續不斷地審視你身邊發生的事情,不要只專注你個人在做的事情。即使你只負責部分的事務,也需要對宏觀上能影響你的事件保持敏銳。

做夠好即可的軟體#

為了追求更好,我們毀損了原已夠好的
—— 莎士比亞《李爾王》

現實世界不會讓我們生產出真正完美的產品,尤其是沒有 Bug 的軟體。時間、技術、急躁合力對抗著我們。對軟體開發者來說要明白以下幾點

  • 將質量視為需求問題 —— 對於你創建的系統,其應用領域和要達到的質量,必須作為系統需求的一部分加以討論
  • 讓用戶參與權衡 —— 無視用戶的需求,一味的堆砌功能,一次次打磨程式,這是不專業的表現。你可能會承諾一個無法兌現的時間尺度,然後為了趕上截止日期,再回過頭去刪減工程。
  • 知道何時止步 —— 不要讓過度地修飾和精煉侵蝕掉一個完好的程式。繼續前行,讓程式在它該有的位置駐留一段時間。它或許不完美,不要緊的 —— 它就算不完美也沒關係(這部分程式既不影響性能,也不影響功能,你可能永遠都不需要再改動它了)

知識組合#

投資知識,收益最佳
—— 本傑明・富蘭克林

知識和經驗的確是你最重要的專業資產,可惜的是,它們是一種時效性資產。隨著新技術的出現,以及語言和環境的發展,你的知識會變得過時。 不斷變化的市場力量可能會使得經驗變得陳舊而無關緊要。鑑於技術社會變化的速度越來越快,這種事情可能會發生得特別迅速。當你的知識價值下降時,你對公司的價值也在下降。想要阻止這一切的發生,學習新事物的能力是你重要的戰略資產。

管理知識組合和管理金融投資組合非常的類似:

  1. 正規投資有定期投資的習慣
    及時更新自己的專業視野,了解新的工具和技能,閱讀相關的新聞和技術貼。
  2. 多樣化是長線成功的關鍵
    擴展自己的技能領域,熟悉的技能越多,越能適應變化
  3. 聰明的投資者會平衡保守型和高風險回報投資的組合
    及時了解新的行業動向,並嘗試接觸與學習,不要去當聽眾,主動參與。
  4. 投資者用低買高賣來獲得最大的回報
    例如前些年的大數據、前端開發,又如現在的低代碼以及車聯網。它們在這時會有相較於平常較高的溢價,如果你有足夠的能力和儲備,那麼你可以在工作回報上有較高的提升,但需要明確的是,在藍海回歸紅海後,也可能有較大的風險。需要你有應對風險的能力
  5. 定期審查和重新平衡投資組合
    根據當前的行業趨勢,去重新審視自己的技術樹,調整自己學習的優先級

學習的機會#

  • 提前把一些資料準備在觸手可及的地方,在有興趣的時候能夠及時拿到
  • 把找到答案當做一個個人挑戰,去嘗試用各種方法更新自己的知識組合

批判性思維#

批判性思考讀到的和聽到的東西。你需要確保組合中的知識是精準的,未受到創作者的影響。

批判性思維是一門完整的學科,這裡起個頭:

  • 問 “五個為什麼”—— 在得到答案後繼續為什麼,來更接近本源。在日常溝通中要注意技巧,防止認為是挑釁而被揍
  • 誰從中受益 —— 雖然聽起來比較世俗,不過這樣更容易理清脈絡
  • 有什麼背景 —— 每件事都發生在它自己的背景下,這也是為何 “能解決所有問題” 的方案通常不存在,而那些兜售 “最佳實踐” 的書或文章經不起推敲(好吐槽)

交流#

我認為被人從頭打量到腳總比被人視而不見的好
—— 《九十歲的美女》

只是擁有是不夠的,還要看你如何包裝它。即使擁有最好的想法、漂亮的程式、最務實的思想,如果不能和他人交流,最終都無法孕育出果實。

把你的母語當做一門程式語言,像寫程式一樣用自然語言寫文章,尊重 DRY 原則,ETC、自動化等等(後續會提到)。

  • 了解聽眾 —— 根據聽眾不同,選擇用不同的方式和風格描述你要介紹的系統
  • 明白自己想說什麼 —— 寫好大綱,提煉核心
  • 選擇時機
  • 讓聽眾參與 —— 讓聽眾參與,把會議變成一場談話,你可以更有效地表達你自己的觀點,還可以聽取他們的反饋,汲取他們的智慧。

務實的方法#

有一些技巧和方法適用於軟體開發的所有層級,其中蘊含的思想幾乎成了公理,實施過程中也非常通用。然而,這些方法很少被規範成文檔。現在,這些想法和過程集中在這裡。形成了 DRY、ETC 等原則,以及原型和便簽等方法論

ETC (Easier To Change)#

能適應使用者的就是好的設計。對程式而言,就是要順應變化(讓程式更容易閱讀、解耦、單一職責、可替換)ETC(更容易變更)是一種價值觀念,而不是一條規則;當你在軟體領域思考時,ETC 是個向導,它能幫助你在不同路線中選出一條

在你有能力辨別時,常識通常都不會錯,有事如果你找不到線索,你可以做以下的事情

  1. 假設不確定什麼形式的改變會發生,那麼就回到問題的可能產生的源頭 —— 讓你寫的東西可替換。這樣無論將來發生了什麼,這塊程式都不會稱為障礙。
  2. 把它當做培養直覺的一種方式。在工程日記中留下你面臨的處境:你有哪些選擇,以及改變的一些猜測。以便以後必須修改這塊程式時,方便回顧。在遇到類似的分叉口時,這會有所幫助。

DRY (Dot Replay You)#

知識並不穩定,知識會改變 —— 通常頻率還很高。可能只要和客戶開個會,對需求的理解馬上就變了。政府改了條規定,一些邏輯就過時了。當我們進行維護時,必須找到變更事物的表達 —— 那些嵌入程式的知識膠囊。問題是,在規範、流程、開發的程式中複製知識太容易了,一旦我們動手這麼做,就會招致維護的噩夢。想要可靠地開發軟體,或讓開發項目變得更容易理解和維護,唯一的方法是遵循 DRY 原則 —— 在一個系統中,每一處知識都必須單一、明確、權威的表達

DRY 指的不要重複自己,所以它並不是但指的 “不要複製粘貼底程式”,這的確是 DRY 的組成部分,但這是很小的部分,一點都不重要。

DRY 針對的是你對知識和意圖的複製,它強調的是,如果兩個地方表達的東西其實相同的,只是表達方式不同,那麼它也違反了 DRY 原則。同理,如果兩個地方的表達方式完全相同,但他們在不同模組中承擔不同的職責,那麼他們並不違反 DRY 原則。

Code Lab#

  • 統一訪問原則 ——《面向對象軟體構造》中描述:一個模組提供的服務都應該通過統一的約定來提供,該約定不應該表露出其實現是基於儲存還是基於運算。
  • 你努力的方向,應該是孕育出一個更容易找到和重用已有事物的環境,而不是自己重新編寫。若果重用不容易,人們就不會這麼做。如果你未能重用,就有重複知識的風險

正交性#

“正交性” 是從幾何學中借用來的術語。若兩條直線相交後構成直角,它們就是正交。

線段 AB 與 CD 彼此正交

在計算科學中,這個術語象徵著獨立性和解耦性。良好的架構系統中,兩個模組之間應該相互獨立,其中一個模組的修改不應該影響另一個模組。正交的系統可以提高生產力和降低風險,更好地應對不斷變化的業務和需求。

如何保持系統的正交性:

  • 保持程式解耦、避免全局數據、避免相似的函數
  • 養成不斷質疑程式的習慣。有機會就重新組織、改善其結構性和正交性
  • 基於正交性設計和實現的系統更容易測試。因此編寫單元測試本身就是一個有趣的正交性測試。做什麼才能讓單元測試構建並運行起來?如果需要導入系統其餘的大部分程式碼,那麼恭喜你就發現一個與系統其餘部分沒有很好解耦的模組
  • 記錄並評估和問題的修復方案和範圍,對已經修復的問題歸檔和記錄,在閱讀報告中去分析每個 Bug 修復的所影響的模組和檔案數量趨勢。以此來發覺系統中不穩定的模組,或是設計的不正交的模組。

可逆性#

  • 保持靈活的架構
  • 放棄追逐時尚

曳光彈#

曳光彈能夠快速抵達目標,槍手可以得到及時反饋 —— 如果曳光彈集中了目標,那麼之後的常規子彈也會被擊中。

同樣地原則也適用於做項目。特別是在要構建一些從做過的東西時,我們可以進行曳光彈式的開發

優勢#

  • 能夠構造一個在其中工作的框架(Core)
  • 能對進度有更好的感覺,通過對這些案例的更重,度量性能和向用戶展示進度要容易得多
  • 更小的試錯成本,你可以將核心部分快速同用戶溝通展示,確認是否是他們想要的。以更快的速度,更小的成本收集到程式的反饋,並生成一個更準確的版本。

方法論#

  • 在需求評審和開發階段,尋找需要的核心部分,那些定義了系統的部分,有重大風險的地方。然後對這部分排列優先級,優先從這裡處理。
  • 注意曳光彈的場景是快速構建一個完整系統的雛形,並非是製作原型

與原型的區別#

原型製作生成的是一次性程式碼,曳光彈雖然簡單,但它是完整的,是最終框架的組成部分。原型是用來驗證方案的可行性,而曳光彈是用來驗證系統的可行性。

原型製作#

原型製作是為了學習經驗。它的價值不在於產生的程式碼,而在於吸取的教訓。這正是原型的意義所在

原型製作比完整的產品製作要便宜得多。因此我們可以通過製作原型來分析和暴露風險,以一種大幅降低成本的方式獲得修正的機會。原型被設計出來,只是為了回答問題的答案,因此可以忽略很多不重要的細節。但如果你發現自己處在於一個不能放棄細節的環境中,那麼可能曳光彈式開發更適合你。

當你製作原型時,哪些細節可以忽略:

  • 正確性 —— 你可以在適當的時候替代掉數據
  • 完整性 —— 原型只需要滿足優先的功能
  • 健壯性 —— 錯誤和邊界條件並不是必須的,你只需要驗證特定的航線
  • 格式 —— 並不需要太多的註釋和文檔

製作原型時,儘量推遲思考細節,你要確定的是,系統的各個部分是怎麼結合形成一個整體的。

領域語言#

語言之界限,即是一個人世界之界限
—— 路德維希・維特根斯坦

計算機語言會影響你怎樣思考問題,影響你怎樣看待信息的傳播。每一門語言都有一個特性列表 —— 靜態類型、動態類型、mixin、函數式還是面向對象 —— 所有這些對問題的解決方案,既可能是提供建議也可能擾亂視聽。在一些案例中,高階的程序員能跨越到下一個層級,不是用詞彙表來編寫程式,而直接用該領域的語言編程,直接使用該領域的詞彙、語法和語義(DSL)

對於傳統的語言,例如 Java 這種,我們可能使用外部語言例如 XML 或者 JSON 需要編寫額外的解析器,但是向現代語言例如 Kotlin 這種,它們對於 DSL 的支持是極為優秀的。我們可以通過現有的詞彙表來輕鬆擴展出 DSL 語言來。

從另一個角度思考,ChatGPT 以及 Copilot 的興起和趨勢。將編寫業務程式的大部分工作交由 AI 來完成會提高我們的工作效率,理想情況下我們只需要提供邊界完善和剪枝的操作。但是如何將業務需求轉換為語言模型能夠明確理解的文字,這也同樣考驗著我們通過母語的編程能力,可以較為清晰地通過母語將需求與環境描述清楚,語言模型才能根據我們需要生成所需要的程式碼。我們在以後的需求場景可能要鍛煉我們通過母語來編寫偽程式碼的能力,以此來應對日新月異的 AI 發展,和提高自己的工作效率

估算#

在接收到一個問題或是需求時,我們通過對估算,可以快速判斷該事件的可行性。而估算的前提是 ——對問題建模。當我們理解問題或是需求時,就開始為之建立一個粗略的思維框架模型。在建模的過程中,你可以發現一些表面上看不出來的潛在模式和過程。在得到模型後,就可以將其分解成組件,你需要發掘出這些組件如何交互的數學規則。

如何估算項目進度#

  • RERT(Program Evaluation Review Technique)每個 PERT 任務都有一個樂觀的、一個可能的和一個悲觀的估算,像這種帶著範圍值的估算,他能避免最常見的估算錯誤因素。
  • 增量開發:將任務分為不同階段,在每次迭代後,提煉其中的經驗,完善對進度的控制。

問題建模也是之後讓 AI 編程的核心方法論,只有通過建模的形式,我們才可以將需求或問題清晰表達,以及將各個節點拆分成組件,再將這些組件的模型在未實現實際程式碼時就明確的劃分其職責和功能

基礎工具#

純文本#

作為程序員,我們基礎材料不是木頭或鐵塊,而是知識。我們把需求以知識的形式收集起來,然後在設計、實現出、測試和文檔中表達這些知識。純文本,則是我們認為是將知識持久地存儲下來的最佳格式。

所謂的純文本並不是但只是指 txt 格式的檔案,而是可以任何可以被人類直接閱讀,編輯器可以直接解析的文本數據。純文本的優勢是

  • 防備老化的保險 —— 如今的很多知識軟體的使用和更新都依賴於網路和維護,當存儲數據的應用程式生命週期結束後,如果它不支持導出純文本數據,那麼你在應用程式中存儲的知識想要重新使用起來就極為困難了。
  • 易於檢索 —— 使用純文本記錄,我們可以無縫地使用版本管理來管理修改記錄,通過 Shell 功能來任意搜索和匹配你的知識,也可以扔到一些文本編輯器中快速查找。而不需要依賴於特定的軟體,和它們垃圾的檢索功能(例如微信)
  • 熟練使用編輯器以及 Shell—— 圖形工具的好處自安於 WYSIWYG(所見即可得);弱勢之處是 WYSIAYG(所見即全部),如果圖形工具的設計者沒有為你的額外的需求設計鉤子,那你就是做不到。而借助編輯器和 Shell 強大的生態和泛用性,你可以組合它們獲得十分強大的能力,且這份知識還是通用的,它並不局限於某個 IDE 中。

工程日記#

日記的好處

  • 它比記憶更加可靠
  • 它為提供了一個地方,用來保存於當前任務無關的想法。這樣你就可以繼續專注正在做的事情,並指導這個偉大的想法不會被遺忘
  • 它就像一個橡皮鴨。當你停下來,把東西寫上去的時候,大腦可能會換檔,幾乎就像在和某個人說話一樣 —— 這是一個反思的好機會。你可以在開始做筆記的時候,突然意識到剛剛做的事情,也就是筆記的主題是完全錯誤的。

還有一個額外的好處,你能時不時的想起很多年前你在做什麼,會想起那些人、那些事,以及那些糟糕的衣服和髮型。

務實的偏執#

自責中往往有種奢侈。我們自責時,總覺得別人無權再則被我們
—— 奧斯卡・王爾德《道林・格雷的畫像》

BDC 契約式編程#

TDD 測試驅動開發#

作者講述了 BDC 和 TDD 的開發模式,主要是針對防禦式編程和斷言式編程的理念的推崇 —— 及在程式設計階段把邊界條件思考充分,並進行 Check。在出現問題時,及早將異常拋出,避免進一步危害整個系統。這是一個合格程序員的基本功,也沒有什麼特別的方法論。其中值得稱道就是斷言編程的開關性,我們可以像一個 Google 源碼一樣,只在 debug 模式中開啟斷言,這樣可以在日常開發和測試流程時就把一些問題明顯的暴露出來。而在生產模式中,秉承著用戶優先和性能損耗的理念。我們可以關掉斷言,補充日誌。#

很多時候,明天看起來會和今天差不多,但不要指望一定會這樣#

  • 在做設計與維護的時候,對超過可見範圍的模組的維護和設計,並不一定需要浪費精力為不確定的未來做設計(徒增複雜性,像另一本書降到,Android 0.x 版本時,硬體是不支持 GPU 的,而負責開發的 Google 工程師在製作圖形渲染這一塊時,並沒有設計整個系統,而是涉及了一塊虛擬的 GPU,當 Android 後續的版本支持 GPU 後,只需要將虛擬 GPU 的模組替換掉,系統的設計仍然保留),還不如將程式設計成可替換的。使程式可替換,還有助於提高內聚性、解耦和 DRY,從而實現更好的設計。
  • 軟體開發中,總是採取經過深思熟慮的小步驟,同時檢查反饋,並在推進前不斷調整。把反饋的速率當做速度限制,永遠不要進行 “太大” 的任務步驟

寧折不彎#

TDA(tell-don`t-ask)#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。