终于搞定了

花了一天时间把数据集对象化的实现基本完成,并写了一篇东东《用DELPHI的RTTI实现数据集的简单对象化》。

顺便参考了Lex CHow的lexlib,实现了一个Object到XML的持久化。不过文章还没写好。:P

这一个休息天用得还算有价值。

不过刚才发给一个朋友看,却被认为意义不大,存心打击偶嘛。sigh~~~

BTW:XML持久化也完成了《用DELPHI的RTTI实现对象的XML持久化

每天一日-奥斯威辛

六十年前的今天,苏军攻占了位于波兰的奥斯威辛集中营。

这个曾经是人类历史最灭绝人性的地方之一走到了终点。

但是其它类似的地方呢?我们有没有记忆?比如731部队。

作弊、英语、就业、整容、游戏……

老方在《关于英语作弊的问题》中提起今年的研究生考试中英语作弊的问题。偶是因为那天要去上体馆跟帮主、色色汇合开本帮常委会,坐在公车上听到乘客们讨论才知道那天是研究生考试,车上的乘客里,除了偶介个FB分子以外,基本都是刚从考场出来的。汗一个。

这种事在这个月已经是第二次发生了,上次便是半个月前的CET考试。又有人通过猫扑泄题了详情)。记得好像去年也是MOP,难怪常有人说现在的MOP已经是小P孩们的天下了。

不过话说回来。考生为什么要作弊?

这不是废话么,比如CET要是没过,学位证就拿不到。

我们对英文的过分要求已经近乎变态了。世界上恐怕很难找出第二国家像我们这样把一门外语看得比母语还重要的,便是殖民国家也不至于这样。就像《英语四六级考试乱象横生 学生汉语水平衰退严重》一文中所说的英语小说翻译大赛的结果那样,绝不是危言耸听。

还有一个问题是没有CET证书、学位证书,工作也不好找。

说到就业压力,昨天一则新闻说最近上海几大整形医院生意兴隆,很多大学生,特别是应届生,纷纷趁寒假之机赶来花大钱大做整形手术。虽然的确有很多用人单位以貌取人,但是作为一个以赢利为目的的企业来说,实力还是最重要的考核标准。正如节目中采访的专家所说:当你选择用整形来改善自己的就业竞争力时,同时也就意味着你在心理上已经放弃了与别人在实力上的竞争,这种做法是不可能达到很好的效果的。

回头来说证书,这其实也是一样的。比如那些曾经很红的MCSE、CCNA之类的证书,现在也不太值钱了。比如前几天给我们公司配路由的那位,好像也是CC口口,一个不算太复杂的路由却配了两天,最后还是找朋友帮忙才搞定。

竞争实力还是来自于平时的学习和积累。求助于作弊可能可以取得一纸证书,但是对竞争力还是没有本质的改善。

那这些作弊的人平时都干什么去了呢?

玩游戏去了……

那我们是不是要打倒游戏?

上周末上视的《1/7》节目采访了陈天桥。记者问起了这个问题,陈天桥说:

这个市场始终是存在的,我不去占领,别人也会去占领。情况不会有任何的不同。而且你们说那些青少年沉迷于游戏夜不归宿荒废学业,那张国荣死的时候还有歌迷也去跳楼的。

虽然我个人对陈天桥没有什么好感,但以这样理由去指责游戏是没有道理的。《网游难道真的猛于虎吗?》一文对这个问题的说法固然不无道理,但是游戏作为娱乐产业中的一项,本来就应该被纳入分级管理中,只是目前国内暂时没有这样的分级制度罢了。

倒是《评论:你找陈天桥干什么》说的更合理一些。重要的还是“如何扶持产业健康发展”的问题。

而在这些问题中嚷嚷得最响的教育界人士们,《评论:网络游戏难道真的是毒蛇猛兽吗》的说法就是给你们的一记响亮的耳光。horse在《道德教育与教育中犹疑》中说到商学院教导学生利润是企业成功的唯一佐证,而忽视了对道德的教育。回头看我们的教育,鲁迅在《死》(《且介亭杂文附集》)中有一段相当于遗嘱的话,其中第七条便是:

