人件与中国古代史:程序员豫让(续)–从盛大的起落说起

前某个周末看了一段上视的《七分之一》节目,是采访盛大的陈天桥。巧得很的是,我以前也从一个朋友那里听到过一些关于盛大的事。

2001年,盛大刚从韩国的Actoz拿到《传奇》代理时,正是盛大最困难的时候。因为当时的投资方中华网从盛大撤资,只给他留下了30万美元,刚好够付《传奇》的独家代理费–按盛大的说法是:因为他们与中华网合作期间,没有像别的.com那样烧钱,这30万是他们省下来的(见《知识经济:聪明不过盛大》)。

我那朋友的一个朋友那时就在盛大,负责《传奇》的汉化工作。不过由于当时盛大的情况已经很困难,而且他也不看好这个游戏,所以后来就从盛大出来自己创业。

我在《人件与中国古代史:程序员豫让》中说到过,员工没有与公司共患难的义务。一个公司平时不怎么善待员工,那么在公司困难时候,员工离开也是无可厚非的。所谓的:士为知己者死。或者叫:良禽择木而栖。

虽然现在的盛大已经不同往日,我也不知道他看到盛大的现在会作何感想。但我还是认为他当时的选择是正确的。

作为公司老板的陈天桥来说,他敏锐地发现了网游这个潜力巨大的新兴市场。但作为员工,特别是搞技术的员工来说,一般不太可能对市场有这样的了解,而且不同的人对同一个问题的看法也会有所不同。

古往今来,不知道有多少公司在面临冬天的时候,都会想要员工跟老板一起扛过去,并且他们也都相信自己可以扛过去。但是无数的事实已经证明,能扛过冬天迎来春天的公司只能是少数。如果一个老板在公司情况好的时候不能善待员工,那么对于员工来说,就算是扛到春天,那也只是老板的春天,不是员工的。更何况还有更大的可能是扛不过去。

具体到这件事上来说,我不敢说陈天桥是一个幸运的赌徒,他多少是有一些过人的眼光的。中华网作为投资方,如果当时知道未来两年里可以有49倍的回报率,那简直是增资都来不及,哪里可能撤资,就是投资贩毒也不一定有这么好的回报。但在当时那种情况下,连中华网都撤资了,说明他们认为盛大此举风险太大了。那么对于员工来说,就更没有理由陪老板冒险了。更何况在员工的角度上说,留下来,就意味着共同扛下所有的风险,而结果如果得到回报,却未必有员工的份–听现在盛大的员工说,他们的员工餐厅就很不怎么样。

关于“一个L头名牌包,能送多少人回家”的8log

小lolo在《晚行说.》里给大叔安排了一个光荣而艰巨的任务。虽然大叔搞不懂L头的名牌包要多少钱,8过回家要多少钱偶素知道滴,所以还是要坚决执行小lolo布置的8log任务。^O^

该任务被分为两部分执行:

首先就是调查一下L头的名牌包。GOOGLE了一下,大致结果是:真品LV的包包一般在人民币1万6左右(-_-|||),不过要是换上襄阳牌的话,差不多500-1000RMB就够了。:P

其次就是那个一年伙食只花8.35元的贫困女生。素为就此发表过他的看法:过分的同情等于侮辱。所以他的同学燕儿自杀了,马加爵去杀了人。

前几天看新闻,说上海各高校为没钱回家过年的贫困生们解决春节期间的食宿,还搞了联欢,每个人还有200块钱红包。但如果像素为所说的:

一位在那个年代就有手机的哥们,居然申请了助学贷款缴纳手机电话费,而他的最后两年的学费一直欠到毕业还似乎没有还。

这种事情没有解决,这样的“送温暖”不过是走过场的表面文章罢了。

其实也有很多人是拎LV包坐公交车,都不是真正的有钱人啊。

TAOCPv4

刚在Isaac Mao的BLOG上看到高德纳的经典著作TAOCP终于要出v4乐。

说实话,TAOCP这样的书对偶来说,真是“高山仰止,景行行止;虽不能至,心向往之”。什么叫大师,高老先生就是大师。什么是经典,TAOCP就是经典。^O^

据说令狐有打算买一套供在家里的书厨中。现在他要准备增加预算乐。:P

制台见洋人,制台何其多

在《补8log一篇》中南桥回复说:

类似的例子只会越来越多.

其实这样的例子已经很多了,厦门DELL不过是其中一例罢了。有时候,我们不得不悲哀地感觉到,这个时代怎么跟清朝末年时有几分相似。

