<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    GHawk

    2005年12月17日 #

    建議方正要是勝訴的話,為開源事業做點貢獻

    中國人民可以說是被盜版和Windows慣壞了。在Linux默認環境下的中文顯示至今慘不忍睹。
    看看現在一些主要的發行版本,默認設置下的日語的顯示已經相當不錯了。
    作為漢字發祥地且擁有眾多人口的中國,實在是有些悲哀。
    文泉驛計劃正在為實現這個目標努力。作為一個非盈利性組織,他們的貢獻的確值得贊賞。
    最近方正正在為字體的事情打官司,并提出了高額賠償的要求。建議方正要是能夠勝訴的話,貢獻一些字體給開源組織,為弘揚漢語言文化多做點貢獻。

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

    Maven2 用于度量和品質保證的插件


    以上是一些常用的用于品質管理的插件。默認情況下都不用配置,相當方便。如果需要手動配置的話,根據網上的文檔也相當容易配置。
    apache的maven plugin頁面: http://maven.apache.org/plugins/
    codehaus mojo 頁面: http://mojo.codehaus.org

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

    Scripting in Mustang 的一點啟發

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

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

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

    對于這個特性,想到的一個可能的應用就是在annotation中寫腳本語言,然后在代碼中用相應的腳本語言引擎解釋執行。
    保留到運行時的annotation可以用實現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 閱讀(1327) | 評論 (3)編輯 收藏

    一個XPer提供的一些經驗

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

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

    工具
    在開展這些實踐的時候,交流比較頻繁。首推的工具是Mini white boardDC
    選擇Mini white board的原因并不是因為帶有"mini"聽上去會像 Mini Cooper 或者 iPod mini 那么cool。因為一塊A3左右大小的白板非常適合個人或者結對使用,而且環保(省去了草稿紙)。雖然整個團隊也有用于大規模交流的更大的白板,但那屬于“競爭資源”,各自使用自己的白板更為方便。
    交流結果產生后,為了不花不必要的時間去做精美的文檔,一臺輕便的DC往往是最合適的選擇。當然,如果足夠,手機上的照相功能也可以完成同樣的任務。相比偷拍街上的MM,這些電子產品能夠實現更大的價值。

    關于結對
    每天進行6小時的結對編程,分3次,每次2小時。每次和不同的成員組隊。在結隊的時候充分利用了上面提到的工具進行交流。如果出現兩個人不能解決的問題的時候,會立即向整個團隊提出,這樣可能導致一次stand-up meeting。即使問題不能馬上解決,至少也能確保每個人都知道這個問題。

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

    關于locale的設定 (轉)

    ?
    locale是國際化與本土化過程中的一個非常重要的概念,個人認為,對于中文用戶來說,通常會涉及到的國際化或者本土化,大致包含三個方面:看中文,寫中文,與window中文系統的兼容和通信。從實際經驗上看來,locale的設定與看中文關系不大,但是與寫中文,及window分區的掛載方式有很密切的關系。本人認為就像一個純英文的Windows能夠瀏覽中文,日文或者意大利文網頁一樣,你不需要設定locale就可以看中文。那么,為什么要設定locale呢?什么時候會用到locale呢?

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

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

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

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

    六、locale的五臟六腑
    ?
    剛剛生成了幾個locale,但是為了讓它們生效,必須告訴Linux系統使用那(幾)個locale。這就需要對locale的內部機制有一點點的了解。在前面我已經提到過,locale把按照所涉及到的文化傳統的各個方面分成12個大類,這12個大類分別是:
    1、語言符號及其分類(LC_CTYPE)
    2、數字(LC_NUMERIC)
    3、比較和排序習慣(LC_COLLATE)
    4、時間顯示格式(LC_TIME)
    5、貨幣單位(LC_MONETARY)
    6、信息主要是提示信息,錯誤信息, 狀態信息, 標題, 標簽, 按鈕和菜單等(LC_MESSAGES)
    7、姓名書寫方式(LC_NAME)
    8、地址書寫方式(LC_ADDRESS)
    9、電話號碼書寫方式(LC_TELEPHONE)
    10、度量衡表達方式(LC_MEASUREMENT)
    11、默認紙張尺寸大小(LC_PAPER)
    12、對locale自身包含信息的概述(LC_IDENTIFICATION)。
    ?
    其中,與中文輸入關系最密切的就是 LC_CTYPE, LC_CTYPE 規定了系統內有效的字符以及這些字符的分類,諸如什么是大寫字母,小寫字母,大小寫轉換,標點符號、可打印字符和其他的字符屬性等方面。而locale定義zh_CN中最最重要的一項就是定義了漢字(Class “hanzi”)這一個大類,當然也是用Unicode描述的,這就讓中文字符在Linux系統中成為合法的有效字符,而且不論它們是用什么字符集編碼的。
    ?
    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等等。
    ?
    另外非常重要的一點就是這些分類是彼此獨立的,也就是說LC_CTYPE,LC_COLLATE和 LC_MESSAGES等等分類彼此之間是獨立的,可以根據用戶的需要設定成不同的值。這一點對很多用戶是有利的,甚至是必須的。例如,我就需要一個能夠輸入中文的英文環境,所以我可以把LC_CTYPE設定成zh_CN.GB18030,而其他所有的項都是en_US.UTF-8。
    ?

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

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

    PostgreSQL的主機認證配置

    轉自 http://www.linuxsir.org/bbs/showthread.php?t=32116

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

    文件 pg_hba.conf 的常用格式是一套記錄, 每行一條。空白行或者井號(“#”)開頭的行被忽略。一條記錄 是由若干用空格和/或 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 ]

    各個字段的含義如下:

    local
    這條記錄適用于通過 Unix 域套接字的聯接.

    host
    這條記錄適用于通過 TCP/IP 網絡的聯接.請注意,除非服務器是 帶著 -i 選項或者等效的配置參數集啟動的,否則 TCP/IP 聯接將完全被禁止掉.

    hostssl
    這條記錄適用于試圖建立在 TCP/IP 上的 SSL 之上的聯接. 要使用這個選項,服務器必須帶著 SSL 支持編譯.而且在服務器啟動的時候, 必須用 -l 選項 或等效的配置設置打開 SSL.

    database
    聲明記錄所適用的數據庫。值 all 表明該記錄應用于所有數據庫, 值 sameuser 表示于正在聯接的用戶同名的數據庫。 否則它就是某個具體的 Postgres 數據庫名字.

    IP address, IP mask
    這兩個字段以各主機的 IP 地址為基礎, 控制一條 host 記錄應用于哪個主機. (當然,IP 地址可能會被欺騙(spoofed),但是這個考慮 超過了 Postgres 的考慮范圍.) 準確的邏輯是,對于匹配的記錄

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

    authentication method(認證方法)
    聲明一個用戶在與該數據庫聯接的時候必須使用的認證方法. 可能的選擇如下,詳細情況在 Section 4.2.


    trust
    無條件地允許聯接.這個方法允許任何有登錄客戶機權限的用戶以任意 Postgres 數據庫用戶身份進行聯接.

    reject
    聯接無條件拒絕.常用于從組中“過濾”某些主機.

    password
    要求客戶端在嘗試聯接的時候提供一個口令, 這個口令與為該用戶設置的口令必須匹配.

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

    口令是以明文的方式在線路上傳輸的.如果要更好的保護,請使用 crypt 方法.

    crypt
    類似 password 方法,但是口令是用一種簡單的 口令對應協議加密后在線路上傳送的.這么做在密碼學理論上是不安全的, 但可以防止偶然的線路偵聽.在 crypt 關鍵字后面 可以有一個文件,文件里包含適用口令認證記錄的用戶列表.

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

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

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


    authentication option(認證選項)
    這個字段根據不同的認證方法(authentication method)有不同的 解釋.

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

    在每次聯接的請求時,文件 pg_hba.conf 都會被重新讀取.因此很容易就能在服務器運行的時候修改訪問權限.

    在 Example 4-1 里是 pg_hba.conf 的一個例子. 閱讀下文理解不同認證方法的細節.

    Example 4-1. 一個 pg_hba.conf 文件的例子

    # TYPE DATABASE IP_ADDRESS MASK AUTHTYPE MAP

    # 允許在本機上的任何用戶以任何身份聯接任何數據庫
    # 但必須是通過 IP 進行聯接

    host all 127.0.0.1 255.255.255.255 trust

    # 同樣,但用的是 Unix-套接字聯接

    local all trust

    # 允許 IP 地址為 192.168.93.x 的任何主機與數據庫
    # "template1" 相連,用與他們在自己的主機上相同 ident 的用戶名標識他自己
    # (通常是他的 Unix 用戶名)

    host template1 192.168.93.0 255.255.255.0 ident sameuser

    # 允許來自主機 192.168.12.10 的用戶與 "template1" 數據庫聯接,
    # 只要該用戶提供了在 pg_shadow 里正確的口令.

    host template1 192.168.12.10 255.255.255.255 crypt

    # 如果前面沒有其它 "host" 行,那么下面兩行將拒絕所有來自
    # 192.168.54.1 的聯接請求 (因為前面的記錄先匹配
    # 但是允許來自互聯網上其它任何地方有效的 Kerberos V5 認證的聯接
    # 零掩碼表示不考慮主機 IP 的任何位.因此它匹配任何主機:

    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 的任何用戶與任意數據庫聯接,只要他們通過 ident 檢查
    # 但如果 ident 說該用戶是 "bryanh" 而他要求以 PostgreSQL 用戶 "guest1" 聯接,
    # 那么只有在 `pg_ident.conf' 里有 "omicron" 的映射,說 "bryanh" 允許以
    # "guest1" 進行聯接時才真正可以進行聯接.

    host all 192.168.0.0 255.255.0.0 ident omicron

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

    UP & XP之爭,意義何在?(續)

    雖然我沒能去參加BEA的活動,但是相關的資料已經下載并且瀏覽過了,確實收獲不少。所以,對于莊兄的這些想法我很理解。

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

    我所關心的問題是“如何能夠用好XP?”。

    莊兄認為“湯的味道,不需要什么過程控制”,我也會認同。為什么?因為你我都是中國人。大部分中國人不會認為湯的味道需要什么過程控制。但是想想看,如果你在不同地方買到的肯德基炸雞味道各異;同一批次生產的同型號的汽車形狀各異;銀行里取出來的一疊百元大鈔大小不一,你不會覺得奇怪么或是有那么一點點憤怒么?

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

    所以,一切質量都有標準,一切標準都應該被度量!這就是工程學的目標之一,為了實現更嚴格的質量標準,就需要過程控制和度量。

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

    不要學習哲學家的方法,提出一層又一層無法解決的問題。我們是工程師,應該試圖解決問題才對!解決問題的關鍵在于,XP同樣需要標準!為了制定標準,必要的文檔是不可以少的。而且,標準本身的質量是嚴苛的。因為,作為標準,他不可以含糊其辭、模棱兩可。在標準的基礎之上,我們才可以談什么TDD、Pair Programming之類的實踐。

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

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

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

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

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

    UP & XP之爭,意義何在?

    不光是做軟件,凡是做產品,最后關注的總是產品的質量

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

    因此,只把焦點放在最后的產品上往往是不夠的。需要對“做湯的過程”加以控制。所以工程界會比較關注過程的管理,在軟件領域也稱作“軟件生命周期管理”。

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

    再拿剛才那個做湯的例子:
    大家都聽說過德國人的廚房像化學實驗室,天平、計時器、量杯……裝備齊全,再配上精確的菜譜,嚴謹的德國人能夠確保不用嘗那最后一口都做出口味基本一致的湯。
    換了中國人,大部分人都不會模仿德國人做菜的方式。解決方案很簡單,讓你的太太和孩子都嘗那最后一口,再根據反饋調整幾次,同樣能做出全家人滿意的湯。

    這個例子也許不太貼切,但是可以聯想一下:德國人做湯傾向于UP;中國人做湯傾向于XP

    UP和XP最終目的都是為了保證產品的質量,不同的是,兩個過程所強調的方法不同。我想,沒有人會說“UP的目的在于變態地追求文檔的完美”、“UP是為了要程序員學會寫各種各樣文檔”……之類的話。同時,也沒人會說“XP就是不要文檔只要代碼”、“XP就是要變態地追求完美的代碼”……這樣的話。

    這些不正確的看法,只是人們對于這兩種過程的誤解。或許是來自于開發人員和項目經理的那些“不堪回首的經歷”。

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

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

    對于不同的技術和過程,應該給予冷靜的分析和慎重的選擇。每個過程和技術都不能以“正確”或“不正確”來定性,只能以“合適”和“不合適”來定性。因為正確或不正確是要嚴格證明的,而合適不合適是來源于工程實踐的結果。所以,COBOL依然在金融領域起著舉足輕重的作用,科學家們仍不忘Fortran,匯編和C仍然健在……

    另外不得不提的是文化上的差異。為什么很多時候,我們學習國外的先進技術,購買了整套生產線,引進了全套圖紙,請國外專家做了詳細的全程化培訓,國人生產出的產品品質依然不如國外原產的?這是每個中國人都應該思考的問題……

    ?

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

    對"UP是正楷,XP是草書"的反思

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

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

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

    • 計劃文檔——項目的開發計劃、迭代計劃、測試計劃等。
    • 技術文檔——項目的設計文檔、某個操作的說明文檔等。
    • 記錄文檔——日常的會議紀要、每日進度反饋、評估報告等。

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

    而正是因為如此繁重的資源消耗,導致真正的設計和代碼只占到了總開銷的很少部分。這對很多人來說不可理解,甚至覺得本末倒置。于是很多敏捷方法誕生了,最具代表性也是對UP思想最具顛覆性的就屬XP了。

    對外,XP以快速的反應速度來響應客戶的需求;對內,XP以高質量的代碼和設計來確保盡可能不產生不必要的文檔和資源開銷。

    從表面上看,在當今,XP確實是一種非常理想的開發過程。

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

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

    UP利用文檔來約束和規范人們的開發活動。當一個沒有經驗的團隊經歷UP后,就等于把性格各異、習慣差別不同的人統一成了“相對較一致的開發人員”。

    他們有一致的編碼習慣,有共同的用語,有嚴格的規則。隨著經驗的積累,這個團隊間的默契越來越高。此時,如果過程由UP向XP切換,付出的代價就會相對較低。

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

    XP主張快速反應。如果一個沒有經驗的團隊在一開始就嘗試XP,那么后果可能是慘痛的。因為一個沒有經驗的團隊其成員間的相互了解頗少,對于一件事,往往十個人有十種想法。當缺少文檔約束時,在以代碼和設計為中心的活動中,成員之間往往因為水平的參差不齊導致無休止的討論甚至爭論,代碼被不必要地頻繁改動。這是因為,在團隊建設早期,成員之間往往連最基本的尊重和信任都不存在。 這種無意義的活動往往會嚴重影響項目的正常進行。

    所以,學習和應用過程不僅僅是個體的事,而是整個團隊的事。只有當團隊采用嚴格文檔化的過程并且經過磨合后,才能漸漸向輕量級的過程遷移,逐漸將不必要的文檔刪減掉,采用更靈活的過程。但是,此時并不是“沒有文檔”而是“心中有文檔”。

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

    加載Classpath中的文件(轉)

       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 閱讀(765) | 評論 (0)編輯 收藏

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

    OCP作為OO的高層原則,主張使用“抽象(Abstraction)”和“多態(Polymorphism)”將設計中的靜態結構改為動態結構,維持設計的封閉性。

    “抽象”是語言提供的功能。“多態”由繼承語義實現。

    如此,問題產生了:“我們如何去度量繼承關系的質量?”

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

    該原則稱為Liskov Substitution Principle——里氏替換原則。林先生在上課時風趣地稱之為“老鼠的兒子會打洞”。^_^

    我們來研究一下LSP的實質。學習OO的時候,我們知道,一個對象是一組狀態和一系列行為的組合體。狀態是對象的內在特性,行為是對象的外在特性。LSP所表述的就是在同一個繼承體系中的對象應該有共同的行為特征。

    這一點上,表明了OO的繼承與日常生活中的繼承的本質區別。舉一個例子:生物學的分類體系中把企鵝歸屬為鳥類。我們模仿這個體系,設計出這樣的類和關系。

     lsp-fig1.jpg

    類“鳥”中有個方法fly,企鵝自然也繼承了這個方法,可是企鵝不能飛阿,于是,我們在企鵝的類中覆蓋了fly方法,告訴方法的調用者:企鵝是不會飛的。這完全符合常理。但是,這違反了LSP,企鵝是鳥的子類,可是企鵝卻不能飛!需要注意的是,此處的“鳥”已經不再是生物學中的鳥了,它是軟件中的一個類、一個抽象。

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

    修正后的設計如下:

     lsp-fig2.jpg

    但是,這就是LSP的全部了么?書中給了一個經典的例子,這又是一個不符合常理的例子:正方形不是一個長方形。這個悖論的詳細內容能在網上找到,我就不多廢話了。

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

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

    1. 每個方法調用之前,該方法應該校驗傳入參數的正確性,只有正確才能執行該方法,否則認為調用方違反契約,不予執行。這稱為前置條件(Pre-condition)。
    2. 一旦通過前置條件的校驗,方法必須執行,并且必須確保執行結果符合契約,這稱之為后置條件(Post-condition)。
    3. 對象本身有一套對自身狀態進行校驗的檢查條件,以確保該對象的本質不發生改變,這稱之為不變式(Invariant)。

    以上是單個對象的約束條件。為了滿足LSP,當存在繼承關系時,子類中方法的前置條件必須與超類中被覆蓋的方法的前置條件相同或者更寬松;而子類中方法的后置條件必須與超類中被覆蓋的方法的后置條件相同或者更為嚴格。

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

    • 繼承并且覆蓋超類方法的時候,子類中的方法的可見性必須等于或者大于超類中的方法的可見性,子類中的方法所拋出的受檢異常只能是超類中對應方法所拋出的受檢異常的子類。
      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開始,子類中的方法的返回值也可以是對應的超類方法的返回值的子類。這叫做“協變”(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呢?很遺憾,主流的面向對象語言(不論是動態語言還是靜態語言)還沒有加入對DbC的支持。但是隨著AOP概念的產生,相信不久DbC也將成為OO語言的一個重要特性之一。

    一些題外話:

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

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

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

    開閉原則很簡單,一句話:“Closed for Modification; Open for Extension”——“對變更關閉;對擴展開放”。開閉原則其實沒什么好講的,我將其歸結為一個高層次的設計總則。就這一點來講,OCP的地位應該比SRP優先。

    OCP的動機很簡單:軟件是變化的。不論是優質的設計還是低劣的設計都無法回避這一問題。OCP說明了軟件設計應該盡可能地使架構穩定而又容易滿足不同的需求。

    為什么要OCP?答案也很簡單——重用。

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

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

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

    OCP-fig1.JPG

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

     OCP-fig2.JPG

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

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

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

    開源 Java 測試框架(轉)

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

     JUnit   

    JUnit是由 Erich Gamma 和 Kent Beck 編寫的一個回歸測試框架(regression testing framework)。Junit測試是程序員測試,即所謂白盒測試,因為程序員知道被測試的軟件如何(How)完成功能和完成什么樣(What)的功能。Junit是一套框架,繼承TestCase類,就可以用Junit進行自動測試了。

    http://www.junit.org/

     Cactus   

    Cactus是一個基于JUnit框架的簡單測試框架,用來單元測試服務端Java代碼。Cactus框架的主要目標是能夠單元測試服務端的使用Servlet對象的Java方法如HttpServletRequest,HttpServletResponse,HttpSession等。

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

     Abbot   

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

    http://abbot.sourceforge.net/

     JUnitPerf   

    Junitperf實際是junit的一個decorator,通過編寫用于junitperf的單元測試,我們也可使測試過程自動化。

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

     DbUnit   

    DbUnit是為數據庫驅動的項目提供的一個對JUnit 的擴展,除了提供一些常用功能,它可以將你的數據庫置于一個測試輪回之間的狀態。

    http://dbunit.sourceforge.net/

     Mockrunner   

    Mockrunner用在J2EE環境中進行應用程序的單元測試。它不僅支持Struts actions, servlets,過濾器和標簽類還包括一個JDBC和一個JMS測試框架,可以用于測試基于EJB的應用程序。

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

     DBMonster   

    DBMonster是一個用生成隨機數據來測試SQL數據庫的壓力測試工具。

    http://dbmonster.kernelpanic.pl/

     MockEJB   

    MockEJB是一個不需要EJB容器就能運行EJB并進行測試的輕量級框架。

    http://mockejb.sourceforge.net/

     StrutsTestCase   

    StrutsTestCase 是Junit TestCase類的擴展,提供基于Struts框架的代碼測試。StrutsTestCase同時提供Mock 對象方法和Cactus方法用來實際運行Struts ActionServlet,你可以通過運行servlet引擎來測試。因為StrutsTestCase使用ActionServlet控制器來測試你的代碼,因此你不僅可以測試Action對象的實現,而且可以測試mappings,from beans以及forwards聲明。StrutsTestCase不啟動servlet容器來測試struts應用程序(容器外測試)也屬于Mock對象測試,但是與EasyMock不同的是,EasyMock是提供了創建Mock對象的API,而StrutsTest則是專門負責測試Struts應用程序的Mock對象測試框架。

    http://strutstestcase.sourceforge.net/

     JFCUnit   

    JFCUnit使得你能夠為Java偏移應用程序編寫測試例子。它為從用代碼打開的窗口上獲得句柄提供了支持;為在一個部件層次定位部件提供支持;為在部件中發起事件(例如按一個按鈕)以及以線程安全方式處理部件測試提供支持。

    http://jfcunit.sourceforge.net/

     JTestCase   

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

    http://jtestcase.sourceforge.net/

     SQLUnit   

    SQLUnit是一個單元測試框架,用于對數據庫存儲過程進行回歸測試。用 Java/JUnit/XML開發。

    http://sqlunit.sourceforge.net

     JTR   

    JTR (Java Test Runner)是一個開源的基于反轉控制(IOC)的J2EE測試框架。它允許你構建復雜的J2EE測試套件(Test Suites)并連到應用服務器執行測試,可以包括多個測試實例。JTR的licensed是GPL協議。

    http://jtrunner.sourceforge.net/

     Marathon   

    Marathon是一個針對使用Java/Swing開發GUI應用程序的測試框架,它由recorder, runner 和 editor組成,測試腳本是python代碼。Marathon的焦點是放在最終用戶的測試上。

    http://marathonman.sourceforge.net

     TestNG   

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

    http://testng.org/

     Surrogate Test framework   

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

    http://surrogate.sourceforge.net

     MockCreator   

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

    http://mockcreator.sourceforge.net/

     jMock   

    jMock利用mock objects思想來對Java code進行測試。jMock具有以下特點:容易擴展,讓你快速簡單地定義mock objects,因此不必打破程序間的關聯,讓你定義靈活的超越對象之間交互作用而帶來測試局限,減少你測試地脆弱性。

    http://www.jmock.org/

     EasyMock   

    EasyMock為Mock Objects提供接口并在JUnit測試中利用Java的proxy設計模式生成它們的實例。EasyMock最適合于測試驅動開發。

    http://www.easymock.org/

     The Grinder   

    The Grinder是一個負載測試框架。在BSD開源協議下免費使用。

    http://grinder.sourceforge.net/

     XMLUnit   

    XMLUnit不僅有Java版本的還有.Net版本的。Java開發的XMLUnit提供了兩個JUnit 擴展類XMLAssert和XMLTestCase,和一組支持的類。這些類可以用來比較兩張XML之間的不同之處,展示XML利用XSLT來,校驗XML,求得XPath表達式在XML中的值,遍歷XML中的某一節點利DOM展開。

    http://xmlunit.sourceforge.net/

     Jameleon   

    Jameleon一個自動化測試工具。它被用來測試各種各樣的應用程序,所以它被設計成插件模式。為了使整個測試過程變得簡單Jameleon提供了一個GUI,因此Jameleon實現了一個Swing 插件。

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

     J2MEUnit   

    J2MEUnit是應用在J2ME應用程序的一個單元測試框架。它基于JUnit。

    http://j2meunit.sourceforge.net/

     Jetif   

    Jetif是一個用純Java實現的回歸測試框架。它為Java程序單元測試以及功能測試提供了一個簡單而且可 伸縮的架構,可以用于個人開發或企業級開發的測試。它容易使用,功能強大,而且擁有一些企業級測試的重要功能。Jetif來源于JUnit, JTestCase以及TestNG的啟發,有幾個基本的概念直接來自于JUnit, 比如說斷言機制,Test Listener的概念,因此從JUnit轉到Jetif是非常容易的。

    http://jetif.sourceforge.net/

     GroboUtils   

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

    http://groboutils.sourceforge.net/

     Testare   

    TESTARE是用來簡化分布式應用程序(比如:在SERVLETS,JMS listeners, CORBA ORBs或RMI環境下)測試開發過程的一個測試框架。

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

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

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

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

          在學習和使用OO設計的時候,我們應該明白:OO的出現使得軟件工程師們能夠用更接近真實世界的方法描述軟件系統。然而,軟件畢竟是建立在抽象層次上的東西,再怎么接近真實,也不能替代真實或被真實替代。

          OO設計的五大原則之間并不是相互孤立的。彼此間存在著一定關聯,一個可以是另一個原則的加強或是基礎。違反其中的某一個,可能同時違反了其余的原則。因此應該把這些原則融會貫通,牢記在心!

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

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

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

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

    敏捷軟件開發 讀書筆記 (1)——設計的目標

    軟件設計是一種抽象活動,設計所要實現的是產出代碼。就這一點來說,任何人都會設計。但是,正如我們日常生活中所耳聞目睹或親身經歷,設計有優劣之分。

    從項目管理的角度去理解,設計是為了滿足涉眾(Stakeholders)的需求。顯然,一個設計應該滿足客戶對系統的功能及非功能需求。但單是滿足了這一點,并不能稱為一個好的設計。因為開發者同樣屬于涉眾!而開發者的需求又是怎樣的呢?至少,應該有以下幾條吧:

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

    所以,設計應該盡可能多地照顧到維護和變更。

    為了兼顧各戶滿意和維護成本,設計應該不斷挑戰其終極目標——松耦合。不管是XP或UP,這個目標都不會改變。OO設計中的五大原則,其根本目的就是降低組件間的耦合度,避免牽一發則動全身的現象發生。降低耦合度不僅能夠提高軟件內在的質量,還能大大減少不必要的編譯時間、減少向版本控制系統提交源碼的網絡開銷……

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

    但是,作為一個開發人員,對手中的代碼應該有適當的敏感性。畢竟,這些代碼是你親手創造的,誰不希望自己的作品得到眾人的贊許?或許能換得一次加薪升職的機會^_^ 退一步,這可關系到寶貴的休息時間啊。所以,開發者應該對自己的產品有這樣一種意識:及時修正設計中不合理的地方。

    敏捷過程告訴我們:在代碼“有味道”的時候進行重構。“有味道”是代碼正在變質的標志,很遺憾,能夠使代碼保持原味的防腐劑還沒發明。為了保證代碼質量,及時重構是必要的。這就像在燒烤的時候為了防止烤焦,你得坐在爐子前經常翻動肉塊一樣。

    如何聞出代碼的味道?認真學習一下OO吧,別以為OO很簡單,就是繼承+封裝+多態,誰都會。即使是書中記述的五大原則,想要運用自如,也得多感覺感覺才行。很多時候,我們不知不覺就把蛆蟲放進了代碼中……

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

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

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

    7-5083-1503-0l.gif

    最近正在讀這本書,喜歡影印版,是因為書中漂亮的插圖。:)慚愧,如此的好書到現在才去讀。
    準備邊讀邊記錄些心得,今天先說些廢話。:P

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

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

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

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

    廢話說到這里,下一步的計劃就是跟著自己的進度寫讀書心得了。我想把對書中內容的理解和以前在林先生的課上所學的結合在一起,導出閱讀此書時的大腦活動鏡像。

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

    一個介紹Java開源項目及工具的網站

    按功能進行了歸類
    http://java-source.net


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

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

    用 Cobertura 測量測試覆蓋率

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

    用 Cobertura 測量測試覆蓋率

    找出隱藏 bug 的未測試到的代碼

    developerWorks
    文檔選項
    將此頁作為電子郵件發送

    將此頁作為電子郵件發送

    未顯示需要 JavaScript 的文檔選項


    對此頁的評價

    幫助我們改進這些內容


    級別: 初級

    Elliotte Rusty Harold, 副教授, Polytechnic University

    2005 年 5 月 26 日

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

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

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

    閱讀 Cobertura 輸出

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


    圖 1. Jaxen 的包級別覆蓋率統計數據

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

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


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

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


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

    Cobertura 是 jcoverage 的分支(請參閱 參考資料)。GPL 版本的 jcoverage 已經有一年沒有更新過了,并且有一些長期存在的 bug,Cobertura 修復了這些 bug。原來的那些 jcoverage 開發人員不再繼續開發開放源碼,他們轉向開發 jcoverage 的商業版和 jcoverage+,jcoverage+ 是一個從同一代碼基礎中發展出來的封閉源代碼產品。開放源碼的奇妙之處在于:一個產品不會因為原開發人員決定讓他們的工作獲得相應的報酬而消亡。

    確認遺漏的測試

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

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

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

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

    理論上,對未覆蓋的代碼編寫測試代碼不一定就會發現 bug。但在實踐中,我從來沒有碰到沒有發現 bug 的情況。未測試的代碼充滿了 bug。所做的測試越少,在代碼中隱藏的、未發現的 bug 就會越多。

    我不同意。我已經記不清在“簡單得不會出問題”的代碼中發現的 bug 的數量了。確實,一些 getter 和 setter 很簡單,不可能出問題。但是我從來就沒有辦法區分哪些方法是真的簡單得不會出錯,哪些方法只是看上去如此。編寫覆蓋像 setter 和 getter 這樣簡單方法的測試代碼并不難。為此所花的少量時間會因為在這些方法中發現未曾預料到的 bug 而得到補償。

    一般來說,開始測量后,達到 90% 的測試覆蓋率是很容易的。將覆蓋率提高到 95% 或者更高就需要動一下腦筋。例如,可能需要裝載不同版本的支持庫,以測試沒有在所有版本的庫中出現的 bug。或者需要重新構建代碼,以便測試通常執行不到的部分代碼。可以對類進行擴展,讓它們的受保護方法變為公共方法,這樣就可以對這些方法進行測試。這些技巧看起來像是多此一舉,但是它們曾幫助我在一半的時間內發現更多的未發現的 bug。

    并不總是可以得到完美的、100% 的代碼覆蓋率。有時您會發現,不管對代碼如何改造,仍然有一些行、方法、甚至是整個類是測試不到的。下面是您可能會遇到的挑戰的一些例子:

    • 只在特定平臺上執行的代碼。例如,在一個設計良好的 GUI 應用程序中,添加一個 Exit 菜單項的代碼可以在 Windows PC 上運行,但它不能在 Mac 機上運行。

    • 捕獲不會發生的異常的 catch 語句,比如在從 ByteArrayInputStream 進行讀取操作時拋出的 IOException

    • 非公共類中的一些方法,它們永遠也不會被實際調用,只是為了滿足某個接口契約而必須實現。

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

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

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

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



    回頁首


    運行 Cobertura

    在了解了測量代碼覆蓋率的好處后,讓我們再來討論一下如何用 Cobertura 測量代碼覆蓋率的具體細節。Cobertura 被設計成為在 Ant 中運行。現在還沒有這方面的 IDE 插件可用,不過一兩年內也許就會有了。

    首先需要在 build.xml 文件中添加一個任務定義。以下這個頂級 taskdef 元素將 cobertura.jar 文件限定在當前工作目錄中:

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

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

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

    用通常運行測試包的同一種類型的 Ant 任務運行測試。惟一的區別在于:被測量的類必須在原始類出現在類路徑中之前出現在類路徑中,而且需要將 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 項目使用 JUnit 作為其測試框架,但是 Cobertura 是不受框架影響的。它在 TestNG、Artima SuiteRunner、HTTPUni 或者在您自己在地下室開發的系統中一樣工作得很好。

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

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

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

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

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

    當然,如果您愿意的話,還可以改變目標任務的名稱,或者將這三項任務合并為一個目標任務。



    回頁首


    結束語

    Cobertura 是敏捷程序員工具箱中新增的一個重要工具。通過生成代碼覆蓋率的具體數值,Cobertura 將單元測試從一種藝術轉變為一門科學。它可以尋找測試覆蓋中的空隙,直接找到 bug。測量代碼覆蓋率使您可以獲得尋找并修復 bug 所需的信息,從而開發出對每個人來說都更健壯的軟件。



    回頁首


    參考資料



    回頁首


    關于作者

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


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

    主站蜘蛛池模板: 日韩亚洲一区二区三区| 国产成人亚洲精品蜜芽影院| 亚洲精品高清在线| 大地资源二在线观看免费高清| 久久久久久av无码免费看大片| 亚洲精品蜜夜内射| 亚洲国产亚洲片在线观看播放 | 在线观看亚洲专区| 亚洲人成电影青青在线播放| 亚洲国产另类久久久精品小说| 免费jjzz在线播放国产| 成人性生交大片免费看午夜a| 狼群影院在线观看免费观看直播| 免费国产叼嘿视频大全网站| 久久久精品视频免费观看| 四虎国产精品永免费| 国产亚洲人成在线影院| 亚洲AV日韩AV无码污污网站| 中文日韩亚洲欧美制服| 亚洲人成网国产最新在线| 亚洲精品国产手机| 久久精品国产亚洲AV香蕉| 久久国产亚洲观看| 亚洲Av熟妇高潮30p| 日韩精品一区二区亚洲AV观看| 亚洲成人在线电影| 久久av无码专区亚洲av桃花岛 | 99久久久国产精品免费蜜臀| a毛看片免费观看视频| 日本免费A级毛一片| a毛片全部播放免费视频完整18| 成人久久免费网站| 久章草在线精品视频免费观看| 免费无遮挡无码永久视频| 99免费观看视频| 国产香蕉免费精品视频| 免费国产黄线在线观看| 日韩免费视频观看| 亚洲精品无码av天堂| 亚洲无人区一区二区三区| 亚洲av无码国产精品色午夜字幕|