湯艷 馬驍驊 孫萍 王鑫
(中國電子科技集團公司第15研究所,北京 100083)
隨著我國各行業(yè)信息化技術(shù)應(yīng)用的不斷深入和發(fā)展,軟件開發(fā)規(guī)模越來越大。通常,項目需要多人甚至多個團隊一起工作,軟件開發(fā)過程所產(chǎn)生的文檔有時多達幾千甚至上萬頁,另一方面,項目交付時間緊迫又要保證質(zhì)量,這就對開發(fā)工作的標準化,實施效率文檔質(zhì)量都提出更高的要求[1]。
目前,在軟件設(shè)計階段,市場上存在很多成熟的建模、畫圖工具,為軟件設(shè)計文檔提供各種更為直觀的圖形化展示,但軟件設(shè)計文檔本身仍主要以手工編制為主。由此,產(chǎn)生了軟件設(shè)計文檔的諸多問題。如由于開發(fā)工期緊迫,造成軟件設(shè)計文檔粗劣、甚至缺少設(shè)計文檔;或由于開發(fā)團隊對設(shè)計工作的不重視,開發(fā)人員沒有完全依照設(shè)計文檔進行編碼,造成軟件設(shè)計文檔與軟件源代碼脫節(jié),設(shè)計文檔形同虛設(shè)。
本文針對軟件設(shè)計文檔缺失或源代碼與設(shè)計脫節(jié)的問題,提出了一種基于源代碼的軟件設(shè)計模型自動生成工具設(shè)計方案和實現(xiàn)方法,通過從源代碼中提取抽象語法樹(Abstract Syntax Tree,AST),逆向生成與軟件代碼結(jié)構(gòu)一致的軟件設(shè)計文檔。
文中所介紹的軟件設(shè)計模型生成工具主要用于分析源代碼、提取抽象語法樹,并根據(jù)源代碼的抽象語法樹逆向生成軟件設(shè)計文檔。該工具由源代碼分析和生成設(shè)計文檔兩大功能模塊構(gòu)成,如圖1所示。
圖1 功能模塊劃分
源代碼分析模塊包括:分析源代碼、查看源代碼分析結(jié)果、修改源代碼分析結(jié)果3個子功能,分別實現(xiàn)以下功能:
(1)分析源代碼。實現(xiàn)對源代碼的分析功能,用于提取源代碼的抽象語法樹結(jié)構(gòu),包括:包、類、注釋等信息;
(2)查看源代碼分析結(jié)果。實現(xiàn)對源代碼分析結(jié)果的展示功能,用于查看源代碼中包、類的詳細信息;
(3)修改源代碼分析結(jié)果。實現(xiàn)對源代碼分析結(jié)果的編輯功能,用于人工維護分析結(jié)果中缺失或需要修改的信息。
生成軟件設(shè)計模塊包括:生成關(guān)系圖、生成設(shè)計文檔2個子功能,分別實現(xiàn)以下功能:
(1)生成關(guān)系圖。實現(xiàn)對源代碼中包、類、方法之間關(guān)聯(lián)關(guān)系的展示功能;
(2)生成設(shè)計文檔。實現(xiàn)根據(jù)源代碼分析結(jié)果,逆向生成與軟件代碼結(jié)構(gòu)一致的軟件設(shè)計文檔的功能。
啟動工具后,為工具指定源代碼所在目錄文件夾,并選擇源代碼的開發(fā)語言,然后執(zhí)行源代碼分析操作。工具完成源代碼分析后,顯示源代碼的抽象語法樹結(jié)構(gòu),并提供以下功能:
(1)查看分析結(jié)果。選擇抽象語法樹上某一節(jié)點,可以查看相應(yīng)節(jié)點的詳細信息,以及所包含的包、類、方法的清單列表;
(2)修改分析結(jié)果。抽象語法樹上各節(jié)點的詳細信息可以在清單列表中進行手動修改;
(3)生成關(guān)系圖。選擇抽象語法樹上某一節(jié)點,通過生成關(guān)系圖功能,可以生成該節(jié)點與其所有子孫節(jié)點之間的包、類關(guān)系圖;
(4)生成設(shè)計文檔。選擇抽象語法樹上某一節(jié)點,通過生成設(shè)計文檔功能,可以按照修改后的分析結(jié)果生成設(shè)計文檔,文檔中包含所選節(jié)點及其所有子孫節(jié)點的詳細設(shè)計信息,包括:包的劃分及設(shè)計、詳細設(shè)計兩部分。其中,包的劃分及設(shè)計包括:包的劃分、各個包的類圖及說明;詳細設(shè)計包括:類的名稱、說明、父類,類中所有屬性的名稱、類型、說明,類中所有方法的函數(shù)名、參數(shù)、返回值、說明等信息。
軟件設(shè)計模型生成工具沒有大量結(jié)構(gòu)化數(shù)據(jù)的存儲需求,所有數(shù)據(jù)保存到本地硬盤中,因此不使用數(shù)據(jù)庫。由于不存在數(shù)據(jù)安全問題,工具也不需要用戶和權(quán)限控制策略。
軟件設(shè)計模型生成工具通過讀取源代碼生成軟件設(shè)計文檔,僅在客戶機本地就可以完成,不需要聯(lián)機操作,因此采用單機結(jié)構(gòu),不設(shè)置服務(wù)器端。
為了便于后期的功能維護和擴展升級,軟件設(shè)計模型生成工具的系統(tǒng)架構(gòu)分為表示層和業(yè)務(wù)邏輯層。其中,表示層負責(zé)與用戶進行信息交互、信息收集以及結(jié)果展示等相關(guān)功能;業(yè)務(wù)邏輯層主要實現(xiàn)提取源代碼抽象語法樹,并將抽象語法樹結(jié)構(gòu)轉(zhuǎn)化為關(guān)系圖和軟件設(shè)計文檔等核心業(yè)務(wù)邏輯。
系統(tǒng)流程圖如圖 2所示。
圖2 系統(tǒng)流程圖
提取抽象語法樹是建立軟件代碼結(jié)構(gòu)的前提。抽象語法樹中保存了軟件代碼的所有信息,通過對語法樹進行深度優(yōu)先遍歷或廣度優(yōu)先遍歷,就可以根據(jù)實際需求,在不同層次和維度上獲取軟件代碼結(jié)構(gòu)以及各個包、類、方法之間的邏輯關(guān)系[2]。
提取抽象語法樹是一個非常復(fù)雜的過程,為了提高開發(fā)效率,本文使用已有開源工具實現(xiàn)抽象語法樹的提取功能。使用已有的成熟工具實現(xiàn)相關(guān)功能,在提高開發(fā)效率的同時,也在一定程度上保證了軟件的質(zhì)量。
軟件設(shè)計模型生成工具,分別使用PMD(Programming Mistake Detector)和ANTLR(Another Tool for Language Recognition)工具實現(xiàn)Java代碼、C/C++代碼的抽象語法樹提取功能。
PMD是一個開源靜態(tài)代碼審查工具,可以在不運行代碼的情況下檢查代碼中的內(nèi)容[3]。因此,進行抽象語法樹的提取不需要擁有完整、可運行的代碼,在僅僅存在部分軟件代碼時就可以進行抽象語法樹的提取。
ANTLR是一個開源語法分析生成器,其前身是PCCTS,它為包括Java、C++、C#在內(nèi)的語言提供了一個通過語法描述來自動構(gòu)造自定義語言的識別器、編譯器和解釋器的框架[4]。
以使用PMD工具提取Java代碼結(jié)構(gòu)為例,所提取的抽象語法樹結(jié)構(gòu)如圖 3所示。
圖3 抽象語法樹結(jié)構(gòu)
軟件設(shè)計模型生成工具使用XML文件作為抽象語法樹的載體,將軟件代碼結(jié)構(gòu)的相關(guān)信息保存在XML格式文件中,從而實現(xiàn)抽象語法樹的存儲,為后續(xù)的軟件代碼建構(gòu)建模功能提供支撐。
通過建立軟件代碼結(jié)構(gòu)設(shè)計模型,來實現(xiàn)抽象語法樹結(jié)構(gòu)讀取和存儲,模型結(jié)構(gòu)如圖4所示。
圖4 軟件代碼結(jié)構(gòu)設(shè)計模型
AbstractXmlElement類為軟件代碼結(jié)構(gòu)設(shè)計模型中所有模型元素的基類,用于存放所有模型元素所共有的公共屬性和方法。
ProjectElement類表示模型中的項目元素,用于存放項目的相關(guān)信息。它是軟件代碼結(jié)構(gòu)的頂層節(jié)點,即所提取的抽象語法樹的根節(jié)點,通過該類可以獲取完整的抽象語法樹的相關(guān)信息。
PackageElement類表示模型中的包元素,用于存放包的相關(guān)信息。
ClassBaseElement類為所有接口和類的父類,由于接口和類具有諸多相似屬性和特征,因此通過設(shè)置相同的父類,來存放它們所共有的公共屬性和方法,如名稱、父類、注釋等信息。
InterfaceElment類表示模型中的接口元素,用于存放接口類的相關(guān)信息。
ClassElement類表示模型中的類元素,用于存放普通類的相關(guān)信息。
FieldElement類表示模型中的屬性元素,用于存放類的全局變量的相關(guān)信息。
MethodBaseElement類為所有構(gòu)造函數(shù)和方法的父類,由于構(gòu)造函數(shù)的本質(zhì)也是方法,因此通過設(shè)置相同的父類,來存放它們所共有的公共屬性和方法,如名稱、參數(shù)列表、修飾符等信息。
ConstructorElement類表示模型中的構(gòu)造函數(shù)元素,用于存放類的構(gòu)造函數(shù)的相關(guān)信息。
MethodElement類表示模型中的方法元素,用于存放類的普通方法的相關(guān)信息。
其中,ProjectElement、PackageElement、Class-BaseElement、FieldElement、MethodBaseElement通過繼承AbstractXmlElement類獲得所有模型元素的公共屬性和方法。
InterfaceElment和ClassElement通過繼承Class-BaseElement類獲得所有模型元素以及類元素的公共屬性和方法。
ConstructorElement和MethodElement通過繼承MethodBaseElement類獲得所有模型元素以及方法元素的公共屬性和方法。
此外,上述模型元素之間還存在相互關(guān)聯(lián)關(guān)系。如:一個項目元素下包含一個或多個包元素;一個包元素下包含一個或多個接口元素或類元素;一個類元素下包含一個或多個屬性元素和方法元素等。
通過將抽象語法樹轉(zhuǎn)化為上述模型元素,并建立模型元素之間的邏輯關(guān)系,實現(xiàn)了軟件代碼結(jié)構(gòu)建模,為生成軟件設(shè)計文檔提供依據(jù)。
各個類的含義及與抽象語法樹結(jié)構(gòu)的對應(yīng)關(guān)系如表1所示。
表1 設(shè)計模型類與抽象語法樹結(jié)構(gòu)對應(yīng)關(guān)系
本工具無需安裝,可直接打開使用本工具。由于軟件設(shè)計模型生成工具不提供用戶和權(quán)限控制,工具啟動后直接打開主界面,如圖5所示。
圖5 工具主界面
設(shè)置選擇項目、保存路徑、以及開發(fā)語言等項目信息后,可以通過“開始分析”按鈕執(zhí)行源代碼分析。
工具首先根據(jù)項目路徑獲取軟件代碼,根據(jù)所設(shè)置的開發(fā)語言,使用相應(yīng)工具提取軟件代碼的抽象語法樹,再將抽象語法樹保存在“保存路徑”中的XML文件中,以便隨時獲取。最后讀取抽象語法樹的XML文檔,生成軟件代碼結(jié)構(gòu)設(shè)計模型,并將其以樹型展示在左側(cè),右側(cè)各個標簽頁用于顯示抽象語法樹上各節(jié)點的詳細信息。
所提取的抽象語法樹的部分XML文件如下:
默認顯示“包的一覽表”標簽頁,用于顯示源代碼中所包含的所有包的名稱、標識、層級編號及其簡要描述,如圖6所示。其中,層級編號、簡要描述列可進行修改編輯。
圖6 包的一覽表
工具從代碼結(jié)構(gòu)設(shè)計模型的頂層包開始,采用深度優(yōu)先遍歷算法,逐層遞歸遍歷所有包,同時記錄遞歸層級作為包的層級編號。最后,將遍歷結(jié)果展示在“包的一覽表”列表中。
在“類的一覽表”標簽頁中顯示源代碼中所包含的所有類的名稱、標識、歸屬包標識、父類、層級編號及其實現(xiàn)功能,如圖 7所示。其中,層級編號、實現(xiàn)功能列可進行修改編輯。
圖7 類的一覽表
選擇抽象語法樹上包含子包的包節(jié)點,在“包的說明”標簽頁中顯示所選包節(jié)點中子包的名稱、標識、層級編號及其簡要描述。其中,層級編號、簡要描述列可進行修改編輯。在“包圖”標簽頁中顯示所選包節(jié)點的所有子包結(jié)構(gòu)圖。
選擇抽象語法樹上不包含子包的包節(jié)點,在“類的說明”標簽頁中顯示所選包節(jié)點中所有類的類名、標識、實現(xiàn)功能。其中,實現(xiàn)功能列可進行修改編輯。在“包的類圖”標簽頁中顯示所選包節(jié)點的所有類的類圖。
選擇抽象語法樹上的類節(jié)點,在“類的詳細設(shè)計”標簽頁中顯示所選類的類名、標識、父類、說明,類中所有屬性的名稱、類型、說明,類中所有方法的函數(shù)名、參數(shù)、返回值、說明,如圖8所示。在“類圖”標簽頁中顯示所選類節(jié)點的類圖。
圖8 類的詳細設(shè)計
完成對源代碼分析結(jié)果的修改后,通過“導(dǎo)出設(shè)計文檔”按鈕,可以根據(jù)修改后的源代碼分析結(jié)果,生成軟件設(shè)計文檔,如圖9所示。
圖9 生成設(shè)計文檔
文中針對軟件設(shè)計文檔缺失或源代碼與設(shè)計脫節(jié)的問題,使用Java語言和Java Swing圖形界面工具,開發(fā)設(shè)計了一套基于源代碼的軟件設(shè)計模型生成工具。實現(xiàn)了從源代碼中逆向提取軟件設(shè)計模型,并生成與軟件代碼結(jié)構(gòu)一致的軟件設(shè)計文檔。其對于提高軟件質(zhì)量,完善軟件配套文檔,提高軟件開發(fā)效率均具有重要意義。