|
|
2010年03月10日
2009年04月19日
最近,由《编程之美-微软技术面试心得》一书稿酬所捐建的第一个机房在福建省漳平一中正式投入使用了!
一个月前,《编程之美》编写小组向漳平一中捐赠了第一笔稿酬,共计16000元整。随后我们又向湖北省五峰县一中捐赠了一笔同样数额的稿酬。一个月来,漳平一中经过公开招标,用这笔钱购买了第一批5台计算机,并将发票寄给了我们。然后又开辟了一个房间安装这些计算机,做为编程兴趣小组的专用机房,并于近日正式投入使用了。从此,编程兴趣小组的同学们就有了专用机房,可以专心地练习编程了。
我们每个人都很平凡,也许一辈子都做不出什么惊天地泣鬼神的大事来,但是,我们依然可以通过努力,踏踏实实地做一些事情,来改变这个世界一点点…漳平一中编程兴趣小组的指导教师李超老师,他之前摔伤了腿行动不方便,为了布置好这个机房还不辞辛劳地奔忙。不光是他,还有博文视点的杨绣国编辑和周筠老师,以及漳平一中多位为促成此事而辛勤工作的老师们,没有他们的无私付出,我们这份微不足道的稿酬也就无法顺利地实现它应有的价值:在鼓励经济欠发达地区计算机教育方面发挥它最大的作用。因此,当我们在为同学们用上新电脑学习编程而由衷地感到高兴的同时,也要对这些为促成此善举而默默付出的人们表达诚挚的感谢。我们并非无所不能,但正所谓“勿以善小而不为”,只要我们每个人都付出一点点,就能改变世界一点点。
一周前,我正式加入了浏览器制造商Opera公司,这是我的第一份工作,我也希望自己能通过辛勤工作,为产品发布贡献力量,藉此改变浏览器之战的历史一点点…
2009年03月16日
最近,福建省漳平一中收到了由《编程之美-微软技术面试心得》编写小组捐赠的第一笔稿酬,共计16000元,这笔钱将用于购买计算机,供编程兴趣小组的同学们作为信息技术竞赛培训之用。这也是从《编程之美》稿酬中捐出的第一笔善款,今后我们还将根据此次捐赠的反馈效果,制定进一步的捐赠计划。
《编程之美》一书自去年3月出版以来销量就一直不错,在博文视点公司的大力推广以及广大热心读者的支持下,获得了:
等种种殊荣。我们几位编者看到自己的劳动成果能被大家所接受,都由衷地感到高兴。然而,随之而来的问题是,我们该如何处理这笔稿酬呢?这时,邹欣老师提议把稿酬都捐赠出去,用于鼓励和支持中学生学习计算机编程知识,这一提议立刻得到了所有编者的一致认同。
作为一个从不发达的山区小县城走出来的编程爱好者,我更是高举双手支持。因为我还记得在高一前的那个暑假初次接触计算机编程时,学校里那个要脱鞋才能进的机房,那些破旧的无盘486工作站,机箱上还有个Turbo按钮,按下去之后,似乎Turbo Pascal的编译速度都会变快一些...更让我记忆犹新的是,那时自己对上机、对敲击键盘和调试程序的渴望,有限的上机机会显得是那么弥足珍贵...从自身的经历出发,我们相信直到今天,在一些经济欠发达地区仍然有许多对计算机技术抱有无限热情和兴趣的学生,因为缺乏上机条件而苦恼。也许,我们可以做些事情来改变这种状况一点点...
经过几次邮件讨论,我们达成了如下捐赠宗旨:我们捐赠的目的是让这份微不足道的稿酬能在鼓励经济欠发达地区计算机教育方面发挥它最大的作用。 基于这个宗旨,我们将从以下几个方面来寻找捐赠对象:
- 经济欠发达地区和缺乏计算机教学资源的学校是前提之一。
- 我们会考虑这些计算机是否能在一段时间内发挥它最大的作用,把这些计算机送到最迫切需要它们的人手里才能体现出最大的价值。
- 由于我们只是捐赠计算机,学校必须有能力自己组织师资力量来维护硬件、教授计算机使用和编程知识。我们坚决反对将捐赠的计算机当成摆设品和宣传的噱头。
不久,在我和博文视点编辑的牵线搭桥下,福建省漳平一中和湖北省五峰县一中最早与我们取得了联系。大家在对学校情况深入了解之后一致决定,将这两所中学选定为第一批捐赠对象。其中,漳平一中的老师过去几年里在缺乏足够的教学资源,尤其缺少专用的计算机供编程兴趣小组进行竞赛训练的情况下,仍然坚持培养学生参加信息学奥林匹克竞赛,也取得了一些不俗的成绩,我们相信这次捐赠的计算机能极大改善他们的上机条件,并让他们在今后的竞赛中取得更好的成绩。
然而,我们也都知道全国有许多更贫困而且需要帮助的学校,它们最迫切需要的也许不是计算机,而是最基本的学费、课本、文具、教师等。我们的力量其实微不足道,只能尽自己的绵薄之力帮助其中一小部分迫切需要计算机资源,同时能将这些资源发挥最大作用的学校。更多的帮助,需要全社会的共同关注,需要每一位有爱心的人伸出援手。
我们对第一批选择的这两所学校是进行分期捐赠的,期间会不断通过校方反馈的捐赠效果来及时调整我们的捐赠策略和方法,甚至决定是否中止捐赠,我们会将这些反馈通过不同渠道公布出来。同时,我们也鼓励热心读者提供一些迫切需要计算机资源的学校信息,我们希望能与校方直接联系商谈,如果情况属实,我们会在力所能及的范围内提供最大的帮助。
捐赠计算机的具体使用是学校的自由,之前提到的捐赠宗旨已经明白无误地表达了我们的价值观,只要不违反这个最基本的原则,我们不会强加任何意志给受捐赠的学校。
2008年08月18日
马上就要找工作了(不知谁会要我...),在我学生时代的最后一个暑假里,看书、做题、写code、看奥运、玩实况足球...一个都不能少。同时,作为一个好奇心旺盛的家伙,加上刚入手个4G Flash版的Zune 2,自然要拿XNA 3.0 CTP来玩玩。
闲话不表,XNA 3.0 CTP开始支持在Zune上开发游戏(可以结合免费的Visual C# 2008 Express来用),可是文档还不齐全,官方只放出了个Alien Game的sample,是一个蛮简单的射击游戏。我花了点时间把它的源码读了一遍,发现它所用到的整体架构和在PC上写游戏时用的XNA Framwork几乎如出一辙,推测是其一个子集而已(比如input不支持keyboard,也完全不支持3D加速等等),实际上,在Zune上写的游戏代码只需要修改一些设备相关的输入处理、文件读写的代码就可以直接移植到PC甚至是xbox360上,Zune和xbox360甚至还共用相同的一个GamePad类接口,只不过做了个键映射,不知道3.0正式release的时候会不会有专门对应Zune Pad的一个输入类。然后我又花了几小时在上面尝试写了个小游戏Pong。Pong是世界上最早的video game之一,但不是第一个(via)。Youtube上还可以找到最早的Atari Pong的游戏视频和广告。
在写这个小游戏时,整体感觉用XNA开发游戏的确是非常简单,程序员的主要工作是实现4个函数,Initialize()用来初始化游戏环境;LoadContent()在游戏开始前用于载入资源;UnloadContent()在游戏结束后释放资源;然后就是两个非常重要的函数Update()和Draw(),顾名思义,Update()函数根据玩家的输入更新游戏的逻辑和屏幕上要绘制对象的各种参数,然后交给Draw()函数一股脑画出来,这两个函数在游戏进行过程中循环被调用,周而复始,驱动整个游戏。
非常值得一提的是Alien Game sample中实现的一个ScreenManager机制,它把游戏中需要绘制的内容抽象成一个个GameScreen对象,每个GameScreen对象都有自己的Update()和Draw()函数,ScreenManager用一个List<GameScreen>来管理它们,最顶层的GameScreen处于List的尾部。每个时间周期,ScreenManager都会从List的尾部到头依次调用GameScreen的Update()函数,这样可以让输入处理的逻辑从位于上层的GameScreen一层层传递下来,实际上在大多数情况下,只有最上层的GameScreen需要处理输入。然后它会从List的头部到尾依次调用GameScreen的Draw()函数,从而自下而上把整个游戏界面绘制出来。
在Deploy到Zune上时,发现会拷入名为mscorlib3_5.dll和System.Xml.dll这样的文件,看来Zune上的XNA运行环境是.NET 3.5的一个子集,难道Zune的操作系统是Windows CE一族派生出来的?从运行情况上看,速度不错,还支持联机debug和设置断点,微软在这一点上一直做得很令人满意:)
美中不足的是,在调试代码时没有像Windows Mobile SDK里的模拟器可以使用的,我索性直接在一个Windows Game项目中把所有代码和逻辑都调试好后再一次性导入到Zune项目中;而且在正常退出一个游戏时,整个Zune会重启,官方上说这是by design,因为这样of course可以把所有资源都释放干净。。。毕竟是小小一个Zune而不是iPhone,勉强接受吧。。。sample中没有涉及使用Zune上的WiFi和其他设备通信的源码,假如正式版中支持使用WiFi通信的话,我想可以做更多更有趣的游戏!
下面上图:
1. 随手设计的游戏图标,板子、小球、一局9分,Pong最鲜明的3个特征:)