七,损着别人的牙眼,却反对报复,主张宽容的人,万勿和他接近。

而在我们伟大的教育产业化中,那些哗哗数钱的人却在教育着孩子们要“道德”。当所有手中有权的人们都在想方设法地为自己或小集体的利益着想时,我们不禁要问:中国教育-谁为你哭泣?

不受监管的权力是不可能不被滥用的。网吧问题就是这样。为什么不取消CET这样的要求?因为它是很多人的摇钱树。为什么总是人有要冒着坐牢的风险去卖考题或当枪手?因为有人为了证书愿意出钱。

唉,都是钱惹的祸。田亮因为只顾赚钱被开除出国家队,郭晶晶又被狗仔队们发现疑似与有钱人家的公子有来往。sigh~~~

用DELPHI的RTTI实现数据集的简单对象化

    在《强大的DELPHI RTTI–兼谈需要了解多种开发语言》一文中,我说了一下我用DELPHI的RTTI实现了数据集的简单对象化。本文将详细介绍一下我的实现方法。

    首先从一个简单的例子说起:假设有一个ADODataSet控件,连接罗斯文数据库,SQL为:

select * from Employee

    现在要把它的内容中EmployeeID, FirstName, LastName,BirthDate四个字段显示到ListView里。传统的代码如下:

With ADODataSet1 DoBeginOpen;While Not Eof DoBeginWith ListView1.Add DoBeginCaption := IntToStr( FieldByName( 'EmployeeID' ).AsInteger );SubItems.Add( FieldByName( 'FirstName' ).AsString );SubItems.Add( FieldByName( 'LastName' ).AsString );SubItems.Add( FormatDateTime( FieldByName( 'BirthDate' ).AsDateTime ) );End;Next;End;Close;End;

    这里主要存在几个方面的问题:

    1、首先是有很多代码非常冗长。比如FieldByName和AsXXX等,特别是AsXXX,必须时时记得每个字段是什么类型的,很容易搞错。而且有些不兼容的类型如果不能自动转换的话,要到运行时才能发现错误。

    2、需要自己在循环里处理当前记录的移动。如上面的Next,否则一旦忘记就会发生死循环,虽然这种问题很容易发现并处理,但程序员不应该被这样的小细节所纠缠。

    3、最主要的是字段名通过String参数传递,如果写错的话,要到运行时才会发现,增加了潜在的BUG可能性,特别是如果测试没有完全覆盖所有的FieldByName,很可能使这样的问题拖到客户那边才会出现。而这种写错字段名的情况是很容易发生的,特别是当程序使用了多个表时,还容易将不同表的字段名搞混。

    在这个由OO统治的时代里,碰到与数据集有关的操作时,我们还是不得不常常陷入上面说的这些关系数据库方面的细节问题中。当然现在也有摆脱它们的办法,那就是O/R mapping,但是O/R mapping毕竟与传统的开发方式差别太大,特别是对于一些小的应用来说,没必要这么夸张,在这种情况下,我们需要的只是一个简单的数据集对象化方案。

    在JAVA及其它动态语言的启发下,我想到了用DELPHI强大的RTTI来实现这个简单的数据集对象化方案。下面是实现与传统代码同样功能的数据集对象化应用代码:

TypeTDSPEmployee = class(TMDataSetProxy)publishedProperty EmployeeID : Integer Index 0 Read GetInteger Write SetInteger;Property FirstName  : String  Index 1 Read GetString  Write SetString;Property LastName   : String  Index 2 Read GetString  Write SetString;Property BirthDate  : Variant Index 3 Read GetVariant Write SetVariant;end;procedure TForm1.ListClick(Sender: TObject);Varemp : TDSPEmployee;beginemp := TDSPEmployee.Create( ADODataSet1 );TryWhile ( emp.ForEach ) DoWith ListView1.Items.Add DoBeginCaption := IntToStr( emp.EmployeeID );SubItems.Add( emp.FirstName );SubItems.Add( emp.LastName );SubItems.Add( FormatDateTime( 'yyyy-mm-dd', TDateTime( emp.BirthDate ) ) );End;Finallyemp.Free;End;end;

    用法很简单。最主要的是要先定义一个代理类,其中以Published的属性来定义所有的字段,包括其类型,之后就可以以对象的方式来操作数据集了。这个代理类是从TMDataSetProxy派生来的,其中用RTTI实现了从属性操作到字段操作的映射,使用时只要简单地Uses一下相应的单元即可。关于这个类的实现单元将在下面详细说明。

    表面上看多了一个定义数据集的代理类,好像多了一些代码,但这是一件一劳永逸的事,特别是当程序中需要多次重用同样结构的数据集的情况下,将会使代码量大大减少。更何况这个代理类的定义非常简单,只是根据字段名和字段类型定义一系列的属性罢了,不用任何实现代码。其中用到的属性存取函数GetXXX/SetXXX都在基类TMDataSetProxy里实现了。

    现在再来看那段与原代码对应的循环:

    1、FieldByName和AsXXX都不需要了,变成了对代理类的属性操作,而且每个字段对应的属性的类型在前面已经定义好了,不用再每次用到时来考虑一下它是什么类型的。如果用错了类型,在编译时就会报错。

    2、用一个ForEach来进行记录遍历,不用再担心忘记Next造成的死循环了。

    3、最大的好处是字段名变成了属性,这样就可以享受到编译时字段名校验的好处了,除非是定义代理类时就把字段名写错,否则都能在编译时发现。

    现在开始讨论TMDataSetProxy。其实现的代码如下:

(******************************************************************用RTTI实现的数据集代理,可以简单地将数据集对象化。Copyright (c) 2005 by Mental Studio.Author : 猛禽Date   : Jan.28-05******************************************************************)unit MDSPComm;interfaceUsesClasses, DB, TypInfo;TypeTMPropList = class(TObject)privateFPropCount : Integer;FPropList  : PPropList;protectedFunction GetPropName( aIndex : Integer ) : ShortString;function GetProp(aIndex: Integer): PPropInfo;publicconstructor Create( aObj : TPersistent );destructor  Destroy; override;property PropCount : Integer Read FPropCount;property PropNames[aIndex : Integer] : ShortString Read GetPropName;property Props[aIndex : Integer] : PPropInfo Read GetProp;End;TMDataSetProxy = class(TPersistent)privateFDataSet  : TDataSet;FPropList : TMPropList;FLooping  : Boolean;protectedProcedure BeginEdit;Procedure EndEdit;Function  GetInteger( aIndex : Integer ) : Integer; Virtual;Function  GetFloat(   aIndex : Integer ) : Double;  Virtual;Function  GetString(  aIndex : Integer ) : String;  Virtual;Function  GetVariant( aIndex : Integer ) : Variant; Virtual;Procedure SetInteger( aIndex : Integer; aValue : Integer ); Virtual;Procedure SetFloat(   aIndex : Integer; aValue : Double  ); Virtual;Procedure SetString(  aIndex : Integer; aValue : String  ); Virtual;Procedure SetVariant( aIndex : Integer; aValue : Variant ); Virtual;publicconstructor Create( aDataSet : TDataSet );destructor  Destroy; override;Procedure AfterConstruction; Override;function  ForEach : Boolean;Property DataSet : TDataSet Read FDataSet;end;implementation{ TMPropList }constructor TMPropList.Create(aObj: TPersistent);beginFPropCount := GetTypeData(aObj.ClassInfo)^.PropCount;FPropList  := Nil;if FPropCount > 0 thenbeginGetMem(FPropList, FPropCount * SizeOf(Pointer));GetPropInfos(aObj.ClassInfo, FPropList);end;end;destructor TMPropList.Destroy;beginIf Assigned( FPropList ) ThenFreeMem( FPropList );inherited;end;function TMPropList.GetProp(aIndex: Integer): PPropInfo;beginResult := Nil;If ( Assigned( FPropList ) ) ThenResult := FPropList[aIndex];end;function TMPropList.GetPropName(aIndex: Integer): ShortString;beginResult := GetProp( aIndex )^.Name;end;{ TMRefDataSet }constructor TMDataSetProxy.Create(aDataSet: TDataSet);beginInherited Create;FDataSet := aDataSet;FDataSet.Open;FLooping := false;end;destructor TMDataSetProxy.Destroy;beginFPropList.Free;If Assigned( FDataSet ) ThenFDataSet.Close;inherited;end;procedure TMDataSetProxy.AfterConstruction;begininherited;FPropList := TMPropList.Create( Self );end;procedure TMDataSetProxy.BeginEdit;beginIf ( FDataSet.State  dsEdit ) AND ( FDataSet.State  dsInsert ) ThenFDataSet.Edit;end;procedure TMDataSetProxy.EndEdit;beginIf ( FDataSet.State = dsEdit ) OR ( FDataSet.State = dsInsert ) ThenFDataSet.Post;end;function TMDataSetProxy.GetInteger(aIndex: Integer): Integer;beginResult := FDataSet.FieldByName( FPropList.PropNames[aIndex] ).AsInteger;end;function TMDataSetProxy.GetFloat(aIndex: Integer): Double;beginResult := FDataSet.FieldByName( FPropList.PropNames[aIndex] ).AsFloat;end;function TMDataSetProxy.GetString(aIndex: In
teger): String;beginResult := FDataSet.FieldByName( FPropList.PropNames[aIndex] ).AsString;end;function TMDataSetProxy.GetVariant(aIndex: Integer): Variant;beginResult := FDataSet.FieldByName( FPropList.PropNames[aIndex] ).Value;end;procedure TMDataSetProxy.SetInteger(aIndex, aValue: Integer);beginBeginEdit;FDataSet.FieldByName( FPropList.PropNames[aIndex] ).AsInteger := aValue;end;procedure TMDataSetProxy.SetFloat(aIndex: Integer; aValue: Double);beginBeginEdit;FDataSet.FieldByName( FPropList.PropNames[aIndex] ).AsFloat := aValue;end;procedure TMDataSetProxy.SetString(aIndex: Integer; aValue: String);beginBeginEdit;FDataSet.FieldByName( FPropList.PropNames[aIndex] ).AsString := aValue;end;procedure TMDataSetProxy.SetVariant(aIndex: Integer; aValue: Variant);beginBeginEdit;FDataSet.FieldByName( FPropList.PropNames[aIndex] ).Value := aValue;end;function TMDataSetProxy.ForEach: Boolean;beginResult := Not FDataSet.Eof;If FLooping ThenBeginEndEdit;FDataSet.Next;Result := Not FDataSet.Eof;If Not Result ThenBeginFDataSet.First;FLooping := false;End;EndElse If Result ThenFLooping := true;end;end.

    其中TMPropList类是一个对RTTI的属性操作部分功能的封装。其功能就是利用DELPHI在TypInfo单元中定义的一些RTTI函数,实现为一个TPersistent的派生类维护其Published的属性列表信息。代理类就通过这个属性列表来取得属性名,并最终通过这个属性名与数据集中的相应字段进行操作。

    TMDataSetProxy就是数据集代理类的基类。其最主要的部分就是在AfterConstruction里创建属性列表。

    属性的操作在这里只实现了Integer, Double/Float, String, Variant这四种数据类型。如果需要,可以自己在此基础上派生自己的代理基类实现其它数据类型的实现,而且这几个已经实现的类型的属性操作实现都被定义为虚函数,也可以在派生基类里用自己的实现取代它。不过对于不是很常用的类型,建议可以定义实际的代理类时再实现。比如前面的例子中,假设TDateTime不是一个常用的类型,可以这样做:

TDSPEmployee = class(TMDataSetProxy)protectedfunction  GetDateTime(const Index: Integer): TDateTime;procedure SetDateTime(const Index: Integer; const Value: TDateTime);publishedProperty EmployeeID : Integer Index 0 Read GetInteger Write SetInteger;Property FirstName  : String  Index 1 Read GetString  Write SetString;Property LastName   : String  Index 2 Read GetString  Write SetString;Property BirthDate  : TDateTime Index 3 Read GetDateTime Write SetDateTime;end;{ TDSPEmployee }function TDSPEmployee.GetDateTime(const Index: Integer): TDateTime;beginResult := TDateTime( GetVariant( Index ) );end;procedure TDSPEmployee.SetDateTime(const Index: Integer;const Value: TDateTime);beginSetVariant( Index, Value );end;

    这样下面就可以直接把BirthDate当作TDateTime类型使用了。

    另外,利用这一点,还可以为一些自定义的特别的数据类型提供统一的操作。

    另外,在所有的SetXXX之前都调用了一下BeginEdit,以避免忘记使用DataSet.Edit导致的运行时错误。

    ForEach被实现成可以重复使用的,在每次ForEach完成一次遍历后,将当前记录移动最第一条记录上以备下次的循环。另外,在Next之前调用了EndEdit,自动提交所作的修改。

    这个数据集对象化方案是一种很简单的方案,现在存在的最大的一个问题就是属性的Index参数必须严格按照属性在定义时的顺序,否则就会取错字段。这是因为DELPHI毕竟还是一种原生开发语言,调用GetXXX/SetXXX时区别同类型的不同属性的唯一途径就是通过Index,而这个Index参数是在编译时就确定地传给函数了,并没有一个动态的表来记录,所以只能采用现在这样的方法来将就。

猛禽 Jan.28-05

[技术贴]强大的DELPHI RTTI–兼谈需要了解多种开发语言

风焱在《“18般武艺”?》中说到他碰上的被多种语言纠缠的问题。我在回复里说:
 很多语言只要能看懂几分就行了,没必要每一种都精通
但是如果只会很少的一两种语言也是不行的。

因为看了一些关于JAVA的反射技术的应用,忽然想到DELPHI的RTTI也很强,于是试着拿数据集下手,用RTTI来实现它的对象化。用了两个晚上时间就搞定了(要不是因为开始时搞错对象–基类用了TObject,其实应该是用TPersistent才对),果然很简单。

假设有一个ADODataSet控件,连接罗斯文数据库,SQL为:

select * from Employee

现在要把它的内容中EmployeeID, FirstName, LastName三个字段显示到ListView里。我通过RTTI实现了一个数据集代理类,使得代码得到大大的简化(这两天争取把结果整理出来另外撰文说明)。其结果大致如下:

TypeTPDSEmployee = class( TMProxyDataSet )publishedProperty EmployeeID : Integer Index 0 Read GetInteger Write SetInteger;Property FirstName : String Index 1 Read GetString Write SetString;Property LastName : String Index 2 Read GetString Write SetString;End;...emp := TPDSEmployee.Create( ADODataSet1 );While emp.ForEach DoWith ListView1.Add DoBeginCaption := IntToStr( emp.EmployeeID );SubItems.Add( emp.FirstName );SubItems.Add( emp.LastName );End;emp.Free;

对比传统的实现代码,好处是显而易见的。

但是当我实现出这个TMProxyDataSet类后,不禁感到痛心疾首,这个我早在三年前就应该想到的。

三年前DELPHI6刚推出时,我就发现它的SOAP功能是通过DELPHI强大的RTTI来实现的,我为什么当时没有想到去深入研究一下DELPHI的RTTI呢?

这次要不是因为看到了一些JAVA的资料,我可能还是想不到,所以多了解一些别的语言是很重要的事。特别是最近以来,动态语言越来受到关注,虽然它们在性能上不能跟原生开发相比,但在很多的开发思想上,具有重要的启发意义。

在做了这个东东以后,我才意识到,DELPHI其实是所有原生开发语言中,动态性最高的,并不比基于虚拟机的JAVA和C#低多少。只是长期在做RAD的开发,没有体会到而已。程序员在RAD下被惯坏了。

做完这个,我打算下一步再试试用RTTI实现对象的XML持久化(基本上就是抄袭一下DELPHI本身的SOAP实现代码-_-|||)。这个思路应该会比我原先用的XML Data Binding要方便很多,至少不用再去写那个麻烦的XML Schema了。

BTW:以前没有太关注RTTI,效率恐怕是其中最重要的一个原因,但是现在看来,跟虚拟机语言甚至动态语言相比,DELPHI作为原生应用开发,这点RTTI效率损失其实根本没有想像中那么大的影响。换来开发效率的大大提高还是很值得的。

