奚耀國 沈立煒 趙文耘
(復旦大學軟件學院 上海 201203)(復旦大學上海市數據科學重點實驗室 上海 201203)
應用程序接口(API)是軟件開發過程中不可或缺的部分,它封裝了類庫和框架的某個功能,開發者無須了解其內部構造只需調用接口就可以快速地編寫程序。開發者傾向于在開發中使用API以避免重復工作[1]并提高軟件系統的可重用性[2]。框架和類庫通常會使用升級版本的方式來提供新的功能或修復缺陷,此過程經常會變更原先提供API。變更的API通常會導致客戶端在升級類庫版本時無法正常運行。為了避免API變更造成客戶端程序無法兼容的情況發生,類庫開發人員往往不會直接更改或移除API,而是將變更的API標記為棄用,在之后的版本中逐步將其移除[3-4]。在此機制下,開發者可以在棄用API被移除之前對其進行遷移[5],從而提升程序的功能性、性能與安全性[3]。
由于API文檔經常出現缺失遷移信息的情況[3,6-7],開發者更習慣于在網絡中搜索替換API及其代碼示例。問答網站Stack Overflow存在很多棄用API的討論帖,其中包含對替換API及其使用方式的介紹。然而由于討論帖數目較多且開發者的問題描述經常與遷移棄用API的詞匯存在差異,因此在尋找替換API及其代碼示例的過程中會耗費大量時間,搜索結果往往也不夠全面。盡管現有的技術可以幫助開發者快速搜索代碼示例[8-9],但搜索結果包含很多開發者不關心的元素,使得代碼可讀性差。同時,這些技術并未對搜索結果進行篩選排序,開發者仍需花費時間從搜索結果中篩選具有參考價值的代碼示例。
針對上述問題,本文提出基于問答平臺的棄用API遷移建議推薦技術,該技術旨在通過快速提供包含與文本描述和代碼示例的遷移建議來提高開發者遷移棄用API的效率。具體而言,該技術首先結合棄用API相關元素、標簽和關鍵詞組成的搜索條件在Stack Overflow中搜索討論帖。在對討論帖進行分析之后為回答生成回答快照,回答快照包括文本信息、代碼示例、回答本身的附加信息。之后根據替換API對回答快照進行分類,以快照集的形式表示分類結果。接著根據回答快照的附加信息從兩個維度上對快照集和回答快照進行排序。最后依據替換API對回答快照中的代碼示例進行簡化。與現有的遷移技術相比,該技術的優勢有:1) 開發者無須提供替換API即可得到包含文本描述和代碼示例的遷移建議;2) 生成的遷移建議將會以特定的規則進行排序,以方便開發者參考;3) 為了幫助開發者更快地掌握替換API的使用方式,該技術會根據替換API移除代碼示例中無關的元素,提供清晰簡潔的代碼示例。本文基于此技術實現了遷移建議推薦工具并組織了用戶實驗。實驗結果表明該工具能夠顯著地提高開發者遷移棄用API的效率。
手動遷移棄用API需要耗費大量的時間與精力,針對此問題,研究者提出了輔助開發者遷移棄用API的技術。Dig等[10]將類庫演化過程中API的變更分為結構變更和行為變更。結構變更表示變更了API對應方法的方法簽名,此類變更會導致客戶端程序無法成功編譯執行,行為變更表示改變了API的功能。Kapur等[11]開發了遷移工具Trident,開發者輸入棄用API和替換API,該工具即可自動掃描項目中的棄用API并將其替換為指定的API。但該工具僅能從文本上對棄用API進行替換,并未適配代碼上下文。Strobl等[12]開發了兩個工具用來遷移棄用API。Generator可以根據一些啟發式規則生成.xml格式的配置文件,而JaSCUT則根據配置文件對源碼中的棄用API進行遷移。然而該工具僅能遷移棄用API的名稱,無法從更細粒度的級別進行遷移。Henkel等[13]開發了Eclipse插件Catch!,該工具可以記錄開發者遷移棄用API的操作,并將這些操作回放到相同的棄用API上。但是該工具需要類庫提供者花費額外的時間錄制腳本,同時由于代碼上下文不同,回放結果經常不能滿足用戶的需要。Dagenais等[14]開發了棄用API遷移推薦系統SemDiff,該系統通過分析類庫在標記棄用API時如何適應自身的變更來抽取遷移策略。以上方法在一定程度上提升了開發者遷移棄用API的效率,然而這些方法經常受到文檔和類庫代碼質量的約束,遷移效果往往不能滿足用戶的需求。
Vásquez等[15]發現API的變更會引發Stack Overflow中關于變更API的討論。Vasilescu等[16]調研了問答網站對開發者的影響,結果表明盡管參與問答過程會花費時間,但是卻能夠在一定程度上提升開發者的開發效率。Rahman等[9]開發了代碼搜索插件RACK,該插件結合IDE中代碼上下文自動從Stack Overflow和Github中搜索代碼示例。Gu等[17]利用深度學習將API序列與自然語言關聯起來,在開發者搜索時可以為其推薦包含相關API序列的代碼示例。李宇琨等[8]將Stack Overflow中的問答信息對應到相關代碼元素上,再利用代碼元素從Github中搜索代碼示例。
與上述研究相比,本文方法可以在開發者不指明替換API的情況下為其提供替換API的描述和代碼示例。同時,為了便于開發者參考,結果將以特定的規則進行排序。此外,該方法會根據替換API簡化代碼示例,使得代碼示例更加清晰。
圖1展示了棄用API遷移建議推薦技術的方法流程,其中:圓角矩形表示組件;矩形表示輸入與輸出;箭頭上的文字表示組件的輸入與產出。該過程以棄用API的相關信息為輸入,經過問答帖收集器、快照生成器、分類器和優化器等組件的加工步驟后,生成遷移建議。

