情境

先前 cron job 的鬼故事還有續集...原以為解決了 K8S 的問題後,王子與公主就可以過著幸福美滿的生活了。當我們放心讓 cron job 運行,滿心期待好人有好報。很不幸,最後還是殺出程咬金。

在資料庫選擇中,使用 transactional DB 儲存交易紀錄,同時將資料同步到全文檢索的資料庫,如elastic search,這樣的搭配是很常見的儲存設計手法 。在新增、修改、與刪除的工作完成後,將這些資料變更同步到全文檢索的資料庫提供資料搜尋。因此商業交易紀錄與全文檢索是整個服務能夠運作順常的重要機制。

我們發現 cron job 雖然有 log 顯示 “Task complete”,但是,後面出現 connection close error,因此整個 process 無法正常結束。經過一段時間爬梳程式碼,我們發現了一段可疑的程式碼:

bookModel.synchronize()

(如果是使用 repository pattern,請使用 synchronizeToSearchDb 的 high level naming 的方式描述需求,而不是運作方式)

最終,我們雖然順利地解決問題。不過,過程中發現了一個很致命的缺失。沒有人能夠了解這行祖傳秘方,也沒有任何文件與測試說明為何需要這段程式碼。還有一件令人笑不出來的事實是它有兩種不同的實作方式,早期有人寫了第一版,後人依照他的理解也實作了另一個版本。

Bad Smell

如果我們覺得很重要的設計或者商業需求,就應該建構一種方式確保這樣的功能與設計能夠代代相傳。

另外,有一個極端的方法用來驗證測試案例是否真實有效...透過刪除“無用”的程式碼,我們的 CI pipeline 是否能夠示警,幫助我們建立安全防護網(Andon Cord),快速排除問題。如果我們拔掉程式碼,沒有任何測試案例示警,直到客戶在真實環境發現產品的缺陷,這樣的的產品品質回饋(feedback loop)的方式與效率,令人擔憂。

在這範例中,雖然只有一行程式碼沒有被測試包覆,即使我們的測試覆蓋率再高,但是重要的功能與設計沒有安全防護網,在高的覆蓋率,也無法協助開發人員提升信心程度。

建議方式

The Beyoncé Rule

The straightforward answer is: test everything that you don't want to break. In other words, if you want to be confident that a system exhibits a particular behavior, the only way to be sure it will is to write an automated test for it.

如果你覺得這段商業需求與功能、軟體設計很重要,就拿出真實可靠的方式確保,而不是口頭說很重要。一但你提出了保證,寫入了測試案例,就建立了防護網與安燈警告機制。任何人不小心改動了產品,都會透過測試案例告訴你這段程式碼的功能。開發人員藉由這樣的高空防護網機制,在修改程式碼時能夠很快的得到反饋,得知品質是可以確保的。因此,藉由信心程度的提深,大大的提升維護程式碼的意願。

測試程式也是最好的知識傳達方式,不管是商業需求或者是技術規範,都能夠明確地在測試案例中呈現。而且測試案例,最好能讓非技術人員如 product owner 了解。

另外,專案的生命週期通常遠大於專案人員負責專案的期間。當人員離開時或者是交接時,即便都是抱持著滿懷熱血,想把在專案中做到的部分盡可能以口頭或者是寫文件的方式傳達清楚。但最終可能會受限於記憶、時間、表達能力等等的因素,產生的結果往往很難讓後人滿意的。與其要求離職前要求盡可能詳細的交接,不如日常落實測試情境說明清楚,這樣就很香了。人員離職或者是轉換團隊時,就讓成員瀟灑地離開吧。

Reference

abseil / Software Engineering at Google