treenode

          在路上。

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            5 Posts :: 1 Stories :: 53 Comments :: 0 Trackbacks

          2006年7月6日 #


          軟件業總是充滿了形形色色的隱喻。比如說,把程序中的問題稱為bug;把互聯網上傳播的病毒叫做蠕蟲;
          把軟件開發的過程比作造房子......這些都是我們這個行業中流行的隱喻,以至于它們已經成為軟件開
          發者文化中一個特有的組成部分。

          在這里,我想要說的是一個特別具有“中國特色”的隱喻:我稱之為武俠隱喻。

          毋庸我多做解釋,可能很多程序員看到這個詞就足以勾起豐富的想象。我們中的很多人喜歡把自己所崇敬
          和佩服的、軟件界有影響力的人稱之為大俠,并幻想自己有朝一日能夠達到他們的境界。(跑題一下,
          這個稱謂現在似乎有了一個比較草根的、或者說比較Web2.0的版本——叫做牛人)上個世紀那個個人
          英雄主義的年代,曾經涌現出一大批這樣的人物,現在很多人仍然習慣稱他們為“大俠”——這其
          中包括求伯君、王志東、鮑岳橋、朱崇君...

          除此之外,我們還喜歡將重量級的出版物稱之為武林秘籍;把軟件開發的組織團體比作江湖幫派;
          要形容軟件開發的理想境界,也常會搬出“飛花摘葉俱可傷人”或“無劍勝有劍”這樣的句子。所有這些
          都或多或少的表明:武俠深深影響了大量的程序員,他們非常喜歡用武俠中的理念來比喻軟件開發過程中
          的現象。或許,也是因為程序員0和1的生活太過枯燥,需要文化來加一點味道,而他們自覺不自覺的
          選擇了武俠。這就是所謂的中國特色吧。

          我必須老實的承認:我自己就曾經深受武俠的影響,過去也一直沒有感到有什么不妥。但是,
          在前幾天看過網上的某些回帖中一些充滿武俠隱喻味道的文字,突然覺得有些不是滋味。
          我開始思考:對于軟件開發來說,武俠是不是一個好的隱喻?結論:不是不好,而是非常的
          糟。武俠和軟件開發根本沒有什么共同點,甚至可以說是水火不容的。

          為什么說武俠和軟件開發沒有共同點?武俠講的是破壞的藝術。太史公說“俠以武犯禁”。
          武俠的意義,在最好的情況下,也僅僅是殺富濟貧、除暴安良,是對舊有秩序的破壞。
          問題在于:破壞是痛快愜意的,但破而不立就是純粹的破壞,沒有任何積極意義。
          破壞以后新的秩序如何建立呢?沒有哪一個武俠故事為此做出答案,
          也沒有一個俠客操心這種事。他們在乎的是“十步殺一人,千里不留形”的高手形象,
          至于走了以后爛攤子誰來收拾?那本大俠可就管不著了。

          軟件開發是建設,而不是
          破壞。即使舊的系統非常糟糕,我們也沒有理由將其付之一炬——這就是為什么現代的敏捷
          開發者非常強調重構的原因。構造新的代碼固然是極具創造快感的工作,但是軟件開發過
          程中還有成打的“骯臟”工作:需求分析,設計,文檔,調試,維護......這些工作繁冗
          而瑣碎,但卻是整個開發過程中必不可少的組成部分。想瀟灑一下就拍拍屁股走人的
          程序員沒有什么職業素質可言。

          武俠中的高手是什么形象?天馬行空,獨往獨來,神出鬼沒。這樣的人看起來很有性格,
          但在現代企業中恰恰是最忌諱的。而正正經經提倡Team Work的團隊反倒在武俠中常常成為
          譏刺的對象——你不妨看看少林或全真這樣的大型團隊在金庸小說中被丑化成了什么地步。

          武俠所描繪的是農業社會的典型情況。一位高手通常只會把自己的技藝傳授給至親和少數幾個
          信得過的弟子;弟子亦然。這種結構非常脆弱:一旦出現任何問題,這門技藝很容易就失傳了。

          武俠中的秘籍是這樣一種東西:你得到它以后,最好藏之名山,偷偷修煉。一旦泄漏,只會給你
          帶來殺身之禍。和師徒授受的問題相同,這樣只會讓最好的技藝在歷史長河中漸漸湮滅。現代社會和開放
          源代碼運動則顯示了相反的情況:知識可以由任何人獲取與學習,而不分門派貴賤。與別人分享
          知識也不會給你帶來任何壞處。

          武俠成為隱喻帶來的惡果就是,程序員以成為“高手”為榮,以炫耀技巧為樂;無視風險
          大量采用一些看上去比較炫的新技術;憤世嫉俗以為天下只有自己懷才未遇;不會與人
          溝通,罔顧客戶需求,把不懂技術的用戶當白癡;不會開誠布公,總是自己偷偷留一手;
          凡此種種,不能說都是因為武俠流毒。但是在程序員中造成了不好的風氣,武俠的影響
          是不可忽視的。

          武俠是成年人的童話,但軟件開發不是童話。軟件開發要的是腳踏實地,而不是快意恩仇。
          還在做俠客夢的程序員,愿你們早點醒來。

          ?

          posted @ 2006-12-01 15:33 TreeNode 閱讀(1199) | 評論 (8)編輯 收藏

          可能是為了保持平臺獨立性,SWT沒有開放許多控件的自定義接口。例如,Win32中的Button、Label、List和ComboBox都是可以自繪(Owner Draw)的,但是SWT并沒有把這些繪制方法開放出來。在最新的3.2版本中添加的一個新特性是Table和Tree現在支持Custom Draw了(但是并未整合到Viewer體系中),不過對于上述控件的支持仍付闕如。

          上一次,我實現了一個自繪的按鈕。現在,看到有人詢問是否可以在Combo的列表中加入圖像。其實這相當容易,只要重載Combo Widget并把自繪接口暴露出來即可。以下是簡單的代碼示例:

          package?org.eclipse.swt.widgets;

          import?java.io.*;

          import?org.eclipse.swt.SWT;
          import?org.eclipse.swt.graphics.*;
          import?org.eclipse.swt.internal.win32.*;

          public?class?CustomCombo?extends?Combo
          {
          ????
          public?CustomCombo(?Composite?parent,?int?style?)
          ????{
          ????????
          super(?parent,?style?);

          ????????
          try
          ????????{
          ????????????InputStream?is?
          =?getClass().getResourceAsStream(?"bullet.gif"?);
          ????????????image?
          =?new?Image(?getDisplay(),?is?);
          ????????????is.close();
          ????????}
          ????????
          catch?(?IOException?e?)
          ????????{
          ????????????e.printStackTrace();
          ????????}
          ????????
          final?int?CB_SETITEMHEIGHT?=?0x0153;

          ????????OS.SendMessage(?handle,?CB_SETITEMHEIGHT,?
          0,?24?);
          ????????OS.SendMessage(?handle,?CB_SETITEMHEIGHT,?
          -1,?24?);
          ????}

          ????@Override
          ????
          int?widgetStyle()
          ????{
          ????????
          final?int?CBS_OWNERDRAWFIXED?=?0x0010;
          ????????
          final?int?CBS_HASSTRINGS?=?0x0200;
          ????????
          //?final?int?CBS_OWNERDRAWVARIABLE?=?0x0020;
          ????????return?super.widgetStyle()?|?CBS_OWNERDRAWFIXED?|?CBS_HASSTRINGS;
          ????}

          ????@Override
          ????
          protected?void?checkSubclass()
          ????{
          ????}

          ????@Override
          ????
          public?void?dispose()
          ????{
          ????????image.dispose();
          ????????
          super.dispose();
          ????}

          ????
          /*?@Override
          ????LRESULT?wmMeasureChild(?int?wParam,?int?lParam?)
          ????{
          ????????MEASUREITEMSTRUCT?mis?=?new?MEASUREITEMSTRUCT();
          ????????OS.MoveMemory(?mis,?lParam,?MEASUREITEMSTRUCT.sizeof?);
          ????????mis.itemHeight?=?40;
          ????????OS.MoveMemory(?lParam,?mis,?MEASUREITEMSTRUCT.sizeof?);
          ????????return?null;?//?super.wmMeasureChild(?wParam,?lParam?);
          ????}?
          */

          ????@Override
          ????LRESULT?wmDrawChild(?
          int?wParam,?int?lParam?)
          ????{
          ????????DRAWITEMSTRUCT?dis?
          =?new?DRAWITEMSTRUCT();
          ????????OS.MoveMemory(?dis,?lParam,?DRAWITEMSTRUCT.sizeof?);

          ????????GC?gc?
          =?new?GC(?new?DCWrapper(?dis.hDC?)?);
          ????????Rectangle?rc?
          =?new?Rectangle(?dis.left,?dis.top,?dis.right?-?dis.left,
          ????????????????dis.bottom?
          -?dis.top?);
          ????????Display?display?
          =?getDisplay();
          ????????
          if?(?(dis.itemState?&?OS.ODS_SELECTED)?!=?0?)
          ????????{
          ????????????gc
          ????????????????????.setBackground(?display
          ????????????????????????????.getSystemColor(?SWT.COLOR_LIST_SELECTION?)?);
          ????????????gc.setForeground(?display
          ????????????????????.getSystemColor(?SWT.COLOR_LIST_SELECTION_TEXT?)?);
          ????????????gc.fillRectangle(?rc?);
          ????????}
          ????????
          else
          ????????{
          ????????????gc.setBackground(?display
          ????????????????????.getSystemColor(?SWT.COLOR_LIST_BACKGROUND?)?);
          ????????????gc.setForeground(?display
          ????????????????????.getSystemColor(?SWT.COLOR_LIST_FOREGROUND?)?);
          ????????????gc.fillRectangle(?rc?);
          ????????}
          ????????String?text?
          =?getItem(?dis.itemID?);
          ????????gc.drawImage(?image,?dis.left?
          +?1,?dis.top?+?1?);
          ????????gc.drawText(?text,?dis.left?
          +?20,?dis.top?);

          ????????gc.dispose();

          ????????
          return?null;
          ????}

          ????
          private?static?class?DCWrapper?implements?Drawable
          ????{
          ????????
          private?int????hdc;

          ????????DCWrapper(?
          int?hdc?)
          ????????{
          ????????????
          this.hdc?=?hdc;
          ????????}

          ????????
          public?int?internal_new_GC(?GCData?data?)
          ????????{
          ????????????
          return?hdc;
          ????????}

          ????????
          public?void?internal_dispose_GC(?int?handle,?GCData?data?)
          ????????{
          ????????}
          ????}

          ????
          private?Image????image;
          }


          值得說明的是,如果設置Combo為OwnerDraw Variable風格,則必須重載wmMeasureChild方法來指定每一項的高度。如果使用OwnerDraw Fixed風格,則只需要在構造的時候發送一條CB_SETITEMHEIGHT消息就行了。

          ?另外一種值得考慮的選擇是將Win32的ComboBoxEx控件包裝成SWT Widget。不過,這需要轉換若干結構并提供接口,Win32的ImageList管理機制和SWT的Image包裝方法差別比較大,使得這種方法實現起來麻煩的多。

          posted @ 2006-07-06 10:08 TreeNode 閱讀(2348) | 評論 (4)編輯 收藏

          主站蜘蛛池模板: 新泰市| 唐海县| 万源市| 博客| 射洪县| 正蓝旗| 桐乡市| 阳信县| 安远县| 潍坊市| 本溪市| 互助| 青川县| 灵璧县| 彩票| 绥江县| 宿迁市| 阳曲县| 湛江市| 靖宇县| 海丰县| 大庆市| 凤山县| 任丘市| 平湖市| 三江| 繁峙县| 桐柏县| 遂溪县| 资阳市| 绿春县| 尉犁县| SHOW| 嵊泗县| 泰和县| 蓬莱市| 农安县| 保德县| 镇康县| 南宁市| 穆棱市|