圖1 棄用API遷移建議推薦技術方法流程
棄用API的相關信息不僅包含棄用API的所屬類、方法名、參數的類型與數量,還包括API文檔中的遷移信息。問答帖收集器可以根據棄用API的元素從Stack Overflow中抽取相關帖子及其附加信息,并對帖子進行篩選過濾,生成回答列表。快照生成器以特定的規則分析帖子中的回答,生成回答快照。回答快照記錄了帖子中某個回答的關鍵信息,包括文本信息、代碼示例、該回答的附加信息。分類器可以從替換API的角度對快照進行分類,產生不同的快照集。最后,優化器根據特定的規則,參考文檔中的遷移信息,從兩個維度上對快照進行排序。同時還會對回答中的代碼示例進行簡化,移除無意義的語句或表達式,從而使遷移建議更加清晰。
問答帖收集包括搜索和篩選兩個步驟。搜索步驟是指根據棄用API和關鍵詞組成的搜索條件從Stack Overflow中搜索相關問答帖的過程。篩選步驟的目的是去除搜索結果中的重復帖子或與目標棄用API無關的帖子。
Stack Overflow提供了不同類型的搜索功能,用戶可以從不同的維度上搜索相關問題,例如標簽、回答、用戶、投票數、是否有被接受的回答、關鍵詞等維度。本文工作以“[deprecated]+{alternative deprecate…}+{棄用API名稱}”作為搜索模板,根據棄用API填充搜索模板生成搜索條件,調用Stack Exchange提供的接口從Stack Overflow中搜索問答帖,之后經過篩選過濾選取足夠數量的回答。
在搜索問答帖的過程中經常會遇到搜索結果太少或結果中排序靠后的帖子相關性不高的情況。針對這一問題,本文結合Stack Overflow的某些特征來改善搜索策略。Stack Overflow會為相似問題的帖子打上“[duplicate]”標記。同時會在問題的開始部分展示與該問題相似的帖子鏈接。利用這一特征可以收集到更多的問答帖,在搜索帖子時,如果發現標題中有該標記,則同時收集此帖子中指示的相似問答帖。除此之外,本文還通過變更搜索條件來擴大搜索范圍,此方式稱為降維搜索,即刪減部分關鍵詞或去除搜索條件中的“[deprecated]”標簽來重新組織搜索條件。
搜索結果中包含一些不相關的問答帖,例如非Java語言或討論內容與輸入的棄用API不一致的帖子。因此需要對搜索結果進行過濾。此過程從兩個方面進行,一方面去除無關問答帖,只保留與棄用API有關的帖子,另一方面移除帖子中低質量的回答。
篩選問答帖的規則如下:1) 移除沒有回答的討論帖。遷移建議主要從回答中產生,因此只考慮有回答的討論帖。2) 篩選Java語言(包括安卓)相關的討論帖。本文工作提出的技術只適用于Java語言,暫不考慮對其他語言的支持。3) 篩選與輸入棄用API相關的討論帖。盡管討論其他API的帖子可能存在一些有用的信息,但這種情況很少出現,故排除此情況。具體操作是首先移除回答數為0的帖子,之后通過判斷問答帖標簽中是否包含與編程語言有關的標簽來確定帖子關聯的編程語言,若沒有此類標簽則從標題和文本中提取編程語言關鍵詞,移除非Java語言的帖子。最后通過文本匹配的方式在帖子的標題和正文中匹配棄用API的名稱,將匹配失敗的帖子從列表中移除。
篩選回答的規則是將投票數少于0且沒有代碼示例的回答從列表中移除。具體操作是根據帖子得到回答的ID列表,再根據ID列表依次得到回答的信息,例如文本信息、投票數或回答用戶。在回答的文本中匹配
標簽,帖子中的代碼示例都是用此標簽包裹的,若沒有此標簽則證明該回答中不包括代碼示例。將上述兩個條件都不滿足的回答從帖子中刪除,之后再次判斷各個帖子的回答數重新篩選問答帖。在問答帖收集的過程中需要記錄帖子的相關信息,例如帖子在搜索結果中的順序、投票數、回答數、回答的投票數、回答有無代碼示例。這些信息將作為對遷移建議進行排序的依據。
3.2 回答分析與快照生成
快照生成器可以分析帖子中的回答并生成回答快照。回答快照包括文本部分、代碼部分、附加信息。文本部分指回答文本中包含方法調用或代碼元素的語句。這些語句通常包含著對棄用API的替換建議,甚至是對替換API使用方法的介紹。代碼部分指與遷移建議有關的Java代碼示例。附加信息指回答的額外信息,例如回答中包含的API集合、回答所屬帖子的相關信息、回答本身的相關情況等信息。
文本部分由回答中包含方法調用的語句組成。對于回答中的文本信息,首先以句子為單位將文本分割成語句列表。語句列表中的語句除了包含純本文之外,還包括HTML標簽,例如、等。接著依次對語句列表中的語句進行分析。對于任意語句,如果符合任意以下規則則屬于文本部分:1) 語句中包含方法調用。使用表示方法調用的正則表達式進行匹配,如果匹配成功則表示語句中包含方法調用。2) 語句中包含標簽。以包裹的單詞表示代碼元素(例如方法調用或類型名稱),這些元素通常代表了可供選擇的替換建議。3) 被標簽包裹的語句。此類型的語句通常是引用API文檔或其他官方說明的語句。4) 語句中存在超鏈接。在語句中通常以超鏈接的形式表達關鍵信息,如果該超鏈接不是URL則將其認定為關鍵信息。5) 語句中存在replaced with/by等表示替換的單詞或短語。該步驟的實現方式是首先判斷語句中是否包含或標簽,如果包含則屬于文本部分。之后判斷語句中是否包含非URL的超鏈接,如果包含滿足條件的超鏈接,則此語句屬于文本部分。接著使用表示方法調用的正則表達式匹配語句文本,若匹配成功則此語句屬于文本部分。最后判斷語句中是否存在表示替換含義的單詞或短語,若存在這些單詞或短語則此語句屬于文本部分。
代碼部分由回答中所有的Java代碼片段組成。Stack Overflow中使用
標簽組合包裹代碼片段。一個回答中可能包含多個代碼片段且部分代碼片段可能與替換API無關,例如由其他語言編寫的代碼或不包含API的代碼。對于任意代碼片段,如果符合以下規則則屬于代碼部分:1) 代碼由Java語言編寫。2) 至少包含一個方法調用語句。3) 內容不是Exception輸出信息。附加信息是對回答進行排序的重要依據,包括回答包含的API集合、回答所屬的帖子、回答所屬帖子在搜索結果中的排序、回答的時間、是否被接受和投票數等信息。API集合由文本部分和代碼部分中出現過的方法調用組成。附加信息中的其他部分可以很容易地通過解析HTML文本獲得。
圖2展示了Stack Overflow中關于遷移棄用API CharMatcher.javaDigit()的回答。該回答中回答者引用了官方文檔對該棄用API的解釋,同時提出了遷移該棄用API的建議,最后給出了替換API的代碼示例。通過上述步驟為該回答生成回答快照,圖中下劃線選中的語句為文本部分,矩形框選中的部分為代碼部分,圖中下半部分展示了分析該回答得到的附加信息。

