去年在TWU的时候,我向徐昊第一次提起了“非线性历史观”。当时的话题是关于重构的:

“在重复代码出现之后就应该重构。我预见到了重复代码的出现,所以我首先就做了重构。这样一来,重复代码就不会出现了。那样的话,重构岂不是也不该出现吗?我的意识干扰了历史的进程,让因果陷入了混乱。所以合理的解释是:历史不是线性因果关系的……”

诸如此类的胡言乱语。

不过这两天看到了另一个证据。汇率代表着两国经济的对比,当一国经济向好时,该国汇价也应该会上升。所以经济向好的消息发布,应该会指引着之后汇价上升才对。问题是大家都已经知道这事了。所以在消息发布之前,汇价就已经朝着预期的方向发展。

例如周三澳联储发布6月CPI,在好的预期之下,周二澳元兑美元涨到18年新高0.8865(本文所有数据都未考证,只凭记忆);超出预期的CPI发布之后,市场却只是小小鼓一下掌,周三下午再次刷出新高0.8871;周三(北京时间)晚上发布的美国6月房屋销售数据仍然不佳,但对于这个数据的反应只是周四中午达到0.8850左右。所有消息——尽管都是利好澳元的消息——出尽之后,美元在周四晚上暴跌100点到0.8760左右,周五再次暴跌200点,目前收在0.8527左右。

消息会利好澳元。所有人都这样想。于是所有人都在消息发布之前买进澳元,于是汇价提前被抬高。连续13天上涨,指标严重超买,只等消息打开水闸。于是在利好消息真正出台之时,所有人开始获利回吐,汇价开始跳水。

小T把这个叫做“背离”。我把这个叫做“非线性因果”:众人的思想干扰了历史的进程,让因果陷入了混乱。市场和消息的背离如何进行,这是小T研究的课题;我有一个理论:由于历史本就是非线性的,你就没办法用因果逻辑来推测它。

要不然,长期资本管理基金怎么会倒下?

RubyWorks production stack is a collection of open-source software required to host a RubyOnRails application on a Linux server.

To set up a production Rails server, you point a package manager to RubyWorks package repository, run one command, and few minutes later you have a skeleton Rails application served by a cluster of Mongrel servers, load-balanced by HAProxy, monitored by monit and controlled by runit.

Version 0.0.4 is the first release candidate on the way to version 1.0. The core stack has stabilized, and changes from 0.0.3 are all peripheral:

  • Officially supported x86_64 packages on Red Hat Enterprise Linux and CentOS.
  • Pre-compiled Ruby gems added to the package repositories: rubygem-libxml-ruby, rubygem-hpricot, rubygem-ferret, rubygem-ruby-debug, rubygem-rmagick. All these packages are optional (not automatically installed with ‘rubyworks’ main package, but available from the same RPM/DEB repositories).
  • Added log rotation script /etc/cron.daily/rubyworks.logrotate.daily.
  • BUGFIX: Corrected the value of clitimeout in haproxy.conf (changed from 150 seconds to 15 seconds).
  • Added documentation for individual components in the stack.
RubyForge project page: http://rubyforge.org/projects/rubyworks
Documentation: http://rubyworks.rubyforge.org
Commercial support: http://studios.thoughtworks.com/rubyworks
Users mailing list: rubyworks-users@rubyforge.org

知易行难

July 26th, 2007

CSDN程序员更喜欢Firefox

“参与这次调查的人数截止到今天达到了1710人,其中38.62%的人使用FireFox”

对此我毫不怀疑。Firefox是比IE好得多的浏览器:符合标准,大量有用的插件,不会成为可怜的安全漏洞。但,做这个调查、发布这条消息的CSDN,对Firefox的支持却实在不怎么样。比如说吧,首页上的漂浮广告,在Firefox底下看着是一团乱。让38.62%的用户不能有效看到自己的广告,我相信这不是CSDN想要的。

