2008年7月8日星期二

windows绘图概述

这两天在开发的时候遇到好多绘图的问题,发现自己在绘图这块实在又是门外汉一个。于是翻出MSDN仔细研究了一下,搞懂了很多概念。我觉得这对于windows编程来说是非常重要的概念,因此仔细的把MSDN上相关的信息全部读了一遍,同时做了翻译和笔记。我贴在下面,希望对跟我一样的朋友有所帮助。
另有PDF版本可以从我的namipan下载->WindowsPaintingAndDrawing.pdf

Windows 绘图详解


几乎所有的windows程序都会在屏幕上绘图,但是由于多任务和多窗口,为了使绘制图形平滑,漂亮,应用程序使用windows作为其主要输出设备,而不是屏幕。

系统提供了与窗口一致的Device context。应用程序就使用DC把输出定向到目标窗口。


什么时候在窗口中绘图?

一个应用程序在很多时候都会在窗口中绘图。比如,第一次创建窗口的时候,当改变了窗口大小的时候,当把一个窗口从别的窗口后面拉出来的时候,当最大最小化窗口的时候,当打开文件显示内容的时候,当滚动,改变或者选择了一部分数据进行显示的时候等等。


系统会管理类似移动窗口和改变大小的操作,如果一个操作影响了窗口的内容(如果屏幕上只有一个窗口,把这个窗口在屏幕范围内不断拖动,不会引发重绘),系统会把这部分被影响了的部分标记出来,以备后面绘图时使用,然后,发送WM_PAINT消息给窗口函数。这个消息告诉了应用程序哪些地方必须被重绘,使得应用程序能够实现有效的重绘。


同样的,应用程序也可以标记需要重绘的区域,一旦标记,也会导致发送WM_PAINT消息。如果一个操作需要立刻得到回应,应用程序可以在操作的同时进行绘图,这样就不必等到下一次WM_PAINT事实上WM_PAINT产生的条件就是有部分窗口失效了。如果不出现这种情况,就不会产生WM_PAINT


在任何情况下,只要窗口创建了,应用程序就可以在里面绘图。为了能够绘图,应用程序首先应该获得一个设备描述表的句柄。在理想情况下,应用程序的大多数绘图在WM_PAINT中完成。在处理该消息的时候,通过调用BeginPaint就能获得DC的句柄。如果应用程序在其他时候进行绘图,可以通过GetDC或者GetDCEx来得到DC的句柄。


WM_PAINT 消息

当窗口的Client Area发生改变的时候,系统给应用程序发送WM_PAINT消息。系统仅在消息队列中没有其他消息的时候发送该消息给应用程序。一般的用法是在WM_PAINT中调用BeginPaint获得DC,然后进行任何GDI绘图,最后通过EndPaint释放DC


beginPaint返回之前,系统为指定的窗口准备DC。它会为DC设置裁剪区域,这块区域就是需要重绘的区域。任何在此区域之外的绘制都会被裁减掉。


beginPaint结束之前,系统还会发送WM_NCPAINTWM_ERASEBKGND两个消息给应用程序。这些消息告诉应用程序绘制Non-Client Area和窗口背景。Nonclient Area也是window的一部分,其包括title barsystem menuscrollbar。大多数应用程序依赖DefWindowProc来绘制这些区域,因此一般会把WM_NCPAINT发送给DefWindowProcWindow的背景是用颜色或者笔刷在任何绘制操作之前填充出来的。背景会盖住任何之前存在的图片或者窗口后面的屏幕。如果一个windowwindow class定义了背景笔刷,DefWindowProc用这个笔刷自动绘制背景。


BeginPaint会填充一个PAINTSTRUCT结构。该结构中包含需要绘制的区域的大小等信息。应用程序可以利用这个信息,(存放在rcpaint中)来确定需要绘制的地方。如果需要输出的内容很简单,也可以不管这个信息,直接输出,让window自己来裁剪。


BeginPaint会把需要更新的区域设为NULL,以防连续导致发送WM_PAINT消息。即没有需要更新的区域就不会发送该消息。如果一个应用程序在WM_PAINT中没有调用BeginPaint或者清除更新区域,则系统会不断发送WM_PAINT,直到更新区域为空为止。在任何情况下,应用程序都必须在离开WM_PAINT之前清空更新区域。


绘制结束,应该调用EndPaintEndPaint释放DC,使得其他window可以使用。如果之前caretBeginPaint隐藏,EndPaint会显示出来。


更新区域(The Update Region

更新区域是window的一部分,这一部分已经过期或者无效了,需要重绘。系统依靠更新区域向应用程序发送WM_PAINT消息。系统只会把无效的区域加到更新区域中去。


当系统发现有一部分需要重绘的时候,它把这部分加入到更新区域中,但不会立刻要求重绘。只有等到系统把消息队列中的消息处理完之后,系统才会检查更新区域,如果更新区域不是空的,则发送WM_PAINT消息。


应用程序可以自己设置更新区域。比如读取一个文件,然后设置更新区域,这样在之后的WM_PAINT中就可以显示文件内容了。但一般来说,应用程序不应该在数据改变的时候绘制,而应该把所有的绘制工作放到WM_PAINT中去。


更新区域的有效化和无效化( Invalidating and Validating Update Region)

应用程序可以通过调用InvalidateRectInvalidateRgn来无效化一块区域,并设置更新区域。这两个函数把指定的矩形和区域加入到更新区域中。与之前加入进去的区域结合起来。


这两个函数不会导致WM_PAINT消息。Window在处理其他消息的时候,系统不断积累无效区域,直到消息队列中不再有任何消息。


ValidateRectValidateRgn两个函数的作用则相反,用来有效化一块区域,并把这块区域从Update Region中去掉。


获得更新区域

使用GetUpdateRectGetUpdateRgn两个函数来获得当前的更新区域。前者获得最小的能全部包含更新区域的矩形,后者返回更新区域。这两个函数用来获得当前的更新区域来精确定位输出。


BeginPaint也会获得包含全部更新区域的最小矩形。该矩形就在PAINTSTRUCT中的rcPaint。因为BeginPaint是更新区域全部有效话,因此在这之后调用GetUpdateRectGetUpdateRgn返回的都是空区域。


同步和异步绘图

大多数利用WM_PAINT来实现的绘图都是异步的。即在window的部分失效之后有一个短暂的等待,才能进行绘图。在这个短暂的等待中,system从消息队列中获取其他消息,并进行处理。因为system认为WM_PAINT是个低优先级的消息。


但有时需要同步绘图,也就是在窗口的部分失效之后立刻就绘图。比如在创建主窗口之后立刻把它绘制出来等等。基本上来说,那些需要立刻绘图的都是需要和用户交互的部分,同步绘图可以保证不影响交互的性能。


UpdateWindowRedrawWindow两个用来同步绘图。如果更新区域非空,UpdateWindow能够立刻发送一个WM_PAINT消息给应用程序。RedrawWindow同样发送WM_PAINT消息给window,但是它给绘制更多的自由,比如是否要绘制nonclient区域、背景,以及是否不管更新区域非空也能发送WM_PAINT消息等等。这两个函数无论消息队列中有多少其他消息,他们都能直接发送WM_PAINTwindow


任何会消耗一定时间的绘图都应该使用异步绘图,免得程序被block住。一个程序如果经常是一小部分window无效化,最好把这些部分合起来,在一次WM_PAINT中进行处理。


不通过WM_PAINT来绘图

尽管大多数时候应用程序在WM_PAINT处理绘图,但是有时候不通过WM_PAINT而直接进行绘图可能效率更高。这一般都是用于需要立刻得到反馈的情况下,比如用户选择了一部文字,拖曳或放大缩小一个对象时。这些情况下,应用程序通常在键盘和鼠标操作中进行绘图。


不在WM_PAINT中绘图时,应用程序通过GetDCGetDCEx两个函数获得窗口的设备描述表(记住,不是client区域,而是整个窗口)。结束绘制使用ReleaseDC释放DC


当不使用WM_PAINT的时候,应用程序使用一种技巧来进行“可恢复”的绘制。比如在反选一些文字的时候,仅仅只要对那一块区域反色即可,当取消反选的时候,只要再次反色即可。


Window区域

除了更新区域,每一个window都有一个可视区域,即用户能看到的所有区域。当window的大小改变时,或者被其他Windows挡住时,或重新显示时,都要绘制这部分区域。用户没法直接改变这个区域,但是系统自动使用这个区域来表示该windowDC中的裁剪区域



裁剪区域决定了系统的那些部分允许绘图,当应用程序通过BeginPaintGetDCGetDCEx获得DC之后,系统为这些DC都设置了裁剪区域。应用程序可以通过SetWindowRgn, SelectClipPath and SelectClipRgn等函数来设置裁剪区域。


WS_CLIPCHILDRENWS_CLIPSIBLINGS这两个样式告诉系统怎么来计算window的可视区域。如果一个窗口有其中一个样式,窗口就会把子窗口或者兄弟窗口(具有相同Parent的窗口)的可视区域排除在外。


Window背景

Window背景是在进行绘图之前对client区域填充的颜色或者笔刷。背景覆盖了屏幕上窗口区域中的任何东西,擦除了以前的图像,防止之后的绘图颜色混合。


系统可以自己绘制背景,也可以在调用BeginPaint的时候给应用程序发送一个WM_ERASEBKGND消息把绘制的机会让给应用程序。如果由DefWindowProc来处理,则系统使用创建窗口时指定的笔刷进行背景绘制。如果笔刷无效或者window class没有定义背景笔刷,则设置PAINTSTRUCT结构中的fErase为非空,告诉应用程序,由应用程序来负责背景绘制。


如果应用程序处理WM_ERASEBKGND,则需要使用WPARAM来进行绘图。WPARAM包含一个窗口的DC句柄(是的,已经帮你获得了)。在绘制完毕之后,应用程序需要返回一个非空的值。这样BeginPaint就不会把fErase设置为非空值了。(从这里可以看出,WM_ERASEBKGND是通过SendMessage发送的,所以在这个函数中处理要快!)即使window class的背景笔刷已经被定义好了,应用程序还是能够处理WM_ERASEBKGND消息的。



改变window大小

当用户用鼠标拖拉window边框时,通过系统菜单选择最大最小化时或者使用SetWindowPos函数时,系统就会改变window大小。当window改变大小时,系统假设之前显示在外的内容没有被影响到,不需要重绘,系统仅仅使新暴露出来的那部分窗口失效,这样可以在处理WM_PAINT时节省时间。在这种情况下,即使window的大小减小,系统也不产生WM_PAINT

但是有些窗口需要不时的重绘,比如一个钟表应用程序,每次大小改变,都需要重绘。当横向,纵向的任意部分或者两者都发生改变时,为了强制应用程序重绘整个client区域,应用程序必须设置CS_VREDRAWCS_HREDRAW这两个样式。有了这两个样式,任何改变大小的操作都会引起重绘。



Nonclient区域

当任何一部分Nonclient区域,比如title barmenubarwindow frame需要重绘时,系统会给应用程序发送一个WM_NCPAINT息。系统也可以发送其他消息来更新一部分Nonclient区域。例如,当一个窗口被激活或者非激活时,系统发送WM_NCACTIVATE来更新Title Bar。一般来说,对普通window最好不要处理这些消息(带NC的),因为应用程序必须处理所有要求处理的Nonclient区域。

但是如果一个应用程序想要自定义Nonclient区域,则必须处理这些消息。应用程式必须使用窗口的DC来进行绘制。应用程序可以通过GetWindowDCGetDCEx来获得窗口DC。当绘制结束,必须使用ReleaseDC来释放DC

系统也会为Non-clinet区域维护一个更新区域。当一个应用程序收到WM_NCPAINT消息的时候,wParam指向一个包含一个指定了更新区域的Rgn handle。应用程序可以使用这个句柄使更新区域和DC的裁剪区域组合起来。当获得DC是,window不会自动组合更新区域,除非使用GetDCEx并且同时指定这个更新区域的handleDCX_INTERSECTRGN标志。如果应用程序不组合更新区域,则只有超出window以外的绘制操作会被裁减掉。无论是否使用该更新区域,应用程序不需要负责清空更新区域。

如果应用程序要处理WM_NCACTIVATE消息,在处理完毕之后需要返回TRUE来告诉系统完成被激活窗口的更新工作。当应用程式收到WM_NCACTIVATE时如果是最小化情况下,应用程序应该把该消息转发给DefWindowProc,在这种情况下,这个默认的函数会重绘Taskbar上面的这个icon

子窗口更新区域

子窗口是具有WS_CHILD或者WS_CHILDWINDOW样式的窗口。和一般窗口一样,子窗口通过WM_PAINT来绘图。子窗口也维护一个更新区域,应用程序和系统都可以通过设置该更新区域来产生WM_PAINT消息。

子窗口的更新和显示区域受到父窗口的影响,其他样式的窗口则不会。系统常常设置父窗口的更新区域的同时设置子窗口的更新区域,使父窗口收到WM_PAINT消息的同时子窗口也能收到WM_PAINT消息。系统把子窗口的位置限制在父窗口的client区域,超出这个区域就会被裁减掉。

无论何时,只要父窗口的更新区域包含了子窗口的一部分,系统就会为子窗口设置更新区域。此时,系统先向父窗口发送WM_PAINT消息,然后向子窗口发送消息让子窗口可以恢复被父窗口覆盖的内容。

但是如果只有子窗口设置了更新区域,系统不会给父窗口也设置。在无效化子窗口时,系统不会给父窗口发WM_PAINT(因为被覆盖住了,根本没有必要)。同样的,如果使被子窗口覆盖住的父窗口的部分无效化,系统也不会给父窗口发送WM_PAINT的。在这种情况下,无论子窗口还是父窗口都不会收到WM_PAINT消息。

应用程序如果设置了WS_CLIPCHILDREN这个样式的话,当父窗口的更新区域被设置的时候,子窗口的更新区域不会被设置。任何在子窗口下面的绘图全部被裁减掉,因此继续给子窗口发送WM_PAINT消息也是没有必要的了。

子窗口的更新和可视区域也受到兄弟窗口的影响。如果两个窗口重叠,则两个窗口都会收到WM_PAINT消息。他们受到WM_PAINT消息的顺序与z-index相反,即最上面的(z-order最高)的收到WM_PAINT消息最晚。

应用程序可以设置WS_CLIPSIBLING来避免兄弟窗口的绘制重叠。设置了这个,高z-order的窗口部分就被下面的窗口裁减掉了。

2008年7月3日星期四

fill_n与generate_n的区别

有些人对未知事物的第一印象一般比之后的印象记得牢,即使是错误的想法,也会根生地固的记得很牢。而有些人却善于用之后正确的印象来代替之前的印象。我很羡慕这种人,因为我自己是第一种人。

我对fill_n这个函数的印象就属于自以为是的错误印象,然而,这个印象被之后的正确印象所替换之后,我还不时的用错这个函数。就像程序员们老生常谈的空指针问题(现在少的多了,铺天盖地的高级语言,很少遇到这种问题了)。

我第一次看到这个函数,我就立马意识到这是初始化容器的好方法。比如

list<int> l1;
fill_n(back_inserter(l1), 200, 1000);

仅仅一行代码,就可以初始化200个元素,每个赋值为1000.多么方便啊。不过这种简单的类型我是没兴趣的。最重要的是可以初始化类,这就是我对其错误认识的开始。为了测试这个程序,我曾写下了如下代码:


//
// test.h

class TObj{
public:
~TObj(){cout<<"Deleting"<<endl;}
};
struct Dest_TObj{
template<class T> T* operator()(T* p){ delete p; return 0; }
};
int main(){
list<TObj*> tl;
fill_n(back_inserter(tl), 20, new TObj());
transform(tl.begin(),tl.end(),tl.begin(), Dest_TObj());
return 0;
}


在main函数中,第二行为tl初始化,20个元素,每个元素是一个指向TObj对象的指针,该指针指向一个新分配的TObj对象。然后在transform中对tl进行purge。如果不用这两个函数,我们只能用循环的方法:

for( int i = 0; i < 20; ++i) tl.push_back(new TObj());
for( list<TObj*>::iterator iter = tl.begin();
iter!= tl.end();++iter)
{
delete (*iter);
}

尽管看起来也行,但是总觉得比较原始,不是吗?

结果,当我满怀信心的运行程序,运行到transform时就崩溃了。我左看右看没发现问题。看看输出,有一个Deleting。那说明至少成功了一次,难道后面指针指错了?我把transform换成了上面的循环,结果也是运行了一次就崩溃了。看来问题在初始化的地方。
我把fill_n替换成上面的循环。程序欢快的跑完了。Shit,还有这事!

看来是fill_n有问题,我只能再回去仔细看fill_n的原型:
template<class>void fill_n(Out res, Size n, const T& val);
我终于注意到了最后一个参数,这是一个值参,fill_n只不过把每一个元素都用这个值进行赋值而已!因此,我希望初始化的20个TObj对象,实际上只有一个,所有的指针都指向这个对象。当第一个被delete之后,后面的就成了野指针。企图删除一块已经被释放了的内存块,当然结果是崩溃了。

如果要实现我需要的想法,只能使用generate_n。该函数和fill_n类似,只不过把最后一个参数换成了一个函数,调用该函数n次。
比如我有一个Create_TObj()的函数,返回一个新创建的TObj对象的话,我就可以把上面的代码改成:
generate_n(back_inserter(tl),20,Create_TObj());
这样程序就能顺利执行了。

不幸的是,这个错误我是屡犯不改,终于不得已写下此文,希望能长点记性。

2008年5月19日星期一

论文初稿完成

经过几天的努力,今天,国难日的第一天,我终于把论文的初稿给完成了。总共将近40,000多个字,其中90%的内容都是原创。除去之前的准备工作和编程序的时间,我真正开始动笔是在上个礼拜三,而今天当我写完的时候,我自己都感到惊讶,没想到能在这么短的时间内完成这篇论文。

可能是这几天救灾的军人们那种拼搏的精神不知不觉也有点影响了我,让我能够耐着性子把论文写完。这句话可能看起来有点虚,但是事实上我这几天,几乎没有上过网,除了每天看救灾的新闻,别的时候电视连碰都不碰一下,msn也基本不上,更别说以前一直盯着看的小说了(不过这下估计又积攒了好几十回了,可以看个够了)。

回想起来,我真的已经好久没有这么认真的做过一件事情了,最近的一次应该是两年多前刚进Thales的时候,很认真的钻研DCP的代码,还做了笔记,不过后来做着做着,人开始疲掉了,在之后的日子里更是不再有当时的激情了。

总之,找回那种感觉是好事。不过现在论文写完了,是该稍微休息一下了。接下去还有一篇小论文要写,还要去发表,大论文虽然给了老师,但是恐怕还要有很多的修改。在答辩完成之前还是不能松口气啊!

2008年5月9日星期五

淳朴的老农

这张照片是我去大盘山徒步时候拍的。当时这位老伯很热情的招待了我们。他的笑容让我想起了我已过世的爷爷,感觉很亲切。
淳朴的老农

2008年4月29日星期二

Be a Flickr Pro!

前不久一个朋友脑子一热,买了个域名。看来这种事情容易传染啊,我今天也是脑子一热,买了一年的Flickr付费服务。价格为$24.95,我个人觉得还行。

从价格上说,RMB在升值,现在已经在1:7上面徘徊了。所以这个价格折合RMB也就180RMB一年,一天5毛钱不到,这个价格相比Flickr的服务,绝对算是超值了。国内抄袭Flickr的Bababian一年也要120,还不提供无限空间,功能远比Flickr差多了。

另外我最近在不断整理照片,发现照片越来越多。另外买了单反不用就是浪费,所以我打算多拍一点,同时提高我的技术水平。pchome有位大侠告诉我,照片一定要拿出去晒,让别人拍砖才能知道自己的不足。相比单反的投资,Flickr上的投资可以算是毛毛雨了。

好了,我要开始上传照片了,大家以后多来拍拍砖:)