圖2 回答快照示例
3.3 回答快照的分類
在生成回答快照后,按照附加信息中的API集合對其進行分類。API集合中的API可以分為兩種類型:關鍵API(K_API)和普通API(N_API)。如果某個API同時存在于一個回答的文本部分和代碼部分中,或該API是棄用API文檔的遷移信息中指示的替換API,則此API為關鍵API。若該API只存在于兩個快照中的其中一個,則為普通API。
在本文工作中,我們認為同時出現在文本部分和代碼部分中的替換API應該是回答者更推薦的API,同時官方文檔中描述的替換API同樣值得被推薦。因此,為了得到更加精準、有價值的替換API,回答快照將根據關鍵API進行分類。回答快照的分類結果是若干個快照集,快照集的類型由關鍵API決定,即一個關鍵API對應一個快照集。在分類之前,首先收集所有回答快照中的關鍵API,對關鍵API進行去重后為每一個關鍵API生成快照集。在對快照進行分類時,依次遍歷API集合中的API。對于任意一個API,如果有對應的快照集,則將該API所屬的回答快照放入對應的快照集。對于沒有對應快照集的API,則將其忽略。由于回答快照中可能包含多個API,因此一個回答快照可能會被放入多個快照集。
圖3是對回答快照進行分類的示意圖。圖中n個快照中有四個關鍵API(A,B,C,D),因此可以分為四類并產生四個快照集。快照1有五個API(A,B,C,E,F),其中A、B、C分別能找到對應的快照集,可以將快照1放入相應的快照集。剩余的兩個API(E,F)無法找到對應快照集,因此將它們忽略。其余的快照可以使用相同的規則將其加入到快照集。

