GHawk

          2005年12月15日 #

          建議方正要是勝訴的話,為開源事業(yè)做點(diǎn)貢獻(xiàn)

          中國(guó)人民可以說是被盜版和Windows慣壞了。在Linux默認(rèn)環(huán)境下的中文顯示至今慘不忍睹。
          看看現(xiàn)在一些主要的發(fā)行版本,默認(rèn)設(shè)置下的日語的顯示已經(jīng)相當(dāng)不錯(cuò)了。
          作為漢字發(fā)祥地且擁有眾多人口的中國(guó),實(shí)在是有些悲哀。
          文泉驛計(jì)劃正在為實(shí)現(xiàn)這個(gè)目標(biāo)努力。作為一個(gè)非盈利性組織,他們的貢獻(xiàn)的確值得贊賞。
          最近方正正在為字體的事情打官司,并提出了高額賠償?shù)囊蟆=ㄗh方正要是能夠勝訴的話,貢獻(xiàn)一些字體給開源組織,為弘揚(yáng)漢語言文化多做點(diǎn)貢獻(xiàn)。

          posted @ 2007-08-23 15:01 GHawk 閱讀(659) | 評(píng)論 (1)編輯 收藏

          Maven2 用于度量和品質(zhì)保證的插件


          以上是一些常用的用于品質(zhì)管理的插件。默認(rèn)情況下都不用配置,相當(dāng)方便。如果需要手動(dòng)配置的話,根據(jù)網(wǎng)上的文檔也相當(dāng)容易配置。
          apache的maven plugin頁面: http://maven.apache.org/plugins/
          codehaus mojo 頁面: http://mojo.codehaus.org

          posted @ 2007-05-28 14:32 GHawk 閱讀(1570) | 評(píng)論 (1)編輯 收藏

          Scripting in Mustang 的一點(diǎn)啟發(fā)

          2006 Sun Techdays Shanghai 的第2天下午有一個(gè)名為《Java Scripting: One VM, Many Languages》的Session。

          Rags為大家展示了Mustang的一個(gè)新特性,Scripting in Java——腳本語言支持。

          通過加入腳本引擎的支持,就能夠在Java中解釋Javascript,python,ruby等諸多腳本語言。

          對(duì)于這個(gè)特性,想到的一個(gè)可能的應(yīng)用就是在annotation中寫腳本語言,然后在代碼中用相應(yīng)的腳本語言引擎解釋執(zhí)行。
          保留到運(yùn)行時(shí)的annotation可以用實(shí)現(xiàn)aop的功能,使用非inline的腳本就可以更靈活地控制aspect的行為。

          比如:
          //inline scripting
          @ScriptBefore(script
          ="",language="javascript"?)
          public?void?foo()?{
          ???
          }

          //non-inline scripting
          @ScriptBefore(file
          ="scripts/logging.js",language="javascript")
          public?void?bar()?{

          }

          posted @ 2006-09-26 10:04 GHawk 閱讀(1336) | 評(píng)論 (3)編輯 收藏

          一個(gè)XPer提供的一些經(jīng)驗(yàn)

          前些天,和一位XPer進(jìn)行了一次愉快的談話。他向我講述了一些感覺很有效的實(shí)踐。

          關(guān)于過程和迭代
          他曾經(jīng)參與過的項(xiàng)目的迭代是以月為迭代單位的,但事實(shí)上每周都會(huì)重復(fù)一個(gè)簡(jiǎn)單的過程。
          在迭代過程中,他非常推崇Burn-Down Charts。這是一個(gè)Scrum的工具。通過Burn-Down Charts,能夠把過程中間的變化記錄下來,使過程高度可視化。等到一次迭代完成,回顧一下所有的Burn-Down Charts就能作為改進(jìn)的判斷依據(jù)。
          KPT Meeting。所謂KPT Meeting就是 Keep-Prevent-Try metting。小組定期舉行KPT會(huì)議(基本上是每周一次)。在KTP會(huì)議上,通過頭腦風(fēng)暴的方式每個(gè)人(不是某幾個(gè)人)把各自認(rèn)為前一階段里做得好的方面寫在Keep一欄里;做得不好的方面寫在Prevent一欄里;希望嘗試的寫在Try一欄里。然后大家對(duì)這些項(xiàng)目進(jìn)行評(píng)估和篩選。下一階段中,Keep的項(xiàng)目繼續(xù)保持,Prevent的項(xiàng)目應(yīng)該杜絕,Try的項(xiàng)目進(jìn)行嘗試。

          工具
          在開展這些實(shí)踐的時(shí)候,交流比較頻繁。首推的工具是Mini white boardDC
          選擇Mini white board的原因并不是因?yàn)閹в?mini"聽上去會(huì)像 Mini Cooper 或者 iPod mini 那么cool。因?yàn)橐粔KA3左右大小的白板非常適合個(gè)人或者結(jié)對(duì)使用,而且環(huán)保(省去了草稿紙)。雖然整個(gè)團(tuán)隊(duì)也有用于大規(guī)模交流的更大的白板,但那屬于“競(jìng)爭(zhēng)資源”,各自使用自己的白板更為方便。
          交流結(jié)果產(chǎn)生后,為了不花不必要的時(shí)間去做精美的文檔,一臺(tái)輕便的DC往往是最合適的選擇。當(dāng)然,如果足夠,手機(jī)上的照相功能也可以完成同樣的任務(wù)。相比偷拍街上的MM,這些電子產(chǎn)品能夠?qū)崿F(xiàn)更大的價(jià)值。

          關(guān)于結(jié)對(duì)
          每天進(jìn)行6小時(shí)的結(jié)對(duì)編程,分3次,每次2小時(shí)。每次和不同的成員組隊(duì)。在結(jié)隊(duì)的時(shí)候充分利用了上面提到的工具進(jìn)行交流。如果出現(xiàn)兩個(gè)人不能解決的問題的時(shí)候,會(huì)立即向整個(gè)團(tuán)隊(duì)提出,這樣可能導(dǎo)致一次stand-up meeting。即使問題不能馬上解決,至少也能確保每個(gè)人都知道這個(gè)問題。

          posted @ 2006-08-24 15:45 GHawk 閱讀(1455) | 評(píng)論 (0)編輯 收藏

          關(guān)于locale的設(shè)定 (轉(zhuǎn))

          轉(zhuǎn)自:http://www.syxin.com/2006/03/localelocale.html

          關(guān)于locale的設(shè)定
          ?
          locale是國(guó)際化與本土化過程中的一個(gè)非常重要的概念,個(gè)人認(rèn)為,對(duì)于中文用戶來說,通常會(huì)涉及到的國(guó)際化或者本土化,大致包含三個(gè)方面:看中文,寫中文,與window中文系統(tǒng)的兼容和通信。從實(shí)際經(jīng)驗(yàn)上看來,locale的設(shè)定與看中文關(guān)系不大,但是與寫中文,及window分區(qū)的掛載方式有很密切的關(guān)系。本人認(rèn)為就像一個(gè)純英文的Windows能夠?yàn)g覽中文,日文或者意大利文網(wǎng)頁一樣,你不需要設(shè)定locale就可以看中文。那么,為什么要設(shè)定locale呢?什么時(shí)候會(huì)用到locale呢?

          一、為什么要設(shè)定locale
          正如前面我所講的,設(shè)定locale與你能否瀏覽中文的網(wǎng)頁沒有直接的關(guān)系,即便你把locale設(shè)置成en_US.ISO-8859-1這樣一個(gè)標(biāo)準(zhǔn)的英文locale你照樣可以瀏覽中文的網(wǎng)頁,只要你的系統(tǒng)里面有相應(yīng)的字符集(這個(gè)都不一定需要)和合適的字體(如simsun),瀏覽器就可以把網(wǎng)頁翻譯成中文給你看。具體的過程是網(wǎng)絡(luò)把網(wǎng)頁傳送到你的機(jī)器上之后,瀏覽器會(huì)判斷相應(yīng)的編碼的字符集,根據(jù)網(wǎng)頁采用的字符集,去字體庫里面找合適的字體,然后由文字渲染工具把相應(yīng)的文字在屏幕上顯示出來。

          ?
          在下文本人會(huì)偶爾把字符集比喻成密碼本,個(gè)人覺得對(duì)于一些東西比較容易理解,假如你不習(xí)慣的話,把全文copy到任何文本編輯器,用字符集替換密碼本即可。
          ?
          那有時(shí)候網(wǎng)頁顯示亂碼或者都是方框是怎么回事呢?個(gè)人認(rèn)為,顯示亂碼是因?yàn)樵O(shè)定的字符集不對(duì)(或者沒有相應(yīng)的字符集),例如網(wǎng)頁是用UTF-8編碼的,你非要用GB2312去看,而系統(tǒng)根據(jù)GB2312去找字體,然后在屏幕上顯示,當(dāng)然是一堆的亂碼,也就是說你用一個(gè)錯(cuò)誤的密碼本去翻譯發(fā)給你的電報(bào),當(dāng)然內(nèi)容那叫一個(gè)亂;至于有些時(shí)候?yàn)g覽的網(wǎng)頁能顯示一部分漢字,但有很多的地方是方框,能夠顯示漢字說明瀏覽器已經(jīng)正確的判斷出了網(wǎng)頁的編碼,并在字體庫里面找到了相應(yīng)的文字,但是并不是每個(gè)字體庫都包含某個(gè)字符集全部的字體的緣故,有些時(shí)候會(huì)顯示不完全,找一個(gè)比較全的支持較多字符集的字體就可以了。
          ?

          既然我能夠?yàn)g覽中文網(wǎng)頁,那為什么我還要設(shè)定locale呢?
          ?
          其實(shí)你有沒有想過這么一個(gè)問題,為什么gentoo官方論壇上中文論壇的網(wǎng)頁是用UTF-8編碼的(雖然大家一直強(qiáng)烈建議用GB2312編碼),但是新浪網(wǎng)就是用GB2312編碼的呢?而Xorg的官方網(wǎng)頁竟然是ISO-8859-15編碼的,我沒有設(shè)定這個(gè)locale怎么一樣的能瀏覽呢?這個(gè)問題就像是你有所有的密碼本,不論某個(gè)網(wǎng)站是用什么字符集編碼的,你都可以用你手里的密碼本把他們翻譯過來,但問題是雖然你能瀏覽中文網(wǎng)頁,但是在整個(gè)操作系統(tǒng)里面流動(dòng)的還是英文字符。所以,就像你能聽懂英語,也能聽懂中文。
          最根本的問題是:你不可以寫中文。
          ?
          當(dāng)你決定要寫什么東西的時(shí)候,首先要決定的一件事情是用那種語言,對(duì)于計(jì)算機(jī)來說就是你要是用哪一種字符集,你就必須告訴你的linux系統(tǒng),你想用那一本密碼本去寫你想要寫的東西。知道為什么需要用GB2312字符集去瀏覽新浪了吧,因?yàn)樾吕说木W(wǎng)頁是用GB2312寫的。
          ?
          為了讓你的Linux能夠輸入中文,就需要把系統(tǒng)的locale設(shè)定成中文的(嚴(yán)格說來是locale中的語言類別LC_CTYPE ),例如zh_CN.GB2312、zh_CN.GB18030或者zh_CN.UTF-8。很多人都不明白這些古里古怪的表達(dá)方式。這個(gè)外星表達(dá)式規(guī)定了什么東西呢?這個(gè)問題稍后詳述,現(xiàn)在只需要知道,這是locale的表達(dá)方式就可以了。
          ?
          二、到底什么是locale?
          locale這個(gè)單詞中文翻譯成地區(qū)或者地域,其實(shí)這個(gè)單詞包含的意義要寬泛很多。Locale是根據(jù)計(jì)算機(jī)用戶所使用的語言,所在國(guó)家或者地區(qū),以及當(dāng)?shù)氐奈幕瘋鹘y(tǒng)所定義的一個(gè)軟件運(yùn)行時(shí)的語言環(huán)境。
          ?
          這個(gè)用戶環(huán)境可以按照所涉及到的文化傳統(tǒng)的各個(gè)方面分成幾個(gè)大類,通常包括用戶所使用的語言符號(hào)及其分類(LC_CTYPE),數(shù)字(LC_NUMERIC),比較和排序習(xí)慣(LC_COLLATE),時(shí)間顯示格式(LC_TIME),貨幣單位(LC_MONETARY),信息主要是提示信息,錯(cuò)誤信息, 狀態(tài)信息, 標(biāo)題, 標(biāo)簽, 按鈕和菜單等(LC_MESSAGES),姓名書寫方式(LC_NAME),地址書寫方式(LC_ADDRESS),電話號(hào)碼書寫方式(LC_TELEPHONE),度量衡表達(dá)方式(LC_MEASUREMENT),默認(rèn)紙張尺寸大小(LC_PAPER)和locale對(duì)自身包含信息的概述(LC_IDENTIFICATION)。
          ?
          所以說,locale就是某一個(gè)地域內(nèi)的人們的語言習(xí)慣和文化傳統(tǒng)和生活習(xí)慣。一個(gè)地區(qū)的locale就是根據(jù)這幾大類的習(xí)慣定義的,這些locale定義文件放在/usr/share/i18n/locales目錄下面,例如en_US, zh_CN and de_DE@euro都是locale的定義文件,這些文件都是用文本格式書寫的,你可以用寫字板打開,看看里邊的內(nèi)容,當(dāng)然出了有限的注釋以外,大部分東西可能你都看不懂,因?yàn)槭怯玫腢nicode的字符索引方式。
          ?
          對(duì)于de_DE@euro的一點(diǎn)說明,@后邊是修正項(xiàng),也就是說你可以看到兩個(gè)德國(guó)的locale:
          /usr/share/i18n/locales/de_DE@euro
          /usr/share/i18n/locales/de_DE
          打開這兩個(gè)locale定義,你就會(huì)知道它們的差別在于de_DE@euro使用的是歐洲的排序、比較和縮進(jìn)習(xí)慣,而de_DE用的是德國(guó)的標(biāo)準(zhǔn)習(xí)慣。
          ?
          上面我們說到了zh_CN.GB18030的前半部分,后半部分是什么呢?大部分Linux用戶都知道是系統(tǒng)采用的字符集。
          ?
          三、什么是字符集?
          字符集就是字符,尤其是非英語字符在系統(tǒng)內(nèi)的編碼方式,也就是通常所說的內(nèi)碼,所有的字符集都放在/usr/share/i18n/charmaps,所有的字符集也都是用Unicode編號(hào)索引的。Unicode用統(tǒng)一的編號(hào)來索引目前已知的全部的符號(hào)。而字符集則是這些符號(hào)的編碼方式,或者說是在網(wǎng)絡(luò)傳輸,計(jì)算機(jī)內(nèi)部通信的時(shí)候,對(duì)于不同字符的表達(dá)方式,Unicode是一個(gè)靜態(tài)的概念,字符集是一個(gè)動(dòng)態(tài)的概念,是每一個(gè)字符傳遞或傳輸?shù)木唧w形式。就像Unicode編號(hào)U59D0是代表姐姐的“姐”字,但是具體的這個(gè)字是用兩個(gè)字節(jié)表示,三個(gè)字節(jié),還是四個(gè)字節(jié)表示,是字符集的問題。例如:UTF-8字符集就是目前流行的對(duì)字符的編碼方式,UTF-8用一個(gè)字節(jié)表示常用的拉丁字母,用兩個(gè)字節(jié)表示常用的符號(hào),包括常用的中文字符,用三個(gè)表示不常用的字符,用四個(gè)字節(jié)表示其他的古靈精怪的字符。而GB2312字符集就是用兩個(gè)字節(jié)表示所有的字符。需要提到一點(diǎn)的是Unicode除了用編號(hào)索引全部字符以外,本身是用四個(gè)字節(jié)存儲(chǔ)全部字符,這一點(diǎn)在談到掛載windows分區(qū)的時(shí)候是非常重要的一個(gè)概念。所以說你也可以把Unicode看作是一種字符集(我不知道它和UTF-32的關(guān)系,反正UTF-32就是用四個(gè)字節(jié)表示所有的字符的),但是這樣表述符號(hào)是非常浪費(fèi)資源的,因?yàn)樵谟?jì)算機(jī)世界絕大部分時(shí)候用到的是一個(gè)字節(jié)就可以搞定的26個(gè)字母而已。所以才會(huì)有UTF-8,UTF-16等等,要不然大同世界多好,省了這許多麻煩。
          ?

          四、zh_CN.GB2312到底是在說什么?
          Locale 是軟件在運(yùn)行時(shí)的語言環(huán)境, 它包括語言(Language), 地域 (Territory) 和字符集(Codeset)。一個(gè)locale的書寫格式為: 語言[_地域[.字符集]]. 所以說呢,locale總是和一定的字符集相聯(lián)系的。下面舉幾個(gè)例子:
          ?
          1、我說中文,身處中華人民共和國(guó),使用國(guó)標(biāo)2312字符集來表達(dá)字符。
          zh_CN.GB2312=中文_中華人民共和國(guó)+國(guó)標(biāo)2312字符集。
          ?
          2、我說中文,身處中華人民共和國(guó),使用國(guó)標(biāo)18030字符集來表達(dá)字符。
          zh_CN.GB18030=中文_中華人民共和國(guó)+國(guó)標(biāo)18030字符集。
          ?
          3、我說中文,身處中華人民共和國(guó)臺(tái)灣省,使用國(guó)標(biāo)Big5字符集來表達(dá)字符。
          zh_TW.BIG5=中文_臺(tái)灣.大五碼字符集
          ?
          4、我說英文,身處大不列顛,使用ISO-8859-1字符集來表達(dá)字符。
          en_GB.ISO-8859-1=英文_大不列顛.ISO-8859-1字符集
          ?
          5、我說德語,身處德國(guó),使用UTF-8字符集,習(xí)慣了歐洲風(fēng)格。
          de_DE.UTF-8@euro=德語_德國(guó).UTF-8字符集@按照歐洲習(xí)慣加以修正
          ?
          注意不是de_DE@euro.UTF-8,所以完全的locale表達(dá)方式是
          [語言[_地域][.字符集] [@修正值]
          ?
          生成的locale放在/usr/lib/locale/目錄中,并且每個(gè)locale都對(duì)應(yīng)一個(gè)文件夾,也就是說創(chuàng)建了de_DE@euro.UTF-8 locale之后,就生成/usr/lib/locale/de_DE@euro.UTF-8/目錄,里面是具體的每個(gè)locale的內(nèi)容。
          ?
          五、怎樣去自定義locale
          在gentoo生成locale還是很容易的,首先要在USE里面加入userlocales支持,然后編輯locales.build文件,這個(gè)文件用來指示glibc生成locale文件。
          很多人不明白每一個(gè)條目是什么意思。 其實(shí)根據(jù)上面的說明現(xiàn)在應(yīng)該很明確了。
          ?
          File: /etc/locales.build
          en_US/ISO-8859-1
          en_US.UTF-8/UTF-8
          ?
          zh_CN/GB18030
          zh_CN.GBK/GBK
          zh_CN.GB2312/GB2312
          zh_CN.UTF-8/UTF-8
          ?
          上面是我的locales.build文件,依次的說明是這樣的:
          ?
          en_US/ISO-8859-1:生成名為en_US的locale,采用ISO-8859-1字符集,并且把這個(gè)locale作為英文_美國(guó)locale類的默認(rèn)值,其實(shí)它和en_US.ISO-8859-1/ISO-8859-1沒有任何區(qū)別。
          ?
          en_US.UTF-8/UTF-8:生成名為en_US.UTF-8的locale,采用UTF-8字符集。
          ?
          zh_CN/GB18030:生成名為zh_CN的locale,采用GB18030字符集,并且把這個(gè)locale作為中文_中國(guó)locale類的默認(rèn)值,其實(shí)它和zh_CN.GB18030/GB18030沒有任何區(qū)別。
          ?
          zh_CN.GBK/GBK:生成名為zh_CN.GBK的locale,采用GBK字符集。
          zh_CN.GB2312/GB2312:生成名為zh_CN.GB2312的locale,采用GB2312字符集。
          zh_CN.UTF-8/UTF-8:生成名為zh_CN.UTF-8的locale,采用UTF-8字符集。
          ?
          關(guān)于默認(rèn)locale,默認(rèn)locale可以簡(jiǎn)寫成en_US或者zh_CN的形式,只是為了表達(dá)簡(jiǎn)單而已沒有特別的意義。
          ?
          Gentoo在locale定義的時(shí)候掩蓋了一些東西,也就是locale的生成工具:localedef。
          在編譯完glibc之后你可以用這個(gè)localedef 再補(bǔ)充一些locale,就會(huì)更加理解locale了。具體的可以看 localedef 的manpage。
          ?
          $localedef -f 字符集 -i locale定義文件 生成的locale的名稱
          例如
          $localedef -f UTF-8 -i zh_CN zh_CN.UTF-8
          ?
          上面的定義方法和在locales.build中設(shè)定zh_CN.UTF-8/UTF-8的結(jié)果是一樣一樣的。
          ?

          六、locale的五臟六腑
          ?
          剛剛生成了幾個(gè)locale,但是為了讓它們生效,必須告訴Linux系統(tǒng)使用那(幾)個(gè)locale。這就需要對(duì)locale的內(nèi)部機(jī)制有一點(diǎn)點(diǎn)的了解。在前面我已經(jīng)提到過,locale把按照所涉及到的文化傳統(tǒng)的各個(gè)方面分成12個(gè)大類,這12個(gè)大類分別是:
          1、語言符號(hào)及其分類(LC_CTYPE)
          2、數(shù)字(LC_NUMERIC)
          3、比較和排序習(xí)慣(LC_COLLATE)
          4、時(shí)間顯示格式(LC_TIME)
          5、貨幣單位(LC_MONETARY)
          6、信息主要是提示信息,錯(cuò)誤信息, 狀態(tài)信息, 標(biāo)題, 標(biāo)簽, 按鈕和菜單等(LC_MESSAGES)
          7、姓名書寫方式(LC_NAME)
          8、地址書寫方式(LC_ADDRESS)
          9、電話號(hào)碼書寫方式(LC_TELEPHONE)
          10、度量衡表達(dá)方式(LC_MEASUREMENT)
          11、默認(rèn)紙張尺寸大小(LC_PAPER)
          12、對(duì)locale自身包含信息的概述(LC_IDENTIFICATION)。
          ?
          其中,與中文輸入關(guān)系最密切的就是 LC_CTYPE, LC_CTYPE 規(guī)定了系統(tǒng)內(nèi)有效的字符以及這些字符的分類,諸如什么是大寫字母,小寫字母,大小寫轉(zhuǎn)換,標(biāo)點(diǎn)符號(hào)、可打印字符和其他的字符屬性等方面。而locale定義zh_CN中最最重要的一項(xiàng)就是定義了漢字(Class “hanzi”)這一個(gè)大類,當(dāng)然也是用Unicode描述的,這就讓中文字符在Linux系統(tǒng)中成為合法的有效字符,而且不論它們是用什么字符集編碼的。
          ?
          LC_CTYPE
          % This is a copy of the "i18n" LC_CTYPE with the following modifications: - Additional classes: hanzi
          ?
          copy "i18n"
          ?
          class "hanzi"; /
          % <U3400>..<U4DBF>;/
          <U4E00>..<U9FA5>;/
          <UF92C>;<UF979>;<UF995>;<UF9E7>;<UF9F1>;<UFA0C>;<UFA0D>;<UFA0E>;/
          <UFA0F>;<UFA11>;<UFA13>;<UFA14>;<UFA18>;<UFA1F>;<UFA20>;<UFA21>;/
          <UFA23>;<UFA24>;<UFA27>;<UFA28>;<UFA29>
          END LC_CTYPE
          ?
          在en_US的locale定義中,并沒有定義漢字,所以漢字不是有效字符。所以如果要輸入中文必須使用支持中文的locale,也就是zh_XX,如zh_CN,zh_TW,zh_HK等等。
          ?
          另外非常重要的一點(diǎn)就是這些分類是彼此獨(dú)立的,也就是說LC_CTYPE,LC_COLLATE和 LC_MESSAGES等等分類彼此之間是獨(dú)立的,可以根據(jù)用戶的需要設(shè)定成不同的值。這一點(diǎn)對(duì)很多用戶是有利的,甚至是必須的。例如,我就需要一個(gè)能夠輸入中文的英文環(huán)境,所以我可以把LC_CTYPE設(shè)定成zh_CN.GB18030,而其他所有的項(xiàng)都是en_US.UTF-8。
          ?

          七、怎樣設(shè)定locale呢?
          ?
          設(shè)定locale就是設(shè)定12大類的locale分類屬性,即 12個(gè)LC_*。除了這12個(gè)變量可以設(shè)定以外,為了簡(jiǎn)便起見,還有兩個(gè)變量:LC_ALL和LANG。它們之間有一個(gè)優(yōu)先級(jí)的關(guān)系:
          LC_ALL>LC_*>LANG
          可以這么說,LC_ALL是最上級(jí)設(shè)定或者強(qiáng)制設(shè)定,而LANG是默認(rèn)設(shè)定值。
          1、如果你設(shè)定了LC_ALL=zh_CN.UTF-8,那么不管LC_*和LANG設(shè)定成什么值,它們都會(huì)被強(qiáng)制服從LC_ALL的設(shè)定,成為 zh_CN.UTF-8。
          2、假如你設(shè)定了LANG=zh_CN.UTF-8,而其他的LC_*=en_US.UTF-8,并且沒有設(shè)定LC_ALL的話,那么系統(tǒng)的locale設(shè)定以LC_*=en_US.UTF-8。
          3、假如你設(shè)定了LANG=zh_CN.UTF-8,而其他的LC_*,和LC_ALL均未設(shè)定的話,系統(tǒng)會(huì)將LC_*設(shè)定成默認(rèn)值,也就是LANG的值 zh_CN.UTF-8 。
          4、假如你設(shè)定了LANG=zh_CN.UTF-8,而其他的LC_CTYPE=en_US.UTF-8,其他的LC_*,和LC_ALL均未設(shè)定的話,那么系統(tǒng)的locale設(shè)定將是:LC_CTYPE=en_US.UTF-8,其余的 LC_COLLATE,LC_MESSAGES等等均會(huì)采用默認(rèn)值,也就是LANG的值,也就是LC_COLLATE=LC_MESSAGES=……= LC_PAPER=LANG=zh_CN.UTF-8。
          ?
          所以,locale是這樣設(shè)定的:
          1、如果你需要一個(gè)純中文的系統(tǒng)的話,設(shè)定LC_ALL= zh_CN.XXXX,或者LANG= zh_CN.XXXX都可以,當(dāng)然你可以兩個(gè)都設(shè)定,但正如上面所講,LC_ALL的值將覆蓋所有其他的locale設(shè)定,不要作無用功。
          2、如果你只想要一個(gè)可以輸入中文的環(huán)境,而保持菜單、標(biāo)題,系統(tǒng)信息等等為英文界面,那么只需要設(shè)定LC_CTYPE=zh_CN.XXXX,LANG=en_US.XXXX就可以了。這樣LC_CTYPE=zh_CN.XXXX,而LC_COLLATE=LC_MESSAGES=……= LC_PAPER=LANG=en_US.XXXX。
          3、假如你高興的話,可以把12個(gè)LC_*一一設(shè)定成你需要的值,打造一個(gè)古靈精怪的系統(tǒng):
          LC_CTYPE=zh_CN.GBK/GBK(使用中文編碼內(nèi)碼GBK字符集);
          LC_NUMERIC=en_GB.ISO-8859-1(使用大不列顛的數(shù)字系統(tǒng))
          LC_MEASUREMEN=de_DE@euro.ISO-8859-15(德國(guó)的度量衡使用ISO-8859-15字符集)
          羅馬的地址書寫方式,美國(guó)的紙張?jiān)O(shè)定……。估計(jì)沒人這么干吧。
          4、假如你什么也不做的話,也就是LC_ALL,LANG和LC_*均不指定特定值的話,系統(tǒng)將采用POSIX作為lcoale,也就是C locale。

          posted @ 2006-08-16 10:45 GHawk 閱讀(764) | 評(píng)論 (0)編輯 收藏

          PostgreSQL的主機(jī)認(rèn)證配置

          轉(zhuǎn)自 http://www.linuxsir.org/bbs/showthread.php?t=32116

          pg_hba.conf 文件
          客戶端認(rèn)證是由 $PGDATA 目錄里的文件pg_hba.conf 控制的,也就是說, /usr/local/pgsql/data/pg_hba.conf. (HBA 的意思是 host-based authentication:基于主機(jī)的認(rèn)證.) 在initdb初始化數(shù)據(jù)區(qū)的時(shí)候,它會(huì) 安裝一個(gè)缺省的文件.

          文件 pg_hba.conf 的常用格式是一套記錄, 每行一條。空白行或者井號(hào)(“#”)開頭的行被忽略。一條記錄 是由若干用空格和/或 tab 分隔的字段組成。

          每條記錄可以下面三種格式之一

          local database authentication-method [ authentication-option ]
          host database IP-address IP-mask authentication-method [ authentication-option ]
          hostssl database IP-address IP-mask authentication-method [ authentication-option ]

          各個(gè)字段的含義如下:

          local
          這條記錄適用于通過 Unix 域套接字的聯(lián)接.

          host
          這條記錄適用于通過 TCP/IP 網(wǎng)絡(luò)的聯(lián)接.請(qǐng)注意,除非服務(wù)器是 帶著 -i 選項(xiàng)或者等效的配置參數(shù)集啟動(dòng)的,否則 TCP/IP 聯(lián)接將完全被禁止掉.

          hostssl
          這條記錄適用于試圖建立在 TCP/IP 上的 SSL 之上的聯(lián)接. 要使用這個(gè)選項(xiàng),服務(wù)器必須帶著 SSL 支持編譯.而且在服務(wù)器啟動(dòng)的時(shí)候, 必須用 -l 選項(xiàng) 或等效的配置設(shè)置打開 SSL.

          database
          聲明記錄所適用的數(shù)據(jù)庫。值 all 表明該記錄應(yīng)用于所有數(shù)據(jù)庫, 值 sameuser 表示于正在聯(lián)接的用戶同名的數(shù)據(jù)庫。 否則它就是某個(gè)具體的 Postgres 數(shù)據(jù)庫名字.

          IP address, IP mask
          這兩個(gè)字段以各主機(jī)的 IP 地址為基礎(chǔ), 控制一條 host 記錄應(yīng)用于哪個(gè)主機(jī). (當(dāng)然,IP 地址可能會(huì)被欺騙(spoofed),但是這個(gè)考慮 超過了 Postgres 的考慮范圍.) 準(zhǔn)確的邏輯是,對(duì)于匹配的記錄

          (actual-IP-address xor IP-address-field) and IP-mask-field
          必需為零.

          authentication method(認(rèn)證方法)
          聲明一個(gè)用戶在與該數(shù)據(jù)庫聯(lián)接的時(shí)候必須使用的認(rèn)證方法. 可能的選擇如下,詳細(xì)情況在 Section 4.2.


          trust
          無條件地允許聯(lián)接.這個(gè)方法允許任何有登錄客戶機(jī)權(quán)限的用戶以任意 Postgres 數(shù)據(jù)庫用戶身份進(jìn)行聯(lián)接.

          reject
          聯(lián)接無條件拒絕.常用于從組中“過濾”某些主機(jī).

          password
          要求客戶端在嘗試聯(lián)接的時(shí)候提供一個(gè)口令, 這個(gè)口令與為該用戶設(shè)置的口令必須匹配.

          在 password 關(guān)鍵字后面可以聲明一個(gè)可選的文件名. 這個(gè)文件包含一個(gè)用戶列表,列表記錄的是那些適用口令認(rèn)證記錄的用戶, 以及可選的候選口令.

          口令是以明文的方式在線路上傳輸?shù)模绻玫谋Wo(hù),請(qǐng)使用 crypt 方法.

          crypt
          類似 password 方法,但是口令是用一種簡(jiǎn)單的 口令對(duì)應(yīng)協(xié)議加密后在線路上傳送的.這么做在密碼學(xué)理論上是不安全的, 但可以防止偶然的線路偵聽.在 crypt 關(guān)鍵字后面 可以有一個(gè)文件,文件里包含適用口令認(rèn)證記錄的用戶列表.

          krb4
          用 Kerberos V4 認(rèn)證用戶.只有在進(jìn)行 TCP/IP 聯(lián)接的時(shí)候才能用. (譯注:Kerberos,"克爾波洛斯",故希臘神話冥王哈得斯的多頭看門狗. Kerberos 是 MIT 開發(fā)出來的基與對(duì)稱加密算法的認(rèn)證協(xié)議和/或密鑰 交換方法.其特點(diǎn)是需要兩個(gè)不同用途的服務(wù)器,一個(gè)用于認(rèn)證身份, 一個(gè)用于通道兩端用戶的密鑰交換.同時(shí) Kerberos 對(duì)網(wǎng)絡(luò)時(shí)間同步 要求比較高,以防止回放攻擊,因此通常伴隨 NTP 服務(wù).)

          krb5
          用 Kerberos V5 認(rèn)證用戶.只有在進(jìn)行 TCP/IP 聯(lián)接的時(shí)候才能用. (譯注:Kerberos V5 是上面 V4 的改良,主要是不再依賴 DES 算法, 同時(shí)增加了一些新特性.)

          ident
          服務(wù)器將詢問客戶機(jī)上的 ident 服務(wù)器以核實(shí)正在聯(lián)接的用戶身份. 然后 Postgres 核實(shí)該操作系統(tǒng)用戶是否被允許以其請(qǐng)求的數(shù)據(jù)庫用戶身份與數(shù)據(jù)庫聯(lián)接. 只有在使用 TCP/IP 聯(lián)接的時(shí)候才能用這個(gè)選項(xiàng). 跟在 ident 關(guān)鍵字后面的 authentication option 聲明一個(gè) ident map(身份映射), 該文件聲明那些操作系統(tǒng)用戶等效于數(shù)據(jù)庫用戶.見下文獲取詳細(xì)信息.


          authentication option(認(rèn)證選項(xiàng))
          這個(gè)字段根據(jù)不同的認(rèn)證方法(authentication method)有不同的 解釋.

          認(rèn)證時(shí)使用與聯(lián)接請(qǐng)求的客戶端 IP 地址和所要求的 數(shù)據(jù)庫名字匹配的第一條記錄. 請(qǐng)注意這里沒有 “fall-through(越過)” 或者 “backup(備份)”:如果選定了一條記錄但認(rèn)證失敗, 那么將不會(huì)繼續(xù)考慮下面的記錄.如果沒有匹配的記錄,則拒絕訪問.

          在每次聯(lián)接的請(qǐng)求時(shí),文件 pg_hba.conf 都會(huì)被重新讀取.因此很容易就能在服務(wù)器運(yùn)行的時(shí)候修改訪問權(quán)限.

          在 Example 4-1 里是 pg_hba.conf 的一個(gè)例子. 閱讀下文理解不同認(rèn)證方法的細(xì)節(jié).

          Example 4-1. 一個(gè) pg_hba.conf 文件的例子

          # TYPE DATABASE IP_ADDRESS MASK AUTHTYPE MAP

          # 允許在本機(jī)上的任何用戶以任何身份聯(lián)接任何數(shù)據(jù)庫
          # 但必須是通過 IP 進(jìn)行聯(lián)接

          host all 127.0.0.1 255.255.255.255 trust

          # 同樣,但用的是 Unix-套接字聯(lián)接

          local all trust

          # 允許 IP 地址為 192.168.93.x 的任何主機(jī)與數(shù)據(jù)庫
          # "template1" 相連,用與他們?cè)谧约旱闹鳈C(jī)上相同 ident 的用戶名標(biāo)識(shí)他自己
          # (通常是他的 Unix 用戶名)

          host template1 192.168.93.0 255.255.255.0 ident sameuser

          # 允許來自主機(jī) 192.168.12.10 的用戶與 "template1" 數(shù)據(jù)庫聯(lián)接,
          # 只要該用戶提供了在 pg_shadow 里正確的口令.

          host template1 192.168.12.10 255.255.255.255 crypt

          # 如果前面沒有其它 "host" 行,那么下面兩行將拒絕所有來自
          # 192.168.54.1 的聯(lián)接請(qǐng)求 (因?yàn)榍懊娴挠涗浵绕ヅ?br /># 但是允許來自互聯(lián)網(wǎng)上其它任何地方有效的 Kerberos V5 認(rèn)證的聯(lián)接
          # 零掩碼表示不考慮主機(jī) IP 的任何位.因此它匹配任何主機(jī):

          host all 192.168.54.1 255.255.255.255 reject
          host all 0.0.0.0 0.0.0.0 krb5

          # 允許來自 192.168.x.x 的任何用戶與任意數(shù)據(jù)庫聯(lián)接,只要他們通過 ident 檢查
          # 但如果 ident 說該用戶是 "bryanh" 而他要求以 PostgreSQL 用戶 "guest1" 聯(lián)接,
          # 那么只有在 `pg_ident.conf' 里有 "omicron" 的映射,說 "bryanh" 允許以
          # "guest1" 進(jìn)行聯(lián)接時(shí)才真正可以進(jìn)行聯(lián)接.

          host all 192.168.0.0 255.255.0.0 ident omicron

          posted @ 2006-06-07 10:42 GHawk 閱讀(1224) | 評(píng)論 (0)編輯 收藏

          UP & XP之爭(zhēng),意義何在?(續(xù))

          雖然我沒能去參加BEA的活動(dòng),但是相關(guān)的資料已經(jīng)下載并且瀏覽過了,確實(shí)收獲不少。所以,對(duì)于莊兄的這些想法我很理解。

          相信不只你我,大部分的人都比較認(rèn)同敏捷化的過程,希望使過程變得敏捷。的確,這是個(gè)好東西,之前我也說過“敏捷過程是三贏的”這樣的話。

          我所關(guān)心的問題是“如何能夠用好XP?”。

          莊兄認(rèn)為“湯的味道,不需要什么過程控制”,我也會(huì)認(rèn)同。為什么?因?yàn)槟阄叶际侵袊?guó)人。大部分中國(guó)人不會(huì)認(rèn)為湯的味道需要什么過程控制。但是想想看,如果你在不同地方買到的肯德基炸雞味道各異;同一批次生產(chǎn)的同型號(hào)的汽車形狀各異;銀行里取出來的一疊百元大鈔大小不一,你不會(huì)覺得奇怪么或是有那么一點(diǎn)點(diǎn)憤怒么?

          西方人(甚至學(xué)習(xí)西方的日本人)對(duì)品質(zhì)的重視程度卻完全不同。他們不允許肯德基炸雞的味道有很大偏差(即便你覺得無所謂);“2毫米工程”不允許整車的總裝長(zhǎng)度發(fā)生2毫米以上的偏差(即便你覺得無所謂);百元大鈔……(我想誰都不會(huì)無所謂)。

          所以,一切質(zhì)量都有標(biāo)準(zhǔn),一切標(biāo)準(zhǔn)都應(yīng)該被度量!這就是工程學(xué)的目標(biāo)之一,為了實(shí)現(xiàn)更嚴(yán)格的質(zhì)量標(biāo)準(zhǔn),就需要過程控制和度量。

          莊兄所說,用測(cè)試用例保證代碼的質(zhì)量其實(shí)還是采用了“測(cè)試用例”作為度量的標(biāo)準(zhǔn)。唯一的問題是:“如何確保測(cè)試用例的質(zhì)量”。顯然,我們不能把一把不直的尺子度量出來的結(jié)果作為可靠的參考依據(jù)。怎么解決呢?“結(jié)對(duì)編程”么?嗯,這是一個(gè)不錯(cuò)的方式,那么最終該信賴誰呢?是Pair中的A還是B呢?或者,是Leader么?那么又是誰提出的要求呢?是老板么?還是客戶?政府?法規(guī)?市場(chǎng)?……問題沒有終結(jié)了。

          不要學(xué)習(xí)哲學(xué)家的方法,提出一層又一層無法解決的問題。我們是工程師,應(yīng)該試圖解決問題才對(duì)!解決問題的關(guān)鍵在于,XP同樣需要標(biāo)準(zhǔn)!為了制定標(biāo)準(zhǔn),必要的文檔是不可以少的。而且,標(biāo)準(zhǔn)本身的質(zhì)量是嚴(yán)苛的。因?yàn)椋鳛闃?biāo)準(zhǔn),他不可以含糊其辭、模棱兩可。在標(biāo)準(zhǔn)的基礎(chǔ)之上,我們才可以談什么TDD、Pair Programming之類的實(shí)踐。

          回到爭(zhēng)論的開端。我引用了林先生的話“UP是正楷;XP是草書。要先學(xué)好UP才能學(xué)好XP,先學(xué)XP會(huì)亂套。”我對(duì)這句話的理解如下:這句話并沒有批判UP或是XP,只是指出了一個(gè)學(xué)習(xí)的順序。我認(rèn)為這句話是有實(shí)踐依據(jù)的,因?yàn)閁P強(qiáng)調(diào)的是一種經(jīng)典的工程方法。軟件工程本來就源于其他行業(yè)的工程實(shí)踐經(jīng)驗(yàn)。UP利用大量的文檔對(duì)開發(fā)活動(dòng)進(jìn)行約束和記錄。正是這種重量級(jí)的過程規(guī)范了規(guī)范了從PM到Coder的所有活動(dòng),有問題可以參照文檔,看看自己應(yīng)該怎么做。文檔也可以作為日后評(píng)估這個(gè)過程的依據(jù)。隨著整個(gè)團(tuán)隊(duì)和每個(gè)個(gè)人的經(jīng)驗(yàn)不斷積累,開發(fā)活動(dòng)中的日常行為漸漸形成了一種職業(yè)習(xí)慣。然后可以通過對(duì)UP的配置,逐漸減少文檔的使用量,一些沒有必要的文檔就可以省去,更具團(tuán)隊(duì)的實(shí)際能力調(diào)整過程。UP是可配置的,不必要的文檔沒有存在的理由,這一點(diǎn)UP和XP沒有什么兩樣。當(dāng)然,隨著大家的職業(yè)習(xí)慣越來越好,經(jīng)驗(yàn)越來越豐富,個(gè)人和團(tuán)隊(duì)就可以采用更敏捷更輕便的過程,逐漸過渡到XP上去。

          反過來,如果一開始就沒有詳盡的文檔,很多活動(dòng)(比如設(shè)計(jì)、版本控制)往往會(huì)脫離控制,進(jìn)入一種無序的、混亂的狀態(tài)。沒有文檔可參考,就意味著很多問題只能問人,而不同人的回答可能各異,同一個(gè)人對(duì)同一個(gè)問題的兩次回答也可能不同!當(dāng)然,如果整個(gè)團(tuán)隊(duì)的工程素養(yǎng)和個(gè)體的職業(yè)習(xí)慣都比較好的情況下可能不會(huì)發(fā)生類似的情況。但是這種工程素養(yǎng)和職業(yè)習(xí)慣從哪里來,可能單靠的XP是不足以培養(yǎng)出來的。

          “UP是正楷;XP是草書。要先學(xué)好UP才能學(xué)好XP,先學(xué)XP會(huì)亂套。”這句話表明了UP和XP在一定程度上是存在沖突的,并且提出了一條路線去降低和避免這個(gè)沖突。

          再次需要強(qiáng)調(diào)的是莊兄所提到的“XP是一種思想”,這點(diǎn)我認(rèn)同。但是我認(rèn)為這個(gè)除了思想之外,還是一種“文化”。這種思想和文化也是出于軟件工程多年來的實(shí)踐,其中也不免有UP等其他過程。不能簡(jiǎn)單地認(rèn)為“我們只要吸取歷史的教訓(xùn),提出新的思想和文化就不會(huì)再犯同樣的錯(cuò)誤了。”很多時(shí)候歷史總是一次又一次地重演著。新的思想和文化如果不能被準(zhǔn)確地理解和運(yùn)用,它所帶來的可能仍然是它原本想解決的問題。只有我們具備了引入這種文化的基礎(chǔ),才能把它變成自己的文化,否則這仍然是掛在嘴邊行于表面的一種不求精髓只求模仿的偽文化、偽思想。這一點(diǎn)對(duì)于UP和XP的實(shí)踐者來說沒有什么兩樣。

          posted @ 2006-04-25 15:03 GHawk 閱讀(2060) | 評(píng)論 (4)編輯 收藏

          UP & XP之爭(zhēng),意義何在?

          不光是做軟件,凡是做產(chǎn)品,最后關(guān)注的總是產(chǎn)品的質(zhì)量

          舉個(gè)例子,比如你做一鍋湯:
          今天你狀態(tài)很好,做完后嘗了嘗,感覺很美味,你的家人嘗了以后也有同感,喝完后感覺心情舒暢、意猶未盡。
          隔了一個(gè)禮拜,你做同樣的湯給家里人喝。做完后你嘗了嘗,感覺依然美味,盼望著得到家人的賞識(shí),然而他們卻說味道咸了點(diǎn)。你很奇怪,為什么同樣自己嘗過了,家里人卻感覺不一樣呢?是不是最近加班多了,休息不好,味覺不準(zhǔn)了?
          一個(gè)月過后,你要去國(guó)外出差,給家里請(qǐng)了個(gè)臨時(shí)保姆。一天,他也做了這么個(gè)湯,做完后,他也嘗了嘗,感覺口味很不錯(cuò),可是端上桌,家里人說這湯太辣了。原來這保姆才從湖南老家出來不久……

          因此,只把焦點(diǎn)放在最后的產(chǎn)品上往往是不夠的。需要對(duì)“做湯的過程”加以控制。所以工程界會(huì)比較關(guān)注過程的管理,在軟件領(lǐng)域也稱作“軟件生命周期管理”。

          再來看看UP和XP。它們都屬于軟件過程,只不過各有特色。

          再拿剛才那個(gè)做湯的例子:
          大家都聽說過德國(guó)人的廚房像化學(xué)實(shí)驗(yàn)室,天平、計(jì)時(shí)器、量杯……裝備齊全,再配上精確的菜譜,嚴(yán)謹(jǐn)?shù)牡聡?guó)人能夠確保不用嘗那最后一口都做出口味基本一致的湯。
          換了中國(guó)人,大部分人都不會(huì)模仿德國(guó)人做菜的方式。解決方案很簡(jiǎn)單,讓你的太太和孩子都嘗那最后一口,再根據(jù)反饋調(diào)整幾次,同樣能做出全家人滿意的湯。

          這個(gè)例子也許不太貼切,但是可以聯(lián)想一下:德國(guó)人做湯傾向于UP;中國(guó)人做湯傾向于XP

          UP和XP最終目的都是為了保證產(chǎn)品的質(zhì)量,不同的是,兩個(gè)過程所強(qiáng)調(diào)的方法不同。我想,沒有人會(huì)說“UP的目的在于變態(tài)地追求文檔的完美”、“UP是為了要程序員學(xué)會(huì)寫各種各樣文檔”……之類的話。同時(shí),也沒人會(huì)說“XP就是不要文檔只要代碼”、“XP就是要變態(tài)地追求完美的代碼”……這樣的話。

          這些不正確的看法,只是人們對(duì)于這兩種過程的誤解。或許是來自于開發(fā)人員和項(xiàng)目經(jīng)理的那些“不堪回首的經(jīng)歷”。

          “UP害慘了整個(gè)軟件行業(yè),讓開發(fā)人員沒完沒了地寫文檔而忽略了代碼,XP才是王道”這樣的話,我不敢茍同,仍然有很多企業(yè)使用著UP這樣的重型軟件工程,就好比德國(guó)人依然喜歡把廚房弄得像個(gè)實(shí)驗(yàn)室。

          XP固然是個(gè)好東西。但是,不知道大多數(shù)人對(duì)于XP的熱衷是出于對(duì)XP文化的理解,還是國(guó)人慣有的“一窩蜂”似的行為。不曉得一個(gè)“能夠熟練閱讀代碼的Leader”是不是能夠真正運(yùn)用好XP,確保他的團(tuán)隊(duì)能夠盡可能少地出現(xiàn)"Over engineering"這種違背Agile精神的東西,或是能夠讓他的團(tuán)隊(duì)保證“每周只工作40小時(shí)”這樣的基本實(shí)踐?

          對(duì)于不同的技術(shù)和過程,應(yīng)該給予冷靜的分析和慎重的選擇。每個(gè)過程和技術(shù)都不能以“正確”或“不正確”來定性,只能以“合適”和“不合適”來定性。因?yàn)檎_或不正確是要嚴(yán)格證明的,而合適不合適是來源于工程實(shí)踐的結(jié)果。所以,COBOL依然在金融領(lǐng)域起著舉足輕重的作用,科學(xué)家們?nèi)圆煌麱ortran,匯編和C仍然健在……

          另外不得不提的是文化上的差異。為什么很多時(shí)候,我們學(xué)習(xí)國(guó)外的先進(jìn)技術(shù),購買了整套生產(chǎn)線,引進(jìn)了全套圖紙,請(qǐng)國(guó)外專家做了詳細(xì)的全程化培訓(xùn),國(guó)人生產(chǎn)出的產(chǎn)品品質(zhì)依然不如國(guó)外原產(chǎn)的?這是每個(gè)中國(guó)人都應(yīng)該思考的問題……

          ?

          posted @ 2006-04-23 18:28 GHawk 閱讀(1913) | 評(píng)論 (4)編輯 收藏

          對(duì)"UP是正楷,XP是草書"的反思

          “UP是正楷,XP是草書。先學(xué)好了UP,才能學(xué)好XP;先學(xué)XP再學(xué)UP就會(huì)亂套。?”

          老師曾這么說。最近,對(duì)這句話有了深刻的體會(huì)。

          軟件過程是一個(gè)以人為中心的活動(dòng)。人是項(xiàng)目中最難確定和控制的因素。休息的質(zhì)量、情緒的起伏都會(huì)影響整個(gè)活動(dòng)。為了盡可能地約束這種個(gè)體的不確定行為和減少開發(fā)過程中不必要的誤會(huì)。"UP"采用了大量的文檔來對(duì)整個(gè)開發(fā)過程進(jìn)行控制。這些文檔主要分為以下幾類:

          • 計(jì)劃文檔——項(xiàng)目的開發(fā)計(jì)劃、迭代計(jì)劃、測(cè)試計(jì)劃等。
          • 技術(shù)文檔——項(xiàng)目的設(shè)計(jì)文檔、某個(gè)操作的說明文檔等。
          • 記錄文檔——日常的會(huì)議紀(jì)要、每日進(jìn)度反饋、評(píng)估報(bào)告等。

          文檔成了UP活動(dòng)的主要部分。在UP中,往往大量的資源用于文檔的制作。這些文檔的目的是為了盡可能減少不必要的溝通成本和誤會(huì),也為了在發(fā)生問題的時(shí)候能夠盡快確定原因找到解決方法。

          而正是因?yàn)槿绱朔敝氐馁Y源消耗,導(dǎo)致真正的設(shè)計(jì)和代碼只占到了總開銷的很少部分。這對(duì)很多人來說不可理解,甚至覺得本末倒置。于是很多敏捷方法誕生了,最具代表性也是對(duì)UP思想最具顛覆性的就屬XP了。

          對(duì)外,XP以快速的反應(yīng)速度來響應(yīng)客戶的需求;對(duì)內(nèi),XP以高質(zhì)量的代碼和設(shè)計(jì)來確保盡可能不產(chǎn)生不必要的文檔和資源開銷。

          從表面上看,在當(dāng)今,XP確實(shí)是一種非常理想的開發(fā)過程。

          但是,從沒有過程到XP往往會(huì)非常失敗。這是為什么?問題的關(guān)鍵還在于人。

          • 無過程-->UP -->XP

          UP利用文檔來約束和規(guī)范人們的開發(fā)活動(dòng)。當(dāng)一個(gè)沒有經(jīng)驗(yàn)的團(tuán)隊(duì)經(jīng)歷UP后,就等于把性格各異、習(xí)慣差別不同的人統(tǒng)一成了“相對(duì)較一致的開發(fā)人員”。

          他們有一致的編碼習(xí)慣,有共同的用語,有嚴(yán)格的規(guī)則。隨著經(jīng)驗(yàn)的積累,這個(gè)團(tuán)隊(duì)間的默契越來越高。此時(shí),如果過程由UP向XP切換,付出的代價(jià)就會(huì)相對(duì)較低。

          • 無過程-->XP-->UP

          XP主張快速反應(yīng)。如果一個(gè)沒有經(jīng)驗(yàn)的團(tuán)隊(duì)在一開始就嘗試XP,那么后果可能是慘痛的。因?yàn)橐粋€(gè)沒有經(jīng)驗(yàn)的團(tuán)隊(duì)其成員間的相互了解頗少,對(duì)于一件事,往往十個(gè)人有十種想法。當(dāng)缺少文檔約束時(shí),在以代碼和設(shè)計(jì)為中心的活動(dòng)中,成員之間往往因?yàn)樗降膮⒉畈积R導(dǎo)致無休止的討論甚至爭(zhēng)論,代碼被不必要地頻繁改動(dòng)。這是因?yàn)椋?font color="#ff0000">在團(tuán)隊(duì)建設(shè)早期,成員之間往往連最基本的尊重和信任都不存在。 這種無意義的活動(dòng)往往會(huì)嚴(yán)重影響項(xiàng)目的正常進(jìn)行。

          所以,學(xué)習(xí)和應(yīng)用過程不僅僅是個(gè)體的事,而是整個(gè)團(tuán)隊(duì)的事。只有當(dāng)團(tuán)隊(duì)采用嚴(yán)格文檔化的過程并且經(jīng)過磨合后,才能漸漸向輕量級(jí)的過程遷移,逐漸將不必要的文檔刪減掉,采用更靈活的過程。但是,此時(shí)并不是“沒有文檔”而是“心中有文檔”。

          posted @ 2006-03-01 16:25 GHawk 閱讀(1666) | 評(píng)論 (4)編輯 收藏

          加載Classpath中的文件(轉(zhuǎn))

             URL url = this.getClass().getResource("EJBConfig.xml");
                  
          try {
                      File xmlFile 
          = new File(URLDecoder.decode(url.getFile(),"UTF-8"));
                      
          if(xmlFile.exists())
                          System.out.println(
          "OK");
                  } 
          catch (UnsupportedEncodingException e) {
                      e.printStackTrace();  
          //To change body of catch statement use File | Settings | File Templates.
                  }

          posted @ 2006-01-19 22:07 GHawk 閱讀(775) | 評(píng)論 (0)編輯 收藏

          敏捷軟件開發(fā) 讀書筆記 (4)——OO五大原則(3.LSP——里氏替換原則)

          OCP作為OO的高層原則,主張使用“抽象(Abstraction)”和“多態(tài)(Polymorphism)”將設(shè)計(jì)中的靜態(tài)結(jié)構(gòu)改為動(dòng)態(tài)結(jié)構(gòu),維持設(shè)計(jì)的封閉性。

          “抽象”是語言提供的功能。“多態(tài)”由繼承語義實(shí)現(xiàn)。

          如此,問題產(chǎn)生了:“我們?nèi)绾稳ザ攘坷^承關(guān)系的質(zhì)量?”

          Liskov于1987年提出了一個(gè)關(guān)于繼承的原則“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“繼承必須確保超類所擁有的性質(zhì)在子類中仍然成立。”也就是說,當(dāng)一個(gè)子類的實(shí)例應(yīng)該能夠替換任何其超類的實(shí)例時(shí),它們之間才具有is-A關(guān)系。

          該原則稱為L(zhǎng)iskov Substitution Principle——里氏替換原則。林先生在上課時(shí)風(fēng)趣地稱之為“老鼠的兒子會(huì)打洞”。^_^

          我們來研究一下LSP的實(shí)質(zhì)。學(xué)習(xí)OO的時(shí)候,我們知道,一個(gè)對(duì)象是一組狀態(tài)和一系列行為的組合體。狀態(tài)是對(duì)象的內(nèi)在特性,行為是對(duì)象的外在特性。LSP所表述的就是在同一個(gè)繼承體系中的對(duì)象應(yīng)該有共同的行為特征。

          這一點(diǎn)上,表明了OO的繼承與日常生活中的繼承的本質(zhì)區(qū)別。舉一個(gè)例子:生物學(xué)的分類體系中把企鵝歸屬為鳥類。我們模仿這個(gè)體系,設(shè)計(jì)出這樣的類和關(guān)系。

           lsp-fig1.jpg

          類“鳥”中有個(gè)方法fly,企鵝自然也繼承了這個(gè)方法,可是企鵝不能飛阿,于是,我們?cè)谄簌Z的類中覆蓋了fly方法,告訴方法的調(diào)用者:企鵝是不會(huì)飛的。這完全符合常理。但是,這違反了LSP,企鵝是鳥的子類,可是企鵝卻不能飛!需要注意的是,此處的“鳥”已經(jīng)不再是生物學(xué)中的鳥了,它是軟件中的一個(gè)類、一個(gè)抽象。

          有人會(huì)說,企鵝不能飛很正常啊,而且這樣編寫代碼也能正常編譯,只要在使用這個(gè)類的客戶代碼中加一句判斷就行了。但是,這就是問題所在!首先,客戶代碼和“企鵝”的代碼很有可能不是同時(shí)設(shè)計(jì)的,在當(dāng)今軟件外包一層又一層的開發(fā)模式下,你甚至根本不知道兩個(gè)模塊的原產(chǎn)地是哪里,也就談不上去修改客戶代碼了。客戶程序很可能是遺留系統(tǒng)的一部分,很可能已經(jīng)不再維護(hù),如果因?yàn)樵O(shè)計(jì)出這么一個(gè)“企鵝”而導(dǎo)致必須修改客戶代碼,誰應(yīng)該承擔(dān)這部分責(zé)任呢?(大概是上帝吧,誰叫他讓“企鵝”不能飛的。^_^)“修改客戶代碼”直接違反了OCP,這就是OCP的重要性。違反LSP將使既有的設(shè)計(jì)不能封閉!

          修正后的設(shè)計(jì)如下:

           lsp-fig2.jpg

          但是,這就是LSP的全部了么?書中給了一個(gè)經(jīng)典的例子,這又是一個(gè)不符合常理的例子:正方形不是一個(gè)長(zhǎng)方形。這個(gè)悖論的詳細(xì)內(nèi)容能在網(wǎng)上找到,我就不多廢話了。

          LSP并沒有提供解決這個(gè)問題的方案,而只是提出了這么一個(gè)問題。

          于是,工程師們開始關(guān)注如何確保對(duì)象的行為。1988年,B. Meyer提出了Design by Contract(契約式設(shè)計(jì))理論。DbC從形式化方法中借鑒了一套確保對(duì)象行為和自身狀態(tài)的方法,其基本概念很簡(jiǎn)單:

          1. 每個(gè)方法調(diào)用之前,該方法應(yīng)該校驗(yàn)傳入?yún)?shù)的正確性,只有正確才能執(zhí)行該方法,否則認(rèn)為調(diào)用方違反契約,不予執(zhí)行。這稱為前置條件(Pre-condition)。
          2. 一旦通過前置條件的校驗(yàn),方法必須執(zhí)行,并且必須確保執(zhí)行結(jié)果符合契約,這稱之為后置條件(Post-condition)。
          3. 對(duì)象本身有一套對(duì)自身狀態(tài)進(jìn)行校驗(yàn)的檢查條件,以確保該對(duì)象的本質(zhì)不發(fā)生改變,這稱之為不變式(Invariant)。

          以上是單個(gè)對(duì)象的約束條件。為了滿足LSP,當(dāng)存在繼承關(guān)系時(shí),子類中方法的前置條件必須與超類中被覆蓋的方法的前置條件相同或者更寬松;而子類中方法的后置條件必須與超類中被覆蓋的方法的后置條件相同或者更為嚴(yán)格。

          一些OO語言中的特性能夠說明這一問題:

          • 繼承并且覆蓋超類方法的時(shí)候,子類中的方法的可見性必須等于或者大于超類中的方法的可見性,子類中的方法所拋出的受檢異常只能是超類中對(duì)應(yīng)方法所拋出的受檢異常的子類。
            public class SuperClass{
                
            public void methodA() throws IOException{}
            }


            public class SubClassA extends SuperClass{
                
            //this overriding is illegal.
                private void methodA() throws Exception{}
            }


            public class SubClassB extends SuperClass{
                
            //this overriding is OK.
                public void methodA() throws FileNotFoundException{}
            }

          • 從Java5開始,子類中的方法的返回值也可以是對(duì)應(yīng)的超類方法的返回值的子類。這叫做“協(xié)變”(Covariant)
            public class SuperClass {
                
            public Number caculate(){
                    
            return null;
                }

            }


            public class SubClass extends SuperClass{
                
            //only compiles in Java 5 or later.
                public Integer caculate(){
                    
            return null;
                }

            }

          可以看出,以上這些特性都非常好地遵循了LSP。但是DbC呢?很遺憾,主流的面向?qū)ο笳Z言(不論是動(dòng)態(tài)語言還是靜態(tài)語言)還沒有加入對(duì)DbC的支持。但是隨著AOP概念的產(chǎn)生,相信不久DbC也將成為OO語言的一個(gè)重要特性之一。

          一些題外話:

          前一陣子《敲響OO時(shí)代的喪鐘》和《喪鐘為誰而鳴》兩篇文章引來了無數(shù)議論。其中提到了不少OO語言的不足。事實(shí)上,遵從LSP和OCP,不管是靜態(tài)類型還是動(dòng)態(tài)類型系統(tǒng),只要是OO的設(shè)計(jì),就應(yīng)該對(duì)對(duì)象的行為有嚴(yán)格的約束。這個(gè)約束并不僅僅體現(xiàn)在方法簽名上,而是這個(gè)具體行為的本身。這才是LSP和DbC的真諦。從這一點(diǎn)來說并不能說明“萬事萬物皆對(duì)象”的動(dòng)態(tài)語言和“C++,Java”這種“按接口編程”語言的優(yōu)劣,兩類語言都有待于改進(jìn)。莊兄對(duì)DJ的設(shè)想倒是開始引入DbC的概念了。這一點(diǎn)還是非常值得期待的。^_^
          另外,接口的語義正被OCP、LSP、DbC這樣的概念不斷地強(qiáng)化,接口表達(dá)了對(duì)象行為之間的“契約”關(guān)系。而不是簡(jiǎn)單地作為一種實(shí)現(xiàn)多繼承的語法糖。

          posted @ 2006-01-18 18:12 GHawk 閱讀(3986) | 評(píng)論 (2)編輯 收藏

          敏捷軟件開發(fā) 讀書筆記 (3)——OO五大原則(2.OCP——開閉原則)

          開閉原則很簡(jiǎn)單,一句話:“Closed for Modification; Open for Extension”——“對(duì)變更關(guān)閉;對(duì)擴(kuò)展開放”。開閉原則其實(shí)沒什么好講的,我將其歸結(jié)為一個(gè)高層次的設(shè)計(jì)總則。就這一點(diǎn)來講,OCP的地位應(yīng)該比SRP優(yōu)先。

          OCP的動(dòng)機(jī)很簡(jiǎn)單:軟件是變化的。不論是優(yōu)質(zhì)的設(shè)計(jì)還是低劣的設(shè)計(jì)都無法回避這一問題。OCP說明了軟件設(shè)計(jì)應(yīng)該盡可能地使架構(gòu)穩(wěn)定而又容易滿足不同的需求。

          為什么要OCP?答案也很簡(jiǎn)單——重用。

          “重用”,并不是什么軟件工程的專業(yè)詞匯,它是工程界所共用的詞匯。早在軟件出現(xiàn)前,工程師們就在實(shí)踐“重用”了。比如機(jī)械產(chǎn)品,通過零部件的組裝得到最終的能夠使用的工具。由于機(jī)械部件的設(shè)計(jì)和制造過程是極其復(fù)雜的,所以互換性是一個(gè)重要的特性。一輛車可以用不同的發(fā)動(dòng)機(jī)、不同的變速箱、不同的輪胎……很多東西我們直接買來裝上就可以了。這也是一個(gè)OCP的例子。(可能是由于我是搞機(jī)械出身的吧,所以就舉些機(jī)械方面的例子^_^)。

          如何在OO中引入OCP原則?把對(duì)實(shí)體的依賴改為對(duì)抽象的依賴就行了。下面的例子說明了這個(gè)過程:

          05賽季的時(shí)候,一輛F1賽車有一臺(tái)V10引擎。但是到了06賽季,國(guó)際汽聯(lián)修改了規(guī)則,一輛F1賽車只能安裝一臺(tái)V8引擎。車隊(duì)很快投入了新賽車的研發(fā),不幸的是,從工程師那里得到消息,舊車身的設(shè)計(jì)不能夠裝進(jìn)新研發(fā)的引擎。我們不得不為新的引擎重新打造車身,于是一輛新的賽車誕生了。但是,麻煩的事接踵而來,國(guó)際汽聯(lián)頻頻修改規(guī)則,搞得設(shè)計(jì)師在“賽車”上改了又改,最終變得不成樣子,只能把它廢棄。

          OCP-fig1.JPG

          為了能夠重用這輛昂貴的賽車,工程師們提出了解決方案:首先,在車身的設(shè)計(jì)上預(yù)留出安裝引擎的位置和管線。然后,根據(jù)這些設(shè)計(jì)好的規(guī)范設(shè)計(jì)引擎(或是引擎的適配器)。于是,新的賽車設(shè)計(jì)方案就這樣誕生了。

           OCP-fig2.JPG

          顯然,通過重構(gòu),這里應(yīng)用的是一個(gè)典型的Bridge模式。這個(gè)實(shí)現(xiàn)的關(guān)鍵之處在于我們預(yù)先給引擎留出了位置!我們不必因?yàn)閷?duì)引擎的規(guī)則的頻頻變更而制造相當(dāng)多的車身,而是盡可能地沿用和改良現(xiàn)有的車身。
          說到這里,想說一說OO設(shè)計(jì)的一個(gè)誤區(qū)。
          學(xué)習(xí)OO語言的時(shí)候,為了能夠說明“繼承”(或者說“is-a”)這個(gè)概念,教科書上經(jīng)常用實(shí)際生活中的例子來解釋。比如汽車是車,電車是車,F(xiàn)1賽車是汽車,所以車是汽車、電車、F1賽車的上層抽象。這個(gè)例子并沒有錯(cuò)。問題是,這樣的例子過于“形象”了!如果OO設(shè)計(jì)直接就可以將現(xiàn)實(shí)生活中的概念引用過來,那也就不需要什么軟件工程師了!OO設(shè)計(jì)的關(guān)鍵概念是抽象。如果沒有抽象,那所有的軟件工程師的努力都是徒勞的。因?yàn)槿绻麤]有抽象,我們只能去構(gòu)造世界中每一個(gè)對(duì)象。上面這個(gè)例子中,我們應(yīng)該看到“引擎”這個(gè)抽象的存在,因?yàn)檐囮?duì)的工程師們?yōu)樗A(yù)留了位置,為它制定了設(shè)計(jì)規(guī)范。
          上面這個(gè)設(shè)計(jì)也實(shí)現(xiàn)了后面要說的DIP(依賴倒置原則)。但是請(qǐng)記住,OCP是OO設(shè)計(jì)原則中高層次的原則,其余的原則對(duì)OCP提供了不同程度的支持。為了實(shí)現(xiàn)OCP,我們會(huì)自覺或者不自覺地用到其它原則或是諸如Bridge、Decorator等設(shè)計(jì)模式。然而,對(duì)于一個(gè)應(yīng)用系統(tǒng)而言,實(shí)現(xiàn)OCP并不是設(shè)計(jì)目的,我們所希望的只是一個(gè)穩(wěn)定的架構(gòu)。所以對(duì)OCP的追求也應(yīng)該適可而止,不要陷入過渡設(shè)計(jì)。正如Martin本人所說:“No significant program can be 100% closed.”“Closure not complete but strategic”

          (下一篇就要講LSP了,我覺得這是意義最為重要的OO設(shè)計(jì)原則,它直指當(dāng)今主流OO語言的軟肋,點(diǎn)出了OO設(shè)計(jì)的精髓。)

          posted @ 2006-01-18 00:26 GHawk 閱讀(7589) | 評(píng)論 (7)編輯 收藏

          開源 Java 測(cè)試框架(轉(zhuǎn))

          from  http://blog.csdn.net/wangyihust/archive/2006/01/02/568616.aspx

           JUnit   

          JUnit是由 Erich Gamma 和 Kent Beck 編寫的一個(gè)回歸測(cè)試框架(regression testing framework)。Junit測(cè)試是程序員測(cè)試,即所謂白盒測(cè)試,因?yàn)槌绦騿T知道被測(cè)試的軟件如何(How)完成功能和完成什么樣(What)的功能。Junit是一套框架,繼承TestCase類,就可以用Junit進(jìn)行自動(dòng)測(cè)試了。

          http://www.junit.org/

           Cactus   

          Cactus是一個(gè)基于JUnit框架的簡(jiǎn)單測(cè)試框架,用來單元測(cè)試服務(wù)端Java代碼。Cactus框架的主要目標(biāo)是能夠單元測(cè)試服務(wù)端的使用Servlet對(duì)象的Java方法如HttpServletRequest,HttpServletResponse,HttpSession等。

          http://jakarta.apache.org/cactus/

           Abbot   

          Abbot是一個(gè)用來測(cè)試Java GUIs的框架。用簡(jiǎn)單的基于XML的腳本或者Java代碼,你就可以開始一個(gè)GUI。

          http://abbot.sourceforge.net/

           JUnitPerf   

          Junitperf實(shí)際是junit的一個(gè)decorator,通過編寫用于junitperf的單元測(cè)試,我們也可使測(cè)試過程自動(dòng)化。

          http://www.clarkware.com/software/JUnitPerf.html

           DbUnit   

          DbUnit是為數(shù)據(jù)庫驅(qū)動(dòng)的項(xiàng)目提供的一個(gè)對(duì)JUnit 的擴(kuò)展,除了提供一些常用功能,它可以將你的數(shù)據(jù)庫置于一個(gè)測(cè)試輪回之間的狀態(tài)。

          http://dbunit.sourceforge.net/

           Mockrunner   

          Mockrunner用在J2EE環(huán)境中進(jìn)行應(yīng)用程序的單元測(cè)試。它不僅支持Struts actions, servlets,過濾器和標(biāo)簽類還包括一個(gè)JDBC和一個(gè)JMS測(cè)試框架,可以用于測(cè)試基于EJB的應(yīng)用程序。

          http://mockrunner.sourceforge.net/index.html

           DBMonster   

          DBMonster是一個(gè)用生成隨機(jī)數(shù)據(jù)來測(cè)試SQL數(shù)據(jù)庫的壓力測(cè)試工具。

          http://dbmonster.kernelpanic.pl/

           MockEJB   

          MockEJB是一個(gè)不需要EJB容器就能運(yùn)行EJB并進(jìn)行測(cè)試的輕量級(jí)框架。

          http://mockejb.sourceforge.net/

           StrutsTestCase   

          StrutsTestCase 是Junit TestCase類的擴(kuò)展,提供基于Struts框架的代碼測(cè)試。StrutsTestCase同時(shí)提供Mock 對(duì)象方法和Cactus方法用來實(shí)際運(yùn)行Struts ActionServlet,你可以通過運(yùn)行servlet引擎來測(cè)試。因?yàn)镾trutsTestCase使用ActionServlet控制器來測(cè)試你的代碼,因此你不僅可以測(cè)試Action對(duì)象的實(shí)現(xiàn),而且可以測(cè)試mappings,from beans以及forwards聲明。StrutsTestCase不啟動(dòng)servlet容器來測(cè)試struts應(yīng)用程序(容器外測(cè)試)也屬于Mock對(duì)象測(cè)試,但是與EasyMock不同的是,EasyMock是提供了創(chuàng)建Mock對(duì)象的API,而StrutsTest則是專門負(fù)責(zé)測(cè)試Struts應(yīng)用程序的Mock對(duì)象測(cè)試框架。

          http://strutstestcase.sourceforge.net/

           JFCUnit   

          JFCUnit使得你能夠?yàn)镴ava偏移應(yīng)用程序編寫測(cè)試?yán)印K鼮閺挠么a打開的窗口上獲得句柄提供了支持;為在一個(gè)部件層次定位部件提供支持;為在部件中發(fā)起事件(例如按一個(gè)按鈕)以及以線程安全方式處理部件測(cè)試提供支持。

          http://jfcunit.sourceforge.net/

           JTestCase   

          JTestCase 使用XML文件來組織多測(cè)試案例數(shù)據(jù),聲明條件(操作和期望的結(jié)果),提供了一套易于使用的方法來檢索XML中的測(cè)試案例,按照數(shù)據(jù)文件的定義來聲明結(jié)果。

          http://jtestcase.sourceforge.net/

           SQLUnit   

          SQLUnit是一個(gè)單元測(cè)試框架,用于對(duì)數(shù)據(jù)庫存儲(chǔ)過程進(jìn)行回歸測(cè)試。用 Java/JUnit/XML開發(fā)。

          http://sqlunit.sourceforge.net

           JTR   

          JTR (Java Test Runner)是一個(gè)開源的基于反轉(zhuǎn)控制(IOC)的J2EE測(cè)試框架。它允許你構(gòu)建復(fù)雜的J2EE測(cè)試套件(Test Suites)并連到應(yīng)用服務(wù)器執(zhí)行測(cè)試,可以包括多個(gè)測(cè)試實(shí)例。JTR的licensed是GPL協(xié)議。

          http://jtrunner.sourceforge.net/

           Marathon   

          Marathon是一個(gè)針對(duì)使用Java/Swing開發(fā)GUI應(yīng)用程序的測(cè)試框架,它由recorder, runner 和 editor組成,測(cè)試腳本是python代碼。Marathon的焦點(diǎn)是放在最終用戶的測(cè)試上。

          http://marathonman.sourceforge.net

           TestNG   

          TestNG是根據(jù)JUnit 和 NUnit思想而構(gòu)建的一個(gè)測(cè)試框架,但是TestNG增加了許多新的功能使得它變得更加強(qiáng)大與容易使用比如:
          *支持JSR 175注釋(JDK 1.4利用JavaDoc注釋同樣也支持)
          *靈活的Test配置
          *支持默認(rèn)的runtime和logging JDK功能
          *強(qiáng)大的執(zhí)行模型(不再TestSuite)
          *支持獨(dú)立的測(cè)試方法。

          http://testng.org/

           Surrogate Test framework   

          Surrogate Test framework是一個(gè)值得稱贊單元測(cè)試框架,特別適合于大型,復(fù)雜Java系統(tǒng)的單元測(cè)試。這個(gè)框架能與JUnit,MockEJB和各種支持模擬對(duì)象(mock object )的測(cè)試工具無縫給合。這個(gè)框架基于AspectJ技術(shù)。

          http://surrogate.sourceforge.net

           MockCreator   

          MockCreator可以為給定的interface或class生成模擬對(duì)象(Mock object)的源碼。

          http://mockcreator.sourceforge.net/

           jMock   

          jMock利用mock objects思想來對(duì)Java code進(jìn)行測(cè)試。jMock具有以下特點(diǎn):容易擴(kuò)展,讓你快速簡(jiǎn)單地定義mock objects,因此不必打破程序間的關(guān)聯(lián),讓你定義靈活的超越對(duì)象之間交互作用而帶來測(cè)試局限,減少你測(cè)試地脆弱性。

          http://www.jmock.org/

           EasyMock   

          EasyMock為Mock Objects提供接口并在JUnit測(cè)試中利用Java的proxy設(shè)計(jì)模式生成它們的實(shí)例。EasyMock最適合于測(cè)試驅(qū)動(dòng)開發(fā)。

          http://www.easymock.org/

           The Grinder   

          The Grinder是一個(gè)負(fù)載測(cè)試框架。在BSD開源協(xié)議下免費(fèi)使用。

          http://grinder.sourceforge.net/

           XMLUnit   

          XMLUnit不僅有Java版本的還有.Net版本的。Java開發(fā)的XMLUnit提供了兩個(gè)JUnit 擴(kuò)展類XMLAssert和XMLTestCase,和一組支持的類。這些類可以用來比較兩張XML之間的不同之處,展示XML利用XSLT來,校驗(yàn)XML,求得XPath表達(dá)式在XML中的值,遍歷XML中的某一節(jié)點(diǎn)利DOM展開。

          http://xmlunit.sourceforge.net/

           Jameleon   

          Jameleon一個(gè)自動(dòng)化測(cè)試工具。它被用來測(cè)試各種各樣的應(yīng)用程序,所以它被設(shè)計(jì)成插件模式。為了使整個(gè)測(cè)試過程變得簡(jiǎn)單Jameleon提供了一個(gè)GUI,因此Jameleon實(shí)現(xiàn)了一個(gè)Swing 插件。

          http://jameleon.sourceforge.net/index.html

           J2MEUnit   

          J2MEUnit是應(yīng)用在J2ME應(yīng)用程序的一個(gè)單元測(cè)試框架。它基于JUnit。

          http://j2meunit.sourceforge.net/

           Jetif   

          Jetif是一個(gè)用純Java實(shí)現(xiàn)的回歸測(cè)試框架。它為Java程序單元測(cè)試以及功能測(cè)試提供了一個(gè)簡(jiǎn)單而且可 伸縮的架構(gòu),可以用于個(gè)人開發(fā)或企業(yè)級(jí)開發(fā)的測(cè)試。它容易使用,功能強(qiáng)大,而且擁有一些企業(yè)級(jí)測(cè)試的重要功能。Jetif來源于JUnit, JTestCase以及TestNG的啟發(fā),有幾個(gè)基本的概念直接來自于JUnit, 比如說斷言機(jī)制,Test Listener的概念,因此從JUnit轉(zhuǎn)到Jetif是非常容易的。

          http://jetif.sourceforge.net/

           GroboUtils   

          GroboUtils使得擴(kuò)展Java測(cè)試變得可能。它包括用在Java不同方面測(cè)試的多個(gè)子項(xiàng)目。在GroboUtils中最常被到的工具是:多線程測(cè)試(multi-threaded tests),整體單元測(cè)試(hierarchial unit tests),代碼覆蓋工具(code coverage tool)。

          http://groboutils.sourceforge.net/

           Testare   

          TESTARE是用來簡(jiǎn)化分布式應(yīng)用程序(比如:在SERVLETS,JMS listeners, CORBA ORBs或RMI環(huán)境下)測(cè)試開發(fā)過程的一個(gè)測(cè)試框架。

          https://testare.dev.java.net/

          posted @ 2006-01-10 10:41 GHawk 閱讀(1256) | 評(píng)論 (0)編輯 收藏

          敏捷軟件開發(fā) 讀書筆記 (2)——OO五大原則(1.SRP 單一職責(zé)原則)

                一點(diǎn)說明:OO的五大原則是指SRP、OCP、LSP、DIP、ISP。這五個(gè)原則是書中所提到的。除此之外,書中還提到一些高層次的原則用于組織高層的設(shè)計(jì)元素,這些放到下次再寫。當(dāng)然,OO設(shè)計(jì)的原則可能不止這五個(gè),希望大家多提寶貴意見,多多交流。

                在學(xué)習(xí)和使用OO設(shè)計(jì)的時(shí)候,我們應(yīng)該明白:OO的出現(xiàn)使得軟件工程師們能夠用更接近真實(shí)世界的方法描述軟件系統(tǒng)。然而,軟件畢竟是建立在抽象層次上的東西,再怎么接近真實(shí),也不能替代真實(shí)或被真實(shí)替代。

                OO設(shè)計(jì)的五大原則之間并不是相互孤立的。彼此間存在著一定關(guān)聯(lián),一個(gè)可以是另一個(gè)原則的加強(qiáng)或是基礎(chǔ)。違反其中的某一個(gè),可能同時(shí)違反了其余的原則。因此應(yīng)該把這些原則融會(huì)貫通,牢記在心!

          1. SRP(Single Responsibility Principle 單一職責(zé)原則)
                單一職責(zé)很容易理解,也很容易實(shí)現(xiàn)。所謂單一職責(zé),就是一個(gè)設(shè)計(jì)元素只做一件事。什么是“只做一件事”?簡(jiǎn)單說就是少管閑事。現(xiàn)實(shí)中就是如此,如果要你專心做一件事情,任何人都有信心可以做得很出色。但如果,你整天被亂七八糟的事所累,還有心思和精力把每件事都作好么?
          fig-1.JPG
               “單一職責(zé)”就是要在設(shè)計(jì)中為每種職責(zé)設(shè)計(jì)一個(gè)類,彼此保持正交,互不干涉。這個(gè)雕塑(二重奏)就是正交的一個(gè)例子,鋼琴家和小提琴家各自演奏自己的樂譜,而結(jié)果就是一個(gè)和諧的交響樂。當(dāng)然,真實(shí)世界中,演奏小提琴和彈鋼琴的必須是兩個(gè)人,但是在軟件中,我們往往會(huì)把兩者甚至更多攪和到一起,很多時(shí)候只是為了方便或是最初設(shè)計(jì)的時(shí)候沒有想到。 

                這樣的例子在設(shè)計(jì)中很常見,書中就給了一個(gè)很好的例子:調(diào)制解調(diào)器。這是一個(gè)調(diào)制解調(diào)器最基本的功能。但是這個(gè)類事實(shí)上完成了兩個(gè)職責(zé):連接的建立和中斷、數(shù)據(jù)的發(fā)送和接收。顯然,這違反了SRP。這樣做會(huì)有潛在的問題:當(dāng)僅需要改變數(shù)據(jù)連接方式時(shí),必須修改Modem類,而修改Modem類的結(jié)果就是使得任何依賴Modem類的元素都需要重新編譯,不管它是不是用到了數(shù)據(jù)連接功能。解決的辦法,書中也已經(jīng)給出:重構(gòu)Modem類,從中抽出兩個(gè)接口,一個(gè)專門負(fù)責(zé)連接、另一個(gè)專門負(fù)責(zé)數(shù)據(jù)發(fā)送。依賴Modem類的元素也要做相應(yīng)的細(xì)化,根據(jù)職責(zé)的不同分別依賴不同的接口。最后由ModemImplementation類實(shí)現(xiàn)這兩個(gè)接口。
          fig-2.JPG

                從這個(gè)例子中,我們不難發(fā)現(xiàn),違反SRP通常是由于過于“真實(shí)”地設(shè)計(jì)了一個(gè)類所造成的。因此,解決辦法是往更高一層進(jìn)行抽象化提取,將對(duì)某個(gè)具體類的依賴改變?yōu)閷?duì)一組接口或抽象類的依賴。當(dāng)然,這個(gè)抽象化的提取應(yīng)該根據(jù)需要設(shè)計(jì),而不是盲目提取。比如剛才這個(gè)Modem的例子中,如果有必要,還可以把DataChannel抽象為DataSender和DataReceiver兩個(gè)接口。
           

          posted @ 2006-01-09 21:17 GHawk 閱讀(5567) | 評(píng)論 (5)編輯 收藏

          敏捷軟件開發(fā) 讀書筆記 (1)——設(shè)計(jì)的目標(biāo)

          軟件設(shè)計(jì)是一種抽象活動(dòng),設(shè)計(jì)所要實(shí)現(xiàn)的是產(chǎn)出代碼。就這一點(diǎn)來說,任何人都會(huì)設(shè)計(jì)。但是,正如我們?nèi)粘I钪兴勀慷没蛴H身經(jīng)歷,設(shè)計(jì)有優(yōu)劣之分。

          從項(xiàng)目管理的角度去理解,設(shè)計(jì)是為了滿足涉眾(Stakeholders)的需求。顯然,一個(gè)設(shè)計(jì)應(yīng)該滿足客戶對(duì)系統(tǒng)的功能及非功能需求。但單是滿足了這一點(diǎn),并不能稱為一個(gè)好的設(shè)計(jì)。因?yàn)殚_發(fā)者同樣屬于涉眾!而開發(fā)者的需求又是怎樣的呢?至少,應(yīng)該有以下幾條吧:

          • 老板希望軟件交付后,不應(yīng)該有很高的維護(hù)成本。如果開發(fā)人員為了維護(hù)而經(jīng)常出差或者加班且久久不能投入新項(xiàng)目,顯然,換了誰是老板都不愿意這種事情發(fā)生。
          • 開發(fā)人員呢?誰愿意放棄和家人朋友而拼死拼活在單位加班,總是有這么多麻煩事纏著你,煩不煩哪!
          • ……等等

          所以,設(shè)計(jì)應(yīng)該盡可能多地照顧到維護(hù)和變更。

          為了兼顧各戶滿意和維護(hù)成本,設(shè)計(jì)應(yīng)該不斷挑戰(zhàn)其終極目標(biāo)——松耦合。不管是XP或UP,這個(gè)目標(biāo)都不會(huì)改變。OO設(shè)計(jì)中的五大原則,其根本目的就是降低組件間的耦合度,避免牽一發(fā)則動(dòng)全身的現(xiàn)象發(fā)生。降低耦合度不僅能夠提高軟件內(nèi)在的質(zhì)量,還能大大減少不必要的編譯時(shí)間、減少向版本控制系統(tǒng)提交源碼的網(wǎng)絡(luò)開銷……

          如何鑒別設(shè)計(jì)的這一指標(biāo)?軟件工程中有專用的度量:CBO(Coupling Between Objects),那是由公式計(jì)算出來的,也有很多工具支持,值得一試。(聽過幾次李維先生的講座,他經(jīng)常拿Together的度量功能炫耀^_^)

          但是,作為一個(gè)開發(fā)人員,對(duì)手中的代碼應(yīng)該有適當(dāng)?shù)拿舾行浴.吘梗@些代碼是你親手創(chuàng)造的,誰不希望自己的作品得到眾人的贊許?或許能換得一次加薪升職的機(jī)會(huì)^_^ 退一步,這可關(guān)系到寶貴的休息時(shí)間啊。所以,開發(fā)者應(yīng)該對(duì)自己的產(chǎn)品有這樣一種意識(shí):及時(shí)修正設(shè)計(jì)中不合理的地方。

          敏捷過程告訴我們:在代碼“有味道”的時(shí)候進(jìn)行重構(gòu)。“有味道”是代碼正在變質(zhì)的標(biāo)志,很遺憾,能夠使代碼保持原味的防腐劑還沒發(fā)明。為了保證代碼質(zhì)量,及時(shí)重構(gòu)是必要的。這就像在燒烤的時(shí)候?yàn)榱朔乐箍窘梗愕米跔t子前經(jīng)常翻動(dòng)肉塊一樣。

          如何聞出代碼的味道?認(rèn)真學(xué)習(xí)一下OO吧,別以為OO很簡(jiǎn)單,就是繼承+封裝+多態(tài),誰都會(huì)。即使是書中記述的五大原則,想要運(yùn)用自如,也得多感覺感覺才行。很多時(shí)候,我們不知不覺就把蛆蟲放進(jìn)了代碼中……

          好了,下一篇:OO五大原則

          posted @ 2006-01-06 18:17 GHawk 閱讀(1607) | 評(píng)論 (3)編輯 收藏

          敏捷軟件開發(fā) 讀書筆記 (序——廢話)

          7-5083-1503-0l.gif

          最近正在讀這本書,喜歡影印版,是因?yàn)闀衅恋牟鍒D。:)慚愧,如此的好書到現(xiàn)在才去讀。
          準(zhǔn)備邊讀邊記錄些心得,今天先說些廢話。:P

          先粗略地概覽了一遍全書。本書主要分以下幾個(gè)部分:

          1. 敏捷軟件過程。主要以XP為例。這部分的最后一章,用一個(gè)對(duì)話式的小故事講述了一個(gè)非常小的過程。給了讀者關(guān)于敏捷過程的形象化的認(rèn)識(shí)。
          2. 敏捷設(shè)計(jì)。這部分是個(gè)很大的看點(diǎn)。它講述了設(shè)計(jì)中一些常見的問題,及其應(yīng)對(duì)(用幾個(gè)經(jīng)典的設(shè)計(jì)原則)。
          3. 案例實(shí)踐。講述了如何利用設(shè)計(jì)模式去實(shí)踐第二部分中提到的設(shè)計(jì)原則和避免設(shè)計(jì)中的“味道”。

          之所以覺得這本書好,還與一個(gè)人有關(guān)。就是交大軟件學(xué)院的林德彰老師。林先生的課,風(fēng)趣幽默,能夠用直觀形象的語言讓學(xué)生對(duì)講課內(nèi)容產(chǎn)生深刻的印象。(我可不是托兒,網(wǎng)上能搜到些林先生講課的片斷,要是懷疑,可以驗(yàn)證一番)。記得在軟件工程這門課里,林先生給我們講了很多有關(guān)設(shè)計(jì)原則的內(nèi)容,其中就有“開閉原則(OCP)”、“里氏替換原則(LSP)”等……就把這本書當(dāng)作是一本補(bǔ)充讀物吧。

          言歸正傳。個(gè)人感覺這本書的總體風(fēng)格,就和所要講的“敏捷”一樣,并不帶著厚重的學(xué)院派風(fēng)味,而是更注重實(shí)踐。并不是沒有理論,只是把理論融入到了實(shí)踐中,簡(jiǎn)化了理論的復(fù)雜性。讀起來感覺很帶勁兒。

          廢話說到這里,下一步的計(jì)劃就是跟著自己的進(jìn)度寫讀書心得了。我想把對(duì)書中內(nèi)容的理解和以前在林先生的課上所學(xué)的結(jié)合在一起,導(dǎo)出閱讀此書時(shí)的大腦活動(dòng)鏡像。

          posted @ 2005-12-27 12:00 GHawk 閱讀(1620) | 評(píng)論 (4)編輯 收藏

          一個(gè)介紹Java開源項(xiàng)目及工具的網(wǎng)站

          按功能進(jìn)行了歸類
          http://java-source.net


          再追加一個(gè)中文的
          http://www.open-open.com

          posted @ 2005-12-20 13:45 GHawk 閱讀(516) | 評(píng)論 (1)編輯 收藏

          用 Cobertura 測(cè)量測(cè)試覆蓋率

          http://www-128.ibm.com/developerworks/cn/java/j-cobertura/

          用 Cobertura 測(cè)量測(cè)試覆蓋率

          找出隱藏 bug 的未測(cè)試到的代碼

          developerWorks
          文檔選項(xiàng)
          將此頁作為電子郵件發(fā)送

          將此頁作為電子郵件發(fā)送

          未顯示需要 JavaScript 的文檔選項(xiàng)


          對(duì)此頁的評(píng)價(jià)

          幫助我們改進(jìn)這些內(nèi)容


          級(jí)別: 初級(jí)

          Elliotte Rusty Harold, 副教授, Polytechnic University

          2005 年 5 月 26 日

          Cobertura 是一種開源工具,它通過檢測(cè)基本的代碼,并觀察在測(cè)試包運(yùn)行時(shí)執(zhí)行了哪些代碼和沒有執(zhí)行哪些代碼,來測(cè)量測(cè)試覆蓋率。除了找出未測(cè)試到的代碼并發(fā)現(xiàn) bug 外,Cobertura 還可以通過標(biāo)記無用的、執(zhí)行不到的代碼來優(yōu)化代碼,還可以提供 API 實(shí)際操作的內(nèi)部信息。Elliotte Rusty Harold 將與您分享如何利用代碼覆蓋率的最佳實(shí)踐來使用 Cobertura。

          盡管測(cè)試先行編程(test-first programming)和單元測(cè)試已不能算是新概念,但測(cè)試驅(qū)動(dòng)的開發(fā)仍然是過去 10 年中最重要的編程創(chuàng)新。最好的一些編程人員在過去半個(gè)世紀(jì)中一直在使用這些技術(shù),不過,只是在最近幾年,這些技術(shù)才被廣泛地視為在時(shí)間及成本預(yù)算內(nèi)開發(fā)健壯的無缺陷軟件的關(guān)鍵所在。但是,測(cè)試驅(qū)動(dòng)的開發(fā)不能超過測(cè)試所能達(dá)到的程度。測(cè)試改進(jìn)了代碼質(zhì)量,但這也只是針對(duì)實(shí)際測(cè)試到的那部分代碼而言的。您需要有一個(gè)工具告訴您程序的哪些部分沒有測(cè)試到,這樣就可以針對(duì)這些部分編寫測(cè)試代碼并找出更多 bug。

          Mark Doliner 的 Cobertura (cobertura 在西班牙語是覆蓋的意思)是完成這項(xiàng)任務(wù)的一個(gè)免費(fèi) GPL 工具。Cobertura 通過用額外的語句記錄在執(zhí)行測(cè)試包時(shí),哪些行被測(cè)試到、哪些行沒有被測(cè)試到,通過這種方式來度量字節(jié)碼,以便對(duì)測(cè)試進(jìn)行監(jiān)視。然后它生成一個(gè) HTML 或者 XML 格式的報(bào)告,指出代碼中的哪些包、哪些類、哪些方法和哪些行沒有測(cè)試到。可以針對(duì)這些特定的區(qū)域編寫更多的測(cè)試代碼,以發(fā)現(xiàn)所有隱藏的 bug。

          閱讀 Cobertura 輸出

          我們首先查看生成的 Cobertura 輸出。圖 1 顯示了對(duì) Jaxen 測(cè)試包運(yùn)行 Cobertura 生成的報(bào)告(請(qǐng)參閱 參考資料)。從該報(bào)告中,可以看到從很好(在 org.jaxen.expr.iter 包中幾乎是 100%)到極差(在 org.jaxen.dom.html 中完全沒有覆蓋)的覆蓋率結(jié)果。


          圖 1. Jaxen 的包級(jí)別覆蓋率統(tǒng)計(jì)數(shù)據(jù)

          Cobertura 通過被測(cè)試的行數(shù)和被測(cè)試的分支數(shù)來計(jì)算覆蓋率。第一次測(cè)試時(shí),兩種測(cè)試方法之間的差別并不是很重要。Cobertura 還為類計(jì)算平均 McCabe 復(fù)雜度(請(qǐng)參閱 參考資料)。

          可以深入挖掘 HTML 報(bào)告,了解特定包或者類的覆蓋率。圖 2 顯示了 org.jaxen.function 包的覆蓋率統(tǒng)計(jì)。在這個(gè)包中,覆蓋率的范圍從 SumFunction 類的 100% 到 IdFunction 類的僅為 5%。


          圖 2. org.jaxen.function 包中的代碼覆蓋率

          進(jìn)一步深入到單獨(dú)的類中,具體查看哪一行代碼沒有測(cè)試到。圖 3 顯示了 NameFunction 類中的部分覆蓋率。最左邊一欄顯示行號(hào)。后一欄顯示了執(zhí)行測(cè)試時(shí)這一行被執(zhí)行的次數(shù)。可以看出,第 112 行被執(zhí)行了 100 次,第 114 行被執(zhí)行了 28 次。用紅色突出顯示的那些行則根本沒有測(cè)試到。這個(gè)報(bào)告表明,雖然從總體上說該方法被測(cè)試到了,但實(shí)際上還有許多分支沒有測(cè)試到。


          圖 3. NameFunction 類中的代碼覆蓋率

          Cobertura 是 jcoverage 的分支(請(qǐng)參閱 參考資料)。GPL 版本的 jcoverage 已經(jīng)有一年沒有更新過了,并且有一些長(zhǎng)期存在的 bug,Cobertura 修復(fù)了這些 bug。原來的那些 jcoverage 開發(fā)人員不再繼續(xù)開發(fā)開放源碼,他們轉(zhuǎn)向開發(fā) jcoverage 的商業(yè)版和 jcoverage+,jcoverage+ 是一個(gè)從同一代碼基礎(chǔ)中發(fā)展出來的封閉源代碼產(chǎn)品。開放源碼的奇妙之處在于:一個(gè)產(chǎn)品不會(huì)因?yàn)樵_發(fā)人員決定讓他們的工作獲得相應(yīng)的報(bào)酬而消亡。

          確認(rèn)遺漏的測(cè)試

          利用 Cobertura 報(bào)告,可以找出代碼中未測(cè)試的部分并針對(duì)它們編寫測(cè)試。例如,圖 3 顯示 Jaxen 需要進(jìn)行一些測(cè)試,運(yùn)用 name() 函數(shù)對(duì)文字節(jié)點(diǎn)、注釋節(jié)點(diǎn)、處理指令節(jié)點(diǎn)、屬性節(jié)點(diǎn)和名稱空間節(jié)點(diǎn)進(jìn)行測(cè)試。

          如果有許多未覆蓋的代碼,像 Cobertura 在這里報(bào)告的那樣,那么添加所有缺少的測(cè)試將會(huì)非常耗時(shí),但也是值得的。不一定要一次完成它。您可以從被測(cè)試的最少的代碼開始,比如那些所有沒有覆蓋的包。在測(cè)試所有的包之后,就可以對(duì)每一個(gè)顯示為沒有覆蓋的類編寫一些測(cè)試代碼。對(duì)所有類進(jìn)行專門測(cè)試后,還要為所有未覆蓋的方法編寫測(cè)試代碼。在測(cè)試所有方法之后,就可以開始分析對(duì)未測(cè)試的語句進(jìn)行測(cè)試的必要性。

          (幾乎)不留下任何未測(cè)試的代碼

          是否有一些可以測(cè)試但不應(yīng)測(cè)試的內(nèi)容?這取決于您問的是誰。在 JUnit FAQ 中,J. B. Rainsberger 寫到“一般的看法是:如果 自身 不會(huì)出問題,那么它會(huì)因?yàn)樘?jiǎn)單而不會(huì)出問題。第一個(gè)例子是 getX() 方法。假定 getX() 方法只提供某一實(shí)例變量的值。在這種情況下,除非編譯器或者解釋器出了問題,否則 getX() 是不會(huì)出問題的。因此,不用測(cè)試 getX(),測(cè)試它不會(huì)帶來任何好處。對(duì)于 setX() 方法來說也是如此,不過,如果 setX() 方法確實(shí)要進(jìn)行任何參數(shù)驗(yàn)證,或者說確實(shí)有副作用,那么還是有必要對(duì)其進(jìn)行測(cè)試。”

          理論上,對(duì)未覆蓋的代碼編寫測(cè)試代碼不一定就會(huì)發(fā)現(xiàn) bug。但在實(shí)踐中,我從來沒有碰到?jīng)]有發(fā)現(xiàn) bug 的情況。未測(cè)試的代碼充滿了 bug。所做的測(cè)試越少,在代碼中隱藏的、未發(fā)現(xiàn)的 bug 就會(huì)越多。

          我不同意。我已經(jīng)記不清在“簡(jiǎn)單得不會(huì)出問題”的代碼中發(fā)現(xiàn)的 bug 的數(shù)量了。確實(shí),一些 getter 和 setter 很簡(jiǎn)單,不可能出問題。但是我從來就沒有辦法區(qū)分哪些方法是真的簡(jiǎn)單得不會(huì)出錯(cuò),哪些方法只是看上去如此。編寫覆蓋像 setter 和 getter 這樣簡(jiǎn)單方法的測(cè)試代碼并不難。為此所花的少量時(shí)間會(huì)因?yàn)樵谶@些方法中發(fā)現(xiàn)未曾預(yù)料到的 bug 而得到補(bǔ)償。

          一般來說,開始測(cè)量后,達(dá)到 90% 的測(cè)試覆蓋率是很容易的。將覆蓋率提高到 95% 或者更高就需要?jiǎng)右幌履X筋。例如,可能需要裝載不同版本的支持庫,以測(cè)試沒有在所有版本的庫中出現(xiàn)的 bug。或者需要重新構(gòu)建代碼,以便測(cè)試通常執(zhí)行不到的部分代碼。可以對(duì)類進(jìn)行擴(kuò)展,讓它們的受保護(hù)方法變?yōu)楣卜椒ǎ@樣就可以對(duì)這些方法進(jìn)行測(cè)試。這些技巧看起來像是多此一舉,但是它們?cè)鴰椭以谝话氲臅r(shí)間內(nèi)發(fā)現(xiàn)更多的未發(fā)現(xiàn)的 bug。

          并不總是可以得到完美的、100% 的代碼覆蓋率。有時(shí)您會(huì)發(fā)現(xiàn),不管對(duì)代碼如何改造,仍然有一些行、方法、甚至是整個(gè)類是測(cè)試不到的。下面是您可能會(huì)遇到的挑戰(zhàn)的一些例子:

          • 只在特定平臺(tái)上執(zhí)行的代碼。例如,在一個(gè)設(shè)計(jì)良好的 GUI 應(yīng)用程序中,添加一個(gè) Exit 菜單項(xiàng)的代碼可以在 Windows PC 上運(yùn)行,但它不能在 Mac 機(jī)上運(yùn)行。

          • 捕獲不會(huì)發(fā)生的異常的 catch 語句,比如在從 ByteArrayInputStream 進(jìn)行讀取操作時(shí)拋出的 IOException

          • 非公共類中的一些方法,它們永遠(yuǎn)也不會(huì)被實(shí)際調(diào)用,只是為了滿足某個(gè)接口契約而必須實(shí)現(xiàn)。

          • 處理虛擬機(jī) bug 的代碼塊,比如說,不能識(shí)別 UTF-8 編碼。

          考慮到上面這些以及類似的情況,我認(rèn)為一些極限程序員自動(dòng)刪除所有未測(cè)試代碼的做法是不切實(shí)際的,并且可能具有一定的諷刺性。不能總是獲得絕對(duì)完美的測(cè)試覆蓋率并不意味著就不會(huì)有更好的覆蓋率。

          然而,比執(zhí)行不到的語句和方法更常見的是殘留代碼,它不再有任何作用,并且從代碼基中去掉這些代碼也不會(huì)產(chǎn)生任何影響。有時(shí)可以通過使用反射來訪問私有成員這樣的怪招來測(cè)試未測(cè)試的代碼。還可以為未測(cè)試的、包保護(hù)(package-protected)的代碼來編寫測(cè)試代碼,將測(cè)試類放到將要測(cè)試的類所在那個(gè)包中。但最好不要這樣做。所有不能通過發(fā)布的(公共的和受保護(hù)的)接口訪問的代碼都應(yīng)刪除。執(zhí)行不到的代碼不應(yīng)當(dāng)成為代碼基的一部分。代碼基越小,它就越容易被理解和維護(hù)。

          不要漏掉測(cè)量單元測(cè)試包和類本身。我不止一次注意到,某些個(gè)測(cè)試方法或者類沒有被測(cè)試包真正運(yùn)行。通常這表明名稱規(guī)范中存在問題(比如將一個(gè)方法命名為 tesSomeReallyComplexCondition,而不是將其命名為 testSomeReallyComplexCondition),或者忘記將一個(gè)類添加到主 suite() 方法中。在其他情況下,未預(yù)期的條件導(dǎo)致跳過了測(cè)試方法中的代碼。不管是什么情況,都是雖然已經(jīng)編寫了測(cè)試代碼,但沒有真正運(yùn)行它。JUnit 不會(huì)告訴您它沒有像您所想的那樣運(yùn)行所有測(cè)試,但是 Cobertura 會(huì)告訴您。找出了未運(yùn)行的測(cè)試后,改正它一般很容易。



          回頁首


          運(yùn)行 Cobertura

          在了解了測(cè)量代碼覆蓋率的好處后,讓我們?cè)賮碛懻撘幌氯绾斡?Cobertura 測(cè)量代碼覆蓋率的具體細(xì)節(jié)。Cobertura 被設(shè)計(jì)成為在 Ant 中運(yùn)行。現(xiàn)在還沒有這方面的 IDE 插件可用,不過一兩年內(nèi)也許就會(huì)有了。

          首先需要在 build.xml 文件中添加一個(gè)任務(wù)定義。以下這個(gè)頂級(jí) taskdef 元素將 cobertura.jar 文件限定在當(dāng)前工作目錄中:

          <taskdef classpath="cobertura.jar" resource="tasks.properties" />

          然后,需要一個(gè) cobertura-instrument 任務(wù),該任務(wù)將在已經(jīng)編譯好的類文件中添加日志代碼。todir 屬性指定將測(cè)量類放到什么地方。fileset 子元素指定測(cè)量哪些 .class 文件:

          <target name="instrument">
            <cobertura-instrument todir="target/instrumented-classes">
              <fileset dir="target/classes">
                <include name="**/*.class"/>
              </fileset>
            </cobertura-instrument>
          </target>

          用通常運(yùn)行測(cè)試包的同一種類型的 Ant 任務(wù)運(yùn)行測(cè)試。惟一的區(qū)別在于:被測(cè)量的類必須在原始類出現(xiàn)在類路徑中之前出現(xiàn)在類路徑中,而且需要將 Cobertura JAR 文件添加到類路徑中:

          <target name="cover-test" depends="instrument">
            <mkdir dir="${testreportdir}" />
            <junit dir="./" failureproperty="test.failure" printSummary="yes" 
                   fork="true" haltonerror="true">
              <!-- Normally you can create this task by copying your existing JUnit
                   target, changing its name, and adding these next two lines.
                   You may need to change the locations to point to wherever 
                   you've put the cobertura.jar file and the instrumented classes. -->
              <classpath location="cobertura.jar"/>
              <classpath location="target/instrumented-classes"/>
              <classpath>
                <fileset dir="${libdir}">
                  <include name="*.jar" />
                </fileset>
                <pathelement path="${testclassesdir}" />
                <pathelement path="${classesdir}" />
              </classpath>
              <batchtest todir="${testreportdir}">
                <fileset dir="src/java/test">
                  <include name="**/*Test.java" />
                  <include name="org/jaxen/javabean/*Test.java" />
                </fileset>
              </batchtest>
            </junit>
          </target>>

          Jaxen 項(xiàng)目使用 JUnit 作為其測(cè)試框架,但是 Cobertura 是不受框架影響的。它在 TestNG、Artima SuiteRunner、HTTPUni 或者在您自己在地下室開發(fā)的系統(tǒng)中一樣工作得很好。

          最后,cobertura-report 任務(wù)生成本文開始部分看到的那個(gè) HTML 文件:

          <target name="coverage-report" depends="cover-test">
           <cobertura-report srcdir="src/java/main" destdir="cobertura"/>
          </target>

          srcdir 屬性指定原始的 .java 源代碼在什么地方。destdir 屬性指定 Cobertura 放置輸出 HTML 的那個(gè)目錄的名稱。

          在自己的 Ant 編譯文件中加入了類似的任務(wù)后,就可以通過鍵入以下命令來生成一個(gè)覆蓋報(bào)告:

          % ant instrument
          % ant cover-test
          % ant coverage-report

          當(dāng)然,如果您愿意的話,還可以改變目標(biāo)任務(wù)的名稱,或者將這三項(xiàng)任務(wù)合并為一個(gè)目標(biāo)任務(wù)。



          回頁首


          結(jié)束語

          Cobertura 是敏捷程序員工具箱中新增的一個(gè)重要工具。通過生成代碼覆蓋率的具體數(shù)值,Cobertura 將單元測(cè)試從一種藝術(shù)轉(zhuǎn)變?yōu)橐婚T科學(xué)。它可以尋找測(cè)試覆蓋中的空隙,直接找到 bug。測(cè)量代碼覆蓋率使您可以獲得尋找并修復(fù) bug 所需的信息,從而開發(fā)出對(duì)每個(gè)人來說都更健壯的軟件。



          回頁首


          參考資料



          回頁首


          關(guān)于作者

          Elliotte Rusty Harold 出生在新奧爾良,現(xiàn)在他還定期回老家喝一碗美味的秋葵湯。不過目前,他和妻子 Beth 定居在紐約臨近布魯克林的 Prospect Heights,同住的還有他的貓咪 Charm(取自夸克)和 Marjorie(取自他岳母的名字)。他是 Polytechnic 大學(xué)計(jì)算機(jī)科學(xué)的副教授,講授 Java 技術(shù)和面向?qū)ο缶幊獭K?Cafe au Lait 網(wǎng)站是 Internet 上最受歡迎的獨(dú)立 Java 站點(diǎn)之一,姊妹站點(diǎn) Cafe con Leche 已經(jīng)成為最受歡迎的 XML 站點(diǎn)之一。他的著作包括 Effective XML Processing XML with Java Java Network Programming The XML 1.1 Bible 。目前他正在從事 XML 的 XOM API、Jaxen XPath 引擎和 Jester 測(cè)試覆蓋率工具的開發(fā)工作。


          posted @ 2005-12-17 11:23 GHawk 閱讀(428) | 評(píng)論 (0)編輯 收藏

          EasyMock 2.0_ReleaseCandidate 文檔翻譯

               摘要: EasyMock 2.0_ReleaseCandidate Readme Documentation for release 2.0_ReleaseCandidate (October 15 2005)? 2001-2005 OFFIS, Tammo Freese. 翻譯:GHawk, 2005-12-15 EasyMock 2 is a library that provides an ...  閱讀全文

          posted @ 2005-12-15 16:06 GHawk 閱讀(4771) | 評(píng)論 (2)編輯 收藏

          主站蜘蛛池模板: 仁布县| 台前县| 凌海市| 梅河口市| 名山县| 和龙市| 延庆县| 来安县| 教育| 鄢陵县| 桓仁| 哈尔滨市| 乐山市| 肇庆市| 长春市| 洮南市| 文化| 于都县| 绥芬河市| 扎兰屯市| 合作市| 格尔木市| 青田县| 海淀区| 改则县| 建阳市| 甘肃省| 陇川县| 东阳市| 呈贡县| 阿拉善右旗| 伊宁市| 龙门县| 贡觉县| 滨州市| 遂宁市| 手游| 依安县| 梅州市| 通渭县| 格尔木市|