在Deploy了XNA之后,Zune就会出现games这个新的菜单项,进入就可以看到已经下载的游戏
 
2. 游戏主菜单,我采用Zune横放的操作方式,背景和菜单都复用了Alien Game里面的素材

3. 游戏画面,用方向键控制板子(Zune Pad太敏感了,所以我只用按键)

4. 两段实际游戏视频,因为边玩边拍的缘故,玩得都很烂。。。如果戴上耳机的话,小球的反弹和得分失分都有不同的音效,而且还可以一边玩游戏一边听歌的(很流畅),在暂停菜单中还可以更换歌曲(抄袭自Alien Game,这里还有个bug,遇上中文歌名就会crash)。在录像中我尝试用一个很老的电脑音箱把声音放出来,可惜声音还是太小了点。
http://www.youku.com/playlist_show/id_2164628.html
源码释出在:http://iamyuan.cn/downloads/zunegames.rar(大量借鉴自Alien Game sample,写得不好,见笑了,小球反弹用的是最简单的反射。。。)
现在掌机市场基本上被$ony的PSP和任天堂的NDS占领(我有个PSP 2000,可以用第三方逆向工程出来的build chain tool在上头写程序),不知道微软让XNA支持Zune是不是也想涉足掌机这个庞大的消费市场。我认为目前市场上这两个巨头的成功都建立在每个平台上都有非常好玩的独占游戏这一基础上(我就是因为怪物猎人和实况足球这两款游戏而购买了PSP),假如微软能通过一些手段激励开发者在Zune上开发出真正吸引人的大作,这个平台火起来也不是不可能的,当然作为一个游戏机,Zune在硬件上比如屏幕和控制方式也要做相应的改进才行。
从下面这张拍摄自北京奥运会的照片看,NDS还是蛮有人玩的,没准他们几个就在用wifi连马里奥赛车吧,呵呵