http://www.flickr.com/photos/ling_hao

2008年4月25日星期五

Ubuntu 8.04 LTS Release

凌晨3点,我还在公司里面加班。我刚刚完成了Release,随手就打开浏览器输入www.ubuntu.com, 因为我知道,今天是Ubuntu 8.04 LTS 正式Release的日子。一看果然Ubuntu的首页不同了,大幅的广告显得喜气洋洋。

Ubuntu 8.04 新增加了许多非常酷,非常实用的功能,Ubuntu桌面环境已经非常实用,这次对硬件支持也更加完善,而且新加入的PulseAudio也提升了其多媒体性能。Ubuntu 8.04集成了现在市面上最新的软件包,比如:Firefox 3,Compiz Fusion 0.7.4,GNOME 2.22,甚至还可以依靠Likewise与windows 的活动目录无缝链接(可以使用Windows域的打印机,可以通过域用户访问域资源)。最后,还有几近完美的升级程序,可以完美的从7.10升级到8.04。由于使用了新的引擎,Nautilus 性能提升堪称恐怖。

还在等什么呢?快去下载吧!
http://www.ubuntu.com

2008年4月15日星期二

宁被偷,不被拣

同事最近运气不好,上个礼拜四早上打的时候钱包掉了。他到公司回想起可能掉在了车子上,于是乎他到公司之后打电话给大众,期望有哪位好心得司机能拣到。可惜,等了好几天也没有任何回音。我当时还安慰他,说如果给谁拣到了,估计钱是找不回来了,但是钱包里面的身份证,银行卡等大概会还给你吧。因为曾经听到好几次说小偷偷了钱包,秉承盗也有道的精神,把身份证之类的东西放回钱包,告诉失主去某某地点去拿的事情。这样至少给失主造成的麻烦会小些。可惜,看来同事这次运气不好,没有给小偷把钱包摸了去。同事感叹道:“宁被偷,不被拣啊”。

2008年4月13日星期日

WikiMedia 2007年最受欢迎照片展

这篇绝对不是新闻,但对于我这个不通时事的人来说也算新闻了。而且照片么,什么时候看都可以的。
其中有几张特别好,人家说好照片能反映出摄影师的心灵。我在这些照片中看到了。这里推荐两张我觉得特别好的。

首先是这张,我第一样看到就特别特别喜欢。这只胖胖的小红松鼠实在太可爱了。我已经把它作为我的桌面了。至少要看个一百天,一百天啊一百天!



第二张。这张给我第一样就是一种恬静。一开始我的注意力被牛吸引,但是很快得,透过牛的眼睛,好像看到了后面的山谷,越看越远。心里也变得越来越安静,仿佛有一种与世无争却万事尽在掌握中的感觉。




第三张。仔细感受一下这张照片,犹如身处浩瀚的宇宙之中,又如身处万卷藏书的古老的图书馆中。一种沉甸甸的感觉给人一种对未知的隐隐的渴望。


其他的照片同样出色,像看原文的点下面链接:
http://commons.wikimedia.org/wiki/Commons:Picture_of_the_Year/2007

2008年4月10日星期四

装着Ubuntu Linux的“龙芯”UMPC

今天在DesktopLinux逛的时候,发现了一则消息让我很振奋。中国的龙芯卖到了国外,还被用在了运行Ubuntu的UMPC上。也许很早以前龙芯就已经出口了,但是我不知道,也可能不相信。但是现在却明明白白出现在我眼前,不由得我不信。

这是荷兰一家公司生产的ultra-mini PC(UMPC),命名为Jisus。使用1GHz 的Loongson 2F CPU。这颗由中科院设计的龙芯目标就是运行Linux,MIPS64位架构。不过Jisus估计是冲着Asus的900MHz的 Eee PC 4G去的。Jisus的参数如下:

  • Processor — 1GHz 64-Bit Loongson 2F
  • Memory — 512MB DDR2-667
  • Flash — 4GB Nand flash
  • Display — 8.9-inch LCD (800 x 480 pixels) with LED backlighting; Silicon Motions SM712 graphics; VGA port
  • Networking — 1 x 10/100 Ethernet (Realtek 8139 contoller); RJ45 port
  • WiFi — 1 x 802.11b/g
  • USB — 2 x USB 2.0 ports
  • Audio — 1 x mic port; 1 x two-channel earphone port; stereo speakers
  • Battery — 4.5 hours
  • Operating system — Ubuntu Linux (other Linux distros possible)