前些年电视上常说广东的外向型经济如何发展得好,外资企业多么的多,利税多么的大。现在不说了,改说长三角了。为什么呢?因为广东的很多出口加工型的劳动密集型外企都搬到如昆山这样的地方来了。据说是因为广东的免二减三到期了,换个地方又可以重新免二减三。

官员们怎么办?还能怎么办,当然是升官了,看人家前几年的”政绩”多么的好。现在?现在怎么样那是现任官员的事,当然他们肯定也会有自己的办法的。

BTW:看到一篇有意思的文章《网虫的绰号与签名文件》,这个作者的版权意识很强啊(见最后一句话)。^O^

[技术贴]继续说一下用DELPHI实现动态代理的问题

昨天的那个动态代理的UML类图还不够全面,在TFooInvHandler实现中并不是直接通过RTTI操作TFooImpl的,而是通过一个通用的RTTI Invoke实现类:TInvoker进行。FImpl作为TInvoker的构造子参数传入,TInvoker通过接口取得VTAB,然后进行Dispatch操作,这个实现是可以独立出来的通用操作。

这样的话,在Handler中的工作就很单纯了,就是实现Aspect。

昨天临下班前,令狐向我指出一个在编译语言中不好解决的问题:Invoke的Context。Aspect除了需要Invoke时的那些如接口,方法,参数,返回值等内容以外,还需要一些额外的内容,对于这些额外内容的处理将最终导致问题不可避免的复杂化。这对动态语言来说可能不成问题,但对于静态语言,这是一件可能导致过多不必要耦合的陷阱。

所以我昨天下班回去后又研究了一下。最后我想还是将问题尽可能地简单化比较好,Aspect所需要的Context还是由Aspect自己维护,DynamicProxy不提供这方面的义务,以尽可能避免不必要的侵入。

在研究完TInvContext的实现后,我决定还是就用它了,因为有现成的代码提供了对不同的调用约定的处理(比如Cdecl/Pascal/StdCall等),自己实现太麻烦了。但如果可能的话,我还是想同时提供一个转换机制,用于生成一个Variant动态数组的参数,以简化使用。

[技术贴]关于动态代理

本来想上周末没能用DELPHI实现动态代理就算了,可是这几天却始终放不下这个想法,这实在是一个太美妙的想法了。而且在认真看了VCL对SOAP的实现后,现在至少有九成的把握可以实现这样一个动态代理。

那么动态代理有什么用?

这要先从GoF的Proxy模式说起。

假设有下面这样一个接口及其实现:

现在,如果你是这个接口的用户,而这个接口及其实现者提供了一个:

Foo : IFoo;

给你,其中Foo指向TFooImpl的一个实例。现在你有了IFoo的定义,和这个Foo实例–注意,你没有TFooImpl的定义和实现代码。如果现在要求你为所有的IFoo.doSth增加事务功能(假设doSth被实现为对数据库作更新操作),要怎么办?

GoF的Proxy模式就是解决方案之一:

如果所示,首先要实现一个新的IFoo接口实现–TStaticProxy。其中用了一个属性FImpl记录了TFooImpl的实例。然后在TStaticProxy中实现doSth和bar,并且将不需要变更的bar函数直接委托给FImpl处理,而在doSth的实现里加入事务处理即可。TStaticProxy的代码大致如下:

TStaticProxy = class( TInterfacedObject, IIFoo )privateFImpl : IFoo;publicconstructor Create( aImpl : IFoo );function doSth( ... ) : xxx;function bar( ... ) : xxx;end;constructor TStaticProxy.Create( aImpl : IFoo );BeginFImpl := aImpl;End;function TStaticProxy.doSth( ... ) : xxx;BeginBeginTransaction;Result := FImpl.doSth( ... );EndTransaction;End;function TStaticProxy.bar( ... ) : xxx;BeginResult := FImpl.bar( ... );End;

然后,在所有需要用到Foo对象的地方,改用新的NewFoo对象,如下:

varNewFoo : IFoo;BeginNewFoo := TStaticProxy.Create( Foo ) As IFoo;...  //  之后就可以把NewFoo完全当作Foo一样使用了。End;

可见,我们通过了一个Proxy类代理了所有对IFoo接口的操作,相当于在从IFoo到TFooImpl之间插入了自己的代码,在某种程度上,这就是AOP所谓的“横切”。当然如果你能有TFooImpl的代码的话,就简单了,只要如下:

从TFooImpl派生一个TNewFooImpl,然后在其中Override一下TFooImpl中的doSth即可,然后就创建TNewFooImpl的实例来代替Foo引用即可。

