去年,在一個大型項目(1500w)中用到Web Services,現(xiàn)在項目進入了尾聲,所以對以前的開發(fā)經(jīng)歷做一個總結(jié)。
我想大家一定會問?為什么你們項目中要用到Web Services,因為客戶有如下需求:
1、客戶要求項目用C/S架構(gòu),并且服務(wù)器端是IBM那一套:WebSphere AppServer+DB2+AIX5.3+RS/6000。
2、最終用戶上報數(shù)據(jù),因為網(wǎng)絡(luò)原因,譬如Modem上網(wǎng),可以離線操作,等填寫了幾十張報表后,可以一次提交。同時,在登錄時,可以將服務(wù)端數(shù)據(jù)同步到本地Access或MSSQL數(shù)據(jù)庫,這樣提高客戶端響應(yīng)速度。
3、由于有些報表以后可能需要修改,或添加一些新報表,又不想重新開發(fā),這樣客戶那邊工作人員可以通過客戶端自定義。
如果有以上需求,我想大家應(yīng)該都比較認同這種異構(gòu)分布式解決方案:客戶端用C# .Net開發(fā),通過Web Services調(diào)用服務(wù)器端Java組件。
其實,上面的解決方案太過于理想,最后我們不得不面對殘酷的現(xiàn)實:三種客戶端中的兩種最后被迫改為B/S。
在項目中,我主要負責Web Services和服務(wù)器端組件開發(fā)中所遇到的種種問題,相當于技術(shù)支持吧,以及部分模塊的開發(fā)。
以下是我們開發(fā)中遇到的實際問題,雖然最終都一一解決,但遇到了幾個無法突破的瓶頸:客戶端不穩(wěn)定,客戶端響應(yīng)遲緩,后期測試和維護困難巨大。
一、異構(gòu)平臺的Web Services兼容性
開發(fā)過程中,我們用Axis做WebServices引擎,Tomcat做容器。因為我們只有IBM提供的RAD6.0的60天試用版。該工具超級占內(nèi)存,用內(nèi)置的WebSphere開發(fā)測試極其緩慢,嚴重影響開發(fā)效率,經(jīng)過我初期試用后,基本廢棄了。推薦項目組二三十開發(fā)人員用Lomboz eclipse3.12開發(fā),基本滿意。
由于Axis是一個嵌入式引擎,所以可以將其打包到最終的WebSphere AppServer(WAS)上,也就是說,我們沒有用到WAS提供的Web Services引擎,這引出了后面會談到的一個問題:Web Services安全性怎么部署?
用Axis時,Axis一直都有一個bug或是說缺陷,官方文檔也詳細注明,只是我們當時沒有發(fā)現(xiàn)而走了很多彎路:用Axis發(fā)布的WebServices給.net客戶端調(diào)用時,必須用RPC風格,不能用Web Services標準的跨平臺風格Document,而后者是Lombozaxis插件的默認方式。也就是說,我們發(fā)布的WebServices總是莫名其妙的不好用。我們用JBuilder2007自帶的Axis插件發(fā)布,竟然非常順利。
二、Web Services開發(fā)中服務(wù)器端組件問題
我們服務(wù)器端開發(fā),是用Spring+Hibernate,在Spring的Service層上再封裝一層,也就是façade模式了,該façade直接發(fā)布為WebServices,必須經(jīng)過這個轉(zhuǎn)換,一是因為性能,二是因為Hibernate的復雜Model對象,在wsdl描述后,被.net客戶端識別有些問題,List、Map也會有問題,總之這些對象太復雜了,我們包裝成簡單的VO對象。
另外一個問題是,我們的service方法,如果直接給WebWork這樣的框架在服務(wù)端用的的話,是不會出問題,當提供給.net客戶端用時,就會出現(xiàn)lazyloading的錯誤,因為.net客戶端不能接收Proxy對象,必須將數(shù)據(jù)全部load出來,但這時Hibernate的session已經(jīng)關(guān)閉。項目組很多人遇到這些問題,最后大家不約而同的全部用eager模式,導致了最后的惡果:嚴重的的性能問題。由于我不是leader,所以當時這個問題發(fā)現(xiàn)了,也沒法要求別人,畢竟很大的一個團隊。
切身體會:一個團隊,如果不熟悉Hibernate就隨便上,技術(shù)風險非常大。Hibernate帶來的開發(fā)效率,是以團隊成員掌握它為前提。
當然,性能問題不只是由Hibernate引起,WebServices本身的性能也非常嚴重:XML的序列化和反序列化耗時,XML文件的膨脹導致的網(wǎng)絡(luò)傳輸,HTTP的無狀態(tài)導致網(wǎng)絡(luò)IO性能。切身體會:如果系統(tǒng)必須用分布式,而不是追求所謂的SOA架構(gòu),WebServices應(yīng)該是下下策,因為還有很多協(xié)議和方式可以選擇:IIOP、RMI、Hessian、burlap、RPC,另外,做系統(tǒng)集成還有Message方式。
Web Services開發(fā)中其它問題比較少,因為Web Services本身不用編程,只是部署的事情,開發(fā)工具和服務(wù)器會自動為我們做,我們只需要理解SOAP引擎的原理和使用就夠了,真的遇到問題,可以通過Axis的TcpMonitor監(jiān)視SOAP數(shù)據(jù)包。
開發(fā)過程中,.net客戶端那邊,VSStudio做得很智能,它會根據(jù)wsdl文件生成我們所要的一切,當然,wsdl文件的變化,會導致VSStudio重新生成所有的類和接口,也很耗時,并且容易出問題。
三、Web Services的安全問題
當時解決Web Services安全問題,花了我將近一個月的時間,主要是學習和處理如下四個問題:
XML和Web Services安全規(guī)范
WAS的 Web Services引擎的安全部署
Axis和參考的Xfire引擎的Web Services安全
.net客戶端WSE3.0的安全以及和WAS的通訊
最后這些問題基本上都解決了,不過還是沒有用上,因為在我們已經(jīng)開發(fā)的幾種客戶端和服務(wù)器端部署上很麻煩,還要測試,另外,客戶也沒法驗收這個啊。
當然,我們還回避了一個嚴肅的問題:我們的Web Services是發(fā)布在Axis引擎上,還沒有移植到WAS的WebServices引擎,而發(fā)布在這個平臺,必須有RAD這類開發(fā)工具支持,幾乎沒法手動做。WAS引擎的WebServices安全配置異常復雜:我們當時只配置了Authentication和Integration,沒有做Encryption,但完全夠用。我當時用Sun的NetBean開發(fā)工具發(fā)布了一下Web Serivces,也是挺好用的,不過沒有配置安全。順便說一下,Sun的webServices引擎jwsdp2.0設(shè)計有點類似于EJB容器,很不好用,移植性特差。
我們當時用Axis引擎是1.3版本,而該版并不支持標準的OASIS的WS-Security,只有到2.0版才開始,而且?guī)缀醵际鞘謱懪渲梦募?/p>
WAS的WebServices安全配置,對照IBM的紅皮書,不是很難,但很復雜,安全相關(guān)的xml代碼都好幾百行,好幾個文件。配置過程中,和.net客戶端通訊時遇到一個問題,怎么也不能互通,但.net和.net客戶端可以互通,Java和Java客戶端也可以互通,最后我通過攔截soap包,找到了解決辦法:必須手動更改http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3后的v3,IBM工具生成的是v1,這是標準不兼容引起的,因為當時RAD是04年底,而微軟的WSE3.0比較新。后來發(fā)現(xiàn)這篇文章有相似的經(jīng)歷:http://pluralsight.com/blogs/kirillg/archive/2005/04/13/7315.aspx
在處理Web Services安全過程中,我通過emule和IBM網(wǎng)站下載了上10本這方面的書籍,我覺得以下資料對我?guī)椭畲螅?br>
四、開發(fā)過程中的的溝通問題
這應(yīng)該不是一個技術(shù)問題,而是一個軟件開發(fā)方法學的問題,但對整個軟件開發(fā)過程影響極大。
我們面對的現(xiàn)實:.net客戶端開發(fā)人員不懂服務(wù)器端Java,服務(wù)器端Java開發(fā)人員不懂.net。
除了技術(shù)壁壘外,還有業(yè)務(wù)銜接性的問題,因為我們不是縱向分模塊開發(fā),而橫向開發(fā)的前提是我們服務(wù)器端開發(fā)人員很熟悉業(yè)務(wù),知道客戶端需要的接口,但實際上,業(yè)務(wù)主要由客戶端推動。所以,兩端的開發(fā)人員都遇到很大的溝通壁壘。
從技術(shù)的角度表達就是:客戶端開發(fā)人員需要的接口,服務(wù)器端開發(fā)人員不清楚;服務(wù)器端開發(fā)人員也不知道怎么把握粒度。譬如,有個 updateUser方法,但更新用戶信息時,可能需要更新很多信息:用戶信息、用戶角色、用戶所屬組….。loadUser時也有同樣的按需加載問題。
當然,從技術(shù)角度,開發(fā)Web Serivces有Bottom-up和Top-down兩種開發(fā)模式。我們選擇了前者,也是最常見的方式,也許用后者更適合我們的項目:從定義的 wsdl文件開始,客戶端和服務(wù)器端開發(fā)都遵循它。但問題是:我們怎么確定wsdl,也就是我們所要求的接口,因為我們自己對業(yè)務(wù)都不是很熟。
五、客戶端和服務(wù)端開發(fā)測試方法
我們當時做得很笨,也最直接:等服務(wù)器端組件發(fā)布完畢后,通知客戶端開發(fā)人員,然后客戶端開發(fā)人員通過VSStudio提供的Web Services生成工具,根據(jù)Axis發(fā)布的wsdl文件,生成所需的.net對象,然后像本地調(diào)用一樣使用。
但問題是:
wsdl隨時都在變,這意味著客戶端生成的組件總在變化,經(jīng)常出現(xiàn)編譯錯誤。
客戶端開發(fā)過程中遇到的問題,一會是客戶端自己,一會是服務(wù)器端組件:我要的方法包含的信息不夠啊。
服務(wù)器組件測試一次,起容器特慢,而且客戶端調(diào)用也慢。
我們的測試,最后走入了一個怎樣的泥潭:譬如測試一張報表,都是在客戶端手工填寫,然后觀察服務(wù)器端日志和響應(yīng)。有人會問,用 LoadRunner或Function Tester這類自動測試工具不就ok了嗎?我都用過,它們對Web UI確實好用,后者對Swing客戶端也好用,但對.net客戶端,像是不太現(xiàn)實。
另外,Debug非常困難,因為它要求兩端開發(fā)人員必須在一起密切配合。
我自己認為的解決方案,但未必真的好用:
服務(wù)器端Service方法必須寫單元測試TestCase,可能代碼量非常大,測試好后方發(fā)布為Web Services。
同時,服務(wù)器端提供同一套接口的Mock實現(xiàn),供客戶端開發(fā)測試,解決并行開發(fā)的問題。
六、其它問題
當然,上面的幾點,具體到細節(jié),我都省略了,總之問題非常非常多:技術(shù)問題、管理問題、方法和過程問題。
特別提的一點是,我們幾乎開發(fā)了兩套“業(yè)務(wù)層+持久化”解決方案,因為離線客戶端也用了NHibernate持久化,這樣導致開發(fā)測試工作量巨大, 就說一點吧:兩邊同步是通過打包的sql語句,通過SOAP傳輸,但Access和DB2的sql有不兼容問題,如果要兼容,就會以犧牲性能和靈活性為代 價。
另外,我們寫項目建議書時很被動,但也沒辦法,因為有好幾家公司競爭。對我們影響極大的幾個問題:
當然,這個子系統(tǒng)只是我們那個龐大系統(tǒng)的一個部分。上面也就算我做的一點點總結(jié)吧,也是教訓??!不過,從個人角度考慮,學到的東西還是很多的。
這個子系統(tǒng)花去了我們將近200個人月,如果說那浪費的部分,估計至少是100個人月的工作量。是什么導致?從我這篇文章只能窺其一角,因為整個系統(tǒng)涉及CMS、OA、BI、E-commerce、GIS、IM、MIS。我自己總結(jié)一下,有以下原因:
1、項目建議書空洞,不切實際:公司也很無奈,客戶也不成熟。
2、需求調(diào)研后的需求分析閉門造車:客戶的合同是分階段,我們上交需求說明書后付20%款,上交設(shè)計書后又付20%。全一個瀑布開發(fā),雖然按RUP文檔寫。到半年后的實際開發(fā)時,發(fā)現(xiàn)很多需求都不合理。
3、整個過程都沒有和客戶溝通,到最后開發(fā)完畢才讓客戶看,那時客戶也懵了:這不是我要的產(chǎn)品啊。改呀,改呀,熬夜啊。
4、項目團隊整體技術(shù)實力薄弱,當時調(diào)來做Java開發(fā)的人員,只有少數(shù)幾個以前做Java,大多數(shù)是臨時學。想起那Hibernate使用,心寒啊。另外,WAS問題、AIX問題在產(chǎn)品環(huán)境下都出來了:系統(tǒng)不穩(wěn)定、宕機。
5、整個開發(fā)階段流程沒有把握好,像項目規(guī)范、測試方法、日志、版本控制,這些后期都出現(xiàn)了,而且非常嚴重。就說那日志吧,最后出問題都不知道怎么查,日志一遍混亂。
6、缺乏做大項目經(jīng)驗,整個系統(tǒng)架構(gòu)都比較松散,項目開始時很多都不知從何入手,也很倉促。
7、項目持續(xù)一年多,人都換了幾批了,工作交接很大問題。
.....
不過,說實話,項目團隊,特別是進公司一、兩年的員工都很努力,沒有人抱怨什么,我和他(她)們一起合作,還是很開心的