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 阅读(1182) | 评论 (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, 
024 );
        OS.SendMessage( handle, CB_SETITEMHEIGHT, 
-124 );
    }

    @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 阅读(2334) | 评论 (4)编辑 收藏