所以,“知道应该做什么”还不够,还需要另外两样东西:

1、有效的交流途径。业务负责人有很多需求,如何评估这些需求的价值,如何让价值最高的需求尽快进入开发,如何验证开发产物是否符合要求,如何让开发出来的软件尽快开始创造价值。一句话,如何让价值流动起来——如果100万用户的网站首页上的广告问题要等到明年的改版才能解决,这成本着实不低。

2、有效的质量保障体系。价值能够流动起来,需要一个基本的前提条件:必须全面严格保证质量。如果开发出的软件总在返工重做,如果开发者没有信心修改bug,如果今天改好的bug明天又再次出现,网站的价值如何流动?

知易行难。有多少绝妙的商业创意因为交流不畅、质量不彰而无法达到预期效果?又有多少商业价值在这些或许不太显而易见的环节被浪费?知易行难。如何为团队注入行动力,让价值在整个企业流动,也许CSDN该开始考虑这些问题了。

其实是没有资格说这些求职之类的东西……因为我自己先天受限,其实从来没有通过“正常”的渠道找过工作。不过最近招聘的工作做了不少,简历看了不少,人面试了不少,多少也有些自己的想法。只当是野人献曝吧。

勾起动念的是JavaEye的一个讨论。特别是里面这样几句话:

“简历嘛,大家都知道,肯定是有水分的,而且人都有一种心理,明明知道这个人的简历很大的水分,还是想叫过来面试,所以,造就了现在的简历水分很多。”
“你忽略了一点,你太高估现在的简历,想想你的简历是什么样子,现在谁的简历没有一点浮夸”

起码我知道两点。第一,我自己的简历不会有任何浮夸,我只会根据不同的需要做不同的删减。第二,如果我知道一份简历有很大的水分,我绝对不会想要面试他/她,首先我花不起这个时间,更重要的是我不想和不诚实的人一起工作。

既不吹牛浮夸,又不让自己的才华在一堆——很可能充斥吹牛浮夸的——竞争简历里被埋没,可能吗?很简单:只陈述事实,不作评论。这其实是给别人提出 feedback时的原则:我说“你没有协作精神”,你说“不对,我有”,“你没有”,“我有”……这嘴仗永远打不干净;如果我说“你在结对编程的时候几 乎没和我说话,我有点跟不上你的节奏”,那么你就知道是怎么回事了。同样的,“18个月的J2EE开发经验”对于一家公司、一个职位来说可能意味着“天 啊,赶快雇他,他将是我们最好的J2EE架构师”,而对另一家公司、另一个职位来说却可能是“呃……他多少有点J2EE背景,或许能帮上忙吧”。既然如 此,在简历里写“精通J2EE”,你想表达的究竟是什么呢?不如实实在在写上“18个月J2EE开发经验”吧,你的目标雇主会给事实加上评估的。

推论一:如果筛选简历的人不是根据这些更显而易见的事实、而是根据“精通”、“熟练”之类毫无意义的自我评价来挑选简历,也许你错过这次面试机会不是坏事。也许这家公司不是一个好的目标雇主。目光放远一点,机会永远都是有的。

推论二:如果没有足够多的项目经历放在简历上,用我说的这种风格写出来的简历不会好看。而对开源项目的贡献显然地能够给这份简历加分。不过我仍然认为,软件开发者在工作中所从事的项目,对自己的reputation所起到的帮助还是不足。这是另一个话题,就不延伸了。

推论三:要自己的简历不被埋在简历堆里,最好的办法就是不要把它扔进那一堆。

关于找工作这件事情,我整个的看法一向是:找工作就像找恋人,一方面你要表现出自己好的东西来吸引对方,另一方面你要真实,不然以后相处的时光足够让你把 肠子悔青。如果对方是因为你表现出的真实自我而不喜欢你,那就看开点吧,至少胜过相处在一起之后再扯筋。简历也是一样,不用费劲心思去跟别人比拼,把自己 描述出来就够了。适合你的那个人(那个公司),也在找你呢。