BTW:抄了令狐的一段CSS(<pre>)。^O^

草根–另一种精英

智识在《Grassroots是“草根”吗?》一文中对“草根”一词咬文嚼字了一番。看了以后恍然大悟,敢情偶们自诩为“草根”,闹了半天原来不是。最多只能是相对于方博士之类的精英人士来说,更加“草根”一些罢了。鹤冲天在《“草根”与 blog》对“草根”一词作了一个调查,发现它是在最近三个月里忽然流行起来的。这也说明了它在很大程度上是一件被用来与商业抄袭者对抗的武器。

坦白说,在两周前mblogger当机事故之前,我几乎没有去看过mblogger以外的Blog。就如Qenghis的《Blog的分类聚合效应》》所说,我就是被聚合在mblogger这个圈子里。当我被迫从这里走出去以后,才发现外面有一个热闹的“草根”VS“精英”的世界。这事是以方博士为代表的少数人企图在Blog世界里制造话语霸权开始的,而以“草根”们为代表的多数人则喊出了“我不是博客”的口号。

那么这个被双方所争权的“话语权”又是什么?

KESO在《骂并被骂着》中所说:

中国人对自由,尤其是言论自由的理解,基本上就是骂人的自由。

对于网上骂战,我在BBS上–比如CSDN的水园–就常可以看到,双方或多方互扔板砖,场面壮观。而对于BLOG的了解也差不多是从骂战开始的:去年刚开始写BLOG时,便听闻不久前博客堂与CoDelphi的对骂。这次事件的后果就是使很多人对部分打着MVP金字招牌的人的RP产生怀疑。

骂人–特别是在网络上–一向是一件很“民主”的事情,这可真是人多力量大,少数人不敢不服从多数。还是Qenghis,在《话语权中的多数人暴政》中说到:

“多数人”并不一定是最理智最正确的人,而多数人一旦就某个问题达成错误的共识,这一共识却极有可能是控制性的。

Tinyfool在后面的回复里也引用了已故经济学家杨小凯关于民主和共和的说法,来证实他的说法。

我在《BC, BD及其它》中曾经说过:精英们垄断BLOG话语权的企图是注定要失败的,他们可以强抄走文字,但话语权还是在文字背后的Bloggers手里。

只是现在看来,这种掌握在草根们手里的话语权未免有些被滥用的嫌疑,比如那种煞有介事地宣称”我不是博客”。Horse说,如果一定要给blog一个中文名,请称呼它为“网志”,我觉得是没有必要。对于Blogger来说,对于什么是Blog,大家心里有数,叫什么中文名无关紧要。愿意叫“网志”还是“博客”是人家的自由,并不是说用了“博客”这个词,就成了方某的Fans。而对于没有实践过BLOG的人来说,跟他们讲BLOG则纯属“对牛乱弹琴”

回顾我最近一两周的BLOG,和以前相比,明显受到草根领袖们的影响,越来越热衷于“热门话题”的讨论。但当我加入这些讨论,成为草根们中的一根后,却忽然发现,其实在对话语权的争夺上,我们与精英们没有什么不同。

重新审视我走出mblogger之前的时光,在BLOG世界中,除了对战的“精英”和“草根”之外,还有为数更多的Blogger们,只是在默默地耕耘着自己的一亩三分地,并不在意于自己的言论造成了多大的影响。

话语权其实就素那浮云。

把视线放到BLOG以外,这个世界上比“草根”们更没有话语权的人还有很多很多。孙志刚之前难道就没有类似的事情发生过吗?只是那些人和他们的亲朋好友都是连“草根”都不是的“泥土”。

我不是博客,也不是Blogger,只是一个八卦的logger–8logger

BTW:写介种东东比较容易招骂。:P
8过偶们应该在在骂声中茁壮成长嘛。
这些年来,网上骂人的水准还是没有很大的长进,大多数人还是只会人身攻击一种招数,我在CSDN发的文档有几篇的回复里多得我都懒得看,乏味得很。

简单8log(追加)

复杂的8log还没有8完,先发一个简单的。

