?

基于低代碼開發范式的Web Service生成方法

2023-01-19 03:54朱紹宏覃章榮
關鍵詞:表達式契約代碼

朱紹宏,覃章榮

(廣西師范大學 計算機科學與工程學院,廣西 桂林 541004)

Web Service[1-4]既是一類基于B/S架構的應用程序,也是為實現團隊內部的流程化管理和高效地完成日常決策任務,而專門創建的一套完整的解決方案。由于它需要滿足不同部門和人員的業務需求,導致在軟件開發過程中,用戶需求會頻繁地發生變動。傳統的軟件開發模式缺乏靈活性,不能適應用戶需求的快速變化,無法有效地用于Web Service軟件的開發。如何高效地開發Web Service程序成為目前業界亟需解決的問題。

在軟件開發實踐中,常規的解決方案一方面是提供簡單易用的軟件開發工具,幫助開發者組織資源和減少失誤,如Eclipse、IntelliJ IDEA等集成開發環境,經過多個版本更新和技術迭代已經成為開發者的必備工具;另一方面是提供通用代碼開發框架,簡化軟件開發中的模塊集成、屬性配置等基礎工作,如Spring、J2EE框架已經被廣泛應用在企業應用的開發過程中。然而,對于Web Service這類應用程序,由于其業務規則復雜多變,開發人員為生成相應軟件,仍然需要耗費大量時間和精力編寫復雜、臃腫的業務邏輯代碼,這為今后程序的部署、維護和升級帶來了高成本問題。

為了有效解決上述問題,目前軟件開發人員主要使用2類方法以達到提升軟件開發效率和目標軟件質量的目的。第1類主要是針對于解決軟件開發過程中存在大量冗余代碼的問題,通過實現代碼重用,降低手工編碼的工作量,以提升軟件開發效率。如Mcmillan等[5]通過從開放源代碼庫中挖掘特征描述和源代碼,實現代碼重用,針對軟件項目中存在大量通用的功能模塊,通過代碼重用來有效減少通用模塊的編碼量,提升軟件的開發效率。Perez De Rosso等[6]提出一種用于開發Web應用程序的方法,該方法將獨立的、可重用的功能抽象成“概念”,然后由開發人員從“概念”存儲庫中提取“概念”,通過配置和組合“概念”來構建應用程序。第2類則是為了在需求分析階段準確地了解用戶需求,減少需求變更引發項目返工問題而提出的基于模型的需求驗證方法[7-10],通過將用戶非形式的需求表述構建成抽象的需求模型,使開發人員能夠充分理解用戶需求,減少需求錯誤,保障軟件開發過程的順利開展。在實際應用中,由于對用戶的需求進行建模存在較高成本,并且在需求足夠清晰之后,模型將會被廢棄,這導致建模的投入成本很難取得與之相匹配的回報。

近年來,基于低代碼開發范式的方法逐漸受到研究者的青睞。其作為一種可視化軟件開發方法,通過提供圖形界面的可視化編程,實現將抽象化的模型直接映射為目標軟件的實現代碼,有效解決建模投入與回報不成正比的問題[11-12]。因此,許多研究人員基于這種方法做了大量研究與探索。李雅雯[13]提出一種將IFML模型轉換為HTML和CSS實現代碼的低代碼方法,可用于解決移動應用開發中難以跨平臺的問題。羅異[14]提出一種用于Web程序生成的低代碼方法,可用于自動生成Web程序的表現層代碼。Viswanathan等[15]提出一種使用活動圖和順序圖對工作流程建模,并將模型轉換成軟件原型的低代碼方法,然而生成的原型由面向過程的代碼組成,不適用于Web Service程序的開發。Forward[16]等提出一種基于類模型(概念類圖)和狀態機模型生成應用程序的低代碼方法,但是使用該方法生成實際可用的應用程序,仍然需要開發人員手工編寫大量代碼。Chen等[17]提出一種將自定義XML類型的數據模型轉換成應用程序的低代碼方法,然而該方法生成的應用程序只能實現簡單的增加、刪除、修改與查找功能。Kundu等[18]提出一種從UML序列圖自動生成一般應用程序代碼的方法,首先以序列圖來構造一個可視化模型,然后通過設計映射規則將圖中的模型元素映射為代碼,由于序列圖一般不會包含代碼層面的信息(如變量的定義、修改、讀取、初始化變量以及異常處理等),因此,該方法只能用于生成代碼框架。王詩宇等[19]提出一種針對移動用戶界面開發的低代碼方法,通過定義模型轉換的映射規則,實現將MUICM元素轉換為Android平臺的用戶界面代碼。Yang等[20-21]為了提升目標軟件的質量,針對需求分析階段容易出現需求錯誤的問題,提出一種低代碼開發方法RM2PT。該方法通過定義用于模型轉化的轉換規則和轉換算法,實現將統一建模語言[22](UML)符號和對象約束語言[23](OCL)表達式構建的需求模型轉化成軟件原型,能夠快速驗證用戶需求,減少因需求錯誤造成的不必要損失。然而,由于原型無法實現數據持久化,且不是標準Web Service程序,所以目前還難以進行實際部署與應用。