这是在第二届“敏捷中国”软件技术大会听了孟岩演讲之后的感想,也是我在构思的一个讲稿。

敏捷早已不仅仅是一件软件开发的事,它是世界变平以后的必然产物。在一个平坦的、被互联网连接的、遵循同一游戏规则的世界里,说得严重一点,每个企业、每个人都面临来自全球的竞争。你要凭什么赢得这场竞争?

永远记住一个等式:profit = revenue – cost

在一个全球化竞争的市场上,价格必定是趋同的,你只能控制成本。有更低的成本,你可以用更低的价格卖出同样的产品(或服务,下同),或者用同样的价格卖出更多(或更好)的产品,从而赢得更大的市场份额;你也可以用同样的价格卖出同样的产品,从而赢得更高的margin——两者的结果都是,更好的profitability。于是问题变成了:如果没有压倒性的技术优势,靠什么降低成本?

最近我MSN的名字是“むだ!”。这就是答案。(むだ,無馱,muda,waste,浪费)

什么样的浪费?譬如说,用不上的预先准备,过高的风险规避成本,做出来却没有用的工作,不流动的价值。消除浪费,不仅仅是软件项目的事。就连工作方式,就连生活态度,也是一样。孟岩说到“Life 2.0”的时候,自嘲是在扯淡,不过我知道他不是扯淡,因为我自己的生活已经比以前敏捷了很多很多。

Chad在演讲的时候说,中国是令人激动、充满希望的地方。我相信是的,因为我今天看到了敏捷中国的曙光。

CSDN全世界软件开发者致管理者的一封公开信

“本文原作者作为一名软件开发者,感同身受着与管理者之间的矛盾和冲突,于是以书信的方式、代表全世界的软件开发者向软件管理者们发出他们的心声。”

但是,文中的观点、作出的承诺、对管理者们提出的要求,我并不完全同意。

重点在于,没有人征询过我的同意。似乎我的朋友、我的同事也没有被征询过同意。我一直以为自己是软件开发者。不过也许这是个误会,因为在我毫不知情的情况下,就有人在代表“全世界软件开发者”在发布公开信了。

所以,我非常明确并且强烈的态度是:这封公开信没有代表“全世界软件开发者”的权力,因为我——作为一个软件开发者——拒绝被它的作者代表。

或者,我要说,我不是软件开发者——如果作为软件开发者就必须被这种自以为是的人代表的话。

最近读了两本书,《赌金者》和《世界是平的》。上周和孟岩聊天的时候说了一句话:“即便美国人民不了解中国那又怎么样呢?他们还是把自己的养老金投资到中国。”

这就是功利而短视的资本。资本选择一个地方,不是因为这里支持它的主义,而是因为这里有盈利的机会、这里信息透明、这里遵守规则。真正有趣的是,人们诚实和努力不是因为他们高尚,而是他们因为喜欢吃麦当劳;资本让人们吃上麦当劳不是因为它想要改善人们的生活,而是因为它追逐高收益低风险。自私和达尔文主义,让战争消失,让麦当劳和星巴克在每个城市里出现,让我越来越不会对出远门感到恐惧。

资本没有主义。想要得到“电子族”签发的支票,就要做那些让人们感到愉快的事——那些正确的事。

敏捷也一样。任何“中国特色”都架不住同一个事实:有效控制浪费等于赚钱;赚钱等于生存——即便是靠中国特色的关系获得订单,即便在竞标过程中玩遍手段,盈利仍然等于收入减去成本。要控制浪费,就在铲煤的工人背后架起高速摄影机。这件事情,泰勒在伯利恒钢铁集团早已做过。而软件团队的敏捷,就像制造业的精益一样,无可阻挡。

Lilu:Rails Mockup驱动开发之道