圖3 回答快照分類示意圖
3.4 回答快照的排序
對回答快照進行排序可以幫助開發者更快地確定替換API進而完成遷移工作。本文從兩個維度上對其進行排序:1) 對同一個快照集內的回答快照排序。2) 對代表不同替換API的快照集排序。
快照集包含多個回答快照,可以根據快照的附加信息對其打分并根據最后的分值進行排序。表1展示了快照集內回答快照的評分規則,并列出了各個規則下可能的分值。以下是對評分標準的詳細介紹。
1) 所屬帖子在搜結果中的順序。帖子在搜索結果中越靠前則分值越高。排名最高帖子中的回答評分為5,隨著排名下降,分值依次減1,最低為1分。不同的搜索輪次有不同的權值。使用完整的搜索條件搜索到的帖子權值為4,在減少搜索條件后,權值相應減少。刪減部分關鍵詞權值為3,移除標簽[deprecated]或完全刪除關鍵詞權值為2,若只使用棄用API的名稱進行搜索則權值為1。搜索過程中重復的帖子(即被[duplicate]標記的帖子)擁有相同的權值。回答快照在此部分中的評分是權值與分數的乘積。
2) 回答是否被接受。被提問者接受的回答應該有更高的分數。在此部分中,被接受的回答快照的評分為10,其余的回答快照沒有評分。
3) 投票數。投票數的高低表明回答被認可的程度。回答快照在此部分中的評分為獲得投票的數量。
4) 回答快照的完整性。代碼部分通常比文本部分更具有參考價值。若快照中包含代碼部分,則評分加2,若包含文本部分,則評分加1。因此,如果回答快照同時包含上述兩個部分,則評分為3。
5) 回答下的評論。評論在一定程度上可以反映回答被關注的程度。若包含兩條以上非作者本人的回答,則評分為3。若除作者以外的評論者大于等于兩人,則評分為5。其余情況在此部分中的評分為1。
6) 回答者的聲望。回答的質量與回答者的聲望有關聯。若回答者的聲望大于10 000,則評分為3。若回答者的聲望處在1 000至10 000之間,則此回答的評分為2。聲望小于1 000的回答者的回答評分為1。