上述工作為推動軟件的高效開發做出了大量貢獻,然而,就筆者調查所知,目前還沒發現采用低代碼方法自動生成標準化Web Service程序的相關文獻報道,因此,基于RM2PT的研究工作,本文提出一種直接將需求模型自動轉換為Web Service程序的低代碼開發方法。該方法建立OCL表達式與數據基本操作的之間的轉換規則,結合創建的轉換模板和轉換算法自動生成數據可持久化的、標準化的Web Service應用程序,從而可有效提高Web Service程序的開發效率與質量。

1 相關知識

1.1 REST

REST[24]是一種互聯網架構風格,它使用HTTP協議,并將網絡上的所有內容視為資源。同一資源具有多種表現形式,最常見的形式是JSON[25],并且每個資源都有一個唯一的標識,通過這種唯一標識,可以輕松地對資源進行操作?;赗EST的體系結構設計,通常使用HTTP的4種方法來表示資源的CRUD(創建、檢索、更新和刪除)操作:

1) GET:訪問資源。

2) POST:創建資源。

3) DELETE:刪除資源。

4) PUT:更新資源。

基于REST體系結構的Web Service稱為RESTFul Web Service[26],其結構簡單,使前端和后端實現解耦,促進了獨立開發,也易于維護和測試,在業界得到普遍應用。

1.2 系統操作(system operation)

在繪制系統順序圖(SSD)時,通常會顯示出其中的系統事件,即設計系統的事件或I/O消息,而輸入的系統事件則表示系統具有用于處理該事件的系統操作[27]。在本文中,業務邏輯的實現代碼被封裝在系統操作中,對外表現為軟件系統在公共接口中提供的操作,用于對輸入的系統事件做出處理,并對外輸出處理結果。

1.3 需求模型(requirements model)

需求模型是使用RM2PT工具建模之后得到的模型,屬于UML的受限子集,包含:

1) 概念類圖:類圖使用類和對象描述目標系統的結構,而概念類圖是通過刪除類圖中的方法所形成一種變體結構。

2) 操作契約(contract):是使用OCL表達式定義的描述功能需求的一種敘述規范,用來約束UML模型,其包含如下4個部分:

(i) Signature:定義了系統操作名稱、輸入參數、系統操作的返回類型。

(ii) Definitions:為減少冗余,提取前置條件和后置條件的公共部分作為共享規范,用于變量的復用。

(iii) Precondition:定義了系統執行前應該滿足的前置條件。

(iv) Postcondition:指定了系統執行之后應該滿足的后置條件。

3) 系統順序圖:呈現了系統事件在一定時間內的發生次序。

4) 用例圖:以可視化的方式呈現參與者與目標系統之間的交互行為。

2 Web Service生成方法

關注點分離的原則認為:軟件系統必須分解為功能重疊盡可能少的部分[28],即程序不要編寫為一個整體,而是將代碼分解成多個模塊,這些模塊是最終確定的系統小塊,每個小塊都能夠完成一個簡單的工作。按照此原則,分層體系結構模式成了一種可靠的通用模式,它使Web Service應用具有高內聚,低耦合,易于實現、測試和維護的特點。此外,考慮到當前業界主流的開發架構在企業開發中的受歡迎程度,本文選擇Spring Boot軟件架構來生成Web Service程序。根據該架構,Web Service程序可分離出如圖1所示的系統操作(system operation)、實體倉庫(entity repository)、實體類(entity class)以及視圖(view)4種核心功能模塊。系統操作是應用程序的核心模塊,包含業務邏輯的具體實現;實體倉庫充當業務層和關系型數據庫的交互媒介;實體類是數據交互的載體,用于存儲程序內部的信息,應用程序也會將實體類映射為數據庫中的數據表;視圖用于渲染圖形用戶界面(GUI)。由于entity類和view的生成過程與文獻[21]中的過程相似,因此本文重點是將需求模型轉換為實體倉庫和系統操作。

