程式接縫
May 19, 2022
接縫(seam)指的是程式中的可以不用修改現有程式便可以達到變動程式行為的位置。這些位置的存在,將有利於讓開發者發現可以取代接縫銜接對象的行為,進而排除掉某些依賴,並且也可以透過這些取代的程式碼達到針對待測試程式感測(見[[程式的感測和分離]]),針對這些被測試者編寫測試。 每個接縫都需要一個致能點(enabling point)存在,其意義在於在執行期間透過致能點的值可以讓程式決定接下來要執行的行為替換掉的行為亦或是原行為,其可以為各種形式,如傳入的物件參數、預處理器定義名稱、建構腳本 Makefile 所 中定義的檔案路徑等。
接縫的類型
預處理期接縫
C/C++ 語言在編譯之前會先由巨集預處理器執行預處理,在此期間我們可以透過預先定義的巨集替換掉待測試程式嗎(遺留程式嗎),過度使用預處理如 #if
、#ifndef
、#ifdef
像是同時保留了多個版本的程式碼會增加程式閱讀的困難度,巨集也容易因為置換程式碼文字而產生許多意料外的錯誤,但其存在帶來程式嗎更多的接縫。
連結期接縫
許多語言支援動態連結功能,可以透過建立同名的類別並修改程式引入路徑來達到置換程式碼的目的如 Java 透過修改 classPath
、Python 透過修改 sys.path
,避免修改到原始的程式碼而達到分離目的。而對於如 C/C++ 等透過靜態連結產生執行檔的語言,可以針對想要替換實作的類別和函式另外建立一個 [[stub]]版本的函式庫,其包含相同的 function signature 在執行上達到與原程式分離的目的,以便便可以在建構腳本如 makefile 決定使用的函式庫避免修改及使用到產品程式碼。
物件接縫
物件透過呼叫產生行為,然而對於抽象類別的呼叫沒有定義是哪個子類別的方法被執行,因此讓我們可以在不修改現有程式的前提下讓該呼叫去執行我們另外繼承的子類別所定義的方法,達到分離與感測的目的。在呼叫階段由於可以自己決定傳入的物件參數為何,進而產生致能點決定不同的程式行為。
註,物件接縫相較前處理接縫和連結期接縫相較容易維護及易讀。
References
- Working with Legacy Code - - Ch4