最近變更

以下是網站最近更新的清單。您也可以取得此資訊作為 RSS 饋送,而我則會在 TwitterMastodon 上宣布新文章。

我使用此頁面來列出新文章和既有文章的增補。由於我經常分期發布文章,此頁面上的許多條目將會是最近發布文章的新分期,此類公告會縮排,且不會顯示在我的首頁的最近變更區段中。


照片串流 130

2024 年 4 月 21 日星期日下午 6:21 美國東部時間

加州大蘇爾


在傳統取代中使用資料複製

2024 年 4 月 10 日星期三上午 11:00 美國東部時間

Alessio FerriTom Coggrave 完成了他們關於在大型主機系統中引入接縫的文章,方法是探討 我們如何使用資料複製。如果執行得當,它可以快速開始取代工作,但我們必須小心它將新系統與傳統架構結合在一起

更多…


在大型主機的批次處理管線中建立接縫

2024 年 4 月 4 日星期四上午 9:39 美國東部時間

大型主機處理通常組織成批次處理管線,使用和建立資料檔案。 Alessio FerriTom Coggrave 展示了他們找到的幾種方法,用於 在這些管線中引入接縫,以便可以用取代平台中的步驟來取代處理。

更多…


揭露大型主機外部介面的接縫

2024 年 4 月 2 日星期二上午 9:46 美國東部時間

Alessio FerriTom Coggrave 繼續分析應用程式的內部接縫,將 資料庫當作粗粒度的接縫 來處理。他們描述了如何將接縫引入資料庫讀取器和寫入器。

更多…


加入 LinkedIn

2024 年 3 月 28 日星期四下午 12:26 EDT

隨著 Twitter 的 enmuskification 持續進行,我越來越常聽說更多人使用 LinkedIn 來關注新的專業資料。因此,幾個星期前,我設定了我的 LinkedIn 帳戶,以便人們可以在該平台上關注我。

我一直避免使用 LinkedIn - 我發現連結的整體氛圍相當令人反感。我已經收到太多來自想要連結的人的垃圾郵件。但 LinkedIn 新增了「創作者模式」,鼓勵人們關注某人的貼文,而不是雙向連結。到目前為止,這個模式似乎運作得相當好,因此我決定我也會將所有更新貼在這一個帳戶上。不過,我仍然避免連結,所以除非我們已經一起完成一些重要的工作,否則請不要傳送連結要求給我。

我仍然會在 X (Twitter) 上發文,但隨著它逐漸惡化,我對它的關注越來越少。如果你在那裡關注我,我建議你改用我的其中一個 其他動態消息(如果你可以的話)。

我並不特別喜歡 LinkedIn 的動態消息,因為我對它的控制力很低。我從來不喜歡該網站的建議,比較偏好人們的簡單動態消息。遺憾的是,LinkedIn 沒有清單,而且會將某人按讚的所有內容推送到單一的連結動態消息中。這會導致貼文太多,這表示我不會特別注意很多貼文。


告別,John Kordyback

2024 年 3 月 27 日星期三下午 12:48 EDT

一位珍貴的同事兼好友 John Kordyback 上週過世,享年 64 歲。

更多…


揭露大型主機外部介面的接縫

2024 年 3 月 27 日星期三上午 10:36 EDT

Alessio FerriTom Coggrave 開始詳細說明他們使用 兩個外部介面領域 來探索的接縫。檔案的批次輸入會複製到新的實作,同時比較處理管線的輸出。API 存取點可以用代理程式涵蓋,而且流量會逐漸導向到新的實作。

更多…


揭露大型主機中的接縫以進行漸進式現代化

2024 年 3 月 26 日星期二上午 09:32 EDT

大型主機系統持續執行世界上大部分的運算工作負載,但要新增新功能來支援日益成長的業務需求通常很困難。此外,讓它們增強速度緩慢的架構挑戰也讓它們難以替換。為了降低所涉及的風險,我們使用漸進式方法來進行傳統系統替換,逐漸用現代技術實作替換傳統功能。這個策略要求我們在大型主機系統中引入接縫:我們可以在其中將邏輯流程轉移到較新的服務。在最近的一個專案中,Alessio FerriTom Coggrave 研究了幾種方法,將 這些接縫引入一個長壽的大型主機系統。

更多…


如何擷取定性指標

2024 年 3 月 19 日星期二上午 09:33 EDT