欢迎交流
2008年06月02日
在yishan.cc的论坛上看到有人发帖讨论[如何防止"过度设计"], 于是根据自己仅有的经验, 也来说说自己的看法.
软件工程, 唯一不变的是变化. -- p41, <移山之道>
"永远在变化"让回答"如何界定过度设计"这一问题变得非常困难, 因为在真正的需求来临前, 你无法确信这是否一定是过度的设计. 但是避免"过度设计"还是可以做到的, 根据我在"移山公司"中有限的软件开发经验, 首先, 我们在需求阶段会进行更精确客观的预估计. 在前期需求分析和设计阶段, 软件采用何种技术, 什么架构, 具有哪些feature, feature都要怎么实现, 开发schedule制订, 都必须综合考虑开发团队的真实水平, 过往的经验和教训, 项目实际需求等客观条件进行比较精确的预估计, 而不是主观地过分追求新潮技术, 以老板或客户开心为目的制订时间表, 对客户不精确的需求描述想当然地制订feature, 对每个feature事无巨细地连函数和变量名都设计好…虽然这些一开始看上去会让大家都感觉到很美好, 但是项目蜜月期一过, 这些立刻会成为大家无穷无尽的烦恼源泉. 其次, 我们必须对可能的需求变更这一风险做好准备. 不要奢望用户一开始就会把需求讲清楚, 而且你真正理解了他们的需求. 如果一开始就意识到需求变更的风险是必然存在的, 那么在设计阶段就应该做出某些应对的策略. 特别是在架构和工作流逻辑的设计时, 就应该令其能够应对某种程度的变更. 制订schedule时留好buffer, 对含混不清的需求不做想当然的设计. 甚至, 在过去项目中”过度设计”的教训, 也能够成为避免再次犯错的绝佳参考.
但是正所谓”人算不如天算”, 之前提到的两种应对”过度设计”的策略也是被动的”兵来将挡, 水来土掩”. 所以我们的领导阿超最常说的一句话是: “既然软件开发中的’变数’是永远存在的, 那么何必寄奢望于一开始就能够将所有的可能性都考虑在内呢? 还不如轻装上阵, 随机应变.”
MSF原则之(6): 保持敏捷, 预期变化. (Stay agile, expect change) -- p30, <移山之道>
不要让所谓”制订好”的开发计划, 设计文档, 技术架构等成为束缚, 而要根据不断变更的需求对其作出持续的改进. 项目管理者的职责不是说在项目前期就把一切都谋划好, 然后接下来就是持续不断地赶着开发人员按照”规定”的进度完成任务而已. 在开发过程中, 管理者要审时度势不断作出一些决策, 这些决策往往需要很痛苦地改变我们已经”制订好”的设计和进度计划(换句话说, 既然改变这么痛苦, 何必一开始就做得事无巨细呢?). 同时, 他要在”质量”和”不断变化的需求”间做出”折衷”的决定, 既要适应用户”不断变化的需求”又必须保证不能太低的”质量”. 为了保证这两点, 所谓的开发进度/实现细节也许每天都会在变, 我们常常要根据当前团队的能力和变化的需求, 合理地裁减feature, 重新安排工作项的优先级, 从而赢得更为合理的时间安排, 让团队把注意力集中在关键功能的质量上. 同时, 在对用户的变更需求说yes之前, 也要好好考虑一下这是否一定是必要的, 及时澄清双方的误解, 让每一次变更都是合理的, 避免绕了一圈回到原地, 做无用功.
对当前项目开发的源起和目的永远保持清醒的认识, 所有的变更都围绕它来做决定. 阿超就常常教导我们在做开发时不妨时常想一想: “我们究竟要做什么? 我们为什么要这么做?”. 软件开发就好比是将一车货物(features)从A点运到B点, 在途中, 我们有时会卸下一些货物, 同时换上更有价值的货物, 或者重新包装已有的货物, 从而腾出更多的空闲空间来装载更多货物. 在行进过程中, 我们会遇到不同的路况, 不同的天气, 不同的麻烦, 车子会抛锚, 轮子会爆胎, 路面会有障碍, 有时为了过一条河, 我们甚至得立刻把车改造成潜水艇或者在上面架一座桥. 当最终到达B点时, 车上的货物和出发时比起来已经大不相同了, 但是我们的目的始终只有一个, 那就是能在这一趟运输过程中, 为B点及时运去他们最需要, 而且价值尽可能高的货物. 这肯定不是一趟轻松的旅程, 在出发时, 我们无法预知即将面临的困难, 但是我们会准备两名司机轮流驾驶来防止疲劳(人力), 制订一个粗略的行程计划, 带够前往下一个补给点的水和食物(资源), 准备好备用胎和零件(风险), 盘算好一些B点当前最需要货物(其中一些货物在运到B点之前就会变得一文不值), 把货物捆得结实又容易装卸(这样的架构的确不简单), 并在上面盖好一顶遮雨棚. 然后我们就上路了…在行进过程中, 我们要根据不同的路况采用不同的驾驶策略, 根据手中的食物和水调整行程计划, 根据货物的易碎程度调整它的包装方式和行进速度. 时刻为爆胎和零件修理做好准备. 当发现前面的道路不允许当前车辆通过时, 我们要立刻卸下货物换上另一辆合适的车(工具), 或者, 为什么不抄一条边上的近路呢? 最后, 这会成为一趟长久的旅行, 也是一趟有趣的冒险之旅, 我们饱览了一路的盛景, 也经历了凶险的磨难, 当我们重新启程把货物从B点运到C点时, 我们会变得更加轻车熟路(也许吧).
2008年03月12日
[本文同时发表于微软亚洲研究院官方博客: http://msrasia.spaces.live.com/blog/cns!BB976602FC1C503F!1152.entry ]
我应该算是最早知道将要编写《编程之美-微软面试指南》这本书的少数几个人之一,那时邹欣老师正在对《移山之道》进行最后的润色,而我还在学校里上研究生课程,生平第一次接受正统的计算机专业教育。当邹老师问我要不要参与编写时,做为一名自诩的“文学青年”而不是“计算机高手”,我毫不犹豫地答应了。
我本科读的是航空学院,在大二时闲得无聊抱着玩的心态才开始真正自学编程的,然后凭着热情和兴趣就一头扎了进来。但是,我心里一直有种隐隐的痛,我可以熟练使用ASP.NET、AJAX很快地做出一个网站来,却对一些基本的数据结构、算法一知半解。唯一一次认真去读《数据结构》那本书还是保研机试前一夜临时抱佛脚,通宵看了排序、树、图之类常考的重点。虽然最后考出来成绩不错,但自己斤两多少,自己最清楚。所以实际上我对许多公司偏重算法的面试一直以来都抱有一种畏惧感和神秘感,而且非常仰慕那些受过ACM、ICPC训练过的同学,尤其是那些能很快分析出问题复杂度的人。
但是毕竟我不是科班出身,而且只在学校里面做过一些简单的网站项目,这让我在很长一段时间里都抱有一种误解,即认为工程能力和算法解题能力是不相干的两回事,佐证就在于有些人可以很轻松地解出一些算法题却无法用C#写一个真正可用的软件;而像我一样的人可以轻车熟路写出一个“看上去很美”的CMS系统,但面对一些课本上的算法题时却手足无措。而且更要命的在于,简单的网站做多了,我逐渐认为做工程不需要所谓的算法,算法好只能让人拿到更高的课程分数或是竞赛奖项,而在计算机科学这一非常讲究实践的领域中,只有良好的工程能力才有办法真正把某个项目实现。于是在很长一段时间里,我对那些能通过解出很难的算法题拿到很好offer的人都比较嗤之以鼻,并对那些公司的招聘标准感到疑惑不解――明明是我更能干活,实践经验和能力上更强,凭什么不要我而是他们呢?
我觉得我最大的幸运在于,随后的一些经历让我很快走出了这个误区。在本科的最后一个学期,我幸运地获得了一个前往微软亚洲研究院实习的机会(面试时考了我一道智力题而不是算法题J),在实习过程中,我才“真正”地做了一个软件项目,并且通过和其他实习生的交流,“耳濡目染”地看到了许多现实中的研究性软件的开发过程,这些经历带给了我许多前所未有的体验。在现实的软件开发中你会看到各种形式各异的需求,比如在一定数量的帖子中找出发帖最多的“水王”,在这之前我开发过的网站最多也不过几千条记录,所以我即使用最简单的遍历也能很快实现这一功能,但是当你面对的是十万甚至百万级别的现实数据时,问题就从最基本的“实现”变成了“更快更高效地实现”了!令我感到汗颜的是,我往往只能用效率最低的复杂度实现类似的功能,而面对如何更优雅更高效地实现它时,我常常感到力不从心。
这些经历让我逐渐意识到,我所沾沾自喜的工程实践能力实际上只是一种“实现”的能力,而在解决现实世界的实际问题时,更需要的是一种“优美的实现”,因为只有在可接受的时间或空间约束条件下的实现才是真正能解决问题的答案。而如何找到所谓的“优美的实现”,一个人算法能力在这里就起到了决定性的作用。算法实际上是对现实问题的抽象,因为现实问题是复杂的,我们可以把它抽象成模型。寻找合适的数据结构表示问题模型,并通过分析,寻找到对应的解决算法,这种抽丝剥茧的思维方式将会使得开发者事半功倍。那句著名的“软件 == 算法 + 数据结构”并非空穴来风,我也从这些经历中逐渐理解了微软等公司的招聘标准实际上没有错,因为他们需要找的是能真正通过分析解决实际问题的人。如果把工程实践能力比作一辆车的轮子,那只说明这辆车具有了移动的能力,而让这辆车能又快又稳地运行,则需要算法分析能力这台强劲的发动机驱动,这两种能力是相辅相成的。
我觉得自己更大的幸运在于,在我逐渐明白了这些道理后,参与编写了《编程之美》这本书。编书的过程也是我自己动手解里面一道道有趣题目的过程,期间我对一个个优美、巧妙的解法拍案叫绝,在遇到难题或想不通的时候,就通过与其他编者一起讨论解决,这些经历都让我不断体会到“解法之美”和“问题之美”。《编程之美》的许多题目实际上都来源于现实项目中所遇到的具体问题,它们或是实际问题的简化,或是改头换面以其他有趣的场景表示出来。但是万变不离其宗,通过把问题抽象化,并运用算法分析寻找解决方案将是解题的利器。这种思考方式也是我们希望通过本书传递给读者们的。祝大家能在阅读的过程中体会到“美”的无处不在。
2008年02月08日
前一段时间读了一本名为《Hard Drive》的书,它以纪实文体讲述了微软公司的成立和发展历史,其中包含了许多对当事人的真实采访资料,书中还对创始人Bill Gates和Paul Allen的童年经历有很生动的刻画。它涵盖了1975微软成立到1992年DOS 5.0发布期间的历史。非常客观翔实地记录了PC时代的来临,操作系统和语言战争,制表软件和文字处理软件的战争,以及微软帝国的形成。 这是一本非常引人入胜的书,在没有读过它之前,即使我在微软亚洲研究院有过不短的实习经历,对微软的公司文化也算耳濡目染,但一提起Bill Gate和Paul Allen的大名,首先想到的还是一种笼罩在巨额财富光环下遥不可及的形象。人们在谈论这个星球上最富有的人时,往往会感慨他的幸运,他的赚钱手腕,他“邪恶”的商业头脑,但是很少会去思考:“这帮家伙是怎么成功的?他们凭什么能挣那么多钱?”。
在没读过这本书之前,我也从没有考虑过这些问题,和很多年轻人一样,我不屑于微软的一些行为,这种“成见”自然而然地最终转嫁到盖子叔叔身上,毫无疑问,他就是“万恶之源”?。但是在读《Hard Drive》的过程中,我就被他们的创业经历深深吸引住了,因为从他们身上,我看到了曾经在脑海中向往过的那种充满激情和梦想的生活,所不同的是,我们的理想在不停地抱怨现实不如人意、社会不公平、环境不够好、教育制度扼杀了我们的天才和创造力中渐渐被遗忘;而他们,没有任何怨言和借口地将理想一步一步变成了现实!
其实最初我们都是一样的,年轻、精力充沛、喜欢幻想、毫无根据的自信、野心勃勃,但多年以后,我们在不断的抱怨中变得“很现实”,转而去追求各种各样眼前的利益,找一份工作、买车、买房,为年薪比别人高了两三万而沾沾自喜;而那些家伙,他们则把自己变成了这个星球上最富有的一群人。
《Hard Drive》不是国内很多企业在校园宣讲会上发放的那些自吹自擂的小册子(两位作者兼记者专门在前言中阐述了独立的写作背景),它用客观翔实的资料说明了一个事实:微软的成功并非偶然或是幸运,即使它的一些做法饱受争议,但它完完全全是靠一群非常聪明而富有激情的人脚踏实地推动而成的。
“I can do anything I put my mind to.” – Bill Gates P8
信念
记得小时候背课文,我们就经常被教育要像那些革命烈士般有坚定的信念,但是背过课文之后,我们果真理解了“信念”这两个字的含义了吗?还是说我们仅仅知道了“坚定的信念是人实现目标的精神支柱”很有道理呢?这句话是Bill Gates上Lakeside中学的时候给一位教堂牧师说过的话。那时他和一帮对计算机非常感兴趣的伙伴们整天泡在学校唯一的计算机室中摸索计算机这一新生事物,他们用的是纸带和电传打字机,通过远程连接一台DEC公司的大型机学习编程,Bill的第一个程序是Tic-Tac-Tor(井字游戏)。那时的他,就已经很认真地告诉他的好友,他会在25岁之前成为百万富翁。他说到做到,在之后的日子里,只要是他贯彻了“信念”二字的事情,的确都给了他丰厚的回报。
“We always had big dreams.” – Paul Allen P51
梦想
在Bill Gates和Paul Allen都还在中学念书的时候,计算机的使用费用非常高,个人用户必须向大型机拥有者按时间支付费用来获得远程登陆使用计算机的权利,于是他们通过给一家公司找操作系统的bug来挣得免费的上机时间。每天晚上,他们都会集合在公司的机房中,想方设法寻找系统漏洞,谈论对未来的畅想。那时Bill和Paul就都认为,计算机将越来越普及,软件的销售将成为一种新兴的产业。后来,Bill将这种想法用更形象的一句话表达出来,即那句著名的:“每个家庭的书桌上都摆放着一台计算机,上面运行着微软的软件”。我个人非常喜欢这种形式的Vision,因为比起现在一些“华丽”的口号,比如“让企业发挥它的潜力”之类的,它让目标和梦想变得富有现实感。
Gates eventually gave up any thoughts of becoming a mathematician. If he couldn’t be the best in this field, why risk failure? P64
抉择
Bill在刚上哈佛大学的时候,经历过一段时间的迷茫和彷徨,和很多聪明的学生一样,他平时不怎么上课,只在考试前猛学一通,然后照样拿A,剩下的绝大多数时间就是通宵和朋友们打扑克牌(他打完牌后常去找Steve Ballmer聊天…)。因为他很聪明,一度希望自己能在数学上有所建树,的确他也因为把一个有趣的“烙饼问题”的数学下界向前推进了一步而发表了自己的第一篇也是最后一篇论文。但是他后来发现有些同学数学上比他钻研得更深,所以他就放弃了在学术方面发展的念头,而工业界则很幸运地迎来了一位未来的重量级选手。在随后微软公司发展的过程中,对于微软究竟要做什么不做什么,因为软件产业那时还不成熟,Bill有很多可选项。但选择多了未必是好事,英国曾有个诗人说道:“我走到十字路口,于是无力地跪下”,太多的选择反而会干扰人的判断力。Bill最后坚持选择成为平台开发商,通过自己设定行业标准来占领市场的观点,让微软获得了长足的发展。做自己最擅长的事且做到最好,Bill的一次次抉择让微软在上个世纪八九十年代所向披靡。相比起来,我的前半生似乎都在不停地挥霍各种选择的机会,直到最终没得选择……
Gates simply liked pushing things to the edge. “That’s where you most often find high performance,” he said once. P127
执行
每个人都有很多梦想,但是我们的梦想往往因为缺乏执行,大多成为了闲聊时的谈资或者自欺欺人的夸夸其谈而已。Bill却不一样,他不光是要执行自己的想法,而且还要设法将执行的效率推到极致。他保持着从微软公司到机场花费时间最短的记录(也许是全西雅图的…),他总是驾驶着绿色的保时捷从一个地方飞驶到另一个地方(超速太多差点被吊销执照)。同样,对于他的下属,替他打工的经理和程序员们,他也通过持续不断的push把开发效率推到极致。正是这种持续不断的推动,让Bill或英明(比如采用鼠标和GUI界面)或愚蠢的想法(比如Microsoft BoB)一个个地得以成为现实,同时也为他挣得了巨额的财富。如果理想和现实之间存在着难以逾越的鸿沟的话,那么“执行力”就是跨越这条鸿沟的桥梁。
More than one unlucky programmer at Microsoft has received e-mail (from Gates) at 2:00 am. That began, “This is the stupidest piece of code ever written” P50
激情
“最初所拥有的只是激情和毫无根据的自信,但一切就从这里开始。”这是软库公司总裁孙正义说过的一句话。对于创业伊始的微软来说,这句话是再准确不过了。Bill是一个精力充沛的工作狂,在为MITS的Altair维护Basic编译环境时他就常常连续工作,支撑不住就睡在办公室的地毯上(曾经有一次被来MITS参观的客户看见…)。即使到后来不写code,成为管理层,他也依然恨不得每天工作24个小时,在微软的规模还不是太大的时候,Bill Gates事无巨细都会过问,无论是谈生意还是架构设计甚至代码编写,只要一发现问题,他就毫不留情地指出。这种激情,保持了微软不断向前,不断壮大的活力。而Passion这个词也成为了微软的核心公司文化之一,直到今天,还可以在最新的公司格言“Your potential, our passion”中见到踪影。反观自己,在不停地抱怨环境不如人意、命运多舛中,本该属于我们这个年龄的锐气和应有的激情被所谓的“老成”所取代,我们变得患得患失而不敢去尝试新鲜事物,对自己所从事的工作失去兴趣,也就没有了激情,生活变得索然无味,在长吁短叹中耗费了最宝贵的青春,很多机会也不知不觉从手中溜走。
But microkids expected to be challenged. And they expected to be able to challenge Gates. In fact, he wanted them to argue with him. P161
不惧挑战
Bill Gates的风格就是不断挑战别人同时也毫不畏惧别人的挑战,他挑战的对手不光有业界的竞争对手,也有替他打工的经理和程序员们。在项目开发中,他习惯于提出许多尖锐的问题,然后看程序员和经理们的反应,因为他认为不断地发问是把问题clarify的最高效方式,同时对于自己提出的观点,他也非常希望看到手下与他进行辩论,因为他认为这是找到正确解决方案的有效手段;当结果明朗后,他也毫不掩饰自己的错误,而是立刻纠正。在与业界对手的竞争中,无论对手多么强大,即使占据了垄断地位的市场份额,他也毫不畏惧,而是通过自己的执行和推动,做出可以抗衡的产品来,并从失败中不断吸取经验教训,进一步改进对策。就这样,随着历史车轮的滚滚前进,那些曾经叱吒江湖一时的Lotus 1-2-3、CP/M-80、WordStar等软件巨头都一个个轰然倒下,Bill和他的微软则笑到了最后。 回顾微软的发展历史,也是一个官司不断的历史,Bill并没有把这些官司看成是成功路上的阻碍,而是把它们当成一个个的挑战问题,然后花费心力去一件一件地解决。虽然这些官司让微软或多或少背上了许多不光彩的外衣,但它没有因此跌倒,不惧挑战的性格让微软越发壮大。
“Believe me,” he said as the interview ended. “Staring out the window and saying ‘isn’t it great,’ is not the solution to pushing things forward…you’ve got to keep driving hard.” P419
永不满足
在微软刚创立的初期,那时计算机的硬件资源非常有限,优秀的程序员们总是毫不满足地想把程序写得越小越好,而Bill Gates,据说在微软内部一直保持着写出最小体积的Basic环境loader程序的记录。 1985年,微软正式IPO,Bill Gates一跃进入全美最富有的人的行列。按理说,正处于“事业上升期”的Bill可谓是春风得意,可以享受生活了。但是他依然没有满足,在推出MS-DOS击败了CP/M-80操作系统后,他又将矛头指向了WordStar和Lotus 1-2-3,很快微软又推出了Word和Excel与之抗衡。他总是不知疲倦地寻找一个个竞争对手,无论竞争对手有多么强大,他都毫不留情地将之击败。他永不满足地扩展微软的产品线,直到它成为多个领域的翘楚,微软公司在这种永不满足的精神推动下,没有固步自封,而是不断发展壮大,直至成为这个星球上最大的软件公司。Bill那句经典的:“微软离破产永远只有18个月”可以说是鲜明地折射出了他永不满足的心态。
诚如《Hard Drive》一书想要表达的观点:Bill Gates和微软公司能获得今天这样的成功,离不开以Bill Gates为首的一群非常优秀非常聪明的创业者坚持不懈的努力推动。导致微软公司成功的因素有很多,我所总结的只是这些因素中令我感触颇深的几点。我即将结束学业开始自己的事业,这本书让我反思了自己,也燃起了对创业的激情和梦想。努力做一个有坚定信念和伟大梦想,懂得选择,充满激情地执行自己的想法,不惧挑战、不找任何借口,永不满足的人,我相信,这些观点和《Hard Drive》这本书,将会影响我很多!
PS:感兴趣的读者可以从amazon上定购到这本书:-)
http://www.amazon.com/Hard-Drive-Making-Microsoft-Empire/dp/0887306292/ref=pd_bbs_2?ie=UTF8&s=books&qid=1202553411&sr=1-2
2008年01月17日
记得上次参加博客堂年会,听着众多老大、前辈、牛人轮番上阵,侃侃而谈,我突然发现他们的讲话都有一个共同的特点:那就是首先回顾自己在软件开发领域的坎坷经历,以及经过N多或成功或不那么成功的项目经历的洗礼后,开始对一些问题的本质认识和解决方案的探索产生了深深的困惑和迷茫。于是他们昼思夜想,仿佛芸芸之中上天也被感动了,终于在某一天,他们分别茅塞顿开,恍然大悟,悟出了软件研发之“道”或是项目管理之“道”。接着各自著书立说,期望以自己的心得体会传道授业解惑,让遇到同样问题的IT人少走一些弯路。J
虽然我并不完全同意他们“顿悟”的观点,但前辈们掏心窝子跟我们分享经验,这样的诚心还是很令人感动。而且当他们谈到自己经历百思不得的苦闷后终于“顿悟”时,欣喜之情溢于言表。这让我又发现了软件开发者的一个共同点:那就是对问题本质进行偏执狂般的探索,以及最终找到解决方案的狂喜,更重要的是,我们都很享受这整个过程!
很多做软件写代码的人也许都有过类似的经历:经过冥思苦想,为一道难题设计了一个高效算法后的满足感;在经过通宵达旦的debug之后终于找到bug根源并将其fix的爽快感;改进算法让程序运行时间减少了50%,让内存占用减少了30%后的自豪感;经过三个月的开发,项目终于release to web,一周内pv就过了50000的骄傲感;check in代码后BVT测试全部通过的自信感… …我们做软件写代码,究竟是什么样的一种力量驱使我们热爱这份职业?我觉得,它应该源自探索问题的激情,不妥协不放弃不找借口的“猛男精神”,以及问题解决后那份小小“虚荣心”的满足。J
所以说,优秀的软件开发者都有一双慧眼,他们能在纷繁复杂的情况中抽丝剥茧,寻找到问题根源。优秀的软件开发者大多是完美主义者,他们觉得,问题是优美的,所以必须有一个相应的优美的解决方案才能相配。于是无论是在探索问题还是寻找解决方案的过程中,他们都会绞尽脑汁,用优雅、简洁、高效的手段代替繁琐、低效、平庸的方法,他们觉得乐在其中,他们发现:“美”,无处不在。
最近在参与编写一本名为《编程之美》的小册子的过程中,让我的的确确获得了许多乐趣和满足感。如果你象我一样,对软件行业充满热情,能在解决各种各样有趣的问题中的找到乐趣,发现“美”之所在,而且你渴望挑战自己,并希望从挑战中获得成功的快乐和满足感,不妨来试试《编程之美》里的题目。我相信,有志于成为一名优秀软件开发者的你一定会从这本书中寻找到许多共鸣!
2007年07月19日
目前市面上还没有一本系统阐述微软软件开发流程, 也就是所谓的Microsoft Solution Foundation (简称MSF)的书籍, 做为世界上最成功的软件公司之一, 它的开发流程不可谓不具有很好的借鉴和学习价值. 那么我们如何才得以一窥其全貌呢?
幸运的是, 一本软件工程书籍《移山之道-- VSTS软件开发指南》即将由博文视点出版上市. 这本书根据虚拟的"移山软件公司"成立 -> MSF和TFS培训 -> 开发技能培训 -> 项目实战开发这一时间主线, 撷取一个虚拟团队"移山群侠"由forming->storming->norming->performing各个阶段中的典型场景, 分享MSF最佳实践的经验, 摆脱刻板的说教, 让读者不光觉得MSF提倡这样做, 而且这样做真的有道理, 可以解决实际问题. 从而为我们将MSF方法论的思想融会贯通, 一一道来. 书中的场景都非常具有代表性, 可能是一次Team meeting, 一次Brain Storm, 一次开发人员间的争吵, 一次培训, 甚至是一次Team building(腐败), 通过这些典型的场景引出软件开发中的典型问题, 引起读者思考, 而后根据作者的经验介绍MSF的实践做法, 来逐一解答这些典型问题. 同时还穿插介绍了如何使用Visual Studio Team System来支持整个开发生命周期各个阶段的活动.
作者邹欣是微软公司的资深经理, 曾经参与Outlook和VSTF产品的开发管理工作, 目前是微软亚洲研究院的研发经理, 在博客堂上的昵称是"关心", 他在软件开发管理和开发技能培训方面有着极其丰富的经验, 他用充满幽默和智慧的笔调为我们奉献了这部软件领域的"移山群侠传", 告诉我们如何把理论上的正确transfer成实践上的正确, 用作者自己的话说"这是一本中国人写给中国人看的怎样在中国搞软件开发的书". 我十分有幸阅读了这本书的初稿, 通过阅读, 使我对MSF方法论有了更直观的认识, 扫掉了心中积郁的一些疑问, 相信当它出版时, 能够为读者带来不一般的阅读感受.
关于这本书的更多信息, 请访问其官方网站: 移山之道, 在上面还可以发现成书过程中的一些趣闻轶事, 还有邹欣老师最后在修改阶段细致入微地进行多次迭代, 修改书中的bug的有趣经历. 相信它们能帮助你更好地了解这本书的质量和内容. 而且, 在移山之道上注册账户之后, 还有机会访问更多有价值的文档内容.
书籍部分章节试读, 请访问: http://book.csdn.net/bookfiles/443/#c1
有趣的延伸阅读:
移山群侠传
故事的背景
<移山外传>之--(1)技术部来的新美工(根据真实故事改编)
VSTS TFS 网上资源
引子(1)
引子(2)
2007年06月02日
这两天拜读了kaneboy的大作<SharePoint Portal Server 2003深入指南>, 现学现卖, 将原来做的两个小玩意儿封装成了web part.
一个是倒计时钟, 设定一个Affair(事件)和一个Deadline(终点日期), 倒计时钟会按秒递减. 另一个是在线版扫雷游戏, 源自俺很早以前写的一个js小游戏, 曾经被我改成live gadget, 现在又改成了web part, 可以自定义雷区的行数, 列数和雷数 :-)
运行效果图:
 2 web part(点击下载)