圖1 Web Service核心功能模塊Fig. 1 Main functional modules of Web Service

2.1 總覽

低代碼(low-code)開發方法使用模型作為業務需求的形式化描述,通過定義的處理邏輯將業務模型轉換為可以運行的軟件應用程序。因此,本文以Low-Code開發理念為指導,使用RM2PT工具構建的需求模型作為本文方法的轉換基礎,通過定義用于代碼生成的轉換規則、轉換模板和轉換算法,實現直接將需求模型自動轉換為Web Service程序。圖2顯示了本文方法的工作原理,方法包含2種角色——設計者與用戶。設計者指代本文方法的提出者,而用戶則指代對用戶的需求進行建模的需求分析師,其建模得到的需求模型作為本文方法的輸入。

圖2 自動生成方法的工作原理Fig. 2 Overview of automatic generation approach

在當前的軟件開發過程中,編程人員的主要任務是編寫目標軟件的業務邏輯,業務邏輯中的查找對象、設置引用、創建和刪除對象以及更新對象,符合眾所周知的CRUD(創建、檢索、更新和刪除)操作,而OCL具有豐富的描述系統狀態的語法機制,可用于描述程序中的業務邏輯狀態。因此創建轉換規則的目的是建立OCL表達式與數據基本操作之間的映射關系。轉換模板用于限定生成代碼的格式,使代碼符合標準的編碼規范,從而提高生成代碼的質量。轉換模板通過提取分層后的功能模塊的代碼特征構建而成,因此,圖1中的4種功能模塊都需要構建轉換模板。轉換算法是本文用來處理和解析需求模型以及用來生成Web Service程序的一種偽代碼描述,后面的章節將詳細介紹轉換規則、轉換模板以及轉換算法的實現細節。

2.2 轉換規則

圖3是應用程序的數據操作示意圖,其中,數據訪問層和數據庫經常受到技術更新換代影響,容易產生較大的變動。而GRASP受保護變量原則認為:預先找出不穩定的變化點,使用統一的接口封裝起來,當未來發生變化的時候,可以通過接口擴展新的功能,而不需要修改原有的實現[29]。為了解決這個問題,本文引入了JPA[30]中定義的數據基本操作來降低底層技術更新對程序的影響。此外,目前Web Service程序最常見的操作是從數據庫中獲取和顯示數據[31],而RM2PT中定義的26條轉換規則無法生成這些操作。為了生成Web Service程序,需要在這26條轉換規則的基礎之上,創建生成數據操作的轉換規則。因此,本文通過建立OCL表達式與JPA基本操作之間的映射關系,形成了如表1所示的10條新的轉換規則。

圖3 應用程序數據操作示意圖Fig. 3 Illustration of application data operations

表1 轉換規則Tab. 1 Transformation rules

(1)save:將執行操作后產生的對象ob保存到ClassName類的對象集合中。

(2)update:在對象屬性被賦值之后,需要將對象修改后的屬性信息更新到系統中,因此類名為ClassName的對象ob在執行賦值操作之后將會被更新到系統中。

(3)delete:從系統中ClassName類的對象集合中,刪除對象實例ob,使系統符合后置條件。

(4)findAll:在系統中查找ClassName類的所有對象。

(5)findById:在ClassName類的所有實例中,通過使用OCL關鍵詞any,以查詢條件Id查找對象ob。

(6)findByLike:依據對象的屬性值查找系統中具有相似屬性值的所有對象。

(7)findByAssociation:從對象ob的關聯對象中查找所有符合約束條件o的單個對象ob。

(8)findByAttribute:從ClassName類的所有對象中,通過使用OCL關鍵詞any和約束條件condition(o)來查找單個對象ob。

(9)findByAssociation:從對象ob的所有關聯對象中查找符合約束條件o的所有對象實例。

(10)findbyAttribute:通過約束條件o以及OCL關鍵詞select在系統中查詢ClassName類的所有對象obs。

在上述轉換規則中,基本操作中的檢索操作,除了findAll以外,都可以通過任意組合形成更復雜的查詢操作。例如,OCL表達式的語義描述為:根據屬性name和關聯對象teacher查找系統中存在的學生類對象,那么其基本操作可以組合為findByNameAndTeacher,其返回值由OCL關鍵字決定。通過這種方式,數據查詢能夠涵蓋軟件開發中大多數常見的數據訪問操作。