表1 快照集內回答快照的評分規則
回答快照的最終評分等于以上各部分評分的和。評分高的回答更具備參考價值。快照集中的回答快照最終將以評分逆序的形式進行排序。在此過程中可能會出現評分相同的回答快照,本文根據回答時間對評分相同的快照進行排序,回答時間越晚則排名更靠前。
每一個快照集代表一個替換API,對快照集進行排序可以使開發者在遷移過程中快速選擇合適的替換API。此步驟同樣以評分的方式對快照集進行排序。表2展示了快照集的評分規則,并列出了各個規則下可能的分值。以下是對評分標準的詳細介紹。
1) 文檔遷移信息中的替換API。文檔中的遷移信息由類庫的維護者提供,相比其他途徑,從遷移信息中獲得的替換API更能夠滿足開發者的需求。因此,此過程中文檔提供的替換API對應的快照集評分為10。代表其他替換API的快照集沒有評分。
2) 快照集包含的快照數。快照集中的回答快照數量反映了對應替換API被推薦的程度。包含最多快照數量的快照集評分為10,隨數量的降低依次減少1分,最低評分為1分。
3) 快照集中排名前三的快照評分總和。回答快照的評分已經反映了替換API被認可的程度,可以參考快照評分對快照集進行排序。由于不同快照集包含的回答快照數量不同,同時為了避免低質量的回答對平均值的影響,此過程中使用每個快照集中排名前三快照的評分總和作為評分依據。評分總和最多的快照集評分為10分,隨著評分總和的降低依次減少1分,最低評分為1分。

表2 快照集的評分規則
與對回答快照進行排序的方式相同,此步驟同樣以各部分的評分和作為排序依據,并以評分逆序的形式作為最終結果。因為快照集的數量有限,此步驟不需要對評分相同的快照集進行額外的排序。
3.5 代碼示例的簡化
回答快照中的代碼示例通常包含著很多API,使得替換API的用法不能被很清晰地呈現出來。為了幫助開發者快速掌握替換API的使用方法,本工作中會根據替換API對回答快照中的代碼示例進行簡化。
抽象語法樹是代碼分析的基礎,該步驟需要為待簡化的代碼示例建立抽象語法樹,以此來分析示例中替換API與上下文的關系。然而,Stack Overflow中的代碼示例通常是無法單獨編譯運行的代碼片段。傳統的抽象語法樹解析器(例如JavaParser)無法解析這些代碼片段[18]。本文通過正則表達式從示例中匹配代碼結構并將其組織成抽象語法樹的形式,從而為代碼片段生成抽象語法樹。
代碼示例通常是以方法聲明或語句(Statement)為單位呈現的,因此本文忽略了方法聲明及以上的結構類型,同時也忽略了不常見的結構,例如Lambda表達式等。表3展示了部分結構類型及相應的示例。其中包含常見的選擇結構(if,switch)和循環結構(while,do-while,for,foreach),也包含了普通的表達式結構,例如變量聲明(VarDeclare)、方法調用(MethodCall)和賦值表達式(Assign)。此外還包含一些語句結構,例如方法返回值結構(ReturnStmt)和異常處理結構(TryStmt)。除了表3中列出的結構,該步驟還對一些更基礎的結構(例如二元表達式、字符串表達式等)做了相似的處理。

