SUMTEC -- There's a thing in my bloglet.

But it's not only one. It's many. It's the same as other things but it exactly likes nothing else...

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  220 随笔 :: 19 文章 :: 2014 评论 :: 22 引用

2009年5月31日 #

这个问题,我老早就想做调查了,苦于博客园一直没有投票系统,我就憋啊憋,终于忍不住了。

我的问题如下:

1、您所在的项目开发中,整个项目/系统的“非空白、非注释”源代码有多少行?而注释一共有多少行?(意思是,注释多吗?我所知道的是,越大的系统注释应该越多,有的时候甚至可能达到1:1)我想这个问题,随着代码规模的增长,总被注意的。但是接下来的两个问题就不一定了。

2、项目/系统中,一共有多少个xml(或者类似的)配置文件?有多少个独立文档(不是代码中的注释)来解说这些问题?(意思是,你的配置文件受到了重视了吗?没有?是否在后来就没有人搞清楚一些很久的文件该如何配置了?是否后来还有人新开了一些配置文件,完成或者部分完成原有配置的问题?是否后来你也搞不清楚到底哪些配置是有用的,那些是没有用的?你知道某一个配置,实际上是受哪一段代码的管理吗?)

3、项目/系统中,一共有多少个独立的开发辅助文档(或者说教材)?(或者,多少行代码有一个这样的独立文档?这标志着,教育新员工的痛苦指数。通常,缺乏教材,也会缺少Sample代码。当然了,可以让新手直接进入某段事迹的代码,但是这样效率高吗?另外,是否有很多很底层的东西,没有几个人能完整说清楚呢?随着这些人的离开,整个项目陷入风险的程度有多大?)

4、项目/系统中,一共有多少个开放给第三方的接口?是否每一个都有一份受管理的完整独立文档?(或者说,这些第三方接口,是否都是清清楚楚的,比如,哪些已经被废弃了,哪些还在被哪些第三方所使用?)与此类似的有,你所使用的第三方所提供的接口以及与之相关的文档都受到管理吗?还是开发完就不见了?

5、项目/系统中,一共有多少个数据库(及其表格)?是否每一个都有独立文档说清楚每个表、每一列的定义和含义?(或者说,是所有表和列都还在用吗?被那一部分的代码使用?)

 

第一个问题不好说,后面四个可能几乎为零,我猜错没?请踊跃说一下各自的情况,好看一下我们的大环境是如何的。

posted @ 2009-05-31 15:04 Sumtec 阅读(1718) | 评论 (27)编辑

(这一篇更早了,两年前的了,也是写一半没完成,赶紧拯救出来。)

一个公司宛如一只球队,成败不是一个人的事情,是一整队的事情。那么球队在某一场具体比赛里面最重要的角色是哪一个?不是教练,如果说整个赛季如何可能是教练的功劳。如果是某一场比赛,最重要的角色是中场。对于公司也有这么一个中场的角色,不过不是老总,而是具体的那个产品经理。

其实产品是否成功,部分取决于总体效率如何。我把效率分为两个部分,一个是工作效率,一个是规划效率。

工作效率很好理解,就是每个工时的投入产出比。提高工作效率很好描述:如果我们以每一个人为坐标轴来观测,就是要求每个人都有合适的负担,不能够某个人负担过重,更不能某个人负担过轻;如果我们以每一天为坐标轴来观测,就要求每一天都有合适的负荷,不能一天忙死,一天闲死。合起来很简单,就是说每一个人每一天都要有合适数量的工作去做。

但是工作效率高了,不代表总体效率就高。比如说每天都在做,但是今天把昨天的推翻了,明天又把今天推翻了,那就是在瞎折腾。所以我们还要有规划上的效率,保证不会出现类似的情况。上面说的那种瞎折腾看起来好像不可能整天发生,但是实际上在我们面对变化的需求时,就会遇到这样的事情。

现代的软件工程是如何保证效率的呢?

从工作效率来讲,就是尽可能准确的给出每一个任务需要的时间,然后根据这个时间给出一个时间线(Deadline)。当然,不准确是必然的,于是还可能会中间有些CheckLine来避免无法完成任务的情况到最后快结束时才爆发,然后就是加班加班再加班。Checkline订多长合适呢?一星期?我个人认为确定每一天的计划更为合理,如果做不到,那么两三天也比一星期强。因为有的时候你会发现有的人做了一天还是好像没有什么进展似的,可能性有三个:要么规划得不好,没有自行细分更细的CheckLine;要么就是觉得得过且过,到那天再说,不急;要么就是能力不济,到最后都是这样。这三种情况我都见过,因此更紧密地时间检查周期是很有必要的,至少可以及时看出到底出了什么问题,可以有更大的余地进行有针对性地调整。

而规划效率呢,则需要准确区分新增需求、对旧有需求(设计)的改进以及对旧系统Bug的改进。作为项目经理,这几个概念是需要严格区分的,否则会产生很大的问题(这我也经历过)。

对于Bug,无论任何时候都是需要及时修改的。那么什么是Bug呢?就是系统的实际执行情况,和原来定义的设计是相违背的,或者对于没有定义的部分,是超出常规思维方式或者逻辑上有矛盾的。与此概念最容易混淆的,是对旧需求(设计)进行改进。我们经常会听到用户会反馈类似这样的抱怨:这个文本编辑器非常的不好用,我想要他固定一个具体的大小,它却只能够设置“大中小”,而且还会随着用户的操作变大变小;那个上传图片的地方也很不好用,只能一张一张照片的上传。那么面对这样的问题,我们可以很简单的将它和Bug区分开来:想一下这是当初就这么定义的呢,还是说定义的和用户一样,只不过开发人员弄错了?要区分Bug和需求改进,还有一个很重要的原因,是修改Bug和需求是完全不一样的。修改Bug的时候,只需要告知程序员哪个地方错了即可,而修改需求,则需要很多前期的工作,例如确定需求、制定UE、制作UI、套UI、修改代码等。通常情况下,修改需求都可以“转化为”新增一个需求。

而需求方面的新增和改进,则应该在新一个迭代之前收集,迭代开始阶段进行设计,然后进入开发阶段的时候就不应该再随意的更改了(除非证明设计有严重缺陷)。如果不这么做,你就会经常体会到今天推翻昨天的代码的情况。软件工程有讲,软件开发的整个过程中,越到后面进行修改,成本就越高。这里隐含着一个意思,就是越到后面出现的改动,你的沮丧情绪也越严重。这对整个团队是非常有伤害的。当然了,这也要求我们的中场,能够坚守立场不动摇,同时在开始开发之前,认真做好设计。

然而这些并不是做好中场的全部,中场还有一个重要的功能是把前后场联系起来,起到承上启下的作用。如果我们把系统限定为软件开发,则后场是UE、UI人员,前场是开发人员。此时中场的一个重要职责是,确定好后场的UE、UI制作是否按时完成,是否达到了前场开发人员能处理的质量水平。有的时候因为各种原因后场过来的东西,开发人员是无法处理的,例如没有切图而把整个页面的PSD给发过来了。中场就要检查和避免这种情况,如果你听UI说做完了,你就认为做完了,那是很不负责任的。最后,你的工作也可能因为这样的原因被拖了进度。

如果我们把系统限定为整个公司的范围,则后场是开发部门,前场是销售和客服部门。这时候,一定要想办法尽量减少前后场直接来回的情况。原因是,一个这样会有很多复杂的路径存在,到时候责任人不好理清楚,响应速度也可能很慢。另一个原因是,前后场直接开大脚,质量很难控制。比如说客服接到反馈说文字编辑器很不好用,直接就告诉相关开发人员,开发人员马上就开始修改了。这样做有很多比较要命的缺点:1、所有任务的优先顺序可能无法控制;2、开发质量无法控制;3、没有任何的设计就直接上去了(多数开发人员在这方面确实很差)。也许中场很忙,会有太多的事情做,那么这个时候也需要交由一个专门的副手来执行着一个工作,而不是前后场大脚乱踢。

如果你的职业规划中,未来有一段时间是要做中场的,那么上述的这类概念则必须要清楚。我不知道你的经历如何,就我的经历而言,违反上述规则的很常见。甚至有的时候,在某些地方我会被告知那样做是理所当然的(其实对方也说不出是个什么理,只是强调就是这样的,这就对了)。您认为呢?

posted @ 2009-05-31 12:58 Sumtec 阅读(1351) | 评论 (2)编辑

(又翻出来一篇一年多以前的半成品,赶紧给补充完整放出来。)

最近终于得以试用Linq to Sql了,刚开始用,感觉还挺不错,因为一切都显得很简单。也许是我还不太熟悉,所以也有不少的困惑。别的先不说,只说一个:“有状态的”实体类。

Linq to Sql 所创建出来的实体类本身并不是有状态的,有状态的是DataContext。但是正是这个有状态的DataContext,造成了实体类也带上了“状态”。对于一般的桌面应用,或者是结合得比较紧密的Web程序,这还不是什么太大的问题。但是如果我们考虑一个分离得比较充分的N层结构,比如说通过WebService提供数据层或者应用层的服务,这就有问题了。例如有一个ModifyCustomer的WebMethod:

[WebMethod]
public void ModifyCustomer(Customer customer)
{
  
// 
}


由于Customer是反序列化得来的,并不在DataContext的监管中。因此在调用DataContext.SubmitUpdate()的时候,这些对象是无法进行更新操作的。同时DataContext并没有提供一个直接的方法,来进行Update的操作。

这个问题在英文网上还真是有一些讨论,解决的方法就是用DataContext.Attach。在这之下还有两种方案:
1、
[WebMethod]
public void ModifyCustomer(Customer customer)
{
  
// 
  XXDataContext dtx = new XXDataContext();
  dtx.Attach(customer, 
true);
  dtx.SubmitChanges();
}

2、
[WebMethod]
public void ModifyCustomer(Customer modified, Customer original)
{
  
// 
  XXDataContext dtx = new XXDataContext();
  dtx.Attach(modified, original);
  dtx.SubmitChanges();
}



然而这两种方法都有各自的一些缺陷。首先说第一种方法,这种方法由于把该实体类强制设置为“已修改”状态,于是就要求该实体类要么有一个时间戳字段,要么就是要求该实体类所有字段都不进行“更新冲突检查”。显然后者是难以接受的,尤其是在一些较为关键的数据表当中,一旦冲突后还允许更新会出现灾难性后果。而前者则要求改动数据库的物理设计,有点为难没有数据库物理设计权限的开发人员。而且即使这样改动,似乎也只能够保证检测出任意的冲突,而在互不相干的改动中是不能认为没有发生冲突的。举个例子:
Client FieldA FieldB TimeStamp
(Original) A B 0
User1 A1   1
User2   B2 Conflict!

如果两个客户端都在对Customer表进行修改,其中User1的客户端修改了FieldA,User2的客户端随后修改了FieldB,这个时候用时间戳判断法,就会被系统判定为冲突。因为在强行向DataContext中塞入一个User对象的时候,这个User对象的所有属性并没有有效的“原值”,或者说认为所有属性都被修改了。数据库更不可能有修改前数值的记录,因此对于DataContext来说,只能当作所有值都修改了,因此自然引发了冲突。但是实际上我们可以看出来,这种情况下并没有任何实际上的冲突,是可以更新的。

而第二种方式呢,看起来可以解决上面的这一个问题。但是,即使抛开需要多传一份对象不说,也会造成客户端变得比较复杂。我们可以想象,客户端中调用Web服务获取原始对象的代码,与更新对象的代码很可能根本就不在一个函数内,甚至不在一个调用堆栈上。比如说我们想象一下,客户端实际上也是一个网站,某个网页需要列出当前用户的一些信息,并允许浏览者对某些属性进行一些修改。那么很明显,获取原始用户对象的Web服务调用是在第一次页面访问上的,而更新用户对象则是在第二次访问过程中的。因此,我们必须在第一次访问的时候,将所有可能会被更新的对象都保存到Session里面,以供更新的时候将这些原始对象回传到服务端。这样做会极大地增加客户端设计的复杂度,也不见得很好。

更麻烦的地方是,Linq to sql里面的每一个对象都是设计器自动生成的,那些打上去的标记一不小心就会被丢掉!在我看来,LinqToSql的设计以及自动代码生成过程,对于WebService/WCF的开发来说,还是比较不友好的。不知道各位以为如何?

P.S.: EntityFramework我也小试了一下,有些东西确是比Linq To Sql好用一些,不过似乎这个问题还是没有很好的解决,如果有这方面经验的请赐教。此外,我觉得EntityFramework取消了Log机制,使非常可惜的一件事情,使得一些Sql性能方面的调试不太方便了,恢复到了要用Sql profiler的时代。而我在用Linq to sql做开发的时候,设计了一套能即时开关,并且可设置针对某一特定Session还是所有访问的Trace系统,使得有问题发生时,可以立即在线上查看,而不需要将整个环境(包括数据库相关部分)Dump下来在调试环境下恢复,然后再进行调试(包括Debug和Sql profiler)。可是在EntityFramework下面,这种方式似乎就不太好使了。

 

___________________

P.S.: 发布到首页还是有Bug,就是保存草稿也算时间。

posted @ 2009-05-31 11:12 Sumtec 阅读(1330) | 评论 (12)编辑

老久不上来写技术类的东西了,偶尔回归一下吧。(其实,这篇文章8个月前写了个大半,后来一直没有时间去完善,再后来就因为各种原因给放下来了。)

非常抱歉,由于需要发表其他文章的缘故,我只能忍着不修正文中一小部分错误,以及增加一些有助免于误解的内容。这里特别说明一下,本文不是要讨论缓存机制的好坏,更不是要讨论如何缓存对象。而是说DAL/BLL上面对DataContext的处理。另外一个需要注意的地方,是修改了一个错误,原来大部分都写成IQueryable了,实际上应该是除了最后一个之外,都是IEnumerable。原因是什么需要大家想一下。此外,也需要大家注意的事,我所提出来的缓存,并不是直接利用Linq2Sql的代码来缓存,而是指是否便于缓存。这部分的内容,会在文章后面补充说明。

Linq to Sql 用的人也应该有些吧,我在cnblogs上面看老赵写的那几篇文章(请看08年9月左右的文章),感觉也很有深度,有不少启发。因此我也打算写一点我自己的实践经验,希望也能同样给大家一些有用的启发吧。

我首先想要问一下大家,Linq to Sql有哪些很特别的地方?这个问题的答案肯定五花八门,我说一下我看到的一些问题吧。

首先,Linq to Sql的基础之一是DataContext,而另外一个基础,则是通过映射产生的实体类,以及这些实体类的Table<>对象。这个不是废话嘛!我想很多人都应该知道这个最基本的知识,不过却不见得有多少人真正注意到,或者认真思考一下这里面的“机关”。不知道“机关”在哪里,那么就不可能写出合适的代码。比如说,在某个页面里面(N层结构没有给弄好的情况下),或者在某个业务逻辑里面(有N层结构),你的Linq to Sql的代码是否是长这样的?

Code

 

“对啊,就是长这样的,有什么问题吗?”当然有问题啦,否则我也不写这个随笔了。不知道大家有没有想过这么一个问题,什么叫做Context?Context就是上下文,上下文的意思就是,依赖于这个上下文的对象,必须存活在这个上下文里面。脱离了这个上下文,那些对象就会出现错误。事实上也确实如此:在上面的例子里面,从ProductInfos中得到的q.ToList(),里面的每一个元素都依赖于MyDataContext。换句话说MyDataContext如果被注销了,q.ToList()生成的对象也就会“部分功能失效”。

“失效就失效好了,反正该做的工作已经做完了,q.ToList()也已经利用完了。”不错,在上面的例子里面,不会发生什么错误。不过这么写的话,会比较难使用的。为什么这么说?我举一个具体的例子:这个网站需要用户登录,而所有的业务逻辑几乎都依赖于当前用户。如果说,我们使用上面的using模式,那么我估计你的代码不外乎是如下两种情况:

1、每一次需要当前用户的地方,你都需要从数据库读取;或者

2、你把当前用户保存为全局变量了,但是你发现currentUser.CompanyInfo因为上下文已经抛弃了,因此是无法使用的,业务层不得不每一次都重新从数据库读取该用户所属公司的数据。

这两种形式如下所示:

 

Code

 

如果你是第一种情况,那么很明显,你会有大量重复的SQL调用。

如果是第二种情况,其实也不见得好到哪里去。因为:

1、currentUser可能不需要经常取,但相关的其它内容,由于上下文各自独立,你还是经常在重复的获取的;

2、有一个地方你无法绕过去——如果你要修改当前用户的属性,而这个全局的当前用户不是当前Context产生的,你还非得从当前Context取出来,然后再修改;或者如果你企图通过currentUser.CompanyInfo来访问的话,也会报错。

3、因为currentUser的上下文已经被抛弃了,因此程序会很容易设计成传入的不是一个UserInfo,而是一个int类型的Id值,否则底层很容易一不小心就用到这个实际上功能不全的对象,然后就抛出异常了。但这样做的后果是,获取同一个类型的实体对象,可能会有各种不同的重载形式,例如:

IEnumerable<TransactionInfo> GetTransactionsByUserId(int userId);
IEnumerable
<TransactionInfo> GetTransactionsByCompanyId(int companyId);
IEnumerable<TransactionInfo> GetTransactionsByCompanyId(int companyId, EAccountName account);
IEnumerable<TransactionInfo> GetTransactionsByCompanyId(int companyId, EAccountName account, ETransactionType transactionType);