2.3 轉換模板

Xtend[32]是一種靜態類型的編程語言,相比其他JVM語言更加簡潔、易讀。Xtend不僅提供了一種編寫代碼生成器的機制,還提供了如類型推斷、擴展方法、分派方法和lambda表達式等強大的功能,從而使模型訪問和遍歷變得非常簡單、直觀并且易于閱讀和維護。這些優點促使本文使用Xtend語言來定義代碼的轉換模板。本文定義的轉換模板包含2種組成成份:第一種是靜態成份,是通過提取應用程序的代碼特征構建的,此部分可以直接作為代碼的組成;第二種是在符號“《 》”中定義的動態成份,它包含模型解析和代碼生成的處理邏輯,當這些處理邏輯執行完成之后,其產生的代碼將會直接嵌入到模板中,與靜態部分組成完整的實現代碼。如圖4所示,模板A為Web Service類的轉換模板(用于封裝系統操作),模板B為實體倉庫的轉換模板,模板C為系統操作的轉換模板。

圖4 轉換模板示例Fig. 4 Transformation templates example

1)在模板A中:@RestController,@RequestMapping這些作為Spring Boot框架的注解用來表示類的屬性和作用。在程序部署之后,根據URL地址,服務端首先會定位到實現類,然后再定位到該類中的某一個具體系統操作。因此,在模板A和模板C中定義的@RequestMapping注解將會作為服務的一種資源標識。DaoManage是對象管理器,能夠返回實體倉庫的引用對象。CurrentUtils是定義的工具類,用來存儲和獲取臨時引用,臨時引用是在操作契約中定義的一種特殊對象實例,由多個操作契約所共享,用來減少代碼冗余。表達式《name》的輸出內容是系統順序圖中的服務名稱?!禛enerateWSCode()》中的表達式,對應于算法2在生成系統操作的實現代碼之后,將代碼封裝到由模板A所形成的實現類框架的執行過程。

2)模板B使用關鍵字public,以及《e.name+"Repository"》共同組成一個public接口,“e”為概念類圖中的類。此接口會默認繼承2個父級接口以實現表1中的(1)~(5)基本操作,而《GenerateRECode()》中的表達式則用于生成(6)~(10)以及它們組合形成的基本操作。

3)在模板C中,“c”為算法2正在處理和解析的操作契約,因此表達式《c.op 》將會動態地解析為當前操作契約的名稱。為了生成具有RESTFul風格的Web Service,本文需要為生成的系統操作設置HTTP動詞來表示資源的狀態扭轉。因此,算法2將會根據操作契約的后置條件生成4種HTTP請求方法類型,然后以字符的形式輸出,即 《HttpMethod(c)》 將會被解析為“GET”“POST”“PUT”“DELETE”中的一種字符。關鍵字public、類型String、系統操作的名稱《c.op》以及輸入變量 《Parameter(c)》 共同組成系統操作的操作簽名。表達式 《GenerateSOCode()》 對應于算法2中將操作契約轉換為業務代碼之后,將代碼封裝到由模板C所形成的系統操作框架的執行過程?!禦eturn(c)》 中定義的表達式可以被動態地解析為系統操作的返回值。根據MVC原則,視圖層不應該包含應用邏輯或業務邏輯,而是應該把請求委派給領域層的領域對象,視圖層只需要呈現領域對象返回的處理結果。在程序部署運行之后,視圖層以HTTP請求的形式訪問領域層,因此,需要考慮領域層到視圖層的通訊問題。鑒于JSON作為數據傳輸的一種理想載體,模板C中定義了用于生成JSON格式字符的處理代碼,其中JSONObject是用來創建JSON格式數據的包裝類,其引用對象將會包裝業務邏輯的處理結果“data”、“msg” 以及“code”狀態數據。模板定義了捕獲程序異常的try-catch代碼,以及將JSON數據轉化為字符串并將其作為系統操作返回值的代碼。

2.4 轉換算法

本文中轉換算法主要有3種:第一種為算法1所示的REST生成算法,可以根據系統操作契約的后置條件,輸出HTTP的4種請求方法,用于標識系統操作將要響應的HTTP請求類型;第二種為算法2所示的Web Service類的生成算法,將系統操作封裝到JAVA類中;第三種為算法3所示的實體倉庫類的生成算法。