“Lilu是一种允许保持Rails视图不变,使其内部无须含有ERB标签侵扰的方法(和工具)。”

教我不由得联想起前几个月听说的ActiveForm的故事。有人想什么都用Ruby(或者Yet-Another-DSL)来写,有人想HTML里面连一句Ruby scriptlet也不包括。DHH的评论更加不留情面:

“对‘无编码’模板的追求,让我想起MDA阵营对‘无编码’程序这个圣杯的找寻。这是一种海市蜃楼式的幻想,也就是和‘把玫瑰换个名字’如出一辙的演出。”

类似的玫瑰之名的演出还有对“无SQL”程序这个圣杯的找寻。就像我前面就已经说过的,既然SQL或者HTML这些语言当初被发明出来就是因为它们是更适合描述特定领域的DSL,为什么又要想办法让它们消失呢?既然scriptlet一直都工作得不错,为什么一定要让它一行都不出现呢?最纯粹的设计就是最好的设计吗?至少Tapestry——据说是Lilu的前辈——并没有证明这一点。

更何况,如果不喜欢HTML里嵌套scriptlet的话,多用点AJAX好了。

rayzer留言说:

“昨天在feisty上装rubyworks的时候,到了安装fastthread一步,会编译本地gem, 并提示mkmf模块依赖关系无法满足,需要引入ruby1.8-dev来解决。”

出现这个问题的原因是,在选择gem安装版本的时候,选中了一个错误的版本:我们提供了预编译好的二进制版本,安装这个版本是不需要有GCC和头文件的;但如果选中了没有预编译的版本,就会在安装的过程中build native extension。

而选中了错误版本的原因是,RubyGems本身没有提供非交互式的安装命令。一旦需要在多个版本中选择,就必须从命令行输入。我们以前用的简单办法是:

echo "1" | gem install fastthread -y

这样做的问题是,如果已经有gem cache(看看你有没有/usr/lib/ruby/gems/1.8/source_cache这个文件),编号1的版本很可能就不是我们提供的那个,而是RubyForge的gem repository里的某一个。于是就出现了开头提到的问题。昨天看到rayzer的留言以后,我终于下定决心把这个问题解决掉……

其实也不难。用IO.popen来开启进程,一行一行读STDOUT,看到合适的选项就往STDIN输入数字:

def install_gem(name)
  cmd = "gem install #{name} -y --no-rdoc --no-ri" 
  puts cmd
  IO.popen(cmd, "r+") do |io|
    io.each_line do |line|
      puts "[out] #{line}" 
      if(line =~ /\s(\d+).*\(i[3|4]86-linux\)/)
    puts "[selection] #{$1}" 
    io.puts $1
      end
    end<br />  end
end
install_gem "fastthread"

这个修改将在0.0.3版本中发布。

http://www.infoq.com/news/2007/06/ibminfo2
As when Oracle announced SOA 2.0 support, IBM also has a suite of products to immediately help get Web 2.0 working.

http://www-306.ibm.com/software/info/web20/
“Web 2.0 technologies at work now.”

http://www.infoworld.com/article/06/05/17/78420_HNsoa20_1.html
“Oracle sees the Java Platform, Enterprise Edition 5 (Java EE 5), SOA 2.0 and Web 2.0 coming together to produce a more productive application platform, said Thomas Kurian, Oracle senior vice president. Web 2.0 features more dynamic clients.”

http://www.jroller.com/page/cooney?entry=just_what_is_info_2
“Info 2.0 is a technology (or information fabric layer) for simplified integration of data and content via Information MASHUPs.”