网通的代理商昨天在这里配了一下午也没有配置好我们的路由,上午他们又找了一个高手过来,情况果然比较好一些,偶们三个人试了半天,总算是把这条路由给配通了。为了安全起见,偶又上网找了一些资料,把路由的密码给改了,不然昨天那个家伙联系了N多朋友帮忙,已经不知道多少人知道偶们的路由器密码了。-_-|||

看了刺猬的MSN ID才想起来今天是shari的生日。

shari生日快乐~~

还有南南的MSN ID,原来她已经回国乐,估计回来筹办婚事吧。^O^

唉,又8挂乐。-_-|||

BTW:某些小宁极其8厚道地抛下大叔,独自去偷欢。TOT

从3721到8848

对于最近的百度VS8848事件,偶本来是没打算掺和的。无非是炒作而已。

但是今天KESO的一篇《比无间道还要凶险》说明了一下8848导演此次事件背后的技术内幕,这让作为技术人员的偶感觉很不舒服。

如题所说,之前一次不舒服是3721。

技术不应该这样被无耻地运用的。

不可否认,作为一个企业,为追求自身利益的最大化,可以不择手段。但从更大的范围,比如国家来说,应该追求的是整体利益的最大化。所以我们要谈环保,谈可持续发展。正如Tinyfool在《别了乌托邦,别了wiki,兼谈黑道的本质和发展问题》一文里说过:黑道是一种可持续发展之道。而如3721,百度,8848们做的,却无一不是通过近于黑道的手段进行的。

3721被NORTON认为是病毒,因为它具有病毒的几乎所有特征。现在这种病毒又多了一个:8848。还好偶用FireFox不用担心这类的病毒。^O^

正是因为有像3721这样的榜样,才有了8848现在走这条路。以后还不知道会有什么1234,9876之类的。

世上本没有路,走的人多了,便也成了路。

据loverty在《8848的瞎咋呼与Blogger的传播》一文中称,现在的8848跟3721还颇有渊源。难怪如outback说,正因为有了第一家3721这样做了,不仅没有得到惩罚而且受益颇丰,所以后来者8848才如此相仿。商业环境就是这样被破坏的。

可持续发展,意味着资源循环再生的链条被破坏。这种杀鸡取卵式的的做法是以牺牲长远发展的代价来换取短期的利益。

我曾经说过关于软件业中存在着这样的环境问题,现在看来,整个中国IT业都是如此。甚至在某种程度上说,整个中国的商业环境都存在这样的问题。正是在这样一个商业道德缺失的环境下,诞生了一批这样的topku所说的“怪胎”

其实也很难说是环境造就了“怪胎”还是“怪胎”形成了环境。只是如果类似这样的做法得不到抑制,整个经济系统的未来的发展都会成问题。

版权意识

这两天的RSS收藏里,最多的就是关于8848与百度的纠纷问题,对这种狗咬狗的事,还是不作评论了。除此之外,还看到hibernator的一篇《常识与创新》以及keso对此的评论《创新的价值》。

在hibernator那的trackback里,我看到一个来自CSDN BLOG的PING,就过去看了一下:也叫《创新的价值》,一字不差地照抄keso的。

在keso的BLOG上,有一个Creative Commons的图标和相应的文字说明:“除非特别声明,本站采用Creative Commons License。”其链接对应的是:CCL下的署名及非商业应用。即意味着,如果转载keso发在BLOG上的文字,必须署keso的名。

但是可以看到,CSDN的那位不但没有署keso的名,连个“转载”都没写,如果不是因为从hibernator那里过去,肯定以为是那个人原作的了。

昨天,CCTV-6播了中国电影导演协会的一个颁奖礼,其中冯小刚带着一帮导演锤烂了一张像征性的盗版光盘,以示对盗版的声讨。

偶也是有用盗版的,灭资格说别人。

不过商业协议毕竟有一个MONEY的问题在那里,还可以找一个“没钱”的借口。像CCL这样的非商业协议,只是要你署个作者的名字,这也这么难吗?我想应该还是那位转载者心里根本没有这种意识罢了。

BTW:声明一下,偶的BLOG用的License是CCL中文版的署名、非商业及保持一致。^O^