表3 抽象語法樹的部分結構類型
本文通過分析代碼示例中不同語句與替換API關系來對代碼示例進行簡化。首先從抽象語法樹中定位替換API的使用位置,并從替換API中抽取元素(即API調用者和參數)。之后遍歷樹中的節點,找到與這些元素相關的節點。元素與節點之間的相關性分為兩種類型:1) 運行該節點的代碼會導致元素的狀態發生改變,這種相關性稱為寫相關。2) 該節點的代碼只是使用元素進行了其他的操作,未改變元素的狀態,這種相關性稱為讀相關。寫相關的節點包括元素被賦值的賦值表達式、聲明元素的變量聲明語句、元素作為調用者或參數的方法調用。讀相關的節點包括元素參與的賦值表達式或變量聲明等語句。該步驟僅考慮寫相關的節點,從寫相關的節點中分離出會決定這些元素的其他元素。例如變量A是變量B經過一系列操作后得到的,則變量B的改變會導致變量A改變,即變量A由變量B決定。重復上述過程,找到其他元素對應的寫相關的節點,直到找到所有與替換API元素有寫相關關系的節點。最后將這些寫相關節點的訪問類型設置為“WRITE”,從抽象語法樹中移除訪問類型不為“WRITE”的節點,剩余的節點可以轉化為簡化后的代碼示例。簡化結果取決于替換API,根據不同的替換API簡化同一段代碼示例會產生不同的結果。
算法1展示了簡化代碼示例的過程。該算法以rAPI(替換API)和AST(抽象語法樹)為輸入,通過分析后確定AST中與替換API元素具有寫相關關系的節點,在修改這些節點的訪問類型后返回整個AST。首先根據替換API從AST中定位對應的節點(第2行),并從該節點中提取替換API的元素,放置到有序集合elements中(第3行)。依次遍歷elements中的元素,對于每一個元素,從AST中搜索所有與該元素有寫相關關系的節點,并放置到列表nodes中(第5行)。之后遍歷nodes中的節點,從這些節點中搜索可以決定elements中元素的相關元素,并將這些元素添加至elements的末尾(第6-第9行)。在添加元素時,elements會過濾重復的元素,因此不會出現死循環的情況。最后,將AST中與elements中的任意元素有寫相關關系節點的訪問類型設置成“WRITE”并返回AST(第11-第16行)。
算法1根據替換API簡化代碼示例算法
1 function Code_Simplify(rAPI,AST)
2 rNode ← find(rAPI,AST)
3 elements ← extract(rNode)
4 for all e∈elements do
5 nodes ← findNodeByElement(e,AST)
6 for all n∈nodes do
7 relatedElements ← findRelatedElement(n,elements)
8 elements.addAll(relatedElements)
9 end for
10 end for
11 for all n∈AST do
12 if accessWrite(n,elements) then
13 n.accessType ← WRITE
14 end if
15 end for
16 return AST
17 end function
算法1中判斷節點之間的關系是通過數據流的方式實現的。現有技術無法對代碼片段生成數據流圖,因此,本文采用了較為簡單的文本匹配的方式來匹配不同語句中相同的變量,以此為不同節點中的變量建立數據流關系。該方法建立的數據流關系基本可以滿足確定節點之間關系的需求。
圖4展示了根據替換API簡化代碼示例。圖中左半部分是未簡化過的代碼示例,右半部分是使用上述方法對其進行簡化后的代碼示例。該示例中的替換API是Calendar.get()。該代碼示例對應的抽象語法樹如圖4所示。其中括號中的數字表示該節點對應代碼中的行號。在對該代碼示例進行簡化時,首先確定替換API的使用位置。從替換API中可以提取出元素cal和Calendar.YEAR,由于參數Calendar.YEAR是常量,因此只需要對cal進行分析。根據算法1,與cal有關的節點對應的代碼是第5-第7行。在這幾行中,可以決定cal的元素只有date,對date進行分析后得出第3行對應的節點與該元素有寫相關關系。最終將第3、第5-第7行代碼對應節點的訪問類型設置為“WRITE”。圖5中矩形框選中的節點表示訪問類型為“WRITE”的節點。將這些節點翻譯成代碼得到簡化后的代碼示例。

圖4 簡化代碼示例

圖5 代碼示例的抽象語法樹
4 工具與實驗
4.1 工具介紹
基于上文介紹的技術,我們設計并開發了棄用API遷移輔助工具,圖6展示了該工具的用戶界面。該工具是一個桌面客戶端應用,用戶可以很方便地使用該工具對棄用API進行遷移。

圖6 棄用API遷移建議推薦工具用戶界面
用戶首先點擊左上角的“打開項目”按鈕,選擇客戶端項目加載到工具中。工具會掃描項目中的Java文件并檢測棄用API,同時以刪除線的形式標記棄用API。用戶點擊棄用API所在行的“遷移”按鈕后,該工具會顯示替換API和遷移建議。替換API列表展示了問答帖中所有回答推薦的替換API。點擊其中的替換API,右下方會顯示對應的遷移建議。遷移建議展示了一個快照集中經過排序的回答快照,每個遷移建議包含所屬問答帖的標題、文本信息、代碼示例。用戶可以點擊標題右側的“打開原帖>>”即可跳轉至Stack Overflow中該帖子的網頁。此外,用戶點擊“遷移建議”右側的“只看代碼”即可屏蔽遷移建議的文本信息。
此外,該工具還提供了一些額外的基礎功能,例如打開項目、代碼文本編輯器、訪問外部鏈接和棄用API定位等功能。這些功能可以為開發者帶來更好的體驗。
4.2 實驗準備
為驗證本文方法和技術的有效性和實用性,設計了用戶實驗。我們選擇了12個在Stack Overflow中有相關討論的棄用API,根據這些API的功能和所屬類庫將它們分為5組。分別為這5組棄用API添加代碼上下文形成5個可以成功編譯的代碼片段。每個代碼片段對應一個任務,表4展示了5個任務中的棄用API與其所屬的類庫。