2007年05月14日
判断网页蜘蛛最简单的一个办法就是设置一个时间段, 然后记录这个时间段内来自某个源的点击数, 再计算其点击频率, 如果点击频率很高, 则认为它是一个爬虫, 反之则是正常访问. 这种做法的缺陷在于:什么样的阈值才算是爬虫的标准呢? 10秒内点击12次, 还是5秒内点击6次? 而且, 对于那些一次性打开多个并发请求的爬虫类型来说(比如突然来个20并发请求的burst), 这个方法可以说是很有效, 但是对于那些周期性的请求爬虫来说(比如每隔1秒请求一个页面), 这种算法就完全失效了, 所以你网站上的信息还是在不知不觉中流失.
对于周期性请求的爬虫, 也有数学方法可以判断, 那就是将每次请求的间隔记录成数组X[ n ], 对这个数组求其方差, 如果方差很小, 那么就可以判断这是一个周期性请求的爬虫, 这又引出了最初的问题, 多大的方差阈值才是爬虫标准?
那么再进一步, 周期性是一种数字的定性规律, 而不是由方差可以定量衡量的. 因为爬虫访问服务器是有规律的, 即频繁且具有一定的周期性, 如果说正常的人类点击可以看成随机分布的话, 那么爬虫的访问数据模型则可以用近似均匀分布来描述. 所以我们可以对请求时间间隔数组X[ n ]求其数学期望e(其实就是均值), 构造另一个数组{Y[ i ] = sum(X[ i : n ]), (i = 0, 1, 2, 3...n)}, 即Y[ i ]为X[ 0 ]到X[ i ]的累加, 再对Y[ n ]和{Z[ i ] = e * i, (i = 0,1,2,3...n)}数组做一元线性回归分析, 对于爬虫来说, 由于X[ n ]接近均匀分布, 那么Z[ i ] = i * e将很有可能约等于Y[ i ], 也就是说Y[ n ]与Z[ n ]数组是线性相关的, 而对于人类点击来说, X[ n ]则更有可能近似于随机分布, 那么Y[ n ]与Z[ n ]则不应该具有线性相关的性质, 基于以上数学基础, 我们通过判断Y[ n ]与Z[ n ]数组是否线性相关, 就可以判断访问是否是爬虫的点击, 即如果得到的直线斜率越接近1 == tan(45'), 则说明其具有周期性规律, 反之则不然. 之所以将回归直线构造到斜率为一的附近, 是根据tan(x)函数的性质, 因为它在离靠近0'时增长缓慢, 而靠近90'时又增长过快, 都不利于性质判定.
下面是我根据上述方法对两个真实iis log记录进行分析的结果(各取300次点击记录, 单位为秒):

图一: ip为222.41.178.219的人类访问记录散点图, x轴为时间线, y轴为两次访问的timespan间隔

图二: 根据上述算法的到的散点图, x轴为Z[ n ]数组, y轴为Y[ n ]数组, 很明显, 他们不具有线性相关的关系

图三: baiduspider的爬虫访问记录散点图, x轴为时间线, y轴为两次访问的timespan间隔(貌似有点规律 :) )