看看微软在下一版的Windows Communication Foundation(WCF)中即将推出的对创建RESTful应用程序的支持。Java的官方组织也上了这条船,他们的JAX-RS也即将面世。(来自InfoQ中文站

这意味着什么?企业应用和web应用的分野在哪里?

企业级超复杂的爱好者和拥护者们要小心了,因为企业级未必非得等价于超复杂。

RubyWorks Production Stack: http://rubyworks.rubyforge.org/

RubyWorks production stack is a collection of open-source software required to host a RubyOnRails application on a Linux server. Supported Linux variants include RedHat Enterprise Linux 4 (both i386 and x64 versions), CentOS 4 (both i386 and x64 versions), Debian 4 (Etch) and Ubuntu 7 (Feisty Fawn).

RubyWorks Production Stack的特点是提供了方便的服务管理、强大的服务监控和可靠的多应用服务器负载均衡。此外,以RPM包/DEB包的形式发布,同时支持RedHat和Debian也是我们的一大优势。

deprec: http://www.deprec.org/

Deprec is a collection of automated recipes, written in Ruby, for setting up production ready Ruby on Rails servers. This includes everything from creating admin accounts and setting up your ssh keys to compiling and installing the packages required to get a Rails application running on a freshly installed Ubuntu 6.06.1 LTS server.

平心而论deprec确实做得很不错。基于Capistrano来搭建远端的部署服务器,这个想法很巧妙,也让部署环境和Capistrano的结合更紧密。主要的缺点有两个:(1)要求部署环境安装GCC(build-essential),因为所有的gem都是在本地build native extension的;(2)目前为止只支持Ubuntu。

LinRails: http://linrails.thembid.com/

While developing ThemBid.com using Symfony, our developers used XAMPP to standardize development environments and have something easy to install. When we started using Ruby on Rails, we could not find something similar for Linux so LinRails was started.

从这段简介来看,LinRails认为他们在做一个Rails的开发环境,事实上他们打包的东西也确实更像是一个开发环境。同时,LinRails也只在Ubuntu上测试过。

Rails Machine: http://www.railsmachine.com/

Rails Machine provides software, services and support for commercial Ruby on Rails application deployments. Our primary customers are professional Ruby on Rails developers that need simple and high quality solutions for deploying their applications either in a hosted environment or internal corporate environment.

我印象里Rails Machine是率先引入虚拟化技术(我喜欢这种大词)的stack:之所以叫“machine”,因为他们发布的stack整个是一个Xen虚拟机,里面装着CentOS和Rails服务器所需的一切东西。这就是它的特点(优点+缺点)所在。RailsMachine是商业软件,同时也提供hosting服务

FiveRuns RM-Install: http://www.fiveruns.com/products/rm/install

RM-Install is a free, multi-platform, full-tested and enterprise-ready Rails stack that enables you to instantly begin developing and deploying your great Rails applications without the worry of installing or maintaining the various integrated software components.

这个产品也不是开源的(尽管是免费的)。不过最困扰的还是:目前压根看不到它是什么样子。FiveRuns最吸引我的是RM-Manage产品,点一下“System Browser”那里的图片,这样奢华的服务管理界面确实值得卖一定价钱。

Engine Yard: http://www.engineyard.com/

We handle deployment and operations, so you can focus on your application and your business. Smoothly scale from 1 user to 1 million.

Engine Yard就完全是shared host了,吸引我注意到它的是一篇“Xen And The Art of Rails Deployment”的演讲稿,以及那华丽的24层架构图。也许他们是不会把自己的deployment stack卖出来的——当然更不用说开源出来了。

AWDWR II终于上市了

July 3rd, 2007

Web开发敏捷之道:应用Rails进行敏捷Web开发》(第2版),DHH和Dave Thomas等著,林芷薰译,电子工业出版社出版。

针对Rails 1.2版本的这个第二版,中文译本终于上市了,此时Rails的大版本仍然是1.2。好样的,芷薰;好样的,博文视点的出版团队。你们也很敏捷,就像Rails一样。

精益设计

July 1st, 2007

过度的预先设计是不好的,这是最近几年形成的共识。缺乏预先设计是不好的,这是长期以来被广泛认可的。

解决这个问题的思路仍然是中庸之道:一定的、适当的、不过分的预先设计是应该并且必要的。下一个问题是,怎样的预先设计是适当并且不过分的?

解决的思路是精益:核算成本和收益,消除浪费。当一个问题既可以用简单的方式实现、也可以引入一个复杂并且具有灵活性的设计时,考虑以下几个问题:

  1. 那个灵活的设计是什么?
  2. 灵活的设计所针对的新需求有多大的可能性出现?
  3. 灵活设计应对新需求带来的收益是什么?
  4. 现在实现灵活设计所需的成本是什么?
  5. 等到新需求出现时再实现灵活设计的成本是什么?

请特别注意最后两个问题。在面对一个复杂并且灵活的设计时,首先要衡量的不是实现它的收益,而是“现在实现它”与“将来实现它”之间成本的差额。不论一个灵活的设计的收益和成本如何,只要这个差额非常小——等到未来实现它也没有什么额外的困难,就应该毫不犹豫地推迟决策,等到真正需要的时候再引入灵活的设计。感谢现代化的IDEs,很多时候我们讨论的这个成本差额确实非常小,这是敏捷设计通常取简单方案的原因所在。

另一方面,如果这个成本差额相当大,就需要认真考察成本和收益,来判断是否应该预先引入灵活的设计了。这个时候往往需要更丰富的经验作为判断依据。

这是加入ThoughtWorks之后,我学到的重要一课:用敏捷的方式、精益的计算和中庸的思想,来克服自己曾经有的很多偏执。特别要感谢郭晓和Michael Robinson的言传身教。

用一个实例来说明。在JavaEye的一个讨论中,作者说:“项目的设计阶段,把数据库扔在一边……在设计的时候不再是优先设计数据库的结构。而是先用一个空壳来做代替,完成业务逻辑的设计,业务逻辑稳定下后……设计数据库,然后优化数据库”。反对的声音说:“对于一个需要长期维护、持续添加新功能的系统,没有好的数据库设计,最终这个应用只能是一团糟,直到无法维护。”

似乎两边都很有道理。因为,确实两边都很有道理。

现在来模仿郭晓经常摆的一个手势:把两手张开,两只手就代表两个极端——右手是“完全以数据库设计来驱动软件设计”,左手是“完全以面向对象设计来驱动数据库设计”。而所有实际存在的策略,通常都是在两只手——两个极端——中间的某个位置。可能以前靠右一点,对数据库的规范比较重视;现在靠左一点,对领域模型比较重视。但可取的、经济的、实用的策略,通常不会是在某个极端:需要同时考虑两个方面,才能得到最好的效果。

中庸之道常常有效的深层原因是边际效用递减律:对一个方面的东西重视到一定程度以后,再加入更多的重视,收到的边际效用递减;同样的重视度放到另一个方面上,能够收到更大的边际效用。让每一分投入收到最大的回报,尽可能地消除浪费,这是精益的追求。而技术偏执,例如“面向对象终结数据库”或者“J2EE优于.NET”(以及它们的相反版本),容易让人忽视对边际效用的衡量而造成浪费——找不到投资回报率最高的解决方案。

敏捷也是一样。敏捷所追求的不是“简单”,而是“价值最大化”——消除浪费,精益。所以,尽管存在种种的误读,对敏捷宣言的正确解读应该是:在过去的数十年里,人们已经对右边的东西(过程、工具、文档、合同、计划)投入了足够多的重视,以致于再对它们投入更多的重视所能产生的边际效用已经相当低;同时人们对左边的东西(个人、交流、可工作的软件、客户协作、响应变化)投入的重视是不足的,在这里投入精力所能产生的边际效用更高。

为了获得更高的单位成本投入产出比,中庸之道往往是必须的选择。另一方面,对杠杆两端的价值进行比较通常是毫无意义的,因为不管缺了哪一端,你能得到的都将非常之少——如果不是一无所获的话。