Abi NodaTim Cochran 完成了他們關於定性指標的 文章,概述了如何有效擷取這些指標。他們討論了人們在回答調查時經歷的心理步驟,並提供了一個在評估開發人員體驗時入門的範本。最後一節探討了定性和定量如何協同工作:通常從定性指標開始建立基準並確定重點,然後使用定量指標深入探討特定領域。

更多…


重構入門章節的程式碼範例

2024 年 3 月 15 日星期五上午 11:04 EDT

時不時有人向我索取我在 重構 一書的入門章節中使用的程式碼,以便他們可以自行演練。我沒有提供此程式碼的原因,特別是懶惰。幸運的是,Emily Bache 更為敬業,她建立了一個 github 儲存庫 - 戲劇演員重構 Kata - 其中包含程式碼和足夠的測試,讓重構變得合理。

然而,這個儲存庫更進一步,它包含了十幾種語言的類似範例程式碼,包括 C、Java、Rust 和 Python。

她最近在她的 YouTube 頻道上發布了一段 影片,概述了她鼓勵人們在閱讀該章節時使用此程式碼的原因。她的頻道包含許多關於良好程式碼技術的影片,並且她有一個 Patreon 讓讀者支持她的工作。


定性指標的好處

2024 年 3 月 13 日星期三上午 10:36 EDT

Abi NodaTim Cochran 繼續討論使用定性指標來評估開發團隊的生產力。 在此分期付款中,他們將定性指標分類為態度指標和行為指標。我們還看到,定性指標允許您測量其他無法測量的內容、提供缺少的可視性,並為定量資料提供必要的背景。

更多…


透過人類衡量開發人員生產力

2024 年 3 月 12 日星期二上午 09:36 EDT

衡量開發人員生產力是一項艱難的挑戰。專注於開發週期時間和產出的傳統指標受到限制,而且對於其他地方在哪裡轉向沒有明顯的答案。定性指標提供了一種強大的方式來衡量和了解開發人員生產力,方法是使用從開發人員自己衍生的資料。 Abi NodaTim Cochran解釋什麼是定性指標 以及為什麼我們不應該因為它們主觀或不可靠而拒絕它們開始他們的討論。

更多…


如果我們每天輪換配對會怎樣?

2024 年 3 月 6 日星期三上午 10:33 美東時間

在配對程式設計時,頻繁輪換配對很重要,但許多執行配對程式設計的組織不願意這麼做。Gabriel RobainaKieran Murphy 提出了一個問題:「如果我們每天輪換配對會怎樣?」並與三個團隊一起進行了一項每日配對輪換練習。他們開發了一種輕量級方法,以協助團隊反思配對的優點和挑戰,以及如何解決這些問題。最初的恐懼被克服,團隊也發現了頻繁輪換配對的好處。他們了解到,頻繁輪換配對會大幅提升配對的好處。他們的文章分享他們開發的方法、觀察結果,以及參與團隊成員分享的一些常見恐懼和見解。

更多…


舊系統取代模式:事件攔截

2024 年 3 月 5 日星期二上午 10:03 美東時間

當我們逐步取代舊系統時,我們有許多案例,舊系統及其替換系統需要互動。由於這些舊系統通常難以且成本高昂地變更,因此我們需要一種機制,可以在將影響降至最低的情況下整合替換元素。Ian Cartwright、Rob Horn 和 James Lewis 說明我們如何對狀態變更事件使用 事件攔截,讓我們能夠將它們轉發給替換系統。

更多…


Bliki:定期面對面

2024 年 2 月 27 日星期二上午 09:17 美東時間

通訊技術的進步導致越來越多的團隊以 遠距優先 的方式工作,這股趨勢因 Covid-19 大流行的強制隔離而更加蓬勃發展。但遠距運作的團隊仍可從面對面聚會中受益,並且應該每隔幾個月進行一次。

遠距優先團隊讓每個人都在不同的地點,完全透過電子郵件、聊天、視訊和其他通訊工具進行溝通。它有明確的好處:可以從世界各地招募人員加入團隊,而且我們可以讓有照顧責任的人參與。浪費時間且令人沮喪的通勤時間可以轉變為生產或休養時間。

但是,無論人們在遠距工作方面有多麼有能力,無論現代協作工具有多麼靈巧,都沒有什麼能比得上與團隊其他成員身處同一個地方。當人們面對面時,人際互動總是更豐富。視訊通話很容易變成交易行為,幾乎沒有時間進行建立適當人際關係的閒聊。沒有這些更深層的連結,誤解就會惡化成嚴重的關係困難,團隊可能會陷入如果每個人都能親自交談就能有效解決的情況。