但问题就在于你必须拥用TFooImpl的代码,并且可以变更所提供的Foo实例,但这在很多时候是做不到的–除非不是用DELPHI,而是如Python一类的动态语言^O^。比如组件容器,比如远程实例等。还有像“虚代理”(就是当创建FImpl代价很高时,就在创建时只创建代理类,然后在真正需要时才创建FImpl的实例)

但上面这种静态代理还是很麻烦。首先,如果IFoo的成员函数很多的话,必须要一一为它们加上代理实现;其次,如果在应用中有很多接口需要代理时,就必须一一为它们写这样的专用代理类;第三,需要变更代理功能时,需要修改所有的代理类……

特别是像组件容器或是通用远程代理这样,对要实现的接口并不能确定的情况下,静态代理一点用也没有。

所以我们需要“动态代理”。我是在看了GIGIX发表在今年第一期《程序员》上的《动态代理的前世今生》一文后,虽然他说是的JAVA在JDK1.3中提出的,在java.lang.reflect中的proxy。但这却让我突发奇想,发现其实完全可以在DELPHI里也实现这样一个动态代理。

一个典型的动态代理如下:

这样,我们只需要把要增加在功能做成一个IInvocationHandler接口的实例,如图中的TFooInvHandler。然后动态创建一个支持IFoo接口的TDynamicProxy的实例–它是一个动态代理,只需要传入相应的参数:要实现的接口和相应的InvHandler实例即可,不需要为每个接口写一个代理。当然如GIGIX文中所说,对于C++来说,这个可以用模板实现,但问题在于模板归根到底是一种编译时的动态化技术,对于组件容器这样需要运行时动态化的应用,它还是不能实现。最后,InvHandler通过RTTI去调用具体的实现Foo。

它的用法大致如下:

TFooInvHandler = class( TInterfacedObject, IInvocationHandler )privateFImpl : IFoo;publicconstructor Create( aImpl : IFoo );function Invoke( IID, MethodName, Args[] ) : xxx;end;constructor TFooInvHandler.Create( aImpl : IFoo );BeginFImpl := aImpl;End;function TFooInvHandler.Invoke( IID, MethodName, Args[] ) : xxxBeginIf ( IID = IFoo ) AND ( MethodName = 'doSth' ) ThenBeginBeginTransaction;Result := DoInvoke( FImpl, IID, MethodName, Args[] );EndTransaction;EndElseResult := DoInvoke( FImpl, IID, MethodName, Args[] );End;varHandler : IInvocationHandler;NewFoo : IFoo;BeginHandler := TFooInvHandler.Create( Foo );NewFoo := TDynamicProxy.Create( TypeInfo(IFoo), Handler ) As IFoo;...  //  之后就可以把NewFoo完全当作Foo一样使用了。End;

注意:其中IInvocationHandler接口我还没想好要怎么定义,所以这段代码只是大致说明一下问题。另外,其中的DoInvoke就是通过RTTI来调用FImpl的。

从上面的代码可以看到,TDynamicProxy通过参数IFoo动态生成了一个对IFoo接口的代理,并且通过Handler参数插入一个处理接口IInvocationHandler,由TDynamicProxy把对IFoo接口的调用全部转成对IInvocationHandler接口的调用,最后由TFooInvHandler类来视情况处理。在这里,可以通过运行时配置方式来动态决定是否需要切入事务所处理,需要对哪个接口的哪个方法切入。

有了这样一个动态代理,还可以很方便地在InvocationHandler里切入如安全性检查,LOG等。这样的话,用DELPHI来实现AOP也不成问题了。

现在我面临的问题就是:如何来定义这个IInvocationHandler。

其实这里最主要的问题就是参数的传递的问题。接口可以用IID表示,方法可以用方法名,但参数变化太多了:一是数量不确定,可以有任意多个参数;二是类型不确定;三是传值参数和引用参数的问题。如前面那个例子用的是简单的办法,就是用一个不定长的Variant数组来记录,可以解决前两个问题,但第三个问题就比较麻烦,难道要用一个Tuple来作返回值?太麻烦了吧。

在VCL的SOAP实现里是通过一个TInvContext在记录的,但这样的话对于Handler的开发者来说,就不得不面对TInvContext的内部复杂性,易用性太差。

这就是我现在还不能确定实现的那一成。-_-|||

猛禽 Feb.03-05

一件有意思的事

事情源于一个MOP贴子《★☆○●◇QQ群发现惊天大秘密(偶然发现)◇●○☆★》,我们几个在群里试了半天,发现果然如此,纳闷了半天。

后来我试了两三次后发现,这个问题跟最后一个“婷”字无关,于是明白乐。

除了这个人物以外,我又试了另外两个人的名字,果然都不行。呵呵。政治无处不在啊。^O^