表4 實驗任務介紹
本實驗邀請了10名Java開發者并將他們分為實驗組和控制組,每組5名實驗者。實驗組的任務是使用工具為棄用API生成遷移建議,并且參考生成的遷移建議遷移代碼片段中的棄用API。控制組的任務是在Stack Overflow中搜索棄用API的相關討論帖,參考帖子中的討論遷移代碼片段中的棄用API。遷移成功的標準是代碼片段中的棄用API全部被遷移且代碼片段仍然可以被成功編譯。
實驗過程中會記錄參與者完成每個任務的耗時,如果參與者完成某個任務超過20 min或放棄任務,則將耗時記錄為20 min。同時,實驗組成員需要對工具生成的遷移建議進行評分。評分共分為四個檔:1分表示生成的遷移建議完全沒有參考價值,例如生成的遷移建議可讀性差或推薦了完全錯誤的替換API。2分表示遷移建議僅推薦了正確的替換API,但參與者無法從文本部分或代碼部分中學習替換API的使用方法。3分表示遷移建議推薦了正確的替換API且文本部分和代碼部分具有一定的參考價值,但參與者仍然需要打開原帖查看原始信息才能完全遷移棄用API。4分表示參與者只需要參考工具生成的遷移建議即可完成遷移任務。實驗組成員需要對5個任務中所有為棄用API生成的遷移建議進行評分。
4.3 實驗結果分析
表5展示了兩組成員在用戶實驗中的耗時以及實驗組成員對遷移建議評分的平均值、最大值和最小值。從時間角度來看,實驗組成員在任務1、2、4中的平均耗時大約比控制組少2 min左右,原因是控制組成員需要耗費額外的時間去Stack Overflow中尋找相關討論帖,同時要總結多個討論帖中的內容并選擇最合適的替換API。而從評分角度來看,在這三個任務中,實驗組成員給分最高的為4分,最低為2分,平均分均在3分以上,說明工具為這三個任務中的棄用API生成的遷移建議具有較高的參考價值。部分參與者在實驗2、實驗4中給了2分,原因是他們認為生成的遷移建議過濾掉了原帖對替換API參數的介紹,導致他們無法直接通過參考代碼示例完成任務。

表5 用戶實驗結果
實驗3和實驗5中實驗組成員的平均耗時與控制組相差不大。兩組成員同時表示在遷移實驗3中的棄用API Component.mouseDown(Event,int,int)時耗費了大量時間,甚至部分參與者直接放棄任務。盡管在Stack Overflow中可以找到關于該API的討論帖,然而大部分帖子中的回答并未提供替換API及其使用方式。兩組成員僅用帖子中少量的替換API描述信息遷移該API,因此都耗費了大量的時間修改替換API使其符合代碼上下文語法規范。遷移實驗5中的兩個棄用API難度較小,且Stack Overflow中關于兩個API遷移建議的討論較為集中,回答者的觀點也類似,因此兩組成員在任務5中的耗時較少。從評分角度來看,實驗組成員對實驗3的遷移建議評分較低,平均分只有2.5分,表明工具對遷移難度大或Stack Overflow中討論較少的棄用API支持力度不足。實驗組成員對難度較低的實驗5給出了較高的評分,表明該工具對遷移難度較低或帖子討論集中的棄用API具有良好的支持度。
總體而言,該實驗中實驗組成員的表現優于控制組。實驗結果表明,本文提出的方法和工具可以顯著提高客戶端開發者遷移棄用API的效率。
5 結 語
本文提出基于問答平臺的棄用API遷移建議推薦技術,該技術根據棄用API從問答網站中收集相關討論帖,對帖子中的回答進行過濾、分類、排序、簡化代碼示例等操作后生成可供開發者參考的遷移建議。基于此技術設計并實現了棄用API遷移輔助工具,實驗結果表明該工具可以顯著提高開發者遷移棄用API的效率。
本文的方法仍然具有不足之處。首先,該方法對遷移難度較大或討論較少的棄用API支持度有待提高,之后的工作會結合自然語言處理技術來應對復雜的文本結構,以此來提供更好的遷移支持。其次,該方法僅能將遷移建議以文本和代碼示例的方式推薦給用戶,不能從這些信息中抽取出可以自動化適配到客戶端的遷移策略,之后的工作中會結合一些機器學習相關技術根據文本和代碼生成遷移策略,提高方法的智能化程度,進一步減少開發者的工作量。