算法1是REST生成算法,以操作契約作為輸入,輸出為HTTP請求方法的字符。算法首先創建2個標記Tag和M,然后解析定義在后置條件中的OCL表達式,對其中的OCL表達式執行遍歷操作,并判斷子表達式的類型。如果子表達式屬于刪除對象類型的表達式,那么算法將Tag設置為1;如果子表達式屬于創建對象類型的表達式,那么算法將Tag設置為2;如果子表達式屬于更新對象類型的表達式,那么算法將M設置為1。當遍歷完成之后,算法會判斷Tag的值,如果值為1則輸出Delete字符;如果值為2則輸出Post字符;如果值為初始值,算法會判斷M的值,如果M的值為1則輸出Put字符,否則輸出Get字符。按照單一職責原則[33],一個模塊應該只有一個引起它發生變化的原因,應該只做一種工作。因此系統操作應該僅包含創建、刪除與更新對象3種業務邏輯中的一種功能,但不限于包含一種或多種查找對象的功能。而并不是所有人都會按照此原則編寫操作契約,因此設置HTTP方法的優先級是必要的,當前算法處理邏輯的優先級為:Delete > Post > Put > Get。

算法1 REST生成算法。

輸入:contract——Contract。

輸出:請求方法類型。

1. Begin

2. Tag ← 0

3.M← 0

4. Post ← parse(contract)

5. oclExp ← parse(Post)

6. for sub-exp ∈ oclExp do

7. type ← GetType(sub-exp)

8. if type = Delete type

9. Tag ← 1

10. else if type = Create type

11. Tag ← 2

12. else if type = Update type

13.M← 1

14. end

15. end

16. if Tag = 1

17. Output(“Delete”)

18. else if Tag = 2

19. Output(“Post”)

20. else ifM= 1

21. Output(“Put”)

22. else

23. Output(“Get”)

24. end

25. end

26. end。

算法2為Web Service類的生成算法,算法以系統順序圖、操作契約、Web Service類以及系統操作的轉換模板作為輸入,輸出Web Service類。首先,算法創建一個空集合用于保存操作契約中的OCL表達式(OCL表達式由一行或多行子表達式組成);其次,遍歷全部系統順序圖,獲取該系統順序圖的系統事件名稱op,并根據Web Service類的轉換模板生成Web Service類的代碼框架;然后,對全部操作契約執行遍歷操作,如果當前操作契約的名稱與op相同,則根據系統操作的轉換模板生成系統操作的代碼框架;之后,解析操作契約中的臨時對象,如果臨時對象不為空,則為其生成引用;接下來,解析操作契約中的definition、前置條件和后置條件部分,如果它們不為空,則會解析其中的OCL表達式并放入到oclSet集合中;接著,遍歷oclSet集合中的OCL表達式,將子表達式與轉換規則中的表達式做匹配,獲取該表達式的類型;此后,根據轉換規則將此行表達式轉換成為代碼。當遍歷執行完成,操作契約中的OCL表達式會轉換成系統操作的業務邏輯代碼,并被算法添加到系統操作的代碼框架SO中。接下來,根據操作契約的后置條件生成系統操作的返回值,并添加到SO中。執行完此步驟,當前遍歷的操作契約就被成功地轉換為系統操作。最后,該系統操作會被封裝到Web Service類的代碼框架WS中。

算法2 Web Service 類生成算法。

輸入:Tws——Web Service類的轉換模板;Tso——系統操作的轉換模板;CS——全部操作契約;SSDS——全部系統順序圖。

輸出:Web Service 類。

1. Begin

2. oclSet ← ? ∥創建一個空集合

3. for ssd ∈ SSDS do

4. op ← ssd.op

5. Generate skeleton WS by Tws

6. for contract ∈ CS do

7. if op = contract.op

8. Generate skeleton SO by Tso

9. TP ← parse(contract)

10. if TP<>null

11. Generate reference

12. end

13. Def ← parse(contract)

14. if Def <> null

15. OCLExp ← parse(Def)

16. oclSet.append(OCLExp)

17. end

18. Pre ← parse(contract)

19. if Pre <> null

20. OCLExp ← parse(Pre)

21. oclSet.append(OCLExp)

22. end

23. Post ← parse(contract)

24. if Post <> null

25. OCLExp ← parse(Post)

26. oclSet.append(OCLExp)

27. end

28. for sub-exp ∈ oclSet do