图四: 根据上述算法的到的散点图, x轴为Z[ n ]数组, y轴为Y[ n ]数组, 很显然, 他们具有线性相关的关系
分析: 两组数据都为300次点击的记录, 单位为秒, 其中人类的访问具有一个很明显的特征, 就是会有许多同时的并发访问, 这是因为, 当人类的浏览器载入一个网页时, 它会同时请求这个网页上的所有图片, 脚本和多媒体, activeX插件文件等, 表现在[图一]中, 就是许多timespan都等于0. 而爬虫由于只需要爬网页内容, 所以他们并不需要访问网页上的图片, 而是遍历网页上的所有超链接来进一步爬整个网站! 从matlab画出来的图看, 我提出的这个线性回归分析算法看上去还是相当有效的说, ^_^
Crawler analysis第一阶段实验数据(实验数据, 包含两个真实的log文件, 感兴趣可以拿去玩玩!)
2007年04月22日
原文发表在yishan.cc, 欢迎大家访问!
两天前, 九条同学刚刚成为[King House Online]网站(简称KHO)技术部的实习美工, 他立刻就被分配了一项任务: 为今天晚上的电影放映活动做一个flash动画. 这个动画不需要太长, 两分钟左右, 会在电影开映前放给大家看, 主要是宣传一下"[KHO]网站是冀之南, 河阳以北最牛X的web2.0服务提供商, 诚邀各界有志青年关注加盟"之类的东东. 九条同学接到这个任务十分兴奋, 琢磨着第一次怎么也得在大伙儿面前露两手吧...于是他极其兴奋地花了一天时间浏览众多设计站点, 借鉴网上的经典作品, 构思如何做一个要让大家张大嘴巴的超炫动画.
看过业界著名的[蓝色理想]设计网站后, 他发现真正的flash高手都是不用designer, 直接裸写action script代码的, 于是他也决定用手写脚本来做这个动画. 这不, 昨天一天他都花在了怎么调试action script上, 由于没有经验, 所以磕磕绊绊, 经常调试不通过, 想着今天晚上就要7:00pm就要放映了, 于是他决定熬一个通宵来赶工! 据今天上午第一个到达网站的同学描述, 他在网站的地板上发现了一具头发凌乱的"尸体", 边上是一台进入屏保状态的笔记本, 废纸团和笔扔了一地...当他叫醒这句的"尸体"后, 九条同学兴奋地告诉他, 他已经把开头和结尾都做好了, 虽然只用了部分手写脚本, 但是他只要把昨天站长给他的那些宣传照片添加到中间再配上优美的背景音乐就可以了!
洗手的时候,日子从水盆里过去;吃饭的时候,日子从饭碗里过去;默默时,便从凝然的双眼前过去。我觉察他去的匆匆了,伸出手遮挽时,他又从遮挽着的手边过去,天黑时,我躺在床上,他便伶伶俐俐地从我身上跨过,从我脚边飞去了。-- 朱自清 <匆匆>
由于脚本还有一些错误, 于是九条同学又花了一些时间做细微的调整, 时间转眼就到了下午, 站长来视察工作了, 九条同学好不得意地把做好的"开头"和"结尾"给她show了一把, 站长看罢很茫然地说: "这么短, 做得太简单了点吧, 连音乐都没有, 昨天给你得相片也没有放进去". 九条同学有点沮丧, 又有点不服气地说: "这可全是用手写脚本做出来的, 比一般用designer做要难! 我只要加上照片的slides效果配上一首超炫音乐就ok了". 站长于是告诉他:"好吧, 你要加紧进度, 一会儿7点就要用了", 九条兄满口答应: "请领导放心! 保证完成任务!"
时间过得好快啊...转眼就五点了, 嗯, 该吃晚饭了..."九条, 一起吃晚饭吧, 好像你午饭也没吃吧...", "麦来乱, 正忙呢", "哦, byebye"...
吃完晚饭已经六点了, 九条兄觉得事情好像有点棘手了, 于是他赶忙打电话让他的铁哥们果冻帮忙处理一下照片的分辨率, 他先把slides动画效果设计好, 虽然本人生平见过很多大忙人, 但是如此忙的还是第一次见到. 只见九条同学同时操作这一台网站的工作站和他自己的笔记本电脑, 不时地掏出电话和果冻沟通, "你能不能快点"(大吼~~), "什么! 我让你处理照片, 你怎么搞成这样, 等于没搞嘛!", "那个照片要这么处理...你听着点!"(大吼!!), "哦, 站长啊, 我马上就好了! 一定赶在七点前完成"(友善真诚地~~), "真的, 只要再10分钟!"(极其诚恳地~~), "大哥, 我求你了, 能不能快点啊"(催人泪下地~~)
时间就像你暗恋的女生, 不追她, 她不会主动停下脚步来等你... -- 小飞
七点已过, 九条同学还在忙, "只剩下加背景音乐了!" 他自言自语道, "可是赶不上了." 站长催得不耐烦了, 又打了个电话说, 如果开场没法放映, 那么就等到两场电影的间隔再放映吧. 九条同学顿时又仿佛抓到了一根救命稻草, 问清楚下一场电影是八点四十放映后, 他兴奋地叫起来:"只剩下背景音乐了. 肯定来得及". 然后又对我说: "小飞, 帮我找一首好听的音乐吧", 我答道: "我正在写一个程序, 一会儿写完了给你找吧", 于是九条同学又开始忙活开了, 他觉得果冻给他处理的照片质量不好, 琢磨着时间肯定够, 于是又自己处理了一下, 调整了slides动画的几处细节.
oh, my god, 怎么就到8点了, 赶紧加音乐, oh, s**t, 怎么是铁达尼号主题曲, 太俗了, 换, 哎呀, 这个音质太差了, 哦, 不行, 这个文件格式flash不支持...折腾来折腾去, 好不容易赶在八点三十五时把音乐加好了. 测试一下吧, 呀, 怎么slides不动了, 而且忘了设置全屏效果了, 赶紧改, 九条同学不由得哭丧着脸说:"又要赶不上了...", 8点45分, bug终于fix了, 荔荔这时很好心地帮他打了个电话, 得知电影可能还会延长10分钟才结束, 于是告诉九条, 现在赶紧赶过去吧. 九条听罢两眼放光: "我还赶得上! 本来还以为从此再也没脸来[KHO]混了!", 但是这时他又觉得有几处细节调整一下比较好, 还有十分钟, 还可以改一下嘛, 大不了把源文件带过去放映厅, 那里也有笔记本可以改的...
看到这里, 我再也忍受不了了(一整天当我写程序时都有一个混蛋在身后对着手机大喊大叫...), 连拉带拽把九条赶去了放映厅...于是, 在两部电影的间隙, 观众终于看到了一个用"手写脚本"制作, 不到一分钟, "开头"是一个倒数时钟, "结尾"是一对飘来飘去的字符, 中间的slides相片速度或快或慢, 背景音乐时断时续的flash宣传动画, 用来宣传"坊间技术最牛X的网站"...
和九条走在回网站的路上, 他说: "今天太幸运了, 不过我那个动画用手写脚本的确是很有挑战性!", 我看了看夜空, 今天天气不错, 一眼就识别出中天偏北的大熊星座, 接下来, 我告诉了九条一个故事: 那是一个用了最新最炫的微软技术开发的, 虽然项目schedule延了好几次, 但是开发人员花了很多时间设计了一个号称很"robust"的架构, 写了好几百万行的代码, 留下了极其详尽而且丰富多彩的文档, 最终却是一个看上去就有不少明显bug的项目...
亲爱的读者朋友们, 你们从这个故事中明白什么了吗?
2007年04月13日
最近因为在维护一个基于CommunityServer的站点, 所以对它关注比较多一些, 前几天官方社区communityserver.org终于放出了CommunityServer2007 RC, 虽然没有源码, 还是下载下来研究了一番. 结果却在授权文件中发现CS 2007(3.0)即将对免费版本(Personal Edition)中的论坛(Forums), 博客(Blogs)和相册(Photos)限制数量, 分别是博客10个, 论坛15个, 相册10个, 当然如果你每年交99美刀给他们的话, 则可以取消数额限制.
详细请看官方授权文件: http://communityserver.org/files/folders/567672/download.aspx
真想不通, 难道开源项目到头来都要走上商业化的道路吗? 而且CS这套系统果真就那么优秀吗? 我从CS1.0beta阶段就开始读它的源码了, 一直到现在CS2.1, 虽然承认CS改进了不少, 但是一些陈年老bug还是经久不衰, 比如它对中文搜索的支持一直以来就是一个不折不扣的joke...CS2.0虽然开始提供ASP.NET2.0的版本, 但是代码中很多实现方法依然还是采用ASP.NET1.1甚至1.0的写法. 并且, CS效率不高, 一些通过拼接SQL来进行的查询造成对SQL Server负担过重的问题也是一直为人所诟病. 缓存设置也不尽合理, 如果你RP不好成为程序池启动后的第一个访问者, oh, god bless you...当然客观说来, CS系统还是瑕不掩瑜的.
总之官方论坛早就吵开了, 不过似乎还没有看到官方表示出在正式发布时作出改变的诚意. CS在国内的应用本来就主要集中在技术社区, 大家主要还是研究它的架构设计和源码, 大部分娱乐性论坛还是采用Discuz!或者dvbbs居多, 我觉得CS2007对授权策略突然作出如此的大的改动, 可能下场就是要不被破解, 要不被放弃了...
听闻宝玉正在开发一套名为Openlab的开源CMS, 而且也见识了这套系统在bbs.openlab.net.cn的试运行情况(不得不感叹, 速度真的很快), 希望这个系统能够早日发布, 让我们在后CS时代多一个选择 :)
2007年04月09日
CommunityServer的搜索功能是通过定时对cs_Post表中的新增文章进行增量分词索引(由communityserver.config的Jobs配置节中ForumIndexing, GalleryIndexing, WeblogIndexing和FilesIndexing完成), 将分词索引结果hash后记录到cs_SearchBarrel表中, 搜索时再根据cs_SearchBarrel同其他表进行关联查询来实现的. 从CS诞生至今, 它的搜索功能一直对中文支持得很不好, 究其原因, 通过查看cs_SearchBarrel表中Word字段的值就可以发现, 主要是由于它对中文分词的实现很糟造成的. 所以一种解决方案是引入一个新的效果更好的中文分词组件, 而我采用的实现方案是使用SQL Server内置的Full-text index服务.
CS中广泛采用了Provider模式来实现各种功能, 搜索模块也不例外, 我们主要关注的有两个类, 一个是SearchTerms类, 一个是继承自SearchProvider类的SearchBarrelProvider类, SQL全文检索采用的是原文, 所以实现步骤如下: 1. 首先将SearchTerms类中对搜索关键字进行hash的代码去掉, 一是在对TokenizeKeywords方法进行调用时将第二个参数赋为false, 二是修改GetAndOrKeywords方法去掉对关键字hash的代码. 2. 其次我们要修改SearchBarrelProvider中的SQL查询字符串, 用全文检索的CONTAINS/FREETEXT谓词取代对cs_SearchBarrel表的关联查询. 同时数据库中的cs_SearchBarrel_Search存储过程也需要修改以去除对cs_SearchBarrel的查询操作. 3. 最后为cs_Posts表的Body字段创建Full-text Index, 设置一个schedule每隔一段时间增量索引一次, 修改communityserver,config文件注释掉那几个CS内置的定时索引Jobs, 重新编译源码, CS就开始采用SQL内置的全文检索功能了, 从实际使用的角度看, 效果还是蛮不错的. (具体修改细节请参考文后的附上的代码下载)
Google.cn主页的搜索框在用户键入关键字时会自动出现一个相关关键字的下拉列表供用户选择, 我们采用AJAX Controls Toolkit中的AutoComplete控件也可以为CS的搜索输入框实现同样的效果. 下面是实现步骤: 1. 首先创建一个名为cs_QueryHistory表, 它具有三个字段:QueryWord(搜索词), ResultCount(搜索结果数), QueryCount(同一搜索词被采用的次数), 在每次用户进行搜索之后, 如果此次搜索词已经在cs_QueryHistory表中存在, 则更新对应的QueryCount和ResultCount, 否则插入一条新的数据. 2. 然后建立一个名为QueryAutoComplete.asmx的web service提供给AutoComplete控件, web service提供一个声明为public string[] GetCompletionList(string prefixText, int count)的web method, 被调用时会根据prefixText查询cs_QueryHistory表, 返回由prefixText作为前缀以及数量为count的string数组. 为了提高效率, 我们还可以将由a-z开头的所有关键词预先取出置入缓存中以加快响应速度.
在调试过程中还发现了两个问题, 一是CS中的输入框控件DefaultButtonTextBox在回车时会触发设置到它的button属性上的按钮的postback行为, 而在AutoComplete控件的下拉框中选取好某个备选条目时, 也是用回车键进行确认的, 这就造成了事件处理先后问题, 如果AutoComplete控件先响应了回车的keydown事件, 则一切正常. 否则, DefaultButtonTextBox先行响应了回车的keydown事件, 会使得AutoComplete控件改变搜索框中值的行为发生在postback之后. 也就意味着submit到服务器的表单中不是我们选中的条目, 而是在搜索框中未补全的关键词. 第二个问题是, 当返回的string数组不足count条目时, AutoComplete控件的下拉框中会用多条名为”null”的条目替代, 用户体验很不好. 还好AJAX Controls Toolkit是开源的, 我们下载源码修改AutoComplete控件客户端脚本中的_onKeyDown响应方法, 在用户选取条目的同时就同时更新文本框的值, 而不必用回车确认. 同时修改呈现下拉框的_update方法, 在增加新条目的循环中加一条判断语句, 一旦遇到null值或者string长度为空则break跳出. 重新编译AJAX Control Toolkit程序集并在CS项目中刷新引用. 这样就实现了关键字自动补完功能.
后记: 通过对CS搜索模块的改进, 发现里面有一些不甚必要代码, 一个简单的过程偏偏要弄得非常复杂, 一个模块的调用要经历大量的继承和多态绑定, 很多人反映CS整体效率不高也就不足为奇了. 当然ASP.NET2.0往往也就陪上成了替罪羊...我在调试过程中, 还发现, 默认的搜索模块拼接出来的查询串相当恐怖, 当搜索"过程 and 计划 or CommunityServer"时, 拼接出来的查询串居然是: SELECT DISTINCT P.PostID, P.SectionID, Weight = (B0.Weight + B1.Weight), P.PostDate FROM cs_SearchBarrel B0, cs_SearchBarrel B1, cs_Posts P, cs_Sections F WHERE (B0.WordHash = -2605057 OR B0.WordHash = -272220937) AND B1.WordHash = -405848999 AND B0.PostID = P.PostID AND B1.PostID = P.PostID AND (P.SectionID in (3)) AND F.SectionID = P.SectionID AND P.SettingsID = 1000 AND F.IsSearchable = 1 AND P.IsApproved = 1 ORDER BY Weight DESC, PostDate DESC, 我们可以看到, 有n个查询关键词, 那么cs_SearchBarrel表就要被嵌套进行自然连接n-1次, 查询复杂度会随着关键字数量增多呈指数级(X^n, n增长)增大, 当索引表在一段时间不断膨胀后, 针对相同的query, 查询的复杂度又会依据幂级数(X^n, X增长)增大!
源码下载
我是陈远(Vincent Chen), 正在上研, 对Web开发和数据挖掘技术很感兴趣, 我的邮件是NickLedson[at]gmail[dot]com, 欢迎交流:-)
|