從程式碼庫中移除已棄用的函數,從概念上講是開發者可以做的最簡單的事情之一:刪除定義,確認沒有其他程式碼使用它,然後提交。但在實踐中,對於任何存在時間足夠長以至於被棄用的函數來說,「確認沒有其他程式碼使用它」這一步往往是整個流程的癥結所在。該函數可能被幾年前由已離職團隊成員編寫的程式碼調用,也可能被位於更新頻率很低的程式碼庫中,或被當前團隊不熟悉的語言或框架調用。它可能透過包裝器、反射或運行時分發機制間接調用,而這些機制不會出現在任何靜態調用圖中。它可能在生成的程式碼、測試腳手架或透過名稱觸發它的設定檔中被引用。如果沒有能夠建立完整的跨程式碼庫呼叫者清單的工具,標記該函數為已棄用的開發者和最終移除該函數的開發者可能根本無法得知所有這些情況。
錯誤處理的成本是立竿見影且顯而易見的。如果函數在呼叫者發現不完整的情況下被移除,會導致仍然依賴該函數的系統出現運行時故障。在單體架構中,故障面是有限的。但在擁有多個獨立部署服務的分散式系統中,故障會像滾雪球一樣蔓延:提供該函數的服務會被更新,但其用戶卻不會,最終導致在生產環境中運行時出現故障,而這些系統可能由不同的團隊負責。在大型主機環境中,COBOL 程式透過名稱呼叫共享實用程式段落,故障可能要等到特定的批次作業執行時才會顯現,而這些作業可能是每週或每月執行一次,因此在正常的測試週期中,缺少的參考是不可見的。從更廣泛的棄用程式碼管理角度來看,風險會隨著時間的推移而累積:未完全移除的棄用程式碼比保留的棄用程式碼更危險,因為移除會造成一種完整性的假象,而剩餘的呼叫者仍在繼續執行一個已不存在的定義。
本文是一份實用的函數移除前呼叫者發現指南:完整的呼叫者清單需要什麼,為什麼開發人員首先使用的工具在結構上是不夠的,不同類型的呼叫關係需要不同的分析方法,以及在混合了語言、平台和儲存庫的企業級程式碼庫中,真正的跨系統呼叫者列舉是什麼樣的。
為什麼來電者發現比看起來更難
對於每位開發者來說,呼叫者發現的淺層版本都耳熟能詳:在 IDE 中右鍵單擊函數名,選擇“查找所有引用”或“顯示呼叫層次結構”,然後查看結果。這種方法在單一 IDE 實例中載入的單一專案範圍內可靠且有效。一旦程式碼庫超出此範圍,結果就會變得不完整,而這種不完整在輸出中是無法察覺的。 IDE 不會指出它沒有找到哪些呼叫者,因為它沒有索引包含這些呼叫者的儲存庫。開發者看到的是一個看似完整的結果集,並據此繼續進行後續操作。
這就是大規模呼叫者發現的結構性問題:開發者最常用的工具受限於其索引範圍,而在大型分散式多語言系統中,該範圍僅覆蓋給定函數可能被呼叫位置的一小部分。開發者對結果完整性的信心與搜尋的實際完整性成反比。在小型單語言程式碼庫中,IDE 呼叫層次結構確實可靠。但在跨越多個程式碼庫、多種語言和部署環境的企業系統中,它卻系統性地誤導使用者。正如在程式碼熵和重構風險的背景下分析的那樣,遺留模組可能依賴於已棄用的接口,而較新的服務仍然調用最初為早期環境設計的例程,這些跨系統的調用關係正是受限於 IDE 的搜索無法發現的。
要了解呼叫方發現失敗的具體原因,需要檢查每種主要的呼叫類型:直接呼叫、間接呼叫、跨語言呼叫和動態分派。每種呼叫類型失敗的原因各不相同,需要不同的分析技術才能正確解決。
跨存儲庫邊界的直接調用
直接呼叫是最簡單的呼叫類型:一個函數透過名稱明確地呼叫另一個函數。在單一程式碼庫內,IDE 可以可靠地處理這類呼叫。但跨程式碼庫時,分析會失敗,因為 IDE 的索引範圍無法跨越邊界。例如,如果程式碼庫 A 定義了一個共享的實用函數,而程式碼庫 B、C 和 D 都匯入並呼叫了該函數,那麼任何一個程式碼庫的 IDE 都只能看到自身索引範圍內的呼叫。
在微服務架構中,這種多倉庫呼叫模式是常態而非例外。在微服務架構中,共享庫以套件的形式發布,並被數十個服務呼叫。庫維護者如果棄用了共享包中的某個函數,就需要知道哪些服務仍在呼叫它。他們的整合開發環境(IDE)對這些呼叫者一無所知。套件管理器知道哪些服務依賴該套件,但不知道每個服務都呼叫了套件中的哪個特定函數。要將“此服務使用此套件的 X 版本”對應到“此服務呼叫了某個已棄用的特定函數”,就需要索引每個呼叫者的原始程式碼,並將呼叫解析到特定的函數定義。
間接呼叫:包裝器、委託和外觀
函數不能被其使用者直接呼叫。它可以透過提供額外日誌記錄、錯誤處理或參數轉換的包裝函數來呼叫。它可以被賦值給委託或函數指針,並透過委託呼叫。它可以註冊到服務註冊表或插件框架中,並透過分發機制按名稱呼叫。在每種情況下,直接搜尋對已棄用函數的呼叫都會傳回不完整的結果,因為實際的呼叫者呼叫的是包裝函數或分發函數,而不是已棄用函數本身。
在大型程式碼庫中,透過包裝器介導的呼叫尤其常見。在這些程式碼庫中,諸如日誌記錄、授權和重試邏輯等橫切關注點通常會透過包裝器模式包裹在核心函數周圍。一個被日誌工具包裝的已棄用函數實際上是由包裝器的每個呼叫者呼叫的,而不是由包含該已棄用函數名稱的任何程式碼呼叫的。要識別這些呼叫者,需要追蹤整個包裝器:日誌工具會呼叫已棄用的函數,因此,日誌工具的每個呼叫者都是已棄用函數的間接呼叫者。這種遞歸呼叫圖遍歷正是徹底的呼叫者清點與表面層級引用搜尋之間的差異所在。
考慮一個典型的 Java 範例,其中透過委託層存取了一個已棄用的方法:
Java的
// Deprecated in the core service
@Deprecated
public BillingResult calculateLegacyFee(Account account) {
// original implementation
}
// Facade that delegates; not visible as a direct caller in a simple reference search
public BillingResult computeFee(Account account) {
return calculateLegacyFee(account); // indirect caller
}
// Actual consumer; calls computeFee, unaware of the underlying deprecated method
public void processMonthlyBilling(List<Account> accounts) {
accounts.forEach(a -> computeFee(a)); // two hops from the deprecated function
}
對“查找所有參考文獻”進行搜索 calculateLegacyFee 返回 computeFee 作為唯一調用者。它不會返回 processMonthlyBilling即,它是已棄用行為的真正使用者。完整的呼叫者清單需要向上游遍歷呼叫圖。 computeFee 找出所有最終呼叫已棄用方法的路徑。
跨語言調用
跨語言呼叫是標準呼叫方發現工具最容易失效的類別。當 Java 服務透過中間件層按名稱呼叫 COBOL 程式、Python 腳本呼叫封裝了已棄用函數的預存程序,或 JCL 作業按 PROGNAME 呼叫內部呼叫了已棄用段落的程式時,這些關係都不會出現在任何單一語言的呼叫圖中。每種語言的工具都只能看到呼叫中屬於它自己的部分。
在大型主機環境中,跨語言呼叫是系統結構的一部分,並且無所不在。 JCL 作業流程會指定它要執行的 COBOL 程式的名稱。 COBOL 程式會依名稱呼叫段落和子程式。複製庫中定義的實用程式段落會被多個程式共用。當複製庫中的某個段落被棄用時,要找到所有呼叫者,就需要了解 COBOL 呼叫關係(哪些程式包含該複製庫,哪些程式呼叫該段落)、JCL 呼叫關係(哪些作業呼叫這些程式)以及任何跨語言介面(與這些程式互動的 Java 或 SQL)。沒有任何單一工具能夠涵蓋所有這些關係。正如對遺留系統靜態分析的分析中所探討的那樣,為現代環境構建的靜態分析工具無法全面了解遺留程序是如何觸發、調用和互連的,尤其是在調用關係同時涉及 JCL、COBOL 和跨系統接口的情況下。
動態調度與反射
有些呼叫者並非透過原始碼中的字面名稱來呼叫函數,而是透過在執行時間解析函數的機制來呼叫:例如 Java 或 .NET 中的反射。 getattr/__call__ 在 Python 中,透過 COBOL 中的後期綁定 CALL identifier透過多態進行動態分發,或在插件框架和配置驅動系統中透過字串調用,這些調用者都不會以任何靜態分析能夠可靠檢測到的形式包含已棄用函數的名稱。
一個配置文件,如果將函數名稱指定為字串,並在運行時加載,用於透過反射來呼叫該函數,那麼它就是在任何原始程式碼分析中都找不到的呼叫者。一個插件框架,如果透過介面發現並調用已註冊的處理程序,那麼它就是一個調用者,在調用圖中僅表現為對分發機制的調用,而不是對任何特定處理程序的調用。識別這些調用者需要結合靜態分析來查找動態分發模式,運行時追蹤來觀察實際調用,以及手動檢查決定分發到哪些函數的配置和註冊邏輯。正如在對混淆和生成程式碼進行靜態分析時所討論的,當執行路徑沒有直接在原始程式碼中表達時,靜態分析必須從結構模式而不是直接的文本引用中重建可能的路徑,而這些重建需要對分發機製本身進行語言感知分析。
開發者首先使用的工具以及他們最終停止使用的工具。
開發者在嘗試發現呼叫者時,會按照一定的順序使用一系列工具,每個工具都會在某個特定的節點停止提供可靠的結果。理解這個順序至關重要,因為即使輸出結果並不完整,每個工具看起來也像是完整的輸出。
IDE呼叫層次結構:在單一專案中可靠
IDE 呼叫層次結構功能是最自然的第一步。 IntelliJ IDEA、Visual Studio、VS Code 和 Eclipse 都提供了某種形式的「尋找所有呼叫者」或「顯示呼叫層次結構」功能,可以遞歸列舉目前專案或工作區索引範圍內所選函數的呼叫者。對於僅在一個程式碼庫和一種語言中使用的函數,這些功能已經足夠準確和充分。
範圍限制在“索引範圍內”非常明確。其他程式碼庫、其他語言執行時期環境,或透過套件管理器而非直接項目引用依賴此程式碼的服務中的呼叫者均不在範圍之內。 IDE 不會指出哪些內容未進行搜尋。開發者會收到一個結果集,但無法了解有多少未被索引的程式碼庫,其中有多少使用了已棄用的函數,也無法判斷「零呼叫者」的結果是指真正的零呼叫者,還是指「此工具可存取的系統中的零呼叫者」。
grep 和文字搜尋:覆蓋範圍廣但結構敏感
當懷疑 IDE 搜尋不完整時,下一步通常是文字搜尋:在可用的原始碼目錄中使用 grep 命令,或透過 GitHub 或 GitLab 程式碼搜尋進行平台搜尋。這大大擴大了搜索範圍,如果其他倉庫可以訪問,也能找到其中的呼叫者。結構性問題在於,文字搜尋尋找的是字串,而不是函數呼叫。它會傳回函數名的每一次出現,包括提及函數的註解、文件字串、出於偵錯目的而命名函數的日誌訊息,以及包含函數名稱但未實際呼叫該函數的字串字面量。此外,它還會遺漏函數名稱與搜尋字串不同的調用者:例如透過別名調用、透過 COBOL 中可能縮寫的部分匹配名稱調用,或透過運行時組裝名稱的動態調用。
文字搜尋結果集需要手動篩選,以確定哪些是實際的呼叫地點,哪些是文件引用,哪些是由於字串衝突導致的誤報。在大型系統中,這種篩選本身就是一項繁重的工作,而且篩選過程無法驗證完整性:如果某個呼叫者因為使用了不同的名稱而被遺漏,篩選後的結果集中不會顯示任何遺漏資訊。
編譯器警告和 @Deprecated 註釋
現代語言和工具鏈提供了棄用註解機制,當呼叫已棄用的函數時會產生警告。 Java 的 @Deprecated 註釋與 -Xlint:deprecation 在調用點產生編譯時警告。 C# 的 [Obsolete] 該屬性會在建置時產生警告。 Go 的命名棄用函數並在 godoc 中進行文件化的約定不會自動產生警告。這些機制很有價值,但存在一個特定的限制:它們僅對針對相同程式碼庫(其中包含棄用標記)進行編譯的呼叫者有效。
呼叫者使用的是舊版的函式庫,早於… @Deprecated 註解不會收到警告。使用二進位檔案而非從原始碼編譯的呼叫者也不會收到警告。使用其他語言並透過跨語言介面呼叫的呼叫者也不會收到警告。關鍵在於,編譯期間產生的警告僅限於編譯器內部:它們只針對編譯器看到的呼叫發出警告,而不會針對其他單獨編譯的倉庫中的呼叫發出警告。在多服務系統中,如果僅使用編譯器警告作為呼叫者發現機制,則會遺漏所有獨立編譯的呼叫者,而這在微服務架構中是常見情況。
靜態分析工具:更好,但範圍有限
專用靜態分析工具比整合開發環境 (IDE) 更能準確地列舉目標語言的呼叫者,並且如果配置為索引多個程式碼庫,通常可以跨越程式碼庫邊界。它們構建的是合適的調用圖,而不是依賴文字匹配,能夠更好地處理別名和間接調用,並且可以在持續集成 (CI) 管線中運行,以便在新增呼叫者時立即捕獲它們。它們是目前功能最強大的單一語言方法。
這個限制與限制整合開發環境 (IDE) 的作用域邊界相同,但現在是在工具層面:Java 靜態分析工具無法索引 COBOL 程序,COBOL 分析器無法索引 Java 服務,也無法索引 JCL 作業流程。在一個系統中,如果被棄用的函數是一個 COBOL 實用程序,它由 COBOL 程式調用,而 COBOL 程式又由 JCL 作業調用,其資料輸出又被 Java 服務使用,那麼每個靜態分析工具只能看到呼叫關係的一部分。正如在「基本重構技術」的背景下所探討的那樣,要識別給定程式碼段的所有執行路徑(包括罕見的錯誤情況和回退分支),需要建立完整的呼叫圖映射,而單語言工具無法跨語言邊界建構這種映射。
完整的來電者資訊清單究竟需要哪些內容?
企業系統中已棄用函數的完整呼叫者清單並非搜尋結果,而是對所有可能到達該函數的執行路徑進行結構化枚舉,包括直接路徑、間接路徑、跨語言路徑和動態分派路徑。建立此枚舉需要多種功能,而這些功能目前尚無任何標準工具能夠提供。
統一的跨語言呼叫圖。此呼叫圖必須涵蓋系統中的所有語言。從 JCL 過程到 COBOL 程式的調用、從 COBOL 程式到共享實用程式段落的調用,以及從 Java 服務透過中間件介面到同一 COBOL 程式的調用,都必須是同一張圖中的節點和邊。已棄用的函數是該圖中的一個節點,呼叫者列舉是對所有入邊(包括直接邊和傳遞邊)的遍歷,無論這些入邊源自哪種語言。
對整個呼叫圖進行遞歸遍歷。直接呼叫者只是第一層。要完整清點調用,需要沿著調用圖向上游追溯,經過間接調用者、包裝函數和外觀層,直到遍歷到自身沒有調用者的函數,這些函數才是調用鏈的真正入口點。路徑中所有以已棄用函數為終點的函數,在相關意義上都是呼叫者:移除已棄用函數會破壞所有經過它的路徑。
跨倉庫索引。呼叫圖必須包含所有可能呼叫該函數的倉庫中的程式碼,包括透過共用程式庫或套件依賴該函數的倉庫。這需要同時索引所有倉庫,並解析跨倉庫的導入關係,將一個倉庫中的呼叫與另一個倉庫中的定義關聯起來。
檢測間接呼叫模式。分析必須識別透過反射、動態分派、函數指標、委託以及設定檔中基於字串的呼叫而進行的呼叫。這需要基於模式的偵測,而不是直接的呼叫邊界解析:即在程式碼中找到動態分派機制,並確定在哪些條件下它們可以分派到哪些函數。
區分活躍呼叫者和僅用於測試或已失效的呼叫者。並非所有呼叫者都需要相同的回應。僅存在於已棄用函數自身測試案例中的呼叫者需要作為清理工作的一部分移除,而不是遷移。透過使用情況分析識別為已失效程式碼的程式碼中的呼叫者不會阻礙函數移除。理解這些差異需要將呼叫者枚舉與實際處於活動狀態的程式碼路徑資訊結合。如同透過靜態分析檢測已失效程式碼的探討中所詳述的,由於文件不完整或對歷史依賴關係的不確定性,無法存取的程式碼和未使用的函數可能會在關鍵任務系統中持續存在數年,因此已棄用函數的呼叫者清單必須區分自身處於活動狀態的呼叫者和自身已失效的呼叫者。
從棄用到移除的流程:一種結構化方法
將棄用函數的移除視為單一事件而非結構化流程是導致大多數呼叫者發現失敗的根源。正確的做法是將移除視為多階段流程的最後一步,而該流程早在任何程式碼被刪除之前就已經開始。
第一階段:標記和測量
第一步是使用語言的內建機制將函數標記為已棄用(@Deprecated 在 Java 中, [Obsolete] 在 C# 中, #[deprecated] 在 Rust 或對應的等效語言中)並建立一個基準調用者數量。該基準並非任何單一搜尋的結果;而是對所有可能調用該函數的已知程式碼庫進行索引並統計結果的結果。此基準有兩個用途:量化遷移範圍,並提供一個參考值,用於衡量調用者遷移過程中的進展。
基線應依呼叫者類型和位置組織:
| 來電者類別 | 計數 | 優先 | 所有者 |
|---|---|---|---|
| 同一儲存庫中的直接呼叫者 | N | 高 | 目前的團隊 |
| 依賴服務的直接呼叫者 | N | 高 | 服務所有者 |
| 透過包裝函數調用 | N | 媒材 | 包裝商擁有者 |
| 產生的或框架程式碼中的呼叫者 | N | 媒材 | 框架團隊 |
| 僅用於測試的程式碼中的呼叫者 | N | 低 | 目前的團隊 |
| 死區來電 | N | 僅清理 | 目前的團隊 |
第二階段:通知與遷移
有了完整的呼叫者清單,遷移變成了一項有組織的行動,而不是被動的回應。每個呼叫者所有者都會收到特定的呼叫位置通知:不是“您可能正在呼叫此函數”,而是“您在第 247 行呼叫此函數”。 BillingService.java第 82 行 AccountProcessor.java,並且在第 14 行的整合測試中 BillingServiceTest.java「這種程度的精確性正是呼叫者清單所能提供的,也是通用棄用警告無法提供的。
在發布通知的同時提供遷移路徑至關重要。棄用說明應包含替代函數的文件、新舊實作之間任何行為差異的描述,以及在變更較為複雜的情況下,提供變更前後的程式碼範例。對於其他團隊程式碼庫中的呼叫者,遷移時間表應明確協商,而非單方面宣布,因為這些團隊有各自的優先順序和交付承諾。正如在跨依賴系統的資料庫重構中所探討的那樣,在棄用舊結構之前逐步引入新結構的使用者,是防止破壞性變更以意外事件形式出現的關鍵所在。
第三階段:監控來電人數
在基準測量和計畫移除日期之間,應持續監控呼叫者數量。每次呼叫者遷移到替代函數時,計數都會減少。當活躍呼叫者(僅用於測試和無效程式碼的呼叫者可能與函數本身同時移除)的計數降至零時,即達到移除閾值。持續監控要求將呼叫者列舉作為持續整合 (CI) 管線的一部分按計劃運行,而不是依賴會隨著程式碼變更而過時的一次性清單。
監控還能捕捉棄用期間新增的呼叫者。在大型組織中,遷移期間經常會出現新程式碼呼叫已棄用函數的情況,原因可能是開發人員不了解該函數已被棄用,程式碼審查遺漏了這一點,或者自動程式碼產生器產生的程式碼呼叫了已棄用函數。針對已棄用函數的持續整合 (CI) 層級呼叫者偵測,配置為在新呼叫點失敗,可防止在遷移過程中呼叫者數量持續成長。
第四階段:移除前核實完整性
在移除函數之前,應針對所有已知程式碼庫的完整範圍,最後一次執行呼叫者列舉。此最終檢查起到安全門的作用:它確認活躍呼叫者的計數已降至零,並識別出持續整合 (CI) 監控未捕獲的任何後期新增程式碼。此時,清單還應驗證是否存在動態呼叫者:例如,透過字串引用函數的設定檔、基於反射的註冊,以及在初始分析期間識別出的任何其他間接呼叫機制。
驗證範圍應涵蓋所有暴露已棄用函數的共用程式庫或套件的依賴關係圖。如果函數是外部使用者使用的公共 API 的一部分,則移除時間表必須考慮到可能無法透過內部程式碼分析觸及的外部使用者。對於內部系統,驗證範圍涵蓋所有已索引的程式碼庫。對於公開發布的 API,驗證範圍涵蓋已知的使用者集合以及一個已定義的過渡期,在此期間外部使用者必須遷移。
傳統系統和大型主機環境下來電發現機制的差異
上述挑戰適用於任何大型軟體系統,但在大型主機和遺留環境中尤為突出,因為這些環境中的呼叫關係是透過現代呼叫者發現工具無法分析的機制來表達的。
在 COBOL 環境中,函數透過 CALL 語句調用,這些語句可以透過字串字面值、包含程式名稱的資料項或過程指標來引用目標。字串字面值的情況可以透過靜態分析來解決;資料項的情況需要進行資料流分析,以確定資料項在呼叫時可能持有的值;而過程指標的情況則需要追蹤指標的賦值方式。每種呼叫機制在原始碼中的表現形式都不同,因此需要不同的分析方法才能解決。
在 JCL 環境中,程式透過 EXEC PGM= 語句以名稱呼叫。程式名稱是一個字串,它映射到載入庫中已編譯的模組。要透過 JCL 追蹤 COBOL 程式的呼叫者,需要解析 JCL 以提取程式名稱,將這些名稱對應到實作它們的已編譯 COBOL 程序,並確定這些程式中的哪些 COBOL 段落呼叫了已棄用的實用程式。這種多步驟的解析完全超出了單獨運行的 COBOL 分析器或 JCL 分析器的能力範圍。
共享副本在 COBOL 環境中尤其重要。副本中定義的已棄用段落可能透過 COPY 語句被多個程式包含。該段落並非在每個程式中實際複製,而是在編譯時被包含。如果分析方法僅統計來源檔案中段落名稱的出現次數而不考慮副本包含關係,則會導致計數過高(在副本本身中找到段落定義)和計數過低(忽略了每個包含該副本的程式都可以存取該段落這一事實)。要正確發現呼叫者,需要了解哪些程式包含哪些副本,以及它們實際呼叫了這些副本中的哪些段落。硬編碼引用與其下游用戶之間的關係說明了為什麼在任何結構更改之前解決這些程式級呼叫關係至關重要:看似簡單的字串引用可能是數十個程式實現關鍵功能的唯一機制。
SMART TS XL 建置完整的來電者檔案
SMART TS XL 它在索引環境中建構一個跨所有語言、平台和儲存庫的統一呼叫圖。 COBOL 程式、JCL 作業流程、Java 服務、.NET 應用程式、SQL 預存程序、Python 腳本和其他原始碼工件都會使用特定於語言的分析方法解析到通用的交叉引用圖中。每個函數、段落、過程、方法和程序單元都是該圖中的一個節點。每個呼叫關係,無論是 COBOL CALL 語句、Java 方法呼叫、JCL EXEC PGM 或 SQL EXEC,都是一條類型化的邊。此圖表示系統的完整呼叫拓撲結構,而不是每種語言的部分視圖。
當一個函數被標記為移除時, SMART TS XL呼叫者枚舉從目標函數節點開始,遍歷呼叫圖,收集呼叫層次結構中每一層的所有呼叫者。遍歷是遞歸的,沿著呼叫圖依序經過包裝函數、外觀層和中間工具,直到到達沒有呼叫者的函數,這些函數代表呼叫鏈的真正入口點。結果按語言、程式碼庫、呼叫者類型和呼叫深度進行組織,為團隊提供了一個結構化的清單,將直接呼叫者與間接呼叫者、活動呼叫者與無效呼叫者區分開來。
此平台的分析功能將其擴展為結構化的變更影響報告:不僅列出哪些函數呼叫了已棄用的函數,還列出依賴鏈中各個層級受影響的程式、服務、批次作業和 JCL 流程。這份報告是使棄用到移除流程可操作的關鍵:它明確了責任人,識別了具體的調用位置,並量化了在安全移除之前所需的遷移範圍。如同在企業變更管理的影響分析詳細探討中所述,在進行結構性變更之前枚舉受影響的元件是確保複雜、互聯的企業系統安全運作的基礎要求。
SMART TS XL 它還支援棄用流程的持續監控階段。由於交叉引用圖會隨著原始碼變更的索引而不斷更新,因此已棄用函數的呼叫次數始終保持最新。 CI 管線整合允許自動檢查在新呼叫已棄用函數時失敗,從而在引入新程式碼時強制執行遷移規範,而不是事後發現違規行為。這種初始枚舉、遷移指導和持續監控的組合涵蓋了已棄用函數從註解到安全移除的整個生命週期。
無悔功能移除
順利移除函數和導致生產環境崩潰的函數移除之間的區別,幾乎總是在於呼叫者發現的完整性。移除本身很簡單:刪除定義並部署即可。真正的困難在於準備工作,而準備工作的完善程度取決於其所依據的呼叫者清單的品質。
在呼叫圖較淺、僅使用一種語言且位於單一程式碼庫內的系統中,IDE 的呼叫層次結構和編譯器警告足以應付。但在呼叫圖跨越多種語言、多個程式碼庫、多個平台,甚至可能包含數十年程式碼的系統中,這些工具只能覆蓋實際呼叫者表面的一小部分,而且這部分內容還無法完全了解。它們傳回的資訊與實際呼叫函數的資訊之間的差距,正是生產環境中故障的根源。
專門建置的跨語言、跨程式碼庫的呼叫者枚舉並非是對開發人員移除函數工作流程的改進,而是在任何足夠複雜的系統中安全執行該工作流程的先決條件。這些複雜的系統會累積企業程式碼庫中已棄用函數通常所包含的那種跨系統呼叫關係。每個在沒有完整呼叫者清單的情況下移除的已棄用函數,都會導致版本發佈時出現未知數量的運行時故障,這些故障會等待到達缺少定義的特定執行路徑。消除這種未知故障正是結構化呼叫者發現的目的。