29. type ← Match(sub-exp) ∥匹配轉換規則

30. code ← Generate(type , sub-exp) ∥依據轉換規則生成代碼

31. SO ← code

32. end

33. resultCode ←GetResult (Post)

34. SO ← resultCode

35. WS ← SO ∥將系統操作封裝到Web Service類

36. end

37. end

38. end

39. end。

算法3為實體倉庫的生成算法,它以概念類圖、操作契約以及實體倉庫的轉換模板作為輸入,輸出實體倉庫的JAVA接口。算法先遍歷概念類圖中的概念類,每執行一次遍歷,都會根據實體倉庫的轉換模板生成JAVA接口的代碼框架(每個概念類都要有一個相對應的實體倉庫)。其次,遍歷概念類中的關聯關系(關聯關系包括一對一、一對多、多對一),如果當前概念類屬于關聯關系中“多”的一方,則根據此關聯關系生成findByAssociation基本操作,并將此基本操作的返回值設置為集合類型,否則其返回值會設置為對象類型。然后,遍歷全部操作契約的所有OCL子表達式,每次遍歷都會設置一個空的集合Set。接下來,分別遍歷子表達式中的概念類的屬性和關聯關系,如果此屬性和關聯關系屬于當前概念類,則將該屬性和關聯關系存入Set集合。接著,將Set集合中的屬性和關聯關系組合在一起,并判斷子表達式是否包含關鍵字“any”,如果包含,則生成findByElement這種由多種元素組合而成的基本操作,并將此基本操作的返回值設置為對象類型,否則設置為集合類型。當所有OCL子表達式的遍歷執行完成,操作契約中關于此概念類的基本操作就會生成完成。最后,把這些基本操作封裝到實體倉庫的代碼框架ER中。

算法3 實體倉庫生成算法

輸入:CS——Contracts;ccd——概念類圖;T——實體倉庫的轉換模板。

輸出:Entity Repository。

1. Begin

2. for Class ∈ ccd do

3. Generate skeleton ER byT

4. for association ∈ Class do

5. if IsMultipe(association) = true

6. Generate findManyByAssociation code

7. else

8. Generate findOneByAssociation code

9. end

10. end

11. for sub-exp ∈ CS do

12. Set ←?

13. for attribute ∈ sub-exp do

14. if callClass(attribute) = Class

15. Set ← attribute

16. end

17. end

18. for association∈ sub-exp do

19. if callClass(attribute) = Class

20. Set ← association

21. end

22. end

23. Element ← Connect(Set)

24. if sub-exp include(any)

25. Generate findOneByElement code

26. else

27. Generate findManyByElement code

28. end

29. end

30. ER ← AllCode; ∥將基本操作封裝進代碼框架

31. end

32. end。

2.5 轉換示例

為了對本文方法的實現原理進行說明,引入用戶登錄案例來介紹需求模型的組成結構和作用,以及如何將模型轉換成代碼。如圖5所示,對該案例建模得到的需求模型包括4種子模型:用例圖、概念類圖、系統順序圖與操作契約。1)用例圖中有參與者User(表示與系統交互的實體)和用例loginService(表示系統需要執行的服務)。2)概念類圖使用User類和Role類描述系統結構,圖中還展示了Role類與User類的關聯關系以及類具有的屬性。3)系統順序圖顯示了4種系統事件與系統的交互順序,表示的含義為:系統對象User首先執行register操作,然后選擇一種登錄方式,打開主界面。4)操作契約封裝了系統對 register() 事件進行響應和處理的執行邏輯,它的組成結構有:簽名(Signature)、Definitions、前置條件(Precondition)、后置條件(Postcondition)。簽名部分包括返回值的類型和3種輸入參數:用戶名(userName)、密碼(pwd)、驗證碼(code)。Definitions部分定義了2種OCL表達式:根據用戶名查詢系統中的對象user;獲取驗證碼str。前置條件中定義了系統運行需要滿足的3種條件:user必須不存在,str必須存在,code與str必須一致。后置條件中定義了系統運行之后對象的狀態變化:首先創建User類的對象u,然后將輸入參數賦值給對象u的屬性,最后將u保存到系統中。

圖5 需求模型示例Fig. 5 Requirements model example