我從那些在遠距工作中表現出色的人身上看到一個規律的模式,那就是他們會確保定期舉行面對面的會議。在這些會議中,他們會安排那些一起完成效果更好的工作元素。遠距工作對於需要獨自專注的任務更有效率,而現代工具可以讓遠距配對變得可行。但是,當每個人都在同一個房間時,需要許多人快速提供意見的任務會更容易完成。沒有任何視訊會議系統可以創造出這種深度的互動,盯著電腦螢幕看其他人正在做什麼會讓人筋疲力盡,而且沒有機會一起出去喝杯咖啡來暫停工作。關於產品策略的辯論、系統架構的探討、新領域的探索——這些都是團隊集結時常見的任務。

要讓人們有效地合作,他們需要彼此信任,了解他們能多依賴彼此。在線上很難建立信任,因為沒有我們在同一個房間時會出現的社交暗示。因此,面對面聚會最有價值的部分不是預定的工作,而是喝咖啡時的閒聊,以及午餐時的歡樂時光。非正式的對話,大多不是關於工作,可以建立人與人之間的聯繫,讓工作互動更有效率。

這些準則建議面對面會議的內容。共同工作本身既有價值,也是團隊凝聚力中重要的部分。因此,我們應該設定一整天的工作時間,專注於那些受益於共處時低延遲溝通的任務。然後,我們應該包含看似過多的休息時間、非正式聊天和走出辦公室的機會。我會避免任何人工的「團隊建設」練習,僅僅是因為我有多麼討厭它們。那些舉辦此類聚會的人強調,聚會後每個人都會充滿活力,因此可以在接下來的幾週內更有效率地工作。

遠距團隊可以組成於很遠的距離,而看到成員相隔數小時的旅途時間是很常見的。對於這樣的團隊,我建議的經驗法則是在每兩或三個月聚會一週。在團隊變得成熟後,他們可以決定減少頻率,但如果一個團隊一年中沒有至少兩次面對面的會議,我會感到擔心。如果一個團隊都在同一個城市,但使用遠距優先的風格來減少通勤,那麼他們可以組織較短的聚會,並更頻繁地進行。

這種聚會可能會導致重新思考如何配置辦公空間。自從疫情以來,辦公室的使用率大幅降低,這一點已被廣泛討論。辦公室很可能不再是一個日常工作空間,而更像是一個用於這些不定期團隊聚會的地點。這導致了對靈活且舒適的團隊聚會空間的需求。

一些組織可能會對像這樣的團隊集會的差旅和住宿費用望而卻步,但他們應該將其視為對團隊效能的一項投資。忽視這些面對面的會議會導致團隊陷入困境、朝著錯誤的方向前進、飽受衝突困擾,以及人們失去動力。與此相比,在飛機和酒店上省錢是一種虛假的經濟。

進一步閱讀

遠距優先是遠距工作的一種形式,我在 遠距與共同定位工作 中探討了不同的遠距工作風格及其權衡。

在 Thoughtworks,當我們在近二十年前首次啟動我們的離岸開發中心時,我們了解到定期面對面聚會對遠距團隊的重要性。這些產生了我所描述的實務,請參閱 使用敏捷軟體流程進行離岸開發

遠距工作,特別是跨越時區時,會更重視非同步的協作模式。我的同事 Sumeet Moghe 是一位產品經理,他在他的書 非同步優先手冊 中深入探討了如何做到這一點。

軟體產品公司 Atlassian 最近完全轉為遠距工作,並發表了 經驗報告。他們發現團隊一年大約需要見面三次。Claire Lew 在 2018 年調查了遠距優先團隊,發現四分之一的受訪者會「一年見面數次」。37Signals 已經以遠距優先的方式經營了將近二十年,而且 一年會安排兩次見面

致謝

Alejandro Batanero、Andrew Thal、Chris Ford、Heiko Gerin、Kief Morris、Kuldeep Singh、Matt Newman、Michael Chaffee、Naval Prabhakar、Rafael Detoni 和 Ramki Sitaraman 在我們的內部郵寄清單上討論了這篇文章的草稿。


LLM 應用程式開發的工程實務

2024 年 2 月 13 日星期二,美國東部時間下午 12:22

