案例研究:巴西國(guó)家醫(yī)療保健系統(tǒng)作者 Fabiane Nardon, Floyd Marinescu譯者 沙曉蘭 發(fā)布于 2007年12月2日 上午9時(shí)0分 巴西國(guó)家醫(yī)療保健系統(tǒng)曾被喻為全球最大的Java企業(yè)應(yīng)用,涉及200多萬(wàn)行代碼,囊括一個(gè)350個(gè)類(lèi)的區(qū)域模塊。該系統(tǒng)把所有能想象到全國(guó)范圍內(nèi)的各類(lèi)行政地區(qū)模塊化,其所實(shí)現(xiàn)的自動(dòng)化給公共醫(yī)療保健系統(tǒng)創(chuàng)造了巨大的價(jià)值,讓巴西人受益匪淺。本案例分析,從系統(tǒng)構(gòu)架、解決方案、教訓(xùn)與啟發(fā)以及項(xiàng)目的未來(lái)趨向等做全方面詳細(xì)深入的探索。 問(wèn)題域巴西是世界上僅有的幾個(gè)提供完全免費(fèi)公共醫(yī)療保健系統(tǒng)的國(guó)家之一。和所有重大的公共服務(wù)設(shè)施一樣,它存在很多操作性問(wèn)題,原先很多工作都基于大量的紙質(zhì)文件之上,政府部門(mén)和地區(qū)醫(yī)療保健部門(mén)的IT系統(tǒng)間只有很小一部分實(shí)行了集成。例如:
考慮到這么多問(wèn)題的存在,政府批準(zhǔn)創(chuàng)建一個(gè)自動(dòng)化醫(yī)療保健系統(tǒng),命名為Siga Saude。系統(tǒng)設(shè)計(jì)目標(biāo)是覆蓋所能想到的公共醫(yī)療保健信息系統(tǒng)的所有方面,包括會(huì)診調(diào)度,醫(yī)生和醫(yī)療器械的目錄清單管理,帳單,病理跟蹤,審核報(bào)告,規(guī)章制度的遵循,以及安全訪問(wèn)控制等。 系統(tǒng)首先在圣保羅市(巴西的最大城市,有近2000萬(wàn)人口,也是世界第4大城市)的所有醫(yī)療保健單位投入使用。如今,該應(yīng)用程序除了在圣保羅和其他20個(gè)城市中投入使用以外,也正逐漸覆蓋到巴西其他一些城市。除此之外,還有一些想要實(shí)現(xiàn)全國(guó)醫(yī)療保健系統(tǒng)自動(dòng)化的國(guó)家對(duì)此系統(tǒng)也產(chǎn)生濃厚的興趣,例如葡萄牙語(yǔ)國(guó)家安哥拉和莫桑比克等。 解決方案概述該應(yīng)用開(kāi)發(fā)基于EJB2.1和Struts,采用成熟的EJB設(shè)計(jì)模式,引入數(shù)據(jù)傳送對(duì)象(data transfer objects)、會(huì)話外觀(session facade),服務(wù)定位( service locator),業(yè)務(wù)委托( business delegates),完美定義了一個(gè)層次分明的構(gòu)架。整個(gè)開(kāi)發(fā)在Eclipse環(huán)境下完成,測(cè)試和最后部署使用JBoss應(yīng)用服務(wù)器。在一些特定部分,也采用了Drools規(guī)測(cè)引擎(rules engine)。目前,應(yīng)用程序非集群地(non-clustered)部署運(yùn)行于Dual Xeon 3.1服務(wù)器之上,該服務(wù)器具有4GRAM,Linux操作系統(tǒng),并運(yùn)行JBoss 3.2.7。 從需求到開(kāi)發(fā),150多人參與了系統(tǒng)的功能定義工作,這些人中包括醫(yī)生和健康資訊專(zhuān)家。根據(jù)功能定義,研發(fā)團(tuán)隊(duì)最終把系統(tǒng)分解成以下這些模塊:
上述模塊圖中所標(biāo)出的每個(gè)模塊代碼行的數(shù)量均包括了服務(wù)層和與該模塊相對(duì)應(yīng)的域模型的代碼。另外,在服務(wù)層,有10萬(wàn)行代碼是模塊間共享,有57萬(wàn)行是各域模型間共享。代碼行的數(shù)量聽(tīng)上去有點(diǎn)嚇人,但實(shí)際上58%是自動(dòng)生成代碼,這在下文主題中關(guān)于注釋?zhuān)╝nnotation)的部分會(huì)討論到。 上述所有業(yè)務(wù)模型都包含JSP頁(yè)面,Struts Actions 和在服務(wù)層實(shí)現(xiàn)的業(yè)務(wù)委托。服務(wù)層包括EJB2.1的會(huì)話beans(session beans)和自動(dòng)生成的會(huì)話外觀(session facade)。域模塊包括pojo's和提供自動(dòng)生成實(shí)例Bean的注釋(annotation)。接下來(lái)會(huì)從URL到SQL一步一步詳細(xì)分析最后實(shí)現(xiàn)的調(diào)度系統(tǒng)。這里提到的系統(tǒng)模塊劃分、分層和其他的功能實(shí)現(xiàn)相一致,該模塊劃分圖實(shí)際上也幫助我們清晰地去了解該系統(tǒng)是如何構(gòu)建的。 經(jīng)驗(yàn)一:專(zhuān)家門(mén)診預(yù)約調(diào)度用例無(wú)論從經(jīng)濟(jì)還是技術(shù)觀點(diǎn)出發(fā),該系統(tǒng)最重要的用例之一是描述一個(gè)地方小診所的前臺(tái)如何幫助病人預(yù)約專(zhuān)家門(mén)診。用例在調(diào)度模塊中實(shí)現(xiàn),同時(shí)牽涉到許多其他模塊。這個(gè)預(yù)約調(diào)度用例是這樣的:
首先,前臺(tái)在時(shí)間安排表中找到空的時(shí)間隙。這可以通過(guò)許多途徑查找,比如查找一個(gè)指定的醫(yī)生、專(zhuān)科、特定的醫(yī)療設(shè)備、醫(yī)療過(guò)程等等(點(diǎn)擊這里查看輸入界面), “getSlots”的序列圖參考下圖。當(dāng)他們找到某個(gè)空的時(shí)間隙(在序列圖上標(biāo)識(shí)為chooseSlot())以后,可以通過(guò)掃描病人醫(yī)療卡上的條形碼或者在病人忘了攜帶醫(yī)療卡的情況下通過(guò)輸入病人的姓名、出生日期或病人任何其他聯(lián)系方式查找到該病人的記錄,使用國(guó)家醫(yī)療保健卡模塊將病人簡(jiǎn)歷關(guān)聯(lián)到該時(shí)間隙(查看searchPatient())。然后,在同一界面上輸入所需的療程類(lèi)型,(參考第二個(gè)用戶輸入界面,序列圖上標(biāo)識(shí)為saveAppointment())。 如果診所沒(méi)有病人所需要的療程,可能的原因之一是診所沒(méi)有空的時(shí)間隙安排給病人預(yù)約就診,或者就是診所不提供這樣的療程,在這種情況下,前臺(tái)或者醫(yī)生可以幫助病人通過(guò)系統(tǒng)在其他診所預(yù)約合適的診療。
此序列圖描繪了一個(gè)典型用例在系統(tǒng)中的執(zhí)行過(guò)程。首先,一個(gè)Struts Action類(lèi)(ScheduleAction)執(zhí)行用戶請(qǐng)求并處理表示層邏輯。當(dāng)需要讀取數(shù)據(jù)或者需要引用業(yè)務(wù)規(guī)則的時(shí)候,Action類(lèi)調(diào)用實(shí)現(xiàn)了業(yè)務(wù)委托設(shè)計(jì)模式(ScheduleCF)的POJO對(duì)象的方法。這個(gè)類(lèi)從會(huì)話Facade類(lèi)(ScheduleCF)自動(dòng)生成,并將Web層從服務(wù)層使用的技術(shù)中獨(dú)立出來(lái)。那些實(shí)現(xiàn)了會(huì)話Facade設(shè)計(jì)模式(ScheduleCF)的會(huì)話Beans負(fù)責(zé)對(duì)其他類(lèi)執(zhí)行業(yè)務(wù)規(guī)則。例如,類(lèi)AppointmentService實(shí)現(xiàn)方法lockSlot()和searchForSlots(),當(dāng)用例需要保持?jǐn)?shù)據(jù)的時(shí)候,方法setAppointmentVO()在一個(gè)實(shí)例Bean上被調(diào)用。實(shí)例Bean機(jī)制不執(zhí)行數(shù)據(jù)庫(kù)查詢,但可以使用一個(gè)稱為Searcher的查詢優(yōu)化控件來(lái)彌補(bǔ)這個(gè)空缺。 會(huì)話Facade對(duì)象負(fù)責(zé)提供事務(wù)處理服務(wù)(transaction service)、數(shù)據(jù)庫(kù)連接和對(duì)應(yīng)用程序其他部分的安全服務(wù)。因?yàn)榉?wù)對(duì)象是POJO,它無(wú)法從Web層直接訪問(wèn)實(shí)例Beans,這時(shí)就需要加入一個(gè)會(huì)話bean層來(lái)幫忙了。 如果某個(gè)時(shí)間隙被鎖定,在會(huì)診預(yù)約安排數(shù)據(jù)庫(kù)中會(huì)存入相應(yīng)的時(shí)間戳和鎖定號(hào)(lock ID)。為了防止競(jìng)爭(zhēng)條件(race condition),這兩項(xiàng)數(shù)據(jù)通過(guò)一個(gè)SELECT FOR UPDATE命令保存。時(shí)間戳用來(lái)決定該預(yù)約是否過(guò)期,而儲(chǔ)存鎖定號(hào)的目的是為了避免對(duì)象試圖儲(chǔ)存過(guò)期預(yù)約的情況出現(xiàn)。當(dāng)對(duì)象請(qǐng)求儲(chǔ)存鎖定預(yù)約的時(shí)候,它會(huì)將收到的鎖定號(hào)和數(shù)據(jù)庫(kù)當(dāng)前鎖定號(hào)做比較,如果這兩個(gè)號(hào)不相同,那么這個(gè)新的診療預(yù)約信息不會(huì)被儲(chǔ)存。這樣一來(lái),即使某個(gè)鎖定發(fā)生在發(fā)送鎖定請(qǐng)求和診療預(yù)約儲(chǔ)存之間,都能被應(yīng)用系統(tǒng)偵測(cè)到且向用戶發(fā)送警告。該用例實(shí)現(xiàn)了一個(gè)邏輯鎖定。無(wú)論是數(shù)據(jù)庫(kù)還是EJB鎖定都不需要很長(zhǎng)的時(shí)間,利于實(shí)現(xiàn)業(yè)務(wù)規(guī)則。 該用例中涉及到的域?qū)ο蟮暮?jiǎn)化類(lèi)圖如下:
經(jīng)驗(yàn)二:應(yīng)用注釋(annotation)生成代碼項(xiàng)目初期,開(kāi)發(fā)團(tuán)隊(duì)采用XDoclet1來(lái)生成部署描述器(deployment descriptors),值對(duì)象(value objects),查詢,會(huì)話facades,Struts表和動(dòng)作,值驗(yàn)證,以及本地和遠(yuǎn)程EJB接口等。由于項(xiàng)目的短時(shí)間開(kāi)發(fā)周期(short time frame)計(jì)劃,需要應(yīng)用一些額外技術(shù)幫助開(kāi)發(fā)團(tuán)隊(duì)在短時(shí)間內(nèi)和保證減少bug的前提下盡可能多產(chǎn),代碼生成也就成為這個(gè)項(xiàng)目中的一個(gè)關(guān)鍵策略。也因?yàn)樗年P(guān)鍵性,最初的XDoclets模板后來(lái)被修改生成“專(zhuān)家代碼”。 起初的10個(gè)月里,XDoclet方式在項(xiàng)目進(jìn)行中很適用,幫助開(kāi)發(fā)團(tuán)隊(duì)達(dá)到了所需的開(kāi)發(fā)能力,但沒(méi)過(guò)多久,隨著代碼的不斷增多,生成代碼的速度卻越來(lái)越慢,以至于生產(chǎn)率慘遭嚴(yán)重影響。于是,開(kāi)發(fā)團(tuán)隊(duì)決定采用另一種代碼生成策略,這就是Java 5 注釋 (annotations)。 注釋策略可以解決XDoclet的以下幾項(xiàng)缺點(diǎn):
團(tuán)隊(duì)為EJB 3.0 注釋和其他一些自定義注釋開(kāi)發(fā)了處理器,使其最后生成的代碼和采用XDoclet時(shí)所生成代碼的相似。這些生成的代碼在EJB 2.1下也同樣兼容。 注釋處理器使用Velocity模板。從XDoclet轉(zhuǎn)移到自己編寫(xiě)使用的模板中,最大的挑戰(zhàn)是構(gòu)建和XDoclet提供的同樣容易理解的一組模板和幫助類(lèi)。 采用注釋以后,代碼生成時(shí)間縮短很多。使用XDoclet,如果其中一個(gè)類(lèi)有所修改,需要1分50秒的時(shí)間從400個(gè)類(lèi)中重新生成代碼,但是使用APT以后,同樣的操作僅需10秒鐘。 經(jīng)驗(yàn)三:規(guī)則引擎如何簡(jiǎn)化業(yè)務(wù)邏輯根據(jù)政府立法,一些業(yè)務(wù)邏輯一直在修改中,有些按城市各異,系統(tǒng)某些部分不得不處理這些特殊的業(yè)務(wù)邏輯。比方說(shuō),某診所想要提供x光透視服務(wù),這等價(jià)于幾項(xiàng)服務(wù)規(guī)則,擁有x光透視設(shè)備,有授權(quán)資格的放射科醫(yī)生等。由于這些規(guī)則經(jīng)常在變,所以最好把它們留在主代碼庫(kù)外頭,這樣即使規(guī)則被修改也不用去修改代碼。 在SIGA-Saude系統(tǒng)中,因?yàn)橐肓?a href="http:///">Drools 規(guī)則引擎而使這個(gè)難題迎刃而解。Drools實(shí)現(xiàn)了JSR-94-Java 規(guī)則引擎應(yīng)用程序接口。規(guī)則由SIGA-Saude系統(tǒng)中一個(gè)稱作Decision的控件來(lái)處理。該控件工作于一組規(guī)則組和一個(gè)工作記憶區(qū)(working memory)。規(guī)則組工作于一組消息,每條規(guī)則都相應(yīng)有一條由實(shí)現(xiàn)了br.com.vidatis.common.decision.message.RuleMessage接口的類(lèi)描述的消息。當(dāng)一條規(guī)則或是規(guī)則組的子集被滿足的時(shí)候,對(duì)應(yīng)的消息會(huì)從隊(duì)列中移除,這樣做可以追蹤規(guī)則的處理。如果最后在隊(duì)列中沒(méi)有任何消息剩下,表明規(guī)則組中的所有的規(guī)則都被滿足。任何一條規(guī)則都可以觸發(fā)許多不同的動(dòng)作,也可以觸發(fā)新的規(guī)則組,規(guī)則在XML文件中描述,然后交由Drools引擎處理。 XML文件范例: <rule name="if_clinic_code_then_checksum_digit_valid"> 這個(gè)例子中,保存某診所數(shù)據(jù)的時(shí)候,服務(wù)類(lèi)會(huì)調(diào)用Drools規(guī)則引擎檢查和認(rèn)證所有的規(guī)則,數(shù)據(jù)只有符合所有的規(guī)則才能被儲(chǔ)存。這些認(rèn)證規(guī)則隨著政府制定的規(guī)章制度的修改而變化。由于修改經(jīng)常發(fā)生,所以把它們和應(yīng)用程序代碼劃分開(kāi)來(lái)非常重要,這樣才能在維護(hù)和修改程序的時(shí)候不需要重啟整個(gè)應(yīng)用系統(tǒng)。 教訓(xùn)與啟發(fā)代碼生成在這個(gè)項(xiàng)目中是成功的關(guān)鍵,它不但提高了開(kāi)發(fā)人員的生產(chǎn)率,同時(shí)也保證了代碼風(fēng)格一致。在50個(gè)開(kāi)發(fā)人員在各個(gè)獨(dú)立團(tuán)隊(duì)中各自工作且共享基礎(chǔ)組件的情況下,使他們保持代碼一致性非常困難。起初采用XDoclet,然而好景不長(zhǎng),由于生成文件時(shí)間越來(lái)越長(zhǎng),對(duì)開(kāi)發(fā)速度帶來(lái)出乎意料的壞影響。之后,轉(zhuǎn)而采用注釋策略,才大大地減短了生成時(shí)間,真正體現(xiàn)了生成代碼的優(yōu)越性。 好的團(tuán)隊(duì)交流是必須的。特別是像這樣的大項(xiàng)目,總會(huì)有些時(shí)候有些人發(fā)表不同的意見(jiàn)。讓所有的人互相理解對(duì)方的觀點(diǎn)實(shí)在很難。特別是在這樣一群人中,交流真的是讓人頭疼的難題:
如果你的構(gòu)架定義確切,有規(guī)則、有代碼生成、套用設(shè)計(jì)模式、構(gòu)件的話,就比較容易進(jìn)行小范圍或中等程度的軟件重構(gòu),大范圍重構(gòu)往往很麻煩。然而,現(xiàn)實(shí)系統(tǒng)的部分構(gòu)架不夠確切,嚴(yán)格的規(guī)則更使得20%的應(yīng)用程序那以實(shí)現(xiàn)。明確你究竟能夠在加強(qiáng)構(gòu)架標(biāo)準(zhǔn)這點(diǎn)上走多遠(yuǎn)至關(guān)重要。項(xiàng)目開(kāi)發(fā)過(guò)程中,有時(shí)候就算一些解決方案顯然不是最好的,開(kāi)發(fā)人員也只是強(qiáng)行將它們向構(gòu)架靠攏,而非重新探討最佳方案。另一方面,系統(tǒng)中某些部分,規(guī)則要求并不嚴(yán)格,比如說(shuō)用戶界面,對(duì)于這些部分,開(kāi)發(fā)人員則各取其愛(ài),以至于造成系統(tǒng)這些部分質(zhì)量較差、代碼不易管理等預(yù)料未及的壞結(jié)果。 在龐大的應(yīng)用程序中,面對(duì)繁雜的依賴性和代碼,開(kāi)發(fā)周期往往不得不延長(zhǎng)。有時(shí)候,在某個(gè)界面上加上一個(gè)簡(jiǎn)單的域(field)就意味著系統(tǒng)的許多部分都隨之需要修改,這很費(fèi)時(shí)間。無(wú)論是開(kāi)發(fā)人員還是客戶都因此感到頭痛,工具變得太過(guò)沉重以至于所有一切都比原本更花時(shí)間。把應(yīng)用程序劃分成許多構(gòu)件,還是不足以徹底解決問(wèn)題。盡管J2EE有很多優(yōu)點(diǎn),但同時(shí)代碼也更加復(fù)雜,生產(chǎn)率還是受到影響,這些很難跟管理人員和客戶解釋清楚。 項(xiàng)目啟動(dòng)最初,很多人都說(shuō)按照那樣的短時(shí)開(kāi)發(fā)周期,項(xiàng)目根本沒(méi)有辦法完成。在其他一些國(guó)家的公共醫(yī)療保健系統(tǒng)開(kāi)發(fā)過(guò)程中,也都發(fā)生過(guò)太多太多令人汗顏的經(jīng)驗(yàn)。所以,從這個(gè)項(xiàng)目中得到的最后一個(gè)啟示是:當(dāng)別人說(shuō)某件事不可能的時(shí)候,千萬(wàn)不要讓他們這樣的泛泛之說(shuō)影響了你去將這件事變得可能。 未來(lái)方向容器外測(cè)試無(wú)法進(jìn)行容器外測(cè)試讓開(kāi)發(fā)團(tuán)隊(duì)很困擾,無(wú)法在初期就進(jìn)行容器外測(cè)試的原因是他們被迫從合法的代碼開(kāi)始工作。政府制定的規(guī)則和規(guī)章條例模塊是一個(gè)巨大的EJB 1.0系統(tǒng)。結(jié)合代碼生成技術(shù)來(lái)處理所有的實(shí)例bean和其他容器假象(container artifact),程序的新生部分變的越來(lái)越基于POJO。但將他們部署到容器中以后,甚至只是一個(gè)漸進(jìn)變化也緩慢到開(kāi)發(fā)人員無(wú)法接受的地步。 遷移到基于POJO的構(gòu)架目前的系統(tǒng)明顯有大量的容器依賴和EJB樣板代碼(plumbing code)(盡管大部分都隱藏在生成的業(yè)務(wù)委托和會(huì)話外觀中),但開(kāi)發(fā)團(tuán)隊(duì)計(jì)劃的遷移方向是完完全全基于POJO,包括業(yè)務(wù)規(guī)則,他們計(jì)劃將所有的會(huì)話Bean重構(gòu)成一個(gè)單一的會(huì)話bean interceptor,由這個(gè)單一的會(huì)話bean interceptor專(zhuān)門(mén)向服務(wù)層調(diào)用。構(gòu)建這個(gè)單一的會(huì)話bean interceptor的目的在于提供像事務(wù)(transaction)和線程管理這樣的中間件服務(wù)。他們?cè)仍O(shè)想在修改之后的構(gòu)架上采用Spring,但這注定開(kāi)銷(xiāo)太過(guò)昂貴。鑒于當(dāng)時(shí)擁有的會(huì)話bean都已經(jīng)全部生成,相比較從EJB中完全引身而退來(lái)說(shuō),修改代碼生成邏輯來(lái)貫徹會(huì)話bean interceptor明顯簡(jiǎn)單得多。將這樣的重構(gòu)變得可能的另一個(gè)元素是現(xiàn)存的業(yè)務(wù)委托層可以將這些大幅修改從Web端屏蔽。 為什么他們沒(méi)有一并擺脫掉EJB呢?理由是最后他們必須將應(yīng)用程序展示給在醫(yī)療衛(wèi)生部門(mén)的另外的團(tuán)隊(duì),這些團(tuán)隊(duì)需要訪問(wèn)該系統(tǒng),并正準(zhǔn)備簡(jiǎn)單地讓工作人員(從圣保羅市)接手開(kāi)始投入使用可行的業(yè)務(wù)委托。由于業(yè)務(wù)委托隱藏了遠(yuǎn)程的各方面,他們知道合作方將不會(huì)工作于Java上,所以預(yù)期系統(tǒng)集成會(huì)非常順利。 不同的事務(wù)類(lèi)型又將如何處理呢?不同的事務(wù)界限有不同的方法,目標(biāo)方法和事務(wù)類(lèi)型間有一個(gè)映射,所以他們知道該執(zhí)行哪個(gè)方法來(lái)處理相應(yīng)的事務(wù)。順便提一句,這里的會(huì)話Bean interceptor和事務(wù)策略同F(xiàn)loyd Marinescu在EJB設(shè)計(jì)模式一書(shū)中描述的極為相近。 :) 最終,他們實(shí)在是想擺脫掉實(shí)例Bean,也許甚至想直接只保存值對(duì)象和Hibernate。面對(duì)這樣修改的潛在可能性最大花銷(xiāo)是測(cè)試,他們必須徹徹底底地測(cè)試系統(tǒng)的每個(gè)方面,單一的單元測(cè)試無(wú)法覆蓋全部。 AJAX簡(jiǎn)化Web用戶界面AJAX被公認(rèn)是為非技術(shù)終端用戶簡(jiǎn)化用戶界面工作流程的有效工具。就如在調(diào)度用例中,自動(dòng)補(bǔ)全(auto-completion)可以幫助輸入醫(yī)生姓名,療程名稱,專(zhuān)科名稱,實(shí)在沒(méi)有理由去調(diào)用彈出窗口來(lái)做查詢,從長(zhǎng)長(zhǎng)的列單中去尋找這些名字。另外,在使用大而冗長(zhǎng)的表單時(shí),使用AJAX一步一步將表單域的值保存到HTTPSession中去無(wú)疑會(huì)更好,還能防止一些用戶因不小心錯(cuò)關(guān)頁(yè)面而遺失所輸入的信息。 最近AJAX也被部署項(xiàng)目中,被用來(lái)瀏覽一個(gè)需要讀取數(shù)據(jù)的巨大的流程樹(shù),幫助我們?cè)诳s短了數(shù)據(jù)錄入時(shí)間的同時(shí)也給終端用戶提供更漂亮的界面。點(diǎn)擊這里查看界面截圖。 查看英文原文:Casestudy: Brasilian National Healthcare System7 條回復(fù)little mistake 發(fā)表人 曉 汪 發(fā)表于 2007年12月2日 下午6時(shí)26分
Re: little mistake 發(fā)表人 霍 泰穩(wěn) 發(fā)表于 2007年12月2日 下午9時(shí)52分
Re: little mistake 發(fā)表人 曉 汪 發(fā)表于 2007年12月2日 下午10時(shí)15分
擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市 發(fā)表人 wander zhou 發(fā)表于 2007年12月3日 下午6時(shí)29分
Re: 擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市 發(fā)表人 sihai T 發(fā)表于 2007年12月3日 下午7時(shí)55分
Re: 擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市 發(fā)表人 霍 泰穩(wěn) 發(fā)表于 2007年12月3日 下午8時(shí)15分
Re: 擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市 發(fā)表人 涼粉 小刀 發(fā)表于 2007年12月4日 上午5時(shí)45分
|
|
來(lái)自: pstn > 《我的圖書(shū)館》
返回頂部
little mistake
2007年12月2日 下午6時(shí)26分 發(fā)表人 曉 汪
在"經(jīng)驗(yàn)三:規(guī)則引擎如何簡(jiǎn)化業(yè)務(wù)邏輯"的內(nèi)容中,jsp-94是否應(yīng)為 jsr-94? 還有,可否發(fā)原文鏈接?謝謝
回復(fù)
返回頂部
Re: little mistake
2007年12月2日 下午9時(shí)52分 發(fā)表人 霍 泰穩(wěn)
經(jīng)核實(shí),確實(shí)是“JSR-94”(一個(gè)Java規(guī)則引擎),已經(jīng)做了修正,并補(bǔ)全了原文鏈接。謝謝汪曉朋友的指正!
回復(fù)
返回頂部
Re: little mistake
2007年12月2日 下午10時(shí)15分 發(fā)表人 曉 汪
^_^多謝
回復(fù)
返回頂部
擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市
2007年12月3日 下午6時(shí)29分 發(fā)表人 wander zhou
2億人口的城市太可怕了。
回復(fù)
返回頂部
Re: 擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市
2007年12月3日 下午7時(shí)55分 發(fā)表人 sihai T
“擁有2億多人口的巴西最大的城市”應(yīng)該是“擁有2億多人口的巴西的最大城市”
回復(fù)
返回頂部
Re: 擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市
2007年12月3日 下午8時(shí)15分 發(fā)表人 霍 泰穩(wěn)
這句話確實(shí)有歧義,已經(jīng)根據(jù)Sihai T朋友的建議對(duì)原文做了修改。非常感謝wander zhou和sihai T朋友的指正!
回復(fù)
返回頂部
Re: 擁有2億(應(yīng)該為2000萬(wàn))多人口的巴西最大的城市,也是世界第4大城市
2007年12月4日 上午5時(shí)45分 發(fā)表人 涼粉 小刀
2000萬(wàn)那里還要改一下的