生成代碼的示例如圖6所示。系統操作中的“POST”請求類型,由REST生成算法,根據操作契約的后置條件轉換生成;整個系統操作的方法簽名和方法體,由Web Service 類生成算法,根據圖5中的操作契約,結合系統操作的轉換模板和匹配到的轉換規則自動生成;實體倉庫由實體倉庫生成算法,結合實體倉庫的轉換模板,根據需求模型中的操作契約和概念類圖轉換形成;概念類圖中的User類可以被轉換形成圖6中的實體類。

圖6 生成代碼示例Fig. 6 Generated code example

3 方法的驗證

3.1 案例研究

通過互聯網檢索開源代碼庫中的源代碼,獲取到了外賣訂單系統(TakeOS)、停車管理系統(Park)、在線教育系統(OE) 3種與日常生活息息相關的Web Service程序,這3個程序的功能需求覆蓋面大,可用來驗證本文方法建模復雜用例的能力。此外,合作企業提供了已投入使用的機場報修系統(AMS)的源代碼,代碼中包含了企業內部工作流程的復雜業務邏輯,可用來驗證本文方法生成復雜系統操作的能力。本文將在以下部分介紹4個案例需求建模和程序生成的結果。

需求復雜度用于估算面向對象程序的編程成本,可通過統計需求模型中參與者(Actor)、用例(UseCase)、系統操作(SO)、實體類(Entity)以及實體類之間的關聯關系(Association)的數量來衡量[21]。因此,本文依據4個案例的源代碼反向推導需求模型,然后分別統計案例的需求復雜度,最終得到如表2所示的建模結果: 4個案例總共包括23個參與者,117個用例,194個系統操作,39個實體類,45種類間關聯關系。

表2 需求復雜度Tab. 2 Requirements complexity

為了說明本文方法可以用來生成哪種類型的系統操作以及生成過程中的錯誤處理等問題,以AMS案例的6種功能性需求(如表3所示)為例詳細介紹系統操作的分析和處理過程。AMS的故障報修、工單轉發、故障受理、完成維修等需求屬于業務邏輯中屬性賦值、查找對象、設置引用、創建對象、刪除對象、更新對象等操作的實現范圍,這類需求完全可以使用OCL語句中的系統狀態表達式描述,也符合轉換規則的轉換條件,因此可以為這些需求創建操作契約。對于AMS的附件上傳需求,由于其系統操作的實現代碼中具有復雜的IO流操作,而這些操作不能使用OCL語句表示,更無法為此需求創建操作契約,因此,本文方法不適用于實現此類需求。保存密碼功能需要前端和后端協同實現,但是因為本文方法目前尚不能生成復雜的前端界面交互邏輯,而且創建的操作契約只能生成后端執行代碼,無法實現對該功能的完整描述,所以此類需求也不適合使用本文方法實現。按照上述同樣的原理或方法,對4個案例的系統操作進行分析,并通過創建操作契約,總結出如表4所示的系統操作生成結果。4個案例總共建模得到194個系統操作,為其中的181個創建了操作契約,占總數的比例約為93.3%,只有約6.7%的系統操作無法實現正確的建模和代碼生成。通過對實驗結果的分析,需求建模和代碼生成的失敗情況通常是以下情形:1)對于發送電子郵件、MD5加密、打印文檔等功能,如果不調用第三方API,則無法在操作契約中正確指定OCL表達式;2)如保存密碼等功能可以通過指定操作契約生成后端代碼,但不能為其生成前端交互代碼;3)一些系統操作目前只能通過手工編碼實現,例如附件上傳、發送語音等功能。

表3 AMS案例需求說明Tab. 3 Requirements specification for AMS case

表4 系統操作的生成結果Tab. 4 Generation results of system operations

總之,本文選擇的4個案例都具有相對復雜的業務邏輯,可用于驗證需求建模以及程序生成的不同方面。而4個案例中93.3%的系統操作可以實現自動生成,證明本文方法自動生成的軟件具有很高的實現程度,同時也證明本文提出的10種轉換規則結合RM2PT中定義的26種轉換規則,適用于生成Web Service程序中的大多數業務邏輯代碼。

3.2 功能測試

為了驗證生成的系統操作是否正確,需要對自動生成的181個系統操作進行功能性測試。本文選擇了如表5所示的實驗環境和參數,并使用Junit單元測試框架創建了350個測試用例,這些測試用例能夠實現對181個系統操作的單元測試。表6為自動生成系統操作的測試結果,其中GET類型的測試用例有131個,執行成功的數量為127個,成功率為96.95%;POST類型的測試用例83個,測試成功83個,成功率100%;DELETE類型的測試用例為56個,測試成功的數量為40個,成功率為71.43%;PUT類型的測試用例為80個,測試成功80個,成功率為100%。測試用例能夠覆蓋全部的系統操作,并且能夠取得大約94.29%的執行成功率,只有5.71%的測試用例發生了預期之外的錯誤。

