通過用例和模擬對象簡化 SOA 開發(fā)——特別在您的項目涉及多個團隊時——并提高 SOA 應(yīng)用程序質(zhì)量。
借助于可重用服務(wù)和需要很少的新代碼的應(yīng)用程序(因為可以依賴這些可重用服務(wù)),面向服務(wù)的體系結(jié)構(gòu) (SOA) 可以大幅度提高應(yīng)用程序開發(fā)的速度。但是 SOA 還可能大大增加應(yīng)用程序開發(fā)的復(fù)雜性,因為團隊需要同時進行應(yīng)用程序的不同部分的工作,而且要在最后成功地將各個部分組合起來。本文將探討致使 SOA 開發(fā)變得困難的原因,并提供了一個可以對其進行簡化的流程。各種組織可以使用此流程來極大地增加其 SOA 成功的幾率。
SOA 開發(fā)問題
使用 SOA 開發(fā)應(yīng)用程序可提供更多的應(yīng)用程序部署選項,但也使得開發(fā)工作變得越發(fā)困難。這是因為 SOA 將應(yīng)用程序開發(fā)拆分為兩個截然不同的部分:
-
SOA 服務(wù)提供程序(SOA Service Provider,SOA-SP) ——該層的代碼實現(xiàn)服務(wù)。它具有服務(wù) API,以對服務(wù)進行聲明和為客戶機提供調(diào)用服務(wù)的方法。
-
SOA 服務(wù)協(xié)調(diào)程序(SOA Service Coordinator,SOA-SC)——該層的代碼通過一個或多個 SOA-SP 中的服務(wù)提供用戶功能。它可能具有 UI 或 GUI,以便同傳統(tǒng)應(yīng)用程序一樣與 SOA-SC 進行交互。
例如,某個金融應(yīng)用程序的 SOA 可能如圖 1 中所示。
圖 1:個人金融應(yīng)用程序和服務(wù)
通常由獨立的團隊分別負責(zé)同時開發(fā)這兩個獨立的部分。一個團隊負責(zé)開發(fā) SOA-SC——對用戶而言的應(yīng)用程序。另一個團隊負責(zé)開發(fā) SOA-SP,或許存在多個負責(zé)此項任務(wù)的團隊,而每個團隊負責(zé)開發(fā)若干服務(wù)。雖然可能已經(jīng)實現(xiàn)了一些提供程序,但可能仍然需要專門為此應(yīng)用程序?qū)崿F(xiàn)其他的提供程序。
而這給我們提出了第一個問題:如果某些提供程序尚未實現(xiàn),協(xié)調(diào)程序開發(fā)團隊如何開發(fā)其負責(zé)的應(yīng)用程序部分呢?
這兩個團隊——開發(fā)服務(wù)的團隊和開發(fā)協(xié)調(diào)程序的團隊——需要使其活動同步。他們必須就服務(wù) API 達成一致;服務(wù) API 可以是簡單的 Java? 接口或 Java Message Service (JMS) 消息格式和隊列名稱,但必須就此達成一致。但僅就接口達成一致是不夠的;服務(wù)具有行為,因此團隊必須就服務(wù)的行為達成一致。服務(wù)并不會始終成功地工作,因此團隊還必須就錯誤情況和相應(yīng)的響應(yīng)達成一致。
在理想的情況下,多個團隊可以非常容易地協(xié)調(diào)工作,最初的決策可以稍后進行修改,而所造成的影響卻非常小,并且評估工作非常靈活,此外還會不斷地進行改進。在現(xiàn)實世界中,團隊之間經(jīng)常存在協(xié)作問題,往往較早地(甚至不成熟地)做出不可更改的決策,而且評估方法是固定的。
這樣就帶來了第二個問題:協(xié)調(diào)程序和提供程序團隊如何較早而可靠地就服務(wù)如何工作達成一致?
經(jīng)常通過多個提供程序來實現(xiàn)服務(wù)冗余。這樣就可以在提供程序之間提供負載平衡和故障轉(zhuǎn)移功能,從而使得協(xié)調(diào)程序的服務(wù)體驗更為一致和可靠。冗余可以通過多次部署同一服務(wù)實現(xiàn)來實現(xiàn)。不過,當不同的供應(yīng)商部署了不同的提供程序時,服務(wù)幾乎肯定具有不同的實現(xiàn)。盡管如此,對于協(xié)調(diào)程序,所有提供程序的全部實現(xiàn)的工作方式都必須一致,以便協(xié)調(diào)程序可以采用可交換的方式來調(diào)用提供程序。服務(wù)的不同實現(xiàn)(特別是來自不同供應(yīng)商的不同實現(xiàn))是由不同的團隊開發(fā)的,而這些團隊必須加以協(xié)調(diào),以確保開發(fā)的是相同的服務(wù)。
因此,第三個問題就是:多個提供程序團隊如何實現(xiàn)相同的服務(wù),以確保他們的實現(xiàn)具有兼容性?
以上是使用 SOA 進行開發(fā)的主要問題。必須實現(xiàn)尚未開發(fā)的服務(wù)來開發(fā)協(xié)調(diào)程序,協(xié)調(diào)程序團隊和提供程序團隊必須就服務(wù)如何工作達成一致,而且,多個提供程序團隊也必須就服務(wù)如何工作達成一致。如果沒有良好的流程,這就會導(dǎo)致一片混亂,如果不對其進行檢查,將會導(dǎo)致 SOA 項目失敗。
SOA 開發(fā)流程
下面給出用于對協(xié)調(diào)程序和提供程序團隊進行同步的簡單流程,以幫助確保可重用服務(wù)以及使用這些服務(wù)的應(yīng)用程序能夠成功地進行開發(fā):
- 使用服務(wù)用例描述服務(wù)。
- 開發(fā)體現(xiàn)服務(wù)用例的服務(wù)測試。
- 開發(fā)通過服務(wù)測試的服務(wù)模擬。
- 提供程序團隊采用服務(wù)模擬作為原型,并將服務(wù)測試作為要求,從而實現(xiàn)服務(wù)。
- 協(xié)調(diào)程序團隊將服務(wù)測試作為服務(wù)使用者可以進行的工作的示例,并在實際的服務(wù)仍然處于開發(fā)過程的同時使用服務(wù)模擬對其代碼進行測試。
這個簡單的流程處理了以下問題:如何確定服務(wù)的范圍以及如何保持團隊的一致性和高效率,從而避免發(fā)生意外。公正地說,還有許多其他問題仍然沒有通過此流程得到解決。該流程并沒有涉及服務(wù)自身如何開發(fā)或協(xié)調(diào)應(yīng)用程序如何開發(fā)的問題。它并不涉及服務(wù)的質(zhì)量問題(即服務(wù)的可靠性問題),而是只定義服務(wù)如何提供必要的行為。該流程總體上也不處理傳統(tǒng)獨立應(yīng)用程序如何使用 SOA 重新進行體系結(jié)構(gòu)設(shè)計,以及如何發(fā)現(xiàn)或設(shè)計服務(wù)。所有這些問題都是必要的,但其并不在此流程的范圍之內(nèi)。
此流程使協(xié)調(diào)應(yīng)用程序和服務(wù)實現(xiàn)協(xié)同工作,并允許團隊以相當獨立的方式同時對這兩個部分進行開發(fā)。這并非 SOA 項目所需的全部內(nèi)容,但卻是一個不錯的起點。
為了說明此流程,我將討論如何實現(xiàn)一個簡單服務(wù)。它就是大家都喜歡用的服務(wù)示例,即股票報價服務(wù)。為了讓內(nèi)容更豐富一些,我提供了以下三種類型的信息:
- 簡單的當前價格報價
- 包含當前價格、當日最高價和最低價以及當天交易量的復(fù)雜報價
- 包含過去某天的復(fù)雜報價的歷史報價
此示例應(yīng)該足以闡釋該流程的工作過程。
服務(wù)用例
此 SOA 開發(fā)流程中的第一步是開發(fā)描述服務(wù)的服務(wù)用例。
Alistair Cockburn 將用例 定義為“系統(tǒng)涉眾之間有關(guān)系統(tǒng)的行為的協(xié)定”(請參閱參考資料部分列出的 Writing Effective Use Cases)。用例必須適合所定義的系統(tǒng)范圍,能夠代表此情況下使用系統(tǒng)的主要參與者的觀點,且能夠在一致的抽象層次上表示參與者的系統(tǒng)使用情況。
Alistair 給出的一個例子是網(wǎng)上的股票購買服務(wù),其中,購買者使用與股票代理的網(wǎng)站協(xié)同工作的個人金融應(yīng)用程序來購買股票。系統(tǒng)范圍既包含金融應(yīng)用程序,又包含代理的網(wǎng)站。購買者是主要的參與者。抽象級別為應(yīng)用程序和網(wǎng)站之間的交互,而不是應(yīng)用程序或網(wǎng)站內(nèi)的詳細信息。用例將描述主要成功方案(購買者根據(jù)這些方案購買股票)和一些可能出現(xiàn)錯誤的擴展。
因此,用例是關(guān)于以下內(nèi)容的文本描述:希望系統(tǒng)如何工作、將涉及到哪些人以及他們之間如何交互、系統(tǒng)在正常運行時如何工作,以及出現(xiàn)錯誤時應(yīng)該如何處理。它關(guān)心的是系統(tǒng)將做什么,而不考慮將如何 實現(xiàn)。
現(xiàn)在,假定所討論的不是系統(tǒng)或應(yīng)用程序,而是一個 SOA 服務(wù)。用例技術(shù)仍然適用。可以采用此技術(shù)來描述服務(wù)使用者與服務(wù)提供程序如何進行交互,說明服務(wù)做什么 而不用描述其如何 實現(xiàn)。服務(wù)用例 的最初草稿應(yīng)將重點放在服務(wù)的行為上。由于這是必須調(diào)用的服務(wù),因此后面的用例草稿還應(yīng)該指定調(diào)用協(xié)議——將用于調(diào)用服務(wù)的技術(shù)、傳輸和數(shù)據(jù)格式。(用例純粹主義者甚至可能說協(xié)議不屬于用例的實現(xiàn)細節(jié),他們是對的。但服務(wù)用例不僅描述服務(wù),而且還要描述如何調(diào)用該服務(wù),因此協(xié)議是使用者和提供程序參與者之間的協(xié)定的一部分,必須在某個地方加以指定。)
因此,開發(fā)用例的第一步是對服務(wù)完成的操作進行充分的描述。此描述代表了使用者對提供程序必須提供的行為的要求,主要由協(xié)調(diào)程序開發(fā)團隊創(chuàng)建,但同樣以提供程序開發(fā)團隊提供的輸出為基礎(chǔ)。這兩種類型的開發(fā)團隊必須對用例滿意才行,因為這些用例是對所有團隊開發(fā)其負責(zé)的應(yīng)用程序部分的要求。
服務(wù)不僅要在條件良好的情況下正常工作,而且還要能夠恰當?shù)靥幚沓霈F(xiàn)錯誤的情況,這非常重要。因此,您的服務(wù)用例應(yīng)該對錯誤情況和服務(wù)無法成功處理的錯誤輸入加以處理。其中很多錯誤路徑最終都表現(xiàn)為用例的備用路徑。其他錯誤場景也可能非常極端,因而需要各自的錯誤用例。在這兩種方法中,用例都必須記錄服務(wù)如何像成功路徑一樣全面地處理錯誤。
示例用例
例如,讓我們看看股票報價示例的服務(wù)用例。它需要做三件事,因此需要以下三個服務(wù)用例:
-
簡單報價:使用者傳入股票代碼;提供程序返回指定的股票的當前價格。
-
復(fù)雜報價:使用者傳入股票代碼;提供程序返回指定股票的當前價格,當前的最高價格、最低價格以及交易量。
-
歷史報價:使用者傳入股票代碼和日期;提供程序返回指定股票和日期的復(fù)雜報價。
即便對于這樣的簡單示例,仍然需要確定很多問題并將其添加到用例中,如下所示:
- 如果股票代碼無效,或者提供程序所屬的交易所不支持該股票,該如何處理?
- 應(yīng)該為價格使用何種格式?浮點數(shù)可能存在舍入誤差。小數(shù)更為準確,但不標準。字符串效率較低,但更為明確。
- 應(yīng)該為復(fù)雜報價使用何種格式?逗號分隔值?數(shù)組?對象?XML 文檔?SOAP 響應(yīng)?
- 如果所請求的日期是當日或?qū)淼臅r間,該如何處理?如果日期是過去的某個市場不開放的日期,該如何處理?對于交易所尚未開始進行股票交易的日期該如何處理?如果日期過早,而不存在相關(guān)記錄了,該如何處理?如果股票代碼或交易從那以后發(fā)生了變化,又該如何處理?
即使開發(fā)本文中的簡單用例也不簡單。用例非常麻煩,必須考慮周全才能圓滿地完成開發(fā)工作。此時的細心工作是非常不錯的一項投資;利用好的服務(wù)用例可以開發(fā)良好的服務(wù)測試和服務(wù)模擬,從而幫助開發(fā)團隊正常進行開發(fā)工作。
服務(wù)測試
此 SOA 開發(fā)流程的第二步是開發(fā)服務(wù)測試,以將用例系統(tǒng)編寫為可執(zhí)行格式。僅當服務(wù)恰當?shù)貙崿F(xiàn)了用例時,測試才能通過。
Kent Beck 指出,測試 應(yīng)該是自動而獨立的,而且應(yīng)該對可能出現(xiàn)問題的部分進行檢查(請參閱參考資料部分,以獲得有關(guān)他的書籍 Extreme Programming Explained 和 Test Driven Development 的信息)。測試——通過測試開發(fā)工作軟件——是 Beck 稱為極限編程 (XP) 的方法所包含的十二項實踐之一。它是測試驅(qū)動的開發(fā) (TDD) 的核心——如果您只能遵循一個實踐,該如何執(zhí)行 XP 呢?當采用 XP 和 TDD 時,將首先開發(fā)測試,然后開發(fā)軟件以通過測試,接著重復(fù)這些步驟,直到軟件足夠完善為止。
應(yīng)該測試什么?測試的概念源于許多地方,但用例是測試的最佳來源。用例文本和關(guān)系圖描述用戶對需求的理解。測試以更明確的方式表述這種理解,并以可靠和重復(fù)執(zhí)行的代碼加以表示。用例和測試是面向不同的受眾(人和計算機)以不同形式表示相同內(nèi)容的對等項。
服務(wù)用例的服務(wù)測試 沒有什么不同,不過更多地將其看作功能測試,而不是單元測試。服務(wù)測試不會驗證服務(wù)如何實現(xiàn);提供程序開發(fā)團隊可以自行實現(xiàn)此用途的單元測試。服務(wù)測試驗證服務(wù)是否提供了服務(wù)用例認為其應(yīng)該提供的行為。這些測試還需要對錯誤路徑進行測試。
測試將最終定義服務(wù)的期望接口。此接口通常為 Web 服務(wù)的 Web 服務(wù)描述語言(Web Services Description Language,WSDL)文件、Java 接口或 Java 組件的 EJB 遠程接口等等。如果首先開發(fā)接口,然后根據(jù)接口實現(xiàn)測試,可能會看起來更簡單,不過更直接的方法是首先開發(fā)測試,然后開發(fā)接口,以使測試能夠成功編譯。
示例服務(wù)測試
可以使用簡單的單元測試框架(JUnit 或 Cactus)來開發(fā)測試。該框架將充當服務(wù)的使用者,并進行使用者將進行的操作。下面是一些可能的測試:
- 使用 IBM 調(diào)用
simple quote
,以驗證獲得的結(jié)果是“$100.00”。
- 使用 MSFT 調(diào)用
simple quote
,以驗證獲得的結(jié)果是“$30.00”。
- 使用 BOGUS 調(diào)用
simple quote
,以驗證獲得的結(jié)果是 invalid stock symbol
錯誤。
對復(fù)雜報價和歷史報價的測試將與此類似。另外,還有針對可能的基礎(chǔ)結(jié)構(gòu)錯誤的測試,如遠程異常和 HTTP 400 錯誤。最后,測試應(yīng)該對服務(wù)用例中指定的所有內(nèi)容進行驗證;如果在用例中指定了操作,但卻不在一個或多個測試中進行檢查,則意味著使用者不能期望提供程序?qū)嶋H執(zhí)行該操作。
服務(wù)模擬
此 SOA 開發(fā)流程的第三步是開發(fā)服務(wù)模擬——通過服務(wù)測試的模擬對象。這些服務(wù)模擬是實際服務(wù)提供程序的簡單原型。
Kent Beck 將模擬對象 描述為測試對象,該對象可以使用常量進行響應(yīng),從而實現(xiàn)開銷大或復(fù)雜的資源的模仿版本。例如,模擬數(shù)據(jù)庫是一個簡單對象,但具有數(shù)據(jù)庫的 API,可以接受一些已知的 SQL 字符串,并為每個字符串返回一組固定的結(jié)果。模擬對象允許您對組件進行測試,而不必依賴于外部資源。
現(xiàn)在假定此外部資源是一個 SOA 服務(wù)。如果您的組件使用該服務(wù),則測試此組件時也在測試該服務(wù)。如果服務(wù)工作不正常,或者不可用,則即使組件工作正常,測試也會失敗。如果服務(wù)很慢(通過網(wǎng)絡(luò)遠程調(diào)用服務(wù)時就是這樣),您的測試也會運行得很慢——這樣就不能如您所愿頻繁地運行測試了。而且,如果服務(wù)尚未實現(xiàn),則根本就不能對您的組件進行測試。
因此,一個不錯的方法就是開發(fā)服務(wù)模擬,模擬對象是實際服務(wù)的簡單仿真程序。服務(wù)具有與實際服務(wù)相同的 API;它會實現(xiàn)針對服務(wù)測試而開發(fā)的接口。服務(wù)模擬應(yīng)該如何工作?它應(yīng)該通過您已經(jīng)開發(fā)的服務(wù)測試,這表明模擬真的和實際服務(wù)的工作方式一樣。
在某些情況下,服務(wù)模擬實際上比實際服務(wù)更適合用于進行測試工作。假定您的組件使用返回股票報價的服務(wù)。如果傳入代碼 IBM,您將獲得什么樣的結(jié)果呢?$50?$100?$150?具體取決于當前的股票價格,但這是測試的一個“雞與蛋”問題。通過使用服務(wù)模擬,已硬編碼的模擬將始終返回 $100,然后據(jù)此進行測試,與測試實際服務(wù)相比,這實際上更加可靠。
誰開發(fā)服務(wù)模擬?提供程序團隊(而非協(xié)調(diào)程序團隊)應(yīng)該開發(fā)服務(wù)模擬。服務(wù)模擬表示提供程序團隊計劃實際實現(xiàn)的內(nèi)容的簡單實現(xiàn)。如果相同的服務(wù)有多個提供程序團隊,則他們必須進行協(xié)調(diào),以產(chǎn)生一個他們都認可的模擬服務(wù)。
示例服務(wù)模擬
此示例服務(wù)模擬需要通過我前面編寫的示例服務(wù)測試。因此,它的簡單報價實現(xiàn)是一個 case 語句。如果服務(wù)只是一個傳統(tǒng) Java 對象(plain old Java object,POJO),則對應(yīng)的模擬將為通用接口的特殊實現(xiàn),如下所示:
清單 1:作為通用接口的特殊實現(xiàn)的服務(wù)模擬
public class StockQuoteMock implements StockQuoteService
|
簡單報價則將為 StockQuoteService 中聲明的一個方法,并在 StockQuoteMock 實現(xiàn)如下方法:
清單 2:在 StockQuoteService 中聲明并在 StockQuoteMock 中實現(xiàn)的簡單報價方法
public String getSimpleQuote(String symbol) throws InvalidSymbolException {
if (symbol == null) throw new InvalidSymbolException(symbol);
if (symbol.equals("IBM")) return "$100.00";
if (symbol.equals("MSFT")) return "$30.00";
if (symbol.equals("BOGUS")) throw new InvalidSymbolException(symbol);
throw new InvalidSymbolException(symbol);
}
|
如果服務(wù)更復(fù)雜(如無狀態(tài)會話 Bean 或 SOAP Web 服務(wù)),此 POJO 代碼仍然可以作為更復(fù)雜的模擬實現(xiàn)的基礎(chǔ)。在任何情況下,模擬實現(xiàn)肯定都不應(yīng)該試圖處理每個可能的股票代碼或訪問具有實時數(shù)據(jù)的數(shù)據(jù)庫。模擬實現(xiàn)應(yīng)該足以通過服務(wù)測試即可。
提供程序開發(fā)
此 SOA 開發(fā)流程的第四步是由提供程序開發(fā)團隊實現(xiàn)通過服務(wù)測試的服務(wù)。
此時,提供程序團隊已經(jīng)準備好,可以進行服務(wù)開發(fā)了。既然他們還沒有開始實現(xiàn)服務(wù),怎么可能進行服務(wù)開發(fā)呢?幸運的是,他們已經(jīng)開發(fā)了描述服務(wù)應(yīng)如何工作的服務(wù)用例,開發(fā)人員就是開發(fā)人員,他們已經(jīng)開始考慮如何實現(xiàn)服務(wù)了。開發(fā)人員已經(jīng)創(chuàng)建了服務(wù)測試,這些測試可說明服務(wù)的 API 是什么,并幫助演示服務(wù)的行為。他們已經(jīng)開發(fā)了服務(wù)模擬,這些模擬是表示實際服務(wù)將如何工作的快速原型。
因此,開發(fā)人員已經(jīng)非常明確如何實現(xiàn)服務(wù),只是尚未實現(xiàn)其相關(guān)的任何代碼而已。
這幾乎是毫無疑問的,但開發(fā)人員實現(xiàn)的服務(wù)必須通過服務(wù)測試。他們?nèi)绾沃雷约阂呀?jīng)完成服務(wù)實現(xiàn)工作了呢?當服務(wù)通過了所有測試后,服務(wù)就已完全實現(xiàn)了。在開發(fā)期間,團隊的開發(fā)活動可能會讓他們添加要測試的其他功能。訓(xùn)練有素的團隊不會放棄這些想法,而將對其進行捕獲并添加到服務(wù)的測試集中。服務(wù)實現(xiàn)也必須通過這些測試。提供程序團隊還應(yīng)該向其他提供程序團隊和協(xié)調(diào)程序團隊通報這些添加的測試,以便所有團隊的測試集保持同步。
理想的情況下,提供程序團隊將可以成功地實現(xiàn)通過測試的服務(wù),而不必修改已達成一致的測試。不過,這經(jīng)常被證明是不切實際的。當開發(fā)人員實現(xiàn)服務(wù)時,他們有時會發(fā)現(xiàn)需要更改服務(wù)的接口或行為。如果服務(wù)測試的質(zhì)量良好,而開發(fā)人員更改了服務(wù)的工作方式,則測試就不能再通過了。為了使測試仍然有效,開發(fā)人員必須修改測試,使其可以驗證新的設(shè)計。更改測試意味著服務(wù)模擬現(xiàn)在將不能通過測試,因此也必須對其進行更改,以實際模擬服務(wù)現(xiàn)在的工作方式。
如果提供程序開發(fā)人員更改了服務(wù)測試或服務(wù)模擬,他們需要盡快通知協(xié)調(diào)程序開發(fā)人員和該服務(wù)的任何其他提供程序的開發(fā)人員。任何使用舊測試和模擬的人員都在根據(jù)一個現(xiàn)在已經(jīng)過時的協(xié)議進行開發(fā),因此各個團隊需要根據(jù)新測試和模擬進行同步。如果其他團隊拒絕接受新測試和模擬,則重新同步的工作就變成了團隊之間的重新協(xié)商點。他們?nèi)匀挥邢M头?wù)用例達成一致,以從此處繼續(xù)開展工作,從而開發(fā)一組一致認可的測試和模擬。
示例提供程序?qū)崿F(xiàn)
提供程序開發(fā)團隊將開發(fā)實現(xiàn) StockQuoteService
的類或組件,其工作方式與 StockQuoteMock
類似,并使股票報價測試能夠通過。模擬是一個包含硬編碼響應(yīng)的簡單對象,而此提供程序是提供實際行為的組件。該實現(xiàn)應(yīng)該執(zhí)行以下操作:
- 支持所有有效股票代碼(至少支持提供程序的股票交易中涉及到的所有股票)。
- 確保使用包含所支持股票的實時價格的數(shù)據(jù)庫。
- 將數(shù)據(jù)庫使用的價格格式轉(zhuǎn)換為服務(wù)返回的格式。
- 將數(shù)據(jù)庫針對無效代碼的輸入結(jié)果(如空查詢結(jié)果)轉(zhuǎn)換為服務(wù)希望的錯誤。
- 實現(xiàn)服務(wù)的協(xié)議,如 EJB 遠程接口、HTTP Web 服務(wù)或 JMS 請求和答復(fù)消息。
由于模擬和實際提供程序?qū)崿F(xiàn)相同的接口——在此例中為 Java 接口 StockQuoteService
,因此服務(wù)測試可以使用兩個實現(xiàn)中的任何一個;只要使用要實例化的正確類對測試進行配置即可。為了運行測試,您還需要使用測試期望的股票價格對數(shù)據(jù)庫進行配置。
協(xié)調(diào)程序開發(fā)
此 SOA 開發(fā)流程的第五步是由協(xié)調(diào)程序開發(fā)團隊實現(xiàn)使用服務(wù)的應(yīng)用程序。在實際服務(wù)實現(xiàn)就緒之前,應(yīng)用程序都將使用服務(wù)模擬。
此時,由于具有大量的服務(wù)模擬,因此協(xié)調(diào)程序團隊可以繼續(xù)進行其相關(guān)工作,就像已經(jīng)實現(xiàn)并提供了服務(wù)提供程序一樣。而且,協(xié)調(diào)程序團隊不僅具有一組可以使用的服務(wù)(也就是模擬),而且也有了可以演示服務(wù)如何工作的和客戶機如何使用服務(wù)的一組測試。該團隊可以將這些測試作為可以如何實現(xiàn)其協(xié)調(diào)程序的簡單原型使用。和提供程序團隊一樣,盡管尚未實現(xiàn)任何代碼,但協(xié)調(diào)程序開發(fā)團隊已經(jīng)早就在進行協(xié)調(diào)程序的工作了。
理想情況下,協(xié)調(diào)程序團隊將可以使用達成一致的服務(wù)模擬來成功地實現(xiàn)他們的協(xié)調(diào)程序。不過有時候這樣做有些困難。模擬并不提供某些需要的行為或希望的接口。協(xié)調(diào)程序客戶還需要比模擬提供的服務(wù)更細粒度的服務(wù)。如果服務(wù)協(xié)調(diào)程序需要其他功能,則可以嘗試自行實現(xiàn)此功能。如果協(xié)調(diào)程序需要不同的接口,則可以嘗試實現(xiàn)一個適配器,來將其所希望的接口轉(zhuǎn)換為模擬實現(xiàn)的接口。如果協(xié)調(diào)程序希望更細粒度的功能,則該團隊需要對模擬及其測試進行修改。
這些更改會使得有必要重新與提供程序團隊進行同步。讓我們假定協(xié)調(diào)程序團隊實現(xiàn)了額外的功能或不同的接口來提高服務(wù)的可用性。如果添加的行為不是特定于協(xié)調(diào)程序,而是會涉及到服務(wù),則添加的行為可以潛在地由其他服務(wù)使用者重用。因此應(yīng)將其內(nèi)置到提供程序中。提供程序所需的更改可以也應(yīng)該建模為對模擬及其測試的更改。當協(xié)調(diào)程序團隊必須修改模擬及其測試時——既可能是為了增強其他功能也可能是為了對功能進行進一步細化——必須將這些更改應(yīng)用到提供程序和其他所有的工作內(nèi)容。已更改的模擬和測試成為協(xié)調(diào)程序團隊、提供程序團隊以及其他協(xié)調(diào)程序提供團隊之間的重新協(xié)商點。他們必須針對達成一致的一組新模擬和測試重新進行同步。
示例協(xié)調(diào)程序?qū)崿F(xiàn)
協(xié)調(diào)程序開發(fā)團隊將實現(xiàn)一個委托給 StockQuoteService
的實現(xiàn)的客戶端組件。它的行為將與服務(wù)測試相似,不同的是,它將使用服務(wù)類為 GUI 或客戶端應(yīng)用程序提供真正的功能。協(xié)調(diào)程序?qū)崿F(xiàn)只能使用 StockQuoteService
中經(jīng)服務(wù)測試證明可用的功能。Java 編譯器將確保協(xié)調(diào)程序代碼只能調(diào)用服務(wù)接口聲明的方法;保持協(xié)調(diào)程序?qū)崿F(xiàn)與測試實現(xiàn)的一致可以確保服務(wù)按預(yù)期的要求工作。
將流程組合起來
那么,該流程在實踐中是如何工作的呢?
第一步,開發(fā)服務(wù)用例。服務(wù)用例團隊可以包括來自提供程序團隊和協(xié)調(diào)程序團隊的代表。或者,這個團隊可以僅由那些專門進行需求收集和用例開發(fā)的分析人員組成。傳統(tǒng)用例開發(fā)主要關(guān)注人們?nèi)绾问褂脩?yīng)用程序,而這個團隊必須將重點放在組件如何集成上。他們不應(yīng)關(guān)心提供程序?qū)⑷绾螌崿F(xiàn),也不用考慮協(xié)調(diào)程序可以如何實現(xiàn)。相反,他們應(yīng)將重點放在服務(wù)是什么、它們完成什么工作以及如何對其進行調(diào)用上。
第二步,將服務(wù)用例編寫為服務(wù)測試。用例是人可讀的,而服務(wù)測試表示相同的需求,但采用的卻是計算機可執(zhí)行的方式。這些測試必須由開發(fā)人員實現(xiàn),而不是由開發(fā)用例的分析人員實現(xiàn)。測試開發(fā)人員可以是提供程序團隊和協(xié)調(diào)程序團隊的成員,也可以是可用且有能力實現(xiàn)測試的人員。在最終確定測試之前,每個團隊的代表都必須對其進行認可,從而表示所有團隊已就其達成了一致,而不考慮誰開發(fā)了哪個測試。
第三步,開發(fā)通過測試的服務(wù)模擬。開發(fā)測試的團體通常也實現(xiàn)模擬。模擬證明測試可以通過,作為原型供提供程序團隊使用,并支持協(xié)調(diào)程序團隊繼續(xù)進行開發(fā)。與測試一樣,除非所有團隊都認可模擬并表示同意,否則就不能認為已最終確定了模擬。換句話說,任何團隊都不能強制別的團隊接受一組測試和模擬,大家必須一致認可,否則遲早會出現(xiàn)混亂。
第四步,提供程序團隊部署提供程序,這些提供程序的行為與模擬相似,且均已通過了測試。如果將這些提供程序添加到測試和模擬,尤其是在更改了測試和模擬的情況下,則他們必須分發(fā)這些更改,以便其他團隊重新進行同步。他們不能強制讓其他團隊接受這些修改;所有團隊必須就此達成一致。
第五步,協(xié)調(diào)程序團隊必須使用模擬開發(fā)可以正常工作的協(xié)調(diào)程序。如果需要更改模擬,他們還需要對測試進行更新。他們需要隨后將其更改分發(fā)給其他組,所有的團隊必須找到一個大家都認可的點——一組共同的測試和模擬,并據(jù)此重新進行同步。
這些步驟一起的確可以形成一個簡單的開發(fā)流程。
解決 SOA 問題
那么,這個流程是否解決了我在本文開始時提出的問題?
1. 如果某些提供程序尚未開發(fā),則協(xié)調(diào)程序團隊如何開發(fā)其負責(zé)的應(yīng)用程序部分?
模擬解決了此問題。模擬可以快速地進行開發(fā)。雖然實際提供程序的開發(fā)需要更長的時間,但協(xié)調(diào)程序團隊可以使用模擬同步開發(fā)協(xié)調(diào)程序。只要滿足了以下條件,此工作就可以順利地進行:
- 模擬的功能全面,即意味著其編寫的測試和用例也全面。
- 沒有團隊必須更改模擬。只要某個團隊必須對模擬進行更改,他們就應(yīng)該在進一步脫離同步之前盡可能快地重新進行同步。
2. 協(xié)調(diào)程序團隊和提供程序團隊如何較早而可靠地就服務(wù)如何工作達成一致?
因為測試和模擬可以快速進行開發(fā),而且它們是真正可以運行的實際代碼,所以提供了早期驗證,從而可以確保用例有意義,并且團隊真的達成了一致。有了經(jīng)驗后,可以在前期投入更多的精力,以確保測試和模擬的全面性,這些構(gòu)件需要更改的幾率越小,剩下的開發(fā)過程中需要重新進行同步的幾率也就越小。
3. 實現(xiàn)相同服務(wù)的多個提供程序團隊如何能確保他們的實現(xiàn)是兼容的?
一組公共測試以及通過這些測試的模擬可以作為公共參考框架使用,以確保獨立的提供程序?qū)崿F(xiàn)始終兼容且可互換。早期的測試越前面,需要更改的幾率就越小,從而團隊需要重新同步的情況也就越少。
這樣一來,該流程就解決了多個團隊實現(xiàn) SOA 的不同部分時所面臨的主要問題。
結(jié)束語
本文討論了以下內(nèi)容:
- 在嘗試使用 SOA 開發(fā)應(yīng)用程序時,并行的獨立團隊可能遇到的常見開發(fā)問題。
- 一個簡單的五步開發(fā)流程,該流程通過使用服務(wù)用例、服務(wù)測試和服務(wù)模擬解決了這些問題。
您可以將此流程應(yīng)用到您的組織中,從而大幅度提高使用 SOA 進行開發(fā)的成功幾率。