随手加到天天网摘里,刚才再去看时发现,MOP上终于有人也明白是怎么回事了。看来这事真的是很久远了,MOP上的小P孩们大多都不知道的。

“神化”后的“胡话”并三谈Gullibility

貌似偶经常就一个问题要谈上三次,看来是越来越像3D乐。-_-|||

一早来就看到老方的一篇《鞭挞“老罗”和扬我中医威风!》。这个话题是我挑起来的,实在是对老罗(传说中的“罗永浩”)关于中医药的说法不敢苟同。

在《Gullibility》里有人回复说:

老罗说的就是事实,戳到了某些人的痛处而已。中药就是经验主义,古代不发达这样没问题,现在是要讲科学的。
如果中药真的是科学,就把你的起作用的成分列出来阿,把毒副重用列出来阿,有没有系统的分析?
伪科学就是伪科学

经验主义有什么不对的?对于未知的领域,经验是解决问题最直接的办法。现在的科学又能怎么样?癌症、艾滋病不也是不能治,西医最伟大的创举之一是发明了抗生素,但是现在造成的后果呢?现在的细菌比抗生素发明前强悍了N倍。

生命是一项奇迹,即使是用现代科学也有很多方面无法解释。

老罗说中药没有成分列表,没有列出毒副作用,你就都相信?Gullibility!!!

《本草纲目》不就是中药的成份表吗?李时珍对各种中药成份都作了总结记录,包括每种成份的药性(功用)及禁忌等都有说明,对于毒性也有说明,还有很多中药的配方都有考虑到各种成份之间的影响,以及通过合适的成份配比来降低毒性或使之相互抑制。对于药品的制备也有如炮制这样的手段来处理。根本不是老罗所谓的“便秘时想出来的方子”。

当然由于认识的局限性,肯定会有一些未知的副作用存在,但这不是反对中药的理由。发现了,记录下来,以后避免就是了。西药也一样,西药不也是要作人体实验的吗?这也是一种经验主义,跟中药没什么不同,何况中药比它有几千年的经验。

说一个大家都知道西药的副作用的例子:PPA。

在PPA被发现有副作用之前,它不是一样被当作感冒药广泛使用吗?吃死了多少人又有谁去管呢?

还是令狐说得对,老罗是个牛人,但不表示他什么方面都牛。

唉,Gullibility!

伊拉克民主的曙光

上周日的伊拉克大选终于落下帷幕。据说有72%的伊拉克人冒着被恐怖袭击的危险参与了投票。虽然计票结果还需要一段时间,但是现在的情况已经足已说明伊拉克人们的意愿。

在伊拉克的三个主要民族中,占人口数最多的什叶派穆斯林和北方希望独立的库尔德人对此次大选是充满热情的,而原来萨达姆所属的逊尼派穆斯林却大多表示抵制,据说是因为他们是少数民族,怕受迫害。还是那个杨小凯关于民主和共和的说法,不论是少数服从多数的民主,还是多数服从少数的共和,只要有服从,就有奴役。

对于现在的伊拉克人来说,最重要的事情就是赶快建立自己的政府,结束现在的被占领状态,并且希望能因此减少由此带来的反对占领的恐怖袭击事件–个人认为“反对占领”在很大程度上这只是恐怖份子的幌子,他们更主要的目的恐怕还是想趁火打劫,利用现在的混乱状况扩大自己的影响力,以武力进行争权夺利的斗争罢了。

像中东那样的地方,宗教对于政治有决定性的影响力,因此专制本来就是一个普遍的现象,伊拉克并非特例。只是希望这一次,伊拉克人民可以选出一个属于自己的政府–虽然在政治这个东东上,百姓永远都只能是政客们玩弄的工具罢了。

说到民主,偶想到今天看到的一则新闻:

云南洱海某村的村委会主任,在碰到一伙卖假药者后,将他们礼聘回村,并让他们假扮和尚,在村里的一座庙里坐镇解签骗钱。而村民们则在村头向游客宣传本村的寺庙的菩萨多么的灵,把他们骗到庙里去。每天晚上骗子们“下班”后与村里坐地分赃,双方居然还为此签定了“合同”。

据说国内的大部分行政村的村委会主任都是由村民直选的,算是最“民主”的一个职位了,看了这个新闻我相信了,至少这个村委会主任一定是得到全村百姓拥护的,因为他为本村带来了多么好的经济效益啊,真是为官一任,造福一方百姓啊。

相信这次选举出来的伊拉克新政府也一定可以为伊拉克人民带来滚滚的美元。

BTW:但还有一点小小的希望就是–类似上面那个村委会主任的方法还是不要用的好。^O^