表5 實驗環境和參數Tab. 5 Experimental environment and parameter

表6 系統操作的測試結果Tab. 6 Testing result of system operations

測試結果顯示,測試失敗的用例主要是GET和DELETE類型。通過分析發生的錯誤信息,發現測試失敗的主要原因是:1)當數據表之間存在外鍵關聯時,將無法正常刪除該表中的數據;2)如果訪問請求中的輸入參數與數據表中的類型不匹配,程序將會在運行時發生異常。因此,使用DELETE類型的請求方法會引起第一種錯誤,可采用軟件開發中常用的“邏輯刪除”機制應對此問題。應用程序中最常見的數據操作是查詢操作,因此使用GET類型的請求方法會有比較大的概率引發第二種錯誤,可通過修改概念類圖中的屬性類型解決此問題。

綜上所述,測試用例的運行結果顯示,大約94.29%的測試用例能夠成功執行,這表明從需求模型中自動生成的系統操作具有很高的正確率。此外,因為測試中出現的錯誤對應于需求模型中的建模缺陷,所以,通過運行測試用例可以快速定位程序運行過程中出現的錯誤,并根據錯誤的原因修改需求模型中的建模缺陷,重新生成可靠的應用程序。

3.3 討論

為了提升Web Service程序的開發效率,本文提出一種低代碼開發方法,并取得了較好的實驗效果,但方法仍然存在一些局限性,主要包含如下3點:

1)因為本文使用的需求模型屬于UML的受限子集,所以適合生成面向對象類型的信息系統。但是本文方法不支持實時系統、嵌入式系統和信息物理融合系統的開發,這類系統需要更復雜的需求模型。

2)本文方法可以提升軟件開發效率,但是目前在將用戶需求形式化的過程中,采用的是手工編寫操作契約方式,可能會產生較高的使用成本。

3)案例研究表明大多數系統操作可以實現自動生成,但是少部分系統操作相對比較復雜,無法滿足轉換規則的使用條件,需要以手工編碼的方式實現。

本文方法目前只針對Web Service程序的開發,但可以通過優化需求模型的組成以使其適用于其他系統的開發。使用操作契約可能產生較高的成本,未來可考慮從自然語言描述的需求規格說明中提取操作契約,以便有效降低操作契約的使用成本。對于存在部分系統操作相對比較復雜的情況,可以通過提供第三方API存儲庫的方式解決。

4 結語

本文提出一種用于Web Service程序開發的低代碼方法,可直接將需求模型自動轉換為標準化的Web Service程序。首先,基于RM2PT定義的26條轉換規則,通過引入JPA定義的基本操作,構建10條新的轉換規則;其次,通過提取Web Service程序的代碼特征構建轉換模板;最后,建立用于解析和處理需求模型的轉換算法。本文通過4個案例評估方法的有效性,實驗結果表明,約93.3%的系統操作可以實現自動生成。與傳統的軟件開發方法相比,本文方法不僅能屏蔽軟件實現的技術細節,降低從事軟件開發工作所需要的技術門檻,而且還能提高軟件的開發效率與質量。

雖然實驗結果符合預期,但是本文方法還存在改進的空間,例如編寫正確的OCL操作契約會帶來一定的使用成本。因此,未來可以從4個方面繼續改進生成方法,使其更加完善:

1)從需求模型中自動生成系統操作的測試用例,實現對需求模型的有效驗證。

2)為了給用戶提供多樣化選擇,未來將通過優化需求模型的組成使本文方法適用于其他系統的開發。

3)使用自然語言描述用戶需求,并實現將自然語言轉換成操作契約,讓普通用戶不需要依賴架構師和開發人員的專業知識就可以生成目標軟件,進一步降低技術難度。

4)通過提供第三方API存儲庫,用戶可直接將第三方API集成到操作契約中,以此實現復雜系統操作的自動生成。

猜你喜歡
表達式契約代碼
一紙契約保權益
靈活選用二次函數表達式
表達式轉換及求值探析
淺析C語言運算符及表達式的教學誤區
創世代碼
創世代碼
創世代碼
創世代碼
以契約精神完善商業秩序
解放醫生與契約精神
91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合