因为这种设计实施之后,有时很可能就会出现只有userId的情况,那么这个时候即使UserInfo对象中其实也存在CompanyId的值,也还是要重新获取一遍UserInfo对象。(注意,后面提到的方案,并非不需要缓存了,而是因为在同一个Context下,可以有效地利用实体对象,因此你可以将BLL层设计依赖实体对象,而不是id值,因此缓存整个实体对象会更加容易。)为了简化这一过程,就可能会产生不同的获取形式。

这样设计完整个系统之后一跑,看着好像没什么,但真正上线却发现有点慢。当我们打开Sql server的Profiler一看,会发现很简单的一个页面的访问,其数据库访问会搞到几十次甚至上百次,其中有很多Sql语句是完全重复的。

这个问题怎么解决呢?有人会说,加个缓存机制吧。也许吧,但这种增加复杂度的设计,我觉得还是不得已而为之的一种做法。(或者说,缓存很好,那是另外一种解决方案,但不解决这个问题。)我认为更好的解决办法是,将上下文在当前页面中缓存起来。所谓的上下文,就是一种运行环境,而一次页面访问,其环境应该是相同的。首先,我们对MyDataContext做一个扩展:

 

Code

 

然后我们再制作一个HttpModule(并且在web.config里面配置好):

Code

 

接下来,我们只要在逻辑层这么直接写即可:

 

Code

 

这么改造完之后,你会发现几乎可以在所有地方直接返回IEnumerable(除了有的时候Linq to Sql本身有Bug),整个逻辑层内的设计变得简单化:一开始检查各种参数(是否具备完整或者部分权限),然后根据检查结果做完全信赖的操作。由于返回的是实体对象,或者IEnumerable,几乎所有重复性的Sql调用也随之自然消失了。如果有所怀疑的话,您可以用Sql Profiler自行做修改前后的对比,看看效果是否“惊人”?

也许有人会质疑,这样好吗?岂不是通过user.Company.Transactions就可以得到所有的Transaction了?没错,如果所有东西都是公开的话,就会有这个问题。如果要彻底解决这样的问题,需要将这些部分变成对逻辑层可见,而对其它层不可见的修饰方式——比如两层在一个dll里面,这些属性是internal的,或者放在两个dll里面并且打上InternalsVisibleTo标记。通过这种方式,就可以避免上层直接查找DAL中一些在BLL中需要经过权限检查才可以得到的内容。当然,如果项目比较小的情况下,你也可以选择不要这么麻烦,直接控制代码质量即可(要求有些东西必须通过BLL来获得)。

_________________________________________

后记:

因为中间跳过了一些产生问题的步骤,引起了不少的误解,这里特别解释清楚:

1、原方案因为不在同一个Context之下,所以返回的实体对象是不分功能失效的。考虑:

_user = BLL.GetUser(HttpContext.Current.User.Identity);

这样的缓存,由于DataContext在GetUser中已经抛弃了,因此,_user.Company这样的访问就会报错。最终你更可能选择,要么全面放弃实体对象之间的关联属性,要么就只是缓存userId。无论哪一种方案,都意味着,当你缓存userId的时候,是不会自动缓存对应的CompanyInfo的。(这么说明报了吧?这才是我说的,可以自动缓存的意思。)

关于这一部分的误解,回复中有一个例子:

public static T_User TestMethod2()
{
    return dbUserDataContext.CurrentHttpContext.T_User.FirstOrDefault();
}

//调用代码
for (int i = 0; i < 5; i++)
{
    BLL.dbUser.TestMethod2();
}

这样显然是会重复发出Sql调用的,这不是我说的场景,我说的是:

public static T_User TestMethod2()
{
    return dbUserDataContext.CurrentHttpContext.T_User.FirstOrDefault();
}

//调用代码

_user =  BLL.dbUser.TestMethod2();  // 缓存
for (int i = 0; i < 5; i++)
{

    Debug.Writeline(_user.Company.CompanyName); // 这个时候Company就不会不停的调数据库
}

从这个角度来讲,我并没有讨论如何缓存,而是讨论的如何便于缓存,如果在不需要过高性能要求的情况下,不动用完整的、同时也很复杂的缓存机制。

 

2、我们再看另外一个例子:

http://www.cnblogs.com/JeffreyZhao/archive/2008/02/19/using-translate-method-and-modify-command-text-before-query-in-linq-to-sql.html

public List<Item> GetItemsForListing(int ownerId)
{
    ItemDataContext dataContext = new ItemDataContext();
    var query = from item in dataContext.Items
                where item.UserID == ownerId
                orderby item.CreateTime descending
                select item;
 
    return query.ToList();
}

大家可以看到,这个设计里面,返回至十一个ToList(),也就意味着已经从数据库中取出所有对象了。但是有的时候,我们实际上希望在这个基础上再进一步收缩。在这种情况下,我们就不能很好的重用原来的代码了,因为这个函数返回的是一个组内存对象,而不是一个IQueryable的表达式。那么我们要么在这个List<Item>结合中在内存中进行过滤,要么重新写一个方法来处理。无论如何,这都导致了BLL层的臃肿。如果是如下的写法呢:

public IQueryable<Item> GetItemsForListing(User owner)
{
    ItemDataContext dataContext = new ItemDataContext();
    var query = from item in dataContext.Items
                where item.UserID == owner.Id
                select item; 
    return query;
}

注意,我连order by 也去掉了,因为这完全可以在更上一层再决定如何处理。同样的,我也可以在这个返回值得基础上继续做进一步的筛选。而这种筛选无论在BLL还是更高层次来做,都会有着更高的效率。(说到这里,我也不得不担心,有人会说,这种筛选应该被封闭起来。这部分是另外一种讨论了:BLL到底应该封装到什么程度。这里不作过多的争论了,我们假定轻量级的BLL更有灵活性。不过如果非要争论,我会说:首先,原来的设计,你也无法避免UI层用这个函数的返回值来做自己的筛选和处理;其次,我的设计,也完全可以在BLL提供进一步的标准筛选函数。因此这也并非我要讨论的内容。)

那么,这么做有什么好处呢?最大的好处是,提供同样级别功能的BLL情况下,我的设计更可能只去所需要的数据——严格的说应该限定为,在只访问一次数据库的情况下。其他情况下也有可能和原来设计一样,需要依赖缓存来提高性能。不过实战情况下,可以发现这么做之后一般都是获取更少的数据。

无论如何,减少从数据库取出的不必要数据,肯定是一件好事。如果加上缓存机制的话,更少需要缓存的数据,也可能提供更高的效率。

3、有一点不需要多说了,就是如果要加入缓存机制的话,在同一个Context下面肯定比在不同Context下面好处理得多,最简单的一个原因,就是不需要考虑Detach和Attach的问题(偏偏Linq2Sql不存在Detach的方法,除非你自己做每一个对象的深拷贝工作,这拜Linq2Sql的Tracker所赐,具体这也不讨论了)。

 

回复中还有一种说法,认为可以尽量将操作都封装到BLL层,例如:

using (new context)
{
receiveRelatedData()
using (new tansation)
{
action1 (context);
action2 (context);
action3 (context);
}
}

例子中,并没有很清晰的指出,是整个代码在BLL中呢,还是只有receiveRelatedData和actions是BLL。无论如何,我想这是另一个问题了,就是BLL应该复杂到什么程度。我个人的理念是:在保证逻辑完整的情况下,尽量提供最小的原子操作,让上层自由互相组合。这样可以避免BLL越来越臃肿,甚至有一些功能会逐渐被抛弃,进而被遗忘的问题。例如,我会提供获取当前用户、某用户购买一个产品,这样两个原子操作,来达到当前用户购买产品的目的。否则,可以想象,让如果要让管理员强制另一个用户购买一个产品,将会需要另一整套的逻辑。而按照我的思路,只要设计一个管理员获取另一个管理员,以及代理权限系统即可,而不需要连后面的购买过程也封装起来。或者说,前一种思路容易导致BLL函数数量呈N*M的方式增长,而我的思路则是尽可能让BLL按照N+M的方式增长。(这个如果要讨论的话,还是另外开篇把,这里可能说不完。)

不过即使是这样,我也没有看出为何不可直接将Context缓存起来?比如:

receiveRelatedData(CurrentContext)
using (new tansationScope())
{
  action1 (CurrentContext);
  action2 (CurrentContext);
  action3 (CurrentContext);

还是一样可以跑得通吧? 

简而言之,本文并非否认缓存机制的作用,更不是要替代缓存机制。与之正好相反,这里面是要让缓存变得更容易一些,同时在一定范围内,提高不使用复杂缓存机制时的效能,推迟系统变得更复杂的时间。

 

 

posted @ 2009-05-31 09:09 Sumtec 阅读(1798) | 评论 (56)编辑

2009年5月29日 #

前面提到了一个很麻烦的问题:问什么有人真愿意花时间做租用首页并四处搜寻合适的内容?

赚得博客园货币——比如叫博元,是我们的设计的动力系统,但是这个博元的内在价值,却是动力大小的根本问题所在。前面的回复中有人提到,这种虚拟货币没有任何价值,除非和RMB挂钩。这个说法可以说是有一定的道理在里面,不过不精确。CSDN中的积分,也就是一种不挂钩的货币,网游中的货币也不挂钩。可是它们仍然是有效的,因为他们仍然衡量出价值——只不过基本上衡量出一个被认同度价值,或者难听点要说是虚荣心也行,总归它仍是有效的。不过,这样的封闭体系,其逼近价值的能力可能是有限的,或者是有偏向的。具体的,作者这篇文章如果出版价值几何,恐怕很难通过博元来衡量。要解决这一类的问题,恐怕需要和RMB扯上关系,而扯上关系不代表一定要“挂钩”。

想要扯上关系关系很简单,只要注入实体经济中的东西就可以了,比如:可以通过用RMB购买博元(Q币的做法),或者可以用博元购买一本书(银行信用卡积分系统,用招行信用卡的就知道他们的积分体系正面临较高但尚且算温和的通货膨胀)。只不过怎么设计更好更有效率,会有一些难,这个后面再说。我要先问一下,这个博元和RMB之间的比例是如何定的?(汇率形成机制问题)

这个问题我们首先要知道蒙代尔(也叫芒德尔)的铁三角理论:一国不可能同时实现固定汇率制、资本自由流动及独立的货币政策三大目标。固定汇率好理解,资本自由流动应该是指能否允许自由“兑换”(或者进出),独立货币的意思就是发行多少博元是否能够独立受博客园控制。前两者好理解,后一个如果不能实现的话,则有时候会导致通货膨胀。RMB在之前很长一段时间以来,都在保持着固定的汇率,资本流动受到一定控制(但不是完全禁止),同时希望保持独立的货币政策。可是在07/08年左右的时候,因为外国热钱对于人民币的低估以及其他一些资本市场的亲睐,大规模涌进来。而此时政府不可能为了拒绝热钱而完全管制资本流动,因为那样会伤害正常的贸易经济。于是就造成了货币政策实施上不独立(或者叫做不完全独立),具体体现是为了稳定汇率,必须大量购买外汇,而购买外汇则必须大量发行货币,这是那一段时间通货膨胀的最重要原因。

这三者要实现哪两个,可能会有很多不同的争议。我个人的看法是,必须实现资本自由流动,以及货币独立。缺乏前者,则无法有效和RMB,或者实体经济联系上。缺乏后者,则内部的经济环境就可能会出现恶化。因此,必须让汇率能够自由浮动。而且根据蒙代尔所指出的那样,对于一个开放的经济来讲,货币政策比财政政策有效,因此保证货币政策独立性可能更好一些。

但是目前我们有一个问题没有触及,就是RMB是否有可能直接的和虚拟货币直接兑换,这个问题的答案是否定的。目前的法律不允许这样的行为,否则搞不好会认为是非法吸收公众存款。那么间接的是否能够做到呢?这个是肯定的,我们可以看到Q币这个具体的例子,就是可以的。也就是说,我们可以允许单向的货币直接流动。此外,我还可以给出不同的几种可能有效的“兑换”机制:

1、通过管理层联系到的一些第三方赞助的实物,例如卓越或者当当的购物券,或者某些书等,甚至一台笔记本之类的,进行拍卖,标价按照博元标价。拍卖成交之后,即可根据实际的RMB价格,来计算相应的RMB卖出价。(注意,拍的价格越高,意味着博元价值越低。)

2、其它使用博元购买的实物(或者现实世界的服务),则参考卖出价。

3、由博客园提供博元拍卖机会,博元的拍卖单位比较大,比如10W,拍卖结果就是最近的RMB的买入价。(注意,拍得价格越高,意味着博元的价值越高。)

4、小额买入博元,则以最近买入价兑换。

这个看着有点复杂,可是我认为有其好处在里面:

A、由于通过买卖土地的租价,已经合理对页面的每一块地方定出合理的价格了,那么某一个邻近区域放置的广告费可以用博元来衡量(进而通过汇率得出实际需要支付的RMB);

B、赋予了博元以实际价值;

C、可以用RMB来衡量博客园内的GDP,或者说,最终可以非常有说服力的说明整个站点的价值是多少。

 

本来我这里想写的复杂一点,也确实写了,但是发现看着有点复杂,搞得像是经济学的讨论贴了。说到这里,其实我也不得不承认,如果真要一下子实现所有这些,会使一个多么复杂的事情。在这里我需要澄清一下,一次都实现这么多东西是不现实的,毕竟罗马不是一天建成的。那么刚开始的时候,简化是肯定要的,怎么简化呢?我想需要放在下一个主题中:市场化改革。

P.S.:不知道本篇有没有值得讨论的地方?或者是否我需要再澄清写什么?说实话,我并非经济学科班出身的,因此对这些经济学上的概念运用的并不是非常的娴熟,甚至写错了都有可能。如果有什么写错了,也请大家指出。

 
眼球网站经济学之我见——在网站上建立现代的经济体系 (5-27 15:37) 博客园首页 其他技术区 (其他)
眼球网站经济学之我见——符号化的意义 (5-27 11:43) 博客园首页 非技术区 (其他)
眼球网站经济学之我见——通货膨胀 (5-27 09:33) 博客园首页 非技术区
眼球网站经济学之我见——劣币驱逐良币 (5-26 16:51) 博客园首页 (其他)
博客园的首页 (5-26 12:55) 博客园首页 非技术区 (其他)

posted @ 2009-05-29 22:18 Sumtec 阅读(1088) | 评论 (11)编辑

2009年5月27日 #

请大家原谅我一下子发这么多文章,因为我真的是很难的有时间这么畅快的写一些东西出来了。对于挤出其他人的文章,我已经有很深的愧疚感了,真诚致歉。如果真有人觉得在这段时间内发文章不划算,可能导致自己文章被很快的刷掉,那么我建议你可以把你的文章存两天再发出来。

在开始将正题之前,再把之前用到的比喻温习一遍:博客园是个国家,国家的管理者(政府)是博客园团队,同时也是货币发行机构,这一点至少目前是这样的。这个叫做博客园的国家,有很多土地,也有很多人民。土地有价值高的,也有价值低的,比如首页就很有价值,最顶上的尤其有价值。而翻了二三十页之后的土地就没有什么价值,此外目前而言,很多板块也是价值很低的。人民也有好有坏,有的坏蛋发光广告贴,有的圣贤出论语。到目前为止,这个比喻还是比较形象的吧?

博客园这个国家要想欣欣向荣,第一个要素我觉得还是要在提高或者至少是保证国民素质的基础上,提高人口数量。我们都知道人口红利是很厉害的,这也是眼球经济存在的最基础原因(有多少人知道?)。第二个要搞得事情,就是尽可能提升每一块土地的价值。比如说,那些非技术板块的价值,目前因为设计不合理(交通不发达啊,游客很难到达),导致价值下降的,我们就应该想办法提升这种地方的价值,比如增加导入流量到这些板块的效率,而不是让所有人只是盯一眼首页(提高每用户点击页面的数量)。这种过程好比把经济形态从全国人民造北京,改造成为国富天下的形式。当然,对于那些翻到二三十页之后的页面,就和离北京60公里地的荒郊野外一样,价值会逐渐降低,我们不太可能通过类似的方法硬翘的。不过经济搞好了,更多的人移民到博客园里面来,物质精神生产极大丰富,同时游客充足,那么也有可能像北京一样3环4环5环6环的发展。尽管改不了还是某些中心区域的价值最高,然后向外辐射的形态,但是土地价值照样上涨。另一个更为重要的问题,就是如何让土地的价值得到正确的体现。这个问题不解决,难免会出现在CBD区域规划出一片农场出来的问题。好,让我们尝试一下,看看能不能解决这个问题!

如果前面的比喻没有什么大问题的话,我们就以此作为参考对照,看看现实世界是如何实现的。现实世界中,土地最初始的状态,是政府拥有土地,然后出卖或者出租给私人。而私人则在这个基础上独立的进行相关的经济活动,比如造一个高楼,或者别墅,或者工厂。而这种活动通常都是采取“法不禁止即允许”的游戏规则的,这意味着经济活动在微观上是允许不断细分的。比如说你造了一个高楼,我可以买下门面房,然后租给张三这个商户,张三聘了李四管理店铺,店铺向顾客收取费用,卖出从王五处进的面包这种商品。那博客园是否有可能搞得这么复杂呢?嗯,也许吧。不过我们已开始讨论,还是把模型简化为好。首先,我们看一下土地这个东西现实世界是如何具体市场化操作的。由于一开始是政府拥有土地,所以刚开始都是政府挂牌开始拍卖土地,价高者得。得到土地的必然希望用此土地来得到与付出所对应的回报,然后就会在其上盖房子。好,这个模型就不再往下细分了,否则会复杂化。套到博客园里面,就是需要管理方以市场自由定价的方式出让版面,而购买方则可以相对自由的在其上选择显示的贴子。

当然,虚拟世界里面有很多地方是和现实世界的模型有着巨大的差别的。首先第一个是首页的不可移动性。如果是现实世界我们发现广州经济不好了,大家可以选择搬别的城市,或者说我发现以前可能朝阳区经济好,现在发现中关村更强,我就改到中关村去租门面房。而博客园的首页却没有这样的特点,如果直接允许首页土地自由买卖的话,后果有可能是买到首页的都在卖广告,导致价格被扭曲不能体现真实的价值。最后园人肯定也得要搬,不过不可能搬到别的版面处,而是搬到另外一个国度里面了。对于这种情况我们是否有好的办法来解决呢?

幸好,这种问题几乎不需要我们浪费脑细胞去思考,现实世界又给我们提供了一些活生生的例子。西方发达国家的社区,是有社区立法机构的,在一定范围内,可以允许这些机构订立本社区的法令。比如,我就看到某些社区是严格禁酒的。在进入这种社区的道路上,我们会看到一个大牌子写着“本社区严格禁止在任何公众场合出示酒水,此外在家中聚众饮酒也是非法行为,向本社区土壤内倾倒含酒精的液体也是被禁止的。如果您带有酒水,建议您包装好不要对外出示,并且在离开的时候带离本社区”。嗯?这个跟我们说的东西有什么关系?别急,我再说一个故事你就知道了。还有的社区呢,会规定本社区公民必须负责整理自家的草坪,草坪中草的高度不能超过25公分,否则将会遭到XXXX元的罚款。当然,大家一般都不在意,不过如果真有人投诉的话呢,社区管理机构就会来人带一个小尺子来量,超了告知法院,法院会给你发罚款通知书。这种通知书到你手里面,你是不敢不上交的,否则法院会告你蔑视法庭,到时候不是交钱就能了事的了。于是乎遭到罚款的公民,除了乖乖交钱之外,还会干另一件事情——剪草坪。这个规定可真够怪的,不是吗?我家的草爱怎么长怎么长,你管我呢,再说了,难道我把草养肥收割后拿去当牧草卖不行吗?不行,因为这个涉及到整个小区的利益。所有小区内的公民自然希望本小区的地价呈稳步上升的态势,如果周围总有那么几家荒草遍野,破败不堪的,你说别人愿意来这个小区住吗?唉?这不就是我们刚才想要解决的问题吗?我们又再一次见识到了货币符号的威力,连你做坏事的价值(负的,或者说是成本),都可以给你衡量出来。更重要的是,通过这个衡量作用,有可能可以正确逼近所有东西的内在价值。

嗯,我们仔细想想,这里面的学问其实和管理一个国家相差并不太大,只不过模型更简单一些。不过麻雀虽小,五脏必须俱全,否则残疾的生命注定只能在保温箱里面,靠机器来维持生命。也就是要靠管理团队不停的思考说,这个首页的文章怎么个规则才算可以放?然后首页放不下了,是不是让一页的文章数量增加一些来解决?又或者说这个菜鸟到底给多少分好呢?多少分才能当版主呢?这样就导致管理团队肩负一个生命维持机器的责任,不停的要根据现实情况的变化改动规则。要命的是,没有人能知道这个规则是否合理,因为其无法衡量。我们只能感受到有的人愤怒有的人喜欢,大概似乎所以然。搞不好规则定错了,生命就玩完。扯远了……

我们看看,是否博客园这个国家,还需要有治理方面的机构与机制呢?显然嘛!所以还应该有立法、执法、行政等机构,不一定三权分立,也不一定真搞出个机构来,但谁也不能否认这种指责肯定是存在的。我们看现代社会,甚至这些机构本身都是被货币所衡量的(成本、预算、税收),可目前还真得很少有站点会这么考虑问题。固然,太复杂也是一个原因,这个已经看到有人在回复里面说到了。扯得有点远了,再拉到博客园上面来考虑。如果说,我们订立一个法则,什么样的东西不允许放在什么小区内,然后同时又一个执法的机构或者过程,如果被判违反法律,就会被强制罚款。是否这样有可能可以解决问题呢?嗯,我猜测有可能。不过必须要注意的是,这个罚款的制定必须要符合博弈论的知识。至少罚款的数目,也就是成本,应该要远高于可能因此而带来的收益。理论的基础是,这种犯罪不是每次都会被发现的,此外,为了发现犯罪而需要的各种付出都是由成本的,这些成本都必须要由犯罪的人来负担。一个很难发现的违法问题,比如说发软文,可能十次当中会发现一次,那么罚款至少就应该达到一次软文可能带来的经济效益的十倍!当然,我们不可能搞那么复杂的事情,说去衡量一下我们发现犯罪的概率有多少。这个问题在现实世界里面也不会搞得那么复杂,而是依靠一种近似市场化的方式来解决的:限定一个猜测出来的价格,高了人民自然怨声载道,就降下来,低了问题会越来越严重,那就涨上去。

啊!太好了!一切看上去是如此的完美!……等会儿,别急,这里面解决的问题恐怕万分之一都没有!我们接下来会马上面对一个更大的问题:烦人!没错,就是很烦人,如果整个系统照这个搞,不用说别人,我马上走人。我哪有时间心思去搞首页经济啊?我如果为了要上首页,还要自负盈亏,然后再融点资什么的,我还有时间仔细思考写出这等文章来吗?所以,在网站经济里面,我们还不得不考虑另外一个问题:行为,就是不同人的不同动机,或者说他们的需求。对于一个只想好好写文章的人来说,自负盈亏在首页搞那么多的操作,绝对是要了他们的命了。

哎呀!摔地狱里面了!那就多看看我的文章,习惯了就好。这个问题是否也有现实对应的参考模型呢?嗯哪,你太聪明了,和我想的一样啊!有啊。我们来看看期货市场是如何工作的。期货市场是干什么的,我真不打算仔细说,这个里面的理论还不是随便一下就可以讲清楚的。简单讲,真正需要期货市场的,是那些希望规避价格波动风险的生产商和进货商,他们需要做套期保值(啥意思自己查吧)。但是光他们来玩这个,是玩不转的,因为他们的资金和精力极其有限,跟我们这些写博客的一样,他们有自己的正事要干。实际上期货市场里面的大部分资金(可能站99%以上),都是一些投机的资金,只是为了发现其价格的不合理,以期从中获得高收益回报。而且和大家想象的不一样,投机资金在期货市场里面,是受到欢迎和鼓励的。甚至在一个度的范围内,从市场管理方到政府,都是欢迎而不是禁止这种资金入市的。原因有两个,一是他们为市场投入巨大的流动性,而这种流动性才真正的让这个市场转起来。另外一个是,这些投机者通常拥有更敏锐的嗅觉,因而更能够找到价格的不合理性,进而实现“发现价值”的功能。套到博客园里面来,我们可以更进一步的修改——写博客的人甚至可以在不用参与的情况下,让其他“读者”来发现价值。读者中很可能会有一些人喜欢干这些投机倒把的事情(好像有点贬义,不过我不这么认为),比如购买某篇随笔的“独家摆卖权利”,然后到首页租一块地晒摘要,而政府则根据点击阅读量来来支付购买人气的成本(发钱),同时也根据市场化的低价收取租金。这不就解决了写文章的人感觉麻烦的问题了吗?对于博主,似乎什么事情都没有变,也不需要做额外的事情。只不过,你的文章要是写得好的话,更有可能会放在更有眼球的地方,放的时间也可能更长。

前面我漏说了两件事情,第一个是那个随笔的价格是怎么定的?我没有仔细想,随便胡诌一个:第一个出价之后3小时内出家最高者得(拍卖嘛)。甚至即使买到的文章,在锁定一定期限之后,会被强制再放到市场上拍卖,如果价格比原价高,则归新的主人。其差价由上一个主人和博主按照一定比例分配收益。如果这样的系统真正运行起来,大家都回很愿意写文章。即便写不出高质量文章的,也可以在四处闲逛中,获得实际收益,甚至是虚拟货币的收益。说不定就可以转化一部分水平稍微欠缺的人,使得他们少发表缺少质量的文章,而“转载”高质量文章,系统进入良性循环的可能性就会相对较高。

第二个是,如果你细心的话,或发现我说的是政府租地而不是卖地。为什么不是直接卖呢?这个我留给大家思考和讨论,也许后面会有什么后传外传之类的出来补充。

啊!太好了!不过是不是还要再提出更多的难题?嗯,没错。目前我想到的至少还有两个难题:第一个是,读者为什么愿意浪费时间来做我们想要他们做的“发现文章价值”的事情呢?毕竟我前面提到的方案娱乐性有点太强了,基本上是建立在假设这个娱乐性能够成为支撑系统运转的动力。第二个是,现在博客园已经有这么多成员了,那么如何发放初始货币会更加公平合理呢?

哇,一下子出来两个难题啊!如果大家愿意,可以先思考讨论一下。想不出来或者懒得想,也没关系,因为这是本系列接下来两篇文章要讲的内容:货币汇率,以及市场化改革。哪一个先写还不一定,看硬币抛到哪一面了。

P.S.:本人第三次遭遇不能直接发首页的痛苦……我承认,这个设计是有其合理的地方的。有道理!我绝对反对取消这种限制,不过我认为真的可以改进,比如像我说到的那样,如果两小时内发布,会自动排队等到两小时后才能发布。甚至如果有人不停的在发布冷却时间内利用排队系统发布的话,冷且时间会成倍的增长,比如第二篇变成4小时,第三篇变成8小时。直到最后一个冷却时间过去之内,没有再使用排队系统,才能将冷却时间变成初始值2。这样既可以排队发送(方便啊),又不会让发广告的占便宜。最后我承认,这种设计很复杂,其收益与成本不成比例。所以,我接受这一个设计不做变化的局面。

 

本系列其它文章:

眼球网站经济学之我见——符号化的意义 (5-27 11:43) 博客园首页 非技术区 (其他)
眼球网站经济学之我见——通货膨胀 (5-27 09:33) 博客园首页 非技术区
眼球网站经济学之我见——劣币驱逐良币 (5-26 16:51) 博客园首页 (其他)
博客园的首页 (5-26 12:55) 博客园首页 非技术区 (其他)

posted @ 2009-05-27 15:37 Sumtec 阅读(1209) | 评论 (16)编辑

“钱不是万能的,但没钱却是万万不能的!”这种调侃很流行,我想也应该有不少人能够在总体上认同——谁不食人间烟火啊!不过有的时候钱确实是很难衡量,甚至会失去作用的,比如为国捐躯、无私奉献、天灾人祸等。也许有人会因此得出一个金钱很俗的结论,那么我在这里就要试图解决两个问题:将人类的感情色彩去处后,还原金钱的本质;以及将这种本质应用到虚拟世界之中。

钱,或者说钞票,实际上并不是价值的直接映射,准确说,钞票是一种货币符号。货币符号的意义其实很像一种衡量的工具,比如说,人民币元是一种衡量价值的单位,就和公理是衡量北京至广州之间的距离的单位一样。与物理单位不一样的是,这种单位不是恒定不变的。比如说,为了解决通货膨找所导致的价格在时间轴上不一致的问题,我们就提出了实际价格和名义价格的概念。再比如说,我们从来都只是说,价格围绕着价值上下波动。既然价格有这种缺陷,为什么我们还用它呢?答案在简单不过了:目前为止,我们还没有找到更好的衡量方式,尤其是能够解决附带的很多其它问题,例如公平与效率,社会问题等。

尽管如此,我们也不得不承认,货币符号提供了一种衡量价值的方法和系统,尽管不是很完美。那么如果我们扒开“钱”这一层皮,我们还可以怎么更深刻的去看待“钱”呢?实际上,价值这种东西属于一种不可直接观察的变量,而这种不可观察的变量缺是很重要的一个东西。怎么办呢?我们就会想办法通过可观测的量,通过计算来逼近这个不可观测量。在别的很多体系中也是如此,比如导弹。导弹要打准了,就需要知道当前所在的具体位置。在没有GPS出来之前,具体位置就是一个不可观测量,于是就必须通过加速度传感器以及陀螺仪来得到六个自由度的加速度值,进而求得当前所在的位置。而这种通过可观测量来推导步客观测量的方法,在现实世界中永远是不可能完美的。一个是因为这个系统内部像是一个黑盒子,内部机制实际上如何运作并不真正清楚,要清楚了就不是不可观测量了。另一个原因是,这种不可观测量通常不会仅仅和一个可观测量产生联系,而很多时候是和无数的变量产生联系。因此,价格要体现价值,自然不可能做到完美,只能够做到逼近。

好了,解决了货币不完美的原因之后,我们再回过头来看网站。网站是否也有价值概念的存在呢?显然有,比如说首页较上放的左边至中间的位置,一定是最有价值的地方,因为那里是最吸引眼球的。而页面的第3048页最右下角的地方,其价值几乎为0。明白这个之后,你才会做一些对得起价值的事情。我们再以现实世界为例子想象看:为什么没有人会在北京CBD位置买一大块地种玉米呢?那么到了网站上,为什么会有站点在如此重要的位置放一些无关的东西,同时又允许高质量的文章被逐渐被搬家搬到戈壁沙漠里去呢?答案是,这里的网站中,每一样东西并没有被一种好的符号所正确衡量,因此也就没有人会注意到这个问题。最后,这些东西的实际定价(比如放到首页还是放到别的地方),就会偏离其实际的价值。

符号化另外一个优势是,统一了衡量的标准,使得所有不同的东西都能够得到统一的衡量。如果我们套用现实的一句话,叫做“萝卜青菜,各有所爱”,就会发现这世界还真是众口难调。我在“博客园首页”的文章中,并没有提出这个问题的具体解决方案,也正是因为我甚至这个问题里面的复杂性,其中一个就是每一个人的喜好是不同的。如果不仔细把这个问题想清楚了,很容易建立起一种扭曲的系统。比如说,想看最新消息的人其实很多很多,却因为德高望重的人希望多发有思想文章,而设计出按照文章原创性来评价的积分系统。这样的系统,必然不能够正确体现“最新消息”的价值,导致这种占数量最大的群体的集体移民。正确的符号化,应该是允许衡量尽可能多的东西。在这一点上面,金钱不可否认是目前为止我们看到的最好的系统之一。其可以衡量的从我们的日常用品,到虚拟的股票交易,到各种不见得光的肮脏交易,到各种权利的寻租,你都可以轻易的订个价。如果不是因为社会价值选择的缘故,禁止和打击某种类型的市场交易,可以想象诸如权力寻租的这种市场照样可以欣欣向荣,告诉“发展”。因为钱这种衡量方式可以衡量各种东西,最终就可以将每一样“商品”的价值逼近于另一种“商品”的价值。这就是货币符号的真正威力所在!

那么回到我们的博客园,如果真要建立一个“符号化”的系统,来体现价值,就一定要尽可能让每一样东西都能够得到衡量。要做到这一点,这个符号的定义必须是中性化的,就如“钱”的真正定义一样。这种符号绝对不能够被赋予“威望”这种含义,也不能被赋予“有思想”这种含义。二是应该让这种符号被允许自由的逼近各种不同的含义,使得他们能够被“交换”。

说道这个,我们还会看到另一些被错误设计的现实例子。比如一些论坛,会有积分、金钱、威望三种体系并存,这是一种在我看来很可能很蠢的设计。大家想想看,威望不能当钱使,但是有些帖子又必须要有一定威望才能看,而有的时候还需要有积分。这样的设计出了人为割裂的不同的价值之外,还因为存在不同的系统所形成的不同循环,各种循环的平衡情况又不一样,会给整个系统的平衡带来很大的麻烦。事实上能否看某种帖子就是一种价值,这种价值却因为三种不同的符号所割裂,最后就会导致价格的扭曲。现实世界也有很强的例子,那就是改革开放前所存在的X票系统。我们知道这种票之多,包括了粮票、油票、电视机票、收音机票等,甚至还细分为粗粮票、细粮票,更好玩的是还分为市、省、全国粮票。这种搞法的最重要作用就是让所有人都无法有效衡量物品的价值,比如我要生存这个需求,到底应该值多少呢?可能是2斤白面加6两肉,或者4斤白米加3条鱼,反过来说一斤广州市粮票所能买到的白面等于多少生活所需呢?没法衡量,这可谓极端的反例了。

在眼球类网站上,这种问题确是在无意识当中被制造出来,并且流行着。实在是……有一种说法,说经济学在如果跟大部分其他学科比起来,还处于一种原始时代,那么网站的经济生态和现实中的经济生态乡比较,更是原始——钱的观念还没有出现呢!

那么,如果要按照经济规律来办事,一个类似博客园的网站,可能会怎么设计呢?嗯,这是下一个命题:在网站内建立现代的经济体系。

P.S.:这个随笔有点“短”,先这么找吧,也许有新的想法我会再度补充。尽管之后看的人可能会少了,那也是没有办法的事情,目前没有办法解决。

另外,我今天再次遇到说时间间隔太短了,不允许发布首页的问题。其成因是:我发完一篇之后,发现思绪澎湃,赶紧接着写。此时距上一篇发贴不到5分钟,因此被判定不允许发首页,尽管等我写完的时候,已经过了2个小时了。解决办法是先存草稿,然后再打开编辑发布。尽管我承认动机是好的,但我仍然认为,其带来的成本比收益要高。原因是,真要捣乱,这么一个机制并不会发挥多大的阻碍作用。但是对于大多数人来说,却是一个多余的操作。即便是那些超过两个小时才点击编辑,开始写并发布下一篇文章的TX来说,想要发布到首页都还是要忍受一个弹出对话框,然后再点一次确定。

另外,我被livewriter给害了一次,他那个玩意儿有个破毛病,就是本地部自动保存的。有一次我写了一个随笔,不知道怎么的被他发布到文章里面了,后来想要改到随笔,却没有成功。想着那我就删了吧,重新发布一边好了。结果删了之后再打开livewriter,才发现本地没有任何保存。TNND,哭都来不及,后来想想算了,价值不高,纯属私藏发泄贴。不过,从此我就再也不用livewriter了。——看到Web编辑界面推荐客户端:livewriter有感而发。

 

相关系列文章:

眼球网站经济学之我见——通货膨胀 (5-27 09:33) 博客园首页 非技术区
眼球网站经济学之我见——劣币驱逐良币 (5-26 16:51) 博客园首页 (其他)
博客园的首页 (5-26 12:55) 博客园首页 非技术区 (其他)

posted @ 2009-05-27 11:43 Sumtec 阅读(1213) | 评论 (16)编辑

说这个之前,先说说我对上一篇随笔中回复的一些想法。没错,我这些文章跟某种Computer Language上作Coding是没有关系的。不过,大家的终极目标不是只是Coding吧?那么做一个真正好的眼球网站,我们需要注意什么?我想这种问题,包括处理这种问题的经验都是比较不容易获得的。我来贡献一下也不是件坏事吧,虽然也许我说的不正确,那大叫就讨论讨论呗。甚至我希望能够呼吁大家,不要死抠技术的东西,那容易误入歧途。有时候跳出来看你会看得更清楚,比如看看经济学的东西,再转战一下各种相关网站,你才会冒然发现:哦!经济学相关的开发那么的挣钱啊!我怎么不早知道呢?

扯远了,回头继续说上一个贴子里面提到的命题:网站里的通货膨胀。

这是我一开始向要写出来打头阵的文章,思考了很长时间了,大概从我离开CSDN转战博客园就开始想了。说实话现在CSDN如何我不太清楚,我能说的都是基于以前的经历。有些TX在之前的帖子中提到过,现在博客园的新手提问区没有人解答问题,很郁闷。我先回答这个问题:这不是博客园的定位,因为搞差异化才有可能在世界上立足。而博客园的定位应该是产生思想的地方,博客应该是有想法的人想要发表出来才会产生,也才会有人看。当然不排除博客园可以在论坛上也能做到差异化,不过会比较难。因为曾经CSDN在我看来很先进,那个论坛比其它普通的论坛好不知道多少!原因是什么呢?因为有积分系统:你能提问题取决于你是否有“分”可以放出来;你的问题能否被解答,取决于这个“分”是多少;而你又多少“分”,则取决于你能解答多少问题。这一切看起来很不错,因为整个逻辑一串通起来,就形成了一个自发的良性循环:我想要不停的问问题,就必须尽我所能解答其它帖子以挣到足够多的分数;不断有人回答问题,则意味着我在这个论坛中得到问题解决得可能性比较高;而不断有人愿意在这里提问,结果就是对大家都有利,三方共赢。而普通的论坛虽然可能也有积分,但这些积分通常是无法消费的。

我在那里做了一段时间的VB.NET的版主,可为什么后来我跑了呢?为什么来到博客园了呢?固然,自身水平提高之后,希望找到更合适的氛围,这是一方面。而另一个方面,恐怕没有多少人会深究,那就是CSDN在其后的几年内爆发了严重的通货膨胀!什么?通货膨胀?CSDN?他又不印钞票,怎么会有通货膨胀呢?没错!就是通货膨胀。在深入探讨之前,我给大家先讲讲通货膨胀。不过我建议大家真有兴趣的话,还是不要光听我胡诌,找些正规的书来看会更好。

通货膨胀最根本的原因就是货币增发,也就是货币发行量超过了实际需要量。07/08年的时候很流行一种说法,叫做结构性通货膨胀。我个人认为,这种说法压根就不成立,我记得有不少真正的经济学家,是坚决反对这种提法的。原因在于,所谓结构性的通货膨胀,实际意思是说,有的商品价格涨了,但有一些却跌了。某些跌了,是因为在某个领域供过于求了(结构性供求失衡是存在的),可是局部供求失衡,是能够自行调节价格关系的。而只有货币超量了,才会导致大家思考货币保值的问题——当大家的钱都多了,而实际上可以购买的商品总数不变,则每个商品的平均价格就会上涨。这是分子分母的游戏,不用多说了吧。那么今天1块钱一斤的大米,过一段时间就可能因此涨上去了变成2块钱一斤了。当大部分物品出现涨价,就意味着你今天的钱如果留在明天才购买,则能买得东西的数量会比今天买要少。解决办法两种:1、想办法让钱生钱;2、今天有钱赶紧花。这都会导致通货膨胀越演越烈,具体原因不多说了。那么“结构性通货膨胀”的原因是什么呢?你想,有东西是相对更可能保值的,比如房子、金子,甚至有可能赚大钱的,比如股票、期货。但有的东西绝对贬值的,比如笔记本,你今天买了过18个月就基本认为是废塑料了。那当然资金会更亲睐保值的东西了,于是保值的涨得厉害,而且是一开始就涨。而非保值的涨得少,甚至如果供过于求还有可能下跌。但是无论如何,由于办法2的存在,会导致货币超发的时候,不保值的东西最终都会涨价。钱没地方花或者必须花的时候,都会导致他们涨价。

扯远了,大家只要记住一点,货币增发会导致通货膨胀就可以了。那么回到CSDN上,有货币马?有啊!那个积分就是一种类似货币的东西,可以购买问题答案,也可以通过回答问题挣回来。可是CSDN的经济模型和大部分正常稳定的经济模型是有不一样的地方的:它存在着一种“直升机撒钱”的机制。“直升机撒钱”大家现在应该不会陌生,因为美国现在就在用这种方法来救市,理论就是为了增加市场货币流动性。有点深了不是?好,回到CSDN的例子就不是那么难理解了:如果大家一注册都没有分数,如何提问呢?在如果新注册的恰好是菜鸟,什么问题都回答不了,如何挣钱呢?或者菜鸟们总是多数,但问题的提出方基本集中在菜鸟方,高手方则基本不需要问问题。因此这个系统像要在主办方所希望的活跃氛围下运行,是动态不平衡的系统,或者说分数总是主要从菜鸟流向高手的。那这个系统就会遭遇严重的流动性紧缺,或者说菜鸟没钱挣也没钱花,高手有很多钱、很能挣钱,但是却不花钱。解决这种问题的方法真的很多很多,好的坏的都有。不过糟糕的是,CSDN选择了一种不算最坏也差不太多的直升机撒钱的方式。我们听新闻都知道了,直升机撒钱很有争议,除了损害绝大部分人的利益之外,搞不好还会导至下一轮更大的通货膨胀,这种方式从来都被评价为“最后的自杀式一搏”。

类似CSDN的这种系统,其实真的很常见。比如QQ的经验值系统,大部分论坛的威望值系统,再比如网游里面的虚拟货币,还比如淘宝的信用系统,无一例外均是(或者近似)直升机撒钱的通货膨胀型系统。回到CSDN,我们看看他具体是怎么操作的。如果我没有记错,就是新注册用户会拿到一定分数(撒钱),并且每天每个用户都可以收到10分(撒钱)。这在最开始的几年时间里面是不会遇到问题的,因为这个时候需要解决的问题非常多,钱是绝对不够花的。同时由于这个钱对于高手来说,通常不需要花出去,也没有地方花,因此会被高手所收储,总体来讲流动性仍然是紧缺的。但是随着时间增长,用户量增长,逐渐会出现货币发行量几何级甚至指数级增长。除此之外,我们会发现,中产阶级开始出现并逐渐增加。所谓中产阶级就是那些需要问问题,同时也可以解答问题的人。这种用户对于货币是不收储的,也就是说,系统对于货币的收储能力是在不断减弱的。当收储不断减弱,发行却不断增长,最后就会导致货币超发,导致通货膨胀。

这种通货膨胀是可以被观察到的。在我刚进入CSDN的时候,大家手头之紧缺,表现在大部分问题都是以10分为标价的,100分的问题可都是趋之若鹜的。而到了我离开之时,已经有很多问题是以100分为标码的,甚至因为有人钱多但是问题紧急,想要标高价格的需求。于是后来规定上了几星的用户可以标200、300,甚至我今天去稍微转一圈,发现还有400分的问题。这就是通货膨胀的现象之一。

通货膨胀了有什么不好呢?这个问题我们到现实世界里面问问就知道了。第一个是看着越来越有钱了,实际上感觉确实越来越缺钱花。比如去年一条牛仔裤才100块钱,今年变200了,于是相当于我去年的结余就损失了一半。相比物价稳定的系统,自然是缺钱花了。而另一个不好的地方在于,标价开始部分的失去了供求关系体现的功能,因为你会发现你很难通过某个商品的价格变化来衡量其供求失衡关系——到底是缺货呢,还是就是货币贬值了?同样的,问题的分数对于其价值的体现,在这种通货膨胀下就失去准确衡量价值的能力了——也许是因为这个问题很值钱,但也可能只是因为这个人有钱。但是一般想要挣钱的人,则不会想那么清楚,反正越贵的问题回答后得到的回报也越高。最后回答问题的人会越来越没有成就感,真正有紧急问题要问的人因为分数不够回答不积极而感到郁闷。

而在CSDN的系统里面,还有一些加剧这些致命伤的规则。第一个是问题价格封顶,这好比价格控制,说这个玩意儿就能卖100,多了不允许卖。第二个是没有很好的整理旧有问题,并形成合理的经济循环。第三个是威望玻璃天花板,就是当你积累分数超过一定程度之后,再想通过积分升级别(比如到4星),那就是不可能的了。这三个规则如何损害着CSDN的内部经济生态呢?

先说第一个,价格控制意味着价格扭曲。比如有一个问题就是超紧急并且超难,按照自由市场估价应该值10000,可是就不让标,只能标100,那你说问问题的人还愿意标出来吗?于是最后问题的技术含量就会显著性的下降,这同时损害双方利益,因为有难度问题的缺乏,让真正的高手倍感无聊,最后这两种人都会离开CSDN。也许有人会问,之前不是说有些问题难度不高也被标高价,那现在通过这种价格控制,难道不可以吧高难度问题价格控制下来,同时从平均上降低物价指数吗?这种想法看似可行,但实际上也是不可能实现的。最简单的原因就是高难度的问题不可能在压低价格之后,和没有难度却标高了价格的问题在同一水平上竞争。你愿意花很多时间解决一个100分但是很难的问题呢,还是让脚指头思考一下一秒钟解决100分的另一个问题?我想这样无聊的问题,你连用膝盖想一下的动力都没有!于是,这个出发点也许很好的设计,就在不知不觉中如同博客园“发布到首页”按钮一样,起到了相反的效果(事实上比那个按钮糟糕多了)。

第二个问题,是这种重复出现的问题其实没有很高的经济价值。你想,当你回答了十遍int.Parse怎么用这样的问题之后,你还有多少动力愿意回答第十一遍?你对这种问题的定价也会逐渐降低(边际效用递减)。而规定恰好与此相反,这种问题不仅没有收敛,还有泛滥的趋势(因为新手永远是不停的加入到市场中,如同刚毕业的大学生一样)。而且似乎被用来解决流动性泛滥了——寄希望于通过允许询问无聊问题,来消耗掉多余的流动性。但只要货币增发不停止,这种流动性是不可能彻底解决的。当这种解决方式也吸收不了流动性的时候,还会进一步抬高问题的价格,最终导致货币失去其衡量价值的功能。当然,准确地说,这里面还有一个定价机制不合理的问题,即价格无法由供给答案方主动参与定价,只能够被动的通过不参与来响应。可以说这是一个不完备的商品及货币市场。

第三个问题,是你发现当你到达一定程度之后,比如说三颗星,无论你如何努力回答问题,积分如何高,最后就是不能通过这种努力来换取更高的级别时,你就会不再愿意回答问题。这时候就会反过来导致货币价值彻底丧失——那些一直爬升到三颗星的用户,最后一头撞向玻璃天花板,才发现原来那些积分到最后是没有意义的,以前的努力几乎白费了。当他们在看到问题后面所附带的积分的时候,其价值就已经等于0了。当然,这种制度在现实世界里面还会引起更多的问题,例如权力寻租——任何只要无法通过市场定价的,只能够通过由垄断权力定价的地方,势必容易滋生权力寻租。不过其实最终还是通过寻租市场定价了,可见货币符号的威力!超出货币范畴的问题这里就少说了,免得被人说这个不是经济学内的问题。

因为这个系统不可避免的走向通货膨胀,进而走向货币失效,我也走向了博客园。不过呢,这个系统也不会一直恶化下去,只要用户流失,则用户账上的价值就会随之沉淀,最终被消灭(价值的消灭)。通过这种消灭途径,系统最终会到达增发和消灭的平衡点,而最终稳定下来。不过这种稳定的代价非常高,是消灭了真正有价值的东西而最后导致货币的稳定。好比说钱发多了之后开始抄有钱人的家,然后继续发钱,如此循环。最后真正能赚钱的,都会想办法不在这个地方呆了。当然,抄了家之后把钞票一烧,货币总量就会下来,这种消灭和超发总能平衡。

那么这种问题可以如何改进呢?我这里给出一些思路,还是看现实世界:

1、宏观经济学研究现实世界的时候,会把世界理想化为几个大部门。两部门经济模型——企业和家庭,显然不适合讨论,因为这种只有生产者和消费者的模型,本身就转不起来。因为流动性缺乏,不过不是经济学上的原因造成的,而是网站模型本身造成的。我们可以看三部门经济——企业、家庭和政府。企业是生产答案的用户,家庭是购买答案的用户,而网站管理方则是政府部门。如果将网站发给新用户的初始资金,以及每天给用户发的一定现金,理解成网站为了采购人气而支付的成本,则可以看作政府部门的政府采购项目。而宏观经济学的理论认为,这样是不均衡的系统,因为政府不断的支出,而没有相应的收入,则会引起预算赤字。填补预算赤字的其中一种办法就是发行货币,而不停的发行货币,就会导致通货膨胀。所以要整个经济循环能够平衡下来,政府还要干另外一件事情,就是收税。网站也一样,分发出去之后,应该向富裕阶层收税,以弥补采购人气导致的政府预算赤字,并尽量减少货币发行量。(不是完全不发行货币,而是应该和社会对货币的需求总量相匹配。)

2、现实世界也远没有理想模型那么简单。事实上还有很多特殊的小部门,例如金融部门,来负责增加整个系统的流动性。事实上他们并不真正生产什么(如果服务不算的话),他们最重要的功能是,通过杠杆来提供或者说调节整个系统的货币流动性。套到网站里面来说,我们也可以允许富裕阶层成立分数银行,来借给需要分数的人来提问,一定期限后要连本带息归还。更好的是有真正的银行可以吸储和放贷,更具体的就不说了。通过这种方式向新进入者提供流动性,比之随意增发货币,其副作用或小一些。不过这种模型要得以顺利实施,必须要解决的问题还有很多,并且不仅仅是技术上的问题。其中一个就是贷方如何挣钱,如果真是一个菜鸟的话,以目前的模型来看,恐怕只能打水漂。所以需要有很多不同的有价值工作来产生商品,并且能在市场上买卖挣钱。这种工作并非不存在,而且很多,就看愿不愿意想,以及系统能提供多大的能力。随便举几个例子,旧问题和答案的整理(可以通过政府支付),引导新用户查阅旧答案(新用户支付),撮合提问方和解答方的价格(买卖双方共同支付),巡查回贴找到疑似违反规则的用户(政府支付)等。

3、形成真正完备的自由市场,即定价机制必须完备。如果只能够由买方(买答案方)定价,没有一个合理的讨价机制,则这个市场的灵敏度必然会降低的。此外,也要提供真正的市场,把各种商品(比如问题的答案)放在市场上,进行充分的比较,形成真正的竞争,这才能寻找到合理的价格,价值规律才能生效。

实际上我说的这些是否完全只是一种想象呢?至少第一点就肯定有系统实现过。我不知道有多少人玩过90年代初的文字MUD游戏?如果没有玩过的,我稍微解释一下,就跟今天的在线网游非常类似,以中国古代武侠小说为背景,有各种门派,甚至还可以攻城略地。在这些个MUD游戏当中,肯定得有钱,因为你需要买装备,买吃的喝的等等。那么通常一个普通万家是如何得到钱的呢?打怪物,和现代的网游一样。不过至少有一点,可能跟现在我们玩的网游很不一样:你存在钱庄的钱,每天都要收取保管费的。这样从货币总量上就能得到有效的控制,不至于货币泛滥,因此物价总能保持于稳定的状态。虽然这样的无差别收税,还是有一定的坏处,但也总比没有的好,其坏处我们接下来会马上讲到。

我前面还提到了淘宝的信誉系统,估计有人会在这点上持反对意见,因为它并没有直升机撒钱,每个用户都均等的增加信誉,最后还是卖得好的赚得多。说得似乎没错,不过我们如果换一个方式思维:这是淘宝为每一个成功卖出的商品所支付的退税,那么这整个经济循环仍然还是不平衡的,仍然和直升机撒钱差别不大,仍然会通货膨胀的。那淘宝里面会是什么现象呢?就是我们会发现,刚开始有钻的商铺,就已经很牛掰了,到后面会出现皇冠,到再后来,就会出现非三皇冠用户看不上眼的情况。这样信誉这个货币就最终贬值了。贬值的结果是,新开的商铺会很穷。而且跟一般的通货膨胀还不一样,因为这种通货膨胀还因为信誉货币不被消费,或者不可消费的缘故,导致这是一种积累与炫耀的系统。而新的商铺虽然也能得到同等的退税待遇,但原始积累却有巨大差别,因此起步会变得异常困难,整个世界也会呈现越来越厉害的寡头垄断情况。而新商铺要打破这种垄断,就会采取非常手段来完成原始积累。比如说,采取虚假交易以骗取政府退税。当有人这么干的时候,这个问题就不可收拾了。越来越多人跟风(不跟风必死),货币增发也越来越厉害,通货膨胀也就越来越厉害。如果不采取措施,结果就会和津巴布韦一样,最后要发行以兆亿为单位的钞票。当然,我看着感觉淘宝是通过“折旧”的方式来消耗超发货币,否则早就该不是皇冠而是别的东西当道了。折旧也不失为一种办法,可以理解为向所有人定期抽税。

但是正如大家认真思考,就会发现这种设计也很不是很好。现代的税收有一个很重要的更能,叫做调节收入。财富不均衡会引起很多问题,同时富裕阶层也会更容易变得更富裕。如果没有任何的调节,系统就会进入发散的状态,最后很有可能会走向崩溃。类似淘宝的“退税”加“定期无差别抽税”机制,绝对是有利于富裕阶层的。因为约有信誉,退税越多,也就是信誉越多,也就越能经得起抽税。而信誉缺乏的,能够被买家看上的几率就越少,能争的信誉也越少。由于同样的速度等比例抽税,会造成这种商铺信誉会一直贴在地板上爬行。正确的做法应该是对富裕阶层适当提高赋税比例,而对贫穷阶层投放福利。不过即便是这样,信誉系统仍然是不平衡的,或者说不容易平衡的。因为总体来讲只能依靠退税和抽税,顶多再加上投放福利这三种方式来流转信誉,整个系统仍然是缺乏生产部门和消费部门之间的互动的。不过这种信誉系统的设计本身就是一种很困难的事情,我也没有想出个所以然来。现实世界的信誉也并没有被很好的符号化,尤其是可比较化的、公认的方法。(说市场化有点像要买卖信誉一样。)不过现实世界也有现实世界的解决办法,就是通过信誉量化后,用货币来调节制约人的信誉,就像信用卡或者类似的体系一样,越有信用越容易贷款,而信用违约则会造成融资困难。(注意,和淘宝中的约有信誉越容易赚钱,其模型是不一样的。)

我之所以提到淘宝,是因为还有一个很类似的体系,叫做威望体系(区别于CSDN的积分体系)。这种体系和信誉体系是很类似的,其相同的地方就是货币不可以用来消费。区别是信誉系统必然影响你的收入,因此肯定会体现出价值,而积分系统设计的不好,却未必能正确体现其价值。这个积分系统具体举一个例子,就是博客园左边的那个排行榜。这个系统通过政府采购人气的方式发行威望货币,通过折旧公式回收货币,理论上这个系统可以做到均衡的。不过有两个很重要的问题存在于这个系统内:

1、理论上可以均衡并不意味着实际上就是均衡的。比如说,系统增发和回收公式在设计的时候,没有考虑到规模扩大后对威望货币的需求如何变化,这样就有可能导致通胀或者通缩。有一种可能有效的解决方案是,采购时支付的价格长期保持稳定,而抽税过程则在一段时期后进行调整。当然,这并不是我推荐的方式,推荐的方式会在以后的帖子里面提到。

2、实际均衡了,也未必能正确体现价值。比如说,他只是一个排行榜,给大家读一读看的。这么设计,就有可能沦为炫耀系统。甚至可能很多人根本就不看这些排名靠前的博客,甚至产生各种负面情绪,觉得怎么也比不过他们于是移民、或者暴动。要让这种威望货币体现其价值,就必须将这种货币,和实际上的价值结合在一块。比如说,威望高的用户,可以选择将文章放在较显眼的位置;与此同时,显眼位置的文章,如果得到负面的评价,扣除的威望(罚款)也会更高。我所举的例子,只是为了说明如何让系统体现威望的价值,从而让用户去关注,甚至“追逐”威望。而这个例子在很多其它方面是有很多缺陷的,也不是我所推荐的方案。

 

说了这么多,不知道大家有没有什么想法和感觉?如果你觉得我说得不对,或者没有任何启发意义,甚至极力反对我放在首页等等,都可以回复。但请不要出现人身攻击的激烈言论,无论是对我还是对回复的过客。

我估计一定会有一种回复的声音说:你怎么这么俗啊!整天钱钱钱的!发贴子的崇高意义怎么到你的狗最里面就变成了俗不可耐的金钱关系呢?

这个嘛,如果真有这么样的想法,我建议您耐着性子,继续看我同系列的下一篇:符号化的意义。也许看完后你会收回这样的想法,也许不会。到那个时候我们再来对此展开讨论,我想至少层次会比钱这种很俗的话题要高得多。

P.S.:

我预计我昨天第一篇放首页的随笔“博客园的首页”,会在今天中午12点之前跑到第二页。同时我预测从今天中午12点之后开始,直到6月5日中午12点为止,所积累的阅读量和回复量应该比第一天的数量分别都要少,甚至可能就不在一个数量级上。我中午会在这里记录一下这个数字,到6月5日中午12点,再记录一遍,看看我的预测是否准确。不过需要说明两点:

1、我可能会忘了,如果有人知道我MSN的,请提醒我。

2、我的“预测”,只不过是研究问题的一种方式,相当于是提出一个假设,然后用实践去检验一下,看看是否能推翻我的假设。当然了,这种检验只能用于推翻自己的假设,而不能用于在验证正确之后,证明这种假设是一种理论,对此我很清楚。(有点绕口令?那算了,你当我没说好了。呵呵)

____________________________________________________________________

5月27日观测结果:

在12:50分左右的时候,也就是“博客园的首页”发表几乎正好一天的时候,该帖子处于第一页的倒数第一/第二的位置。(因为似乎有一篇文章被抽出首页了!)这个结果没有达到我预测的那样,不过相当的接近。我猜测可能是端午节前的缘故,导致有些TX已经放假了。至少看着今天的文章阅读量远没有昨天多。

截至观察时刻,有1571个阅读,以及87个回复。看看下一次观察的结果如何。

 

posted @ 2009-05-27 09:33 Sumtec 阅读(1359) | 评论 (49)编辑

2009年5月26日 #

现在很多人都很专,专到了随便张口就一堆英文术语,其实狗屁不通。为了避免大家误会,特意声明一下,这个只是我在真实世界里面的遭遇,导致有感而发,跟博客园内的任何现象完全没有任何关系。我憋了很久了,实在憋不住找这一机会发泄一下而已。请大家真的不要对好入座。好,这个就不说了,回归正题。

我今天要开讲眼球网站经济学之我见,大家别误会了,以为我说怎么开一个吸引人眼球的网站来赚钱。我要说的是,一个眼球吸引型网站——比如CSDN啊、淘宝啊、新浪啊等吸引不了眼球就会消亡的网站,他们内部的一些经济学规律(或者其它学科的规律)。有点晦涩?没关系,我们下面就直接开始讲生动的案例——博客园。

我一开始不打算以博客园作为开篇的,不过后来发现那个该死的按钮竟然引出来一些这样的回复:

我最讨厌博客园的首页制度,以前发了几篇文章,就被弄下去了,而却还留了恶意的留言,恶心死了。所以从那以后我就在博客园上封笔了,安安静静做一个潜水者,因为这不是你发表思想的地方,这里有很多的大佬,是他们的天地,你一个无名的小辈给我滚一边去。
从我做了一个潜水者之后发现一个现象,那就是博客园现在的文章的更新率越来越低了,在2008年年初的时候一个周末(2天)就会有十几篇文章出来,而现在一个礼拜才十几篇,呵呵,看来越来越多的人选择和我一样,做一个安安静静的潜水者,就让那些大佬们高声唱响吧,因为他们才是有资格上首页的人!

好久没写过文章了,现在只是观望,潜水观望

是啊。我第二天看博客园首页,都有一小半还是第一天的文章。希望社区氛围能够好起来。

我一直以为自己的观察方法有误,或者自己的感觉器官有问题,现在才确认原来没有错。对,博客园首页首页能看得东西确实越来越少了,更新速度也似乎越来越慢了。为什么?

首先,更新速度越来越慢这个问题,我要修正一下,是否真的越来越慢我不清楚,没有统计。但是感觉越来越慢是确实,因为通常我可以好几天不上来,然后上来一次翻个五六页,也就能看上个几篇。因此会有主观的感觉——现在可以好几天才上来看一次了。造成这个问题的原因,再上一个讨论法不到首页的按钮里面已经作了一些比喻了,这里我就继续使用这些比喻,并把它给具体化。

夫有一国,曰博客园,于网际间。国地方万里,都城仅三分。众民止往都城,外鲜去。缘此都城地值千两,复引众。夫国始“代表”年间,今约十年矣。民初仅十几,地尚足盖,现众不可数,地缺。为决民宿之题,设巧律,曰:众人皆可造房,新造者拆旧房。初群起奋勇,造而复毁,不亦乐乎。后觉无用,且毁与优无关,善造者始旁观。终劳民伤财,国库弗进。

这个就是我们博客园的问题,这种问题可以用一种经济学现象来近似的解释,叫做劣币驱逐良币。什么是劣币驱逐良币网上一搜一大把,详细的自己去看,我这里也给稍微解释一下。所谓略币驱逐良币,就是说在金属铸币时期,货币发行当局为降低铸造成本(尤其是特殊困难时期),而做出不足重或者成色不纯的货币投放到市场,这种称之为劣币。而大众由于觉得手里面的劣币成色不好,被拒收的可能性较大,因此都倾向于把成色好的留在手中,以便未来不时之需(尤其是紧急状况时)。于是在市面上流通的货币中,劣币就越来越多,最终导致良币在市面上事实消失。这种问题,在近代甚至是今天也都会出现。先说今天,如果你不小心收到假币,十之八九是首先尝试把它花出去,而不是留在你的手里。而稍微早半个世纪之前,美国仍然实施银本位,也就是你拿着一块钱的美元到银行换,银行是有义务按此给你兑现一定重量的白银的。后来因为各种原因,导致出现了一种不可兑换白银的美元,此美元背面是绿色的,叫做绿背,相对的原来那种叫做银背。这两种美元钞票在一段时间内同时流通,按照法律解释是等价的。但谁也不是傻子,显然银背更值钱,可以兑换真金白银啊。于是最后大家都收藏银背,使用绿背,其结果就是绿背美元在市面上流通,而银背实施上退出流通。美国政府后来也不发行银背了,因为发行多少被收藏多少,市面绝对不流通。这完全起不到增加流动性的目的,反而增加自己的成本和兑付风险。虽然现在仍然是有效的钞票,但谁也不是傻子,实际价值超出票面价值的钞票是绝对不可能流通的。

还有一种很特殊的劣币驱逐良币的现象,大家每天都经历着,甚至每个人都会在运用:破损残旧钞票。你打车的时候,手里一张新的100,一张旧的,你会给司机哪一个?不用想,只要神志清醒,脑子正常的都会给旧的。当然,如果是一个很破旧的100块钱,司机多半会拒收。你被拒收之后多半还会尝试在别的地方优先把它给花掉。当然,还有一种途径就是到银行要求换新的,虽然极少这么做,但是我看应该有不少人这么做过。实际上各大银行都会在柜台、存款机那里抽出残旧币退出流通,甚至央行跟各大银行之间也应该有这种专门点旧钞的机制存在。中国有没有不知道,美国的联邦储备局每天收到其它银行的往来现钞,都会经过几台巨大无比的机器,然后抽走不合乎流通规格的钞票。否则你想,这市场上流通的,肯定都是其旧无比的钞票了。

那么套到博客园身上,我们如何解释呢?

前面我也已经解释了,博客园首页不分流,导致绝大多数读者仅停留在首页。而博主发文章,当然是为了寻求认同感,甚至寻求被追捧的感觉。这本身没有什么问题,是再正常不过的事情。但由于首页页面毕竟有限——记得以前首页一页没那么多文章的,很多还是不做摘要整篇的挂出来;现在人多了,文章也多了,即便强制自动整理出摘要,也无法容纳太多的文章。而整个机制又设计成新文章永远在前面(无论好坏),旧文章永远靠后(同样无论好坏),于是为了占地盘,大家就要不断地发文章。刚开始还好,有一种踊跃的气氛,但后来人越来越多,不用想也知道会出现文章不到一天就被挤到第二页的结果。

以前是写一篇文章整个园子的人都看一遍,如果写得好,几乎都来评价一下。现在呢,也许还没有被五个人看到就已经被挤出去了。当然,有点夸张手法,不过我确实曾经发了一篇文章,没过一天就被挤出去了,实在不爽。好,大家发文章为了什么,简单化说,是为了受关注。现在文章被挤出的速度那么快,为了出名受关注怎么办?最简单的办法就是拼命的发文章,摘抄啊,转载啊,无所不用其极。第一个发现这个窍门,并且付诸实施的,一定是最爽的。后来其它人也发现了,于是质量差,但是生产速度快的文章就更容易在市面上“流通”。而花时间思考,细心制作的同志自然感觉亏——我花那么多的时间写得文章,得到的关注却越来越少。这就形成了一种“劣币驱逐良币”的效应,只要不加以控制,这种自发的循环就会越演越烈,最后导致经济循环的奔溃。当然,摘抄转载也没有什么不好的,甚至有不少高质量的。但是同样的,低质量摘抄转载也会驱逐类似的高质量摘抄转载。

那个该死的按钮从这一角度讲,也是为了控制这个问题,只不过效果有限。劣币驱逐良币的问题其实解决起来并不难,我们从经济学世界可以找到一些答案:

1、合法铸币方不制造劣币,没有劣币也就无法驱逐良币;

2、对制造假币的,施以极刑;

3、提供鉴别劣币(破损币)的方法;

4、提供合法但破损钞票的回收途径,甚至主动想办法收回。 

那么我们来分析一下这个按钮,看属于上面这四种的哪一种?都不是!最接近的是第二个,但是,这个按钮只是实施“恐吓”,是否真的有什么后果没有人知道。你想那些造假币的,被逮起来了肯定都会被各大媒体疯狂宣传,最后判个极刑也是公开宣判搞得路人皆知,恨不得再来个公开枪决。为什么?就是要达到极大的、有目标性的威吓。要是我们把故事改一下:国家对所有人宣称“使劣币流通的都会被处罚”,然后怎么算劣币、怎么处罚大家都不清楚,有没有处罚过、处罚了那些人大家也不清楚。而这些真正“恶意使用劣币”的人,国家采取暗杀,然后消灭一切档案,搞得这个人似乎从来就没有出现过一样,人间蒸发了。可以想象,真正造劣币的不会感受到多大的威胁,与其得到的好处比起来,会得到一个错误的结论,认为仍然是划算的(不就是多看一眼“你真的要发布吗?”)。而与此同时,所有良民却要因此受到不必要的骚扰和恐吓,每次使用货币的时候都要揣测我手上的这个是不是劣币,万一被认为是劣币,我会被如何处罚,五马分尸吗?(未知和不确定性对于公众是最大的恐惧。)

现在这个按钮的设计就极其符合我说的后面那个故事,所有人遭罪的同时,没有起到多大的效果。我们继续顺着刚才那个故事想,是不是造劣币的坏蛋继续造劣币,好人却不敢使用任何钞票了(甚至会愤愤不平的把自己家的黄金收藏好)。博客园的“发布到首页”及其后续弹出对话框,是否符合我的假说,就留给大家评论了。

那么我的建议是什么呢,和上面四点类似:

1、改造首页,使得首页呈现更精彩的内容(制造良币,不要制造劣币);

2、对制造劣质文章的行为,有明确且可操作的惩罚方法,并且公布处理结果(施以极刑);

3、提供明确且可操作的鉴定方法,能够识别文章的质量和水平,合理的、分别门别类的处置这些文章(不是所有的劣币都是非法的,甚至完全不可流通的。其中假币要严惩,破损或者残旧的货币应该允许合法流通,但应该有合理的回收机制,或者其它处置方式使之处于合理的范围中流通。比如北京的钞票就相对较新,边远二级城市的就相对较旧。甚至有的时候为了某种目的,应该允许其广泛流通,就像绿背美钞一样。套到博客园则可能是一些广告,或者软文,我这是打比方,虽然我不喜欢这种东西,但是能理解。);

4、提供合适的旧贴回收机制,而不是单纯从文章的发布日期来判断。有些很有深度的文章,即便十年后看仍然是相见恨晚的。而一般的文章,可以让普通的网友通过举报,然后经过一定程序(不是计算机程序)判断,最后可能因此打入冷宫,这相当于到银行柜台主动要求换新币。同时通过被点击数量等技术手段,判断文章被认为陈旧的程度,类似银行内的回收旧币机制。有些文章很可能每天都有人点击,每天都有评论,那么为什么要让这些新刷刷的钞票被回收呢?这不是极大的资源浪费吗?(合理的回收途径)

我对于目前首页中充斥着对各种最新技术的“报道”感觉很不满意,因为这种报道说难听点就是随便一Google就出来了,并不是真正有价值思想的根本源泉。不排除有些最新技术报道中有个人的思想闪光点,但是总体来说一个是确实少,二个是这种报道能产生思想的概率相对是较低的。这种文章应该有,但绝对不应该大量出现,因为新技术不是天天出,大家都报道,同质化也会很严重。而产生这种现象的一个根本原因,我认为就是“劣币驱逐良币”。这种问题不解决,我可以断言未来的情况会越来越严重,有思想的文章会越来越少。我不是赌气说的,因为我当然不希望这样的情况真的发生。 

对于上面的分析,不知道各位看官认同不认同。我的个人感觉是,这种网站经济学生态的问题,似乎很少被关注,甚至很少有人这么去思考,而这些问题则是导致一个站点成败的重要原因之一。我们博客园还有一个很不好的气氛在于,技术最优先,尤其是计算机代码技术最优先。而我个人认为,这个世界有很多很多的知识,那些跨学科的知识有的时候是很重要的。如果你不懂经济学的话(哪怕是皮毛也算懂),那么这种问题你永远也不会看到,更不用说想到了。我还可以再举一个例子:你想过网站内也会发生“通货膨胀”吗?

P.S.:我现在才发现,那个该死的按钮还有一个更雷人的设计:

立即发布到博客园首页(2小时之内只能在首页发布1篇随笔)(2小时之内只能在首页发布1篇随笔)(2小时之内只能在首页发布1篇随笔)(2小时之内只能在首页发布1篇随笔)(2小时之内只能在首页发布1篇随笔)

为什么?凭什么认为我两小时之内不会产生两个很有思想的文章?而且更何况,我第一篇文章是中午发的,而后面看到了大家的评论,只是修改了一下原文,把诸位的答案写到文中,以便各位看官更好的理解我的本意。没想到这也被计算到发表到首页的最后时间里面了。

不过从这个雷人的设计可以看出,要么博客园已经遭遇了极其严重的“劣币驱逐良币”问题,要么就是面临了一些其它问题——例如广告贴和发贴机器人。不过从这种无差别首页杀人技术看,其针对的更可能是“劣币驱逐良币”问题,否则就应该设计在发表这个按钮上了。嗯,设计问题啊!有人意识到这是设计问题吗?不要以为设计问题就知识继承、派生、封装、SRP、OCP、DIP、设计模式、XX驱动开发、X层结构等纯代码技术的问题。这种也是设计问题!作为客户,更关心的是这种设计问题,我才不关心博客园代码里面有上述术语中的几种呢。

没办法,诸位看官看到的时候,估计已经因为这个可恶的设计被推延了不少时间了。

 _________________________________________________

嗯,有同志说,着劣币驱逐良币不是正儿八经经济学里面的东西,我承认。说得好,确实不是经济学研究的东西,不过也算是一个经济现象吧。这种细节我个人觉得不必深究了,借喻一下没什么不好的吧?我记得我第一次看到这个说法,还真是在博弈理论里面看到的。我说跨领域的问题,并非批评某个具体的人,而是说一种现象——就是每一个小圈子内的人,多数只会关注这个小圈子内不的事情,其它问题几乎不知道也不关心。当然我知道要求一个人同时在两个领域都很深入的了解是一件很难的事情,但是你也不得不承认,跨学科的科学,会有不少对人类社会产生重大的影响,有很高的价值。但即便是对别的一些领域的有所知晓,在很多时候也能给我思考问题的方向带来一定的启发。

我的文章被否定?我不怕别人否定我的文章,我会很认真地去讨论和研究,有错误了就会改正,深刻反省。不过有些东西我觉得是不能认同的,即:将寻求被认同感等同于炫耀。有时候有些概念的差别说起来就是一线之间,但毕竟还是有着本质意义上的不同的。如果寻求认同能推导出就是为了炫耀,那么估计人类就不会进步了——四处招摇炫耀的人,显然是大家的公敌,恨不得一棒拍死。我写文章为了什么?名誉?不觉得。发发牢骚?真不认为。我说博客园首页的问题,真的只是为了博客园有更好的发展,也许和我自己所批评的一样:动机是好的,结果却是坏的。如果果真那样,也请多包涵。但不管怎么样,说我动机不纯我绝对不接受。此外,这位看官说的和我的不是很有交集——我说的问题,不是如何允许没有价值的文章待在首页,更不是替自己某篇滥竽充数的首页文章被砍掉了而撒气。我印象中没有任何自己的文章被管理人员刷下来的记录,而且我认为我放首页的文章都是仔细思考的内容,顶多是跟Coding沾边比较少。另外,我自己觉得对自己还是要严格看待,因此我也经常把一些很想放首页,但是有所犹豫的文章给私藏起来了。如果说,我站出来是有什么目的的话,正是希望让更多人的好文章(但不是太过Coding相关的)能够被看到。比如怎么写一个Photoshop的滤镜,其实也是一个饶有趣味的事情,我很有兴趣看。不过这类的文章确实会被埋没,而这又是博客园网站设计所造成的。我想,如果有人提出这个问题,真心希望是有人来思考,并最终解决这样的问题,应该不是一件什么坏事吧。我想,更不应该会有受这个问题负面影响的人,站在这种立场的对立面上吧?

还有回复说,我把问题想简单了。呵呵,没错!不过嘛,建模的时候都应该是尽量简单化,否则太复杂了,模都没法建。不过我也知道问题当然没那么简单,所以我很愿意在这里说一句,大家不要把问题想简单了。事实上我并没有给出很具体的操作性答案,而只是给出一种思路。真正要实现真的没有那么简单,不是说加一个评分系统就可以解决的,如果真那样简单真是天下太平了。我不希望类似的改进在仓促中出台,这样可能伤害更大,这种责任我担当不起。

最后要说一句,感谢dudu提供这么好的一个平台,真心希望博客园越办越好。

(其实我说的这些问题,也正是博客园成长之后才会面对的问题。所以,也许我的用词重了一些,但我认为其实也算是一种好现象。请感觉用词太重的TX,就当作是一种玩世不恭的风格吧。)

posted @ 2009-05-26 16:51 Sumtec 阅读(1864) | 评论 (51)编辑

我不知道这个问题有多少人感到头痛:当你发布一篇文章的时候,该不该选择发布到首页呢?

尤其是对于一些你没有把握的内容,例如:我想谈一下F#统计学上产生替代R语言的可能性,但我又不敢肯定我的想法一定是对的,因为我既没有用过F#,也没有用过R,更对统计学没有很深入的研究,因此文章内容基本上是基于表面观察以及不知道考不考谱的假设。这我就很头痛了。

再比如,我用E文写了一些关于设计的浅显文章,是否可以放到首页?着我也很头痛。

我相信对于很多新手,这更是一个问题:比如设计模式,在这里其实都已经颠来倒去的说了很多遍了。对于一个新手来说,也许确实很有价值,但是放在首页,有的人也可能会觉得没有价值。

这个时候如果选择“发布到首页”,我会感觉在犯罪。不选择我也知道没人看,就好像股票被放到三版后就没人买卖一样。想了半天,硬着头皮上吧,管它呢,骂就骂吧!结果屏幕弹出来一个:“友情提示:……万众瞩目……精品的地方。你真的要放在首页吗?”心想,还是算了。

于是你说发布个文章还处于这种心情不愉快的过程中,真是让我感到despressing——为什么要自讨苦吃点那个按钮呢。

其实这个问题本质很简单,就是要保证首页文章的质量,大致办法有两种:

1、限制会员群体(限制会员本身的质量)

2、限制发布到首页的文章质量(不限制会员)

目前按照博客园的思路,断然是不可能用第一种方式的。但即便采用第二种,方法也很多。怎么样才能够以“用户友好”的方式来解决这个问题,其实是很有学问的难题。在这里我也先不说那么多我的想法了,大家讨论一下有何改进方式如何?

反正我是对这个按钮已经无法忍受了,每次点不是有犯罪感,就是有自讨没趣感(发牢骚没人看发来干什么?!)。抛砖引玉ing...

____________________________________________________________

我看大家的回复分为:

1、审核机制

2、评分机制

3、靠自觉

4、吃饱了撑的吧,去死吧

5、分级机制(嗯,提这个的比较有创意)

我简单回答一下:

1、审核机制的好处:质量把关松紧好控制(不意味着一定精确合理);

坏处:需要耗费极个别同志的极大精力,并且这个机制除非是内生性的,否则不可持续(人总有自己的生活,指不定哪一天就没工夫了,很正常,不能要求人家无条件奉献)。

2、评分机制的好处:持续性容易保证,并且不需要特定人员来处理(有着广泛的群众基础);

坏处:这种系统的设计很重要,弄不好会没人愿意使用,或者会有逐渐失效或者部分失效的风险(CSDN既是一个例子)。

3、靠自觉我觉得有点跑题了,不是我的本意,既然有人说,我也回答一下。

好处:不用说了,主办方最省心,同时似乎有利于提高全民素质。

坏处:实际上一点也不省心,照样要设计一个按钮出来。此外,人总会偷懒,或者有各色想法,你很难保证自觉自律能够一直work下去。人越多,这种方式越不可靠,否则也不会有法律及法治社会。最后,也是最难用这种方法解决的一点是:一百个人有一百个哈姆雷特。我觉得好,别人不一定觉得好。返回来再想就很别扭:我该不该发到首页呢?可能别人不喜欢看回复几个去死多不好!

明明应该是很愉悦很有成就感的事情,会因为这种情形变得感觉不好,感觉不好肯定是一个导致不愿意发表文章的原因。现在关键是这个按钮的设计在我们想要发表文章的时候都会提醒我们这种不愉快的感觉,因此我认为很有必要用其它更合理的方式来实现。

4、吃饱了撑着?我不想多说了,当年我就是因为类似的原因逐渐不上CSDN的,我当然不希望博客园面临类似的问题。我个人认为那个按钮从感情上讲应该是个不小的负数,虽然从动机来讲是好的。而且我认为这种按钮实际上只是一种表象,不是病因,实际上是别的原因引起这种按钮的出现。例如:首页没有起到应有的分流作用,几乎所有人都只是看首页,最后导致首页“地价”飞涨。作为官方当然不希望唯一赚钱的来源——卖地皮受到威胁,因此其对策就是不允许各种有损市容的建筑出现。这是问题的来由之一,估计能想到这个问题的不会超过50%。说我吃饱撑的,有谁认真想过了。

5、分级机制好处:适合不同的人群,让几乎所有文章都有一个合适的去处;

坏处:不好分级,谁分?怎么分?此外对于首页来说也不太好设计。

还有别的提议没有?感谢所有认真思考的TX。

______________________________________

@winter-cn:
理解不准确,我的意思如下所示。

以前:
人少地多国民素质高-〉随便盖一个都是艺术品(懒得思考的人进不了博客园的,也许只有老同志才知道),并且可以保留相对长的一段时间。—〉自我感觉良好

后来:
为了和博客堂这个国家搞差异化竞争(同时也有GDP方面的考虑)->降低移民条件-〉人口暴涨(鱼龙混杂)-〉人均土地(首页)占有量减少 -> A&B
A:为了盖房子必须要拆房子-〉按照时间先后顺序拆老房子->刚开始大家都拼命的建以替代被拆掉的不良感受-〉实在耗不起那个精力-〉懒得写了,看吧

B: 部分浑水摸鱼的用转载文章等低劣建筑占地-〉其它公民抗议(凭什么用这么丑的东西把我的老城堡给拆了)-〉可恶的按钮出现了—〉每个人造新房子的时候开始要思考,我的房子好看吗?-〉C|D|E|F

C:我尽最大努力造了个房子放在首页上-〉被骂(因为这方面我确实不熟悉或者其它原因,但绝对不是我没有思考)-〉没劲,不发了(这不是按钮出现的目的,相反,这类群众应该受到合理保护,否则有违移民政策的初衷)

D:我尽最大努力早了个房子,感觉没把握没放首页-〉没有人买(每人看啊)-〉认真思考:我造这个房子干什么,没事白折腾么 -〉没劲,不发了(这个也不是按钮出现的目的,或者说目前没有机制适合这个问题扯上关系的,这也有违移民政策的初衷)

E:我尽最大努力造了个房子放在首页上-〉赞扬 -〉一天内就被拆(因为有新房子)-〉每人看了-〉不爽-〉没劲,不发了(说明按钮不解决土地稀缺问题)

F:我随便造了个房子放首页-〉被骂-〉不爽-〉再也不敢了或者走人(这个确实是按钮出现所希望达到的同样结果,但是大家有没有想到过,最终这个按钮并没有阻止这类违章建筑出现,最终是被骂导致的)

当然还有别的几个路径,比如认真思考-〉爽,或者懒—〉算了,这种就不再讨论了。

这个该死的按钮不会解决想要解决的问题,反而会带来一些别的问题。当然,在没有新的解决方案之前,这个按钮是不能撤下去的。一来是心理上的安慰,第二也是对犯罪分子的一种恐吓(虽然也会恐吓良民)。

 

现在我:

实在想些点什么-〉写-〉按按钮-〉看提示-〉思考-〉头痛—〉算了

 

_____________________________________________

看来我的想法还真不是很另类,也有人和我一样感受的,比如首页特别单调的问题。这个问题确实也是很致命的,俗语说众口难调,如果硬要给首页来一个“非高深技术不能上”,最终结果会导致小众市场。如果这样又何必当初允许大家来注册呢?到底是要小众还是大众,相信dudu心里面很明白。 这种限制已经使得我不只一次想过自己搞一个空间放自己的首页,但后来都是因为这里志同道合的人多一些,浏览量高一些,以及自己搞很麻烦之类的不是问题的问题而放弃了。但可以看到,确实因此损失了一些能出产“房子”的公民。当一个国家的国内福利政策,与其移民政策相违背的时候,这个国家肯定要陷入极其尴尬的局面,就是高流失率。这和经济学的问题一样重要,只不过想到的人能有多少呢?

此外,也有人提到了,现在有人争论还是好事,等没有人争论了,就是晚了。(过来人,你说的是我心里话啊。)同样的,我相信你也应该感觉到,有些人说话口气很冲,目中无人的那感觉很糟糕。甚至有人笑话老赵幼稚,真是不知天高地厚,怎么说人家在这里呆时间比你长,你也不想想你比他幼稚是不是会几率很高。再说了,人家那也是很有无私奉献的精神,处于很好的动机说的话。怎么就变成幼稚了?也许有可能不具备可操作性(有待考证),但怎么也不是人的秉性问题。很多时候我都对这种回复报以极大的忍耐,今天我实在是看不过去了。我希望这种问题应该得到控制,至少要有明确的说法,对这种问题如何处理。论坛有版主,网游也有类似的(气得叫什么都忘了),总有个人管,而这里没有人也没有规矩可管的。

通常对于这种回复,我都不会做删除这种事情,觉得没必要。但是有的时候这样的用户确实应该要先给予劝告、警告,直至开除。游客随便乱叫无所谓,也没有很好的管理办法。关键是看到一些顶着博客园URL的也这么做,会有一种在这里呆有点丢脸的感觉,想要换一个素质高一点的氛围呆。

 

posted @ 2009-05-26 12:55 Sumtec 阅读(2002) | 评论 (89)编辑

The last story told us that we should buy an air ticket. However, some times we do buy train tickets. What will be their destinations? And what can we do with them?

If we do buy some train tickets, the destination of the tickets definitely can not be Brisbane. Well, yes, maybe there are chances to ship the carriages. Let's suppose it is in a common condition and we can't ship the carriages. So, you would probably get a ticket to Guangzhou, a ticket to Hong Kong, a ticket to Hanoi, or a ticket to New Delhi. We can take a train with the ticket we bought and we can arrive at the destination printed on the ticket. Yet, we can't get to Brisbane. If some one bought such a ticket for you, I guess you will be clever enough to make a dicission to refund the train ticket and bought an air ones instead. Even the most stupid ones who do get on the train will get off it as soon as possible. It is because we know that farther we get, the more it costs. It is a common sense, too.

However, in code designing world, we often fail in the simular situations. Here is a funny story:

Long long ago, we started a asp.net project. In the early age of the project, we needed to rewrite paths to cover some meets. So, we created a HttpModule in one of which events we checked the request paths and rewrite the paths in some conditions. We could call it an url rewriting module at that time.

Centuries passed, and one day, we found that we need to mount an equipment called smartcard in order to enhance our security strength in some special scenes. I don't who, since the alphabets were not yet developed and no history about this was recorded, decided to append some codes in this module to achieve the goal. It did achieve the goal. And it seems convinience for the author to write the codes in such a place. It is sure there was no such kind of module which could capture global events except the so called url module. Ah, yeah! I forgot to mention that the module was called url rewriting and smart card supporting module since then on.

Another decades passed, and one day, we found that DOS attack happened. We need an interceptor or a black list. Yet, there is no clue about why but it did happen that some one put the intercepting logic in this module. From then on, its name became the url rewriting, smart card supporting, and DOS intercepting module.

I think you may guess what would happen next. Yes, indeed, there were more and more functions sat inside this module. And one day, we found that the module was named "the url rewriting, smart card supporting, DOS intercepting, error handling, users and directories authorizing, load balancing, logging, access recording and analyzing module. If there were something missed, I can say nothing but a "coffee making" function.

All right, what is wrong? Yeah! It just broke an important rule called "SRP" - Single Responsibility Principle. I think most of you should know this clearly. Nevertheless, there are still too many developpers who do not know that. Or, even worse, some of them know its name but nothing more, and they do not only obey the rule, but also reject it and sweep them out of the code. It is horrible if you are in such a situation because you will found that you are a cleaner, a disrespectable cleaner. Day after day, you will find this job will be becoming more and more unenjoyable.

Okey, let us focus on the story again. After reading this story, you should ask why this happened. I provide two posible answer: One is lack of designers; another one is that concepts were not formed up concretely. In my opinion, one who do not know SRP clearly should not be called a designer. So let us take a look into the second reason.

Sometimes we did know what SRP is, and we did design it in the beginning like our story. However, we would found that the things happened next was out of the track, like our story too. First, you should ask your self whether the concept of the module was defined clearly. In this example, it was. But sometimes it is not, for example: a module for preliminary tasks. If you are in this situation, you should clarify the concept and pick out the frustrating part. Another depressinging situation is that the module was neither limited enough, nor understood by the others enough. If so, you so do the following two steps:

1. Refactory the module with better design patterns so that the others cannot insert irrelevant codes. One pattern I love most is the "Template Method". Maybe you have your own favorite, it does not matter;

2. Train or educate your colleagues. Sometimes they just do not know what they did would harm the quality of the codes.

Overall, it is easier said than done. Probably you would find that you are in the same boat with me.

Next time, maybe I will continue talk about something. Or maybe not, who knows?!

posted @ 2009-05-26 12:25 Sumtec 阅读(73) | 评论 (0)编辑

2009年5月25日 #

人类的世界发展到今天,真是无奇不有。最近看了一些关于计量经济学的贴子,发现了一个对于我们这一圈子的人来说,可能是极其陌生的计算机语言,叫做R。这个R语言的前身是S,是一种函数式脚本语言,主要就是为了做统计学,才特别被设计出来的。据了解,发明S语言的团队,还荣获了199X年的ACM最佳软件系统大奖,说是统计学软件中的唯一一个获此殊荣的。

当我看完这一堆堆的文章之后,不得不感慨,科学发展到今天,恐怕最大的鸿沟不是垂直意义上的知识深度问题。我相信知识深度问题应该是很好解决的,例如90年代初的时候,大多数国内的软件人才对于开发语言估计还停留在C上面,实际上此时C++都已经发展了十多年了。即便到了21世纪初,仍然会有某些学校的某些院系仍然停留在C,甚至是PASCAL这种古董级语言的教学上(注意:是“停留在”,这些老语言简单固然比较容易入门,但是接下来就没有教别的了)。当然了,今天国内也已经有很多人能够追上时代潮流,比如.NET 4.0还在CTP的时候就已经有很多人在学习研究了。所以,这真不是什么问题,毕竟在一个领域一直钻下去不难。

真正的Gap在于跨领域的时候所存在的问题,比如当经济领域需要使用到统计学方法,或者反过来说,统计学方法应用到经济领域的时候。具体讲,当一个纯粹的经济学需要用统计学方法来解决问题的时候,这些统计学方法对他来说可能就会变成新的、相对陌生的领域,需要花很多精力和时间去解决。而这个时候更麻烦的问题在于,他可能很难找到一个对经济学感兴趣的统计学大师来教他最新最先进的统计学方法,能找到一个能听懂最基本经济学术语的统计学菜鸟估计就已经很不错了。因此,这个时候通常只能从最简单的问题开始,慢慢的进行融合,直到两个学科都懂的人才出现,这种交叉学科才有可能出现大发展。当然,今天的计量经济学已经不是我所举例的那种状态了,但我敢肯定当这种交叉学科刚出现的时候,十之八九和我说的情景是相似的。

我之所以这么说,是因为我发现这个R语言被称之为先进,在我粗略看来却并非如此(姑且算是妄下论断吧)。有人号称这种语言是“面向对象的”,可我怎么看也并不觉得是真正现代意义的面向对象的。当然,这个语言中有“对象”这种概念确实是对的,这个先进在统计学圈子内也是能算得上的。关键是,在我粗略看到的信息里面,似乎很少R语言的使用者真正了解甚至关心R语言到底是一种什么样的语言,比如说是静态的还是动态的?强还是弱类型的?动态还是静态类型的?编译的还是解释的?等等。他们所关心的是这种语言能解决什么样的问题,我认为这是理所当然,也无可厚非的。但正如统计学中“不拒绝并不意味着可以接受”一样,关心能解决什么问题并不意味着一种语言的本身属性就不重要了。语言本身的属性决定着其各方面的性能,甚至决定了适合解决什么样的问题,以及编程解决这些问题的效率如何。就目前我的认知:R语言对于绝大多数统计学学者来说,应该是“Thanks god,there is a good *language* for me to use”这种的感受。我也不得不承认,就目前而言,这个语言用于解决目前的大多数问题,应该是足够了。不过,以开发人员的角度来衡量,这个语言仍然有一些缺陷:

1、并非现代意义上的面向对象,其实现方式有点像C语言的那种,需要自行封装分派的。此外成员也没有公有、私有、受保护的修饰,也没有不可重载或已经封闭等修饰,缺少接口(或者多继承),此外还有一些由于语言本身的设计所造成的、在我们看来很怪异的问题。我们举一个具体的例子,比如说下面这个求均值的函数:

mean <-function (x, ...)
     UseMethod("mean")

当我们具体调用这个函数的时候(结果是3):

mean(1:5)

调用的时候,系统首先会将当前函数的名称mean放到上下文变量.Generic上,然后把x的类型Integer放入到.Class变量。而UseMethod函数在这一个例子中,会根据.Class以及UseMethod("mean")中的第一个参数的类型名称Integer来找合适的方法mean.Integer,然后再调用它(有点像C那种的派生继承吧)。实际上还可以写成UseMethod("mean",x),或者UseMethod(,x),或者UseMethod()。缺少的参数会从.Class和.Generic里面找。

好了,现在有两个很“奇怪”的问题。第一个是,如果有人直接通过mean.Integer(1:5)来调用,则.Generic不会有内容,因此UseMethod缺少第一个参数是很危险的。第二个是,UseMethod调用之后,即随便后面还有其他代码,也不会执行的(实在太怪了)。

从上面的描述可以看出来,这种面向对象是一种比较不正规的,揉合了泛型的对象模型。甚至根据我目前的理解,“面向对象”的函数都必须首先要有开放泛型函数的存在。而UseMethod的特殊行为,导致了每一个“面向对象”的函数都必须要写且仅写一句废话。

(注意:我确实没有用过R语言,因此其实我并不确定上面那个例子中的.Class会是什么,也许不是Integer,但概念应该是没有理解错的。具体请见http://cran.r-project.org/doc/manuals/R-lang.html#UseMethod

 

2、没有命名空间的概念。这个设计缺陷必然会导致命名污染的问题,同上,没有一段足够长的时间,这种问题是不会被注意到的。

3、缺少很多其他先进的语言特性,这里就不详再一一列举了。因为这是很自然的事情,毕竟我们不可能期待一个目标是要解决统计问题的语言,能够在出现后短短的时间内跟上通用语言的发展步伐。

需要特别说明的是,我这么说也许会给大家带来误解,认为R语言就一定很落后。非也,R语言也有自己的垃圾收集器实现,而且和.NET的类似,是分代标记收集法(具体分3代,说不定还是.NET 参考了R或者类似的语言设计的)。 其实其内核算不上最前沿的,但也绝对不能说是土得掉渣的。目前的情况之所以如前面说到的那样,语言设计本身并不先进,其实也是因为统计学领域确实缺乏能够很好的解决他们的问题的语言,包括相应的函数库或者模块。我估计,就其目前的发展阶段,该语言的侧重点应该还是“能很方便的解决多少统计学问题”,而不是这种语言在解决这些问题时所面临的计算机语言本身的缺陷。可以这么说,我这里所做的推断也许要十年左右之后才会得到印证。当然,我希望能够更早一些。因为从我的角度看,这语言对我来说还真是有点丑,预计用起来会比较的不爽,而这种不爽并不是因为我对统计学知识的缺乏导致的(也许统计学研究人员未必能体会到,也许会坚持认为那还是因为我对统计学知识的不了解导致的,对此我也不想过多地争论,因为我也确实是缺乏此类知识)。

关于计算机领域和统计学领域之间仍然存在鸿沟的另一个印证是,在我们这一个领域里面,对统计学的认知是极端匮乏。我估计博客园的博主中至少50%以上不熟悉回归分析(甚至可能都没听说过),75%的博主可能不知道偏最小二乘法,这都包括我在内。我相信我的估计已经是相当相当的保守了,同时我也相信,这里的博主和统计学中使用R语言的大部分人比起来,在计算机语言、软件工程等方面都要强得多。理由前面提到过了,通过互联网搜索就可以发现,讨论R语言本质的人相对是比较少的,讨论R语言的软件工程方面问题的也是比较少。

对此,我有一个有趣的想法,即F#能否承担类似的工作。

关于好的方面,首先是F#在语言级别上会显得更先进一些,也许有可能会更快一些。这方面我就不多举例了,至少面向对象的概念更完整和严谨一些,底层核心也应该是更先进一些才对。

在F#上面做统计学框架, 还有一个很大的好处,就是由一些统计学无关或者关系较小的内容,可以很容易的由专业Coding的人或者公司来完成。比如说,数据库访问、页面展示、并行运算、负载均衡等。

不好的地方有,现在F#上面估计没有多少可以供使用的统计学函数库,而且R上面已经有不少现成的代码在被世界各地的学者所使用。这种积累性的问题,不是一天两天就能抹平的,就如java和.net之间的差距,至今仍然没有被抹平。(我在想,F#至少已经出现了,也具备一定的挑战能力了,java阵营呢?)

另外一个痛处在于M$的$上面。IDE要钱,Windows要钱等等,之前看了一个PHP的问题,我都不想说什么了。说实话还真不是要不要钱的问题,这个世界上很多问题都是源自于“恐惧”。有多少人会真正的仔细想想所有的成本,多数都只是对某种比较让人敏感的数据产生化学反应。这个问题就不多讲了,随便举一个SRSS好了,据说是按年租用,费用多是几十K美刀计的,这个成本呢?可能和Linux上面跑R比起来是要买一个Windows的License,不过这似乎也不是一般学者所负担不起的。如果把IDE的好处抹掉,光用免费的.NET Framework和Notepad,估计$的差距应该不会太大。(我确实承认,在大数量级系统上,Windows上的免费资源,甚至是收费资源都比Linux上少、差,但至少个人使用应该不是太大问题。)

 

P.S.:

已经有人用F#搞统计方向的研究了(http://cs.hubfs.net/forums/permalink/326/335/ShowThread.aspx),似乎评价不差 。

此外在F#使用R也已经有方案了(http://cs.hubfs.net/blogs/thepopeofthehub/archive/2007/11/06/FSharpWithR.aspx),似乎问题不是太大。

搜索有关R的东西实在太难了,因为R这个字母实在是太常见了。

posted @ 2009-05-25 12:25 Sumtec 阅读(104) | 评论 (0)编辑

2009年3月11日 #

Hi all! I'm Frank. I would like to begin a series of short articles about code designs in English. It is because I found that we have nearly no chance to use English, especially in writing. I can't guarantee that there is not any types of mistakes, including gramma, spelling and knowledge ones. I do hope that there will be some comments so that I won't feel alone.

Yesterday, a strange story came up in my mind suddenly: What will happen if a person get a task about buying a train ticket to Brisbane from his boss?

As all we know, Brisbane is in Australia. And a train can never running over the sea. Probably, you will refuse to complete the task if you are not crazy. In an alternative way, you might suggest you boss not to go there by train, but by airplane. The reason for which you will persuade your boss to change the travelling way is that you speculate the main object is not to travel by train, but to arrive at Brisbane.

It is a common sense. However, when you're in a designing team of a software project, you might not notice that. Sometimes, you customers will order you to design a function or a page, which is not so suitable in the information world. When the old-fashioned guys are asking you to do so, they are neither right nor wrong. In the real world, human can not process a business in a perfect way as computers do. For example, they can not remember every thing, create relative links to every thing which ought to be, or querying information in flexible ways.

Let's take a close look at this real case:

One day, my boss asked me to do a business support system. In this system, he specified some detailed functions. One of which is a page in which it could show up a report ordered by month and should have some specified columns. At the beginning, the system was designed as what he expected. However, he found some more new demands, which meant you should provide some more pages with different ways of ordering, and with different kinds of data under each columns. That became a totally mess since the system is not designed to be like that. It was hard designed. Any new requirements would need a completely new set of codes behind a completely new page though we have a business layer and a data adapter layer.

Finally, we found that it was a task to buy a ticket to Brisbane: The boss actually need a support system which can report any sets of information in any ordering and grouping ways. So the system should not be designed to make a page for each specific request, but be designed to gather any information in any proceeding way as ones wishes. How would this happen?

In fact, the boss didn't realize all the requirements at the beginning. What came up in his mind is the most urgent stuff to be resolved, for example, a monthly report about revenue in sales pipeline. As soon as this was done, he would think about something more as the system brought him so many conviniences. So, the first requirement he discribed to you would sound like to buy a train ticket to Brisbane. Although he didn't mean it.

After we realized that, we designed a module to render a reporting page by explaining an xml configuration file. Thanks to this module, we can produce many pages to satisfy abundant of demands without coding any more. What we have to do is just providing different xml files. And next, we also designed a module with which you can pick up the fields you want to show up in a report and select a way of statistic. That module will generate the xml configuration files for you. In another words, I bought an air ticket for him.

In this case, I learned that it is very important to dig into the requirements before you start designing. Knowing the requirements provided by customers is not enough. Some times they just don't know what would be the best solution for them.

Alright, what if you did buy a train ticket to Brisbane? Guess what might happen if you still can't feel the coming terrible situation? I will try to tell a different story in the next essay.

posted @ 2009-03-11 01:38 Sumtec 阅读(929) | 评论 (9)编辑

2008年11月23日 #

前言

今天看了两篇讲协变/反变的文章,写得很好也很有意思。不过我猜应该有不少人可能还是很难理解这个新概念——每一次推出新的概念的时候,都会或多或少造成我们的困惑:这是个什么东西?为什么要出这么复杂的东西?我们什么时候应该用这种东西,什么时候不该用?

有这样的困惑没关系,我想绝大多数人都经历过这个过程。我在这里呢,也说说从我的角度是如何看这个新鲜事物的,也许对理解这个东西有帮助。不过先声明一下,我没有装过,更没有用过.NET 4.0,因此我写的内容基本是自己推导出来的,如果有什么不正确的地方,也希望大家能够指出。

先给出刚才提到的两篇文章,因为也许有人是通过搜索引擎过来的:

http://www.cnblogs.com/Hush/archive/2008/11/22/1339140.html

http://www.cnblogs.com/Ninputer/archive/2008/11/22/generic_covariant.html

其中第一篇文章的内容相对简单一点,也好理解一点,后者更加理论化一些。
本来呢,我看完Ninputer的文章产生了两个想法:
1、好!
2、有点太理论化了,恐怕难以理解。
基于第二点想法,我就产生了要从更容易理解的角度去描述这个问题的想法,结果一刷屏幕,已经出来了第二篇了——有人捷足先登了。这让我郁闷了一下会儿,不过后来还是发现了一些有趣的事情大家都没有提到,于是又重燃了我码一堆文字的热情。

 


什么是协变和反变?

其实前面的文章里面已经有很清晰和正规的定义,我这里不打算再写得更详细了。相反,我想把问题简化,因此我会给出一个较简单但不太准确的说法:

interface IFoo<in TIn, out TOut> // TIn 就是反变,TOut就是协变
{
    TOut Output();
    
void Intput(TIn value);
}

 

这个定义估计足够简单明了了,那么他们是干什么用的呢?

提示:理解协变和反变,需要从泛型之间的类型转换入手,而不要把注意力定格在泛型中某个函数的类型参数T上面。比如:IEnumerable<object> objs = new List<string>();

 

 

为什么要有协变和反变?

这个问题嘛,跟继承和派生的概念是有一定关联的。比方说:

对派生和继承了解的就别看了,浪费时间!

这个和协变好像还有点远,哦,对,还跟泛型有关系:我们在泛类型上是否也可以像刚才那样使用呢?我们看一个例子:

IList<string> source = new List<string>;
IList
<object> target = source;  // 可以这么干吗?

我们先撇开“能不能”不说,至少我们是很期望能够这么干的,比如说:

public void RemoveNull(IList<object> objList)
{
  
// 把中间员素值为null的元素删掉
}

IList
<string> stringList = GetItFromSomewhere();
RemoveNull(stringList); 
// 嗯,看着很诱人的样子!
// 如果这样做是被允许的话,那么我们就不用再写一个针对
// IList<string>版本的RemoveNull函数了

那到底能不能呢?这个问题很有趣,在Ninputer的文章里面提到了另外一个类似的例子:

如果两个类型T和U之间存在一种安全的隐式转换,那么对应的数组类型T[]和U[]之间是否也存在这种转换呢?
……
举个例子,就是String类型继承自Object类型,所以任何String的引用都可以安全地转换为Object引用。我们发现String[]数组类型的引用也继承了这种转换能力,它可以转换成Object[]数组类型的引用,…… 

我这里只是节选了其中一部分,是因为有一部分的描述是不准确的。为什么说是不准确的呢?我们来看这么一段例子:

string[] source = { "A""B""C" };
object[] target = source; // 编译会出错吗?不会!
target[1= 1// 能运行通过吗?不能!

由于编译是可以通过的,所以上面我节选的那一段话是正确的。但由于实际上运行是不通过的,原因也很显而易见。

关于Ninputer的原话,以及不那么显而易见的“显而易见”的解释可以看这里

 

刚才的object数组的例子,能够给我们带来很多的思考:

一、为什么数组就可以编译通过,那么泛型呢?

泛型和数组的对比

泛型的类型转换是不能编译通过的!可为什么不行呢?其实前面数组的那个例子已经给出了答案:运行的时候如果我们试图对某个元素做赋值操作,是有可能出现运行时错误的。实际上数组本身也没有解决这个问题,只是忽略了这个问题。忽略这个问题的原因也很简单,比如说我们看看string.Format(string format, params object[] objs)这个函数,如果不忽略又怎么提供这种方法呢?可以说数组允许这种情况的转换,其实是一种不得不作出的妥协,而并不是真正的协变(按照泛型的协变/反变规则,其实是不允许这么做的)。


二、如果我们想要编译及运行通过,应该怎么去做?

前面曾经举了一个例子,说明我们是那么期望这种泛型之间的转换,协变和反变就是为了解决这一问题的。让我们回顾最开始的那个例子:

interface IFoo<in TIn, out TOut> // TIn 就是反变,TOut就是协变
{
    TOut Output();
    
void Intput(TIn value);
}

我们考虑有如下的代码:

Code

通过这段代码,应该能理解,如果我们需要在泛型之间能够达成安全的隐式类型转换,是会有一定的前提条件限制的。在应用这些限制之前,泛型之间的隐式转换是不可能的事情,即使类型参数T之间是有继承关系的。而协变/反变就是为了完成泛型间类型转换而提供的,用于明确限制转换方向、给编译器验证条件的语法工具。

 

什么时候使用协变/反变?

我的经验是,先看看框架里面是怎么用的,用多了之后再总结,别轻易在自己设计的泛型中使用。原因很简单:刚学会新特性的时候,很容易把它当作金锤子四处滥用,最后可能反而会增加了整个程序的复杂度。 

 

后记

大家考虑一下,前面举的例子IList<T>能通过协变/反变来达到目的吗?答案在Ninputer的文章中。

posted @ 2008-11-23 14:33 Sumtec 阅读(1860) | 评论 (16)编辑

2008年11月22日 #

注:文中提到的案例不是真是实施,只是为了便于描述虚构的;文中提到的公司也非真实发生事件,也只是为了便于描述和理解而使用,并无任何占取利益的意图,请勿对号入座。

通常当我们说要开发一个项目的时候,作为程序设计人员,比较容易想到的地方是,我要有一个比较好的框架,好的代码质量。这是从维护的角度讲的。而稍为正式一点的公司,可能会有一个UE设计部门,专门负责用户体验方面的职责。这是从客户使用的角度讲的。相对来说,这方面的工作已经是比较容易遭受忽略的部分了——试问一下,你所在的企业是否有专人专门负责这一职责?据我的了解,很多公司在这方面是重视程度不足的。当然了,很多公司会有人去做这样的工作,但不一定是专职人员,可能是管产品策划的产品经理,也可能是技术负责人。不过怎么讲,如果说我们需要做这部分工作,大部人人还是较容易得到理解的,毕竟产品好卖与否,市场占有率多大,附加值有多高,跟着客户的感觉是有很大的关联的。

还有一些工作,则非常容易被忽视:部署和维护。


一说到部署和维护,感觉好像就是开发完之后,与程序设计人员无关的一些工作了。比如说部署,那就是找个什么人,往服务器里面一装就好了。再比如说维护,可能就是找个人当客服,把用户的问题收集收集,能解答的解答之,不能解答的找技术人员处理之。看起来似乎真的很简单的事情,其实这里面学问还不少。如果系统在设计的阶段不考虑这部分的内容,那么总有一天就会对你造成很大的压力。这类问题比程序架构问题的潜伏周期更长,暴露出来后,其直观严重性较小。这让我想起来一个典故:“君有疾在腠理,不治将恐深。” 桓侯又不应的原因是因为看起来没什么大问题,如果说哪个手指头动不了了,又或者肚子痛得无法吃饭了,恐怕不会不应的。这些问题的也有点类似,只是更为隐蔽——再怎么积累,看起来也死不了人。因此,我们需要再系统设计的阶段,至少在重构的阶段,就要考虑到这些问题。我要和大家交流的,是原则层次的部分,不涉及到编码,甚至可能不会谈到具体的设计。这些原则都比较简单,应该是比较好应用的。


今天,我只说部署。部署一个相对较大的系统,其实不是一件很简单的工作。先说第一个部署问题:配置文件。

比如说,你会有一堆的配置文件需要配置,会有一堆的周边应用或者服务要随之部署。对于配置文件,恐怕已开始大家都是随便找个地方一搁就好,比如放在APP_DATA目录下,甚至是直接就在web.config里面添加<add key="xxx" value="zzz"/>。这种做法一开始确实觉得很顺手,可是时间一长,你会发现这些配置内容越来越多。多不是问题,问题是他们是有区别的。之所以有配置文件,是因为如果能够通过配置而改变和扩展系统的功能,将会变得很方便。可是这些“改变和扩展”有的是发生在时间轴上,例如随着时间推移发现用户需求改变了。而还有的呢,是发生在空间轴上的,例如部署在不同的机器上需要有不同的配置,比如本地调试的时候可能希望把IP限制全部放开,而真正运营的服务器不能这么干。如果你没有考虑到这一点,很可能会把这些东西都放在一块,最严重的莫过于所有配置都在web.config里面。

“有问题吗?配置文件都是要修改的啊!”没错,甚至一些超大系统的部署工作实际上需要另一个程序去扶助之才能完成。可是如果你的系统没到那么大的程度时,花费人力去做这么一个部署工具实在是不值得。因为这个工具在每一次新版本升级的时候,都需要重新开发测试。对于一些在线运营的系统,很多时候甚至就是小修小补。比如说博客园这样的系统,你总不能说整天“安装”整个新版本吧?这时候部署工具恐怕无能为力,除非你又弄一个“升级/补丁部署工具”来。

“反正这也就是一次性的工作,有那么重要吗?大不了稍微花点时间去弄一下就好了。”也没错,修改一下也不花多少时间——相对开发整个系统来说。可是那也是时间啊!对于一个正在运行的系统,修改配置的速度越快越好,因为它影响你系统的上线速度。而更重要的是,人很容易就会犯错,如果配置方面的设计有问题,就会增加出错的机率。

“容易出错?不会吧?”确实很容易,这个可能需要举一个很具体的例子:

相信不少同学的开发过程是有源代码工具做管理的,那么我们也会发现,这些配置文件通常也受源代码管理工具管理的。这很正常也很有必要,配置文件如何配置,以及其变化,如果丢失了,则很有可能需要花很多时间才能搞清楚如何部署这个系统。比如说这个工具就是TFS,开发的工具是VS。好了,为了便于开发,我们通常也会在开发人员所在的机器中部署一个完整系统,或者子系统、微系统。为了简便,我称为local系统。

“没有!”不会吧?你们的系统大到了这种程度?或者是因为安全方面的原因?好吧,那就没有吧。但是,总会有一个安装在内网的,类似alpha版本的这么一个系统吧?那么,无论是前面说到的local系统,还是这个alpha系统的配置很可能和真实系统之间还是有差别的。比如说,我们的系统可能需要和第三方的某个系统做联动,开发的时候调用的应该是对方提供的一个测试接口——人家肯定不会让你直接一上来就用正式运营的接口的,除非他疯了。相应的,正式版肯定是要调用人家正式的接口。容易想到,这个差异肯定是在配置文件当中的。不容易想到的是,签入到源代码管理工具中的配置,很可能是local或者alpha的配置。那么,当我们部署完正式版——我称之为release版, 我们肯定得要修改这个配置。

到这里,问题还没出现。假设,某天我们发现系统中有一个较大的Bug需要修改,然后呢,需要增加或者修改十几项无论部署在那一台机器都需要的配置。改之,签入。嗯,接下来该打补丁了。我们对比history,发现wwwroot中改了几个aspx/cs文件,有一个dll项目中的cs改了(也就是说这个dll也要重新编译),还有某一个配置文件改了。于是,我们编译好那个dll,连同其他aspx/cs和配置文件一打包,上传到服务器覆盖对应的旧文件,然后重启一下IIS的AppPool(或者保存一下根下面的web.config),好了!真的好了吗?打开IE访问之,真的好了,原来的那几个Bug不见了,新的功能也有了!

过了几天,你可能会惊讶的发现,这几天用户的在线付费都通过测试接口“付钱了”,你也给用户“发货了”。用户付给你的是“测试币”,可你发的可是真货啊!检查后发现,原来上次覆盖的那个配置文件的问题——虽然大部分配置在测试环境和真实环境中没有区别,可是那个接口……

“这个根本就是机制的问题,应该有其他的机制保证!”太对了,不过我是为了便于描述,才省略了中间很多步骤和机制。比如说,你应该有beta/rc等中间过渡测试版本,再比如应该有完整的测试案例,至少是关键测试案例,最后应该有专人检查。但是,没有任何一种机制能够百分之百的打包票的,因此我们通常会设置多个机制来提高可靠性。每增加一个机制,自然就会增加一份成本。而且,如果你打算最后还有人能够检查的话,更是需要这个检查过程能够简单清晰。

“我们这种升级,都不会复制配置文件的!”哎呀,你这么说,我感到太高兴了,因为我也是这么认为的。不过,如果配置文件有修改,是不是变成需要手工干预了?这个过程可能会比较惨痛,而且,通常只有部署的同学才会感同身受,别人通常会站着说话不腰疼——觉得没什么大不了的。

“我们不会都不复制,我们把那些有差别的文件都剔除了。”嘿嘿,这已经比较接近我想要说的方案了。不过还有一个问题:哪些文件是要剔除的?看花眼了吧?

说了半天,也该说出我自认为成功的实践原则了:

1、配置文件的位置要相对集中在一个地方,比如说~/App_Data。与之相反的是到处都有,比如每个目录里面的web.config或者App_Data里面都有点配置,除非真的有必要(通常都是没有必要的);

2、配置文件要按照部署差异归类,比如说~/App_Data/MachineDependent是机器相关的,~/App_Data/MachineIndependent则存放每一台机器都应该相同的配置;

3、暂时没有第三了。

这个很简单的原则,可以让你的部署过程变得更为简单,比如说,部署的时候,只要记得把MachineDependent目录咔嚓掉,通常就不会出什么大乱子了。当然了,这个原则不是银弹,不解决所有的问题,该有rc版还得有,该做检查还得检查,甚至需要手动修改的地方还得手动修改。但是其它因素完全相同的情况下,确实大大简化了一些工作:

1、该复制什么不该复制什么只有一条规则,不容易搞错;

2、不是所有配置都需要手动修改了,有一部分只要复制就好了;

3、即使是要修改的,你也知道在哪里找到他们,而且由于不需要修改的部分已经摘出来了,配置内容肯定相对少了不少,因此看花眼的可能性降低了不少。

即使部署工作全程自动化,哪怕是补丁部署也是自动化的,应用这个原则也会使得开发部署工具会变得更简单清晰一些,最后人工检查也更轻松一点。当然了,这里说的只是原则,实际上要应用这个原则,简单点可以“告知”开发人员即可,复杂点的,我建议把配置相关的东西封装到底层,不允许开发人员直接接触配置文件,这样会更好一些。


还有一种部署问题,是周边的小服务、小应用。请注意,我要说的不是如何部署周边服务,而是说,如何设计才能减少因为部署周边小服务小应用而产生的问题。

不可避免的,当系统增长到一定程度的时候,会发现这个系统太庞大了,改减减肥了。比如说,我们会考虑类似“微内核”的思路,把周边的一些东西尽可能剔除出去。这样做有几个巨大的好处:第一,系统复杂度随着解耦而降低;第二,能够更容易分解开发组,降低管理的难度;第三,部署也会解耦而相应的简化。关于第三点,我稍微多说一点点:以前某个功能的升级可能要整个系统测一遍才能上线,甚至可能这个功能本身测过已经没有问题的,但是系统中的其他部分还有Bug,导致用户迫切需要的这个功能迟迟无法上线。如果我们把他们拆出来,这个问题就会得到巨大的简化。

那么,当我们拆出来很多小服务之后,就涉及到这些小服务和核心的连接,通常还是离不开配置。除了配置本身,还有另外一个细节需要考虑到,而这个通常是我们比较容易忽略的部分——版本。我这里所说到的版本,可以是指前面说到的alpha/beta/rc/release等版本,还可以是指面向不同客户的的版本。后者可能需要给一个具体的例子,大家才好理解:

比如说,我是一个Blog引擎服务提供商,通过定制就可以提供Blog的Hosting服务。比如说,新浪说要这样这样的样式和功能,我这边一配置就出来了;猫扑说要那样那样的风格和服务,我一配置也出来了。假设这个Blog引擎可能是跑在我的服务器上,而不是安装在新浪或者猫扑的服务器上,也可能安装在对方机器上,这个假设很重要,这么做的理由可能是:可以控制我的无形资产;或者是节约对方的成本;或者是部署方便,等等。然后呢,也为了提供“快照”功能,我们需要些一个小服务,这个小服务会定时的直接抓取系统中的数据,然后以文件或者数据库的形式缓存下来。很显然,新浪和猫扑不太可能用同一个数据库来存放Blog数据,因此这个小服务抓取出来的内容可能key值相同,但数据不一样,因此至少这些缓存信息也应该独立存放。通常,我们的设计都是只有一个数据库连接配置——简单啊,不容易出错;要访问不同的数据库通常也是互相独立的,因此分别部署就好了,那么快照服务很可能是分别部署的。好了,考虑后来又有“慢照”、“连续照”、“不照”、“什么照”等一系列周边服务,这些服务也要独立部署,那么问题就来了:

你的部署过程将会使一个n*m的关系,n个小服务对应m个内核。这是十分痛苦的,只要有一个地方配置错了,很可能就会出现安全泄露,或者数据互相串扰等严重的问题。 如果我们稍微考虑一下,通常这些小服务除了版本差异的地方之外,其它的差异都会比较小,比如对于同一个服务来说,程序代码通常只要有一套就可以了。因此,我们应用以下原则可以减少部署的困难:

提供一个底层的框架,能够识别不同的(内核)版本,根据不同的版本能够读取不同的配置;

如果能够把这个过程变成对服务本身是透明的,则更为理想——这意味着你不需要给开发服务的人员讲解过多的细节,以及便于把旧的代码迁移过来。

除此之外,我们还会发现一个问题,就是随着服务的增多,部署仍然是一个困难的事情,尤其是涉及的迁移的时候。比如说,我们发现猫扑访问量很大,需要把周边服务迁移到一个独立的机器去运行。于是乎我们要找到每一个服务所在的目录,复制到新的服务器上,同时分别修改这些服务的配置,甚至是文件系统的权限等。此外核心的配置可能也发生了变化——需要修改有关服务所在位置的配置信息。考虑到这个问题,我们还可以应用以下原则来减少这部分的困难:

尽量将周边的一些小服务集中起来,同时提供一个底层框架,能够根据正在使用的服务读取不同的配置;

如果这个过程是透明的则更理想——理由同上。


当我们应用了这两个原则之后,我们就可以把周边服务的部署过程,从n*m转变为n,甚至是1的程度。当然,开发不会因此简化,甚至可能会变得复杂一些——要额外开发一个底层框架出来。不过我想先这个额外的开发,其复杂度还是相对较低的,带来的好处确不少。


不知道我的这些想法,大家是否能够理解和认同?

 

posted @ 2008-11-22 09:47 Sumtec 阅读(1611) | 评论 (5)编辑