LLM 工程不只是提示設計或提示工程而已。在這裡,David TanJessie Wang 反思了測試和重構等一般的工程實務如何 幫助他們快速且可靠地交付 LLM 應用程式原型。

更多…


入職瓶頸:最後一期

2024 年 1 月 31 日星期三,美國東部時間上午 11:57

Tim 和 Prem 完成了他們關於有效入職的文章。 他們討論了 結對程式設計、設定個人環境和消除流程摩擦的價值。

更多…


入職瓶頸:更多有效入職的步驟

2024 年 1 月 30 日星期二,美國東部時間上午 09:33

Tim 和 Prem 繼續概述有效入職流程的步驟。 他們談到 讓新進人員融入公司文化、掌握錄取後和第一天體驗,以及投資於自助式知識管理。

更多…


使用自動完成功能改善我的 Emacs 體驗

2024 年 1 月 25 日星期四,美國東部時間下午 13:20

我已經使用 Emacs 多年了,用它撰寫網站上的所有文章、寫書,以及編寫大部分程式碼。(例外是使用 IntellJ IDEA 編寫 Java 程式碼,以及使用 RStudio 編寫 R 程式碼。)因此,我很高興看到過去幾年 Emacs 功能有了很大的進步,讓它不再像演化死胡同。對我的 Emacs 體驗來說,最大的進步之一就是使用正規表示式作為自動完成清單。

許多 Emacs 指令會產生清單供您挑選。我想開啟一個檔案,我輸入鍵盤組合來尋找檔案,Emacs 會在迷你緩衝區(與指令互動的特殊區域)中彈出候選檔案清單。這些檔案清單可能會很長,特別是我要求列出目前專案中的所有檔案時。

若要指定我想要的檔案,我可以輸入一些文字來篩選清單,因此,如果我想開啟檔案 articles/simple/2024-emacs-completion.md,我可能會輸入 emacs。我不一定要取得那個檔案,只要篩選出夠小的清單通常就夠了。

有一種特定的 regex 建構器樣式,我發現它最有幫助,它以空格分隔 regex。這將允許我輸入 articles emacs 來取得檔案路徑中包含「articles」和「emacs」的任何檔案路徑清單。它基本上將字串「articles emacs」轉換為 regex \\(articles\\).*\\(emacs\\)。更好的是,這種比對器允許我以任何順序輸入 regex,因此「emacs articles」也會比對。這樣,一旦第一個 regex 彈出篩選後的清單,我就可以使用第二個 regex 挑選我想要的,即使區分 regex 早於我的初始搜尋。

安裝這種完成比對器對我使用 Emacs 產生了顯著的影響,因為它讓我在與指令互動時輕鬆篩選大型清單。其中最顯著的一項是它如何改變我使用 M-x 的方式,這是顯示所有互動式 Emacs 函式的鍵盤組合。透過 regex 比對器來篩選清單,它允許我使用名稱呼叫 Emacs 指令,只需按幾個鍵盤按鍵。這樣我就不必記住鍵盤快速鍵。有了這個,我透過 M-x 呼叫較少使用的指令。我不會經常列出所有開啟的緩衝區,因此,與其試圖記住它的鍵盤組合,我只需輸入 M-x ibibuffer 就會快速彈出。這有助於我用於 M-xcounsel-M-x)的指令在 regex 中插入「^」作為第一個字元,這會將第一個 regex 固定在行的開頭。由於我為所有自寫函式加上 mf- 前置詞,因此我可以輕鬆找到自己的函式,即使它們有很長的函式名稱。我寫了一個指令來從 URL 中移除網域,我稱之為 mf-url-remove-domain,並可以使用 M-x mf url 呼叫它。

Emacs 中有許多套件可以進行這種比對,多到令人困惑。我現在使用的是 Ivy。預設情況下,它使用以空格分隔的 regex 比對器,但它不支援任何順序。若要按照我喜歡的方式設定它,我使用

