前后端分離按照現(xiàn)在的趨勢(shì),前后端分離幾乎已經(jīng)是業(yè)界對(duì)開(kāi)發(fā)和部署方式所達(dá)成的一種共識(shí)。所謂的前后端分離,并不是傳統(tǒng)行業(yè)中的按部門劃分,一部分人只做前端(HTML/CSS/JavaScript等等),另一部分人只做后端(或者叫服務(wù)端),因?yàn)檫@種方式是不工作的:比如很多團(tuán)隊(duì)采取了后端的模板技術(shù)(JSP, FreeMarker, ERB等等),前端的開(kāi)發(fā)和調(diào)試需要一個(gè)后臺(tái)Web容器的支持,從而無(wú)法將前后端開(kāi)發(fā)和部署做到真正的分離。 通常,前后端分別有著自己的開(kāi)發(fā)流程,構(gòu)建工具,測(cè)試等。做前端的誰(shuí)也不會(huì)想要用Maven或者Gradle作為構(gòu)建工具,同樣的道理,做后端的誰(shuí)也不會(huì)想要用Grunt或者Gulp作為構(gòu)建工具。前后端僅僅通過(guò)接口來(lái)協(xié)作,這個(gè)接口可能是JSON格式的RESTFul的接口,也可能是XML的,重點(diǎn)是后臺(tái)只負(fù)責(zé)數(shù)據(jù)的提供和計(jì)算,而完全不處理展現(xiàn)。而前端則負(fù)責(zé)拿到數(shù)據(jù),組織數(shù)據(jù)并展現(xiàn)的工作。這樣結(jié)構(gòu)清晰,關(guān)注點(diǎn)分離,前后端會(huì)變得相對(duì)獨(dú)立并松耦合。但是這種想法依然還是很理想化,前后端集成往往還是一個(gè)很頭痛的問(wèn)題。比如在最后需要集成的時(shí)候,我們才發(fā)現(xiàn)最開(kāi)始商量好的數(shù)據(jù)結(jié)構(gòu)發(fā)生了變化,而且這種變化往往是在所難免的,這樣就會(huì)增加大量的集成時(shí)間。 歸根結(jié)底,還是前端或者后端感知到變化的時(shí)間周期太長(zhǎng),不能“及時(shí)協(xié)商,盡早解決”,最終導(dǎo)致集中爆發(fā)。怎么解決這個(gè)問(wèn)題呢?我們需要提前協(xié)商好一些契約,并將這些契約作為可以被測(cè)試的中間產(chǎn)品,然后前后端都通過(guò)自動(dòng)化測(cè)試來(lái)檢驗(yàn)這些契約,一旦契約發(fā)生變化,測(cè)試就會(huì)失敗。這樣,每個(gè)失敗的測(cè)試都會(huì)驅(qū)動(dòng)雙方再次協(xié)商,有效的縮短了反饋周期,并且降低集成風(fēng)險(xiǎn)。具體的實(shí)踐方式,請(qǐng)參加我同事的一篇博文,“前后端分離了,然后呢?”http:///2015/06/whats-next-after-separate-frontend-and-backend/。 不過(guò),僅僅靠紀(jì)律是不夠的,還需要通過(guò)工具的輔助來(lái)提高效率。下面,我們就來(lái)看一下,一個(gè)API設(shè)計(jì)工具——Swagger,將如何幫助我們更好的實(shí)現(xiàn)“前后端分離”。 SwaggerSwagger包括庫(kù)、編輯器、代碼生成器等很多部分,這里我們主要講一下Swagger Editor。這是一個(gè)完全開(kāi)源的項(xiàng)目,并且它也是一個(gè)基于Angular的成功案例,我們可以下載源碼并自己部署它,也可以修改它或集成到我們自己的軟件中。 在Swagger Editor中,我們可以基于YAML語(yǔ)法定義我們的RESTful API,然后它會(huì)自動(dòng)生成一篇排版優(yōu)美的API文檔,并且提供實(shí)時(shí)預(yù)覽。相信大多數(shù)朋友都遇到過(guò)這樣一個(gè)場(chǎng)景:明明調(diào)用的是之前約定好的API,拿到的結(jié)果卻不是想要的??赡芤?yàn)槭怯腥诵薷牧薃PI的接口,卻忘了更新文檔;或者是文檔更新的不及時(shí);又或者是文檔寫的有歧義,大家的理解各不相同??傊?,讓API文檔總是與API定義同步更新,是一件非常有價(jià)值的事。下面我們通過(guò)一個(gè)例子來(lái)感受一下Swagger給我們帶來(lái)的好處。 首先我們需要安裝一個(gè)Swagger Editor,或者也可以直接使用在線版本http://editor./。如果需要在本地啟動(dòng)編輯器,執(zhí)行以下三行命令即可(前提是已經(jīng)安裝好了Node.js):
當(dāng)我們修改了API的定義之后,在編輯器右側(cè)就可以看到相應(yīng)的API文檔了,而且永遠(yuǎn)是最新的。 不僅如此,它還能夠自動(dòng)生成Mock server所需要的代碼,這樣一來(lái)前端開(kāi)發(fā)就再也不用等著后端API 的實(shí)現(xiàn)了。除此之外,它還有一個(gè)更強(qiáng)大的功能,甚至能夠幫助我們自動(dòng)生成不同語(yǔ)言的客戶端的代碼。Swagger是基于插件來(lái)實(shí)現(xiàn)各種不同的語(yǔ)言的,所以,如果已經(jīng)提供的語(yǔ)言中沒(méi)有你正在用的,你也可以自己實(shí)現(xiàn)相應(yīng)的插件,甚至是從源代碼級(jí)別進(jìn)行定制化。 契約測(cè)試談到了前后端分離,那么在所難免,會(huì)遇到一些集成的問(wèn)題:一撥人在全心全意的進(jìn)行前端開(kāi)發(fā),另一撥人在心無(wú)旁騖的做后端開(kāi)發(fā),那么誰(shuí)應(yīng)該為集成買單呢?在現(xiàn)在這個(gè)持續(xù)集成、持續(xù)交付的年代里,我們應(yīng)該如何去保證雙方不會(huì)分道揚(yáng)鑣、越走越遠(yuǎn)呢? 所以,在一開(kāi)始就定一個(gè)契約就成了迫在眉睫的事情,雙方就API相關(guān)的內(nèi)容,包括路徑、參數(shù)、類型等達(dá)成一致,當(dāng)然,這份契約并不是一旦創(chuàng)建就不能修改的,而且,如果一開(kāi)始沒(méi)有設(shè)計(jì)好,很有可能會(huì)頻繁的修改。這個(gè)時(shí)候,要讓雙方都能夠?qū)崟r(shí)的跟蹤最新的API就成了一個(gè)難題。還好,在總結(jié)了前人的經(jīng)驗(yàn)和教訓(xùn)之后,我們?cè)缫延辛藨?yīng)對(duì)之策,那就是 老馬(Martin Fowler)早在2011年的時(shí)候就發(fā)表了一篇博客http:///bliki/IntegrationContractTest.html,專門討論了如何做契約測(cè)試。 首先,我們先假設(shè)我們已經(jīng)有了一份契約,可能是基于JSON格式的,有可能是基于XML格式的,這都不重要。然后,前端會(huì)根據(jù)這份契約建立一個(gè)Mock server,所有的測(cè)試都發(fā)往這個(gè)Mock server。有兩方面的原因:一是這個(gè)時(shí)候可能后臺(tái)的API還沒(méi)有開(kāi)發(fā)完成;二是有可能因?yàn)榫W(wǎng)絡(luò)等其他方面的原因?qū)е轮苯诱{(diào)用真實(shí)的后臺(tái)API會(huì)很不穩(wěn)定或者很耗時(shí)。到這里,可能有人就要說(shuō)了,如果后臺(tái)的API實(shí)現(xiàn)和之前約定的并不一樣,怎么能保證到了集成的時(shí)候雙方還能很順利的集成呢?其實(shí)這個(gè)問(wèn)題并不難,只需要讓前端的測(cè)試定期連接真實(shí)的API執(zhí)行一遍就能盡早的發(fā)現(xiàn)差異性。比方說(shuō),在我們平常的build pipeline上添加一個(gè)job,讓這些測(cè)試每天在午夜里連著真實(shí)的API執(zhí)行。如果,第二天發(fā)現(xiàn)這些測(cè)試有的失敗了,那么就需要和開(kāi)發(fā)后臺(tái)API的人員進(jìn)行一次溝通了,很有可能由于真實(shí)的業(yè)務(wù)邏輯發(fā)生了變化,API在實(shí)現(xiàn)的時(shí)候,已經(jīng)和之前的契約不一致了,如果是這樣,那么相應(yīng)的測(cè)試和契約定義就需要更新以滿足最新的業(yè)務(wù)需求。 總之,進(jìn)行契約測(cè)試的目的就是盡早的發(fā)現(xiàn)差異性,并作出調(diào)整,將最后集成的風(fēng)險(xiǎn)降到最低。 |
|
來(lái)自: ThinkTank_引擎 > 《自動(dòng)化》