这款机器将于4月25日在欧洲开卖。价格为300EUR。感觉上是不是很贵。但是实用性如何就不是我能知道的了。但是最求新潮的人肯定会去买,而且它有多种颜色可以选择。对于我个人来说,我不太喜欢小的笔记本。因为我手大:(

总之由市场来见证这台装着Ubuntu的龙芯UMPC吧。

原文链接:http://www.desktoplinux.com/news/NS3294112608.html

2008年3月29日星期六

用例浅谈

用例(use case)是现代软件工程中用来采集需求和软件设计的一个常用工具。那么用例到底是什么东西?什么时候用这个工具?如何使用这个工具呢?本文就结合本人在日常工作中的实践经验来做一个简单的介绍。

用例的定义有很多,几乎每一本书的作者都有自己的理解。但是用例的本质不变,系统的使用者对系统发出的一次请求,用例描述系统完成这个目标的过程的一种方法。因此我们可以用4个词来概括用例;他们是:角色,请求,步骤和目标。 有的书上说是三个要素。一个是参与者,也就是我这里的角色。一个是用例只描述单独的任务,也就是我这里的请求和步骤;最后一个是用例必须产生一个对用户有意义的结果,也就是我这里的目标。

系统的主要角色(可能是最终用户,也可能是其他系统)启动了一个交互,他有一个用户目标(user goal)。由于用户请求的上下文不同,前提条件不同,因此这个交互可能产生多个场景。一个UC会把目标相同的场景集合起来。


用例的格式

一般来说,用例可以以多种形式编写,但是大多数情况下都是用于和非专业人员交流,因此,用纯文本方式比较好。同时可以节约时间。

对于用例的格式,很多书上面都有不同的定义,但是我个人认为,用例没有特别的格式。只要意思清晰明了即可。每个人编写的用例都是不同的。UC写作有简化版本和完全格式版本,可以根据项目规模大小选用。

使用用例来发现需求

当编写一个新系统的用例时,一般先写黑盒,然后设计人员细化时变成白盒。黑盒UC的作用主要用来引发讨论,一般由PD或者RE来写,写好之后和Dev和Test以及客户进行讨论。因此UC常常被用作是头脑风暴的工具。UC本身的功能就是捕捉已知的功能性需求并为之建模,这样可以完成高质量的需求报告,相对来说比一般方法要可靠,完全的多。

但是用UC来找出需求时需要注意两点:
1. 它是真正的需求,不是行为或者过程,应该要正确的写出系统必须做的事情,而不是如何做事情。
2. 它不是所有的需求,它们不包括外部接口,数据格式、业务逻辑以及复杂的公式等。他们组成了所有需求中的一部分。不过虽然只有一部分,但是是最重要的一部分。


用例的价值

UC很流行大抵上是因为他们一致、连贵的说明了这个系统是如何使用的。在早期提出完备的UC,系统的使用者就知道该系统可以做什么了。他们可以及早的做反馈、进行调整或者拒绝该UC。不管采用何种设计方法,需求分析阶段的用例建模工作都能发挥极其重要的作用。

有一些公司是不是用用例方法的。他们使用的是Feature。首先获取用户需求,然后由PM大致写出该系统的Feature,当然要包括所有的用户需求,然后通过头脑风暴完善Feature List。最后为每个Feature添加Function List。

事实上,系统级的黑盒UC就可以看作是Feature。每一个步骤就是这个Feature下面的功能。

UC的价值最早产生于当这个用户目标(user goal)创建,并把它们放入到系统的特性列表中去时。这个列表说明了系统可以做的事情,规定了系统的范围。

这个List会由用户代表,PM,公司专家,行业专家代表等人检查。他们会用这个Feature List估算成本和系统实现复杂度,由此确定系统的起始点。这个列表可以联系到复杂性、风险管理、成本、时间和状态检查。

第2个价值体现在UC的作者用头脑风暴的方式把主成功路线上一切可能的错误列举出来的时候。这时候,他可能会发现一些令人惊讶的事情,或者是客户没有想到的事情。这些事情可能导致新的使用者,新的UC的出现。

第三,用例可以帮助我们划分软件的开发周期,评估研发工作量。对于优先级较高的用例会在早期的迭代周期中实现,优先级较低的用例则安排在后续的迭代中完成。

用例模型在整个开发过程中都扮演着非常重要的角色。它用来驱动软件的分析和设计逐步细化。

最后,软件项目中的功能性测试用例,基本上都是根据用例模型来确定的。

用例建模

用例建模是通过分析用户的功能性需求,得到用例模型的工作过程。一般包括下面几个步骤:

  1. 确定系统边界
  2. 确定参与者
  3. 找出所有用例
  4. 确定每个用例的级别
  5. 用例描述
  6. 画出以整个系统为对象的顺序图
编写用例

不要一开始就写出所有的细节,这是违反事物发展规律的,就像荒谬地要求把需求全部搞清才能做设计一样。用例的细化一般有4个阶段。
1. Actor & Goals
列出所有参与者以及他们的用户

2. Use case brief or main success scenario
选出主要的一些UC,写出触发条件和一个大致的轮廓,也就是主成功场景。保证该系统的功能真的是Stakeholder们感兴趣的。

3. Failure conditions
完成主成功场景后,用头脑风暴的方式找出所有可能的失败,首先把它们全部列出,而不是直接就讨论系统的应对之策。

4. Failure handling
写下系统是如何处理每一个错误的。这时候,常常会有一些原本不明显的问题被渐渐暴露出来或者错误处理会突然引入新的用户或者新的用户目标。

大多数项目时间紧张,人员精力有限,在项目前该确定要工作到何种细致程度,因此我强烈建议按照上面4个顺序来。

2008年3月20日星期四

到底什么是需求?

《HFOOAD》给了一个我觉得很简单,又很好的答案。单独拿出来做个笔记。
首先我借用一下里面的图片来说明问题。


那些黑色高亮的词是需求的几个特点。

specific thing
一个需求往往是一件单独的可测的事情。因为只有可测,才能保证你完成了客户的需求。

system
系统指一个完整的应用,或者是项目程序。因为客户只能看到这个。

do
系统做的事情,或者说是行为。

work correctly
一个系统是否正确是由客户说了算的。为了使最后系统能够正确运行,我们不能漏了任何一个需求,即使客户当时忘了,我们也不能忘。要从客户那里找出潜在的,忘记了的需求。才能使系统正确工作。


给出一个比较正规的定义
需求就是一个单一的要求,该要求详细规定了指定的系统或者服务的特征和行为。

论文写作正式开始

今天终于开始论文写作了!

自从我提交开题报告到现在都有4个多月了,如果按照开题报告里面的进度计划,我应该已经在收尾阶段了。可是当中遇到了很多事情,一开始准备复习高口,想在三月份把高口考出来,论文放到高口考完之后再写,可是接下来遇到母亲生病,很多计划都打乱了,最后到三月份高口也没有考,论文也没有写,这几个月几乎什么事都没有完成。真是人算不如天算啊。

现在我就开始觉得时间有些紧了,一般来说工程硕士要在4月中旬提交论文初稿,然后在5月份修改和审批,5月底答辩。但是我现在除了一个idea,还什么都没有,心里有点不安啊。

前两天每天下班回家都会考虑两三个小时,昨天晚上基本上把写论文的过程整个想了一遍。然后做了一个简单的计划,于是今天正式启动!接下去的两个月里面,基本上就是苦难的生活了,白天上班,晚上做论文。朋友老段曾说过,做事情要一鼓作气,“一而再,再而衰,三而力竭”,我很同意这句话,这次的论文不能拖,一定要一鼓作气完成。

像我们工程硕士,写的大多是工程应用论文,我也不例外。但是我不想写些什么“XX系统的实现与改进”,这个太没有技术含量了。我写的论文跟我的工作有密切关系。我的工作是AFC系统,我的论文就是AFC系统中一个关键模块--数据采集的改进。里面涉及到一些有意思的技术,比如词法分析器,处理分发器等等,因此总的来说还是有点技术含量的。

我把这个程序看作一个小项目,完全按照一个项目来安排需求分析,设计与开发,测试与部署。希望在写论文的过程中把我这两年里面学到的各种技术总结一下,运用一下。这样,我两年的研究生也就没有白读,对得起那40000块大洋了。

2008年3月19日星期三

好书推荐《HFOOAD》

为了不把标题弄得过长,我用了缩写,本书全称为《HEAD FIRST OBJECT-ORIENTED ANALYSIS & DESIGN》中文译名《深入浅出面向对象分析和设计》。



这本书是O'Reilly的Head First系列丛书中的一本。本书为什么好,我觉得有这几个方面。

一、本书对OOAD的讲解由浅入深
OOAD发展到现在也有10几个年头了,现在大多数人都在名义上采用OOAD在开发。但是有多少人真正懂OOAD呢?很少!国外少,国内更少!OOAD不是UML,OOAD 不是需求分析,OOAD不是Design Pattern。OOAD是一整套分析与设计的架构,它包含很多东西。市面上不乏好书,比如《Applying UML and Patterns An Introduction to Object-Oriented Analysis and Design and Iterative Development, 3rd Ed - Craig Larman》,或者《AGILE SOFTWARE DEVELOPMENT: PRINCIPLES, PATTERNS, AND PRACTICES》。但是在看这两本书的时候,我总是有摸不着边的感觉。看书的时候以为自己懂了,可是真正写UC或者做领域模型设计的时候又发现自己无从下手。后来我发现这是我自己水平未到。而且我喜欢的是简单的,真正能让我模仿的例子。《HFOOAD》做到了,它写的很浅,由浅入深。从一开始的分析客户需求到后面的健壮、可重用的设计,重构和设计模式,以及在设计时候遇到问题时功能和效率,成本与维护的平衡的选择,这么多OOAD的步骤和技术被作者抽丝剥茧,一步一步放在我面前。

我相信,一个希望自己变得更专业的软件从业人员都会喜欢这本书的。对我自己来说,我觉得虽然我进入这个行业有4,5个年头了,而且还有着计算机科学与技术的教育背景,但是我还是要很羞愧的说一句:我还不是专业的。

专业的人员是怎么样的?一句话,人家用正规的方式做软件,人家有方法学的支持。现阶段,主流的方法学就是OOAD。需求分析用什么?用例、场景、故事板,原型等等。怎么过渡到设计?领域模型、E-R关系模型、接口设计,类图等等。详细设计怎么做?UML主打,敏捷和迭代随行,设计模式长伴左右,测试驱动护驾。人家知道在什么时候用什么方法来解决问题。

所以要成为专业的人员,我以为有三个阶段:
第一阶段:学习理论基础,知道有哪些方法,有哪些阶段;
第二阶段:知道在什么阶段该用什么方法;
第三阶段:知道如何有效率地使用方法以及该得到什么样的结果。并且保持知识更新。
我认为《HFOOAD》这本书可以让我进入第二个阶段。而第三个阶段需要自己不断实践和摸索。

二、Head First系列独特的学习风格
我不知道这种学习风格是不是适合所有人,但是我觉得很合我胃口。
首先它不像其他的书,首先扔出一大堆定义把人砸晕,然后给出零零碎碎的例子,没有连贯性,实用性。它的教学方法是通过给出真实的场景,图片,对话等各种刺激大脑的方法来促进学习的效果。让人身临其境肯定要比单纯的文字要让人感兴趣的多,不是么?但是这需要看书的人主动参与,用自己的想像力带自己进入文中的场景,和里面的人一起动脑筋,一起动手做。面对如此好书,还用以前囫囵吞枣的方式看书,那还不如不看。

我还没有看完本书,有谁原意和我交流学习心得,欢迎来信。

补充:
2008-3-19
1.有人认为学习OOAD需要学习UP,RUP等开发过程。我觉得这个不是必须的。UP只是一个被定义了的开发过程,是个成品,大家可以直接使用。但是作为产品,就肯定有用户群。有用户群也就有非用户群。很不幸,大多数企业都有自己的一套做法,这时候生搬硬套某一种开发过程反而会起反作用。 因此我们学习OOAD就是学习OOAD的各个组成部分,既将他们独立开来,又让它们保持一定的联系,然后选择合适的应用到我们自己的企业中。慢慢的形成以OOAD为基础的自己的一套流程。

2.最近被人关注的比较多的是《Head First Design Pattern》。我自己个人认为,Design Pattern是具体技术,做软件应该由大及小,自上而下,先把握整体,再考虑细节。同时DP是需要有大量的经验支持的,掌握DP需要顿悟,我自认没有10年功底,我即使学了DP,也无法灵活应用。就像一个小孩拿着一把倚天剑,却无法发挥其作用一样。而OOAD则相反,这是基础,能早学一定要早学,打好基础。

善解人意的google

我一直使用google作为我首要的搜索引擎,是因为我一方面对google有一种盲目的好感,另外在心里面也觉得其他的搜索引擎不如google好。但是到底google好在哪里,我也说不大出,只是曾经用google和baidu,yahoo比较过,发现还是google找出来的东西又快又正确。

今天又让我见识了一下google的人性化。我在搜索Head First这个词组,因为最近一直在看Head First系列的书,对国内翻译的深入浅出有点不太理解,所以像看看它原来的解释。金山词霸上面的解释是“冒失地,头向前地”,这显然不是我要地答案。

我想到了Marriam Webster这个最详细的词典。我一般来说都会先进入Marriam Webster的网站(http://www.m-w.com/)然后查找单词。但是今天我却想试试google能不能一下子定位到Marriam Webster。

我在google里面输入"head first m-w",结果google就像我肚里的蛔虫一样,第一条记录就是Head First在Marriam Webster的解释。妙哉!搜索引擎能做到google这样“善解人意”,我还有什么好说的?

比较了国内的BAIDU,出来一大堆不知所云的结果,看也没看,直接关掉!

2008年3月17日星期一

Visual Studio 2008,我还没有准备好

昨天从MS网站下载了一个Webcast,是关于VS 2008的新特性介绍的。本来是为了写会议记要用来交作业的,所以也不打算仔细看。但是后来慢慢被吸引了,最后发现VS 2008竟然让我感到我离技术的浪尖越来越远了。

在VS 2008中,.Net Framework 已经升级到了3.5。

在VS 2008中推出了一种和编程语言整合的简单数据访问语言LINQ(Language INtegrated Query),用LINQ可以很简单的访问数据库,进行增加,删除和修改操作。它的思想和OR Mapping很相近。把Table映射成对象后,所有的操作都是对对象进行的,然后通过后台的序列化更新到数据库。

MS也终于把VSTO整合到了VS中去,这个开发Office所用的组件从通房大丫鬟变成小妾了。在VS2008中可以直接创建基于VISIO,WORD,EXCEL等的项目。

VS2008还增强了HTML/CSS编辑器,B/S项目现在已经成为主流,MS在这方面的支持实在很到位。HTML编辑器增加了和Dreamweaver一样的上下屏编辑窗口,上屏代码,下屏直接预览效果。CSS编辑器也非常强大,以前写CSS要靠开发人员的经验,手写CSS,还要进行调试也比较麻烦。在VS2008中,有一个傻瓜化的CSS编辑器,点击下鼠标一个漂亮的效果就出来了。不过在我看来,这个功能很鸡肋。假设我们在一个注重版权的公司里面。做HTML和CSS往往是UI设计师的工作。我很难想象公司会为这些人配置一套VS2008。要知道一套VS2008 Team Edition的价格可以抵得上N个UI设计师了。

WPF, WCF, WWF的完美支持。MS一直希望加强B/S系统的可操作性和表现力。但是要把瘦客户端程序做成和富客户端程序一样效果,光从HTML和CSS来说还是很困难的。于是MS就推出了WPF,一个基于XAML的图形库。不过老实说,我觉得还不如Adobe推出的基于Flex的解决方案好。WWF是基于Workflow的东东,我不懂,也没有兴趣。

VS2008的重定向功能,在VS2008中,用户可以随意的创建基于各种版本的.Net Framework的项目,其实也就是三个2.0,3.0和3.5。确定了.Net Framework的版本之后,支持的项目也会变化,乃至动态提示功能也会只对应的那个.Net Framework。我觉得MS在兼容性上做的的确很好。

不过说了这么多,这些都不是我需要的。我做的是系统编程,用的是C++,这个看起来快要落伍的东西。但是我相信C++有它自己的一片天地,我也有我的。只是发现VS离我越来越远,有些感慨罢了。

2008年3月13日星期四

妈妈已经可以起床了!

《Overload now, payoff later》中我提到了我妈开了一个大刀治疗椎管狭窄。今天是我妈手术之后第21天,按照医生的嘱咐,第14天拆线完毕之后就可以带着腰围下地了。但是我们都还有点担心,所以让我妈多躺了一个礼拜。同时她自己心里也不怎么敢下地。

今天早上我去为她付出诊费,回到家里一看她床上没人,吓了我一跳。后来发现她竟然一个人在洗手间!原来妈妈感到大便很急,而阿姨又出去买菜了,她实在没办法,只能自己起床去大便。没想到这样也让她去除了心理障碍,从今天开始她终于愿意起床做康复治疗了。

不过她说一开始起来头晕的很,恐怕是长期卧床导致的。我扶她上床的时候发现她的腿已经萎缩得不成样子了。穿着原来的棉毛裤空落落的。我妈原先的体重大概120多斤,现在估计100斤都没有了。以前听医生说长期卧床大腿会萎缩,但是毕竟没有亲眼见过,但是今天真是让我大吃一惊,仅仅3个礼拜卧床就能让大腿变得那么细。我不敢想象如果这次没有果断的做手术,导致我妈长期卧床做保守治疗会是个什么样子!

有时候,做人一定要果断。

接下来我要求阿姨帮助我妈一步一步做康复治疗,先坐起来,等头不晕之后,在下地活动。一开始时间少点,10分钟到15分钟,慢慢的增加时间。

今天真是一个值得庆贺的日子!

2008年3月12日星期三

开源和免费

今天上网的时候在PCHOME上看到一篇文章《够用就好 常用共享软件的免费替代品》。里面介绍了几个常用软件的开源或免费替代品。在我们这个不注重版权的国家里能有人提倡这个,看来人们也开始关注这方面了。事实上,在很多大公司里面都很注意这方面的问题,有些公司很严格的完全杜绝盗版,比如我一个朋友所在公司“中芯国际”。他们很早就已经强制把ultraedit,acdsee等软件请出了硬盘。一开始,人们不习惯,但是经过一段时间的适应,人们也慢慢有了版权意识,就算在家里也只用开源或者免费软件了。这方面,台湾人做的的确不错。

我自己用的大多数也是开源和免费软件。我这里也介绍一些我常用的软件。作为PCHOME那篇文章的补充。

Office软件:
SUN OPENOFFICE 2.3非常不错,完全兼容MS Office。不是我不支持国产软件,但是我一直不怎么喜欢WPS。

压缩解压缩:
7zip,绝对是7zip。其实winrar也可以不买一直用,只不过如果要浏览内容的话会出现一个提示窗口。7zip的速度完全没有问题,我解压缩一个1g的rar文件,用winrar是4分13秒,用7zip是4分16秒,效率上差不多。另外压缩比例7zip要比rar高一些。LZMA算法果然强悍!

图像浏览
IrfanView不错,界面稍微丑了点,Picasa也很不错。两个正好互补用来看单个图片和批量图片。

文本编辑
文本编辑对于我们程序员来说是很重要的。因此我有好几个编辑器,一个是基于SciTE的Notepad++,一个是vim7。一般情况下Notepad++已经可以胜任大多数情况,界面也非常友好。vim7可以提供一个很强大的编程环境,vim+ctags以后就能通过函数名找到函数声明,对读代码很有用处。vim的!%xxd命令可以用来查看二进制内容,这使得我最后一个留恋Ultraedit的理由也没有了。vim另外一点就是所有操作几乎都可以在主键盘上完成,对于使用笔记本的人来说很方便。emacs我也用过一段时间,但是emacs时间比较复杂,所以我放弃了。

图像处理
Paint.net需要.net支持,所以我不太感冒。我使用的是Unix下大名鼎鼎的Gimp。一开始可能用不管,但是时间长了就知道他的强大之处了。我个人认为比Photoshop有一段差距的,但是一般处理图片绝对能胜任。

PDF
阅读PDF当然是用Foxit Reader。这么快的pdf阅读器,谁不用谁是傻子!
生成PDF,有两个工具。一个是我常用的open office 2.3,直接保存成pdf。另外一个是Letex,这个我在linux下用,据说也有windows版,生成的PDF绝对漂亮!

听音乐
千千静听和foobar这两个我都用过,最后还是foobar占据了我的硬盘。无他,就是喜欢简单的工具。如果想听APE需要下载一个插件。

FTP
FileZilla,我用下来感觉很稳定,很方便,很强大。大概带Zilla的东西都不错。不知道以后会不会有Zilla Fan这一说!

源代码管理
公司用的是又贵又不好用的Clearcase,现在在Clearcase下面我连Debug都不行,只能靠打trace或者用Dump Stack来分析问题。因此我喜欢小巧的SVN,配上windows上最好的客户端TortoiseSVN,已经能完全满足一个大型公司的要求了,更别说我自己个人开发了。

播放器
还用说么?Windows Media Classic 6.4.9.1。稳定,CPU占用率小,启动快,自动加载字幕,对一般看看片子够了。另外国产的酷热影音也不错,速度很快,插件管够!

安全
安全涉及到杀毒软件和防火墙。我用的是Avast! Home版。这个捷克的软件我很喜欢。CPU占用率中等,每天自动更新。实在不放心再装个360安全卫士。Windows这东西防是防不住的,只能自己注意不要上乱七八糟的网站。浏览器用FF可以防止一些ActiveX控件。

基本上一般日常使用的软件都在这里了。详细以后会有越来越多的付费软件被开源或者免费软件所替代。

2008年3月11日星期二

搞定无线路由

昨天在淘宝上买的NETGEAR WGR614终于到了。拿到手一看,白色的,样子很漂亮,真是很庆幸没有买TP-LINK或D-LINK那些黑色的砖头。

不过在设置的时候遇到了些麻烦。这个机器真是奇怪,说是无线路由,但是无线一开始是禁用的。必须要用有线方式把无线功能开启才行。于是照着说明书连好网线。因为我是在公司里面试,所以用的是固定IP的局域网。然后就搞出一系列稀奇古怪的问题,我在这里总结一下,希望对以后自己和别人都有用。

  • 设置页面进不去
这是第一个问题,IE总是处于返回状态,但是界面上面就是一片白。我感觉可能是插了外网的网线所致,所以把外网的网线拔了。然后再试,一下子就进去了。结论是:进控制界面最好拔了外网网线,如果不行就把路由断电,再重新开启。

  • 配IP
如果在局域网内就直接配置局域网IP,网关和DNS。配好之后按“测试”按钮,如果成功就能连到NETGEAR中国网站。

  • 什么都设置好了但是还连不上INTERNET
我运气不好,遇到的就是这种情况,结果只能死马当活马医,不管三七二十一直接RESET。这个RESET键可以看机器背后的示意图,就在WAN插口附近。按5秒左右就能重置。然后再设置一边。


信号强度。NETGEAR不愧是排名第二的厂商。质量要比公司自己用的TP-LINK好的多。我站在60米外,隔了3堵墙还有1~2个信号。看看页面是绝对可以了。

少吃三、五斤

中午看到消息,食品价格上涨20%多。尽管近几个月各种物价持续上涨已经让我神经粗了很多,但是这个消息还是让我感觉一种无力感。看来我的减肥大计终于要在08年实现了。真好×_×~!。

其实从去年8,9月份物价上涨开始,我已经感到开销的增加了。比如脱脂牛奶,从6.7元变成现在的10.9。幅度之大令人乍舌。由于我妈身体不好,日常开销基本上就由我来把关了。“不当家不知柴米贵”这句话我现在有了深刻的体会。我也学会了买东西挑挑拣拣,和菜场里面小贩讨价还价,在抽水马桶的水箱里面放个瓶子节约用水。

对于这样的变化,同事们都在叫怎么还不加工资。前两天传出消息,这次工资涨幅将是10%~15%,不过是在基本工资的基础上。公司打的真是如意算盘啊。本来这10%应该是去年物价上涨的时候全国统一要求。公司那时候硬是不涨,一直到这个月才给涨。看似最后还是涨了,但是实际上公司却把两次加薪并作了一次。着实耍了我们一回儿。

更让我气愤的是,两个月前的报销单被退了回来,说现在加班吃饭已经不能报销了。Admin会在每个月底根据实际加班单把饭贴(12元)打到我们的饭卡里面。我真不知道公司什么时候变这样了,连通知我们一声也没有,我们还照着以前加班50元饭贴来吃饭,结果可想而知,两个月下来,我亏了好几百!!!要人干活,还不让人吃好,这班不加也罢!

这两个礼拜已经开始有人陆陆续续离开公司了,甚至4年多的老员工也离开了。为什么,因为做了4年还只是一个SE,两个Senior都没有捞到。可笑的是,公司随便招个根本不懂业务的,又不会C++的也能当Senior,因此他失望透顶,不想再留了。看来公司4月份将是一个大换血月。前年4月份,公司发好年终奖,一个人都没有走,大家都干劲十足。今年4月还没有到,公司里面就弥漫着一股子颓废的气氛。人心散了,公司也不远矣!

2008年3月7日星期五

PM with no IT background

这片文章我准备写双语,因为这是个真实的笑话。虽然还不是非常可笑。
It's a real joking, though it's not so funny.

昨天我正在写程序,突然听到旁边得一个PM在和他手下得一个程序员通电话。很快他说出了非常经典得一句话:
“……那个错误号是0乘以80004005……”
我还没有反应过来,但是80004005对我来说再熟悉不过,是COM的错误“Access Denied”。于是我很快反应过来,这个PM报的是一个COM错误。不过把0x报成0乘以,这个PM真是太有才了。从这一句话,我就能知道他没有多少编程经验或者it行业经验。
还好他没有报成0乘以8千万4千零5,否则我肯定喷饭!!

I was writing program when I heard a PM beside me calling his engineer. Soon I was attracted by him, : ".... the error number is 0 multiply 80004005....."
80004005 is very familiar to me because it is a COM error "Access Denied". Thus I knew he was saying a COM error, but he mistook the hexidecimal prefix 0x to be "0 multiply".... He is genius, my God!
It's not bad he didn't say "0 multiply by 80 million 4 thousand and 5" , otherwise he was killing me for sure!!


---------------------------------
PS. 我好像没有讲笑话的天赋,我自己看了都不觉得好笑。。。。。 原谅我把,就当冷笑话冷处理好了。。。。

2008年3月3日星期一

钱到用时方恨少

我有记帐的习惯。但是我平时用钱很少,所以基本上每个月都能控制在千把块。开头我把2月份的账单整理了一下,结果吓我一跳!我2月份竟然用掉了将近25000块。但是也的确是事情比较多。一开始买了个WII,然后过年,然后开学交了学费8K,最后是买了台笔记本,妈妈生病用掉8W多块钱,虽然都是父亲付得,但是平时零零碎碎加起来我也付了4,5千了。

真是钱到用时方恨少啊。平时觉得自己还有些积蓄,但是真正碰到事情了,这钱用起来就像流水一样哗哗哗地往外流。现在就这样,我不知道到结婚,买房会怎么样个惨烈的情形。

我准备这一年的目标就是努力赚钱了。再和去年一样混日子是不行的了。

2008年2月29日星期五

小黑入手-ThinkPad T61 AM6

自从几个月前我的PC开始间歇性抽风以来,我就知道我那台老机器该退役了。之后我一直在台式机的优秀性能和笔记本的轻便上犹豫着。后来我终于决定买笔记本,一方面是因为现在工作和读书的性质已经决定了台式机无法胜任我的要求了,另一方面是因为我要搬到张江去了,台式机搬起来不方便。经过一个多礼拜的调查和观望,今天我终于出手了。机器是从www.nbclub.net的上海分部买的。我下了班之后直奔普陀区中江路。到那里已经7点半左右,nbclub比我想的要大的多,有好几个员工,看来水货笔记本生意还是很好的。

机器我早已经定好,ThinkPad T61 AM6 + 1G内存。
机器配置很不错,
CPU: T7500 2.2G
Memory: 1G
Hard Drive: 160G 5400/8m
LCD: 14.1 SXGA+ 1400*1050
Display Adapter: Quadro NVS 140M 128M DDR
外加DVD-RW,蓝牙,1G迅盘,指纹识别、802.11agb
OS:Vista Home版
外加nbclub附送的原装红点包+IBM原装鼠标+IBMThinkPad清洁套装+转换叉头+IBM原装内胆包一个+微软专业游戏鼠标垫一块+一次成型网线一根+NBCLUB T61全自动恢复光盘一张。

价格: 机器9950+1G原装内存180=10130RMB。

在我看来这个价格配这台机器已经是相当超值了,更别说外带的这么多实用的附加产品。看照片永远没有实物来的震撼。当我看到小黑酷酷的外壳,IBM舒适的键盘,再加上IBM ThinkPad的标志,我开始激动起来了!我知道我买对了,没有买笨重的台式机真是明智的选择啊!!试机用了大概半个小时,运气很好,没有遇到坏点机器。虽说一两个坏点不影响使用,但是心里总归会有疙瘩。机器的分量2.3kg对我来说还是很轻的。本来想买宽屏的一款,可惜宽屏的都是4芯电池,待机时间太短了。换成6芯的就会突出来一块,极不雅观。而且我也不大看片子,所以还是这款标屏的算了。

现在我唯一担心的就是我只要买大件就出问题的超级霉运。希望这次老天爷能够抬抬手,睁一只眼,闭一只眼吧。





大多数机器都不在有IBM的标签了,据说这款是最后一款带有IBM ThinkPad标签的机器。


不过在屏幕下方还是打上了Lenovo的烙印。

Overload now, Payoff later

My mother was made a major operation last Thursday because her acantha hyperplasia oppresses her nerves nearby which deprived her mobility of her right leg. Unfortunately, it happened on the first day of Chinese Spring Festival. A unbearable pain stoke her and put her stay on bed. She wes sent to hospital on 12 Feb, and the doctor ask her to be in hospital immediately.

The operation was very successful according to doctor. 3 pair of nails were injected to her back bone to help enlarge the gap between acantha and fix it. It costed us more than 70,000 RMB. She was able to speak the next day. And I was surprised that she could even bend and unbend her right leg without any pain.

My mother is recovering very well, but this is not the point of this article.

From this event, I am asking myself. Why Mom got this painful thing just when she is just 54. After this operation, She has to live rest of her life with some steel stuff within her body. She can't bow too much. She can't do too much manual work. I can't image how her rest life will be.

Why? A simple reason is that she worked too much and avoided to protect her acantha. Of course no body likes to work and overwork. But in fact, most people are overloading there youth and energy when they are young no matter they are involuntary or have to.

I am one of them. Overwork to me is just like a habbit. I didn't remember when was last time I had gone back home on time. My working buddy is a computer, I sit almost all day long. I never go to gem. I go jogging every 2 or 3 weeks. I am getting fat. I always feel tired. I am just typical one of this generation. We have heavier stress more than any generations before both in mental and physical. Some of us try to change their life style. They manage to do it some a period. They turn a full circle back because the reality.Other people are overloading too. But they are just profligate of their lives. They play online game all night. They stay up in KTV, dance club and bar.

They maybe or maybe not realize that they are over using their life energe. Dead and alive are two ends of a seesaw. When we are living, the alive end is down relatively. We use energe of our lives and alive end goes up. When we run out of our energe, Dead end goes down and we die. When we overload our life energe, Alive end goes up quicker than usual. So do Death. The more we use our energe, the earlier payoff comes.

It is nature rule that Alive end goes up. But we can control its speed. But how do we know its speed? Easy, if you feel any uncomfortable, tired, pain etc, your body is warning you that its over speed. You should get to take care, avoid overworking, go to work out, take some centrum, go camping to have fun, change your mood. The sleep is low if you feel sharp, energic when you get up.

Remember, life is not credit card.

2008年2月13日星期三

Linux之父的人品令人质疑

最近一直在使用linux,因此对linux关注也比较多。随之看到Linux之父Linus Torvalds的新闻也多了。昨天就看到一篇Linus Torvalds抨击Leopard和Vista的文章。他在说Leopard完全是个废物,他说从编程开发讲,OSX的环境要比windows差很多,它的HFS文件系统简直是垃圾。

老实说,我自己很喜欢Leopard,我并不觉得它是个废物。同样,使用苹果的人也都很赞赏Leopard。Linus的言论给我感觉就像一个偏激的极端主义者。人们尊称其为lead of cult of Linux,说他是Linux世界的领袖。但是这种极端主义者能做领袖么?

Linus很喜欢做这样的事情,上次就抨击过C++,“C++是一种糟糕的(horrible)语言。而且因为有大量不够标准的程序员在使用而使情况更糟,以至于极容易产生彻头彻尾的垃圾(total and utter crap)”。我的C++水平还不到能和他辩论的水平,但是我相信就算我的水平到了他的级别,我也不会随便去贬低其他语言来彰显自己的地位。当年Andrew发明C#的时候,他没有说过一句Java的坏话。C++之父也只是实事求是的指出C在一些应用领域的不足才导致C++的产生。

作为自由世界公认的领袖人物,我认为Linus更应该注意自己的言行和修养,现在Linux是在夹缝中求生存,Linux在桌面领域只占有1%左右的市场份额,我不知道他从哪里获得那样的自信来抨击这两个桌面市场大颚。

前阵子看到另外的报道Con Kolivas放弃继续对Linux桌面性能提高的开发。Con Kolivas在Linux世界中是个异类,他很早就注意到Linux在桌面领域的性能远远不如windows和apple。但是Linux核心开发组的人们仍然陶醉于Linux在服务器市场上的发展,而对桌面领域视而不见。他只能自己操刀提高Linux桌面应用的性能。他的CK Patch在好几年来获得了大量的支持者。可惜,他还是没法改变Linux世界的那些人的观点,最终他心灰意冷放弃了。这其实也和Linus所指定的Linux发展方向有关。他的方向就是关注服务器市场,这样导致Linux内核越来越笨重,把应用于服务器的内核放在桌面应用中,当然导致的就是较差的用户体验。

Linus还有很多偏激的言论,基本上google这个人,出来的一半结果都是他发表自己的偏激的意见。Linux到了今天这个地步,已经不再是他个人的东西了,作为一个自由的OS核心,这么难能可贵的东西,他更应该考虑使用者们的感受,而不是自己的个人喜好。

2008年2月4日星期一

X11,FVWM,GNOME,KDE的区别

我用Linux也有一段时间了,但是在看一些老鸟们的文章时经常看到一些WM啊,桌面啊,X11啊之类的词,我模模糊糊的知道这些都是关于图形介面的名词,但是具体什么区别就不知道了。

今天抽空稍微查了一下,终于知道了他们的区别。

X Window System
X Window 系统版本 11,简称 X11,是一个运行于UNIX上的对网络透明的客户/服务器架构的图形显示系统。X并不是UNIX核心的一部分,而是在核心之上的一个应用程序。X提供一种协议,用来产生图形用户界面GUI。X不会负责很多事情,它只负责绘制(Drawing),移动窗口(Moving windows),和鼠标、键盘交互。X11 是 Unix 事实上的图形系统标准。Linux,各种 BSD 版本和多数的商用 Unix 都采用它,类似 CDE,KDE 和 GNOME 等桌面环境都运行在它之上。但是Linux使用的是一个叫XFree86的免费X11实现来提供相同的功能。不过由于一些License的问题,现在 X11的实现已经变成XOrg了。在Linux里面可以到/etc/X11/xorg.conf看到其配置文件。

Window Manager
在多数图形环境中,窗口边框的外观(标题栏,关闭按钮,等)如何显示是由系统定义的。 X11 则不是这样。在 X11 中,窗口的框架(也称为"装饰")是由一个称为窗口管理器的单独程序提供的。一般认为,窗口管理器只是另外一个客户程序;它用通常的办法启动,并与 X 服务器按同样的方法通信。有很多不同的窗口管理器供我们选择。 xwinman.org有一个详细的清单。多数常见的窗口管理器都允许用户定制称为主题的窗口外观。许多窗口管理器还提供额外的功能,象在根窗口上的弹出菜单让用户启动程序,docks,或程序启动按钮,提供一个或多个虚拟桌面。有一些WM还提供与桌面环境(A Desktop Environment)交互接口。

WM的功能可以用简单的一个词来概括--中转。比如一个程序要求X11绘制一个窗口,这个请求会首先被重定向到WM,WM来确定如何绘制窗口的标题栏(caption)和边框(Frame),在X系统中,这两个元素是由WM决定的。因此用户在窗口上拖拉和缩放也是由WM来做出反应。大多数WM还支持窗口最小化,也就是变成一个在窗口底部的图标。这项工作不属于X系统核心协议之列,因此是一些WM自己实现的。

大多数WM还处理一些其他的任务,比如显示根窗口(root window),这个就是Linux里面的桌面,和windows的桌面是topmost window同样的概念。WM还处理在根窗口上的键盘和鼠标操作,比如Alt-F4关闭窗口之类的功能。


GNOME,KDE,xFce等
这些都是桌面环境(Desktop Envrionment),他们运行于WM之上,提供更完善的桌面集成功能,更自由的定制操作系统使用方式。X上面的桌面环境与windows,Mac OS X等不同,它可以自由组合,自由更改。大多数的DE由窗口管理器(WM),文件管理器(FM),一组主题(Theme)与其他用来管理桌面的程序和库组成。所有这些组件都可以单独调换,随意组合成自己想要的桌面环境。不过现在很多Linux发行版都有一个预先固定的组合比如GNOME,KDE等(这两个已经成为最流行,最成熟的DE了)。这里有篇文章对大多数的DE做了比较。
http://en.wikipedia.org/wiki/Comparison_of_X_Window_System_desktop_environments

2008年2月2日星期六

2008年第二场大雪

前两天刚刚下了一场雪,没想到昨晚上又下了,而且更大。早上起来一看,地上的积雪足足有5公分厚。

看看我们家门口.....
家门口的雪


不幸的是我还要到公司加班。哦,忘了说了,我们和其他公司不同,这个双休日是照常休息的。中午吃饭仍旧去软件园,这里的人已经在打雪仗了,一路走过去,受到无数“友善”的问候。
软件园的人们兴奋啊


打起了雪仗


吃好饭,路过软件园的时候看到好多雪人,于是心血来潮把所有的雪人都拍下来,弄个“张将软件园雪人大赛”呵呵!
Snow Ogre


雪人1


猪头雪人
雪人2


呆瓜鼠
这个不错


这个有创意,还有耳环,不过总给我一种感觉好像是《Star War》里面的人物......
有创意,还有耳环!


这个比较一般
这个比较一般


招财猫
招财猫


这几个雪人酷
这几个雪人酷!

某人贡献了袜子和喜糖
某人贡献了袜子和喜糖


比基尼MM
泳装MM

我们浙江网新的作品友情参与,不过似乎比软件园的差些。
我们浙江网新的作品


软件园一角
软件园一角


路上全是雪
路上全是雪

和上次的比比,这次的雪厚多了
这次雪厚多了

我自己做的太极图
我自己做的太极图

2008年2月1日星期五

PHP5 can't connect to SQL Server 2005 Database

Yesterday, I started my small PHP tool for traffic chart embeded in my AFC project. Although using PHP with MySql and Apache is very common, I had to use Php adapting to my AFC project environment that is under windows 2003 server R2 and SQL server 2005 standard.

I built the environment in minutes and made php run quickly. Things seemed go easy. But a strange problem got in my way that my program could not connect to the SQL server 2005 database. I checked everything to ensure no grammer error and made the source file as simple as just one line -- calling "mssql_connect" function.

I knew the reason till I read a post in http://cn.php.net/function.mssql-connect, it said "The ntwdblib.dll should be version 2000.80.194.0, and not version 2000.2.8.0 that PHP 5 ships with"

But I can't download that file from the website the author provided and it is difficult for me to find it over the internet. So I upload and share it from my box. Anyone needs can download it from:
http://www.box.net/shared/qfmoo1ask4
and override the one in your php5 folder.

2008年1月28日星期一

2008年第一场大雪

上海昨天已经开始下大雪,今天早上起来,竟然积了挺厚的一层雪,虽然还没有银妆素裹的感觉,不过对于好几年没有下大雪的上海来说,已经够我兴奋一阵子了。我记得上次看到这么大的雪应该是在我初二的时候,也就是大概93,94年的样子。之后就没有过这么大的雪了。我今天特意带上了相机,一路上班,一路稍微拍些照片,留个纪念。谁知道下一次上海下这么大的雪是什么时候呢?随着全球气候变暖,上海这个南方城市能飘个雪花,下个雪子已经很不错了。

这是张江,我工作的地方。
First Snow of 2008



First Snow of 2008



路上的积雪其实不是很厚,但是走在上面滑溜溜的感觉真是久违了!路上看到有些女孩子很开心的滑着走路,看来年轻人的心情都差不多啊,呵呵。
Not so thick



走向张江软件园...路上的积雪已经被无数张江男,张江女踩化了。
Walking to Office



以前短短的5分钟路,今天却格外的长。
Still snowing



First Snow of 2008

2008年1月26日星期六

C++基础知识:函数指针

本文总结了C++中函数指针的使用方法和使用场合


声明
函数指针在C语言中已经存在,顾名思义,这是一个指向函数的指针。其声明方式如下:

int (*fp)(int); // a pointer to function that takes an int and return an int

这是一个“指向带有一个int参数,返回int值的函数的指针”。这时候可以把为该指针这样赋值。

int foo(int);
fp = foo;
fp = &foo;
fp = 0;

可以用函数名直接赋值,也可以用显式的方式用地址符取函数地址,函数指针还可以赋值为0。这和其他指针是一样的。不过直接取地址的方式是没有必要的。编译器会帮你取地址。

调用
函数指针的调用有两种方式,显式(简化)调用和隐式调用。

int k = (*fp)(100);
k = fp(100);

这两种方式是一样的。但是后面一种显然更符合使用习惯,不过请记住,这只是一种简化

使用
最常见的使用方式是回调函数。回调函数的意思是把函数指针告诉别的程序,由别的程序决定何时调用。比如windows编程常用的subclassing方式

LONG NewWindowProc(HWND,UINT,WPARAM,LPARAM); //申明了一个用来回调的函数。
SetWindowLongPtr(hWnd,DWLP_DLGPROC,NewWindowProc); // 设置了回调函数

// 当有信息过来的时候,windows 会调用NewWindowProc。
LONG NewWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// message processing logic.
}

回调函数一般在“当你不知道何时调用函数,但是知道函数该执行什么样的任务,返回什么样的结果的时候用
再来一个例子,一个书店有两种方式付款,现金和信用卡,用户可以选择使用一种方式付款,为了让程序简便,可以使用函数指针:

extern bool PayByCash(double);
bool PayByCreditCard(double){...}

bool (*Pay)(double);

if( CustomerWantByCash )
Pay = PayByCash(amount); // amount is a double
else
Pay = PayByCreditCard(amount);

....// do some prepaid check and preparation
bool success = Pay();

如果想要把函数指针用在重载函数中,函数指针本身必须提供多个重载版本。解析规则和重载函数解析规则相同。比如:

bool PayByCash(double);
bool PayByCash();
bool (*Pay)(double);
Pay = PayByCash;
Pay(1000.0); // 调用的是第一个PayByCash; 因为类型一致
Pay(); // error!
还有一种常用的方式是把函数指针传递给另外一个函数,使得那个函数可以在它自己的函数体内调用我们传入的函数指针。比如设计一个sort函数,它接受三个参数,前面两个参数是两个相同类型的对象实例,最后一个参数需要一个函数来告诉它如何比较。我们这里不讨论具体实现,仅看看其声明方式:

void sort( T, T, fp);

这里的fp将是一个函数指针,指向一个函数接受sort的前面两个参数,然后返回一个int值,来表明两个T的逻辑上的大小。因此这样的函数可以声明为:

int compare( T , T )();

因此对应的函数指针为:

int (*fpc)(T,T)();

其类型为

int (*)(T,T)

因此sort函数的原型可以声明为:

void sort( T, T , int (*)(T,T) ) ;

使用typedef,提高可读性:

typedef int (*CH)(T,T);
void sort( T,T, CH );



提升难度
现在,我们来提升一下难度!假设我在首地址为0的地方有个子函数,我该如何去调用呢?让我们想一想!首先我们已经知道了函数指针的声明方式:

void (*fp)();

在C/C++中,知道了一个类型,那么它的类型转换符也就容易得到了。只要把声明中的变量和最后的分号去掉即可,再在外面用括号括起来,也就是:

(void (*)())

这就是一个指向没有返回值的函数的指针。
这时候,我们可以把0地址强制转换成函数指针了。也就是:

(void (*)())0 ---- (1)

这就是一个指针,把他看做void (*fp)()中的fp即可。想想我们如何调用fp指向的函数的?不就是fp()么?但是这里由于是强制转换的,因此不能用这种隐式方式,要使用显式调用方式,也就是(*fp)();
我们把上面的fp替换为开头的 (1)式,既得:

(*(void (*)())0)();

但是这种方式大家都会看着头痛,因此我们可以用typedef声明。

typedef void (*fp)()
(*(fp)0)();

2008年1月24日星期四

一等奖引发的混乱

我发誓这是最后一次写关于这次的一等奖了。主要是我实在忍不住要骂人了。

上次提到公司让我自己订票,然后他们找代理公司打钱。然后出票,把行程单发给我。今天我想这事宜早不宜迟,于是早上找熟人订了票,2570RMB。把信息发给公司行政后就开始考虑怎么把钱拿到手了。结果等了半天没有回信,没办法,打电话过去催一下,行政也客气,说马上就帮我去办。结果等了半天,行政电话过来说代理公司觉得麻烦,所以决定直接把钱给我,明天让司机带过来。当时我就像骂人,我这几天可没少在公司问人,想转手那个破奖,直弄得别人见我就摇手。然后好不容易以一顿饭的代价找了同事的姐姐帮忙订了票,现在竟然说可以直接给我钱,TMD早点干嘛不说!!

我只能让同事的姐姐把票给取消了,虽然没有折钱,但也是一个人情了。遇到这样的公司我真的无语!

2008年1月22日星期二

Primeval Season2 Start

Primeval,中文名是远古入侵,这部片子是我前阵子无意中看到的,剧情老套,但是很合我的口味。另一方面英国英文听起来别有一番风味,英国式的幽默也和美国人的幽默不同,看多了美剧换换英剧也不错。

这部片子讲的是时空中出现了Anomaly,一种类似时间隧道的东西。远古生物可以通过这个东西来到现代社会,这个东西可能出现在任何地方,有霸王龙的森林,有15英尺长的远古巨鳄的湖泊,甚至还有超级进化捕猎生物的未来世界。每集讲一种生物通过Anomaly来到现代,然后英国的Home Office组成了一个team来处理这种情况。但片子不是那种重口味的恐怖片,里面到处充满了英国式的小幽默,我喜欢!

还有一条主线,就是主角,Cutter教授的妻子在8前年进入这种隧道,然后在现在世界和远古世界中流连忘返,她明明知道回来的途径,但是却不肯回来,然后又每每在众人危及的时候出现帮人一把,给人感觉是非常不可信任的一个人。但是她却有着比主角们多8年寻找和对付Anomaly的经验,使得主角们不得不依靠她的帮忙。

这个故事听起来很老套,但是时间和空间错位永远可以有无数吸引人的话题。而且巨型怪兽或者傻乎乎的渡渡鸟之类的东西,还是很吸引人的。特别是最后教授在过去做的事情竟然影响到了现实世界,使得现实世界的一个人一下子从人们的记忆当中消失了,而这个人却是教授在失去妻子8年之后重新爱上的一个女人,呵呵,事情有趣了。

现在,第二季终于出来了,回去下载!

对我来说不实惠的一等奖

今天特意去行政那里问了一等奖到底是怎么兑奖的。结果行政告诉我,要我先去订一张飞机票,然后通知公司行政,他们会去找代理商,如果价格超过2500,我需要先垫上差额,然后代理商才会打款给订票公司,然后让他们出票,把行程单给我送来。然后如果我要退票之类的自己再单独和订票公司办!

对于我这个想换现的人来说,这样的做法简直超级麻烦!唉,为什么我不是二等奖或者特等奖呢?

这句话是不是有点欠揍,不过,欠揍我也要说,因为我不爽!

2008年1月21日星期一

我中了一等奖!

真不敢相信,我竟然在公司年终联欢上面中了一个一等奖--价值2500RMB的机票一张。

公司这次竟然难得大方了一回,百来号人几乎人人有奖。首先50个普奖,价值100元-200元不等的奖品,然后25个高级点的普奖,价值200元-700元不等,三等奖3名,价值800元的三星移动硬盘一个。然后两个二等奖,PSP一个。一个一等奖和一个特等奖,价值5000多的液晶电视一台。

老实说,我一开始就在祈祷,因为我最想要的是PSP,所以我一直要老天保佑,不要让我抽到垃圾奖。抽完普奖我一下子心情激动起来,因为在还剩下20来个人里面抽三等奖,二等奖,一等奖和特等奖,概率是多么的高。但是抽完二等奖,看到PSP落入他人之手,我的心情又沮丧起来。因为我从小到大就没有中过任何奖,既然我一直期盼的PSP没有给我,那说明这次老天还是没有帮我。可是等到一等奖的电话号码出来,我一看最后四位是2007,我一下子傻了,没想到老天还是给我开了个玩笑,先让我沮丧一回,然后一下子给我一个惊喜。

不过老实说,这个奖实在不实惠,要我自己拿了机票去报销。我又不打算出去玩,这机票只能从别人那里拿了。

我现在正在考虑,这点钱该怎么用呢?买PSP好呢,还是买XB360?

2008年1月17日星期四

C++基础:重载与覆盖

今天,问了一个同事关于overloading和overriding的区别,但是这位已工作多年的程序员竟然支支吾吾说不清出其中的差别。这点我很吃惊。后来又问了几个人,发现竟然不止一个人没有搞清其中的差别。>


重载(overloading)和覆盖(overriding)其实是八竿子都打不着的两个概念。

重载指在同一个程序块范围中有多于一个函数用相同的函数名但是拥有不同的函数签名。

这句话里面有几个概念。一个是在同一个程序块范围(Scope)里面的才算重载。第二个就是函数签名。不同的函数签名指的是有不同的个数和类型的参数,函数签名不包括返回值。比如:

void foo(int& i);
int foo(int& i);

这两个函数拥有同样的签名,因此不算是重载,而且编译器会报错。

当提供了重载函数,在调用这个函数的时候,编译器会根据一定的规则(参数匹配,自动转换匹配等),来找到最合适的函数调用。重载的意义很重要,他提供了一种设计手段,使得相同的抽象概念接口可以根据实际情况(参数)来产生多种实现。比如最常用的是操作符重载。当一个自定义类型在语意上应该提供类似自然数的+操作的时候,它可以通过重载这个操作符来获得这种很自然的行为。

T t1,t2;
t1 = t1+t2; // overloading operator +
t1 = t1.Add(t2); // member function.

上面两种表达法中,很明显第一种更自然。

覆盖(overriding)指派生类(derived class) 提供了和基类(Base Class)中相同名字和签名的虚函数。那么这里也有两个概念。一个是覆盖仅发生在继承关系中,这和重载产生作用的范围不同。另外一个是覆盖只能针对于父类的虚函数,不是实函数也不是纯虚函数。看下面的代码

class Base{
public:
//....
virtual void foo(int);
void foo(double);
//....
}

class Derived{
public:
//...
void foo(int);
void foo(double);
//...
}

在这段代码中,基类Base中有两个函数,这两个函数是重载函数。在派生类中,第一个函数覆盖了基类中的虚函数。而后面一个foo(double)并不会覆盖基类中的同样签名的函数。因为在基类中那个函数不是虚函数。另外在派生类中的两个foo同样是重载函数。派生类中的foo(double)不会重载基类中的函数,因为他们在不同的scope中。

重载和覆盖的话题并不至于此,还有在template中的让人混淆的用法,但是千变不离其宗,记住这两个概念的作用域和发生的上下文即可进行判断。

作坊式的开发

什么是作坊式的开发方式?

需求只有短短的几句话,不能构成场景。
SPEC和需求完全对不上。一旦开发,就再也没有更新过SPEC。
TEST人员在开发后期介入,TEST CASE和SPEC毫无联系,凭自己想像写。
Bug描述就是短短的一句话的描述。没有过程,没有环境,没有对应的SPEC号。
测试人员和开发人员分开工作。
开发人员没有SPEC,只有需求,针对需求直接进行开发。

这就是作坊式的开发。而我们公司就是这样!

2008年1月14日星期一

软件开发方法浅谈(三)

最近生了一场大病,浅谈的整理断了几天。我已经好几年没有生病了,没想到这次一下子来的这么猛。我整整吊了4天盐水,现在还没有恢复,但是班还是要上的,否则没钱看病了。现在自己觉得身体越来越差,希望和我一样做IT的朋友要注意自己身体了,每天至少要有半小时的锻炼,吃一些善存之类的维生素片,弥补饮食结构带来的隐患。好了,闲话不多说,继续。

浅谈(二)里面已经整理了一些需求获取的方法。那么这里就可以说说从需求到设计的过程了。软件设计是大家研究的最多的东西,至今为止有可以说无数中设计方法。从以前学校里面学的自上而下、模块化到现在主流的面向对象(OO)的设计方法。我现在主要使用模块化和OO这两种方法。前者用于设计小型的工具软件,后者用于设计公司的软件产品。但是从需求到设计的过渡,关注的人就少很多了。下面就仔细说说从需求到设计的过程,或者说--需求工程。因为据我的经验来说,这部分是最难的。Frederick Brooks在《没有银弹》中也充分说明了需求工程在软件项目中扮演的重要角色。这部分过了之后,再细分就是水到渠成的事情。就算小部分出错,也不会影响到系统全局。

1. 需求的层次
最为困难的概念性工作便是编写出详细技术需求,这包括所有面向用户、面向机器和其它软件系统的接口”。这句话充分说明这个过渡阶段的重要性。

一般来说,需求有两种:用户需求和软件需求[1]。这两种分类也是两种层次。前者就是我在浅谈(二)中所指的从用户那里搜集过来经过简单加工的关于系统行为和反应的要求。用户需求往往包含着两个目的。

  • 我要完成一项工作
  • 这项工作的流程和结果要符合业务规则
软件需求(或者说技术需求)就是为了达到这两个目的而对软件系统提出的要求。这种要求分为两类:功能性的要求和非功能性的要求。
  • 功能性需求规定了系统要实现的功能,使得用户可以完成他们的工作,并且符合业务规则。
  • 非功能性需求则指明了为了要使用户完成目标而需要满足的除了功能以外的要求。这些要求往往是涉及系统的性能、可靠性,安全性,可维护性等方面的要求。

2. 需求的粒度
需求获取到什么程度可以进行设计,这个度的把握不容易。如果无法获得足够的信息,就没法过渡到设计。如果要获得足够多的信息,时间却不允许。那么如何掌握这个度呢?我认为,能把用户的一个目标实现从输入到输出串得起来就可以了,也就是说得通,细节部分不用太关注,要关注得是搞清用户目标,以及现存的支持系统。

我相信实践出真知,检验知识也要靠实践,因此这里开始用一个贯穿全文的例子来说明如何精化需求的。

例子是这样的:我们刚刚获得了一个项目,这个项目是要为牛逼公司打造一个报表系统。首先从NB公司那里获得的需求。他们的要求很简单,“我们要一个报表系统,我们经理每天早上一上班就要看到报表打印出来放在他的办工桌上面。”。然后经过一连串的需求挖掘。我们整理出了初步的需求如下:

牛逼公司的生产部经理牛魔王每天早上需要看报表。报表的内容是前一天公司生产车间所有设备的生产计划、实际生产结果、运行情况、维修明细、产量、故障情况、员工生产率和库存情况。
是的,听起来很简单,但是我们很快会发现一些问题。比如数据从哪里来、有哪些种类的数据等等。然后继续获取需求。然后我们扩充了这个需求(通过上一篇文章中的方法)。

牛逼公司的生产部经理牛魔王每天早上需要看报表。报表的内容是前一天公司生产车间所有设备的生产计划、实际生产结果、运行情况、维修明细、产量、故障情况、员工生产率和库存情况。他要求每一种分类单独一张报表,然后把他们合起来打印成一张大报表(B3),使他能看得方便,快速。

数据来源于各个设备。设备每过一段时间会自动产生这段时间内的运行状况的数据。如果出现紧急问题,设备会直接发送事件。如果断线,设备在连接恢复之后自动上传断线期间的数据。

车间主任负责制定生产计划,核查实际生产结果,核对库存情况。他需要将这些数据记录下来,以备核查。

到了这个程度,所有的过程听起来似乎已经比较合理了。车间主任制定生产计划,然后工人使用设备进行生产。设备定时产生数据,我们只要获取这些数据,加上车间主任制定的计划,就可以自动产生报表。当然,把报表放到牛魔王经理的桌上这种工作还需要小秘玉面狐狸来做。

3.从需求过渡到设计
需求过渡到设计的最终目的就是完成可用的软件需求和设计。告诉开发人员该怎么开发,才能完成客户的要求。所以这一阶段需要和开发人员,测试人员进行讨论,一并决定如何设计。这在很多公司都不受到重视,甚至无视,这是一种完全错误的做法。这些公司的做法是由一个较为资深的人单独决定什么该做,什么不该做,该怎么做。听起来不错,但是实际上资深的人往往并不如表面上那么“资深”,他在做决定的时候往往对可行性,可测性考虑太少。说到底,资深的人考虑的是上层抽象,“资浅”的人考虑的是实现细节,两方面合起来,达到的效果才能最好。

实际的过渡方法有很多种,现在流行的是OO方法通过编写用例,转化为领域模型,然后设计E-R模型,然后用UML中的静态视图,活动视图,交互视图等方法来完成初步的设计。但是有一点要清楚,UML是工具,真正的产出是我们的设计思想。我们一步一步把需求转化为设计的思想才是我们真正要追求的。

这里是我自己以及和同事,同学讨论的一个简单的方法的总结。

第一步我们有了类似上面那段话一样的需求。这样的需求常常被称为场景(Scenario),或者有时候还不构成场景。但是最起码我们知道了要做一件什么事情。于是我们可以把用户做这件事情的步骤一步一步写下来,这就是所谓的用例(Use Case)。但是很多人常常犯一个错误,总是把UC写成软件规格说明,常常写系统第一步做什么,第二步做什么,最后输出什么等等。我到现在还会不由自主的犯这种错误。记住:用例和场景都是用户从系统外部使用系统的过程以及系统给出的反馈。所有用例的总和就是该系统需要完成的所有任务。

第二步我们需要把用例转化为软件规格说明,但是并不是一下子转过去的。在这里,有两种方法。第一种是首先把UC转化为粗粒度的领域模型,这时候领域模型中的各个元素都是系统的各个组件(物理或者逻辑),这些组件相互作用完成系统的所有任务。然后对各个组件的相互作用进行分析,设计出系统接口,也是功能需求,最后对各个组件内部进行细分,自上而下的分析,最后形成细粒度的软件设计。第二种则是在UC和场景的基础上,对软件进行全面的评估,然后写出特性列表(Feature List)。每个特性都由一到多个功能提供实现。然后对每个功能都写一个Func Spec描述这个功能的软件规格说明。

第三步,就是把软件规格说明变成软件详细设计。这一步的花样就很多了,可以用UML大展拳脚,也可以用传统的伪代码模块化实现,也可以把一个一个函数的实现写出来。反正这一部分对于程序员来说是最亲切的。

总得来说,需求分析中最复杂的还是第一步,这一步做好了,后面的事情就是按部就班,逐步细化。并没有太多的技巧。而需求分析却需要很多技巧和经验,需要想记者一样不停地挖掘客户的真正想法。

系列文章:
软件开发方法浅谈(一)--软件开发过程
软件开发方法浅谈(二)--需求工程之需求获取


[1] 有些分法是把需求分为业务需求,用户需求和软件需求三种。还有更甚者增加系统需求。但是在我看来,业务需求应该包括在用户需求里面。在真正做软件的时候,当然可以把一些很独立的,成体系的行业规范单独列出。但在需求工程中,这部分往往已经包含在用户需求之中。

2008年1月9日星期三

GFW bans tool of goolge

The GFW gets crazy again.
This time, it bans toolbar.google.com. But I think it bans a pattern of tool*.google.com.

I found this because I try to install google toolbar in my new laptop which loaded a new version of Ubuntu. I kept waiting the response of the page until I suddenly realize d that it is possibly baned.

I add the address to tor of firefox in my desktop computer. It works, it proved to be true that tool of google is baned.

What a stupid and presumputous GFW!

Is tool of google illegal? Is toolbar of google sensitively political?

The major product listed in tool.google.com is Google IME. Can we imply that this is a mean indirectly made by some local company who also want to publish their IME?

Well I don't know. What I can do is to harness tor.

If you don't know how to make use of tor to sufer internet freely, google it.

Thank god! google.com is not banned!

2008年1月3日星期四

软件开发方法浅谈(二)

上一篇文章浅谈(一)已经整理了我接触到的4种主要开发过程。这一篇文章就来仔细的整理一下软件开发中最重要的部分--需求获取和分析。

老实说,自己公司在这方面做的不是很好,大多数的实践方法是我从别的公司那里学来的,还有一些是自己看书和在网上与人讨论得来的知识。经过实践,祛除了一些我认为不是很好用的方法,改进了一些方法的实践步骤。

需求在很多人的眼里虽然重要,但是还是没有重要到能够和产出或者代码相提并论。但我觉得在整个开发环节中,需求是最重要的。我可以毫无疑问的说,需求是软件开发项目成功的首要条件。我们在开发过程中会遇到很多问题,比如最明显的就是不知道哪些要做,哪些不要做;做出东西之后客户不认可,性能没有达到要求,在部署之后客户发现软件和自己想要的完全不是一个东西等等,所有这些,都是没有搞清楚客户到底要什么所造成的。

那么,通过简单的询问就能得到客户的需求么?客户告诉你的就是他要的么?客户一天一个想法,哪个想法才是他真正想要的呢?这些问题不容易回答,我自己经验尚浅,但是经过了几个大型项目的锻炼,我也总结出一些粗糙的方法,这些方法在某种程度上可以解答这些问题。

1.从什么地方获取需求
首先可以从技术合同中获取需求。但是经验表明,那样的需求粒度太粗,只能用于提纲挈领,无法直接转换为软件需求。但是有了这些需求,就可以一条一条去确认,去核对,去细化。

通过和最终用户沟通获取需求。这里的最终用户一定要搞清楚,比如我们做地铁项目的,最终用户就是那些自动售票机的售票员,而不是地铁公司的领导。

通过和销售、售后人员沟通获得需求。对于产品项目,就会有销售,他们会告诉你客户想要什么,或者什么样的软件特性是卖点。售后人员会告诉你上一版的软件有什么问题,这一版需要改经等等。

通过分发试用版本获得需求。beta版的产品就可以分发给用户进行试用了。他们的反馈是非常珍贵的实际需求。

以上都是一些大分类,另外还有一些途径比如产品论坛,内部其他项目人员,技术支持等等。但是有些需求是会遗漏的,那就是来自自己老板的需求。这些需求大多和盈利指标挂钩,这些可是非常重要的。

2. 什么是真正的需求
“客户往往不知道自己要什么”,这句话一定要牢牢记住。一般来说,第一次和客户谈,他给出的信息都不是最终需求。为什么呢,因为他也没有经验,他没有使用过。所以他只能大概的说一些。而第一次,我们需要的也就是大概的东西。然后如果使用敏捷法,那就可以开始干活了,然后再让客户使用,获得正确的反馈。但是在一般开发过程下,我们需要做一些东西,比如原型系统、Storyboard等等,给用户一个能够使用的环境,让他切身体会一下。但是,一定要有场景。只有在某个通用的场景下面的试用活动才能挖出真正的需求。客户会兴致勃勃的把自己代入那个最终场景,然后你就能清清楚楚的知道他怎么来做的,他想怎么做。不要怕麻烦,这种方法绝对可以让你省去后面一大堆麻烦。

谈话的技巧很重要,我们时间有限,不能跟客户胡侃,必须要在有限的时间内尽量引导客户谈正题。因此在找客户谈之前,了解客户行业背景,做准备,列问题就很重要。实际上,这个时候我们就和一些谈话节目的主持人一样。因此对于需求分析工程师来说,学习行业知识远比技术知识重要得多。

尽量找行业经验丰富的客户了解需求。比如我们去一家公司为其定做一套软件,那我会找怎么样的人来了解需求呢?我不能直接跟对方客户说,我要找一个经验丰富的人。我会虚拟一类人,把他代入这个软件的使用者,给他尽量真实的生活经历和工作经历,然后向对方要最符合的一个人。

注意大量隐藏的需求。比如我们地铁行业,一条线路的客户只会考虑本线路的要求,但是多条线路会共同运营,乘客会换乘,我们就需要考虑一些客户没有考虑到的问题。另外比如我们观察到北京地铁使用自动售票机的最终用户都是年纪比较大的大妈,大婶级人物,那么一个隐藏的需求就是字体要大些,对比度高些,能让他们看得清楚。这些往往是生活常识,因此不太可能从别人嘴里得来,要靠自己的观察。

不要光靠自己。一个人的力量永远是渺小的。在获得需求的时候,可以使用头脑风暴之类的方法,让客户和己方不同人员共同参与,各抒己见,这样往往能获得很多需求,但是筛选也是个麻烦事。

并不是所有需求都接受!在谈需求之前,我们要记住项目的范畴,客户往往会认为自己是甲方,所以漫天开价,什么都想要,对于不在范畴里面的需求,可以拒绝。但有时候为了打开市场等目的,对于无理等要求也只能接受。对于有些需求,本身在范围之内,但是和开发与测试讨论后发现这个需求开发时间非常长,或者根本无法测试的,这些需求也要和客户商量修改。

3.怎么样确定需求
一个需求分析到什么程度能够算行。这是仁者见仁,智者见智的问题。但是一般来说,如果一个需求能够写出一个用例(use case),那么这个需求也差不多可以了。用例需要有进入条件,退出条件(结果)和核心价值。进入条件指这个case是怎么触发的。结果就是这个case是怎么结束的,这两个都很好理解。那么核心价值是什么?核心价值是指该用例满足了用户哪个明确的需求。

需求就是我们要开发的东西。这个开发涉及到很多人,不光是需求分析人员的事情。很多公司上层人员获得需求,但是却不让开发和测试人员知道,这些上层人员以为自己同意就行了,这种做法是错误的。因为真正开发的人是开发和测试人员,只有他们认可的、知道的需求才有意义。当然,上层人员可以命令他们做,但是告诉别人怎么做和自己知道怎么做,要做什么将会产生完全不同的结果。因此,在需求定下来之前,要一条一条获得开发与测试人员的同意。每个需求要和开发、测试人员要提出对这条需求的看法,是否能开发,是否可测等等。对于不能开发或者不能测试的需求,一律拒绝或者修改。一旦同意,则他们就要签字,这样也能形成连带责任。

需求的获取也有迭代,一开始的几次迭代只要把一部分核心功能的需求搞清楚即可,对于这部分的需求描述,粒度要细;而对于后面几次迭代的需求只要大致知道有这几个需求即可。那么,粒度要细到什么程度呢?简单的说,一个需求一个用例,一个到多个用例合起来形成一个用户场景即可。在写用例的时候,不涉及任何技术或者系统内部的表现,只有系统外部的表现和给用户的反馈。

比如说,用户在线买本书。用户看到了一本要买的书,然后点击加入购物车,然后去网上支付,完成交易。这是一个完整的场景,而核心价值就是用户买到了书。因此无须写多个用例。一个用例即可。同时在用例里面加入可能的分支情节,比如用户未登录等等。

再举个例子,用户进入地铁站。那用户首先要去买票,他可以在自动售票机那里买,也可以在人工售票机那里买。然后他在闸机那里刷卡进入车站。那这种情况下,就是一个场景多个用例了。买票是就有两个用例,然后进站整个是一个用例。两个买票的用例从属与进站这个用例。但是对于客户来说,因为他最终目的是为了进站,所以买到票在进站是一个完整的需求。

总结一下,需求分析的目的就是要获得客户真正想要的东西,也是我们能够真正开发的要求。很多项目的失败都是因为没有搞清楚这点。做出来的东西和别人要的不一样,别人当然不肯给钱。然后再进行修改,变更,成本也随之上升。千里之行,始于脚下。眼睛不要看得太远,而忽略了身边的事情。

2008年1月2日星期三

软件开发方法浅谈(一)

很久没用中文写文章了,这篇就用中文吧。

做事情要有方法论指导,否则就是瞎做,乱做。在软件行业,有着别其他行业更多的方法论。在过去的几年中,我接触了一些,实践了一些,对各种软件开发方法有了一定的了解。正值岁末,我就来简单地整理一下,首先说说软件开发过程。

首先了解一下概念,一个软件的开发要经过的一系列的环节,一般的开发主要包括分析,设计,编码,测试和发布(或部署)这几个环节,在这个行业的人都知道。但是如何区分这几个环节呢?这几个环节每个环节的输入是什么?输出是什么?

为了回答这些问题,人们开始制定一些标准或准则,用来规定各个环节的工作以及产出。毕竟,一个软件的开发是为了赚钱,如果没有产出,如何赚钱呢?这种标准就是软件工程中说的软件开发过程。也有人称之为软件生民周期。但是这两个概念还是有所不同。前者着重一个东西从无到有的过程,后者着重时间的发展。但我这里还是把两个概念并成一个,主要介绍过程,因为过程也包括了时间的发展。

很显然的,这个过程设计的好坏会直接影响到东西的质量,更会影响到这个东西能带来的利益好坏。因此,很早以前,国外很多公司就成立了QA部门,定义一些自己的过程来确保质量。有一些过程名声显赫,最终成为了一个时代的标准。

1. 瀑布模型(Waterfall Model)

这个名字软件行业的人耳熟能详,但现在已经成为了贬义词。如果你公司使用瀑布模型,估计会遭人白眼。为什么,因为使用瀑布模型而失败的项目不计其数。但是,要知道,这是第一个把软件生命周期明确定义出来的模型,现在的很多开发过程,只不过是把这几个阶段拆分,打散,拉长,缩短来适应需求而已。再把眼睛往后看30年,那个时候的软件远远没有这么复杂,需求简单而明确,因此瀑布模型还是很适合的。但是,现在的世界发展太快,人类的知识面和想像力都无限膨胀,对软件开发商的要求越来越多了,很好,这才是真正的产业。因此瀑布模型的缺点就出来了---简单的说,就是不能应付需求变更,或者更准确地说,应付需求变更的成本太大。瀑布模型中要求需求全部弄清楚之后才开始设计和开发,但是现在的软件大多数规模庞大,跨地域工作又提高了沟通成本,导致需求很难在一开始就全部弄清楚,但是时间不等人啊,根据瀑布模型就开始工作,到了后期,需求变更对于已经设计差不多完成的软件来说无疑是个灾难。很自然的,人们开始想到螺旋模型。

2. 螺旋模型(Spiral Model)
这个模型很简单,就是把一个大的瀑布模型拆分成多个小的瀑布模型。这很符合需求导向的软件开发实际情况。比如一开始掌握了20%左右的关键需求就开始了第一个瀑布模型,完成这个阶段之后再开始后面的20%或者30%需求。很明显,这样提高了质量,减少了需求变更的成本。而且在每个阶段也不需要投入非常多的人力了。试想一下,原本三个月做100%需求可能需要6个人,现在1个月做20%的需求可能只要1个人了。这是多大的节省啊。老板们开始期待软件项目的成功了。可是,他们很无奈的发现,螺旋模型也有缺点--每个周期结束没有明确的输出,这可能导致后面的周期无法正常开始,最后的集成往往产生很大问题。往往螺旋模型一开始很顺利,到后面越来越难转下去,就想一个陀螺一样。我一开始就说过,开发过程是一些准则和标准。因此,人们决定要把螺旋模型改造一下,定义其开始标志和结束标志(输入和输出)。于是,迭代模型产生了。

3. 迭代模型(Iteration Model)
迭代模型是一个很有意义的进步,他每个阶段的设计都非常灵活。通常来说,每个公司都有自己的迭代模型,但是有一点不会变,就是迭代模型明确规定了各个阶段的开始标志,输入条件,输出内容和结束标志。当然,其中最重要的还是输入的内容和结束标志。每个阶段的结束都称为Milestone。迭代是很灵活的,对于小规模的开发,迭代是线性的,也就是一个迭代完成再进入下一个迭代。而对于大规模开发,可能就是并行的。各个子系统并行迭代,每个子系统内部再进行线性迭代。




然后每个迭代也不能就这么叫迭代了。对于一个软件项目,总归会有需求分析阶段,设计阶段,开发阶段,验证阶段和发布阶段。这些阶段都不是纯粹的做单一的工作,比如需求分析阶段,不是单纯的做需求分析,也有一些少量的开发,同时一些测试用例也开始设计起来。但是这个阶段主要还是做需求分析,因此就叫做需求分析阶段。类似的,开发阶段的主要工作还是开发,但是也有一定量的需求分析工作。简单的说,就是谁占主导地位,就叫谁的名。对于阶段的名称,每个公司都不同,每种开发过程也都不同,不用去特别的记忆,因为背后做的事情就是这些。但是对于大的项目,往往每个大阶段里面还有小的迭代。比如一个需求分析阶段就会有1~2个迭代,开发有2~3个迭代等等。这要根据实际情况来。

那么每个迭代干什么事情呢?其实每个迭代也犹如一个小的软件生命周期,基本上都包括了需求分析,开发,测试等阶段。但是每个阶段时间很短。因为实践证明,一个迭代不要超过4~6周,因此在开发阶段往往是2~3天分析这个迭代要做的事情,1~2周进行开发,1周进行测试,然后几天进行发布。但是再需求分析阶段,需求才是最重要的事情。因此在该阶段的迭代的特征是需求往往占据80%以上的迭代时间,剩下的是一些原型开发,不带测试和发布的迭代。

迭代的内容和内部时间比例是灵活的。但是输出却是固定的。在设计迭代的时候就已经定义好,每个迭代的输出是什么。这个标准在很多公司被称为迭代的退出条件(Exit Criteria)。达到这个条件,迭代就可以退出,向下面一个前进。比如在需求阶段,第一个迭代做了20%的需求分析,这些需求就是要在后面一个迭代进行开发的内容,因此这个迭代的输出就是需求分析文档和这部分的设计文档。需求文档需要非常详细,每个测试人员和开发人员要清楚的知道自己那部分的需求是什么。设计文档中软件规格说明书一般由PM编写,不涉及具体的技术细节,是用户需求到软件需求的一个转化。这部分也需要很详细。设计文档还包括SE编写的软件设计文档(系统架构,数据库设计,接口设计,类图,事件流程等),但是可以是一个初步的第一版的设计。如在开发阶段,那每个迭代的主要输出就是程序了。

刚接触迭代开发的人会觉得很简单,但是真正做了之后就发现根本无法估量后面的工作量。甚至后面的几个Milestone都无法确定时间,这真是件头疼的事情。事实上,这却是很难。在现实生活中,有这几种情况。一、项目是时间点驱动的。比如某某时间会开一个软件大会,某某时间是娱乐,游戏软件的黄金上市时间,某某时间是行业大会等等。这种情况下,时间就是确定的了。所要做的就是把这些时间里面能够完成的功能做出来。二、项目是有固定截至时间的,无论是合同规定还是成本要求都使这种情况最普遍。这种情况下面,首先把几个大的阶段分出来。只要粗略地分一下即可。但是对于需求分析阶段,却需要仔细的分配时间。因为往往需求阶段只有一个迭代。后面就直接进入设计阶段了。因为需求分析的这个迭代和设计阶段的第一个迭代需要在一开始就定义清楚退出条件的。这个阶段的需求包括系统总体的需求和一部分地层的,关键的需求。因此需要对所有的需求分优先级,然后完成一部分最高的。估算迭代的具体方法会在后续文章中详细介绍,这里就说一个宗旨,估算迭代只要估算清楚当前的和后面的一到两个即可。

有些公司在迭代模型的基础上,详细的定义了每个阶段的输出,并且附带实行的方法,可称之为一套完整的方法论,其代表就是RUP(Rational统一过程)和MSF(微软解决方案框架)。RUP把原先上面我说的一维阶段--需求,设计,开发等变成了两维的--时间和内容。时间分为初始、细化、构造和交付;内容则用工作流定义分为建模、需求、设计、实现、测试和部署这几个核心工作流和配置管理、变更管理、项目管理和环境这几个支持工作流。每个时间阶段里面都有一到多个迭代,每个迭代中都有不同的工作流,每个工作流的制品输出也不同。每个工作在不同时间的不同迭代里面占的比重不同。看下其概念图,很容易理解。


MSF的体系很复杂,包含了开发过程,团队合作,技术体系等一系列内容。这里不考虑其他的东西,仅仅考虑其开发过程。MS的开发过程分为planning, initialization,implementation,stabulization和release这几个阶段。其实这样的分法更科学。第一个是计划(planning)而不是需求更表明了他们在迭代开发时候的灵活性。这两套体系都是他们根据各自的多年经验积累而成的,但是选择使用却要符合自己公司的现状,不能照搬照套。

4. 敏捷开发(Agile)
敏捷开发严格来说不是一种开发模型,也不是一种严格的生命周期模型。我更倾向于称它为一种理念。敏捷开发门派众多,我所知,所用也是有限,因此就拣这些我接触过的来整理比较好。说它是理念,因为敏捷开发实际上仍然逃不出需求,设计,开发,测试和发布这几个基本元素。它只是把这些元素的具体实践方法做了一些改动,使其适应性更强,灵活性更高,交互性更好,时效性更强。比如XP(eXtremeProgramming),有12种实践方法用来提高各个阶段的输出质量。它提倡的是快速开发,做出可交付的产品,交由客户使用,获得反馈,然后继续下一轮迭代。但是注意,它不是随便做做,我们以前做原型都是报着可作可不坐的心态,但是XP提倡的是“可交付的产品”,这句话保证了其质量品级。XP提倡TDD(Test Driven Development)测试驱动开发也是一个非常有用的实践。通过写测试用例,程序员很清楚这个功能的需求是什么,要达到什么目标才算通过,有目标的行为,当然效率要高些。Scrum有15min standing meeting,提倡开会少而精,每天跟踪进度,让每个人清楚三件事情:昨天已经做好什么,今天要做什么,现在有什么问题!

敏捷开发现在正在慢慢被人接受,别人认可。但是在真正的应用上,我个人认为还是应该先练习“楷书”--传统过程,再学习“草书”--敏捷开发。这样才能以不变应万变,特别是对年轻的没有经验的团队。君不见发明Agile的都是那些大胡子秃顶的老头么?他们的经验何其丰富,草书再草也不会失去控制变成涂鸦。


总结一下,软件开发方法很多,但是经典的就这么几种。重要的不是方法本身,而是知道在什么时候使用什么方法。比如自己做个习作,就一两个月的时间,需求明确,那用瀑布模型是最省力省心的。总之两句话: Do right things! Do things right!

2007年12月19日星期三

From heaven to hell

Our HR manager just announced holiday arrangement some days ago, which we will have a 4 days Christmas holiday and a 4 days New Year holiday. Many people in our project were quite excited about it and started to plan how to enjoy our holidays include me. Some even intended to ask for 3 days annual leave to bridge the two 4 days holiday so that it becomes 11 days. And we really want relax, even stay at home instead of going outside because we've been working hard for several months. Last month, I worked 13 hours every day averagely.

But we dropped from heaven down to hell after yesterday's meeting hold by out PM. She annouced overwork day arrangment for us.

"From today to 17th Jan, no holidays, 6 days a week". Said our PM.

At that time, I felt extremely quiet in the meetingroom. But a few minutes later, the air is less stressed; people accepted this decision.

I am not mad at this decision. If I was in her shoes, I probably did the same thing. The cause is we have to pass the integration test in Beijing before 17th Jan. But the problem is we don't have enough time,enough resource to do test here as they did in Beijing. We have 8 devs but only 4 tests. We are supposed to finish all the integration test before we ship the software to site. As a matter of fact, four integrators working for Beijing subway system can finish their integration test in Beijing before 17th Jan or even early except us.

It's shamed. One that always claims to be the No.1 in this field gets the last score.

So what is wrong? Why we can't catch the schedule? Why don't so many know what customers want yet?

Summing up my theoretical musings about the whole of Beijing project, I conclude that it is due to management of this project.

2007年12月11日星期二

Pugnacious Mouse

Mouse is small rodent known as scary and cautious. They live in burrow, cockloft and anywhere dark and safe. They walk out at night to search food. Grownups regard them as one of the source of some bad diseases such as plague, rat bite fever and other infections. However, children prefer regarding them as cute little creatures to bad ones because they've never suffered the dark age of plague. They get to know these animals from TV, movie and pets shop where selling harmless relatives to rat.

Mouse is endowed with smart, flexible, cute and humorous, all the good traits by cartoon makers. But they missed one trait which is hardly thought from such a little and scary rodent. That is pugnacious!

I had known it when I traveled to Manila Philippines for a subway project. One day, I went to one of the station intending to get some data. When I moved the mouse, the cursor was like frozen. I was not surprised at that time because it had occurred many times due to the lack of power of USB port. What I would do is simply switch to another USB port. But I suddenly found that there was not even a cable connected to the mouse. I had the mouse close to my eyes and was astonished to find there were some bite marks on the plastic shell of mouse. What on earth happened to this mouse?

My local partner, Jojo, seemed already used to this and told me it was bitten by a mouse. And obviously that mouse was in blue mood so it fought against this one without having had identified if it was a real one.

Yesterday, I sent a new version to Jojo and asked him to test in workshop. He replied that unfortunately, he couldn't do it because some problem happened with the cable between equipments and computer due to rodent bite!!

Well, believe or not, however small an animal is, pugnacity is its nature. Mouse is not able to fight with human or even a cat. But how about also a mouse or an ant?

2007年11月20日星期二

A most touched sentence from customer

I am getting tired about my company recently as well as 2 projects I am working for. I think it is from the end of August when I was supposed to leave this company. Some of my colleagues had left this company successively because low salary and losing interests with their work. So did I! The package I was working for that time was really a crap with countless bugs. Even I fixed bugs with crazy speed, its essence would not be changed. Crap's crap!

So I decided to leave as I got a chance to work in a new and small company to create a requirement manangement software. What an exciting job this is! That's what I've been looking for -- to develop a product rather than a project towards a narrow field of people. But our COO persuaded me to stay because he said he will raise my salary and give me a promotion. He also told me that Beijing Project needed me. I also wished I could carry Beijing project through to the end. But COO is a lier!! None of his promise came to true. I was totally disappointed and lost enthusiam.

Last night, I was talking with a customer of Manila project. He's also my friend rather than just a customer. I was getting much agitated when we were talking about my company. But he said, Jeff, don't be so sad. Listen, when I think of Manila project software I think of Jeff Ling not TSSS(My company).

I was touched! I admitted. At that time, I felt this is the most touched sentence I've ever heard to assess my work!

Yes, this is enough. As a software engineer, I don't ask too much. Just a simple word or sentence to assess my work is enough. It is so ridiculous that this estimation is not from my PM, my company but from my customer.

I will memorize this sentence forever.

2007年10月19日星期五

Double Ninth Festival

Today is a traditional festival in China -- The Double Ninth Festival. We Chinese celebrate it on the ninth day of the ninth month in Chinese Calendar.

In the traditional theory of YinYang, 9 means the extreme Yang. So you can see how Yangs double 9 brings. One of empire of Han dynasty named this double 9 date to be a festival. In this date, people were customary to climb the high mountain, drink chrysanthemum wine and eat double ninth cakes which are made by sticky rice(also called chrysanthemum cakes or flower cakes).

With the days past, people endow a new meaning to this festival, to respect elder people, to wish elder people to live to 99 or older.

Nowadays, these activities become obsolete for people in modern cities. They are too busy to climb the high mountain and nowhere to buy chrysanthemum wine. The only convention is to eat double ninth cakes. I did this morning. This reminds me what date is today.



Pic Reference: Double Ninth Cake


Reference: Double Ninth Festival in Wikipedia

2007年10月16日星期二

Adjustment to my blog

Since GFW bans blogger, my blog is no longer viewed from China mainland without any help of proxy tools. Well, even it was ok, almost nobody visited my blog.....

So, I decide to maintain this blog in English rather than in Chinese. All Chinese blog will publish to my other blogs which can be visit from mainland China.

I am not a native speaker, so if you find my English is hard to understand, please tell me. I will learn how to use English from your comments. Thanks in advance.

2007年9月6日星期四

mutable的使用方法

在C++中,很多关键字是我们平常不注意的。今天要提到的一个就是mutable。

mutable是个变量修饰符。它的作用是让这个变量在const成员函数中可以被修改。那const成员函数的语义本来就是防止成员变量被修改,为什么还要允许mutable来破坏这样的语义呢?

事实上,很多情况下面const是作为一个getter函数在使用。对于一个getter函数来说,他只要简单的返回要求的值就可以了。但是当这个值在已经被计算过,被赋过值的情况下,这个说法是成立的。但是在很多程序中,为了加快速度,对于不用的成员变量都采用了推迟计算。如果所有的值都放在类型初始化的时候,会大大减缓速度。这就是为什么很多设计者都会为一个类提供init()方法而不是把所有的初始化工作都放在构造函数里面的原因。

言归正传,有时候需要在getter函数里面在返回值之前先进行计算,这就要改变const函数内的内容了。这种时候,有些人就会这样写:

int get_value() const{
if( !isInited ){
Type* const pThis = const_cast(this);
pThis->value_ = 123;
}
return value_
}
千万不要这样用,这是“犯罪”。这种做法完全破坏了const成员函数的语义。
正确的做法就是使用motable。

class Type{
public:
//...
int get_value() const{
if( !isInited ){
Type* const pThis = const_cast(this);
pThis->value_ = 123;
}
return value_
}

private:
//...
mutable int value_;
};

这样的设计符合“把逻辑上,设计上来说应该是const的函数声明为const函数”

2007年8月2日星期四

马尼拉项目回忆录(一)

马尼拉项目终于结束了,一个花费了我们小组整整一年半时间的项目终于圆满了。不带一丝遗憾的结束,不带一个残留FT的结束。

有位同事第一时间给我道贺说:“听到你们项目结束比听到北京申奥成功还感动!”,这让我着实深深愧疚了一把,因为我自己都没有这么感动呢。不过想想也对,我身在其中一年半多,这个项目都成了我生活的一部分了(嗯,应该还是挺大的一部分),最后结束也象是水到渠成,非常自然,反而就没这么激动了。

回想这一年半来,我恐怕是这个项目中感触最多的人了。从这个项目中,我学到了很多东西,除了技术本身,还有项目管理,成本核算等等。再加上同时在交大读工程硕士,像很多武侠小说中印证功夫一样,我也把书上的东西和现实中的运用一一印证,的确受益颇多啊。

想写篇小小的回忆录,却一时间都不知道从那里说起。

还是从最开始说起吧,这恐怕是我第一次把一个项目这么完整的写下来。

项目开始

大约在2005年11月份,部门经理Jay来找我,“Hey,凌浩,有没有兴趣做manila项目啊,这是个很不错的项目哦~”。“好啊!”。这么一句简短的话,我就开始进入这个项目。同时公司的一纸任命书也下来了。WPM-Working Package Manager,一个我至今还搞不清楚做什么的职务。由于当时我们的RIS(相当于系统架构师)不在,因此我也代理了他的工作。PM也是一个刚刚来公司的新人,对AFC(自动售检票)系统没有任何了解。而我也就多看了几个月的代码,稍微在其他项目为某个package改改FT(我们对bug的称呼),也是相当缺乏经验。同时加入的还有一位同济大学的实习生。于是三个新丁就开始了一个真正的AFC项目。

公司这么做的原因恐怕首先是认为这个项目相比其他项目是小项目,而且又有所有的源代码,风险已经降到最低了。所以才放心大胆的放到我们手里。其实恐怕也是没的选,当时公司人太少。

但是事实证明,这个项目比其他很多大项目都难缠。有一段时间弄得我精疲力尽。这个在后面细说。

平台迁移

我们首先遇到了一个难题,就是源代码的升级工作。原来的系统是dos6.22+win3.1+win nt4.0 + access 2.0 + sql server 6.5 的系统。我们现在要全面升级到windows 2000 , xp,2003 server + sql server 2005的平台。我们有两个选择:一是看懂源代码,然后抛弃掉,自己重写一份;二保持原来代码,一点一点在上面改。基于公司一贯的保守政策,我们采取了后者。事实证明,这样做真的把我们害苦了。

如果我们当时做些成本估算,绝对是前者成本低很多。特别是到维护期间。一开始的选择错误,会在项目后期慢慢显现出其巨大的危害。到那个时候,维护的成本呈几何级上升。

我们首先花了将近两个月时间学习原来的业务逻辑和研究代码难点。我们发现进程间通讯协议是DDE,这个极其古老的进程间数据交换方式。我提出了使用COM,被无情的拒绝.......

最复杂的通讯协议

最复杂的还是和设备的通讯,使用的是一种20年前写的协议--ADLC。这是项目中最难的一个难点。因为原先有一块硬件电路板,用来负责和设备的通讯。但是现在这种板子已经完全停产了。没办法,只能用软件代替。幸运的是我们已经有最底层通讯代码了。但是这些代码是用法文写的,就连变量名都是法文,几千行的代码,我过了一遍,愣是一点没看懂。

这时候RIS从曼谷回来了,他开始进入这个项目,他首先负责设计了ADLC协议应用层的程序框架,由那位同济的实习生来负责编写具体代码。在整个项目中,这块代码是改的最多的,前前后后基本上改了一年多才终于稳定下来。

我和这位RIS的家挺近的,我们都买了一辆自行车,每天一起下班,锻炼身体+聊天,真是很开心的一段日子。

经过一段时间,我们开始有点上手了,代码也改的快多了,但是我们慢慢发现,这些代码似乎是未完成品,很多地方有明显的缺陷。代码错误随处可见。那时候可真把我们郁闷坏了,不仅要看逻辑,还要看很多莫名其妙的代码错误。

在闷头苦干中,我们终于迎来了2006年新年。我那时候对这个项目充满了干劲,而且觉得这个项目绝对能完美的成功。因为升级工作出奇的顺利,很多问题基本上不过夜。

集成的教训

新年后回来上班,我们终于迎来了第一个集成。设备模拟器和车站系统的集成。这个集成是个大失败,几乎什么功能都跑不起来。首次失败让我的心情有点沮丧,不过后来仔细考虑了一下。当时做集成显然时机未到,unittest都没有做好,就开始做连调,实际上所暴露出来的问题都是应该在unittest的时候解决的。因此PM开会,分发任务,各人又回去完成自己未完成的事情。我认为,即使release时间来不及,也要做好unittest后再integrated test。UnitTest在软件开发过程中绝对重要。那时候,我也开始了解到CppUnit的威力。但当时想在公司推广被拒,一气之下再也没有提过。连自己都不用了,整整过了一年才重新拾起。

极尽重用之能事

这时候又一位同济的实习生加入了我们,负责线路级系统的开发,主要负责各个机器之间的通讯。原先的系统使用的是NamedPipe和拨号联机。现在显然不可能再用拨号方式,于是又一次展开讨论--在车站和线路之间用什么通讯方式比较好。由于公司一直相当抵触Socket(公司宁愿用shared folder+ copy file这种一点也不可靠的低级方式也不愿意用Socket让我始终觉得相当奇怪),最后还是采用了NamedPipe,因为有现成的代码可以重用。省钱啊~~PM和RIS的算盘打的就是比我好!果然技术人员和管理人员看到的就是不一样!想想在新技术层出不穷的年代,我们还使用如此古老的技术,真让人汗颜啊~。最终的代码就是NamedPipe上面包一层DDE通讯,呼,这种代码我看了就想吐。多线程资源共享和互斥,数据传输机制过于繁琐等等问题至今还存在其中,但我也懒得管了。这些问题就如跗骨之蛀,除非整个机制重写,否则再改也没有用。

我们的系统见证了windows的变迁

2006年3月28号,系统Internal Release,我至今还记得这一天。我记得那天终于我们有了真正的测试环。一台windows server 2003, 两台windows xp pro,一台windows 2000 pro,一台dos7.22 + windows 3.11,我们的软件真是见证了几个windows 系列几个时代的变迁啊。

不过测试刚开始就遇到许多设置问题,让新来的测试工程师大为恼火。事实上我作为开发人员也希望能够提供简单,方便的软件,不需要过多复杂的设置就可以运作 良好。可是这毕竟不是通用软件,专门软件就只有一份,在这点资金下面,我们没有更多的余力(也不想做)来完成那些额外的功能了。

在回家路上感叹manila项目设置困难,结果同事笑着告诉我,bangkok项目的安装配置才叫地狱呢。仅仅安装手册(不包括使用手册)就有400多 页,那里的测试系统有我们的人在的时候还能听使唤,我们的人一走,那里没几天就完蛋了。超级复杂的安装,配置系统曾经差点逼疯一个工程师。我听得瞠目结 舌。

提供傻瓜式的安装程序

我一直感叹我们公司项目的安装实在过于复杂,我终于下定决心要做一个安装文件。我选用的辅助工具是Inno Setup。这是个得过多次大奖的安装工具。制作安装程序相当简单,还提供一定的脚本编程能力。最后我们的程序基本上只要next, next就可以顺利安装上目标机器,并自动完成大多数设置。这个工具在后来的北京项目中也开始使用。我相信,大多数客户还是会喜欢这样的方式。至少,我们的客户看到这个安装程序时大为满意。

第一次正式Release是马拉松的开始

3月的最后一天,也是个值得纪念的里程碑。一个振奋人心的好消息从法国RIS那里传来,我们发给法国的第一个版本就能和真实设备连通了。几个多月的努力没有白费。这个项目终于出现了一曙光。

线路系统也已经external release出去。接下来就是新的一轮开发了。第一次迭代开发也快接近尾声。主要剩下的就是联调,微调。让我们的程序更健壮。这个阶段往往会发现很多原先注重功能开发阶段不注意的程序错误。而一些深层次的程序问题也暴露出来。这个阶段持续了很长一段时间。不停的向外面发Release,不停的测试,不停的修改。

签证风波

5月份,我要到法国去和真正的设备集成测试了。我在4月份办签证整整用了一个月。公司一向让我们办Training,但是没有人告诉我,于是我傻乎乎地对签证官说我去工作。因为我知道对签证官要诚实。于是签证官要求我叫法国那边警署出一个劳动证明,同时法国Thales还要出我地用工证明。

结果这两个东西法国那边都办不出来,护照又被扣在了大使馆,这里公司找了好多人,托了好多关系,甚至让法国地大老板打电话过来,还是不行。没办法,公司不如Alcatel有名啊,听说他们申请签证可以走特殊通道,很容易申请到。

最后我没辙了,准备好了另外一封资料,在去领退回来地签证时候,同时递交另外一份申请。因为我的飞机就在几天后。时间已经不允许我再预约一次了。但可恶的法国签证官一眼看出了我的企图,坚决的回绝了我。在我万般无奈的时候,里面的中国签证官出面让这个法国签证官放过了我,似乎她官大一级,法国签证官也无话可说。其实从这里就可以发现,法国人的等级观念很严重的。上级说的话,下级几乎没有反驳的余地。可惜我在最近才真正体会到这一点,可以看《对不起,我逾越了》。

终于,我还是拿到了签证,和另外一个同事一起,坐上了开往巴黎的飞机。说来惭愧,这还是我这个乡巴佬第一次做飞机。样样透着新奇,就像刘姥姥进了大观园一样。接下来,我就要开始一个人在巴黎度过一个月时间了。

2007年8月1日星期三

删不掉的目录

今天学到了一招,觉得非常有用。那就是--“Windows上删不掉的目录”。

首先看看我这里的一个目录:c:\tomcat.6.0.14. 嘿嘿,看起来很正常是不是?我们来打开看看。当我双击它,想打开看个究竟时立刻出现了一个错误“c:\tomcat6.0.14.引用了一个不可用的位置......”


当你想删除它时,windows提示无法删除文件!
够布尔比的目录了。看又不能看,删又不能删。那这个文件夹到底怎么产生的呢?真相只有一个,那就是--这个文件夹不叫这个名字。

开始->运行里面打开cmd,在c:\根目录下打
c:\rmdir tomcat.6.0.14..\

你就会发现这个目录被轻易的删除了。原来这个目录真正的名字是tomcat.6.0.14..\ 注意最后的.\ 这个在windows里面被隐藏起来了。做GUI的程序员没有把这部分显示出来,因此在资源管理器里面看出来的就是tomcat.6.0.14. 因为前面有这么多点了,最后一个点大家也不会特别注意,因此就起到了掩人耳目的作用。

创建这类目录也很容易,在命令行里面打
c:\mkdir tomcat.6.0.14..\
那么看到这里,聪明人就知道怎么利用这个漏洞了,在里面放点不想让别人看到的图片啊之类的东西(嘿嘿,某人很猥琐的笑笑),或者放点木马,病毒之类的,统统没法被杀毒软件查出来。这个目录还无法显示大小,一般人根本不会注意到自己的硬盘上被划分出去这样一块空间。其实最先找到这个bug的还是黑客们,他们通过这个在目标机器上放程序或者在肉鸡上面创建这样的目录来存放中间文件。

不过奉劝大家一声,看过了就算了,不要做坏事情啊,要遭雷劈的!(假如做坏事,也不要放在C盘根目录下面这么明显的地方)

2007年7月26日星期四

ATL8的COM服务器实现(一)

在现阶段,ATL仍然是实现COM组件的一个重要手段。在几年的发展中,ATL出现了两个重要的版本-ATL3和ATL8。虽然ATL8已经出来好几年,但是由于我一直重用着以前用ATL3开发的老代码,因此对ATL8没有什么太多的研究。这次借着新项目的机会,能够正式使用到Visual Studio 8进行开发,我也因此得以好好的研究了一下ATL8的实现。虽然现在是.net大行其道的时代,但我这个守旧的人还是希望能记录下这个快要被遗忘的技术的研究心得。


COM服务器的种类

Win32版本的COM有两种服务器

  • inporc server --进程中服务器(动态链接库,DLL等形式)
  • out-of-proc server --进程外服务器(exe程序,进程外是对客户进程而言)
其中out-of-proc server有几个特例,一个是DCOM,可以叫做Remote Server,一种是系统服务,也就是service。

对于InProc-Server,我没有过多的研究其在ATL8中的实现,毕竟相当简单。这里主要对out-of-proc Server的实现进行研究。研究对象也是一般的EXE程序,而不是service。

COM服务器的职责

COM服务器有三个基本职责
  • 注册和反注册服务器
  • 暴露类厂(实现IClassFactory),使SCM能够访问
  • 服务器生命周期管理
进程外服务器简述

进程外服务器就是一个exe程序。如果在命令行上面指定 regserver或unregserver就能要求该服务器进行注册和反注册。注册成功就会在注册表中出现该服务器所包含的所有接口的ProgID和ClSID。ATL实现了这个简单的功能。

ATL同样是调用标准COM辅助函数CoRegisterClassObject把类厂和每个类的IUnknown暴露给SCM,这样客户就可以通过SCM来使用组件提供的接口。在Server结束生命周期之前,调用
CoRevokeClassObject把组件从SCM中注销。

对于生命周期管理,由于是exe程序,所以它可以自己管理自己的生命周期。当服务器检测到已经没有任何客户在引用它内部对象时,它可以选择是否退出运行(ATL中默认是exe退出运行)。


服务器与COM对象

一个服务器在程序中是什么呢?事实上没有具体的对象可以代表它。ATL使用OO编程,因此为服务器定义了一个类,其最高层父类是CAtlModule。它是个全局变量,因此它有着和exe程序本身相同的生命周期,因此由他管理COM对象再合理不过。

一个COM对象可以通过CoCreateInstance创建。它有自己的类厂,该类厂实现IClassFactory接口。
注:有些对象是不能被CoCreateInstance创建的,只能通过其他对象间接的创建。

那么服务器如何与COM对象打交道呢?
ATL从一开始的版本就提供了一个叫Object Map的结构来存放服务器内COM对象的信息。CAtlModule(简单起见,就把它当作服务器吧,这样容易理解一点)利用Object Map来做要求每个类自己注册和反注册,创建类厂,提供一些辅助函数来进行初始化和结束前的工作。

下一章 详细介绍Object Map




2007年7月22日星期日

BENQ海湾键盘,让我对你说爱还是恨

这已经是我第二个海湾键盘了。黑色的键盘,非常酷,不宽,占地小,有质感。最重要的是这个键盘的手感很好,很像ThinkPad T系列键盘的手感。打上去戚戚嚓嚓,有点像以前机械键盘的感觉,但没有那么坚硬,反而很有弹性。让我在两年前第一次看到这款键盘的时候就毫不犹豫地在新蛋上买了下来。

有了这个键盘,我在打字的时候常常停下来感叹一番,国产的键盘也不错阿,谁说国产的东西不行的。

但是没想到这款键盘还是个扶不起的阿斗,一年也没有到,这个键盘边缘的键位上的字已经磨光了,然后开始成皮成批的键位失灵。那时候我有点气愤,想想以前的无名键盘用了3年都没有什么问题。这个100多块的键盘竟然才用了1年就报废了。

我今年年初拿着键盘去太平洋三期准备保修的,结果找不到发票了,本来想去磨磨看的,结果鬼使神差得又买了一个一模一样的海湾键盘回来。当戚戚嚓嚓的声音再次想起,熟悉的感觉又回来了。我心说,算了,希望这个好些。上次那个估计没有保养好。

可是恼人的事情又来了,这次的键盘质量更差,才6个月不到回车键就失灵了。这样的质量,让我太失望了。

我曾经一度希望支持BENQ这样的国产品牌,我买BENQ的光驱,买BENQ的鼠标(公司里面),买BENQ的键盘,换来的结果就是没有一样东西能用超过1年的。一个还算知名的品牌,就连一个键盘,一个鼠标都做不好,还谈什么振兴国货!!

本来想直接去买罗技的键盘的,不过BENQ海湾键盘两年包换,我昨天带了键盘去换,没有发票,没有保修卡,人家也收下了,说检修完之后等到键盘来了就通知我。恩,售后还算不错,但我希望给我的不是返修货。。。。。。

我决定,这次拿到键盘就再用一阵子,如果再坏了,我不换了,直接去买罗技的。

2007年7月19日星期四

manila项目终于结束了

昨天,收到了马尼拉项目的项目经理发来的祝贺信,说客户终于签字接收了。由此,项目结束,开始进入一年的维护期。

这是我在Thales第一个完整的项目,历时一年半,经历了数不清的困难,现在收到一封简简单单的祝贺信,却让我由衷的高兴。

回想这一年多来的经历,也不是那么平淡的。自己眼界在开阔,经验在增加。

简单的写下自己一路走来的历程:

  • 一开始拿到手像狗屎一样的代码。
  • 开始在原来代码上改造,不过狗屎就是狗屎,永远不会变成美味的狗腿。
  • 到法国总部做第一次集成测试。天天品尝法国美食。
  • 第一次看到上位机程序和设备(下位机)通讯。
  • 第一次对整个AFC系统有了整体,清晰的理解
  • 步行游巴黎,里昂看老友。
  • 去签证署办延期,整整站了一天,深刻体会到法国公务员工作效率。
  • 在上海用模拟器痛苦的调试程序,体会和真实设备的天壤之别
  • 第一次去马尼拉部署,发现菲律宾是个贫富差距极其严重的国家。
  • 连续工作两个通宵49小时,没有空调,没有凳子,只有白花花跳动的Trace和那颗兴奋的心。
  • 看着自己的成果让几十万人用,激动的心情不言而喻。
  • 每天早上在5星级宾馆狂吃美味的早餐,省掉午餐,晚上和法国人在Makati一家一家餐馆吃过去
  • 回到家里发现自己重了整整5斤。
  • 第二次去马尼拉部署,开始学会坐轻轨,喝gulaman,尝试了解菲律宾普通人的生活。
  • 第三次去马尼拉,硬啃用法文写的代码,花了两个礼拜终于解决了困扰我们半年的通讯协议问题。
  • 在小年夜匆匆赶回上海。
  • 第四次去马尼拉,不停得到处救火,发现法国人的软件水平比较差,菲律宾人实在是懒。
  • 法国人卖给菲律宾人的烂键盘一年不到已经按下去键弹不起来了,鼠标被真正的老鼠咬坏。
  • 感叹没有知识,没有技术就要被别人欺负。
  • 第五次去马尼拉,被领事馆的签证官警告,如果再办旅游签证,将把我和我们公司放进黑名单。
  • PM换成了拽的没边法国小伙子。
  • 发现自己不过是个小巴拉子,法国的PM宁愿相信那个新来的PM也不愿意相信我这个全程跟进的工程师。法国公司和国企一样,等级森严啊。
  • 按照不合理的安排干了两个通宵。
  • 回来改掉最后几个Bug,发现法国人的设备全是毛病。
  • 然后---结束!
一个项目结束了,但别的项目在开始,在继续。生活也在继续。过了浪尖,又是平淡。