(setq ivy-re-builders-alist '((t . ivy--regex-ignore-order)))

Ivy 是稱為 counsel 的套件的一部分,其中包含各種增強這些選取的指令。

Ivy 不是唯一執行這種操作的工具。事實上,Emacs 中的完成工具世界是我發現非常令人困惑的世界:許多工具具有重疊和互動,我並不真正理解。此領域中的工具包括 HelmcompanyVerticoConsult。精通 Emacs 有一篇文章 了解迷你緩衝區完成,但它沒有說明它所討論的機制如何與 Ivy 所做的相符,而且我沒有花時間弄清楚所有這些。

一般來說,我強烈推薦使用這本 Mastering Emacs 書籍,以學習如何使用這個令人難以置信的工具。Emacs 具有如此多的功能,即使像我這樣使用數十年的使用者,也發現這本書帶來了「我不知道它可以這樣做」的時刻。

對於那些好奇的人,以下是我的 Emacs 配置相關部分

(use-package ivy
  :demand t
  :diminish ivy-mode
  :config
  (ivy-mode 1)
  (counsel-mode 1)
  (setq ivy-use-virtual-buffers t)
  (setq ivy-use-selectable-prompt t)
  (setq ivy-ignore-buffers '(\\` " "\\`\\*magit"))
  (setq ivy-re-builders-alist '(
                                (t . ivy--regex-ignore-order)
                                ))
  (setq ivy-height 10)
  (setq counsel-find-file-at-point t)
  (setq ivy-count-format "(%d/%d) "))

(use-package counsel
  :bind (
         ("C-x C-b" . ivy-switch-buffer)
         ("C-x b" . ivy-switch-buffer)
         ("M-r" . counsel-ag)
         ("C-x C-d" . counsel-dired)
         ("C-x d" . counsel-dired)
         )
  :diminish
  :config
  (global-set-key [remap org-set-tags-command] #'counsel-org-tag))

(use-package swiper
  :bind(("M-C-s" . swiper)))

(use-package ivy-hydra)

加入瓶頸:建立一條邁向成效的道路

2024 年 1 月 24 日星期三上午 10:45 美東時間

Tim 和 Prem 開始討論如何擺脫加入的困難,他們說明如何為新進員工 建立一條邁向成效的道路。這條道路概述了員工的需求,以及加入流程應如何滿足這些需求。

更多…


擴展瓶頸 #06:加入

2024 年 1 月 23 日星期二上午 09:13 美東時間

去年對科技產業來說是艱難的一年,它面臨了自本世紀初網路泡沫破滅以來最大規模的裁員和裁員潮。隨著 2024 年的開始,我們看到了好轉的早期跡象,這意味著科技組織很快就會再次考慮招聘。如果這樣的好日子回來了,公司將再次遇到新進員工需要很長一段時間才能發揮成效的常見問題。Tim Cochran 和 Premanand Chandrasekaran 在我們關於擴展瓶頸系列的第六部分中解決了這個問題。在第一部分中,Tim 和 Prem 檢視了成長中的組織 遇到這個瓶頸 的跡象。

更多…


持續整合的主要修訂

2024 年 1 月 18 日星期四上午 10:01 美東時間

在世紀之交,我很幸運參與了幾個開發持續整合實務的專案。我在我的網站上寫了一篇關於這項工作的經驗教訓,它仍然是這個重要實務經常引用的資源。去年底,一位同事聯絡我,說這篇文章雖然已經將近二十年了,但仍然很有用,但已經顯得老舊。他寄給我一些建議的修訂,我以此為契機對 這篇文章進行徹底的修訂,考量原始文章中的每個章節,並新增章節來處理過去二十年出現的問題。

在過去的幾十年中,功能分支廣泛應用於產業中。我的許多同事認為,持續整合更適合許多團隊,我希望本文能幫助讀者評估是否如此,如果是,如何有效實作持續整合。

更多…


Bliki:傳統接縫

2024 年 1 月 4 日星期四上午 9:13 EST

在使用傳統系統時,識別和建立接縫非常有價值:在這些地方,我們可以改變系統的行為,而無需編輯原始碼。一旦找到接縫,我們就可以使用它來中斷依賴關係以簡化測試、插入探針以獲得可觀察性,以及將程式流程重新導向到新模組,作為傳統取代的一部分。

Michael Feathers 在其著作中,針對傳統系統中的「接縫」一詞提出定義,書名為 與傳統程式碼有效合作。他的定義:「接縫是您可以在程式中改變行為的地方,而無需在該處進行編輯」

以下是一個接縫會派上用場的範例。想像一些計算訂單價格的程式碼。

// TypeScript
export async function calculatePrice(order:Order) {
  const itemPrices = order.items.map(i => calculateItemPrice(i))
  const basePrice = itemPrices.reduce((acc, i) => acc + i.price, 0)
  const discount = calculateDiscount(order)
  const shipping = await calculateShipping(order)
  const adjustedShipping = applyShippingDiscounts(order, shipping)
  return basePrice + discount + adjustedShipping
}

函式 calculateShipping 會存取一個外部服務,該服務很慢(且昂貴),因此我們不希望在測試時存取它。相反地,我們想要引入一個 存根,以便我們可以為每個測試情境提供罐頭且確定性的回應。不同的測試可能需要函式提供不同的回應,但我們無法在測試中編輯 calculatePrice 的程式碼。因此,我們需要在呼叫 calculateShipping 周圍引入一個接縫,這將允許我們的測試將呼叫重新導向到存根。

執行此操作的方法之一是將 calculateShipping 的函式傳遞為參數

export async function calculatePrice(order:Order, shippingFn: (o:Order) => Promise<number>) {
  const itemPrices = order.items.map(i => calculateItemPrice(i))
  const basePrice = itemPrices.reduce((acc, i) => acc + i.price, 0)
  const discount = calculateDiscount(order)
  const shipping = await shippingFn(order)
  const adjustedShipping = applyShippingDiscounts(order, shipping)
  return basePrice + discount + adjustedShipping
}

此函式的單元測試接著可以替換一個簡單的存根。

const shippingFn = async (o:Order) => 113
expect(await calculatePrice(sampleOrder, shippingFn)).toStrictEqual(153)

每個接縫都附帶一個啟用點:「您可以在其中做出使用一種或另一種行為的決策的地方」[WELC]。將函式傳遞為參數會在 calculateShipping 的呼叫者中開啟一個啟用點。

這現在讓測試變得容易許多,我們可以輸入不同的運費成本值,並檢查 applyShippingDiscounts 是否正確回應。儘管我們必須變更原始原始碼才能引入接縫,但對該函式的任何進一步變更都不需要我們變更該程式碼,所有變更都發生在啟用點中,而啟用點位於測試程式碼中。

將函式傳遞為參數並非我們可以引入接縫的唯一方法。畢竟,變更 calculateShipping 的簽章可能會很困難,而且我們可能不想在生產程式碼中透過傳統呼叫堆疊串接運送函式參數。在這種情況下,查找可能是更好的方法,例如使用服務定位器。

export async function calculatePrice(order:Order) {
  const itemPrices = order.items.map(i => calculateItemPrice(i))
  const basePrice = itemPrices.reduce((acc, i) => acc + i.price, 0)
  const discount = calculateDiscount(order)
  const shipping = await ShippingServices.calculateShipping(order)
  const adjustedShipping = applyShippingDiscounts(order, shipping)
  return basePrice + discount + adjustedShipping
}
class ShippingServices {
  static #soleInstance: ShippingServices
  static init(arg?:ShippingServices) {
    this.#soleInstance = arg || new ShippingServices()
  }
  static async calculateShipping(o:Order) {return this.#soleInstance.calculateShipping(o)}
  async calculateShipping(o:Order)  {return legacy_calcuateShipping(o)}
  // ... more services

定位器允許我們透過定義子類別來覆寫行為。

class ShippingServicesStub extends ShippingServices {
  calculateShippingFn: typeof ShippingServices.calculateShipping =
     (o) => {throw new Error("no stub provided")}
  async calculateShipping(o:Order) {return this.calculateShippingFn(o)}
  // more services

我們可以在測試中使用一個啟用點

const stub = new ShippingServicesStub()
stub.calculateShippingFn = async (o:Order) => 113
ShippingServices.init(stub)
expect(await calculatePrice(sampleOrder)).toStrictEqual(153)

這種服務定位器是一種經典的物件導向方式,可透過函式查詢設定接縫,我顯示此處以指出我在其他語言中可能使用的做法類型,但我不會在 TypeScript 或 JavaScript 中使用此做法。相反地,我會將類似內容放入模組中。

export let calculateShipping = legacy_calculateShipping

export function reset_calculateShipping(fn?: typeof legacy_calculateShipping) {
  calculateShipping = fn || legacy_calculateShipping
}

我們可以在測試中使用類似這樣的程式碼

const shippingFn = async (o:Order) => 113
reset_calculateShipping(shippingFn)
expect(await calculatePrice(sampleOrder)).toStrictEqual(153)

如同最後一個範例所建議,用於接縫的最佳機制非常取決於語言、可用的架構,以及舊系統的樣式。控制舊系統表示學習如何將各種接縫引入程式碼,以提供正確類型的啟用點,同時將對舊軟體的干擾降至最低。雖然函式呼叫是引入此類接縫的簡單範例,但實際上它們可能更為複雜。團隊可能花費數個月時間找出如何將接縫引入歷經考驗的舊系統。將接縫新增至舊系統的最佳機制可能與我們在全新環境中為類似彈性所做的不同。

Feathers 的書籍主要著重於讓舊系統接受測試,因為這通常是能夠以合理的方式處理舊系統的關鍵。但接縫還有更多用途。一旦我們有了接縫,我們就可以將探測器放置在舊系統中,讓我們增加系統的可觀察性。我們可能想要監控對 calculateShipping 的呼叫,找出我們使用它的頻率,並擷取其結果以進行個別分析。

但接縫最有價值的用途可能是它們讓我們能夠將行為從舊系統遷移出去。接縫可能會將高價值客戶重新導向到不同的運費計算器。有效的舊系統置換建立在將接縫引入舊系統,並使用它們逐漸將行為移至更現代的環境上。

當我們撰寫新的軟體時,接縫也是需要考慮的事情,畢竟每個新的系統遲早都會變成舊系統。我的許多設計建議都是關於建立具有適當放置接縫的軟體,這樣我們就可以輕鬆地測試、觀察和增強它。如果我們在撰寫軟體時考慮到測試,我們往往會得到一組良好的接縫,這就是為什麼測試驅動開發是一種如此有用的技術。


我最喜歡的 2023 年音樂發現

2024 年 1 月 2 日星期二下午 6:42 美東時間

又過了一年,又是時候挑選六首最喜歡的音樂發現了。2023 年包括環境藍草、非洲安地斯放克、諾森伯蘭小型風笛、舞蹈科拉琴和烏克蘭民謠爵士樂。

更多…


Bliki:軟體與工程

2023 年 12 月 13 日星期三凌晨 12:00 美東時間

在我的職業生涯中,人們將軟體開發與「傳統」工程進行比較,通常是用這種方式來責罵軟體開發人員沒有做好工作。作為一名電子工程學位畢業的人,這在我職業生涯的早期引起了我的共鳴。但這種思維方式是有缺陷的,因為大多數人對工程在實務中的運作方式有錯誤的印象。

Glenn Vanderburg花了很多時間探討這些誤解,我強烈建議任何想要將軟體開發與工程進行比較的人觀看他的演講真正的軟體工程。也值得聽聽他在 Oddly Influenced 播客上的訪談。遺憾的是,我無法說服他寫下這些材料 - 這將成為一篇很棒的文章。

另一個對這種關係有深入思考的人是 Hillel Wayne。他採訪了一群「跨界者」 - 既在傳統工程領域又曾在軟體領域工作過的人。他將所學寫成了一系列文章,從我們真的是工程師嗎?開始。


Bliki:測試驅動開發

2023 年 12 月 11 日星期一下午 2:40 美東時間

測試驅動開發 (TDD) 是一種透過撰寫測試來指導軟體開發的軟體建構技術。它是由Kent Beck在 1990 年代後期作為極限編程的一部分開發的。我們基本上重複執行以下三個簡單步驟

儘管這三個步驟通常簡稱為「紅燈 - 綠燈 - 重構」,是這個過程的核心,但在我們首先寫出一個測試案例清單時,還有一個至關重要的初始步驟。然後我們挑選其中一個測試,對其套用紅燈 - 綠燈 - 重構,一旦完成,就挑選下一個。正確排序測試是一項技能,我們希望挑選能快速引導我們到設計中要點的測試。在這個過程中,我們應該在想到時將更多測試新增到我們的清單中。

先寫測試,XPE2 稱之為測試優先程式設計,提供了兩個主要好處。最明顯的是,這是一種取得自測試程式碼的方法,因為我們只能在讓測試通過後才能寫出一些功能程式碼。第二個好處是,先思考測試會迫使我們先思考程式碼的介面。這種對介面和如何使用類別的關注,有助於我們將介面與實作分開,這是許多程式設計師難以應付的良好設計關鍵要素。

我聽說搞砸 TDD 最常見的方式是忽略第三個步驟。重構程式碼以保持其乾淨是這個過程的關鍵部分,否則我們最終只會得到一個雜亂無章的程式碼片段集合。(至少這些會有測試,因此它比大多數設計失敗的結果不那麼痛苦。)

進一步閱讀

Kent 對執行 TDD 的正規方法的摘要是關鍵的線上摘要。

更深入的探討,請參閱 Kent Beck 的著作測試驅動開發

James Shore 的敏捷開發的藝術一書的相關章節是另一個有力的說明,它也將其與其他有效的敏捷開發聯繫起來。James 還寫了一系列名為讓我們玩 TDD的螢幕錄影。

修訂

我最初發布此頁面是在 2005-03-05。受到 Kent 的正規文章啟發,我在 2023-12-11 更新了它


Bliki:Diff 除錯

2023 年 12 月 4 日星期一美國東部時間上午 00:00

回歸錯誤是軟體功能中新出現的錯誤,這些功能已經存在一段時間了。在追蹤這些錯誤時,找出軟體中哪個變更導致這些錯誤出現通常很有價值。查看該變更可以提供有關錯誤位置和如何消除錯誤的寶貴線索。這種調查形式沒有廣為人知的術語,但我稱之為 Diff 除錯。

Diff 除錯僅在我們將程式碼置於版本控制中時才有效,但幸運的是,現在這已成為常態。但還有一些其他事項需要使其有效運作。我們需要可重製建置,以便我們可以輕鬆執行舊版本的軟體。由於高頻率整合,因此擁有小提交非常有幫助。這樣,當我們找到有問題的提交時,我們可以更輕鬆地縮小發生情況的範圍。

若要找出產生錯誤的提交,我們首先找出沒有錯誤的任何過去版本。將其標記為最後良好版本,將目前版本標記為最早錯誤。然後找出介於兩者之間的提交,看看錯誤是否在那裡。如果是,則此提交變為最早錯誤,否則則變為最後良好。重複此程序(這是「半區間」或「二進制」搜尋),直到我們找出有問題的提交。

如果我們使用 git,則git bisect指令會自動執行大部分的這項工作。如果我們可以撰寫一個測試來顯示錯誤的存在,則 git bisect 也可以使用它,自動執行找出有問題提交的整個程序。

我經常發現 Diff 除錯在程式設計階段中很有用。如果我有需要花費幾分鐘才能執行的慢速測試,我可能會編寫半小時的程式,只執行最相關測試的子集。只要我在每次綠色測試執行後提交,如果其中一個較慢的測試失敗,我就可以使用 Diff 除錯。即使它們很小,以至於我認為最好將它們壓縮以供長期歷史記錄,極頻繁地提交的價值也是如此。一些 IDE 會自動保留比版本控制提交更精細的本地歷史記錄,讓這項工作變得更容易。

修訂

我最初在 2004-06-01 發佈此頁面。其原始形式更像是一份隨意的體驗報告。我在 2023-12-04 對其進行了重寫,使其更像是一個術語定義。差異化除錯並不是業界中流行的一個術語,但我沒有見過另一個通常用於描述它的術語。


如何應對編碼助理的不可靠性

2023 年 11 月 28 日星期二上午 10:21 美東時間

在過去的一年中,許多開發人員已將 LLM 編碼助理納入其工作中,發現它們是一個有用的工具。但這些工具的一個問題是它們不可靠,經常提出糟糕或完全錯誤的建議。Birgitta Böckeler 繼續探索 GenAI for developers,傳授她所瞭解的關於如何思考這種不可靠性,以及為什麼稱你的 LLM 工具為「Dusty」可能是件好事。

更多…


分布式系統模式由 Pearson 出版

2023 年 11 月 24 日星期五下午 2:11 美東時間

在過去的四年裡,我的同事Unmesh Joshi 一直在開發一系列模式,以幫助我們所有人更好地理解現代分布式系統是如何工作的。我們一直在本網站上發佈這些模式的草稿。現在這些已經變成了一本由 Addison-Wesley 在我的簽名系列中出版的書。因此,我們現在已從本網站中刪除了正在進行中的草稿,並用模式摘要目錄取代了它們。對於訂閱了 oreilly.com 的人,我們從摘要到線上書籍相關章節提供了深度連結。

更多…


文科文憑幫助我在科技領域取得成功的三個原因

2023 年 11 月 09 日星期四上午 10:12 美東時間

我的同事Sannie Lee 遇到了許多正在考慮進入科技領域並選修狹窄專業導向專業的學生。然而,Sannie 發現傳統的文科文憑賦予了她技能,這些技能與她作為產品經理的工作高度相關。

更多…