<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>思考讨论 - 老赵点滴 - 追求编程之美</title>
    <link>http://blog.zhaojie.me/discussion/</link>
    <description>先做人，再做技术人员，最后做程序员。打造国内最好的.NET技术博客。</description>
    <language>zh-cn</language>
    <managingEditor>jeffz@live.com (老赵)</managingEditor>
    <webMaster>jeffz@live.com (老赵)</webMaster>
    <pubDate>Wed, 30 Dec 2009 16:11:00 GMT</pubDate>
    <lastBuildDate>Wed, 30 Dec 2009 16:11:00 GMT</lastBuildDate>
    <ttl>60</ttl>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <title>IBM面试记</title>
      <link>http://blog.zhaojie.me/2011/07/ibm-interview.html</link>
      <guid>http://blog.zhaojie.me/2011/07/ibm-interview.html</guid>
      <description>&lt;p&gt;话说其实我很久没有被正经面试过了。一开始去微软实习自然经过了经典的笔试和几轮面试，然后去了朋友的创业公司并立即被激动集团收编——没有面试，接着从激动集团去合伙创业——没有面试，然后被朋友推荐去盛大创新院——面试更像是讨论及聊天。由于长久缺乏职场磨练，我虽然对自己能力有一定信心，但也怀疑自己如果通过“正经渠道”去面试的话能有多少机会成功。而这次面试IBM终于算是过足了面试瘾，记录一下。&lt;/p&gt;

&lt;p&gt;大约一两个月前，我收到一封邮件，某同学忽悠我去尝试下&lt;a href="http://blog.zhaojie.me/2011/06/two-job-descriptions.html"&gt;在IBM的.NET工作机会&lt;/a&gt;。我感觉这机会似乎还不错，也正好想考察一下自己的面试水平，于是表示说愿意尝试一下。很快收到HR的邮件，让我做一套在线的笔试题。&lt;/p&gt;

&lt;p&gt;笔试题分两部分，一部分是.NET测试，另一部分是英语测试，分别有几十道选择题。HR在电话里说，.NET测试会偏向理论一些，有些难，可以用搜索引擎找下答案。被她那么一说我也不知道该如何是好，更不知该如何准备，于是就打算死马当活马医，霸王硬上弓吧。当天晚上直接打开链接做题，做了以后才发现，所谓“偏理论”估计是HR从以往的被面试者那里得到的反馈，事实上这套题目考的其实就是我一直强调的.NET基础，例如C#语言的特性（从面向对象到LINQ里的种种），CLR的一些表现，BCL内常用类库的实现细节，还有就是代码阅读题了。总体而言其中相当部分也是我&lt;a href="http://blog.zhaojie.me/2011/03/my-interview-questions-for-dotnet-programmers.html"&gt;常用的面试题&lt;/a&gt;，自然正中下怀。&lt;/p&gt;

&lt;p&gt;.NET笔试十分顺利，但英语就麻烦许多了。要知道自从大学前两年的英语课以外，我已经好多年没有正经地学过、考过、用过英语了，什么GRE，托福，雅思，甚至六级我都没接触过。英语测试就跟传统的测试一样，例如给你一大段文字，提出一个问题，并选择一个正确答案，还有选出出现语法错误的某句话。测试的内容涉及政治、金融、文化、生活等方面，唯独没有我最熟悉的——技术领域的内容。尽管有Google和Bing翻译，但是从实际效果来看，自动翻译技术要达到“可用”还有很长的路要走。&lt;/p&gt;

&lt;p&gt;第二天一大早就我收到的结果，.NET测试96%，这意味着我的成绩在“做过这套测试”的人里面排在前5%。为此我也暗自得意了一番，因为从某同学那里了解到，在之前应聘这个职位的人里面，笔试成绩无一超过50%。此外我的英语是71%，而“及格线”似乎是30%。总体而言，我的笔试成绩应该还是比较令人满意的。于是，HR跟我预约了第二天的电话面试，由J.P.Morgan的人来面试，全程英语。&lt;/p&gt;

&lt;p&gt;于是我立马找出机器里的一堆技术视频来看，希望能让耳朵适应一下英语内容。听下来感觉倒还算不错，基本没有大大障碍。但是在第二天电话面试的实际过程中，我发现一旦隔了电话，导致背景里出现了很多噪音之后，听力立马会打一个折扣（适应以后会好一些）。面试我的人是两个老外，基本上没有口音（或者说就是美剧里常见的标准口音）。他们问了我很多东西，有部分和笔试差不多，例如最典型的：某对象分配在堆还是栈上——有趣的是，在他们的追问中，我也发现原来这个问题在流传甚广的“标准答案”以外还有一个变数，不过我略加思考应该也回答地没有问题。还有印象比较深刻的便是让我解释一下LINQ的相关内容（例如LINQ Provider的实现方式），GC的工作方式及特点，多线程开发会遇到的问题等等。就我个人感觉来说，这些问题我都应该回答地不错，用“对答如流”来形容似乎也不太过分。与其形成极端对比的是，对于WPF和WCF方面的问题，我也没有作任何“挣扎”，基本都是直接回答“不好意思，没有接触过，不太清楚”。电话面试耗时大约50分钟。&lt;/p&gt;

&lt;p&gt;比较有趣的事情是，我在简历和自我介绍里提到我平时接触过及感兴趣的技术（基本就是我博客右边写的那样），可能他们也正巧对Scala感兴趣（毕竟是要用Java的），于是就提出让我向他们解释下Scala这门语言。解释地过程没有什么值得一提的，不过我也适时地表达了我对Java一贯的厌恶态度，我的原话是：Java is a dead language, it sucks，然后就围绕Java语言展开了简单地讨论，主要还是我以前谈过的那些。例如我解释道，我很喜欢Java平台、类库、框架、运行时等等，讨厌的只是Java语言；我很了解和关注Java语言，说它dead是因为它死不肯演化或者演化地很奇怪（Java 7和8）；还有Java表达能力太差，虽然看上去简单，但是需要太多代码，写完了以后还看不懂。前段时间有人问我说去了IBM以后还会不会骂Java？我说我就是骂着Java进IBM的，所以绝对会继续骂不停口。而且我很希望到时候我在骂得时候，某些弟兄不要仅仅看到我是微软MVP的身份，也可以顺便一提IBM员工这茬。&lt;/p&gt;

&lt;p&gt;电话面试后的第三天，HR又给我来电话说通过了，说接下来便是一场“面对面”的面试，地点在深圳。会有两个团队的人从香港过来与我面试，一个是做.NET的，一个.NET和Java均有涉及——同时还发给我一份Java的在线笔试题，说希望我能在面试前完成“以供参考”。那天正好是个周五，而面试安排在周一，与.NET的裸考不同，我有一个周末的准备时间。有了.NET笔试的经验，我估摸着Java笔试应该也是类似的题目，于是找了本一千多页的SCJP的辅导教材，认真地啃了一天半。期间也弥补了我对Java语言认识的一点缺失，因为我实在被Java的&lt;a href="http://blog.zhaojie.me/2011/06/java-anonymous-method-closure-scope-this.html"&gt;内嵌类、匿名类、泛型的复杂度给恶心到了&lt;/a&gt;。后来再有人跟我说Java语言简单，我就会回应说其实“它比你想象地要复杂很多”，要不我们可以来谈谈某些话题——更重要地是，复杂而不好用，导致人们会刻意规避这些复杂度，因此“连你也不知道Java语言原来这么复杂”。&lt;/p&gt;

&lt;p&gt;不过Java笔试其实比.NET要简单不少，完全没有涉及Java语言的复杂部分，更像是考一些代码阅读题以及基础类库，对于后者我只能根据一些“常识”和“经验”来猜测结果了。最后我的Java笔试成绩是93%，也算是不错的样子，面试时老外跟我的开场白便是说我.NET和Java成绩都很好——他的组会同时使用Java和.NET。倒是原本提到的用.NET那组的面试，由于签证没有过关，只是在电话里简单地聊了几句。&lt;/p&gt;

&lt;p&gt;面试房间有白板，因此面试的方式也有所不同。首先他提出一些业务上的场景，给我一些可用的组件（例如持久化队列），让我在白板上画出解决方案的设计图。然后他会继续做出一些假设，例如某一个服务的压力提高，成为了性能瓶颈，那么可以如何改进这个服务。不断涂涂改改最终也差不多画满了整面墙。此外还有各种关于性能诊断和优化的问题，涉及到日志记录的设计，CLR（主要还是GC部分），WinDBG，数据结构（线性表，哈西表，优先队列，平衡二叉树）等等。这些大都是开放题，因此可以谈得东西不少，我也不太担心因为不了解而无言以对。而且因为可以使用手势和示意图来辅助我那半吊子英语，也比纯粹在电话里的交流来的清楚。此外对方也谈到他对JVM的了解多过CLR，所以很多时候我也更像是在“解释”CLR的行为，目的是能够让对方理解，而不是去“迎合”对方心里的正确答案。总体而言，面试后的感觉其实比电话面试更有自信一些。&lt;/p&gt;

&lt;p&gt;回到上海后，我也很快收到了回应：我通过了J.P.Mongan方面的面试，也是第一个通过的.NET技术人员。剩下的便是令人烦躁的Offer商讨问题，略过不谈。值得一提的是，在正式发Offer之前，IBM还让我做了一套智力题（就是那种根据规律选则下一个数或下一幅图），据说是每个IBM员工都需要经历的测试——这是我整个过程中经历的最困难，也是最没有信心的环节了。最后我得了72分，堪堪超过65分的及格线，幸好终究没有在阴沟里翻船。&lt;/p&gt;

&lt;p&gt;以上便是我这次整体的经历。我也不想总结出什么理论地哲学化的大道理，就这样完整地记叙一遍吧。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/07/ibm-interview.html#comments</comments>
      <pubDate>Sat, 02 Jul 2011 15:29:37 GMT</pubDate>
      <lastBuildDate>Sun, 03 Jul 2011 08:57:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>道理人人有，就看怎么说</title>
      <link>http://blog.zhaojie.me/2011/03/mac-windows-valuable-arguments.html</link>
      <guid>http://blog.zhaojie.me/2011/03/mac-windows-valuable-arguments.html</guid>
      <description>&lt;p&gt;前几天猛鸟兄（&lt;a href="http://twitter.com/#!/raptorz"&gt;@raptorz&lt;/a&gt;）作为在使用Mac OS X时跌了个跟头，他之前是长期的Ubuntu用户，最近也买了台Mac。情况是这样的：OS X在文件夹复制（包括移动）的时候，如果目标地方也出现了同名文件夹，则OS X的策略是“替换（Replace）”，而Windows和*nix下cp命令的策略则是“合并（Merge）”。前者相当于完全删除了重名文件夹，而后者则是把其中的文件合并。对于习惯了后者的人来说，一没看清楚前者的提示，于是就丢失文件了。我当时也遇到过这情况，不过估计猛鸟兄不如我能忍，于是&lt;a href="http://twitter.com/#!/raptorz/status/48373090060746752"&gt;在吐槽推里fuck了乔教主&lt;/a&gt;，果不其然引发了各方争论。今天丁宇同学将他的观点（&lt;a href="http://twitter.com/#!/felixding"&gt;@felixding&lt;/a&gt;）整理为&lt;a href="http://dingyu.me/blog/hci-metaphors"&gt;一篇文章&lt;/a&gt;，表示OS X的做法更合理，对于这个说法我不敢苟同。现在先提一下这个问题，再引出真正想说的内容。&lt;/p&gt;

&lt;p&gt;丁宇同学的主要观点就是：OS X的做法更符合“文件夹”这个概念在现实中的隐喻，在这方面用户是给微软带坏了（完整内容请&lt;a href="http://dingyu.me/blog/hci-metaphors"&gt;阅读原文&lt;/a&gt;）：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;相比Win，Mac桌面的隐喻是非常贴近现实世界和统一的。比如刚才说的文件夹替换的问题，在现实世界中要替换两个文件夹的话，是把旧的拿走把新的放这，谁也不会预期说把新的往桌子上一放，结果啪的一下它里面又出现了旧的文件吧！喔，很不幸，ms的工程师认为世界应该是这样神奇的。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;而我的看法简单来说是：软件系统不应该以“符合现实隐喻”为尊，Windows的做法更好用，也并没有什么问题：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;还是就看你愿意怎么去解释，容我也来解释一番。&lt;/p&gt;

  &lt;p&gt;你说Mac的文件夹“替换”方式是“符合现实隐喻”，但什么时候开始计算机系统设计时就以这点为尊了呢？现实世界不是“没有”文件夹的合并操作，也并非“不需要”合并，而是“合并”的代价太高。但是，操作系统完全有能力快速地完成“合并”操作，这就是计算机辅助人类工作，改进人类生活啊，为什么非要符合现实世界里低效率的“人肉”工作方式？&lt;/p&gt;

  &lt;p&gt;Unix下的cp也是合并，说明这个策略是被人广泛接受的，更早于Mac的出现。Win在出现重名文件夹的时候，策略是“合并”，也是符合比Mac更早的传统。更何况，Windows也根本没说它在“替换”，“合并”写的清清楚楚明明白白，并非打着“替换”的旗号做“合并”的事情，这只是Windows所选择的策略而已。&lt;/p&gt;

  &lt;p&gt;再者，在Windows里如果想要实现你要的“替换”，删除目标文件夹，再复制过去即可。而在Mac下要实现“合并”，几乎就是如现实一样，人力不可为了。所以在我看来，Windows的策略弹性更大。&lt;/p&gt;

  &lt;p&gt;所以，你说这点Windows带坏用户，我不敢苟同。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;好，那么您说，我和他的说法哪个是有问题的？我觉得都可以说的过去，而且都可以继续往下说。每个人都是聪明人，每个人也都有自己的道理，这就是互联网上各种争论的来源，说着说着谁一个不小心就变味成了“争吵”（惭愧地说有时连我也不能例外）。&lt;/p&gt;

&lt;p&gt;这样的例子还可以举好多。例如，人类的适应能力是很强的，刚上手时感觉各种不好用的软件，如果坚持用过一段时间也会习惯，甚至切换回之前使用的软件也会觉得碍手碍脚。于是支持方会说：“看这软件多好用，之前的做法都不习惯了”，反对方会说“这软件真难用，好难上手”。谁对？谁错？更关键的是，谁能有力地证明自己的观点，而不是讲大道理？要知道，正反这两种说法都是有一定道理的。人类就是那么矛盾而变态的东西，否则也不会有&lt;a href="http://zh.wikipedia.org/zh-cn/%E6%96%AF%E5%BE%B7%E5%93%A5%E5%B0%94%E6%91%A9%E7%BB%BC%E5%90%88%E7%97%87"&gt;斯德哥尔摩综合症&lt;/a&gt;这种心理问题了。&lt;/p&gt;

&lt;p&gt;其实，如果能把问题从两个方面说清楚，这也是讨论的魅力所在。但现实中有个问题是，在许多情况下我们能够让别人相信自己是完全中立的，自己也很难保持没有偏向性——《美国宪政历程》里提到某首席大法官，为了保持不受社会舆论影响而坚持不看报纸，这实在不是件容易的事情。尤其是对于“用户体验”，“产品设计”这种难以道明的东西，可谓“人人都是产品经理”。现在好多时候在我看来充斥着“事后诸葛”、“成王败寇”的道道，搞得跟很多成功学一样，让我接受不了，能躲即躲。&lt;/p&gt;

&lt;p&gt;更关键的是，因为大伙都是聪明人，一件事情正说反说都有一定道理，于是人们很容易选择有利于自己一方选择“论据”，正所谓“你讲道理我跟你摆事实，你摆事实我跟你讲道理”，在实际情况下，上面提到的“好用”和“难上手”两派在“合适的时机”都会选择对方的思维方式，而且这种“切换”也可以很有道理，叫做“就事论事”，您又能奈我何。&lt;/p&gt;

&lt;p&gt;当然，即便我懒得搞这种正说反说，也不代表我就支持中间派（显然也不代表我反对中间派），更不代表我没有自己的看法。比如我对于PHP的观点。昨天正好又有&lt;a href="http://robbin.javaeye.com/blog/970047"&gt;关于Rails和PHP的讨论&lt;/a&gt;，于是我也正好拿它作例子。我对PHP的看法是：Quick and Dirty，随便找个人来就能写点代码，再加上历史积淀，可谓是最最流行的Web开发技术，没有之一。说的好听点，PHP叫做有着“辉煌的大尾巴”，难听点叫作“又臭又硬”。我一直强调要打开视野，但如果要我推荐，我不会推荐别人去学习PHP，即便工作上要使用PHP，我也建议去学习Ruby，Python平台上更有“文化”，更为“优雅”，开发效率更高的Web框架。有些人的理由就是，PHP社区更大，更流行，搜索引擎上的记录更多，某某排名都更高，怎么可能不是更好呢？要我看来，这种靠市场“成王败寇”的判断方式，我就根本不会认同，例如认可这种观点的同学，您认为“Windows比Mac OS要优秀十几倍”吗？要我说，这些还都是PHP的“历史优势”，不能直接说它在各方面就多么多么好了，你想说它哪方面好，还得有针对性的说清楚。而且话说回来，比尔盖茨如今560亿美元身价不可不谓之成功，但也没说陈天桥12亿美元这样的“零头身价”就变成“失败”，就不能做为榜样了。换言之，Rails等平台的质量足以受人推崇，足以干些了不起的事情了。引霍炬同学（&lt;a href="http://twitter.com/#!/virushuo"&gt;@virushuo&lt;/a&gt;）的&lt;a href="http://twitter.com/#!/virushuo/status/50282676300693504"&gt;一句话&lt;/a&gt;（&lt;a href="http://blog.devep.net/virushuo/2011/03/23/rubyror.html"&gt;完整内容在此&lt;/a&gt;），道理正是如此：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;寻找ruby开发的“top项目”没意义。DHH和37s创造的都不是适合所有人的产品，他们只愿意在某一领域做到最好。不是所有人都有兴趣创造亿级别产品，何况也没几个人真能做成。对大部分项目，千万是一个很好的级别，那是ror最佳实践领域。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;同样，JavaEye的站长范凯同学（&lt;a href="http://twitter.com/#!/robbinfan"&gt;@robbinfan&lt;/a&gt;）也提到了&lt;a href="http://twitter.com/#!/robbinfan/status/50369318151667712"&gt;JavaEye的近况&lt;/a&gt;：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JavaEye的PV到了140万了，一年前才100万出头，增长算不错的。仍然是单台Web服务器，Rails处理动态请求超过340万，除了真实用户访问，还有API，RSS以及很多爬虫的请求。看JE的alexa排名，CN排92名，全球790名，其实需要屠龙术的网站并不多。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;此外他还&lt;a href="http://robbin.javaeye.com/blog/972242"&gt;谈了其他一些话题&lt;/a&gt;，例如PHP和Rails程序员的培训和招聘等等，其中也谈到前来面试的PHP程序员很多基本功不过关，和某同学一直坚持认为“PHP程序员老nb，ASP.NET程序员啥都不懂”颇有出入。同样，还有人老说.NET产品作不大，其实您先超过StackOverflow再说吧，到那时您已经相当成功了，像MySpace什么就先不提了。&lt;p&gt;

&lt;p&gt;好象有点谈远了，再把话题扯回来：JavaScript在浏览器端处于垄断地位，是因为它有多么优秀吗？我觉得明显是因为用户没有第二选择嘛。当然我也没说JavaScript不好，只是正确的命题一定要用正确的论据来证明——好累，这句话本身应该是不言自明的，不是么？&lt;/p&gt;

&lt;p&gt;总之，所谓正反、对错、好坏、优劣……好多情况下就看您想怎么说。也正因为如此，我越来越懒得讨论这方面话题，除非心情特别好或是有人非要前来挑逗。但是久而久之，搞得我都有些虚无了，例如，现在除非是我上手就觉得好用（比如Mac触摸板的二指控制滚动条），否则您说其他一些东西的体验有多么多么好或是设计有多么多么合理（例如OS X Lion上的二指控制突然与之前方向相反了），我都会懒得去相信。当然，我个人觉得自己还是比较容易被说服的，例如有人提到了一篇文章：《&lt;a href="http://cmoney.info/dm/Knowledge/210.html"&gt;理念的缺失：Windows 7任务栏 vs. OS X Dock&lt;/a&gt;》，就一下子就让我高潮了。尽管我在这方面的能力还远不能跟他有所呼应，甚至，即使他是在骗人我也发现不了，但我就是愿意相信他的说法。就像有人在推上发发私信能跟女生上床，有人只能招人厌恶。&lt;/p&gt;

&lt;p&gt;最后，比如PHP什么的又碰到了您的G点，轻请拍。我懒。&lt;/p&gt;

&lt;p&gt;&lt;span style="color: red"&gt;广告时间&lt;/span&gt;：&lt;a href="http://nbazaar.org/"&gt;nBazaar技术交流会&lt;/a&gt;即将举办第四届活动。为了便于组织或活动通知，我们申请了&lt;a href="http://groups.google.com/group/nbazaar"&gt;官方的Google群组服务&lt;/a&gt;。该群组的作用只是为了联系和通知，活动的具体信息和资料发布依然会使用&lt;a href="http://nbazaar.org/"&gt;http://nbazaar.org/&lt;/a&gt;。我们已经向历届活动的报名者发出了邀请，请查收邮件（包括垃圾箱）。不过由于众所周知的原因，您可能无法接受该邀请，我们也在设法直接添加成员，只苦于Google群组的每日限制。此外，第四节活动还有一个讲师席位正虚位以待，如果您有这方面的意愿，或者对邮件列表有任何疑问，请发邮件至&lt;img class="embed" src="http://services.nexodyne.com/email/customicon/9xaGAYDnFdYrRqAdl1tTvrs%3D/Y4fIT8s%3D/000000/ffffff/000000/0/image.png" /&gt;。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/03/mac-windows-valuable-arguments.html#comments</comments>
      <pubDate>Tue, 22 Mar 2011 12:50:13 GMT</pubDate>
      <lastBuildDate>Thu, 24 Mar 2011 05:20:37 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>既要马儿跑的快，又要马儿不吃草</title>
      <link>http://blog.zhaojie.me/2011/02/there-is-always-a-trade-off.html</link>
      <guid>http://blog.zhaojie.me/2011/02/there-is-always-a-trade-off.html</guid>
      <description>&lt;p&gt;这年头技术社区里的一些观点让我很看不惯，例如动辄就说什么什么要被淘汰，什么什么要被替换。比如微软出个F#，就以为它要淘汰C#了，但C#和VB.NET不都已经共存很多年了吗？在我看来，明明是“多了一个选择”，绝对是好事情，又没逼你学，也没人说不学就落伍（不学VB.NET您就不觉得落伍吗？）。ASP.NET MVC也是如此，但非要有人说ASP.NET WebForms要被淘汰了，却“选择性忽视”至今WebForms还在不断成长的事实。MVC和WebForms都是好东西，各有千秋，两种选择罢了，仅此而以。&lt;/p&gt;

&lt;p&gt;某段时间常会看到很多人说WebForms是垃圾，一大堆问题，比如说ViewState放在页面上很占空间。我说，ViewState是个很神奇的东西，自动保持状态，许多场景下都能十分方便。如果你嫌它占空间，也可以选择性地关闭，不会影响你什么。可是，某些人还是不愿接受，嗷嗷数落WebForms的不是。好吧，MVC编程模型的确在许多方面胜过WebForms，用好就好。但是，怎么现在就会有人写信问我，诸如在ASP.NET MVC里怎么实现多个下拉框联动这种问题呢？此时往往还会提到WebForms时代实现这个功能有多么方便。我说，您也体会到WebForms的优势了么？结果某位兄台还继续抱怨说，用MVC也真是麻烦，进而说ASP.NET上面怎么就没好用东西。于是我说爱干嘛去干嘛去，还“既要马儿跑得快，又要马儿不吃草”么？&lt;/p&gt;

&lt;p&gt;ASP.NET不是傻瓜设计的，否则也无法如此轻易地实现出ASP.NET MVC。WebForms模型也十分精妙，尤其是带上UpdatePanel，绝对让人耳目一新（我知道某些人又要说UpdatePanel性能差了，我还是那句话，我读过UpdatePanel的完整代码，性能绝对不差）。只要不是愚蠢的作品，基本有失就会有得。刚好，前两天和公司里某个项目的弟兄聊天，他说他建议后台数据管理系统使用WebForms开发，结果项目组还是决定使用传统的方式写，原本计划三天完成，现在已经做了两个星期了，还在和大堆数据表的增删改查以及六个下拉框联动搏斗。&lt;/p&gt;

&lt;p&gt;还有个“马儿”的例子是关于.NET的。我见过有人抱怨说.NET的程序集管理很混乱，例如一个程序集还会在系统中存在多个版本。有趣的是，他同时还提到了Dll Hell，认为微软怎么总是搞不定此类问题。其实.NET程序集的管理方式，不就是为了解决Dll Hell问题嘛。所谓Dll Hell，往往就是因为不同程序间同名的库文件相互覆盖所造成的。如果高版本的库文件被低版本所覆盖，那么依赖高版本中新增API的程序就无法正常运行了。而且，即使是高版本的库，也有可能无法做到百分百兼容低版本（疏忽谁都会有）。因此，最合适的做法其实就是如.NET那样，同名没有问题，版本不同也不会相互影响，程序集自带元数据。A程序用1.9版本，B程序用2.0版本，大家和平共处，互不干涉。如果一个程序依赖1.0版本的程序集，那么即便系统中已经存在2.0版本也照样无法运行。如果没有这样的机制，即便是传说中伟大的Java平台也会有类似&lt;a href="http://en.wikipedia.org/wiki/Java_Classloader#JAR_hell"&gt;Jar Hell&lt;/a&gt;问题，最终可能还是需要一个类似于.NET中GAC的东西。&lt;/p&gt;

&lt;p&gt;很多东西都是这种权衡。世界上聪明人不多，但也没那么多笨蛋，我们大家其实都差不多。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/02/there-is-always-a-trade-off.html#comments</comments>
      <pubDate>Sun, 27 Feb 2011 17:01:21 GMT</pubDate>
      <lastBuildDate>Wed, 02 Mar 2011 04:53:38 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>分清“语言/规范”以及“平台/实现”，以及跨平台.NET开发</title>
      <link>http://blog.zhaojie.me/2011/01/be-clear-with-language-spec-and-platform-implementation-dotnet-cross-platform.html</link>
      <guid>http://blog.zhaojie.me/2011/01/be-clear-with-language-spec-and-platform-implementation-dotnet-cross-platform.html</guid>
      <description>&lt;p&gt;在许多年前，“语言”就等同于“平台”，例如C，C++以及最早的Ruby和Python等等。但是随着技术发展，出现了一些通用的平台，例如.NET和Java，逐渐这些平台上的语言也越来越多。再后来，某些语言在不同平台上的实现也越来越多，事情也变得有些复杂。技术在发展，但是从目前社区的讨论中，我发现许多朋友的观念还没有跟上。简单地说，如今的观念，一定要从“语言即平台”切换成“语言及平台”，当分清“语言”和“平台”这两个不同事物之后，许多问题才能讨论地清楚。&lt;/p&gt;

&lt;p&gt;例如我写过一个太监系列《&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html"&gt;Why Java Sucks and C# Rocks&lt;/a&gt;》，其中谈的是C#和Java两个“语言”而不是两者的“平台”。编程“语言”其实是一种“规范”，它涉及了程序员在使用这门语言时的文本表现形式（这里暂不考虑其他形式的语言），而“平台”则包括对这个规范的“实现”（广义的“平台”还包括整个生态环境等等）。C#和Java分别处在各自的平台上，但许多语言其实是跨多种平台的。例如Python，Ruby，Scala，Clojure，JavaScript等等，数不胜数。同样，一个平台上也会出现多种语言。而且事实上，由于.NET和Java这样的平台越来越成熟，语言的设计及实现者也都越来越倾向于让语言运行在“某个平台”上。这么做可以尽可能地利用前人的成果，而不是什么都要自己从头做起。&lt;/p&gt;

&lt;p&gt;其实基本的原则就是这么简单，但是真正在考虑问题的时候，可能就不是那么容易了，我们必须时刻保持清晰地头脑。&lt;/p&gt;

&lt;p&gt;例如有个人说“C#比Java执行效率高（或低）”，这个说法是否正确？其实这种说法有很大问题。因为我们知道，在这里C#和Java都是“语言”，它们的执行环境CLI及JVM一样都是“规范”，但“执行效率”是一种表现，这和“实现”得如何有很大关系。例如，C#是运行在.NET平台还是Mono上（它们都是CLI规范的具体实现），Java是运行在JRockit还是Hotspot（前者是Oracle的JVM商业实现，后者是Sun的开源实现——当然现在也是Oracle的），亦或是Android的Dalvik上？很显然，不同实现之间的表现会有区别，不可一概而论，否则也不会出现JavaScript引擎的效率之争了。同理，有些人使用Hotspot上的Java性能来说明Java在Android上运行时的表现，这也是不对的——要知道Google在和Oracle的Java专利官司中不断强调Dalvik不是“Oracle那种Java”。作为结论，Java在Android上的表现的确不错，但论证方式也必须正确才行。&lt;/p&gt;

&lt;p&gt;当然，有时候“规范”也会影响到“实现”，例如一个动态分发的语言，其性能基本百分百不如在编译期绑定的静态语言。所以事情原本就是这么复杂，做一个思路清晰的程序员并不是件容易的事情。顺便一提，女人在这方面的头脑一般都比较清楚，她们一般都知道骑白马的不一定是王子，也有可能是唐僧。&lt;/p&gt;

&lt;p&gt;对于俗称“.NET程序员”的那一批人来说，分清“语言”和“平台”更是一件十分重要的事情，因为C#语言可以说是目前“平台”、“实现”最为广泛的“语言”之一了。之前我为InfoQ写过一篇文章，其中提到Mono的创始人&lt;a href="http://tirania.org/blog/"&gt;Miguel de Icaza&lt;/a&gt;给出的&lt;a href="http://www.infoq.com/cn/news/2010/11/mono-cross-platform"&gt;目前C#语言可执行平台的“不完全”列表&lt;/a&gt;，几乎覆盖了各种流行的操作系统及设备等等，例如：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Windows &lt;/li&gt;

  &lt;li&gt;Mac OS &lt;/li&gt;

  &lt;li&gt;Linux / BSD / Solaris &lt;/li&gt;

  &lt;li&gt;Windows Phone，Android，iOS &lt;/li&gt;

  &lt;li&gt;XBox 360，Wii，PS3 &lt;/li&gt;

  &lt;li&gt;…… &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;因此就拿C#这一种语言来说，“实现”也会各自略有不同，这便是所谓的“配置（Profile）”。目前至少已经有这么多配置了：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;.NET 4.0配置 &lt;/li&gt;

  &lt;li&gt;Silverlight配置 &lt;/li&gt;

  &lt;li&gt;Windows Phone 7配置 &lt;/li&gt;

  &lt;li&gt;XBox360配置 &lt;/li&gt;

  &lt;li&gt;Mono核心配置：与.NET配置相同，可以在Linux，MacOS X，Solaris，Windows和BSD里使用。 &lt;/li&gt;

  &lt;li&gt;.NET Micro Framework &lt;/li&gt;

  &lt;li&gt;Mono的iOS配置 &lt;/li&gt;

  &lt;li&gt;Mono的Android配置 &lt;/li&gt;

  &lt;li&gt;Mono的PS3配置 &lt;/li&gt;

  &lt;li&gt;Mono的Wii配置 &lt;/li&gt;

  &lt;li&gt;Moonlight配置（与Silverlight兼容） &lt;/li&gt;

  &lt;li&gt;Moonlight扩展配置（Silverlight和完整的.NET 4 API） &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;“配置”之间的区别主要体现在执行环境的能力（例如iOS不支持运行时代码生成，因此支持AOT但不能JIT）以及类库的覆盖面上（例如XNA类库只存在于Windows Phone及XBox 360等游戏平台），不过它们终究实现了一个核心规范，因此我们可以说在不同平台上都可以“使用.NET进行开发”。&lt;/p&gt;

&lt;p&gt;Mono实在是一个了不得的作品，它让我知道了“跨平台原来可以这么做”。之前我也写过有关&lt;a href="http://blog.zhaojie.me/2010/06/is-cross-platform-a-lie-or-not.html"&gt;跨平台的问题&lt;/a&gt;，其中谈到在“客户端的跨平台一般都很难得到最佳的体验”，这个论点的最佳证明便是Java。但Mono走的却是另一条跨平台的道路，它在各平台上实现了核心的执行引擎和类库之外，解决“体验”的方式便是在各个平台上提供原生平台的绑定。这样无论是在Mac OS，iOS，Android上都可以得到原生应用的体验。&lt;/p&gt;

&lt;p&gt;我很奇怪为什么有些搞.NET的人一边说.NET的适用面太小，一边却忽视Mono的成果，在我看来这完全是“自作孽不可活”，我愈发觉得是否接受Mono是判断一个.NET程序员是否优秀的重要准则。其实Mono实在很火，因为他为广大.NET程序员扩展了工作领域，使用现有的知识来开发iOS等平台的应用程序，还可以共享代码，何乐而不为？前不久苹果发布了Mac上的App Store，于是MonoMac也立即推出了&lt;a href="http://tirania.org/monomac/archive/2011/Jan-10-1.html"&gt;面向AppStore的打包器&lt;/a&gt;，&lt;a href="http://twitter.com/#!/praeclarum"&gt;Frank Krueger&lt;/a&gt;也开始着手移植它的作品&lt;a href="http://icircuitapp.com/"&gt;iCircuit&lt;/a&gt;，&lt;a href="http://vimeo.com/18651634"&gt;成果显著&lt;/a&gt;。因此在我看来，这才是一个现代.NET程序员该有的工作台：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/morden-dotnet-prog-workbench.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/morden-dotnet-prog-workbench.jpg" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;对于MonoTouch这样的新思路，带有疑惑是正常的。我也知道还有许多聪明人可以找到各种反对的理由。不管怎样，我现在这里随意列上几条吧：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;有人说，用MonoTouch等.NET实现来做iOS开发“不正式”；我说，这个说法颇有“血统论”的意味，不过既然在Windows上用C++和Delphi都很正式，那么为什么在iOS上使用Objective-C才是正途？&lt;/li&gt;

  &lt;li&gt;有人说，MonoTouch性能一定不如Objective-C好；我说，这是猜测，即使性能不如Objective-C，看看各种案例也知道这在实践中并不是问题（事实上MonoTouch的前身便是Unity3D对Mono的使用，而iOS上实在有太多游戏在使用Unity3D了）。&lt;/li&gt;

  &lt;li&gt;有人说，MonoTouch或MonoDroid没有大公司支持，不靠谱；我说，您之前不是经常鄙视类似“开源没有微软靠谱”或是“微软开发人员只知道微软技术”这种说法的吗？&lt;/li&gt;

  &lt;li&gt;有人说，用MonoTouch等于抛弃了CocoaTouch社区，出了问题都没人问；我说，MonoTouch的问题基本就是CocoaTouch的问题，MonoTouch的UI层就是CocoaTouch，有问题直接去CocoaTouch社区或CocoaTouch程序员，代码直接映射，类库直接使用。&lt;/li&gt;

  &lt;li&gt;有人说，用MonoTouch的人不好招；我说，用C#、.NET的人比用Objective-C、Cocoa多太多了。给我一个熟练使用.NET和C#的人，三天上手，一周成为能够开发出成品的iOS开发者。&lt;/li&gt;

  &lt;li&gt;有人说，难道就是为了用.NET所以用MonoTouch？我说，用MonoTouch/MonoDroid的好处很多，例如我可以在iOS、Android、Windows Phone甚至更多平台上共享UI以外的代码，并可以直接使用大量.NET上的类库——这点实在太方便了。不要问我为什么Android上不能使用Java类库，我只知道开发Andorid的同事发现SOAP访问类库没有，REST找不到好的，JSON支持也只有最原始的支持，于是痛苦万分。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我还知道，这些说法依旧挡不住出现基于MonoDroid的&lt;a href="http://deltaengine.net/"&gt;DeltaEngine&lt;/a&gt;，这是个跨平台的游戏引擎，在Mono的支持下可以运行在Linux，MacOS X，iOS和Android上，在微软.NET支持下可以运行在XBox 360，Windows Phone 7自然还有普通的Windows系统上。在CES 2011上&lt;a href="http://blogs.nvidia.com/2011/01/nvidia-press-conference-ces-2011/"&gt;NVidia演示了一个游戏&lt;/a&gt;，&lt;a href="http://mobilebits.de/Blog/post/2011/01/05/Delayed-blogging-of-building-the-first-SoulCraft-Tech-Demo-version.aspx"&gt;Soul Craft&lt;/a&gt;，它运行在&lt;a href="http://blogs.nvidia.com/2011/01/lg-launches-optmus-2x-dual-core-superphone-powered-by-tegra-2/"&gt;LG Optimus 2X&lt;/a&gt;，这个游戏正是使用了DeltaEngine。&lt;/p&gt;

&lt;p&gt;对于我们来说，最大的限制其实还是眼界和思维，突破这一屏障也是我组织&lt;a href="http://nbazaar.org/"&gt;nBazaar技术沙龙&lt;/a&gt;的目的之一。本周六将会举办第三届nBazaar技术交流会，具体信息请访问&lt;a href="http://nbazaar.org/"&gt;http://nbazaar.org/&lt;/a&gt;。如果您还没有报名，也可以直接前来，也欢迎带上感兴趣的朋友或同事。根据以往的经验，场地就像乳沟，挤挤总是有的……&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/01/be-clear-with-language-spec-and-platform-implementation-dotnet-cross-platform.html#comments</comments>
      <pubDate>Thu, 13 Jan 2011 15:35:21 GMT</pubDate>
      <lastBuildDate>Fri, 14 Jan 2011 02:29:51 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>“花钱”购买App Hub Membership终于成功了</title>
      <link>http://blog.zhaojie.me/2011/01/paid-for-app-hub-membership.html</link>
      <guid>http://blog.zhaojie.me/2011/01/paid-for-app-hub-membership.html</guid>
      <description>&lt;p&gt;作为一个身在天朝的开发人员，要及早使用国外的服务总是一件杯具的事情，注册Windows Phone 7的App Hub Membership也不例外。不幸中的万幸，我工作于&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;，这也是个奇妙的地方，身边的同事就有美国人，在他的帮助下，从提及注册信息到审核成功也只用了6、7个小时。说起来美国人在这方面的确占有十分重大的优势，不光是审核速度快（其他国家用户还需要等待GeoTrust主动联系，并提交更多信息，多花上2、3个工作日十分正常），连价格也便宜（年费只需99美金，前两天让荷兰的朋友帮忙注册需要99欧元），不得不长叹一声。&lt;/p&gt;

&lt;p&gt;由于注册无法重现，我在这里只能简单描述一番。第一个环节是选择国家/地区，以及帐号类型等等，这与接下来的信用卡以及费用有关。接着则是各种信息，姓名电话地址邮编等等，也要和最后那张信用卡相符。之后则是提交信用卡的信息了，自不必说。值得一提的是，在提交信用卡的时候，网站总是说我的信息无法通过认证，几经尝试，最后使用我的美国VPS作代理才注册通过，看来是IP问题。通过之后，邮箱里会收到微软和GeoTrust发来的确认邮件，其中包含一个用于身份认证的链接，点开后则要求输入美国公民的各种信息，例如社会保障号等等。填写必需的字段，提交后便说“请等待处理”了。下午注册，晚上8点就收到邮件说成功了。总体而言，对于国内用户来说，App Hub Membership的“注册代理”比Android Market要宽松一些，后者似乎还要验证邮箱等等。&lt;/p&gt;

&lt;p&gt;App Hub包含了Windows Phone和XBox的开发和发布权限，我虽然也&lt;a href="http://blog.zhaojie.me/2011/01/htc-7-mozart-t8698-windows-phone-7-review-and-xbox-kinect.html"&gt;刚入手了XBox和Kinect&lt;/a&gt;，但我注册个App Hub完全就是为了Windows Phone上面的开发。诚然，如果不需要发布到Marketplace，使用微软提供的免费工具，&lt;a href="http://blog.zhaojie.me/2011/01/htc-7-mozart-t8698-windows-phone-7-review-and-xbox-kinect.html"&gt;再加上ChevronWP7的破解&lt;/a&gt;早已足够了，但我还是选择了购买App Hub。这不到700块钱用于体验时代潮流，仔细想来也并不太多——当然这也涉及到个人的价值观。有些人认为4、500块钱的手机用来打电话发短信也已够用，而另一部分人（包括我）的看法是，几千块钱本身说起来也不能做太多事情，不如用于体会互联网时代的价值，这也是一种进修。所以我会较快购进Windows Phone、Kinect以及MonoTouch等等，即使从某些角度来看Windows Phone并非是一个适合国内用户的产品。&lt;/p&gt;

&lt;p&gt;以前我总是舍不得花钱，和许多朋友一样觉得这也很贵，那也很贵，于是也会用盗版等等。后来我和别人一起创业，虽然并非直接掌管资金，但也对于各种花销建立了一些概念。例如我知道了开一天公司需要多少钱，给员工交工资和福利、网站托管、流量购买需要多少钱，于是我就不会认为一套不到3000的MonoTouch，或是其他某个组件的商业授权有多么昂贵，因为它们的确可以为我省下更多的钱。从那时起，我会适当地选择开发效率更高的.NET平台加上价格便宜（3000左右）工作足够对硬件也十分宽松的Windows Web Server 2008，配合价格便宜选择丰富的*nix作后端存储。&lt;/p&gt;

&lt;p&gt;学会合理花钱的好处其实很多，首先我可以自豪地宣布，我已经不用盗版软件许多年，其次我学会通过花费现在的钱来提高自己或是节省精力，以便赚到更多的钱。我现在越来越喜欢适当使用一些收费的组件，因为我相信他们为了卖更多的授权，会不断提高自己的产品以及服务质量，这让我可以轻松不少。反之如果一切都由自己从头做起，可能大量的时间都耗费在一些无谓的细节上面才能得到与商业产品差不多的质量。时间往往比金钱更有价值。如果纠缠于那些细节无法让人提高，我情愿将时间用在自我学习、娱乐甚至是简单的休息上面。&lt;/p&gt;

&lt;p&gt;说起来购买App Hub Membership也是类似的道理，我不想把大量精力耗费在刷机、破解等方面（虽然我知道许多朋友乐在其中）。非官方的解锁方式总是无法让人安心，可能一次系统升级就让手机重新锁定了，于是又要折腾半天。现在则不然，即便微软接下来会升级Windows Phone，我也可以放心继续使用。因为我已经成为了正式的开发人员，XBox Live的Avatar都可以使用新装备了，哈哈。&lt;/p&gt;

&lt;p&gt;如今是程序员的黄金年代，移动平台和应用市场的兴起让我们可以比以往任何时候都轻松地赚取零花钱，甚至开创一番事业——当然前提是要有创意，这也是我最缺乏的。因此，如果您有什么需求或是点子，也不妨给我一些指点，我也有点实际内容可做。&lt;/p&gt;

&lt;p&gt;最后，依然来推广一下本周六即将举办的“&lt;a href="http://nbazaar.org/"&gt;第三届nBazaar技术交流会&lt;/a&gt;”，欢迎继续报名（近日将发出邀请函）。在今后的交流会上，我也会引入更多有趣的话题，例如移动平台的开发，甚至是与Kinect相关的话题。Kinect的确是神器，在我家已经成为父母每天必修的娱乐活动，可能我还会再买一套送给他们。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/01/paid-for-app-hub-membership.html#comments</comments>
      <pubDate>Mon, 10 Jan 2011 17:45:57 GMT</pubDate>
      <lastBuildDate>Tue, 11 Jan 2011 05:25:36 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <title>Silverlight与微软技术（下）：微软技术与技术学习</title>
      <link>http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-2-microsoft-technology-and-how-to-learn.html</link>
      <guid>http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-2-microsoft-technology-and-how-to-learn.html</guid>
      <description>&lt;p&gt;经常听到有人说微软的技术变化太快，持续性不好，让程序员追得很累。这种观点在微软技术社区内部和外部都有出现，似乎是一个不争的事实。但从我追随.NET平台这近十年的时间里，我并没有明显的感觉。微软的技术的确很多，但至少在.NET领域过渡性做的非常好，我没有任何疲惫之感。微软技术开拓了我的眼界，让我在微软内外许多技术方面越来越少有“新奇”的感觉，一切都是那么自然和稳妥。我现在就来仔细谈谈我在学习微软技术方面的经验与感受。&lt;/p&gt;

&lt;p&gt;我一直对编程有浓厚的兴趣，上大学前在编程方面的经验主要来自于信息学竞赛，此外就是用一些VB或是Delphi写一些小程序，拿去参加高中的一些名不见经传的小比赛，那点小名次，小打小闹，仅此而已。到了大学里，学习（或自学）了Java，少许LISP，数据结构与算法，操作系统，计算机体系结构，计算机网络，编译原理等最传统的科班课程，但似乎学的不太好，现在想来颇是后悔。此外学过几次C++，但智商有限，几次下来都没有坚持到底，现在也忘得差不多了。可以这么说，我的专业程序员生涯的成长离不开微软与.NET。当然，我热爱各种技术，各方面也学习了很多。我接下来也会说到，技术本就不应该分为“微软”与“非微软”两个部分。&lt;/p&gt;

&lt;p&gt;我在大学的时候学习和使用的是Java，也用Java参与了一些奇怪的“企业项目”——如上海海关进出口检疫局的什么什么系统（不过那时候我也已经开始接触C# 1.0和.NET了）。后来由于去了微软，自然全面转向.NET。我在微软只待了一年半，但这一年半给我最大的帮助就是让我开阔了眼界，知道技术领域有多么广阔，知道学校里了解的一些东西是多么的不靠谱。可以说在微软的这段时间对我来说是个突破，从那时起我就对各种技术都抱有强烈的兴趣。&lt;/p&gt;

&lt;p&gt;有人说微软技术发展太快，且时常淘汰很多东西，对此我并不赞同太多。我接触到的说微软技术变化太快的同学，大都是老程序员，他们因为微软将重心放在了.NET上，导致了COM等技术运用场景减少，于是颇为不满。他们时不时“预言”微软以后会抛下.NET，虽然.NET已经发展了近10年，且力度越来越大，所以我称这种“预言”是一种FUD。我是从.NET 1.x/C# 1.0学起的，一直到现在，无论是语言还是基础类库，一切都良好过渡。您在C# 1.0里学到的东西，有哪些在C# 4.0里消失了么？您写的ASP.NET 2.0程序，直接无痛升级到ASP.NET 3.5——这是&lt;a href="http://www.dianping.com/"&gt;大众点评网&lt;/a&gt;的架构师&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;在分享会上提到的&lt;/a&gt;，它的应用规模及复杂度不低于您的项目吧？微软是个对企业应用有许多投入的公司，在过渡和兼容性方面必须做到几乎百分百的保证，这些经验也总结成册，例如获得Jolt大奖的《&lt;a href="http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756"&gt;Framework Design Guildline&lt;/a&gt;》，其中不断强调的一点，就是在设计时对兼容性方面的考虑。&lt;/p&gt;

&lt;p&gt;在兼容性方面，某些技术领域的程序员就有更高的“觉悟”。例如Python 3.0成为了一门不兼容Python 2.x的语言，Rails 3.0也不兼容Rails 2.x。我咨询过几个Rails程序员对此的看法，他们观点十分一致，那就是对Rails 3.0很有好感，至于以前的项目，“没有必要从2.x升级到3.0啊！”。我也支持他们的看法，如果您不喜欢C#里的新特性，那就不用那些特性。如果您不喜欢新框架的功能，那就继续用原来的方式做事情，新的框架也不会对您有影响。我支持Python和Rails项目发展的决定，他们为了前进抛下一些历史包袱，我可以理解。这并不会影响我对Python和Rails的喜爱，它们依然是十分优秀的语言和框架。&lt;/p&gt;

&lt;p&gt;有人说，微软会淘汰技术，那么对这些技术的投资不就失效了吗？这方面我认为自己有很好的发言权。我&lt;a href="http://blog.zhaojie.me/2009/10/talk-about-blogging.html"&gt;之前也提到过&lt;/a&gt;，我在社区里的“声望”是靠ASP.NET AJAX积累起来的。但是现在ASP.NET AJAX似乎慢慢地淡出了人们的视线，那么我的投资失败了吗？完全没有，确切地说简直太成功了。ASP.NET AJAX覆盖了浏览器端的JavaScript开发，以及后台对ASP.NET WebForms页面模型的扩展，当然，还包括两者的交互。我一直认为UpdatePanel是前后端交互的经典之作，它通过在前端页面的hook，以及对后端WebForm模型输出的捕获，做到了非常透明的AJAX效果，只可惜由于项目分工，前端开发人员大都喜欢手写的纯客户端模型，因此UpdatePanel不太受人待见。我读过了ASP.NET AJAX的前台代码，由此全方面了解了JavaScript语言和许多前端开发的技术和技巧。我读过了ASP.NET AJAX的后端代码，由此我了解了一个JSON序列化框架可以如何实现出来，体会到了ASP.NET及其WebForms模型丰富灵活的内涵。从ASP.NET AJAX开始，我可以自豪地认为自己“精通”了ASP.NET，对它各方面的扩展可谓如鱼得水。例如，我可以轻易写出一个&lt;a href="http://blog.zhaojie.me/2008/05/build-component-to-upload-file-in-updatepanel.html"&gt;UpdatePanel上传文件&lt;/a&gt;，或是&lt;a href="http://blog.zhaojie.me/2008/04/try-to-build-an-updatepanel-for-asp-dot-net-mvc.html"&gt;ASP.NET MVC中UpdatePanel&lt;/a&gt;的原型，虽不至于成为一个通用的组件及解决方案，但是对于自己项目本身已完全够用（我几乎没有纯“玩闹”而写的扩展，都是源自于项目本身）。后来微软出了ASP.NET MVC，我花两天时间扫视一遍它的源代码，也已经基本掌握了它的原理，使用方式，扩展也罢，一切都那么顺其自然。例如Rails是个优秀的Web框架，包含许多对实际生产非常有效率的特性，但是我在看了这些特性的使用方式之后，几乎都可以立即想象出它在ASP.NET里的实现方式，就例如&lt;a href="http://blog.zhaojie.me/2009/09/aspnet-mvc-fragment-cache-1.html"&gt;表现层的片段缓存&lt;/a&gt;那样。&lt;/p&gt;

&lt;p&gt;我一直强调，我并不了解所有的.NET相关的框架，但就我所了解的.NET技术而言，它们都有这样的特征：过渡性很好，自然地，有底蕴的发展。就拿C#来说，C# 1.0中创造了“委托”这个函数的一等公民类型，而在C# 2.0里引入了匿名方法，C# 3.0里强化了函数式编程的理念，成就了这一到目前为止最为经典的C#语言。C# 3.0中引入了Monadic的LINQ语法，几年下来基于LINQ发展了太多太多，如PDC 09中的&lt;a href="http://blog.zhaojie.me/2010/09/async-programming-and-reactive-framework.html"&gt;LINQ to Observable&lt;/a&gt;，PDC 10上的&lt;a href="http://player.microsoftpdc.com/Session/bfa72307-6534-41ad-bcf7-0f4fb9280515"&gt;LINQ to Azure&lt;/a&gt;。社区里如围绕NHiberante的贡献更是数不胜数。微软技术在我看来是十分领先的，这个领先并不一定指它在计算机科学上的创新和突破，而是指它对于这些经典理念与工业生产相结合方面的超前。可能它不如某些朋友心目中LISP那般博大精深，但可以说更直接地在让我在实际生产中体会到了经典的魅力。&lt;/p&gt;

&lt;p&gt;这样的“领先”给我带来了许多乐趣，也让我慢慢难以从其他技术上感到“惊喜”。例如，一个Java程序员转到Python以后，会感觉生产力有了显著的提高，但就我来说，&lt;a href="http://blog.zhaojie.me/2009/02/1381867.html"&gt;相当部分的生产力在C#中都有体现&lt;/a&gt;，我不会以为生产力低下是“静态语言”的关系。同样，我最近在关注iOS及Mac OS方面的应用程序开发，接触了一些Objective-C，发现它的block就相当于.NET中的委托，而在09年随Snow Leopard引入的block的支持语法早在C# 2.0中就由“匿名方法”特性实现了，更不说C# 3.0在这方面有更进一步的发展。同样，我阅读了&lt;a href="http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html"&gt;GCD（Grand Central Dispatch）的文档&lt;/a&gt;之后，发现它和.NET 4.0中的TPL（Task Parallel Library，任务并行库）解决的是相同的问题，其实现思路也有许多相同之处，例如都是主要通过描述“任务”（如任务内容及依赖关系）来避免程序员直接使用线程，避免复杂的同步问题，并由系统来负责对任务的调度。有时在推特上，我时常可以看到一些Cocoa的开发者津津乐道于block及GCD对于并行开发所带来的诸多便利——于是我想，这个早已不该是新闻了嘛。我现在还知道&lt;a href="http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html"&gt;未来C#还会在这方面有更多便利&lt;/a&gt;，它在Anders Hejlsberg的带领下再一次走到了领先的位置。&lt;/p&gt;

&lt;p&gt;微软的技术大都容易入门，但这并不影响这些技术深厚的底蕴，您在学习时应该了解这种底蕴。例如，您在学习C#时，不应该只关注它的表面特性，而要知道“为什么Anders会设计这样的特性”。我认为，一个优秀的C#程序员应该对函数式编程有一定程度的理解。当您学习&lt;a href="http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx"&gt;Reacive Framework&lt;/a&gt;时，应该顺便去了解一下响应式编程。同样，我看到社区里有一些关于TPL的文章，但认为它们还是没有把握到精髓。事实上这些精髓都不是秘密，微软对各种原理几乎都不做保留。例如微软免费提供了《&lt;a href="http://parallelpatterns.codeplex.com/"&gt;Patterns for Parallel Programming&lt;/a&gt;》等资料，详细解释了并行编程中的诸多模式，以及它们在TPL（C#与VB）或是F#中的实现方式，这些都体现了微软在设计这些语言或类库时的思路。微软在构建这些技术的时候并非无中生有，都是事先设计好使用场景的。例如用Task应对任务并行，用PLINQ应对数据并行，毫不草率，堪称经典。此外，TPL的设计者&lt;a href="http://www.bluebytesoftware.com/blog/Default.aspx"&gt;Joe Duffy&lt;/a&gt;是业界大牛，他写过一本《&lt;a href="http://www.amazon.com/Concurrent-Programming-Windows-Joe-Duffy/dp/032143482X"&gt;Concurrent Programming on Windows&lt;/a&gt;》，描述了大量关于TPL的实现细节，例如无锁数据结构的编写方式，Work Stealing，如何改善&lt;a href="http://blog.zhaojie.me/2009/01/system-architecture-and-program-performance.html"&gt;局部性&lt;/a&gt;等等。您了解了这些内容以后，我想GCD对您来说可能也只是换套API而已，应该也不算是件难事儿。我一直认为，就算微软明天给外星人一锅端了，我也能很快进入其他技术领域，并很快达到较高级的程度。但是，如果您每次都只了解一些表面，自然很容易觉得天崩地裂。盲目追赶，那也只是恶性循环而已。&lt;/p&gt;

&lt;p&gt;我一直强调“眼界”，微软技术不断为我打开新视野，这些技术的设计者都在各种场合提到其他技术对他们的影响。因此，学习了C#和F#，我对于Python，Ruby，Scala，Haskell都产生了浓厚的兴趣，我不会像许多Java程序员认为Java语言已经足够了，或是像许多Ruby程序员那样认为&lt;a href="http://blog.zhaojie.me/2010/08/programmer-hierarchy-disgusting-csdn-news.html"&gt;自己领先于其他程序员&lt;/a&gt;，我能时刻保持Keep Stupid，Keep Hungry。我时常不解一些技术人员在我看来&lt;a href="http://blog.zhaojie.me/2010/03/microsoft-technology-and-the-attitude.html"&gt;莫名其妙的轻视（不是“敌视”）微软技术&lt;/a&gt;，我认为技术的大千世界何其美好。因此，即便我再是厌恶Java语言，也对JVM和其生态环境敬爱有加。于是，我通过《&lt;a href="http://www.amazon.com/CLR-via-Dev-Pro-Jeffrey-Richter/dp/0735627045/"&gt;CLR via C#&lt;/a&gt;》对.NET运行时浅尝辄止之后，又通过《&lt;a href="http://www.amazon.com/Oracle-JRockit-Definitive-Marcus-Hirt/dp/1847198066/"&gt;Oracle JRockit: The Definitive Guide&lt;/a&gt;》深入了解JVM的虚拟机世界。我看过了《Concurrent Programming on Windows》之后，又去阅读了作者推荐的《&lt;a href="http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601/"&gt;Java Concurrency in Practice&lt;/a&gt;》。&lt;/p&gt;

&lt;p&gt;如果眼界没有打开，即便您学习的是业界“最先进”的技术，也可能产生偏差。例如时常看到Rails开发人员自豪地说，他们可以从Rails里学习RESTful。由于前段时间我刚巧看了《&lt;a href="http://www.amazon.com/REST-Practice-Hypermedia-Systems-Architecture/dp/0596805829"&gt;REST in Practice&lt;/a&gt;》一书，再结合我对Rails的了解，我实在没有感到这个Web框架在RESTful方法的独到之处。于是他们让我去看Rails 3.0里&lt;a href="http://guides.rubyonrails.org/routing.html"&gt;强大的Routing功能&lt;/a&gt;。我看后，才意识到其实他们似乎对于REST的理解有所偏差——REST的精髓在于&lt;a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven"&gt;由Hypermedia驱动的State Transfer&lt;/a&gt;，而形如“/article/20”这样的URL，以及映射一些HTTP方法等等，其实远非RESTful架构设计里的关键。RESTful只是要求“每个资源对于一个URI”，但并没有规定URI的形式，而且如果客户端直接了解服务器端的URL规格并直接访问，就与REST的“解耦”目标渐行渐远了。事实上，《RESTful in Pratice》一书甚至有建议对URL做些混淆。总体而言，Rails只是对REST架构中的一小部分提供了较好的支持而已，还远不能“从Rails学习REST”。昨天晚上我和REST专家李琨老师谈了我在这方面的理解，他基本赞同我的看法。我庆幸不已，要知道在此之前我还看过《RESTful .NET》一书，但我走向《RESTful in Practice》之后，才意识到前者给我带来了不少错误的观念。幸好，我并没有良好的自我感觉，也没有满足于现状。&lt;/p&gt;

&lt;p&gt;如果您学习的是.NET，那么打开眼界的一个有效工具便是Mono。Mono及Miguel de Icaza已经不再拘泥于跨平台的.NET这个目标，而是努力在其之上实现大量的开源或商业产品。其中的典型便是&lt;a href="http://www.infoq.com/cn/news/2010/10/Cross-Dev-WP7-iPhone-Android"&gt;MonoTouch和MonoDriod让.NET及C#进入iOS和Android平台&lt;/a&gt;，&lt;a href="http://tmssoftware.com/site/blog.asp?post=183"&gt;广受喜爱&lt;/a&gt;，也已经&lt;a href="http://matt-greer.com/blog/2010/10/optix-trailer/"&gt;有越来越多的成功案例&lt;/a&gt;。此外，Mono对于&lt;a href="http://www.infoq.com/cn/news/2010/10/MonoMac-Update"&gt;开发原生Mac OS应用程序的支持&lt;/a&gt;也步入了正轨。我作为一个.NET开发人员，从没有过如此兴奋的感觉。&lt;/p&gt;

&lt;p&gt;如果您正确地学习了.NET技术，您会发现自己走上了一条良性发展的道路。从另一方面来讲，微软的技术固然多，但作为开发人员我们并不需要了解每项技术。微软在创建一门新的技术的时候，都会讲清楚这门技术所解决的问题是什么，如果与您无关，完全可以不去学习。例如.NET 2.0与3.5之间还有一个3.0，其中提供了WPF，WF和WCF三个框架。我可以坦率地讲，我对它们没有任何了解，但这丝毫不影响我自称是一个优秀.NET技术人员的自信。很多时候，如“疲于追赶”这种事情，我觉得太多程度上都是自寻烦恼了。这样“无中生有”的烦恼还有很多，例如微软给出F#以后，就有人说微软要抛弃C#了。您为什么就不能认为这是一种互补，或者说，给您多了一种选择呢？微软同时发展VB.NET和C#语言好多年了，您一直没有学习VB.NET的烦恼，为什么现在多了一个F#，您又动摇了呢？还有例如近日的Silverlight问题，&lt;a href="http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-1-is-silverlight-dead.html"&gt;前篇文章已有详述&lt;/a&gt;，不提。&lt;/p&gt;

&lt;p&gt;许多人会持有这样的观念：整个技术领域分割为“微软”和“非微软”两部分，然后指责“微软”技术不如“非微软”来的丰富。在我看来这种分割方式是十分可笑的，怎么没有人将技术分为“Ruby”和“非Ruby”，然后指责“Ruby”技术不够丰富呢？此外，还有一些观点，认为ASP.NET应用程序靠memcached提高伸缩性是种失败，这也是同样的割裂逻辑。为什么PHP和Rails使用memcached就被视为正当手段呢？说起来，memcached是C语言写的，还真不关PHP和Rails什么事情呢。&lt;/p&gt;

&lt;p&gt;而且，正如我之前说的，微软技术对我的重要价值之一，便是促进了我对各方面技术的浓厚兴趣。无论您是专攻哪种技术的开发人员，如果只是停留在自己这一亩三分地上，这都是不甚可取的。没有人限制微软系的技术人员从其他领域吸取经验，正如一个优秀Ruby程序员肯定也从Ruby外的技术领域吸收了大量精华。说实话，除了政治需要，我实在找不到将微软和开源社区（或是其他社区）对立起来的理由。事实上，我时常感觉，您即便工作于.NET的竞争性平台，学习.NET对于个人提高来说也是大有帮助的。&lt;/p&gt;

&lt;p&gt;就写到这里吧。希望对您了解微软技术，以及如何学习微软技术能够有所帮助。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-1-is-silverlight-dead.html"&gt;Silverlight与微软技术（上）：微软抛弃Silverlight了么？&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;Silverlight与微软技术（下）：微软技术与技术学习&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-2-microsoft-technology-and-how-to-learn.html#comments</comments>
      <pubDate>Thu, 04 Nov 2010 10:57:48 GMT</pubDate>
      <lastBuildDate>Sun, 27 Feb 2011 17:08:07 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>Silverlight与微软技术（上）：微软抛弃Silverlight了么？</title>
      <link>http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-1-is-silverlight-dead.html</link>
      <guid>http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-1-is-silverlight-dead.html</guid>
      <description>&lt;p&gt;话说，在最近的PDC上，微软的副总裁Bob Muglia说了类似的话“我们对Silverlight的策略改变了，我们要用HTML5来实现跨平台的应用程序”，于是乎，社区铺天盖地响起了“微软要抛弃Silverlight”的调调。出现这个说法并不奇怪，媒体转述一遍，再给社区理解一下，很正常。但是我觉得奇怪甚至有些恶心的是，当事实愈发明朗化的时候，冒出的一些莫名其妙，兴灾乐祸，事后诸葛还在愈演愈烈。这两天我在社区里看的很多说法，某些“评论家”连一些基本概念，如“Silverlight是Windows Phone 7的开发平台”都不清楚，就来捕风捉影，实在让我难以继续旁观。&lt;/p&gt;

&lt;p&gt;其实&lt;a href="http://www.zdnet.com/blog/microsoft/microsoft-our-strategy-with-silverlight-has-shifted/7834"&gt;Bob Muglia的原话&lt;/a&gt;是这样的：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&amp;quot;Silverlight will continue to be a cross-platform solution, working on a variety of operating system/browser platforms, but HTML is the only true cross platform solution for everything, including (Apple's) iOS platform.&lt;/p&gt;

  &lt;p&gt;Silverlight将继续是一个跨平台的解决方案，未来Silverlight将持续工作在各种操作系统/浏览器平台上，但是HTML才是目前一切运用真正跨平台解决方案，包括苹果的iOS平台。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这句话的问题在哪里？我看不出任何要放弃Silverlight的意思。微软从一开始就说Silverlight将会跨操作系统及浏览器运行，目前是，将来也是，包括Windows，Mac OS及这些平台上的各种浏览器。但是，对于移动设备又能怎么办呢？苹果的iOS上已经拒绝Flash进入，因此拒绝Silverlight也是可以预料的，因此Silverlight方面就算尽再大努力也无法实现这点。而苹果是支持HTML 5的，因此微软为了发展，将HTML作为“跨所有平台”的手段，在我看来十分顺理成章。可能Silverlight以后不会进入iOS，但并不表示它不会进入Android等其他手机平台，而就目前来说，Silverlight本身已经是Windows Phone 7的开发平台了。&lt;/p&gt;

&lt;p&gt;Silverlight之于Windows Phone 7，WPF之于Windows，就好比CocoaTouch之于iOS及Cocoa之于Mac OS，它们都是十分正常的产品及开发平台策略。就拿苹果来做例子吧，CocoaTouch只能工作在iOS系统上，您担心CocoaTouch被苹果抛弃吗？诚然，微软的手机才刚刚起步，平板电脑更是没有踪影，从商业上来说远不如iOS设备成功，但是人人都能看到微软对Windows Phone 7的重视，WP7是微软不断强调的“三屏一云”战略的重要组成部分，而Silverlight就是WP7上的开发环境，那么您为什么会担心它会被微软抛弃？我看到有些文章的标题类似于：“Silverlight失败，未来属于移动互联网”，于是我就转不过脑子了，Silverlight对于微软来说，就几乎等同于“移动互联网”，您一边看好移动互联网，一边觉得Silverlight挂了，你让微软情何以堪？&lt;/p&gt;

&lt;p&gt;有人说，这次的&lt;a href="http://player.microsoftpdc.com/session"&gt;PDC 2010&lt;/a&gt;都没有Silverlight的内容了，可以看出微软不要Silverlight了，否则怎么没有Silverlight 5的消息？我也觉得很奇怪，PDC是有主题的，这次的主题是Azure，IE 9和WP 7，因此强调的是云计算，HTML 5和移动互联网开发，最后一个其实就是Silverlight。事实上Silverlight的内容本就没少，只是换了个名字叫做WP 7。我不知道嚷嚷着PDC没有了Silverlight的同学有没有真正看过PDC，不过我在看，看了很多，感觉很爽。我看到了&lt;a href="http://player.microsoftpdc.com/Session/6f853fa2-06f6-45e5-ac25-18c31cc4ba32"&gt;PDC的Keynote演讲&lt;/a&gt;上ScottGu就在现场操练Silverlight开发，分会场里也在大谈“&lt;a href="http://player.microsoftpdc.com/Session/58d670be-bd26-4ee3-9db1-5f2767eba4f8"&gt;基于Silverlight开发面向Azure平台的WP7应用程序&lt;/a&gt;”、“&lt;a href="http://player.microsoftpdc.com/Session/14b74bfd-d2e5-42de-accf-3ff2418783a8"&gt;优化WP7中Silverlight程序性能&lt;/a&gt;”，“&lt;a href="http://player.microsoftpdc.com/Session/73abab73-15e2-4911-a125-ab9487ebea22"&gt;早该知道的WP7开发注意事项&lt;/a&gt;”，还有与WP7几乎无关的“&lt;a href="http://player.microsoftpdc.com/Session/76864d75-b4da-4858-aac7-786c5f28e344/2.69"&gt;使用Silverlight 4开发商业应用&lt;/a&gt;”，“&lt;a href="http://player.microsoftpdc.com/Session/638f610a-ea51-4aef-9657-e3fe425ae745/469.163"&gt;如何在WPF和Silverlight中共享代码&lt;/a&gt;”等等太多内容。半年前的MIX 10大会上微软还在大谈Silverlight和WP7，只不过打得是Silverlight的旗号，而仅过了半年，微软打着自己正在全力推广的WP7的旗号来谈几乎相同的话题，您怎么就突然崩溃了呢？&lt;/p&gt;

&lt;p&gt;PDC是微软专业会议，议程及其有限，而微软的技术实在太多，没有登上PDC讲台的话题实在太多太多了。去年的PDC还有关于CLR、虚拟化、Windows Server的话题呢，这次都看不到了，莫非微软要抛弃这些了？如果像某些同学希望的这样，微软发布了Silverlight 5的消息，我估计对于微软铺天盖地的谴责之声就要变成“技术发展太快”了。&lt;/p&gt;

&lt;p&gt;如果说CocoaTouch只是在iOS设备上运行，而Silverlight除了Windows Phone 7以外，之前Windows和Mac OS上该有的还有，已经在的还在。Silverlight对于微软的重要性，不会比CocoaTouch对于苹果的重要性来的差。作为一个Silverlight开发人员原本该干什么，现在还是干什么，除此之外，退可开发WPF，进可出手WP7。&lt;a href="http://player.microsoftpdc.com/Session/b3efbe56-08c0-4ea9-85ec-eb481c189abd"&gt;ScottGu在PDC上接受Scott Hanselman采访时&lt;/a&gt;说，微软将开发语言、框架、工具进行统一，让开发人员可以很自如地进入WP7的开发领域。我对WPF和Silverlight一窍不通，但我从没像现在这么羡慕您已经掌握了这部分技术（当然其实也没那么羡慕啦，我相信自己会学得很快），因为在移动互联网的大潮下，我可能以后还真要去学习WP7上的Silverlight开发，而您已经可以顺利过渡了。&lt;/p&gt;

&lt;p&gt;如果您还是对Bob的那段话表示纠结的话，其实也可以继续看看他的说法了。他和微软Silverlight团队估计也没想到，当然现在也意识到事态的严重性，于是连续发表了两篇声明，一是&lt;a href="http://team.silverlight.net/announcement/the-future-of-silverlight/"&gt;微软对Silverlight未来的担保&lt;/a&gt;，二是关于&lt;a href="http://team.silverlight.net/announcement/pdc-and-silverlight/"&gt;PDC上关于Silverlight那些表态的后续解释&lt;/a&gt;，其中写到：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I said, &amp;quot;Our Silverlight strategy and focus going forward has shifted.&amp;quot; This isn't a negative statement, but rather, it's a comment on how the industry has changed and how we're adapting our Silverlight strategy to take advantage of that. &lt;/p&gt;

  &lt;p&gt;我之前说到：“我们的Silverlight策略和前进的重心转移了”，这不是一个负面的说法，它只表示业界的现状改变了，我们调整Silverlight的策略希望可以利用这种改变。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在我看来，业界现状的表现之一，就是之前我所说的苹果不会接受Silverlight和Flash，但它对HTML 5友好。微软不强求Silverlight进入iOS——这是Bob之前所特地强调的设备——而是让Silverlight去迎合HTML 5大潮。例如，Adobe在刚刚结束的&lt;a href="http://max.adobe.com/blog/"&gt;MAX 2010&lt;/a&gt;大会上&lt;a href="http://news.csdn.net/a/20101101/281147.html"&gt;展示了一款Flash至HTML 5的转化工具&lt;/a&gt;，那么我猜想，微软今后也会这么做吗？利用Flash和Silverlight所配备的高度生产力与HTML 5相抗衡也不失为一种竞争手段。当然，谁知道呢。此外，文章里还谈到过几个月就有下一代Silverlight的消息了，不知道这能否让某些朋友松一口气。&lt;/p&gt;

&lt;p&gt;讨论和争议是好事，但是在这个过程中出现了一些声音让我很不满。例如某些同学连Silverlight与WP7的关系都不知道就来指点江山。Ivony写到过类似的意思：社区里有一些人，看着某个事物不断发展却无力接触，一遇任何风吹草动却跳出来幸灾乐祸，正如这次Silverlight事件，还有上次微软于LINQ to SQL等等。我不知道上次的那些认为微软放弃LINQ的同学，看到.NET 4.0中LINQ to SQL的更新，LINQ to Entity在&lt;a href="http://player.microsoftpdc.com/Session/68cfa011-c399-4151-ad9f-748d8723a19d"&gt;最近两届PDC中的表现&lt;/a&gt;，以及本次PDC上随Azure出现的“&lt;a href="http://player.microsoftpdc.com/Session/bfa72307-6534-41ad-bcf7-0f4fb9280515"&gt;LINQ to Azure，LINQ to Everything&lt;/a&gt;”的演讲是什么感觉。&lt;/p&gt;

&lt;p&gt;微软的技术一定是有问题的，但是我们完全可以用合适的方式来对待，受用无穷。当然，这方面内容就下次再展开了。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Silverlight与微软技术（上）：微软抛弃Silverlight了么？&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-2-microsoft-technology-and-how-to-learn.html"&gt;Silverlight与微软技术（下）：微软技术与技术学习&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/11/silverlight-and-microsoft-technology-1-is-silverlight-dead.html#comments</comments>
      <pubDate>Tue, 02 Nov 2010 05:10:48 GMT</pubDate>
      <lastBuildDate>Tue, 02 Nov 2010 05:10:48 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/news/">新闻信息</category>
      <title>关于Iron语言的近况及nBazaar交流会</title>
      <link>http://blog.zhaojie.me/2010/10/status-of-iron-languages-and-nbazaar.html</link>
      <guid>http://blog.zhaojie.me/2010/10/status-of-iron-languages-and-nbazaar.html</guid>
      <description>&lt;p&gt;最近Iron语言方面有了一些令人瞩目的动作。我们知道IronPython及IronRuby一直是由微软维护的，不过前段时间微软有消息说要“取消”这两个项目，并直接导致&lt;a href="http://blog.jimmy.schementi.com/"&gt;Jimmy Schementi&lt;/a&gt;和&lt;a href="http://hugunin.net/"&gt;Jim Hugunin&lt;/a&gt;离开微软。于是有人觉得Iron语言要死了。我倒不这么觉得，因为这两个是开源项目，是用的是Apache 2.0协议，它们会死的唯一原因便是社区放弃了它们，这和微软是不是参与维护并没有太大关系。微软固然有其影响力，但社区才是开源软件的核心。&lt;/p&gt;

&lt;p&gt;当然，有些事情还是比较可惜的，例如&lt;a href="http://www.infoq.com/cn/news/2010/10/Jim-Leaves-Microsoft"&gt;Jim Hugunin离开微软加入Google&lt;/a&gt;。Jim是个让我佩服的人，这不是因为他的技术，尽管作为Jython和IronPython之父他的技术水平有目共睹，更重要的是他能够努力维护自己作为纯粹的技术人员的理想。当时一个名为ActiveState的公司实现了一个.NET平台上的Python，但执行效率非常低下，于是他们得出的结论是“.NET不适合托管动态语言”。微软一直遭受FUD，&lt;a href="http://blog.zhaojie.me/2010/03/microsoft-technology-and-the-attitude.html"&gt;很多技术人员提到微软技术就不屑一顾&lt;/a&gt;，我可以想象这样的结论会被无数人引用，欢欣鼓舞，而情况究竟如何，谁又会关心那么多呢？而Jim Hugunin却觉得很奇怪，因为他已经通过Jython证明了动态语言在Java平台上的可行性，于是便着手开发了IronPython的原型，想研究一下CLR的问题究竟出在哪里。他原本是想写一篇“为什么CLR对于动态语言来说是个糟糕的平台”，但结果发现CLR上的Python在许多情况下比CPython要快上不少。这方面更多情况，请参考&lt;a href="http://www.codeplex.com/wikipage?ProjectName=IronPython&amp;amp;title=v1.0%20Release%20Notes"&gt;IronPython 1.0的发布信息&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;后来Jim加入了微软CLR小组，推动CLR成为一个对动态语言更加友好的执行环境，例如当年在.NET 1.0时，动态生成的代码无法被GC回收，这显然会造成内存泄漏，而在.NET 2.0里出现了DynamicMethod，.NET 3.5里出现了Expression Tree，.NET 4.0中甚至集成了DLR。可以说.NET已经成为越来越适合动态语言的执行平台。按照Jim的说法，DLR可谓是他的巅峰之作，包含了他开发IronPython总结出的大量精华，最重要的是它可以让.NET平台上的动态语言轻松地集成交互，例如在IronRuby中调用IronPython中的Python类库。&lt;/p&gt;

&lt;p&gt;更重要的是，Jim在刚加入微软的时候，花了八个月的时间和公司与律师谈判，坚持将IronPython使用MS-PL协议开源，几年后&lt;a href="http://www.opensource.org/licenses/ms-pl.html"&gt;MS-PL&lt;/a&gt;也成为了OSI认证的开源协议，可以说从那时候起IronPython、以及IronRuby和DLR成为了真正的开源项目。不过MS-PL一直没有摆脱个认知度的问题，因此后来这些项目都使用了Apache 2.0这个开源协议。&lt;/p&gt;

&lt;p&gt;在加入微软六年之后，Jim选择加入Google。从他在博客和邮件列表中的说法来看，微软对于开源项目的态度，以及社区对微软的认知度也是令他颇为苦恼的事情，用他的说法是：“开源和微软有些格格不入”，而Google在和开源社区的关系等方面便领先微软许多。对此我很能理解，因为我虽然很喜欢.NET等技术，虽然也看得到微软的进步，但也的确对微软有些做法不满，同时也很羡慕一些开源社区的氛围。我很希望自己的本职工作是为某个受人广泛使用的开源项目作贡献，但这点在国内看来是个奢望，似乎也只听说&lt;a href="http://twitter.com/bluedavy/status/26729058924"&gt;淘宝有这方面的打算&lt;/a&gt;，而其他公司，即便是开源了自己的产品，如果从认知度上面考虑还只能算是小打小闹。当然，理想终归是理想，不能强求。像我现在这样能够有20%自己支配的时间，已经可以说是相当不错的条件了。同时，理想终归是理想，在这方面我还在探索，还在寻找方向。&lt;/p&gt;

&lt;p&gt;如今微软已经&lt;a href="http://blogs.msdn.com/b/jasonz/archive/2010/10/21/new-components-and-contributors-for-ironpython-and-ironruby.aspx"&gt;放开对IronPython和IronRuby的控制&lt;/a&gt;了，这方面已经完全交给&lt;a href="http://tirania.org/blog/"&gt;Miguel de Icaza&lt;/a&gt;及&lt;a href="http://blog.jimmy.schementi.com/"&gt;Jimmy Schementi&lt;/a&gt;等人进行管理。在我看来这是好事，Miguel是Gnome和mono的创建者，可以说是.NET开源界的领军人物，对于mono及开源的发展一直有强烈的决心和信心。而mono在.NET领域也可谓是创新十足，集中了.NET平台下开源爱好者的集体智慧，在平日里给了我很大帮助。而Jimmy Schementi原本就在微软领导IronRuby的开发，在他们的带领下，我觉得&lt;a href="http://tirania.org/blog/archive/2010/Oct-22.html"&gt;IronPython和IronRuby不会停下良性发展的脚步&lt;/a&gt;，例如&lt;a href="http://www.infoq.com/cn/news/2010/10/DLR-Defunded"&gt;IronPython 2.7和IronRuby 1.9的近况&lt;/a&gt;都不错。&lt;/p&gt;

&lt;p&gt;十年前，ESR写下了著名《&lt;a href="http://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar"&gt;大教堂与集市&lt;/a&gt;》（&lt;a href="http://man.lupaworld.com/content/other/The_Cathedral_and_the_Bazaar.pdf"&gt;双语版&lt;/a&gt;），阐述了两种不同的自由软件的开发模式。“大教堂（Cathedral）”模式是指由专属团队所掌管的开发模式（如GCC），而“集市（Bazaar）”模式则是交由社区群体共同完成。这恰好对应了IronPython和IronRuby早先与现在的开发方式——尽管它们是开源软件，而不是自由软件。我欣赏集市模式，因为它够热闹，够社区化，够集体智慧，这也是国内.NET社区甚至是技术社区所缺少的东西。&lt;/p&gt;

&lt;p&gt;因此，我决定将我组织的&lt;a href="http://blog.zhaojie.me/tag/nBazaar/"&gt;.NET技术交流会&lt;/a&gt;取名为nBazaar，已经准备nBazaar.org域名，希望籍此机会让这一活动步入正轨。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/10/status-of-iron-languages-and-nbazaar.html#comments</comments>
      <pubDate>Mon, 25 Oct 2010 12:26:48 GMT</pubDate>
      <lastBuildDate>Mon, 25 Oct 2010 12:26:48 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>Why Java Sucks and C# Rocks（补1）：Reddit，兼谈C#属性</title>
      <link>http://blog.zhaojie.me/2010/06/more-why-java-sucks-and-csharp-rocks-1-reddit-and-property.html</link>
      <guid>http://blog.zhaojie.me/2010/06/more-why-java-sucks-and-csharp-rocks-1-reddit-and-property.html</guid>
      <description>&lt;p&gt;最近博客冷清了不少，主要是事情较多，一是&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;.NET交流会&lt;/a&gt;，二是工作，三是几篇暂时无法发在博客上的文章。周末在家，发现邮箱里经常收到&lt;a href="http://www.slideshare.net/"&gt;SlideShare&lt;/a&gt;的邮件，说是我的&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html"&gt;Why Java Suck and C# Rocks幻灯片&lt;/a&gt;在推特上很火热。而今天早上我忽然发现，&lt;a href="http://www.reddit.com/r/programming/comments/cjhzk/why_java_sucks_and_c_rocks_final/"&gt;它被人发到Reddit的编程版块了&lt;/a&gt;，讨论地颇为热烈。关于讨论内容，您可以亲自阅读一下。最近的讨论也让我想要补充一些关于C#属性的问题。&lt;/p&gt;

&lt;p&gt;关于这个话题，在我&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html"&gt;不断强调讨论的目的&lt;/a&gt;之后，在我的博客上还是有许多朋友没有明白我在说什么，热血上涌当即给予反击，这些从后面的评价中便可以看出。不过在Reddit上，当围观人群看到相同的内容，甚至&lt;a href="http://www.slideshare.net/jeffz/why-java-sucks-and-c-rocks-final"&gt;只有幻灯片&lt;/a&gt;，没有更多解释说明，但是大家都能理解我的意思，都能意识到我是希望“用Scala代替Java语言”。而即便是没有看到幻灯片的最后，或是对此有不同意见，也都是在用正常的方式提出质疑。这样的差别让我感到很讽刺，有些话我已经说过很多次了，现在只是引一个例证，也就不再重复了。&lt;/p&gt;

&lt;p&gt;在Reddit上的讨论中，有人提出C#里的属性和事件其实都只是方法的语法糖，意义不大。最近在一些人的文章里也出现了类似的说法。我在这个系列的中原本并不打算着重分析C#里的“属性”概念，因为它对于“编程思维”的影响可能并不如其他方面来的明显。不过如果真要深究的话，我还是非常看重这个语言特性的（不过其实属性和事件都是.NET特性）。那么现在我也来简单谈一下“属性”，而“事件”则在后面的文章里讨论吧——那篇文章的草稿已经躺了大半个月了。&lt;/p&gt;

&lt;p&gt;属性，在C#里以get/set方法对的形式出现，例如：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// C#&lt;/span&gt;
&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MyClass
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private int &lt;/span&gt;m_count;
    &lt;span style="color: blue"&gt;public int &lt;/span&gt;Count
    {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return this&lt;/span&gt;.m_count; }
        &lt;span style="color: blue"&gt;set &lt;/span&gt;{ &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_count = &lt;span style="color: blue"&gt;value&lt;/span&gt;; }
    }
}&lt;/pre&gt;

&lt;p&gt;而在Java中的等价代码则是：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Java&lt;/span&gt;
&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MyClass&lt;/span&gt;
{
    &lt;span style="color: blue"&gt;private int &lt;/span&gt;m_count;
    &lt;span style="color: blue"&gt;public int &lt;/span&gt;getCount() { &lt;span style="color: blue"&gt;return this&lt;/span&gt;.m_count; }
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;setCount(&lt;span style="color: blue"&gt;int &lt;/span&gt;value) { &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_count = value; }
}&lt;/pre&gt;

&lt;p&gt;在Java中并非没有“属性”的概念，而是将它直接拆成了getXxx和setXxx两个方法而已，而对于一些工具（如IDE）、框架（如序列化框架）来说，它会忽略方法之前的get/set，直接将后面的字符识别为一种“成员字段”，而在.NET对象中，“属性”天生就是一种表示成员字段的标准方案。&lt;/p&gt;

&lt;p&gt;在我看来，从使用上来说，属性比分离的方法要方便一些。例如我们要将MyClass对象的Count属性加1，则可以这么写：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// C#&lt;/span&gt;
c.Count++;&lt;/pre&gt;

&lt;p&gt;而在Java里则必须这样：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Java&lt;/span&gt;
c.setCount(c.getCount() + 1);&lt;/pre&gt;

&lt;p&gt;当然您可能会觉得这方面的差距并不大。那么我们换一个场景，现在有一个User数组，我们要根据它的年龄进行排序：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// C#&lt;/span&gt;
users.Sort(u =&amp;gt; u.Age);

&lt;span style="color: green"&gt;// Java&lt;/span&gt;
users.sort(#(&lt;span style="color: #2b91af"&gt;User&lt;/span&gt; u)(u.getAge()));&lt;/pre&gt;

&lt;p&gt;这里我们暂且忽略Java中古怪的Lambda表达式写法，只关注“属性”和“get方法”之间的区别。在我看来，C#的代码体现了声明式编程的理念，从语义上讲可以清晰地视为“将u按u.Age字段”排序；与之想法，一旦我们只能利用getAge方法时，便又重新回到了“命令式”思维方式上。为什么这么说？因为调用getAge方法，意味着“获取”这个“Age”字段，它代表的是一个“动作”，表明排序时去“获取”这样一个数值，也就是体现了“怎么做（how to do）”，而不像C#代码中体现的是“做什么（what to do）”。&lt;/p&gt;

&lt;p&gt;下面一个例子可能更为典型。例如在使用ORM框架，如(N)Hibernate时，我们时常会在复杂的XML配置中迷失方向。后来有了Fluent NHibernate，让我们可以使用“代码”来进行配置，这样无论是从可读性还是可维护性来说都有了质的飞跃。目前在项目中，由于没有使用关系型数据库，于是我便遵循Fluent Interface的理念，设计了这样的API：&lt;/p&gt;

&lt;pre class="code"&gt;Property(c =&amp;gt; c.ArticleID).Identity();
Property(c =&amp;gt; c.Content).Name(&lt;span style="color: #a31515"&gt;&amp;quot;Html&amp;quot;&lt;/span&gt;);
Property(c =&amp;gt; c.Tags);
Property(c =&amp;gt; c.Keywords).ChangeWith(c =&amp;gt; c.Content).ChangeWith(c =&amp;gt; c.Tags);&lt;/pre&gt;

&lt;p&gt;以上代码是Article对象的映射规则，四行代码表明：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;将ArticleID映射为标识符 &lt;/li&gt;

  &lt;li&gt;将Content映射为存储中的Html字段。 &lt;/li&gt;

  &lt;li&gt;将Tags映射至存储，名称不变。 &lt;/li&gt;

  &lt;li&gt;将Keywords字段映射至存储中，并随Content及Tags字段改变。 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我写的映射框架支持传统ORM框架的状态跟踪功能，不过还提供了只读字段的“按需改变”。如Keywords，它是只读属性，框架会读取它的值，并将其放入存储内（以便进行查询），但是我们不需要将其写回对象中去。同时，在Contents和Tags改变的时候，框架也会重新获取Keywords的值，并跟新至存储内。利用C#的表达式树特性，我们可以十分轻松愉快地“声明”出这样的规则。在这个规则中，我们利用“属性”来标明字段之间的关系，这可以说是一种DSL。但如果没有属性，一切都是get方法，那么这段代码又会是什么样子呢？&lt;/p&gt;

&lt;p&gt;所以，相对C#来说Java语言中很难写出优雅的声明式代码及Fluent NHibernate这样的框架。原因有多种，如Lambda的古怪语法形式是为一、缺少表达式树功能是为二，而不直接支持“属性”这样的概念也是另一个原因吧。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html"&gt;演讲预告：Why Java Sucks and C# Rocks&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html"&gt;幻灯片：Why Java Sucks and C# Rocks&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html"&gt;Why Java Sucks and C# Rocks（1）：比较的意义与目的&lt;/a&gt;&lt;span style="color:red;"&gt;（重要）&lt;/span&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-2-primitive-types-and-object-orientation.html"&gt;Why Java Sucks and C# Rocks（2）：基础类型与对象&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-3-attribute-and-annotation.html"&gt;Why Java Sucks and C# Rocks（3）：Attribute与Annotation&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/05/why-java-sucks-and-csharp-rocks-4-generics.html"&gt;Why Java Sucks and C# Rocks（4）：泛型&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;Why Java Sucks and C# Rocks（补1）：Reddit，兼谈C#属性&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/06/more-why-java-sucks-and-csharp-rocks-1-reddit-and-property.html#comments</comments>
      <pubDate>Mon, 28 Jun 2010 06:18:19 GMT</pubDate>
      <lastBuildDate>Mon, 28 Jun 2010 06:18:19 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>讨论？讨论你妹啊！</title>
      <link>http://blog.zhaojie.me/2010/06/no-room-for-discussion.html</link>
      <guid>http://blog.zhaojie.me/2010/06/no-room-for-discussion.html</guid>
      <description>&lt;p&gt;无论是针对什么东西的讨论，或是争论也好，最重要的便是观点明确，论据清晰，这样大家也可以有针对性进行回复或是反驳。但如果&lt;a href="http://www.cnblogs.com/firelong/archive/2010/06/22/1762376.html"&gt;观点和论据不配套，处处呓语，动辄“因为A所以一定是B”的非逻辑性判断&lt;/a&gt;，这又让人如何应对？我遇到许多争论，虽然明显是错的，但从头到尾却不知道如何入口，这往往会让我很无奈，寻思几遍只能作罢。&lt;/p&gt;

&lt;p&gt;此外讨论中还经常出现一些对人不对事的论调，比如&lt;a href="http://www.cnblogs.com/firelong/archive/2010/06/20/1761357.html"&gt;有些人会说&lt;/a&gt;：“北大青鸟出来的吧”，“你这个码工”。北大青鸟出来的又如何，码工又如何？就算我，也只是反对北大青鸟，而不是北大青鸟出来的人。一个说法，无论出自谁之口，是不影响它的正确性的。有效的讨论，就应该只针对问题，不针对人。我支持语言激烈的讨论，但是语言激烈的前提还是对事不对人。我不愿意参与暴烈又缺少内容的讨论，但如果&lt;a href="http://www.cnblogs.com/firelong/archive/2010/06/22/1762376.html"&gt;有时候一件事情直接扣我脑袋上&lt;/a&gt;，逼我进退维谷，我总归还是会郁闷的。&lt;/p&gt;

&lt;p&gt;不知道以后会慢慢习惯么？&lt;/p&gt;

&lt;p&gt;最后可能还要说些不好听的，朋友们别在意。俗话说：不怕神一般的对手，只怕猪一般的队友，这话的确没错。小弟不才，可能是做了些小事让大家得到了一些收获，因此许多朋友都对我表示支持。但是我时常发现，有些朋友的支持让我哭笑不得。例如没有看清楚我的结论就表示同意，甚至某些时候同意的还是我反对的看法。有些时候观点和我相同，但是给出的论据确是漏洞百出。要知道即便是正确的结论，也需要用正确的道理才能说服别人，否则我在阐述自己说法的时候，还得帮您修补漏洞，甚至如果您把话题引偏了，那我该怎么做比较好？&lt;/p&gt;

&lt;p&gt;所以你会发现，如果&lt;a href="http://blog.zhaojie.me/2010/06/is-cross-platform-a-lie-or-not.html"&gt;遇上一些关于.NET和Java比较的话题&lt;/a&gt;，我往往就会在两边跳来跳去，谁都打几巴掌，因为这方面的比较时往往错误的说法满天飞。我不关心谁输谁赢，我只关心事实本身如何。&lt;/p&gt;

&lt;p&gt;最后再说一下博客园吧，在话题引导方面做的实在不好，就刚才又建了个专题叫做“&lt;a href="http://www.cnblogs.com/topic/53/"&gt;编程语言之争&lt;/a&gt;”，点进去一看发现没有一篇是在进行靠谱的讨论（似乎现在终于有了）。我喜欢讨论编程语言，是因为我不像许多人认为的那样，说“编程语言意义不大”，但是也并不希望产生这样的争论好不好？这样争论下去，我也觉得意义不大了。&lt;/p&gt;

&lt;p&gt;还是类似的道理：我不希望您来表态支持“编程语言争论”，我希望的是您来开展一场有价值的争论。否则我嘴上不说，心里还是会把您归为猪一样的队友的。&lt;/p&gt;

&lt;p&gt;我也不想这样。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/06/no-room-for-discussion.html#comments</comments>
      <pubDate>Tue, 22 Jun 2010 04:50:48 GMT</pubDate>
      <lastBuildDate>Tue, 22 Jun 2010 04:50:48 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>跨平台到底是不是谎言？</title>
      <link>http://blog.zhaojie.me/2010/06/is-cross-platform-a-lie-or-not.html</link>
      <guid>http://blog.zhaojie.me/2010/06/is-cross-platform-a-lie-or-not.html</guid>
      <description>&lt;p&gt;前几天是个神奇的日子，博客园里咣咣咣地出现了三篇文章，都包含了“跨平台”和“谎言”这两个关键字。从&lt;a href="http://www.cnblogs.com/hack/archive/2010/05/30/1747513.html"&gt;Java&lt;/a&gt;开始谈到&lt;a href="http://www.cnblogs.com/Nobel/archive/2010/05/30/1747701.html"&gt;.NET&lt;/a&gt;，最后哐地一下，&lt;a href="http://www.cnblogs.com/happycharles/archive/2010/05/30/1747740.html"&gt;“跨平台”本身也变成一种谎言&lt;/a&gt;了。从文章内容上看，我个人觉得基本不靠谱，主要论述方式是用“气势”或是“自信”来压倒对方……呃，是“说服别人”。我不打算谈那两篇文章的内容了，许多意见我和其他人也在文章后面回复过了。我现在只想在这里简单谈谈我对“跨平台”这个问题的看法。&lt;/p&gt;

&lt;p&gt;关于“跨平台”这个问题，我感觉还是要分“客户端”和“服务器端”两个方面来谈，或者说“表现层”或“服务层”，或者说“带界面的”和“跑服务的”……总之您明白就好。当然无论拿方面都还是要再细说的。&lt;/p&gt;

&lt;p&gt;说到客户端程序，譬如说是一个桌面应用，那么它的跨平台也是很尴尬的东西。就说UI吧，你说不靠谱，它的确能用；但如果你说它挺好，它从视觉效果，使用体验，样式风格方面，都会和周围环境有些格格不入的感觉，无论是&lt;a href="http://java.sun.com/docs/books/tutorial/uiswing/"&gt;Swing&lt;/a&gt;，&lt;a href="http://www.gtk.org/"&gt;GTK&lt;/a&gt;还是&lt;a href="http://qt.nokia.com/products/"&gt;QT&lt;/a&gt;，跨平台的UI库都有这个问题。其实这也十分容易理解，一个跨平台的UI库，它的确可以做到在不同平台上出现相同的样式或风格。但是，不同的平台，如Windows，Linux或是Mac，它们的桌面环境都有着非常明显的区别。而即便是XP和Vista，Gnome或KDE，再加上各个参数细节的定制，想要在单一平台上做出合适的界面都是不太容易的事情，更何况跨平台。而且，即便一个界面的Look与周围环境一样了，那还有Feel这个说不清道不明的东西。水果公司为了保证界面美观，还提出了详细的“&lt;a href="http://developer.apple.com/mac/library/documentation/userexperience/conceptual/applehiguidelines/XHIGIntro/XHIGIntro.html"&gt;用户界面规范&lt;/a&gt;”，您说这让跨平台的UI库情何以堪？&lt;/p&gt;

&lt;p&gt;当然，这方面还可以往细了说。例如，我觉得从某些小处来讲，跨平台的UI库还是很有市场的。比如说Silverlight或Flash，它们的应用场景一般是网页中的一小部分，关注的可能是一个“页面”而不是系统应用的体验。再往大了里说，例如您在做一个游戏，那么选择OpenGL就比DirectX更容易移植到各个平台上去（如果拿Silverlight或Flash做独立的RIA也可以算做这种情况）。在这些情况下，我觉得跨平台的UI库是很有意义的，但它们也有个特点，那就是对系统环境Look &amp;amp; Feel的依赖很小，它们的界面自成一体，更像是从一个空白的画布上自己重新造轮子的情况。对它们来说，“老子本来就不需要来迎合你”，那还有什么可担心的呢？&lt;/p&gt;

&lt;p&gt;因此我对这方面的质疑，说的更具体些，可能应该是那些“带窗体的、组件形式的可复用的UI库”吧。&lt;/p&gt;

&lt;p&gt;那么服务器端是不是就没问题了呢？反正看不到。不过我倒感觉正好相反：客户端跨平台主要问题是感官上的，对我这种非艺术家来说忍忍便罢，而服务器端的问题在我看来就是“叔可忍，婶不可忍”了。说到服务器端跑的程序，总是给人一种高性能，高可用性啊，高稳定性的感觉，总而言之对运行效果的要求很高。那么，跨平台的服务器运行机制，能否做到在各个平台上都用最佳状态工作呢？&lt;/p&gt;

&lt;p&gt;这并不容易，因为如果要提供最高质量的服务，往往都需要利用到平台自身的特性。即便是CPU密集型应用理论上也会受到操作系统的虚拟内存管理机制的影响——更别说网络通信等IO密集型应用了。举个例子吧，&lt;a href="http://nginx.org/"&gt;Nginx&lt;/a&gt;是个高性能的Web服务器，主要跑在*nix环境下，也可以运行在Windows下（是直接使用Win32 API开发的，不是利用Cygwin做中间层的方法）。这看上去做到了跨平台，但是说到细节的话，Nginx在*nix下面用了高效的&lt;a href="http://linux.die.net/man/4/epoll"&gt;epoll&lt;/a&gt;或&lt;a href="http://people.freebsd.org/~jlemon/kqueue_slides/index.html"&gt;kqueue&lt;/a&gt;，而在Windows下使用的便是低效的select了。同样，&lt;a href="http://jetty.codehaus.org/jetty/"&gt;Jetty&lt;/a&gt;，&lt;a href="http://mina.apache.org/"&gt;Mina&lt;/a&gt;等框架所依赖的nio，在Java 6中已经开始使用epoll，而对Windows下IOCP的支持，&lt;a href="http://blogs.sun.com/alanb/resource/bof0895.pdf"&gt;只能等到尚未发布的Java 7&lt;/a&gt;了。要知道IOCP作为一种与epoll类似的基于事件的IO机制，早在NT 3.5 / Windows 2000就出现了，而Java 6诞生于2006年底，我相信“时间”不是问题。&lt;/p&gt;

&lt;p&gt;所以问题就来了，在我看来“跨平台”不仅仅是“能够运行”的意思，运行的好不好也是十分重要的一点。前一段时间水果教主&lt;a href="http://www.apple.com/hotnews/thoughts-on-flash/"&gt;对Flash的指责&lt;/a&gt;得到了果粉们的一致拥护，许多人还补充了更多理由，其中一点便是“Flash对Mac的支持很不好，虽然能运行但是资源消耗严重”（事实的确如此），接下来就是说Flash目前的处境是自找的等等，不提。那么，比如Nginx和Mina，它们在*nix下表现良好，而跑到Windows下面如并发能力就大大折扣了，这又算是谁的问题呢？与Flash问题的看法相同，我不认为这是Windows或Mac OS的问题，问题出在跨平台的机制上。&lt;/p&gt;

&lt;p&gt;但我也不会去责怪Nginx和Java（但我会去XX那些因此认为Windows性能差的说法），因为跨平台本来就是很不容易的事情。有时候，即使两个平台都提供了高性能的编程模型，但是它们的编程模型不同，很难用相同的模型进行统一，而强制统一带来的折衷效果可能就变成“都不是最佳”。而且即便“能够”做到在多个平台上实现最好的性能，也需要我们去投入更多的分散的精力——那么，如果我们把这些精力放在对单一平台的努力优化上面呢？因此，我也很能理解如&lt;a href="http://code.google.com/p/go/"&gt;Go语言&lt;/a&gt;不支持Windows的情况，用来做服务器的语言么，只支持单一平台也无可厚非。&lt;/p&gt;

&lt;p&gt;而且说实话，我也并不是很看中“跨平台”这一点。有些人说Java比.NET好的理由是，Java能跨平台，而Linux比Windows既XX，又YY，还不要钱。但事实上，那些朋友看中的是“Java能运行在Linux上”而不是“Java能跨平台”。而即便Java只能运行在Linux上，对他们来说也就够了。对于一个正经的应用，您会动辄迁移它的运行平台吗？就我许多年前写Java的微薄经验来说，就见到过一次把应用服务器从Websphere迁移到WebLogic而导致问题不断的情况。完美的基于标准的（这是跨平台的必要条件）实现只能存在于理想之中，想想浏览器就能理解这点了。同理，我中意&lt;a href="http://www.mono-project.com/Main_Page"&gt;mono&lt;/a&gt;，也不会强求它多么多么追求与MS .NET实现一致，我对它的期望只是个足够好的.NET运行环境就行了（当然也不能跨得太差了）。&lt;/p&gt;

&lt;p&gt;顺便插一句，我上面的说法可以得到一个推论：对于一个服务器应用来说，程序员在工作时的运行/调试环境要尽可能与生产环境相符。例如一个在Windows下运行调试的Java程序，但生产环境下却是部署在Linux下的做法我就感觉不靠谱。如果真因为条件限制，至少&lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;持续集成&lt;/a&gt;时的环境要和生产环境尽可能一致吧？同样的情况还有在Windows XP上开发ASP.NET应用程序的人，在我眼中这就是无比山寨的做法，甚至我认为对此没有怨言的程序员也是相当不专业的。&lt;/p&gt;

&lt;p&gt;这样看来，不知道是否有朋友会认为我觉得“跨平台是谎言”——我可没这么说。我常干的事情（例如就是这次的“谎言”事件），便是跳到某个针锋相对的场景，比如.NET vs Java，左边扯扯右边拉拉，谈点楼主的问题，也反对一些楼主反对方的看法，所以千万不要以为我反对您的（部分）说法就是在赞同您的对手的（反之亦然）——总之，千万要仔细理解我的意思才好。事实上，虽然我指出了跨平台的一些问题，也可以理解“不跨平台”的做法，但是我同样认为，无论是.NET，Java在二进制层面上，还是如C++，C语言（也包括如PHP，JavaScript等）在语言层面上的跨平台，都是有足够优秀的案例，或者说是实现的。而各种跨平台的机制本身，也可以显著减少程序员对于平台的依赖，也大大简化了开发跨平台应用程序的难度。&lt;/p&gt;

&lt;p&gt;总而言之，我认为跨平台不是谎言，它是成功的，也是必要的，虽然有缺点，但还是值得努力的——就是这样。&lt;/p&gt;

&lt;p&gt;此外，文章里的“平台”大都是指“操作系统”，但事实上“平台”这个概念远大于此，比如CPU体系结构，浏览器等等都算是平台——因此，其实我的意愿是您可以用一种“泛化”的方式来理解文章的意思。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/06/is-cross-platform-a-lie-or-not.html#comments</comments>
      <pubDate>Wed, 02 Jun 2010 03:05:57 GMT</pubDate>
      <lastBuildDate>Wed, 02 Jun 2010 03:05:57 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>随便说说邮件列表那点事儿</title>
      <link>http://blog.zhaojie.me/2010/05/things-about-mail-list.html</link>
      <guid>http://blog.zhaojie.me/2010/05/things-about-mail-list.html</guid>
      <description>&lt;p&gt;这两天推特上在讨论RT方式与时间线干扰的问题，主要是有人抱怨官方的RT，或是民间的RT，还是所谓RT式回复的方式会污染追随者的时间线。对此有朋友应对到，如果感到“信息过载”，应该寻找合适的工具来进行管理（例如几个同事便设法实现一个&lt;a href="http://code.google.com/p/tinytui2/"&gt;带自动过滤机制的客户端&lt;/a&gt;）。我没有参与这个问题的讨论，因为我本身其实还没有搞清各种RT方式分别是指什么，而且我也没有混乱的感觉──要知道我才fo了不到300人，如&lt;a href="http://twitter.com/xiaolai"&gt;笑来老师&lt;/a&gt;fo了超过一万五千人还处理的井井有条，和他相比我算什么嘛。&lt;/p&gt;

&lt;p&gt;不过&lt;a href="http://twitter.com/virushuo"&gt;霍炬&lt;/a&gt;刚才&lt;a href="http://twitter.com/virushuo/status/14697792885"&gt;举了一个例子&lt;/a&gt;说：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;前几天，我们公司有人投诉，说在群发全体邮件中讨论问题干扰了他的工作。听起来很有道理，直到&lt;a href="http://twitter.com/haxy"&gt;@haxy&lt;/a&gt;说，应该好好使用工具，任何邮件客户端都能帮助你做过滤。大家立刻接受了这个观点。对于RT问题，一样，如果你觉得被干扰了，请寻找更好的工具。 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;本来今晚我是想写篇技术文章的，不过写着写着没激情了，也没写完，于是就稍微谈谈邮件列表那点事儿吧。&lt;/p&gt;

&lt;p&gt;这事儿说得细一些也无妨，主要是一封发给&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;所有员工的邮件，说的自然是工作上的正事儿，不过后来引发了讨论，再加上人人都reply all，自然邮件数量就哗啦啦地增加了，于是就有人抱怨说影响工作──其实我觉得还不算太热烈，而且毕竟是正事儿有关的讨论，不是灌水。不过，的确也出现过在全体员工的邮件列表中讨论动画片或是电影的情况，这与理就不太合适了。 &lt;/p&gt;

&lt;p&gt;但这其实怪不得个人，因为这实在是因为缺少一个好的邮件列表管理机制引起的。试想，为什么会在全体员工的邮件列表中讨论动画片？就是因为没有一个独立的邮件列表可用嘛。 &lt;/p&gt;

&lt;p&gt;我是个邮件列表爱好者，这是当年在微软混饭时养成的习惯。我一直说，微软最让我怀念的地方便是内部的邮件列表。每个人都能挑选自己感兴趣的列表订阅，仅仅是浏览也好，参与讨论也罢，时不时还能看到传说中的大牛发言，对自己的帮助很大。而创新院在这方面和微软有很大差距。 &lt;/p&gt;

&lt;p&gt;就拿微软来说吧，每个人都可以去申请一个邮件列表，无需审核，任何主题都行，由你来定。比如您可以创建一个“黑丝同好会”列表，然后宣传一下，等人来加入。待这样一种邮件列表机制普及开来之后，还有谁会在allstuff@microsoft.com这样的邮件列表中讨论问题呢？ &lt;/p&gt;

&lt;p&gt;有针对性的邮件列表对于邮件的管理也很有帮助。例如，我们可以在邮件客户端中定制规则，来自“黑丝同好会”的邮件都被自动转移到“黑丝”目录中去，然后我们便可以在夜深人静时“悄悄的干活，打枪的不要”。如果所有邮件都来自同一个邮件列表，那又该如何管理呢？自然我们可以设定关键字，但谁都知道关键字的方案其实是不太靠谱的，说不定什么时候“黑丝”就匹配到“黑夜里的一丝光明”。我们当然也不能把规则定义在大范围的邮件列表上……小心类似“部门集体裁员”这样的重要消息你都不小心就漏过了。 &lt;/p&gt;

&lt;p&gt;在我看来，邮件文化、邮件规范等道貌岸然的东西，其实还是相当重要的。当然这话题说了就大了。 &lt;/p&gt;

&lt;p&gt;当然，如果从个人角度说，我们完全让自己不被邮件打扰到。例如，您可以关闭邮件提醒，每天稍微检查几下邮件即可。像我一般也就是早上刚到公司，吃饭前后，下班前，再有上午一次下午两次检查就差不多了。而周末甚至都不太会检查个人邮箱，上周日还因此错过别人请客吃饭。其实邮件本来就是一种“异步”的通信方式，您在半小时内回复还是三小时后再回复其实也差不了太多。如果有人真有急事找您，不还有IM或是电话么？&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/05/things-about-mail-list.html#comments</comments>
      <pubDate>Tue, 25 May 2010 16:26:08 GMT</pubDate>
      <lastBuildDate>Tue, 25 May 2010 16:26:08 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/architecture/">架构设计</category>
      <title>2010年5月《程序员》杂志“架构师接龙”栏目中的问答</title>
      <link>http://blog.zhaojie.me/2010/05/programmer-magazine-2010-5-architect.html</link>
      <guid>http://blog.zhaojie.me/2010/05/programmer-magazine-2010-5-architect.html</guid>
      <description>&lt;p&gt;上个月《程序员》杂志向我约稿，希望我可以参加5月份的“架构师接龙”栏目，我略为犹豫了一下便答应了。“架构师接龙”是一个问答形式的栏目，每期由一个人提问，并由另一个人回答。回答的一方便是下期的提问者。这次提问的架构师是&lt;a href="http://t.sina.com.cn/"&gt;新浪微博&lt;/a&gt;的技术经理&lt;a href="http://timyang.net/"&gt;杨卫华&lt;/a&gt;。他提出的问题包括语言选择与架构设计、NoSQL存储方案的取舍、微博类系统的架构等多个方面。杨卫华是国内技术社区一等一的高手，这使得我在回答问题时更有小心翼翼地班门弄斧之感。如果您对某些问题感兴趣，也不妨来一起讨论一下。&lt;/p&gt;

&lt;h1&gt;语言选择与架构设计&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;很多架构师表示编程语言不重要，架构设计思想才重要，但是大部分团队都是非常依赖某种语言的，甚至很多项目负责人也存在对某种语言存在偏好而对另外一种语言反感的现象。你怎么看待编程语言选型问题？同时业界也存在另外一种现象，很多前沿技术研究者对一些新兴语言如Erlang, Go等表示出狂热，你对团队或项目中是否引入这些新的语言持什么观点？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;回答：&lt;/strong&gt;在我看来，编程语言的选择也是至关重要的。诚然，架构的设计思想可谓直接决定了系统本身的质量。与此相反，从理论上说，只要是图灵完备的语言，就不存在“能力”上的根本差异，任何工作都是可以实现的。但是，有一点也无法被忽视，那便是我们使用的语言，往往也会影响，甚至决定了我们的思维方式。 &lt;/p&gt;

&lt;p&gt;举个有些极端的例子，如果人们还在使用汇编语言进行开发，那么估计程序员的思维永远无法跳出“子过程”这个抽象级别，什么面向对象设计，函数式编程几乎无从谈起。人们在生产和学习过程种会引发一些需求，因而需要产生一些工具来辅助学习和生产，而“语言”便是此类工具之一。只有利用高级语言，人们才能有效地把真实世界抽象成计算机这些机器盒子能认识的东西。 &lt;/p&gt;

&lt;p&gt;如今，可用于构建项目可选的主流语言往往都会有多种，有时候的确会发现，好像不同的语言──例如Ruby和Python──从各方面来说并没有太大区别。这其实也是比较正常的，因为某些（甚至是大部分的）语言特性，并没有对我们的“思维”产生影响。 &lt;/p&gt;

&lt;p&gt;举例来说，某些喜欢Ruby的朋友认为Ruby语言的编程体验非常良好，好比它的数组操作可以直接做加法或减法： &lt;/p&gt;

&lt;pre class="code"&gt;array = ['aaa', 'bbb', 'ccc'] - ['ccc', 'ddd'] &lt;/pre&gt;

&lt;p&gt;或者说，在Python里交换两个变量的值也只需要一行代码（大部分语言中可能需要借助中间变量）： &lt;/p&gt;

&lt;pre class="code"&gt;a, b = b, a &lt;/pre&gt;

&lt;p&gt;但是，就我个人观点来说，这些语言特性，虽然它们的确可以让编程工作变的相对轻松一些，例如可以让我们少些一点代码，但终究没有改变，或是表现出另一种编程思维。这样的语法特性，一般来说都可以通过构建一些简单的辅助函数来做到类似程度的“简化开发”（如上面Ruby的例子），对于那些非“即写即抛”的程序来说，这些特性的优势并不明显。 &lt;/p&gt;

&lt;p&gt;而与此相比，Ruby的Mixin机制和Python的Decorator就不仅仅是“语法糖”，而是比较重要的语言特性了，因为它们可以带来或大大简化某些十分有用的编程模式。 &lt;/p&gt;

&lt;p&gt;不过对于语言的选择有时候还需要往更高处看。现今一些新出现，或者新流行起来语言，对于系统开发方面的影响则更为深远。举个例子，目前说起并发/并行程序设计，无法忽略的便是Erlang语言。这门语言提供了一种构建轻量级计算单元（在Erlang中被称为“进程”），使用发送消息（Message Passing）的方式进行相互间的通信。这种做法避免了共享状态（Shared State）方式下容易出现的各种问题，并且在其独特的虚拟机实现下可以得到很强大的并发能力。但是，Erlang的任务调度机制有个特点，那便是它会为每个“进程”分配相同的计算能力。这样，如果系统中有1000个进程，那么每个进程得到的计算能力便会是100个进程时的十分之一。这种调度方式对于某些类型的应用来说可能并不合适，因为它可能在并发压力增大的情况下，造成吞吐量的降低甚至完全停止服务（因为每个任务都超时了）。Erlang的这个特性往往会直接影响到系统的架构方式。 &lt;/p&gt;

&lt;p&gt;不过在某些场景下，我们也可以选用其他的语言。例如Scala，它同样提供了基于Actor模型的消息传递并发机制。但是它的调度方式与Erlang不同（事实上由于平台功能限制，它也无法实现Erlang的调度方式）。由于Scala的Actor模型构建与JVM之上，因此它只能准备一个线程池，让其中的线程不断地处理消息的传递及处理任务，而额外的任务则会在队列中等待。因此，Scala使用的并不是Erlang那样完全公平的调度方式，但是这样反而可以优先处理先出现的任务，保证稳定的吞吐量。 &lt;/p&gt;

&lt;p&gt;因此，Erlang和Scala这两种不同的调度机制，决定了它们适合不同的应用场景，或是系统架构的不同方式。我相信Facebook选用Erlang构建聊天平台，Twitter选用Scala构建消息中间件都是有这方面考虑的。 &lt;/p&gt;

&lt;p&gt;当然，调度方式更像是由平台决定，而不是语言决定的。不过在刚才的特定问题上我认为两者其实是统一的。因为Erlang既是门语言，也代表了一个平台。而Scala虽然是JVM平台上众多语言之一，但也只有它能够优雅的实现Actor模型的消息传送机制。我始终认为，一个语言特性只有真正“好用”，它才能被人们广为接受。例如，使用Java语言能实现Actor模型吗？能，但是它缺少Scala那样灵活的函数式语法，以及模式匹配等特性，因此无法构建出一个好用、易用的Actor框架，自然也就无人问津了。这其实也是“语言影响思维方式”的典型案例之一。 &lt;/p&gt;

&lt;p&gt;异步及并行是如今系统构建不可或缺的因素。如今的新语言大都在这方面下了很大功夫。除了Scala和Erlang以外，在微软.NET平台上的新语言F#引入的创新特性“计算表达式（Computation Expression）”，使用类似于Monad的机制大幅度简化了异步程序的开发难度。而JVM中的Clojure语言也引入了软件事务内存（STM，Software Transactional Memory）。我们几乎可以这么说，如今每种新出现的语言都有独特的“杀手级”特性，它们都是影响系统开发的重要因素，使用语言本身的支持可以显著降低系统的开发难度，增加可维护性和健壮性，这些并非是由架构改进可以轻松获得的效果。 &lt;/p&gt;

&lt;p&gt;如今“多语言”开发逐渐成为一种趋势，例如在Facebook的各个子系统分别使用了C、C++，Erlang，Java等多种语言/平台，然后使用PHP作为黏合剂连接起来。而Twitter也毫不例外地使用了Ruby，C，Scala和Java。现在的系统日趋复杂，几乎没有任意一种工具可以完全适合系统的全部开发，为系统不同的组成部分选择合适的语言，也是如今架构师需要面临的挑战。 &lt;/p&gt;

&lt;p&gt;与过去不同，现在即使确定构建系统所用的平台之后──如JVM，也会发现语言的选择余地会有很多，不同的语言的确也有不同的特性，可以带来一些特别的优势。例如，利用Ruby的动态特性，便可以方便地进行单元测试。而系统的生产部分代码，可能便可以选用Scala等静态编译型语言，以便借助更完整的静态检查工具来确保更加稳固的产品质量。 &lt;/p&gt;

&lt;p&gt;对于新语言的选取，不同风格的架构师会采取不同的策略。例如保守的架构师可能会根据语言所在社区是否活跃，语言相关资源是否丰富，相应的程序员是否容易招聘来考虑语言或平台的选择。这种做法是十分正常的。但是万事都讲究个平衡，在某些情况下“保守”和“抱残守缺”或“固步自封”之间仅一步之遥。 &lt;/p&gt;

&lt;p&gt;我个人的风格相对比较“激进”，十分乐于吸收和尝试一些新事物。我的建议是，每个技术团队都应该挑选出几个技术水平较高，经验较为丰富的成员，广泛的吸收新事物的发展，并在合适的时候向团队及生产环境做出提案，以改进系统的开发效率或者质量。由这些高级技术人员进行引导，往往可以较好的预估新技术对于产品的影响，即便出现了一些问题也可以设法自行解决。 &lt;/p&gt;

&lt;p&gt;据我了解，一些较为活跃的技术团队，尤其是一些Web 2.0产品的技术团队，在这方面都有比较好的实践。&lt;/p&gt;

&lt;h1&gt;NoSQL存储方案的选型&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;最近很多公司有向NoSQL方向发展趋势，很多架构师也关心是否需要将关系数据库转向NoSQL，请问能给正在选型的架构师哪些建议？ &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;回答：&lt;/strong&gt;我的个人看法是，NoSQL本身是好东西，但是在使用的氛围方面稍有一些扭曲。可能是受到关系型存储方式的“压抑”太久，如今冒出一个NoSQL运动让人眼前一亮，不由得热血沸腾起来。 &lt;/p&gt;

&lt;p&gt;NoSQL的出现，原本不是为了完全取代关系型数据库，而是为了应对关系型数据库在性能和伸缩性方面的缺陷而提出的存储方式。NoSQL不应该是“No SQL”，更为妥当的方式应该是“Not Only SQL”。 &lt;/p&gt;

&lt;p&gt;放眼如今比较成功的NoSQL应用，似乎除了Google由于数据规模，资源沉淀等原因之外，其他系统大都是将NoSQL作为一种优化的手段在使用，而并非是作为系统的主要存储方式，它们主要使用的存储方式依然是MySQL等关系型数据库。而事实上，各系统也是在架构演变过程中，发现关系型数据库成为了系统优化的瓶颈，进而在一定程度上引入NoSQL存储方式以改善性能。 &lt;/p&gt;

&lt;p&gt;例如就在不久之前，SourceForge宣布将在系统中引入MongoDB，而Twitter也打算开始使用由Facebook创建的Cassandra。但是以SourceForge与Twitter目前基于关系型数据库所支撑起来的规模，也已经是无数系统难以企及的目标了。更何况，如Stack Overflow这样号称全世界最大的程序员网站，作为存储后端也只是使用了单台关系型数据库。 &lt;/p&gt;

&lt;p&gt;毕竟，关系型数据库的性能并非差到不可接受，NoSQL的优势也只有在达到一定规模时才能体现出来。而且，除了存储方式以外，系统中可以优化的地方还有很多。例如最传统的，缓存，一个实现较好的缓存机制可以减少95%以上的数据库访问，这对于系统性能的影响也是相当巨大的。 &lt;/p&gt;

&lt;p&gt;在目前，使用NoSQL存储方式的另一个不便之处便是工具的缺失。我在项目中也使用了MongoDB，一个十分明显的体会便是，对于MongoDB的操作比关系型数据库要麻烦不少。例如在访问关系型数据库时可以利用现成的映射工具，经过多年发展此类工具也已经变得非常灵活、高效，能够应对绝大部分的使用场景。而在使用MongoDB时，我似乎又有了回到当年裸写JDBC的感觉了，甚至对于某些平台来说，连一个成熟的驱动（例如有连接池的支持）都需要亲自动手开发一个。对于一个有经验的开发人员来说，便写一些“够用”的代码自然不是难事，不过这的确也是一件会影响投入产出比的事情。 &lt;/p&gt;

&lt;p&gt;此外，NoSQL虽然性能高，但这也是通过在一定程度上牺牲数据的完整性或一致性的保证换来的，传统的关系型数据库却在这方面投入了很大的精力，例如事务机制，虽然会降低性能，但是却保证了数据的一致性。但是，如今的NoSQL存储几乎都没有提供类似的机制（毕竟有个无法回避的CAP规律），这样多个相关的操作一旦中断（例如出现了异常），则很容易造成数据“此长彼短”的现象。而且，如今的NoSQL产品出于性能考虑，几乎无一例外会带有一定程度的缓存机制，不会将新建或更新的数据直接写入磁盘。因此，如果没有一个集群环境，在遇到突发状况时则很可能带来数据丢失的情况。对此，如MongoDB明确指出，它对于单机的持久性并不十分重视，它的设计人员以此换来更为重要的参数：性能。这意味着，一旦使用NoSQL作为主要存储方式，则往往会需要同步跟进一些周边措施，例如可能要在保证数据的最终一致性方面投入较多的精力。 &lt;/p&gt;

&lt;p&gt;当我们确定要选择NoSQL存储方式的时候，则必须根据自己的业务特征选取特别的NoSQL产品。目前NoSQL主要分为四大类：BigTable，Key-Value，文档型，及图数据库。它们有各自的性能优势及适用范围。例如Key-Value存储方式支持的查询方式非常有限，但是由于结构简单，它的性能和伸缩性可谓傲视群雄。而文档型数据库，如MongoDB，它所支持的查询方式非常灵活，并内置Map Reduce机制，可以直接输入JavaScript脚本进行一些特殊的数据处理及汇总。而如Neo4j这样的图数据库，由于直接支持“节点”、“（有向）关系”等概念，则对于一些关系型数据库、文档型数据库难以应对或建模的查询或遍历方式（如最短路径计算），就有了非常直接、自然且高效的支持。 &lt;/p&gt;

&lt;p&gt;总之，架构师选择的不是SQL或NoSQL本身，而应该只是“最合适”的东西。&lt;/p&gt;

&lt;h1&gt;关注的方向和领域选择&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;很多架构师都喜欢学习Google, Facebook等大型系统的经验，但另外不少架构师则认为绝大多数网站都不会成长成一个“大型网站”。绝大多数工程师都没有能力建立和维护一个类似GFS的系统。对绝大多数网站而言，把时间耗在所谓“大型网站”的架构上没有意义，你怎样看待这种说法，架构师应该如何选择关注的方向和领域？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;回答：&lt;/strong&gt;我在这方面的看法是，虽然Google，Facebook等大型系统的规模对于绝大多数人来说可能是永远无法接触到的，但是它们的经验及措施可能会给我们带来一些其他方面的体会。 &lt;/p&gt;

&lt;p&gt;例如，Map Reduce原本是函数式编程中再普通不过的概念和手段，但是Google将它和GFS等其他基础设施一结合，便成为了一个无比强大的分布式计算技术。但是，Map Reduce它本身还是十分简单的东西（Google Map Reduce实现的复杂点主要还是在于GFS），它也并非Google专有的东西，我们受到这样的启发也可以将其用到别处。例如在MongoDB和CouchDB中都内置了MapReduce支持，在去年的QCon Beijing大会中，FreeWheel公司在它们的广告平台中，也使用了自己的方式实现了Map Reduce计算机制。 &lt;/p&gt;

&lt;p&gt;因此，即便是无法成为真正的巨人，也可以关注巨人成长过程中所吸取的经验教训，从中也可以得到一些启发。即使是当作一个有趣的故事去了解也好，即使是为了打开眼界也好。有时，我们需要的可能只是一个不经意的提示。&lt;/p&gt;

&lt;h1&gt;微博类产品的架构难点&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;目前国内很多互联网门户都在做微博产品，你觉得微博技术架构的主要难点在哪些方面？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;回答：&lt;/strong&gt;从复杂度上面来说，微博产品的业务是相对比较简单的，我认为它在技术架构上有两大要素：消息传递与缓存。 &lt;/p&gt;

&lt;p&gt;微博产品从产品性质上来说几乎完全就是一个消息分发平台，因此一个良好的消息传递机制是至关重要的。当一个用户发出消息之后，它可以被许多人观察到。对于一个名人来说，被数十万用户所追随是一件非常普通的事情。那么此时，如果期望所有的追随者都即时地看到消息这几乎是件不可能的事情，因此在实现时我们往往需要构建一个消息队列，将消息快速地派送至队列中等待处理，最终将这条消息“陆续地”显示在每个追随者的时间轴上。这里势必会产生延迟，但对于业务质量来说并非不可接受。但显然这个延迟也不可以太长，在Twitter上这个平均延迟是500毫秒，从绝对数值上看并不算太短，但也已够用。Twitter在这方面的处理方式是利用Scala的Actor模型及Apache Mina编写了一个分布式的消息传输框架Kestrel，它具有快速、轻量（包括注释才不到2000行代码）、持久、稳定等特性，但不具备事务性，也不保证消息的顺序处理。因此可以这么说，Kestrel是一个Twitter根据自身需求“定制”出的消息传输机制。 &lt;/p&gt;

&lt;p&gt;另外一个要点便是每个大型系统都不可或缺的缓存机制。有人说缓存就好比万能膏药，哪儿不舒服就再哪儿擦点便能见效。这话有一定道理。如Twitter便设计了相对复杂的多级缓存机制，几乎对于每个IO密集的地方都进行了缓存。例如记录ID序列的向量缓存（Vector Cache），纪录每条消息等具体内容的行缓存（Row Cache）。此外，由于它的API访问量很大，仅仅是从消息内容转化成API的输出形式（可能只是一些字符串连接操作）也会消耗较多代价，因此Twitter还为消息的API输出形式设计了片断缓存（Fragment Cache）。最后自然还有对某些热门页面的页面缓存（Page Cache）。除了页面缓存之外，其他缓存的命中率都在95%以上，可见缓存机制对于Twitter系统的重要程度。值得注意的是，向量缓存及行缓存都是Write Through的，这意味着基本上所有的新数据都在缓存中存在一份拷贝。正如Twitter的Evan Weaver在QCon London 2009会议上讲的那样：Everything runs from memory in Web 2.0。 &lt;/p&gt;

&lt;p&gt;最后，对于微博类应用来说，可能会因为某个突发事件造成访问量暴增的现象，如何抵抗住消息轰炸也是一个重要的课题。例如Twitter使用了云计算的方式来应对此类问题，在需要的时候它便会租用更多的计算资源。不过增加服务器只是纯硬件的投入，而架构设计能否顺利且充分地利用起新增的设备也是一个值得关注的地方。从这个角度看，一个高效的分布式消息传递机制在这里会扮演重要的角色。如果有了合适的消息机制，首先能够将消息负载较为容易地平衡至多台服务器上，其次即使是在压力增大的情况下，响应时间虽然会按线性增长，但是系统的吞吐量还是可以保持在正常的水平。 &lt;/p&gt;

&lt;h1&gt;给未来架构师的建议&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;很多工作2-3年的软件工程师谈到职业规划都是希望往架构师方向发展，请问能给这些正在成长的工程师哪些建议？如何才能成为一个优秀的架构师？ &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;回答：&lt;/strong&gt;其实我也不知如何给出一些有效而具体的建议。我认为架构师不是一个职位或是职责，而更像是一种思维方式。其实只要打开眼界，不断吸收和关注技术及业务的发展，待积累到一个合适的时候便可以对系统架构提出自己的思路及建议的时候，那你就是一个架构师了。 &lt;/p&gt;

&lt;p&gt;其实每个程序员都可以是架构师。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/05/programmer-magazine-2010-5-architect.html#comments</comments>
      <pubDate>Fri, 21 May 2010 01:48:19 GMT</pubDate>
      <lastBuildDate>Fri, 21 May 2010 01:48:19 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>永远的G点：中医和科学</title>
      <link>http://blog.zhaojie.me/2010/05/science-and-chinese-medicine.html</link>
      <guid>http://blog.zhaojie.me/2010/05/science-and-chinese-medicine.html</guid>
      <description>&lt;p&gt;最近由于&lt;a href="http://twitter.com/tinyfool"&gt;@tinyfool&lt;/a&gt;同学要对博客的缓存插件进行压力测试，于是又引发了&lt;a href="http://tiny4.org/blog/2010/05/traditional-chinese-medical-is-not-science/"&gt;一场关于中医和科学的讨论&lt;/a&gt;、嗯或者说是争论……讨论……好吧我也不知道算是什么。这的确是个G点，一碰就能让许多人兴奋。兄弟我学识浅薄，既不懂科学，也不懂中医，本来不该参与这个话题讨论的，但最近看着其他人围着G点打转，脑子里也产生了不少想法，如果不记下来着实有些浪费脑细胞了。&lt;/p&gt;

&lt;p&gt;之前也有很多牛人对中医和科学的话题有过很多讨论、嗯或者说是争论……讨论……读书人的事……好吧我也不知道算是什么，他们自然也发表过许多看法。例如李笑来老师也&lt;a href="http://www.lixiaolai.com/index.php/archives/6300.html"&gt;明确地拒绝中医&lt;/a&gt;，为啥？不科学嘛。例如，它有双盲实验吗？例如您相信&lt;a href="http://twitter.com/mathena/status/14111453516"&gt;内经里说“逆春伤肝，夏伤心，秋伤肺冬伤心”，原因是五行与五脏对应&lt;/a&gt;吗？郝大（就是@tinyfool了）的文章标题便是《&lt;a href="http://tiny4.org/blog/2010/05/traditional-chinese-medical-is-not-science/"&gt;中医是不科学的，且不是科学&lt;/a&gt;》，其主要观点已经表露无遗，论点明确论据充分（有朋友指出文章里论据不足，那么估计这论据是在其他讨论内容，或是其他人的文章中吧……考据不能，多多包涵）。这种方式对我来说很有说服力，我很吃这一套。同样我很相信&lt;a href="http://www.pianopractice.org/"&gt;一个有演奏家水平的科学家记录下的科学的钢琴练习方法&lt;/a&gt;，更何况他的确培养出两个有绝对音准的演奏家女儿。&lt;/p&gt;

&lt;p&gt;不过自然有人会提出反对意见，比如说中医不科学，但它是千百年来经验积累的结果，有效。而中医使用的是另一个完备、自洽的体系，它和“科学”完全是两个体系内的东西，它自然是“不科学”的，因为它根本“不是科学”，但这并不影响它的“正确性”。即便是&lt;a href="http://twitter.com/zhuangbiaowei/status/14149584460"&gt;郝大也不是在要否定中医&lt;/a&gt;，在他的说法里“不科学”是个中性词，不带褒贬。&lt;/p&gt;

&lt;p&gt;在我看来看来，这本来便是个没有什么争议的说法，大家是可以和平共处的。不过事情哪有真么简单，否则那么多争论又是哪里来的呢？关键就是在于，双方不是在争论“中医是否科学”这个“中性”的“定论”，而是在争论“中医是否有效”或者说“是否相信中医”这样的命题。 &lt;/p&gt;

&lt;p&gt;据我观察，事实上信奉“科学”的人在说“中医不科学”的时候，其潜台词便是说中医“不可靠”：“因为不科学，所以不可靠”。您说，这能让中医的支持者们满意吗？于是乎，争论就开始了。没办法，“科学”在现实社会中占有绝对的话语权，比如对于一个普通人来说，他会将“不科学”当作中性词来对待吗？“不科学”随之而来的便是“虚假”、“错误”、“骗子”等等，这明显是十足的贬义。而事实上，即便是中医的支持者们，其中相当部分也是深信“只有科学的才是正确的”，于是他们一再试图“证明”中医也是科学的，但中医本就不是科学，因此说的再多也只能是些无力的争辩了。 &lt;/p&gt;

&lt;p&gt;但问题就在于，“科学”本身也没有说自己可以解释一切，也没有说自己是唯一真理。因此我觉得引发争论的一大原因便是：“科学方”有意无意的利用了自己在话语权上的优势，毫不让步，不给“中医方”留什么余地。换句话说，这更是“情面”上的问题，是种感觉。别说感觉不重要，人是情绪的动物，感觉这种东西往往是更能引发争论，产生G点的地方。很多时候&lt;a href="http://blog.zhaojie.me/2010/02/logic-is-not-everything.html"&gt;光有逻辑也是万万不能的&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;不过，如果“中医方”找不到合适的回应方式，沉默也比“狡辩”来的靠谱。显而易见的一点是，即便是正确的命题，使用错误的方式来进行证明也是不对的。就好比，说“JavaScript是门优秀的语言”是因为“用它的人多”，这种证明方式和说“中国是个好地方”，因为“住在中国的人多”是相同的流氓逻辑。同样的道理，使用“经验说”或是“弘扬传统文化说”来支持中医也是不妥当的，“传统文化”难道就该保留吗？如果是些“糟粕”呢？我想现在应该没有什么人还支持裹小脚吧。 &lt;/p&gt;

&lt;p&gt;所以在我看来，正是因为“科学方”如春哥般的霸气，以及“中医方”如曾哥绵羊音般疲软的回应，造成中医和科学成为一代G点，永远能给许多人带来一波又一波的高潮。&lt;/p&gt;

&lt;p&gt;同时我认为，造成长时间高潮主要矛盾，其实也是“信仰”与“直觉”的冲突。什么是直觉呢？那便是我们根据以往的学习经验，对一个事物的倾向性的看法。对于“中医方”来说，从小的科学教育让他们信仰科学，但“直觉”告诉他们：凝聚了几千年来智慧结晶的中医怎么会有问题呢？而换到“科学方”来说，“五行与五脏对应”从直觉上说也是错误的嘛！但对我来说，无论是哪方面的“直觉”都不能作为靠谱的依据。比如您如果翻开之前提到的那本“科学家写的钢琴练习方法”，它在前言里便提到说“最有效的钢琴练习方法是违反直觉的（the best piano practice methods are surprisingly counter-intuitive）”。我们也不是经常会遇到一些 “违反直觉”但正确有效的东西吗？ &lt;/p&gt;

&lt;p&gt;而我对这方面的观点……好吧，其实我也是更相信科学的，披着科学外衣的东西更容易让我信服，毕竟我和大部分人受到的科学教育也并没有什么区别。当然，我也相信“科学”体系外的东西也可以有其道理，换句话说，我并不认为“不科学”的东西就一定是有问题的──这些东西里包括中医，还包括风水，星象，宗教等等。我很乐意去了解和接受中医，但得让我感觉有道理，不是吗？ &lt;/p&gt;

&lt;p&gt;落实到具体实践上，我可能就表现为，得病时我也愿意去看正规的中医，但是我不会接受所谓的“祖传秘方”。同样，在您说的清个条条框框之前，也千万不要用星象、风水等东西来为我做些预测啥啥的。当然，对于星座等东西，如果是打算用来骗骗小女生我还是挺愿意接受的。&lt;/p&gt;

&lt;p&gt;最后，您是否觉得我这篇文章说的没啥感觉？其实我很能理解您的感受。幸运的是，我的大部分观点在著名相声表演艺术家&lt;a href="http://www.supengcast.net/"&gt;苏鹏&lt;/a&gt;老师那里&lt;a href="http://www.supengcast.net/post/2010/05/19/e7a0b4e999a4e8bfb7e4bfa1efbc8ce4b8ade58cbbe4b88ee7a791e5ada6.aspx"&gt;已经谈的差不多啦&lt;/a&gt;。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/05/science-and-chinese-medicine.html#comments</comments>
      <pubDate>Tue, 18 May 2010 15:17:53 GMT</pubDate>
      <lastBuildDate>Tue, 18 May 2010 15:17:53 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>您精通XXX吗？那么就来谈谈它的缺点吧</title>
      <link>http://blog.zhaojie.me/2010/05/learn-from-disadvantages.html</link>
      <guid>http://blog.zhaojie.me/2010/05/learn-from-disadvantages.html</guid>
      <description>&lt;p&gt;“精通”这个词已经被用滥了，当年招人时收到过无数简历，继而发现，似乎简历上面不写几个“精通”还真对不起咱这张脸。那么到底啥叫精通呢？应该是对某样东西无比了解，不能再了解的程度吧——不过地球人都知道，简历上的“精通”已经算不得数了。那么，如果我们真要考察一个人（比如自己）对某件事情是否“精通”，又有什么合适方法呢？我觉得有个方式比较靠谱，那就是谈谈这东西的缺点。&lt;/p&gt;

&lt;p&gt;不过咱先说点废话吧，比如谈谈耍流氓——呃，不，搞对象吧。比如您看上一个妞，面容姣好，身材窈窕，气质温文尔雅，不错挺好挺心动，那就上吧。吃过几顿饭，搞过几次活动，小手牵牵小腰搂搂，成了。您那心里乐得欢呀。不过日子长了，您会发现，咦怎么好象矛盾慢慢多起来了呢？比如每个月总有几天会让您觉得无理取闹，谈一些正经话题却也话不投机，性格好象也不是那么合拍……更关键的是您忽然发现对方不化妆的时候咋就看上去有些……异样涅？废话，人姑娘和您熟了而已。您自己追求人姑娘时会带人去听音乐会，送花送礼物，现在呢？您追求人姑娘时衣衫整洁装模作样，现在不还拉里邋遢的……对了，居然还抖腿！别走，说得就是你。&lt;/p&gt;

&lt;p&gt;其实道理也都是一样的，任何东西在初期总是显得特别美好。比如您要搞一门技术，去书店找书看，哪本书不是说它优势的？又有多少书是在谈它缺点的呢？技术推广者或拥护者基本也只会不断地宣传技术的优点，否则谁会来跟进这门技术？因此，了解技术的优点很容易，但是想要知道它的缺点就困难了。如果一个人能谈论这门技术的缺点，并进行有效的分析，我更愿意相信他对这门技术是有深入研究的。而且在很多时候，对这门技术越是了解，那么发现的缺点也会更多，因为熟悉了呗。没有什么技术毫无缺陷，有缺点不是问题，关键是怎么去解决，如何去扬长避短。事实上，一个看不到OO缺点的人，真能算是了解面向对象，真能做出良好的设计吗？&lt;/p&gt;

&lt;p&gt;更关键的是，想要了解一门技术的缺点并不容易，这需要更广阔的眼界。而且在这方面工具只能起到“辅助”作用，起关键性作用的还是人的态度。就好比&lt;a href="http://twitter.com"&gt;推特&lt;/a&gt;，应该说是个打开眼界的好去处吧？我倒觉得……未必，还要看您怎么用。推特需要您去特意“追随”一些人，才能看到那些人的消息。&lt;a href="http://twitter.com/xiaolai"&gt;笑来&lt;/a&gt;老师昨天&lt;a href="http://twitter.com/xiaolai/status/13366693990"&gt;谈到&lt;/a&gt;“有时候，真相比谣言更难传播的原因，主要在于人们只传播自己认同的东西。”因此，您看到的消息，其实很可能也是您“愿意”去看到的东西——您不想看的人，不想去关注的消息，您完全可以不去订阅嘛。就比方说，我就被一些人给Block了，这样他们看不到我说的任何东西——比如F#或.NET的优势是什么。他们不愿听，因此就能听不到。&lt;/p&gt;

&lt;p&gt;比如，要了解.NET的缺点，把视野放在.NET社区是远远不够的。此时您要去关注其他社区里的人是怎么说的（通过订阅博客或是在推特上关注相关的技术人员）。例如在Java社区中，他们就会谈到Java目前的发展状况及优势是什么，甚至会直接谈到.NET的缺点。此时就是个更进一步了解和反思.NET自身的契机。对方的优势是否就是我的缺陷？我在对方眼中的问题，是否真的是我的短处？如果真是缺陷或短处的话，那么我又可以怎么去弥补？&lt;/p&gt;

&lt;p&gt;不过问题在于，国内技术社区的眼界总体是封闭的，即便是所谓开放社区的群众也会&lt;a href="http://blog.zhaojie.me/2010/03/microsoft-technology-and-the-attitude.html"&gt;盲目排斥微软技术&lt;/a&gt;，更别说大大方方承认自己的缺陷了。不久之前Oren Eini写了一篇文章，谈到“&lt;a href="http://ayende.com/Blog/archive/2010/05/05/i-like-strong-typing-and-compilation-errors.aspx"&gt;缺少编译期检查会不容易重构&lt;/a&gt;”，我在推上表示赞同。但就是这么一个普通的说法，还是有同学反驳我说“除非完全不需要（反射等）动态特性，不然编译检查靠不住”，因此编译期检查毫无意义。也有人说重构用正则替换即可，或是重构不易是因为代码写的不好，有Bad Smell的缘故——是不是偏激了点？似乎在某些技术人员的眼里，自己使用的技术不会有任何缺点，否则自己会随着技术本身而掉价——其实这又何苦，为什么不能大方的接受对方的优势，再想办法去弥补自己的缺陷呢？比如，不是有人说Ruby重构不方面吗？那么，您可以为它编写一个辅助工具嘛（而且又不是没有现成的）。&lt;/p&gt;

&lt;p&gt;我一直很乐意承认对方的优势，例如我承认Rails框架——或者说工具集的生产力很高，有很多值得ASP.NET学习的地方，我在开发项目时也从中吸取了不少优势，也对我长进很大。我深刻体会到吸取别人长处是促进自己进步的有效方式。因此，在六月份举办的&lt;a href="http://blog.zhaojie.me/2010/03/snda-dotnet-conference-advices.html"&gt;.NET技术会议&lt;/a&gt;上，我也打算请人来讲一场关于Rails的话题。同时，&lt;font color="#ff0000"&gt;以后每次技术会议上，我都会邀请其他社区的高手来讲解相关技术&lt;/font&gt;，希望可以以此打开.NET社区技术人员的眼界。&lt;/p&gt;

&lt;p&gt;好像有些偏题？嗯，就是这样。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/05/learn-from-disadvantages.html#comments</comments>
      <pubDate>Thu, 06 May 2010 07:31:37 GMT</pubDate>
      <lastBuildDate>Thu, 06 May 2010 07:31:37 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>关于“程序员圈子”说几句废话</title>
      <link>http://blog.zhaojie.me/2010/04/programmers-group-effect.html</link>
      <guid>http://blog.zhaojie.me/2010/04/programmers-group-effect.html</guid>
      <description>&lt;p&gt;最近有人在&lt;a href="http://groups.google.com/group/pongba/"&gt;TopLanguage&lt;/a&gt;上发了一条，怎么说，我个人感觉写的还不错的帖子。帖子的标题叫做“&lt;a href="http://groups.google.com/group/pongba/browse_thread/thread/2a2fb932b5fa53c2#"&gt;程序员的虚伪&lt;/a&gt;”，里面主要谈的是说如今在程序员社区里有这么一种不好的现象：话说一群人抱成团，有福同享有难同当，一荣俱容一损俱损，你方开张我来捧场，谁遇问题同仇敌忾。这样的风气造就了一些南郭先生，本事不大却感觉良好。这样的事情简直就是一出台湾偶像剧大陆白领剧，俗不可耐矫揉造作。&lt;/p&gt;

&lt;p&gt;关于这个帖子，不同的人有不同的看法。例如有不止一个朋友说里面有酸葡萄心理：明明是自己进不了圈子而在那里眼红；也有人觉得这个帖子说得好，犀利，透彻——其中也包括我。我其实也有过这样的感觉，或者说是“担心”吧，但感觉如此“不惮以恶意揣测”的方式不甚妥当，于是就没说出来。当然我觉得这种现象其实很常见，也不光是程序员圈子里有这种问题，几乎有人的地方就有江湖，有江湖的地方就有门派，有门派就会有私利，有私利就会出现南郭先生北郭女士，这再普通不过了。&lt;/p&gt;

&lt;p&gt;虽然“存在即是合理”，但“合理”只说明“有原因”，不代表“正确”，很显然这样的圈子是很可能坏事的。&lt;/p&gt;

&lt;p&gt;比如半年多前出现过这么个“&lt;a href="http://blog.zhaojie.me/2009/09/1572868.html"&gt;JavaScript征途事件&lt;/a&gt;”。这个事情呢，其实是《JavaScript征途》这本书出现了不少原则性错误，而作者本人……坚持得紧，这自然没法让人感到满意，一来而去你来我往，终于在我国技术图书出版领域又留下了浓墨重彩的一笔。这件事情还反映出另一件事情，那就是这么有问题的一本书，却还是得到了不少业界专家的联名推荐。您觉得专家们会看不出这本书的问题吗？那为什么还要写些不靠谱的软文呢，还不是因为大家都在一个圈子混，拉不下个面子嘛。唉，这可苦了我等可怜的读者了。&lt;/p&gt;

&lt;p&gt;不过这个帖子似乎只提到了圈子的缺点，而我觉得圈子肯定也有优点——我不是指为圈子内部人士谋求福利，我是指造福群众的那种。&lt;/p&gt;

&lt;p&gt;有趣的事情也经常成对出现，例如帖子里提到的&lt;a href="http://blog.zhaojie.me/2010/02/0-bug-and-sjtu-acm-champion.html#0bug"&gt;0 Bug事件&lt;/a&gt;。这件事情一开始其实只是“圈外人士”MiloYip在豆瓣上客气地指出0 Bug老师书中的错误，结果遭到0 Bug老师谩骂，后来又删帖等等，最终事情闹得还是挺大的，我个人认为与“征途”一样值得好好纪念，不时把玩一番。我估计，让0 Bug老师发彪的主要原因之一也包括某些“圈内人士”的围观和插嘴。要知道，如果没有圈子，可能许多人就懒得掺和这样的破事，或者看看便罢也不会去连番挑逗0 Bug老师。&lt;/p&gt;

&lt;p&gt;但如果是那样的话，我们可能就没法让更多人知道0 Bug这本书的问题，我们也很难发现强大的Milo同学，我们也会少了&lt;a href="http://www.cnblogs.com/MiloYip"&gt;许多有价值文章&lt;/a&gt;可看了。所以，我倒觉得0 Bug事件应该算是“圈子”的伟大胜利——好吧，有些说过了，而且我相信0 Bug老师也一定认为自己胜利了，至少他很得意自己的书卖出去很多呢。&lt;/p&gt;

&lt;p&gt;所以么，这个圈子问题是好是坏还真不好说，就看如何对待了。话说，这篇文章里面写到南郭先生会搞些“&lt;a href="http://blog.zhaojie.me/"&gt;博客连载&lt;/a&gt;”、“&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html"&gt;写slides&lt;/a&gt;”、“&lt;a href="http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html"&gt;开个小讲座&lt;/a&gt;”——还提到了&lt;a href="http://blog.zhaojie.me/2010/04/why-i-say-no-to-aptech.html"&gt;北大青鸟&lt;/a&gt;，这明显就是在说我嘛。所以对我来说，这篇文章倒的确是个良好的警钟。&lt;/p&gt;

&lt;p&gt;挺好的。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/04/programmers-group-effect.html#comments</comments>
      <pubDate>Wed, 28 Apr 2010 15:51:50 GMT</pubDate>
      <lastBuildDate>Wed, 28 Apr 2010 15:51:50 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>幻灯片：Why Java Sucks and C# Rocks</title>
      <link>http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html</link>
      <guid>http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html</guid>
      <description>&lt;p&gt;昨天在&lt;a href="http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html"&gt;5173与博客园联合举办的技术交流活动&lt;/a&gt;中进行了演讲，现在幻灯片终于可以放出了。当然，光看幻灯片本身的效果不大，在演讲过程中我进行了非常多的代码演示和说明，幻灯片本身只能算是一个辅助手段，因此各位没有来听演讲的朋友，还是等我慢慢地对这个话题进行详细讨论吧。&lt;/p&gt;  &lt;p&gt;不过既然幻灯片放出了，那么我进行这场“闹剧”的目的也可以完全公开了，其中有三：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;揭露Java语言的生产力的缺失 &lt;/li&gt;    &lt;li&gt;表达C#的发展现状与常用编程范式 &lt;/li&gt;    &lt;li&gt;鼓励别人抛弃Java语言，采用Scala。 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;没错，我的最终目的不是为了“让Java程序员使用C#”，而是“让Java程序员使用Scala”。&lt;/p&gt;  &lt;p&gt;这里我不得不多说几句。前天我写了“&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html"&gt;比较的意义与目的&lt;/a&gt;”之后得到了许多评论，从评论中我看得出，许多朋友在评论时并没有看我的文章。为什么这么说？因为我已经在文章里不断强调“只是让Java程序员抛弃Java语言，不是Java平台”，而且“并没有想让Java程序员转向C#”。难道这还不能看出，我是想要推广JVM上的另一门语言吗？只可惜我还是收到了许多类似的回复：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;你说要用另一门语言来代替Java，这门语言是什么，C#吗？可笑…… &lt;/li&gt;    &lt;li&gt;你让黑莓，Android程序员去使用C#？他们看了只会一笑了之…… &lt;/li&gt;    &lt;li&gt;比较Java和C#语言本身不会有什么结果的，做开发还得看整体情况…… &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;如果不是没有看我的文章，那么我只能想出另一种可能了：有些朋友&lt;font color="#ff0000"&gt;并不知道JVM上的语言发展情况，并不知道目前JVM平台上除Java外最火热的语言是什么&lt;/font&gt;。那我就觉得奇怪了，要知道，现在可是在开&lt;a href="http://days2010.scala-lang.org/"&gt;Scala Days 2010&lt;/a&gt;呢，而且之前连&lt;a href="http://www.adam-bien.com/roller/abien/entry/java_net_javaone_which_programming"&gt;Java之父高司令都高度评价Scala&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;Java的粉丝们一直认为Java平台的最大优势是开放，我同意。但是，我想Java如此开放，但是为什么一些Java粉丝给我的感觉却是狭隘的心态和视野呢？例如，看到有人说Java坏话了，于是立即热血上涌，文章内容也不用看，文章目的也不去关心，不管三七二十一就在评论中想尽各种办法进行反驳。抛出各种论点，却鲜有论据——我是指靠谱的论据，而不是向某个朋友说的“.NET程序员90%只会拖控件，而Java程序员90%是了解核心技术的”这种莫名其妙的说法。要知道，论点易抛，论据难得。我的文章动辄数千字，就是为了想办法把文章内容说清楚。但是不管怎么努力，我还是会不断发现值得额外详述的地方——更何况在评论中的寥寥数字？&lt;/p&gt;  &lt;p&gt;是的，从某个角度来说.NET平台资源是比Java平台要少。所以我觉得很高兴，我可以时刻发现前进的目标。例如有人说Java平台有个地方很好而.NET很糟糕，我不会想办法去驳倒对方，我会很乐意去了解它，然后看看它在.NET平台有没有类似的东西，它的思想能否借鉴给.NET平台，如果发现这种说法有明显问题才去“摆事实、讲道理”。除了Java平台之外，我还关注其他各种技术，让各技术为我所用。&lt;/p&gt;  &lt;p&gt;Java平台的确开放，但对于某些Java粉丝来说，这难道只是您用来建立信心的借口吗？我一个封闭的微软平台的封闭的.NET程序员，如果心态和眼界都比您要开阔──就好比，一个Java平台上的Scala语言需要我一个.NET程序员告诉您，这难道不很讽刺吗？还好，我相信说一些没边评论的Java粉丝只是少数盲目分子，而Java领域的大部分朋友还是相当靠谱的。&lt;/p&gt;  &lt;p&gt;那么，我单纯比较Java和C#语言有意义吗？当然有，我只要能说明Java语言本身是多么糟糕，让我们有足够的理由转向Scala就行了。&lt;/p&gt;  &lt;div style="width: 425px" id="__ss_3763050"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="Why Java Sucks and C# Rocks (Final)" href="http://www.slideshare.net/jeffz/why-java-sucks-and-c-rocks-final"&gt;Why Java Sucks and C# Rocks (Final)&lt;/a&gt;&lt;/strong&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=why-java-sucks-and-csharp-rocks-100418041313-phpapp02&amp;stripped_title=why-java-sucks-and-c-rocks-final" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=why-java-sucks-and-csharp-rocks-100418041313-phpapp02&amp;stripped_title=why-java-sucks-and-c-rocks-final" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;    &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt; &lt;/div&gt;  &lt;p&gt;感谢&lt;a href="http://www.cnblogs.com/waynebaby/"&gt;韦恩卑鄙&lt;/a&gt;提供&lt;a href="http://cid-fba4447598b1d752.skydrive.live.com/self.aspx/Public/Why%20Java%20Sucks%20and%20C%5E3%20Rocks%20-%20%E5%BD%95%E9%9F%B3[20100417].zip"&gt;演讲录音&lt;/a&gt;，关于演讲的详细内容，自然还是请关注的我的后续文章：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html"&gt;Why Java Sucks and C# Rocks（1）：比较的意义与目的&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html#comments</comments>
      <pubDate>Sun, 18 Apr 2010 09:52:49 GMT</pubDate>
      <lastBuildDate>Sun, 18 Apr 2010 09:52:49 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>Why Java Sucks and C# Rocks（1）：比较的意义与目的</title>
      <link>http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html</link>
      <guid>http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html</guid>
      <description>&lt;p&gt;&lt;a href="http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html"&gt;消息发布之后&lt;/a&gt;，许多朋友都表示对我这个主题的关注——无论是正面还是负面的——这让我很高兴。不过说实话，我原本并没有打算写这篇文章。我原本的打算是从一开始就进行技术方面的讨论，但是大家在前文的反馈让我把一些问题想得更清楚了，也认识到有些东西可能需要先说在前面可以有更好的效果。希望各位朋友可以继续给我一些反馈，这样我可以在必要的时候进行补充更完整的内容。这次的话题很有价值，我想把它做的更好。&lt;/p&gt;  &lt;h1&gt;为什么是Java？&lt;/h1&gt;  &lt;p&gt;这个系列我将详细比较C#和Java——语言，而不关Java平台任何事情。其实这本不想强调这一点，因为语言和平台之间是没有任何可比性的。因为C#明显只是一门语言，因此根据“类型推断”，则Java也应该是“语言”类型才对。因此，我在标题中就不想加入“Language”这样较长的单词了，累赘啊！&lt;/p&gt;  &lt;p&gt;那么，我为什么选中Java来和C#进行比较，而不是其他语言呢？原因很多，主要有以下几点。&lt;/p&gt;  &lt;p&gt;首先，&lt;strong&gt;Java语言足够热门&lt;/strong&gt;。看看&lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;TIOBE语言排行榜&lt;/a&gt;，Java语言风光无限，从2002年开始几乎全程领跑。如果我说这门受众如此之广的语言一些坏话（好吧，其实是很多坏话），那响应的人一定会非常多。例如，事实上Delphi语言在停滞发展之后，在我看来它也已经和Java处于同一级别了。但是我不想说Delphi Sucks，因为即便这么说，可能也不会有多大影响力——当然，可能在&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;里会正好相反。&lt;/p&gt;  &lt;p&gt;其次，&lt;strong&gt;Java语言真的很糟糕&lt;/strong&gt;。好吧我承认，它在诞生初期还是有重大意义的，它简化了编程难度，大大提高了生产力。但是，由于它多年来的固步自封，它已经完全跟不上如今时代的发展了。用现在的标准来衡量Java语言，会发现它是如何拖累程序员的生产力，如何成为Java平台上最短的一块木板。作为一次关于语言比较这种“争议性话题”来说，如果不是有一方“全面落后”的话，那一定就会陷入双方粉丝的口水战——掺杂大量主观内容的讨论，那倒真就没有任何意义了。&lt;/p&gt;  &lt;p&gt;还有，&lt;strong&gt;知道Java语言有多糟糕的人并不多&lt;/strong&gt;。可能有不少朋友的确会感觉Java语言在使用时“挺啰嗦”的，但是由于并没有去仔细了解其他语言的的发展情况，对Java语言的糟糕之处也说不出个所以然来。但是大部分人，真的是大部分，他们一直认为Java是一门不错，甚至很优秀的语言了。为什么？看看排行榜咯。但是我想说，排行榜只能说明它的“热门”程度，并不能代表Java语言有多么优秀。正所谓“劣币驱逐良币”，我这个系列的文章也是想告诉坚持Java语言的程序员们，您到底损失了什么。&lt;/p&gt;  &lt;p&gt;更重要的是，那就是&lt;strong&gt;Java虽然糟糕，但还是有解决办法的&lt;/strong&gt;。如果没有解决办法，那么这场讨论的价值就会大打折扣了，因为讨论了半天我们还是只能保持现状。例如，C语言生产力高吗？当然不如如今许多高级语言。但是，C语言是不朽的，因为我们必须有一种语言来负责底层的开发，这要求它和冯·诺依曼结构尽可能的对应，而不能有太高级的抽象（因为一高级就难以生成最为高效的机器码了）。因此，我不会讨论C语言的特性，我会选择Java语言。当然，这个解决办法就是抛弃Java，换用一种生产力更高的语言。&lt;/p&gt;  &lt;p&gt;最后，好吧，其实还有一点便是，&lt;strong&gt;我对Java语言足够熟悉&lt;/strong&gt;。我的“职业程序员”生涯便是从Java开始的（之前都算是小打小闹），大学里的编程课学的也是Java（期末考试时是全班最高的106分，满分是100+10分附加题），也用它做了不少项目。我还记得最后一个Java项目是2004年参与开发的是海关审批工作流，当时翻来覆去看的参考书是《&lt;a href="http://www.amazon.com/Expert-One-One-Development-without/dp/0764558315"&gt;J2EE Development without EJB&lt;/a&gt;》。只不过接下来我便投身于.NET世界，用的最多的语言便是C#了。C#从2.0起突然发力，瞬间将Java语言甩开几条马路，而3.0的改进更是堪称经典。不是我不想回到Java平台，是我实在不想在Java语言上浪费生命。&lt;/p&gt;  &lt;p&gt;嗯嗯，其实我也挺希望许多朋友在批评一个事物的时候，先对它的现状有足够了解的。否则，真挺没意思的。&lt;/p&gt;  &lt;h1&gt;又为什么是C#？&lt;/h1&gt;  &lt;p&gt;好吧，那为啥要拿C#出来耍？直接说Java的不是就行了嘛。其实我也有几点理由：&lt;/p&gt;  &lt;p&gt;首先，&lt;strong&gt;我的博客毕竟还是主要关注于.NET技术的&lt;/strong&gt;，来看我文章的大部分朋友相信使用的还是C#语言。我这一系列文章虽说是要讲Java烂，但可能大部分“手法”是在说明C#和Java语言之间的差距。因此，我也会努力地在文章中体现C#的美妙之处，会展示大量C#的编程模式。这些模式并非只是为了好看，而绝对是在生产过程中非常有用且常用的。我希望这系列文章除了鼓励别人摆脱Java语言的负累以外，也可以给C#程序员带来同样的价值。&lt;/p&gt;  &lt;p&gt;其次，&lt;strong&gt;我想改变许多朋友对C#的看法&lt;/strong&gt;。我想大部分朋友应该了解C#语言比Java的特性多，但是您可能不太了解C#目前的发展状况，以及C#和Java之间的真实差距。您可能会认为，C#虽然比Java特性多，但也只是一些语法糖而已，虽然可能的确比Java生产力来的高，但是优势并不明显。我想要告诉大家的便是，C#有别于Java的特性并非这么普通，它是凝聚了&lt;a href="http://en.wikipedia.org/wiki/Anders_Hejlsberg"&gt;Anders Hejlsberg&lt;/a&gt;这个天才的理想，都是对生产力提高有重大意义的。&lt;/p&gt;  &lt;p&gt;还有，&lt;strong&gt;如果要与Java语言进行比较，还有比C#合适的对手吗？&lt;/strong&gt;我想不到很合适的。因为根据TIOBE语言排行榜的纪录，排名靠前的语言中也只有C#和Java颇为相似。这个相似体现在多个地方，其中最重要的在于它们所在的平台所面向的应用类型几乎完全相同。C#和Java语言也是纠缠如斯，相信这两者的碰撞会比其他情况带来更多关注。同样，至今还有些朋友认为C#只不过是在抄袭Java而已。不过我在这里想说的是，好吧我承认C#在最初和Java颇为相似（但也有许多不同），但是&lt;font color="#ff0000"&gt;自从C# 1.0诞生之日起，就只出现Java借鉴C#特性的情况，至今已将近10年&lt;/font&gt;。您可以记住这句话，我会证明给您看的。:)&lt;/p&gt;  &lt;p&gt;当然，我对C#也足够熟悉，我想这点就不用多做解释了吧。&lt;/p&gt;  &lt;h1&gt;LISP那点事儿&lt;/h1&gt;  &lt;p&gt;呃，我在表示要写Why Java Sucks and C# Rocks系列文章后，收到的许多质疑是有关LISP的。&lt;a href="http://en.wikipedia.org/wiki/Lisp_%28programming_language%29"&gt;LISP&lt;/a&gt;是一门（或者说是一类）神奇的语言，虽然在工业界的应用并不广泛，但是却有着不容置疑的历史意义。我有幸在大学时加入了复旦大学软件学院和爱尔兰都柏林大学合办的所谓“&lt;a href="http://www.software.fudan.edu.cn/education/jointdegreeprogramintroduction.shtml"&gt;爱尔兰班&lt;/a&gt;”，开办的第一门课便是函数式编程，使用LISP讲解（不过现在的同学已经使用&lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt;了），于是我在那时候也对LISP产生了一定的兴趣，也有了大半年的学习接触。虽远不能说是精通，但基本的了解想必还是有的。&lt;/p&gt;  &lt;p&gt;关于LISP，有种说法便是“LISP之后，再无创新”。于是有朋友说，那么你不谈LISP，在Java和C#之间比什么劲儿嘛。首先，我想上文也已经表现了我的一部分想法了，现在则再谈一些。其实我觉得这种说法就好比说“某某人已经是第一名了，后面的争夺又有什么意义呢？”，这个说法显然是不妥当的。语言的争论和评价从来不曾停止，即便是大师们，例如&lt;a href="http://thread.gmane.org/gmane.comp.version-control.git/57643/focus=57918"&gt;Linus炮轰C++&lt;/a&gt;，&lt;a href="http://news.cnet.com/2008-1082-817522.html"&gt;高司令谈C#&lt;/a&gt;，&lt;a href="http://www.artima.com/intv/generics2.html"&gt;Anders认为Java的泛型不好&lt;/a&gt;，Matz在邮件列表中&lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/179642"&gt;戏称Ruby为MatzLisp&lt;/a&gt;，这些都是有趣的，有价值的，值得关注的东西。&lt;/p&gt;  &lt;p&gt;也有朋友说，有什么语言能带来LISP那般革命意义，能够代替Java呢？LISP的确有其革命意义，但是语言的确知道它的缺陷，因此也就主要是把它供在神坛上，需要的时候膜拜一下便是，紧抱不放便是问题了。语言同样在不断发展和演变，尤其是对于工程应用来说，人们对于生产力的追求永远不满足，这点从业界关于语言的会议（如&lt;a href="http://www.langnetsymposium.com/"&gt;Lang.NET&lt;/a&gt;）便可得知。而即便是如&lt;a href="http://www-fp.cs.st-andrews.ac.uk/ifl-workshops/"&gt;IFL&lt;/a&gt;这类专注于函数式编程的学术会议，对于LISP语言本身的关注程度也有所降低。人们都知道，是该站在LISP的肩膀上向前看的时候了——其实很久以前就是这样了。&lt;/p&gt;  &lt;p&gt;而且，我的目的主要还是想鼓动大家抛弃Java语言，这和它的替代者是否革命意义并没有关系。这就好比，对于石器时代的人们来说，第一根铁棍的革命意义远超后来的神兵利器，但是人们什么时候放弃过对神兵利器的追求呢？只要真正是“更好”的东西，那也就足够了。&lt;/p&gt;  &lt;p&gt;我也是个俗人，讨论讨论对真正生产有直接影响的东西，也就够了。&lt;/p&gt;  &lt;h1&gt;糖、糖、糖&lt;/h1&gt;  &lt;p&gt;再回到关于“语法糖”的讨论。之前提到，有不少朋友认为C#相对于Java只是语法糖较多，够甜。但事实上，我在这一系列文章中并不想提“语法糖”这些东西。嗯，我是说，我眼中的语法糖。&lt;/p&gt;  &lt;p&gt;从理论上说，只要是图灵完备的语言，就不存在“能力”上的根本差异，任何工作都是可以实现的。但是我们使用的语言，往往也会影响，甚至决定了我们的思维方式。因此一门语言的关键，我认为就是它的思想，或者说，是它对我们“思维方式”的影响。同时，由于语言会影响我们的编程思维，甚至系统的架构设计，因此在我看来它也是至关重要的。&lt;/p&gt;  &lt;p&gt;举个有些极端的例子，如果人们还在使用汇编语言进行开发，那么估计程序员的思维永远无法跳出“子过程”这个抽象级别，什么面向对象设计，函数式编程几乎无从谈起。人们在生产和学习过程种会引发一些需求，因而需要产生一些工具来辅助学习和生产，而“语言”便是此类工具之一。只有利用高级语言，人们才能有效地把真实世界抽象成计算机这些机器盒子能认识的东西。 &lt;/p&gt;  &lt;p&gt;如今，可用于构建项目可选的主流语言往往都会有多种，有时候我们的确会发现，好像不同的语言——例如Ruby和Python——从各方面来说并没有太大区别（或者说优劣之分）。这是比较正常的，因为某些（甚至是大部分的）语言特性，并没有对我们的“思维”产生影响。 &lt;/p&gt;  &lt;p&gt;举例来说，某些喜欢Ruby的朋友认为Ruby语言的编程体验非常良好，好比它的数组操作可以直接做加法或减法： &lt;/p&gt;  &lt;pre class="code"&gt;array = ['aaa', 'bbb', 'ccc'] - ['ccc', 'ddd'] &lt;/pre&gt;

&lt;p&gt;或者说，在Python里交换两个变量的值也只需要一行代码（大部分语言中可能需要借助中间变量，好吧，我承认Ruby里也能做到这一点）： &lt;/p&gt;

&lt;pre class="code"&gt;a, b = b, a&lt;/pre&gt;

&lt;p&gt;但是，就我个人观点来说，这些语言特性，虽然它们的确可以让编程工作变的相对轻松一些，例如可以让我们少些一点代码，但终究没有改变，或是表现出另一种编程思维。这样的语法特性，一般来说都可以通过构建一些简单的辅助函数来做到类似程度的“简化开发”（如上面Ruby的例子），对于那些非“即写即抛”的程序来说，这些特性的优势并不明显。就我个人来看，我并不会太重视这些内容。&lt;/p&gt;

&lt;p&gt;而与此相比，Ruby的Mixin机制和Python的Decorator就不仅仅是“语法糖”，而是比较重要的语言特性了，因为它们可以带来或大大简化某些十分有用的编程模式。“简化”也是语言设计中非常重要的一点，我始终认为，一个语言特性只有真正“好用”，它才能被人们广为接受。例如，使用Java语言能实现Actor模型吗？能，但是它缺少Scala那样灵活的函数式语法，以及模式匹配等特性，因此无法构建出一个好用、易用的Actor框架，自然也就无人问津了。这其实也是“语言影响思维方式”的典型案例之一。&lt;/p&gt;

&lt;p&gt;其实人们在LISP之后继续前进的原因，也是因为LISP虽然提出了许多编程理念，范式，但是每个都不够“好”、“优雅”、“简单”等等。做的“更好”便是其他语言不可忽视的意义。&lt;/p&gt;

&lt;p&gt;是的，我不会强调C#如“属性”，“操作符重载”等语言特性，虽然它很多时候的确让开发变得简单，但是它们并不能改变我们的开发思维。那么这一系列的文章中我会重视哪些语言特性呢？我想，它们至少应该同时具备以下三个条件吧：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;必须是纯粹的语言特性：&lt;/strong&gt;有人说Python方便，很多事情一个方法就能搞定了。这在我看来只是类库相关的东西而已。在这里，我并不关注类库与框架，我只关注纯粹语言特性。&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;无法，或很难通过类库或框架弥补的差距：&lt;/strong&gt;同样是一个方法能搞定的案例，但是如果这个方法必须借助特定的语言特性才能实现，那么这便是我的关注点。&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;能够改变编程思维、或是引出额外的编程范式：&lt;/strong&gt;正如上文讨论的那样，这是我最为重视的东西。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;嗯嗯，就是这样。&lt;/p&gt;

&lt;h1&gt;再补充一些内容&lt;/h1&gt;

&lt;p&gt;好吧好吧，我知道您看到那么多文字之后也一定也想说些什么了，不过您再坚持一下，等我把话说完吧。&lt;/p&gt;

&lt;p&gt;写这一系列文章的目的，我想已经说得很清楚了。不过我想我还是有必要强调一下，我并&lt;font color="#ff0000"&gt;不想&lt;/font&gt;让您：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;立即抛弃Java语言（不过我希望您可以现在就开始准备了）&lt;/li&gt;

  &lt;li&gt;使用C#来代替Java语言&lt;/li&gt;

  &lt;li&gt;使用.NET来代替Java平台&lt;/li&gt;

  &lt;li&gt;认为.NET平台胜过Java平台&lt;/li&gt;

  &lt;li&gt;认为CLR强于JVM&lt;/li&gt;

  &lt;li&gt;……&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;总之一句话：我没说过的东西，您也别多想。我说过的，您也不用怀疑我的“诚意”。:)&lt;/p&gt;

&lt;p&gt;再来一些问答吧，如果有需要的话我也会不断补充一些内容的。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;问：语言的生产力，关键还是看熟悉程度吧？&lt;/strong&gt;答：我不这样认为，很多东西的差距是实实在在，不容置疑的。例如，C语言的生产力就比汇编要高，电锯的切割效率就比手工锯条要好。的确，我承认使用者对工具的熟悉程度会影响生产力，但我想您可以想，就当您已经对两种语言都足够熟悉了，这时候总可以开始比较生产力了吧。不了解怎么办？学咯，“磨刀不误砍柴工”，有句俗话应该是这么说的吧。&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;问：开发项目并不由语言一个方面来决定吧？&lt;/strong&gt;答：没错，所以我也不认为您应该“立即”将Java语言抛弃。例如，假如您对它的替代品还不够熟悉的话，假如您的团队还是对Java语言有足够了解的话，假如您的老板决定非要用Java语言而您离开他又活不了的话……那就继续用Java咯。总之，项目的技术选型是个平衡的结果。我只是给您在语言方面给出建议而已。&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;问：Java语言的替代品足够成熟吗？&lt;/strong&gt;答：足够成熟。当然，它的社区资源肯定还不如Java语言，但我认为它也足够了。而且，如果我现在对它进行推广，那么它又会有什么发展，资源又如何增多呢？是啊我承认，我是个颇有理想主义的人。&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;问：为什么不比较Java与.NET平台？&lt;/strong&gt;答：因为在我看来两者实在难分高下，上文也说了，这样的比较几乎就一定会沦为双方程序员的口水战，因为没有一方可以拿出切实的证据来说服对方，大家主观对主观，实在不专业。当然，如果您感兴趣的话可以自己比较一下，我会适时跟进的。:)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;好，该说也说得差不多了。那么从下一篇文章开始，我们就来一起享受技术带给我们的快乐——和挫折吧！&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html"&gt;演讲预告：Why Java Sucks and C# Rocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html"&gt;幻灯片：Why Java Sucks and C# Rocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Why Java Sucks and C# Rocks（1）：比较的意义与目的&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-2-primitive-types-and-object-orientation.html"&gt;Why Java Sucks and C# Rocks（2）：基础类型与面向对象&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-3-attribute-and-annotation.html"&gt;Why Java Sucks and C# Rocks（3）：Attribute与Annotation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/05/why-java-sucks-and-csharp-rocks-4-generics.html"&gt;Why Java Sucks and C# Rocks（4）：泛型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/more-why-java-sucks-and-csharp-rocks-1-reddit-and-property.html"&gt;Why Java Sucks and C# Rocks（补1）：Reddit，兼谈C#属性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/07/why-java-sucks-and-csharp-rocks-5-anonymous-method.html"&gt;Why Java Sucks and C# Rocks（5）：匿名方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/07/more-why-java-sucks-and-csharp-rocks-2-standard-event-model.html"&gt;Why Java Sucks and C# Rocks（补2）：标准事件模型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/07/why-java-sucks-and-csharp-rocks-6-yield.html"&gt;Why Java Sucks and C# Rocks（6）：yield及其作用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html#comments</comments>
      <pubDate>Fri, 16 Apr 2010 15:48:50 GMT</pubDate>
      <lastBuildDate>Wed, 16 Mar 2011 07:23:43 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/news/">新闻信息</category>
      <title>演讲预告：Why Java Sucks and C# Rocks</title>
      <link>http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html</link>
      <guid>http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html</guid>
      <description>&lt;p&gt;怎么样，这个标题是不是足够吸引眼球？嗯，我下个星期便打算在&lt;a href="http://www.5173.com/"&gt;5173&lt;/a&gt;和&lt;a href="http://www.cnblogs.com/"&gt;博客园&lt;/a&gt;举办的&lt;a href="http://www.cnblogs.com/cmt/archive/2010/04/09/1708073.html"&gt;技术交流会&lt;/a&gt;上讨论一下这个话题。&lt;/p&gt;  &lt;p&gt;产生这个话题的缘由，是因为大约在一个月前，&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;里有位同事开始分享Android开发方面的体会——Android开发主要使用的是Java语言，大家也应该知道我对Java语言的感受。因此在交流会后，我和他在这方面有过一些讨论。我的主要观点就是，Java这门语言的的发展过于滞后，与如今流行的其他高级语言相比其生产力已经落后太多。对方的看法是，如果认为Java的生产力不足，一般是对于Java语言不太了解的缘故。&lt;/p&gt;  &lt;p&gt;您一定可以猜到，后来话题逐渐演变成C#与Java的比较。我一直强调如今的C#已经超越Java太多，恰好那位同事当年也使用过一段时间的C#。于是，他问我有什么事情是C#可以做到而Java做不好的。其实这样的例子有很多，因此他不一会儿便改变了对C#的看法，同时对目前C#的发展现状也产生了比较浓厚的兴趣。后来他建议我不妨详细准备一下这个话题，然后可以在创新院内部的分享交流会上详细讨论一下这方面的话题。&lt;/p&gt;  &lt;p&gt;几乎是第一时间我便想出了这样的一个标题：Why Java Sucks and C# Rocks。选择这个标题的主要原因还是足够吸引眼球，而且也正好可以充分表达我对Java语言的看法。在推特上一吹，响应者还真不少。&lt;/p&gt;  &lt;p&gt;在准备过程中，博客园的弟兄也找到我，说即将和5173共同举办一个技术交流会，邀请我主讲一个话题。5173？没错，就是那个5173，其中既有Java团队主要又是由.NET构建的电子商务平台，5173。很显然，他们使用的语言是Java和C#，那么还有比那儿更适合比较Java和C#的地方吗？因此几乎是第一时间我就确定了演讲主题。要知道，创新院内部使用Java的人实在太少，我还嫌不够过瘾呢。&lt;/p&gt;  &lt;p&gt;在创新院分享会上的“预演”效果不错，同事们大都可以认同C#是一门在各方面超越Java的语言。如果您对这个内容感兴趣，就不妨来参加下周的活动咯。&lt;/p&gt; &lt;img src="http://pic002.cnblogs.com/img/cmt/201004/2010040910263056.jpg" /&gt;   &lt;p&gt;以下是这次话题内容的简单描述：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Java语言的流行毋庸置疑，在TIOBE语言排行榜上遥遥领先，并占据了榜首位置长达数年时间。然而，从目前的眼光看来，Java语言的生产力已经严重落后于行业中其他流行的语言，C#便是其中的一个典型。自诞生起，C#似乎便和Java有些纠缠不清，因为在当时看来，无论是语言层面还是它们所处平台的目标都十分相似。不过经过了将近10年的发展，如今C#的生产力已经大大领先于Java语言，甚至在近几年的变革中已经成为了Java模仿的对象。本次交流会将回顾Java及C#语言的发展历程，基于它们的最新进展（C# 4.0和Java 7）对比两者在生产力上的差距，并演示C#领先于Java语言的一些常见编程模式。&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;直到现在，还有许多朋友认为，Java语言和C#的区别并不大，也有人认为C#只是语法糖比较多，没有什么特别的——而我现在便打算详细阐述&lt;font color="#ff0000"&gt;C#是如何改变开发人员编程理念及思维方式，并在生产力上大大超越Java语言&lt;/font&gt;。这是个大话题，在创新院分享会上耗时1小时40分钟，而在下周更是准备2个小时的时间（在这里感谢主办方的支持）。当然，如果只是这么一次演讲，其效果和影响力还是非常有限的。因此，我也打算在会后将这个内容详细地总结成一系列文章，除了发表在博客上，还会转载去一些Java开发社区，看看那儿的弟兄们对这个话题会怎么看。&lt;/p&gt;  &lt;p&gt;啥，您说我是去砸场的？不不不，到时候您就知道我的目的了。&lt;/p&gt;  &lt;p&gt;因此，我现在也希望您可以帮老赵个忙，例如告诉我国内比较著名的Java社区是哪些。目前我已经确定的有&lt;a href="http://www.javaeye.com/"&gt;JavaEye&lt;/a&gt;，不过有人告诉我其实那里最活跃的其实是Ruby社区。&lt;a href="http://www.csdn.net/"&gt;CSDN&lt;/a&gt;也是个不错的地方，毕竟那里是国内最大的程序员基地。&lt;/p&gt;  &lt;p&gt;哦，对了，还有一件事情请您帮忙：如果要将“Why Java Sucks and C# Rocks”翻译为中文，哪种译法会比较妥当呢？我目前还没有想出既有气势又不粗俗的翻译。我想这一系列文章的标题还是用中文比较合适。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-slides-final-version.html"&gt;幻灯片：Why Java Sucks and C# Rocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html"&gt;Why Java Sucks and C# Rocks（1）：比较的意义与目的&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/04/speech-why-java-sucks-and-csharp-rocks.html#comments</comments>
      <pubDate>Sun, 11 Apr 2010 08:49:57 GMT</pubDate>
      <lastBuildDate>Sun, 11 Apr 2010 08:49:57 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/life/">生活心情</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>Keynote，对不起，我爱的是PowerPoint 2007</title>
      <link>http://blog.zhaojie.me/2010/04/powerpoint-2007-vs-keynote-for-beginners.html</link>
      <guid>http://blog.zhaojie.me/2010/04/powerpoint-2007-vs-keynote-for-beginners.html</guid>
      <description>&lt;p&gt;两个月前&lt;a href="http://blog.zhaojie.me/2010/02/use-mac.html"&gt;我加入了水果党&lt;/a&gt;，使用至今，感觉挺好，尤其是触摸板的多点触摸功能令人着迷。一直听许多果粉说Mac系统在艺术设计方面表现一流，其办公套件&lt;a href="http://www.apple.com.cn/iwork/"&gt;iWork&lt;/a&gt;更是远胜于Microsoft Office，后者的流行完全是“劣币驱逐良币”的结果。耳濡目染之下我自然对此期待万分，于是在&lt;a href="http://www.openoffice.org/"&gt;Open Office&lt;/a&gt;及&lt;a href="http://www.neooffice.org/neojava/en/index.php"&gt;NeoOffice&lt;/a&gt;这两个免费的办公套件身上无法得到快感的情况下，兴冲冲地花费了近700块钱购买了一套正版的iWork。然后打开&lt;a href="http://www.apple.com.cn/iwork/keynote/"&gt;Keynote&lt;/a&gt;制作幻灯片，心想终于可以尝试一下超越PowerPoint 2007的产品了。可能是期望过高吧，初尝Keynote的感觉只能用“大失所望”来形容——而且，真的是我期望过高吗？&lt;/p&gt;  &lt;h1&gt;PowerPoint 2007&lt;/h1&gt;  &lt;p&gt;为什么会这样，那么还是从我用PowerPoint时养成的习惯说起吧。说起制作幻灯片，其基本功能自然就是写字，切换版式，套用模版等等，在这些方面Keynote和PowerPoint 2007没有太大区别。那么我为什么会对Keynote大失所望呢？主要还是在创建图示方面。显然，一个幻灯片不能只有文字，有的时候一副简洁明了的示意图能够更好的说明问题。而在这方面，PowerPoint 2007给我的感觉非常好。&lt;/p&gt;  &lt;p&gt;因为，它有SmartArt功能。&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-smart-art.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-smart-art.png" width="450" /&gt;&lt;/a&gt;   &lt;p&gt;Smart Art可以用来表示各种概念，例如列表、流程、循环等等。对于每一种概念，PowerPoint 2007都提供了许多不同的预定义图示，总共有一百多个不同的Smart Art形式。&lt;/p&gt;  &lt;p&gt;例如，我想表示一个循环，便可以选择如上的环绕方式。然后我们可以编辑它的每一项内容，编辑时会有即时预览：&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-circle-text.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-circle-text.png" width="450" /&gt;&lt;/a&gt;   &lt;p&gt;如果对这种样式不满意，PowerPoint 2007也为每一种Smart Art提供各种不同的表现样式，如平面的，三维的，空心的……同样包含即时预览：&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-circle-style.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-circle-style.png" width="450" /&gt;&lt;/a&gt;   &lt;p&gt;在选择了这种三维的方式之后，我们还可以选择不同的配色方案：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-circle-color.png" /&gt;   &lt;p&gt;最终，我只是使用了几次简单的文字输入，再加上一些鼠标点击，便完成一幅看上去还不错的示意图：&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-circle.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-circle.png" width="450" /&gt;&lt;/a&gt;   &lt;p&gt;即便不是Smart Art，在PowerPoint 2007里也为“形状”增加了预定义的样式，例如我随便拖出一个矩形，便可以选择：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-shape-style.png" /&gt;   &lt;p&gt;同样包括艺术字：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/ppt-text-style.png" /&gt;   &lt;p&gt;可以这么说，PowerPoint 2007为我节省了太多时间，我能够很轻松地制作出样式丰富的幻灯片来。&lt;/p&gt;  &lt;h1&gt;Keynote&lt;/h1&gt;  &lt;p&gt;第一次打开Keynote后会出现一个主题选择界面，很酷。然后我写了几页文字，换上一些版式，添加一些切换效果，感觉都挺不错。然后，我打算加一些图示，顺便体会一下传说中Mac软件中令人惊艳的效果……等等，类似于SmartArt的功能在哪里？&lt;/p&gt;  &lt;p&gt;真的没有，我仔细找过了。而且，我担心是因为我太笨太弱的缘故，我今天在公司里向一位常年使用Mac，并且十分鄙视MS Office的同事请教Keynote的用法，得到的答复是：这个可以有……这个真没有。&lt;/p&gt;  &lt;p&gt;于是我打开PowerPoint 2007（公司办公系统要求使用Windows，上面都安装了MS Office 2007），演示了一点点SmartArt和形状的预定义样式，想知道相似的功能应该如何在Keynote里完成。对方表示，MS Office的体验很差，而在Keynote中我们可以这么做：&lt;/p&gt;  &lt;p&gt;首先，只要点击工具栏上的Shape按钮便可以插入一些图形：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/keynote-shape.png" /&gt;   &lt;p&gt;然后可以打开Inspector，切换到Graphics栏目，这样就可以选择填充，渐变，线条，透明，三维等效果了：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/keynote-graphics.png" /&gt;   &lt;p&gt;然后颜色的选择方式也很丰富，很方便：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/ppt-vs-keynote/keynote-color.png" /&gt;  &lt;p&gt;然后，我们就可以用这些东西自行组成一幅示意图了，十分灵活！&lt;/p&gt;  &lt;h1&gt;这个……&lt;/h1&gt;  &lt;p&gt;客气地说……可能是我太笨了吧，我还是更喜欢PowerPoint 2007的做法；不客气地说法便是，我根本接受不了Keynote的使用方式。&lt;/p&gt;  &lt;p&gt;我是一个程序员，我可能会作不少的演示和报告，会用到不少幻灯片。但是，做幻灯片不是我的主业，我只想在有限的时间里能够很快地做出一个不错的效果来。我这里也枉自猜测一下，绝大部分的普通用户都和我一样，甚至他们不会像我一样地有耐心，为了追求几个像素的平衡不断调整。这点我想您看了我的博客皮肤就应该明白了——看上去应该还不错吧，它是靠我一个不懂HTML和CSS的人，通过不断查资料，提问题，然后再多个浏览器里不断尝试后的结果。同时我也完全禁止用户使用IE 6访问我的博客，原因之一便是我不打算为IE 6下的显示效果劳心劳力了。&lt;/p&gt;  &lt;p&gt;嗯，我让您看到的一定是“令我自己”满意的一面。&lt;/p&gt;  &lt;p&gt;是的，我承认，PowerPoint 2007能做到的效果，在Keynote中一定可以完成。毕竟所谓SmartArt也没有什么神奇的，不就是一些预定义的组合嘛，还有样式和配色等等都是十分简单的东西，在Keynote里完全可以对显示方式进行更细致的控制（不过细致的控制在PowerPoint 2007里就做不到吗？）。但这导致的结果便是，我用PowerPoint 2007便可以比较轻松地制作出如&lt;a href="http://www.slideshare.net/jeffz/real-world-aspnet-mvc"&gt;这个幻灯片中第5、8、10、21页的示意图&lt;/a&gt;——且拿上手立即可用；与此相反，用Keynote奋斗半天却只能搞出&lt;a href="http://www.slideshare.net/jeffz/why-java-sucks-and-c-rocks-midterm-draft"&gt;这种纯文字的幻灯片&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;是的，我承认我懒，我承认是我自己不会用Keynote，我知道Keynote中可以像Adobe Flash、Microsoft Expression Blend那样定制每个元素的运动轨迹，我承认一个Keynote高手可能比一个PowerPoint 2007高手更快地做出夺人眼球的幻灯片效果……但是这又如何呢？我只想在准备好内容的时候，有一个看上去不错的方式可以表现出我设想中的内容。在这方面，PowerPoint 2007要合适得多；在Keynote中，我必须自己选择3维效果的角度及深度如何，光源的方向，渐变的角度、起始和终止颜色。拜托，我不是美术人员，我无法自己想出这些高级货来，我只要你给我一些效果，我来评价好不好就行了！&lt;/p&gt;  &lt;p&gt;一个再强大的功能，也必须使用起来够简单才能被人广泛接受。Java中没有匿名函数，没有闭包吗？有，使用它的匿名类型可以得到差不多的效果。但是，&lt;a href="http://blog.zhaojie.me/2009/08/from-delegate-to-others-2.html"&gt;因为它的语法太嘈杂，就根本不像C#那样可以将函数式编程，声明式编程推广开来&lt;/a&gt;——事实上，这也是直到C# 3.0中出现Lambda表达式这种简单、优雅地匿名函数定义方法之后才出现的结果。同样道理，有人认为“LISP之后，再无创新”，但是LISP这门在语言学术研究，理论界如此完美、自洽、优雅的语言，就没有广泛被人接受呢？这主要还是因为LISP虽然“什么都能做”，但是“什么都做不容易”，因此人们还是更接受在它之后的那些理念“窃取者”……咳咳，推广者。而事实上，上世纪90年代，以Java为代表的语言，其设计目的便是降低开发难度，而到了本世纪后，语言的进化及流行，也都是在易用的基础上提高生产力——它们的代表便是C#及Ruby等。至于LISP……它永远是广大语言设计者的偶像，但在我看来，它也永远只能是广大语言设计者的偶像了。&lt;/p&gt;  &lt;p&gt;因此，我认为Keynote远不如PowerPoint 2007适合初学者。我将这话发在推特上之后，&lt;a href="https://twitter.com/CatChen"&gt;@CatChen&lt;/a&gt;同学提出了一些不同意见，我在这里一并列举一下，也附上我的答复：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;如果有些东西在Keynote里不容易做，那么就要好好考虑这些东西是不是真的有必要了：&lt;/strong&gt;在我看来，这句话和当年&lt;a href="http://www.cnbeta.com/articles/76147.htm"&gt;王垠对Windows和Linux的著名评价&lt;/a&gt;十分相似，那便是“Windows能干而Linux干不了的事情，那就是不需要干的事情”。如果要说这句话有道理，那么它的前提必须是您已经是Linux / Keynote的专家了——此时您做不到的东西，我相信基本也就是没有必要的事情了。&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;看一些著名的Keynote吧，或者看看Jobs是怎么用Keynote的：&lt;/strong&gt;即便如此又如何呢？它们都不是初学者能搞定的，我要做成那样还得先投入不少精力去学习Keynote，甚至美术设计、人机交互方面的东西。Jobs能用好Keynote很正常，他是产品设计的天才，如果他能代表普通人的话，那么我也可以作为广大果粉的偶像了，不是吗？&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;建议去读一下《&lt;/strong&gt;&lt;a href="http://www.amazon.com/Presentation-Zen-Simple-Design-Delivery/dp/0321525655"&gt;&lt;strong&gt;Presentation Zen&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;》，幻灯片和讲稿应该有所区别：&lt;/strong&gt;我没有读过Presentation Zen，但是我看过蔡学镛写的“&lt;a href="http://www.slideshare.net/Fenng/caffeinenicotine"&gt;不瞌睡的简报设计模式&lt;/a&gt;”，但是按照其中的道理，一份幻灯片的关键在于内容的组织，图片和文字的搭配等等，并不需要Keynote所提供的丰富效果（要知道很多幻灯片甚至是使用pdf格式提供的）。从这个角度来说，就我对PowerPoint 2007的粗浅了解（没学过，直接上手就用），从技术角度来说也已经足够了。&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;如果说PowerPoint 2007的面向群体是普通人的话，那么Keynote的理想用户就应该是——艺术家了吧。&lt;/p&gt;  &lt;p&gt;最后，也有朋友向我推荐说，在SmartArt这方面&lt;a href="http://www.omnigroup.com/products/OmniGraffle/"&gt;OmniGraffle&lt;/a&gt;可谓是神器。看了看，的确相当不错——只要我再拿出100多美元就可以了。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/04/powerpoint-2007-vs-keynote-for-beginners.html#comments</comments>
      <pubDate>Thu, 08 Apr 2010 10:35:17 GMT</pubDate>
      <lastBuildDate>Thu, 08 Apr 2010 10:35:17 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>如何成为一名优秀的博主（PPT）</title>
      <link>http://blog.zhaojie.me/2010/03/how-to-become-a-good-tech-blogger.html</link>
      <guid>http://blog.zhaojie.me/2010/03/how-to-become-a-good-tech-blogger.html</guid>
      <description>&lt;p&gt;如何成为一名优秀的博主？这是一个问题。我一直到处建议别人写博客，写技术博客，但是还真没想过或总结过这个问题。上个星期微软“社区精英计划”讲解了微软内部关于撰写优秀博客的一些方法和注意事项——同时微软的朋友也希望我分享一下我的经验，于是我制作了这份PPT。后来发现，我写的内容和微软的内部资料倒有相当部分不谋而合的地方，自然微软的资料更为美观，图示丰富，而我的内容则相对更有山寨的感觉。&lt;/p&gt;

&lt;p&gt;在PPT中我多次强调这么一样东西：“社区是盲目的”。再加上一些“技巧性的”东西，从这方面看来似乎我把写博客作为一种有些功利的事情。其实我的考虑是这样的：我写博客是种兴趣爱好，不过既然是在“社区精英计划”里进行推广，就不能假设人人都像我一样。“精英”也需要吃饭，功利点并不是错，不是吗？&lt;/p&gt;

&lt;p&gt;以下便是此次内容的PPT：&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_3571087"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="如何成为一名优秀的博主" href="http://www.slideshare.net/jeffz/why-blogging"&gt;如何成为一名优秀的博主&lt;/a&gt;&lt;/strong&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=why-blogging-100327080618-phpapp02&amp;stripped_title=why-blogging" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=why-blogging-100327080618-phpapp02&amp;stripped_title=why-blogging" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;最后，再次希望大家加入技术博客创作的队伍。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/03/how-to-become-a-good-tech-blogger.html#comments</comments>
      <pubDate>Sat, 27 Mar 2010 13:42:42 GMT</pubDate>
      <lastBuildDate>Sat, 27 Mar 2010 13:42:42 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>谈谈微软技术，以及对待技术应有的态度</title>
      <link>http://blog.zhaojie.me/2010/03/microsoft-technology-and-the-attitude.html</link>
      <guid>http://blog.zhaojie.me/2010/03/microsoft-technology-and-the-attitude.html</guid>
      <description>&lt;p&gt;昨晚在家上网，看看&lt;a href="http://research.microsoft.com/c/1078/en-us/events/techfest2010/default.aspx"&gt;微软研究院TechFest 2010&lt;/a&gt;的消息，逛逛&lt;a href="http://channel9.msdn.com"&gt;Channel 9&lt;/a&gt;，瞅瞅&lt;a href="http://msdn.microsoft.com/en-us/devlabs/default.aspx"&gt;DevLabs&lt;/a&gt;里的项目，以及F#与&lt;a href="http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx"&gt;Reactive Framework&lt;/a&gt;之类东西。然而，我一边对那些有趣而奇妙的技术感叹不已，同时却又产生出一种忿忿之情。为什么？因为在国内的技术圈子里，经常有一种在我看来莫名奇妙的鄙视微软技术的风气。这样的风气在国内的推特圈里也非常明显，基本上只有我一个人对微软的技术抱有好感，并“勇于”和大量意见向左的人争辩。忿忿之余，我便在推特上不断表达我对这种风气的抱怨及否定，在这个过程中也基本表达了我在这方面的大部分看法，在这里也进行一番总结总结吧。同时，我也想对微软社区的许多弟兄讲一些话。 &lt;/p&gt;  &lt;p&gt;现在有这么一个群体叫做“Microsoft Hater”，他们的表现出对微软十足的敌视，在他们眼中，微软的一切都是恶劣的，凡是微软的就要抵制，微软的任何产品任何技术都不值一提，因为微软本身就是一家没有技术的小公司，只是靠商业手段而成功的小公司。在他们眼里，但事实真是如此吗？是的，我不否认微软的成功有相当部分是商业上的运作，毕竟像Sun公司那样孕育了无数优秀技术的公司最后还是走上落没之路。但是我在这里还是想告诉那些Microsoft Hater们，在许多方面微软的技术绝对是值得钦佩的。 &lt;/p&gt;  &lt;p&gt;我有时候很不了解一些人的逻辑，他们经常说微软技术差，没有创新。但是，微软那么多科学家搞出来的LINQ，Reactive Framework，Parallel Library，F#等等，哪个不是创新，哪个不是开发方式上的突破呢？是的，在一定程度上我同意微软在商业方面常常是个后来者，它在产品上的创新似乎并不突出。但是，我相信所有人都能够明白一个道理：产品和技术是两码事，技术优秀并不是产品优秀的充分条件，反之一个创新产品背后的技术也可能已经被运用了无数多次。如果从技术角度来说，微软的创新绝对不少。但问题就是，您关注了吗？ &lt;/p&gt;  &lt;p&gt;在争辩的过程中，我时常发现对方其实并不重视微软技术——有时他们也会表示根本不在乎这些。诚然，不关注微软技术，对于一个技术人员来说也是十分正常的事情。但是，如果在不关注，不了解的同时，却还自信满满地坚持微软没有优秀技术，这便让我难以接受了。再者，由于多年不关注微软的技术发展，有些弟兄也会拿某某领域在如今的发展与微软在5年甚至更早前的情况进行比较，以此证明微软技术有多么糟糕。但是，可能在另一场争论中，他们又会认为微软技术发展得太快——那么到底什么才是真实的情况呢？ &lt;/p&gt;  &lt;p&gt;事实上，我们可以发现，在各种技术大会上都能看到微软的身影，微软更是世界知名的科研“大户”，这正说明业界顶级技术领域也是承认微软技术实力的。在业界有许多著名的科学家，他们的贡献非常令人瞩目。但是在某些人眼里，他们一旦到了微软，接下来的工作也就没有价值了。几年前在学校BBS与人吵架时，我还听说过这样的说法：那些人不能算是微软的，他们都是微软从别处挖来的，所以微软还是没有技术。但是他们却没有想过，他们所爱戴的谷歌公司，却也特别喜欢从微软挖人。甚至可以这么说，在谷歌里有几个人不是挖来的呢？好吧，俗话说“爱她就要包容她的一切”，我相信Microsoft Hater们一定都是好男友，好丈夫。 &lt;/p&gt;  &lt;p&gt;不过也有人会这么说：微软研究院和微软的技术水平并没有关系。微软研究院只能看作是微软对IT业所建立的“慈善机构”，或是微软开办的大学，与微软“自身”的技术水平关系并不大。但事实上，微软的技术大都是由研究院发起或指导的，譬如我之前提到的每个技术都是这样，无一例外。微软不是傻子，它为什么要出钱出力不求回报，它最强的地方不就是商业手段吗？如果您关注一些微软相关的资料，例如Channel 9或&lt;a href="http://microsoftpdc.com/"&gt;PDC大会&lt;/a&gt;，就会发现讲解我们那些常用技术的，许多都是研究院的科学家。例如，F#的设计者之一&lt;a href="http://research.microsoft.com/en-us/people/dsyme/"&gt;Don Syme&lt;/a&gt;&lt;strike&gt;也是Haskell语言的主要设计者&lt;/strike&gt;（经人指出是我搞错了，Haskel语言的设计者是微软研究院另一名科学家&lt;a href="http://research.microsoft.com/en-us/people/simonpj/"&gt;Simon Peyton-Jones&lt;/a&gt;），而站在.NET平台GC背后的&lt;a href="http://www.microsoft.com/presspass/exec/techfellow/dussud/default.mspx"&gt;Patrick Dussud&lt;/a&gt;在加入微软之前，也一直在LISP运行时等领域耕耘。微软研究院的技术实力并不是空中楼阁，其中许多都是实实在在体现在微软的技术中。&lt;/p&gt;  &lt;p&gt;我承认，微软的很多东西都有问题，因此我也从来不为Vista辩护。我也喜欢开源，支持开源，从来不会在任何场合支持微软的封闭策略。总而言之，我从来没有昧着良心去为微软做广告，写软文。我甚至也对&lt;a href="http://blog.zhaojie.me/2009/07/embarrassed-mvp.html"&gt;国内微软MVP有太多名不符实的情况&lt;/a&gt;提出过质疑。既然微软有那么多不好的地方，但我为什么喜欢微软技术？因为我是个纯粹的技术人员，我了解微软有着多么优秀的技术，如果放弃这些我一定会心有不甘。同理，我也会去接触微软平台之外的技术以及各种优秀的东西。例如，在推上听到很多人说Mac是多么多么好，即便某些地方略显偏激，但的确也表达了他们的真实想法和相当部分的真实情况。于是，我为了更深一步理解他们的说法，也找个机会&lt;a href="http://blog.zhaojie.me/2010/02/use-mac.html"&gt;加入了水果党&lt;/a&gt;。然后，即便用得不爽也努力地unlearn在Windows下的各种习惯，不以此认为是Mac的缺点。学习新东西，我可以理解这种情况。 &lt;/p&gt;  &lt;p&gt;我现在感到不爽的原因，实在是觉得微软那么多好技术，却没个讨论的地方，这算是什么状况！在我看来，仇视微软不是个正确的技术氛围，推上那么多nb的技术高手，舆论氛围为什么却是一边倒？我“发飙”也不是因为微软被鄙视了，而是我认为太多技术人员鄙视微软的手段实在不够技术化。Linus也曾经说过：&lt;a href="http://www.linux-mag.com/cache/7439/1.html"&gt;仇视微软是一种病（I think the Microsoft hatred is a disease）&lt;/a&gt;。在我看来，很多时候我们的技术氛围的确有些病态。 &lt;/p&gt;  &lt;p&gt;我还是想说那个经典到有些老掉牙的案例。在很多年前，业界普遍存在的观念，便是“.NET平台不适合实现动态语言”，这是因为之前ActiveState公司实现Python后发现性能太差。但是，Jython的创建者&lt;a href="http://hugunin.net/"&gt;Jim Hugunin&lt;/a&gt;认为，既然JVM上实现Python语言的效果不差，为什么同样在原理类似的CLR平台上却有不一样的结论呢？于是他便开始关注.NET平台，关注CLR，并且尝试实现一个Python原型，希望找出.NET平台不适合动态语言的原因。但是最后的结果令人惊讶，因为在标准的pystone评测中，Python在CLR上的性能表现甚至比C语言的Python实现有很大领先（这个故事的更多情况，请参考&lt;a href="http://www.codeplex.com/wikipage?ProjectName=IronPython&amp;title=v1.0%20Release%20Notes"&gt;IronPython 1.0的发布信息&lt;/a&gt;）。 &lt;/p&gt;  &lt;p&gt;后来，Jim加入了微软的CLR小组，为了得到更好的&lt;a href="http://www.codeplex.com/IronPython"&gt;IronPython&lt;/a&gt;实现，也努力让CLR成为一个更好的运行时。因为IronPython的突破，后来又有了&lt;a href="http://ironruby.net/"&gt;IronRuby&lt;/a&gt;，最后又总结出动态语言实现的通用基础类库&lt;a href="http://www.codeplex.com/dlr"&gt;DLR&lt;/a&gt;。而在我看来Jim最了不起的地方在于，他努力使IronPython，IronRuby和DLR都保持完整的开源（使用通过OSI认证的&lt;a href="http://www.opensource.org/licenses/ms-pl.html"&gt;MS-PL开源协议&lt;/a&gt;）。我们现在也可以发现，微软后来的各种框架/类库，包括ASP.NET MVC，F#等等都是MS-PL开源的，说不定其中也有受到Jim的影响在里面。 &lt;/p&gt;  &lt;p&gt;好，那么我们来做个假设。如果Jim当年和许多Microsoft Hater一样对微软抱有敌视态度——而且理由很充分：“已经有人“证实”了.NET是个垃圾平台”——那么，世界上就不会有IronPython，IronRuby或是DLR。再假如，如果Jim在加入了微软之后，没有坚持自己的态度，让IronPython等项目就此闭源，那么我们也无法如此轻易地学习到这些美妙的技术。Jim对于技术所保持的这种纯粹，才是真正推动技术进步的手段。与此相比，靠耍嘴皮子来敌视微软算个毛本事？ &lt;/p&gt;  &lt;p&gt;其实我也能够部分理解某些人的看法。例如昨天有朋友这样说到： &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;回顾下微软的商战史，对Linux的打压，企图收购WPS时的高傲姿态之后，就一点不会觉得微软冤枉。微软技术牛谁都清楚，但恐怕对这里的人对微软进行口碑反营销够不成什么影响。这个过程理性是次要的，掀起一阵弃用微软的潮流才是目的。 &lt;/p&gt;    &lt;p&gt;微软的东西在有些层面上确实高效方便，甚至对很多企业和个人扮演救世主的角色。但当你要产业链中向上跻身的时候，早晚有一天微软会变成一个恶魔，四处围剿你的产品。因此作为任何一个有远见的从业者，都是无法坦然的接受这种IT财阀的存在的。 &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;而我的看法依然没变：我没有对微软进行口碑营销，我只是在谈技术，我只是不想技术被其他东西淹没了。我也没有打算让任何人喜欢微软的商业文化，我只想谈论技术——作为技术人员，为什么要让商业来盖过技术？借鉴技术，交流技术才能发展技术。我现在只是希望不喜欢微软商业的人，也能够正确对待微软的技术。即便是自由教主RMS，他也仅仅是在商业或是软件版权问题方面向微软发难，而从没有像许多Hater那样认为“微软的技术都不值一提”。&lt;/p&gt;&lt;p&gt;此外，技术也是相通的，我相信微软今天倒了，下个星期我就能去开发Java，开发Rails，开发Django。我有自信可以比无数不了解HTTP协议，不知道Web开发规律的人要厉害。同样，我相信让某些牛人来搞.NET，不出一个月肯定能比8成博客园的弟兄要强大许多。为什么谷歌当年要从微软大量挖人？是因为谷歌在使用微软的技术，还是微软在使用谷歌的技术？那些熟悉微软技术的牛人们，难道不也是立即转向某些人眼中“截然不同”的领域吗？我认为其中的道理已经再清楚不过了。&lt;/p&gt;  &lt;p&gt;我写了这么多，其实也并非只在对Microsoft Hater们表态。事实上，我在推特上遇到的技术达人们并非我之前描述的那么夸张。他们虽然不喜欢微软，但是大都还是理性的，和他们的辩论过程中我也了解到很多其他技术的优秀之处，对我帮助很大。接下来，我就想谈一下我对微软技术社区的一些不满之处了。 &lt;/p&gt;  &lt;p&gt;博客园是国内微软技术的标杆，这点毋庸置疑，但从中我们可以观察到另外一些倾向。一是盲目自卑，二是盲目自信。两者其实是统一的：前者不了解微软技术（或只了解一小个侧面），认为微软技术不过尔尔，没有竞争力，而后者却认为微软实力天下无敌，或是每样技术都是完美无缺。这些也都是闭塞的表现。微软不是一个整体，它是由许多个人和团队组成的，这些团队的实力和成果各有高低，几乎任何一概而论的判断都是不妥当的。&lt;/p&gt; &lt;p&gt;我认为，作为一个优秀的技术人员，一定要放开视野，吸收各种技术的优秀之处，取长补短，这样才能有所发展。喜欢一门技术不要紧，对一门技术有倾向性也不要紧，这才构成了多元化的世界。甚至，我认为这也是技术发展的要素之一，因为只有喜欢一门技术才想要真正去发展这门技术。从某个角度来说，盲目敌视外部世界往往也不是真粉丝们的表现，因为这样的人是很难对技术发展做出贡献的。&lt;/p&gt;  &lt;p&gt;闭塞还导致了另一种现象：某些朋友先是对微软技术抱有盲目乐观的态度，但是忽然有一天，在发现微软技术也有其局限性（这难道不是必然的吗？）之后大失所望，于是转向另一个平台再开始鄙视微软技术。这就好比一个极端的理想主义者，在思想收到冲击之后变成一个极端的虚无主义者。无论走哪种极端都是不对的，而且，如果从一开始就保持良好的视野和心态，便可以各取所长，同时享受多个平台的技术优势。&lt;/p&gt;  &lt;p&gt;至少在目前看来，至少在国内，我认为微软平台的技术人员还是太闭塞了，比微软外的技术人员要封闭许多。举个实例，我的真实体会，为什么作为一个微软平台的技术人员，在推特上我总是很少见到博客园的各位呢？ &lt;/p&gt;  &lt;p&gt;弟兄们赶快打开视野吧，就从上推特开始吧，&lt;a href="https://twitter.com/jeffz_cn"&gt;我在那里等着你们&lt;/a&gt;。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/03/microsoft-technology-and-the-attitude.html#comments</comments>
      <pubDate>Thu, 04 Mar 2010 15:20:00 GMT</pubDate>
      <lastBuildDate>Thu, 04 Mar 2010 15:20:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>哥谈的是语言，不是寂寞</title>
      <link>http://blog.zhaojie.me/2010/02/programming-languages-platform.html</link>
      <guid>http://blog.zhaojie.me/2010/02/programming-languages-platform.html</guid>
      <description>&lt;p&gt;经常看到一些文章在谈论语言，例如“哪个语言更有前途”，“语言选择是否关键”。我是个语言粉丝，但是看到这些文章总有一些奇怪的感觉。因为在我看来，这些文章谈的东西都不是我眼中的语言——可能与国内技术环境有关，语言本身被淡化了，例如，谈语言的时候涉及更多的却是“平台”方面的内容（例如冯老大的《&lt;a href="http://www.dbanotes.net/review/choose_programming_languages_important.html"&gt;编程语言的选择并非无关紧要&lt;/a&gt;》）。那么我现在便来描述一下我眼中的“语言”该如何谈论吧——下次在我猛砍Java语言时也好有个参考。&lt;/p&gt;  &lt;h1&gt;语言&lt;/h1&gt;  &lt;p&gt;语言是给人看的，人们设计出各种各样的语言，最终会通过某些工具变成机器可以执行的形式。人们设计出语言，是为了进行大规模的程序开发，否则使用机器码来0110着写，估计只有神仙才能写出如今动辄数十万数百万行高级语言的项目来——即便是“高手”也得用汇编哪。但可惜的是，如果仅仅使用汇编，估计程序员的思维永远无法跳出“子过程”这个抽象级别，什么面向对象设计，函数式编程几乎无从谈起。人们在学习和生产过程中会引发一些需求，因而需要产生一些工具来辅助学习和生产，而“语言”便是此类工具之一。只有利用高级语言，人们才能有效地把真实世界抽象成计算机这些机器盒子能认识的东西。&lt;/p&gt;  &lt;p&gt;显然，不同的语言适合不同的领域——尤其是那些所谓的“&lt;a href="http://en.wikipedia.org/wiki/Domain-specific_language"&gt;领域特定语言（Domain Specific Language）&lt;/a&gt;”，因为在不同领域中所需要的思考方式可能会不一样，对于语言来说就有特定的抽象方式与之应对。不过，对于广大程序员来说接触到的更多的应该是“&lt;a href="http://en.wikipedia.org/wiki/General-purpose_programming_language"&gt;通用目的语言（General Purpose Language）&lt;/a&gt;”，例如C，C++，Java，C#，Ruby，Python，F#……它们都是通用目的语言。对于这些语言来说，它们是为了解决广泛问题而存在的。当然，由于通用目的语言的语言特性不同，它们也是有一定“倾向性”的。例如，F#的Workflow特性尤其适合异步编程，而函数式编程语言可能更适合科学计算或金融方面的应用，因为它们和那些问题（业务）的思维方式比较接近——假如使用Java这样的面向对象语言来说可能就要使用一些奇怪的模式了。&lt;/p&gt;  &lt;p&gt;因为语言是用来解决问题的，因此在谈论语言的时候，其实我们主要还应该把关注点放在语言抽象或描述事物（包括“思维”等等）的能力上面，以及用它们解决问题的时候是否方便，是否“舒适”——这可能有“感觉”的因素在里面，但的确也有一些客观的，可以衡量的标准在里面。例如《&lt;a href="http://www.amazon.com/Concepts-Programming-Languages-Robert-Sebesta/dp/0136073476/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1266666448&amp;sr=8-1"&gt;Concepts of Programming Languages&lt;/a&gt;》一书中就提出了以下一些标准：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;可读性：&lt;/strong&gt;读代码的次数比写代码要多得多，可读性自然是非常重要的评判标准。例如Perl语言就比Python要难读的多，可谓是一种著名的&lt;a href="http://en.wikipedia.org/wiki/Write-only_language"&gt;Write Only语言&lt;/a&gt;。 &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;可写性：&lt;/strong&gt;例如，使用Fortran 77这种不支持指针和动态内存管理的语言中，实现一个二叉树结构会很困难。还有，虽然使用while可以实现任何循环需求，但是没有for语句的语言写起来便会麻烦不少。此外，表达同样的逻辑，代码是否紧凑？如C#或Java等需要相当“架子代码”的语言，同样实现面向对象编程就不如F#或Scala来的紧凑。 &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;可靠性：&lt;/strong&gt;语言特性是否易于写出正确可靠的代码，如异常处理，静态/动态类型，强/弱类型都是和可靠性有关的特性。此外，一些脚本语言，如PHP或JavaScript中经常被人诟病可靠性不佳，便是由于一些操作（如相等或相加操作）过于“宽容”，容易出错。 &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;代价：&lt;/strong&gt;例如，语言规则是否太多？是否自然？学习起来是否容易？ &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;通俗来讲，我们考察语言，关注点应该放在它的“语言特性”上。语言特性哪里来？自然是语言制定时定下的，例如&lt;a href="http://java.sun.com/docs/books/jls/"&gt;Java&lt;/a&gt;和&lt;a href="http://msdn.microsoft.com/en-us/library/aa645596(VS.71).aspx"&gt;C#&lt;/a&gt;都有其规约（Specification），其中定制了关于语言的方方面面。但是如Ruby和Python，它们都只有各自的“参考实现”（CPython及MRI），并没有明确的规约文档——有人认为这是个比较重要的问题，因此如Ruby社区便开展了&lt;a href="http://rubyspec.org/"&gt;RubySpec&lt;/a&gt;项目希望定制一个严格的Ruby语言规约。&lt;/p&gt;  &lt;p&gt;我认为，&lt;font color="#ff0000"&gt;语言规约&lt;/font&gt;（再扩大一点，也仅仅包括其&lt;font color="#ff0000"&gt;标准&lt;/font&gt;库）&lt;font color="#ff0000"&gt;是讨论语言，比较语言的唯一依据&lt;/font&gt;——这也是我在谈论语言（如讨论Java语言之低劣）的思考准则。&lt;/p&gt;  &lt;h1&gt;平台&lt;/h1&gt;  &lt;p&gt;当然，语言设计的最终目的是让计算机进行计算，因此我们不可能回避其他方面，仅仅谈论语言规约。我这里把除了语言规约外语言实现的其他方面统称为“平台”。因此，这个平台其实包括多种东西，例如：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;将程序文本转化为二进制形式的：&lt;font color="#ff0000"&gt;编译器&lt;/font&gt;（包括解释器，Linker等等）。打个比方，主流C++编译器有VC++，GCC；C#编译器也有微软实现的CSC及Mono上的MCS。同样的源文件交由不同的编译器，得到的结果会有不同，而最终也会影响程序性能等因素。但是，我们可以简单认为，这些编译器最终生成的结果是符合一个统一标准的，也就是说它们得到的结果可以用相同的规则来识别与执行。&lt;/li&gt;    &lt;li&gt;&lt;font color="#ff0000"&gt;运行时&lt;/font&gt;也是平台的重要组成部分。例如，使用微软的CSC编译出的程序集可以在微软的CLR或Mono提供的运行时上执行，同样Sun的Java编译器生成的Byte Code也可以在Sun和IBM两种JVM上运行。由于运行时实现不同，所涉及的标准库也有不同，其程序执行的性能和稳定性都会有所区别。&lt;/li&gt;    &lt;li&gt;在不同的执行环境下，可以利用的周边事务是不同的。例如，IronPython便非常容易和.NET程序进行互操作，而JRuby便可以利用Java平台上的各类框架。而一个C语言程序本身也是一个合法的Objective-C程序，但是在Mac OS X上编写Cocoa程序利用的也是不同的环境（不确定，求证）。&lt;/li&gt;    &lt;li&gt;技术以外的方面，如社区活跃度等等。&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;当然，上面举的编译器和运行时都是最为典型的例子。事实上，很多平台并没有如此明显的划分，它们的编译器和运行时都是一体的。例如Python语言的实现有传统的CPython，.NET平台上的IronPython，Java平台上的Jython，以及追求比CPython更高性能与灵活性的PyPy。此外，JavaScript语言除了在各浏览器引擎中不同的原生实现外，现在又有了神奇的&lt;a href="http://nodejs.org/"&gt;Node.js&lt;/a&gt;，可以在服务器端使用JavaScript编写高性能的服务器端程序。&lt;/p&gt;  &lt;p&gt;当我们谈论到一门语言“能做什么”，“性能如何”时，往往就是在讨论的就不（仅仅）是语言，而是平台了。语言里的概念和平台实现并非完全相关，例如在Scala语言中，1 + 2并不是一个表达式，它其实表示的是1.+(2)，也就是一个整型对象上的“加”方法的调用。但是在编译器的实现上，出于性能考虑就会尽量将其编译成原生的整数加法操作。当然，语言中的很多部分也在真切地影响其平台相关的部分，例如C语言的目标是系统语言，因此便尽可能的接近计算机体系结构，没有高级的语言特性，要把很多细节都交由程序员去控制。而如C#或Java这样的语言，从语言特性上就注定了其执行环境需要GC能力，这样对于一些空间密集型的场景可能就比不上如C语言般精细控制所带来的性能；同样，C/C++这样的语言可能并不适合高性能计算，因为它的语言设计注定了会遇上“&lt;a href="http://en.wikipedia.org/wiki/Alias_analysis"&gt;别名检测（alias detection）&lt;/a&gt;”方面的问题，于是编译器便无法像一些无副作用的函数式编程语言那样进行自动并行，或者生成充分利用系统缓存的高性能指令。&lt;/p&gt;  &lt;h1&gt;吵架&lt;/h1&gt;  &lt;p&gt;以上，我承认语言与其平台其实有着密切联系，&lt;font color="#ff0000"&gt;但是在很多情况下我们可以忽略平台而仅仅谈论语言&lt;/font&gt;。&lt;/p&gt;  &lt;p&gt;例如，因为CLR和JVM的性能和可靠性是相同的（您有不同意见？嘿嘿，这里不讨论这个），所以我们便可以比较C#与Java（甚至F#与Scala）；因为Rails和Django的能力不分上下，因此我们可以比较Ruby和Python语言在业务逻辑实现方面的优劣；因为它们都在JVM上执行，因此我们便可以引发Java，Scala，JRuby，Jython，Jaskell，Groovy及Clojure的混战。由于我们“求同”，那么“存异”也就有了意义，因为此时语言也是进行技术选型的重要方面了。&lt;/p&gt;  &lt;p&gt;语言引发的争吵不计其数，这点有目共睹。我写这篇文章的目的也是希望可以减少这方面的无谓争论。例如我在猛砍Java时，有朋友会回应到：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;做项目不能只考虑语言——没错，这并不影响我说Java语言差，我也不想以此让您来用.NET。&lt;/li&gt;    &lt;li&gt;JVM成熟——没错，但这并不代表Java语言就好了，您可以用Scala，Clojure等语言。&lt;/li&gt;    &lt;li&gt;语言不重要，谈语言层次太低了——呃，吵不过您，我妈叫我回家吃饭，吃好饭我就洗洗睡了。&lt;/li&gt;    &lt;li&gt;……&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;其实有时候，我也只是想单纯讨论一下语言罢了——&lt;font color="#ff0000"&gt;哥谈的是语言，不是寂寞&lt;/font&gt;。&lt;/p&gt;  &lt;h1&gt;广告时间&lt;/h1&gt;  &lt;p&gt;大腕云集的&lt;a href="http://www.qconbeijing.com/"&gt;QCon Beijing 2010&lt;/a&gt;又要开始了，本次QCon更增加了语言这个主题：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;以前，语言还几乎等同于平台，选择了平台也就自然而然地确定了语言。如今，在相同的平台或运行时上已经有多种成熟语言可供选择。以前，语言常被认为是一种单纯的工具。如今，语言更进一步被赋予了文化的意味。正因为如此，目前越来越多的团队在语言的选择上投入了更多的考虑，甚至已经在多种语言的混合编程上获得了成功经验。那么，您是否想了解他们为什么选择这门语言，他们在语言的设计、选择或使用方面又有哪些体会的呢？相信这部分内容可以让您满意。&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;继去年大受好评的“豆瓣网架构变迁”之后，洪强宁将带来Python语言在豆瓣网中的使用案例。同时，被孟岩誉为年轻一代四大高手的邓草原也会比较Scala与Erlang两者的Actor模型在生产环境下的效果。此外还有一些不知名的老外，如Paul King（Groovy顶级贡献者、《Groovy In Action》的作者）会讨论“动态语言的敏捷开发实践”及“Groovy中的强大功能”，JCP主席Patrick Curran也会来谈论有关一致性测试方面的话题。&lt;/p&gt;  &lt;p&gt;现在拨打订票热线还可以享受XXXX的优惠，机不可失，失不再来，您还在等什么，还不赶快订票？&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/02/programming-languages-platform.html#comments</comments>
      <pubDate>Sat, 20 Feb 2010 13:48:00 GMT</pubDate>
      <lastBuildDate>Sat, 20 Feb 2010 13:48:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/life/">生活心情</category>
      <title>总结：史上第一混乱、程序员的爱情、Nobody &amp; Sorry Sorry</title>
      <link>http://blog.zhaojie.me/2010/02/play-novel-nobody-sorry-sorry.html</link>
      <guid>http://blog.zhaojie.me/2010/02/play-novel-nobody-sorry-sorry.html</guid>
      <description>&lt;p&gt;星期六是我的休息日，这天一般我不安排自己做什么和工作有关的事情，一般就是去看看电影，出去逛逛，或者在家上上网吹吹牛。昨天&lt;a href="http://blog.zhaojie.me/2010/02/0-bug-and-sjtu-acm-champion.html"&gt;总结&lt;/a&gt;了一部分由&lt;a href="https://twitter.com"&gt;推特&lt;/a&gt;上的讨论，现在继续剩下的一部分。不过，这次的内容可能就要和技术或产业略远一些了，其中大部分是我自己的一些体会和感想。现在我打算谈三个东西，一是《史上第一混乱》这部话剧，《程序员的爱情》这本小说，以及Nobody和Sorry Sorry（您不知道这是啥？你成奥特曼啦！）。&lt;/p&gt;  &lt;h1&gt;史上第一混乱&lt;/h1&gt;  &lt;p&gt;上周五公司开年会，其间我侥幸拿下喝啤酒比赛第一，赢得价值300元的电磁炉一个——这还是整场年会中唯一比蛮力的项目，我那个自豪啊。呃，扯远了，其实下一件事才和我要谈的事情有些联系。那就是后来我又在年会上表演节目，唱了两首歌，因此拿到了昨天晚上《史上第一混乱》话剧的门票。至于为啥是这个话剧，后来我才意识到原来这个话剧改编自盛大文学旗下&lt;a href="http://www.qidian.com"&gt;起点中文网&lt;/a&gt;上的&lt;a href="http://www.qidian.com/Book/174075.aspx"&gt;同名小说&lt;/a&gt;，如此说来盛大准备几张该话剧的门票自然就顺理成章了。&lt;/p&gt; &lt;img class="floatRight" src="http://img.zhaojie.me/blog/ssdyhl.jpg" /&gt;   &lt;p&gt;昨天下午先去看了场电影，锦衣卫，甄子丹演的，我对于此类动作片的兴趣始终不减，不过看完后倒也没有什么留下什么深刻的印象。看完后吃了晚饭，发现时间尚早，想票子不要浪费了吧，于是便去看了这场话剧。座位不太好，第一排，需要一直仰着头。不过由于距离够近，因此可以清晰地看到演员横飞的唾沫星子，还有演女人的mm身材也不错，腿细胸大的。&lt;/p&gt;  &lt;p&gt;提起话剧内容，您可以将其理解为是一个非常单纯的，不包含任何思想在内的，完完全全的无厘头闹剧。总之，就是把最近各种流行的玩艺儿，笑话，网络词，广告串在一起。虽说笑果扑面而来，但听得多了倒也会有些疲劳——因此某些情况下其他观众哈哈大笑的时候我却有点无动于衷。不过也有不少地方挺有创意的，虽说都是耳熟能详的东西，但是在令人意想不到的地方跑出来确实也有眼前一亮的感觉。其中也有很多桥段在为80后的童年生活致敬，如蓝精灵，葫芦娃，黑猫警长，北斗神拳，颇为亲切。&lt;/p&gt;  &lt;p&gt;按常理说我不太会喜欢这样的东西，不过可能是由于事先已经了解过这部话剧/小说的背景，再加上“童年回忆”的影响，我倒也并不讨厌这部话剧（但也没推荐啊）。事实上，可能的确是由于平时天天山珍海味，忽然来了一顿粗茶淡饭似乎也别有一番风味。前一段时间&lt;a href="http://blog.tianya.cn/blogger/post_show.asp?idWriter=0&amp;amp;Key=0&amp;amp;BlogID=41917&amp;amp;PostID=19055487"&gt;发生了这样一个著名的事件&lt;/a&gt;：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;天涯的“天涯时代”版块，本月举办了一次“天涯车友会Logo征集大赛”，参赛作品约30件，最后著名的“27号”勇夺桂冠。再总共3227张投票中，27号作品获得1627票的支持，支持率超过50%，而第二名的得票数还不到它的五分之一。绝对的、毫无争议的、毋庸置疑的众望所归。&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;而这27号参赛作品的设计是这样的：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/tianya-car-logo.jpg" /&gt;   &lt;p&gt;有人认为这是一次“反智主义”的胜利：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;回到我们前面谈到这个“27号”，它为什么表现了反智主义？很显然，在众多的设计作品中，有一些是由“知识精英”创作的，那些作品有他们的设计思想、美学理念，这些都可以统称为一种“知识性”或者“智识性”。而粗陋的27号与之相比基本上没有什么知识性可言，但是它获胜了，这说明，广大的投票者普遍地带有一种蔑视、否定设计知识的倾向，具有一种反智主义的态度，“恶意地”支持这样一个很糟糕的作品。&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;试想，如果您参与到这样一次投票中去，当每个参赛者都在不断展现他们优秀的设计，不断阐述这些设计背后的理念，原理，思考，含义，您的感觉如何？对我来说，我可能会感到不知所措。似乎现代人常常会有选择恐惧症，例如我去餐馆吃饭，在面临一大堆琳琅满目的选择时往往会不断左右摇摆，这也可以那也不错。此时，我最终可能就会选择那些“无需选择”的东西，例如我会每天去吃套餐，因为餐厅每天都会自行为我进行搭配，我要做的选择可能只是从3个荤菜里选择一个就行了。&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/xyyyhtl-hhsw-1.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/xyyyhtl-hhsw-1.jpg" width="300" /&gt;&lt;/a&gt;   &lt;p&gt;其实在知识扑面而来的现在，想要寻求一种纯粹的宁静的时刻也并非那么容易。最近还有一部动画电影非常火爆：“喜羊羊与灰太狼2：虎虎生威”，这部原本纯粹为儿童准备的动画片似乎也吸引了许多成年观众——包括我。在我看来，这部动画片与众不同的地方便是在众多商业大片的包围中显得如此富有童真，如此轻松愉快。它没有“2012”和“阿凡达”的惊人画面，甚至也远不如日式动画片中精美成熟的效果，但是在看这部片子的时候我不会想到玛雅文明与地球毁灭，强拆与钉子户，或是动画水平差距与&lt;a href="http://www.google.com/search?hl=en&amp;amp;source=hp&amp;amp;q=%E8%9C%A1%E7%AC%94%E5%B0%8F%E6%96%B0+%E6%8A%84%E8%A2%AD&amp;amp;aq=f&amp;amp;aqi=&amp;amp;oq="&gt;大嘴巴小新&lt;/a&gt;——看过，笑过，忘掉，然后带着轻松的心情继续工作，继续生活，这可能也就够了。&lt;/p&gt;  &lt;p&gt;简单点，有时也没什么不好的。&lt;/p&gt;  &lt;h1&gt;程序员的爱情&lt;/h1&gt;  &lt;p&gt;诚蒙机械工业出版社朋友们的垂青，他们会不定期地，在我丝毫不知情的状况下给我寄一些书来看。惊喜之余，这样做的毛病也就体现出来了——他们把书寄到我上一个公司的地址去了，因此我也才刚拿到这两本书：《&lt;a href="http://www.douban.com/subject/4196673/"&gt;程序员的爱情&lt;/a&gt;》和《&lt;a href="http://www.douban.com/subject/4188128/"&gt;林立立成长记&lt;/a&gt;》。&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/programmer-love.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/programmer-love.jpg" width="150" /&gt;&lt;/a&gt;   &lt;p&gt;我昨天出门前捎上了这本书，在路上将这本300页不到的书从头到尾匆匆翻了一遍。总体来说，我觉得这本书没什么价值。&lt;/p&gt;  &lt;p&gt;为什么这么说呢？因为在我看来，这本书仅仅是打着的程序员的旗号而已。其中的男主人公的确是一个程序员，但是几乎没有对程序员的工作，程序员的生活有太多描写。换句话说，我们可以很轻易地将主人公改写为其他的职业——“程序员”在书中仅仅是一个标记，一个可有可无的东西，也并没有对小说的内容产生什么影响。在书的封面中写着“告诉你收获爱情的秘密”，但是书中男主人公最终的归宿，是和原本就一直喜欢他的海归漂亮姑娘结婚，而他们在一起的“方式”居然是因为男方失恋酒后乱性……哪儿有什么秘密啊，唯RP耳。&lt;/p&gt;  &lt;p&gt;其实有时候我也怀疑作者是否真的是一个程序员（当然作者简介里给出了肯定的答案啦），因为对于程序员生活的描写很少，又基本是停留在表面，因此我觉得写出这些内容并不需要有亲身体会——从一些表面渠道来了解就行了（例如找个程序员朋友聊聊天，听听他们的抱怨）。此外，书中还有一些不符合实际的内容，例如第16章的开始：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;陈旭（男主人公）被提拔为项目组长后，主要负责协调和管理方面的工作，不再需要他编写代码了，但他依旧保持着对学习技术的巨大的热情，坚持要求自己每天写几百行代码。&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;我看到这“几百行”后立刻就被雷翻了。&lt;/p&gt;  &lt;p&gt;这部小说是一个普通的故事，没有华丽的词藻，没有跌宕起伏的剧情，甚至包含一些奇怪的情景——例如男主人公的好友莫名其妙地车祸身亡，这似乎没有任何意义。但也正是这样的“普通”，我很愿意相信这个故事有个真实的蓝本，如果作者的确是一个程序员而不是个职业写手，如果作者并非是为了名利而是为了兴趣进行写作，那么我对于这部小说和作者本人还是非常尊敬的。&lt;/p&gt;  &lt;p&gt;虽然我还是不喜欢，如果我是编辑，也不会出版这本书。如果您对它感兴趣，我觉得您可以去书店里捧着这本书看2个小时，或是先在CSDN上&lt;a href="http://blog.csdn.net/theloveofprogrammer"&gt;浏览其连载&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;不知道什么时候开始流行起程序员小说了，例如之前有比较著名的《疯狂的程序员》，现在又出了这两本书。这两本书看起来还是挺受程序员群体追捧的。但是我读下来其实感觉都不怎么样，难道是因为程序员群体看到“亲切”的内容因此产生了好感吗？对于我在推特上对《程序员的爱情》的看法，图灵出版社的主编刘江老师评论到：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;其实小说比较代码难写多了，是门高超的技术，可惜有些出版社和某些作者就是不信。&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;我也很同意陈猫（&amp;#64;catchen）的说法：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;向人比較准確無誤地傳達信息，比向電腦准確無誤地傳達信息，要難得多，因為向人傳達嘅信息需要包括情感。程序員習慣無需向電腦傳達情感，所以……&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;当然，我还是十分建议程序员朋友们总结自己的所做所想，也算是锻炼自己的表达能力。事实上表达能力是优秀程序员的基本素养之一。呃……其实我觉得这句话有些奇怪，因为这本应该是每一个正常的“社会人”所具备的能力，但是慢慢地程序员似乎变成了木讷、不善言辞的群体。当然我遇见过许多不善表达的的程序员，他们可能连一个简单的问题也表达不清楚，但我也认识不少善于表达的程序员。&lt;/p&gt;  &lt;p&gt;例如，我现在在盛大创新院的同事们，他们大都是很有想法，并乐于表达自己观点的人——甚至我觉得有时候这样的人太多，聚在一起时反而会有烦恼。上周在进行集体讨论的时候，要不是由主持人进行控制，一个人说着说着就很可能就停不下来了……我这个准话唠真有些插不上话的感觉。&lt;/p&gt;  &lt;p&gt;兄弟们一定要锻炼好自己的表达能力（&lt;a href="http://www.programmer.com.cn/1798/"&gt;Joel也这么说&lt;/a&gt;）——而写写小说可能也是不错的方式。&lt;/p&gt;  &lt;h1&gt;Nobody &amp;amp; Sorry Sorry&lt;/h1&gt;  &lt;p&gt;最近是各公司的举行年会的日子，每个公司年会上的节目自然大不相同。但是，如果把所有公司年会的节目取一个交集，您会发现必然会涉及到一个节目，那便是一个叫做Nobody的东东。&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/168980/o_wg_nobody_pic1.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/168980/r_wg_nobody_pic1.jpg" width="200" class="floatRight"/&gt;&lt;/a&gt;   &lt;p&gt;如果您还不知道啥是Nobody，那么您实在是奥特曼了（如果您也不知道奥特曼是啥意思……）。话说由棒子国的几个“卖馄饨的小姑娘”组成了一个团体，&lt;a href="http://www.youtube.com/results?search_query=Sorry+Sorry&amp;amp;search_type=&amp;amp;aq=f"&gt;Wonder Girls&lt;/a&gt;，而她们最被人熟悉的单曲便是&lt;a href="http://www.youtube.com/results?search_query=Wonder+Girls+Nobody&amp;amp;search_type=&amp;amp;aq=f"&gt;Nobody&lt;/a&gt;。这首曲子已经被翻译为多种文字，这些小姑娘们也已经在全世界转了一大圈（去年底也来过上海）。当然，我一直觉得棒子文没啥好听的，而Nobody的流行也不是因为音乐或歌词，而是——扭啊扭，基本上就是用来诱惑男人的舞蹈。&lt;/p&gt;  &lt;p&gt;有时候我们不得不佩服棒子国的编舞能力。Nobody能够在世界范围内的成功不是偶然，也不是靠着强大的整容技术搞出一个个近乎完美的身材相貌（许多朋友看“&lt;a href="http://www.youtube.com/results?search_query=girls+generation&amp;amp;search_type=&amp;amp;aq=f"&gt;少女时代&lt;/a&gt;”就是去看大腿的）。这方面另一个佐证便是&lt;a href="http://www.youtube.com/results?search_query=Wonder+Girls+Nobody&amp;amp;search_type=&amp;amp;aq=f"&gt;Sorry Sorry&lt;/a&gt;，而且这次是一群男人。现在Sorry Sorry的流行程度已经不亚于Nobody，不知道吸引了多少小女孩们的视线。而我看了&lt;a href="http://www.youtube.com/watch?v=bqMq82S7OVQ&amp;amp;feature=related"&gt;它的MV&lt;/a&gt;也不得不承认，这帮小子真tmd的很帅。&lt;/p&gt;  &lt;p&gt;如果你还是对它们的流行程度没有概念的话，看看菲律宾监狱集体版的&lt;a href="http://www.youtube.com/watch?v=iVkKBHCVVbg"&gt;Nobody&lt;/a&gt;和&lt;a href="http://www.youtube.com/watch?v=_43TO_OPj-8&amp;amp;feature=related"&gt;Sorry Sorry&lt;/a&gt;吧——记得接着下巴哦。&lt;/p&gt;  &lt;p&gt;当然，要说舞蹈技术，看过&lt;a href="http://so.youku.com/search_video?q=%E8%88%9E%E6%9E%97%E4%BA%89%E9%9C%B8&amp;amp;searchdomain=http%3A%2F%2Fso.youku.com&amp;amp;searchType=video&amp;amp;sbts=bar"&gt;舞林争霸&lt;/a&gt;的人根本不会觉得棒子们有什么厉害的——那群百老汇级别的牛人们是真正的舞蹈家，他们的力量，技巧都非一朝一夕之功。&lt;a href="http://v.youku.com/v_show/id_XMTQ3MjUwNjM2.html"&gt;他们的舞蹈&lt;/a&gt;更令人震撼，但是远没有Nobody和Sorry Sorry那么流行，甚至永远不可能像后两者那样被那么多人模仿。道理很简单，因为棒子艺人的舞蹈能力有限，因此编舞只能设计一些技巧性不那么强的舞步，因此许多业余人士，学生，老师，警察，程序员……人人都能模仿，人人都能“传跳”。&lt;/p&gt;  &lt;p&gt;其实这样的二分选择还有很多，各个行业都是如此。例如，李斯特的曲目在当时几乎只有他才能演奏（现在音乐学院的学生几乎个个不在话下），这给他带来了无限声望；而肖邦的许多作品在技术上容易许多，也更被人广泛接受——尤其是在我等业余人士中。那么，如果是您，您的选择是什么呢？&lt;/p&gt;  &lt;p&gt;呃，Sorry Sorry的确不错，有机会我也要尝试一下。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/02/play-novel-nobody-sorry-sorry.html#comments</comments>
      <pubDate>Sun, 07 Feb 2010 13:19:00 GMT</pubDate>
      <lastBuildDate>Sun, 07 Feb 2010 13:19:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/life/">生活心情</category>
      <title>总结：0 bug事件、交大ACM夺冠</title>
      <link>http://blog.zhaojie.me/2010/02/0-bug-and-sjtu-acm-champion.html</link>
      <guid>http://blog.zhaojie.me/2010/02/0-bug-and-sjtu-acm-champion.html</guid>
      <description>&lt;p&gt;如果您还没有上&lt;a href="http://twitter.com/" target="_blank"&gt;推特&lt;/a&gt;（或是还没有想到办法上），那您失去的不光是一个风靡世界的网络应用，您同时还失去了一个优秀的信息获取平台及讨论环境。目前国内大部分靠谱的技术专家都在推特上有帐号，您几乎不会错失任何有价值的信息，更可以&lt;a href="http://blog.zhaojie.me/2010/02/twitter-talk-about-ms-dev-at-20100201.html" target="_blank"&gt;参与一些有价值讨论&lt;/a&gt;。周六是休息日，因此也在推特上和大家聊得不亦乐乎。不过推特的一个缺陷可能便是难以留住有价值的信息，它们会随着时间推移渐渐消失，因此还是及时记录一下吧。&lt;/p&gt;
&lt;h1 id="0bug"&gt;0 bug事件&lt;/h1&gt;
&lt;p&gt;0 bug事件原本什么都不是，只不过是有人使用非常普通、就事论事地方式，在豆瓣上指出了《0 bug》一书中不妥的地方。但是由于作者令人费解地谩骂和指责使“事态升级”。再由于网络上围观群众（&lt;a href="http://blog.zhaojie.me/2010/02/logic-is-not-everything.html" target="_blank"&gt;其中也有我的份&lt;/a&gt;）与作者本身不断地进行“交锋”，0 bug事件终究一发不可收拾了。&lt;/p&gt;
&lt;p&gt;其实我对这件事情已经不太在意了，因为我本来就是围观群众，而且目前0 bug事件已经出离了纯粹的技术讨论。不过现在我继续谈这个问题，是因为直接参与此次事件的双方又有新的动作了。首先是大牛&lt;a href="http://www.cnblogs.com/miloyip/" target="_blank"&gt;Milo Yip&lt;/a&gt;已经在园子里建立博客了，他的原话是希望“&lt;font color="#ff0000"&gt;將會陸續把牆外的技術文章整理及分享&lt;/font&gt;”，不过第一篇文章是&lt;a href="http://www.cnblogs.com/miloyip/archive/2010/02/06/1665099.html" target="_blank"&gt;对0 bug事件的过程进行了系统的总结&lt;/a&gt;；当然&lt;a href="http://blog.csdn.net/tonyxiaohome/" target="_blank"&gt;0 bug&lt;/a&gt;老师也没有闲着，他这几天还在勤劳地进行辩解。不久前又转载了一篇雄文《&lt;a href="http://blog.csdn.net/tonyxiaohome/archive/2010/02/05/5291216.aspx" target="_blank"&gt;五毛党与网络打手&lt;/a&gt;》，从始至终地坚持他的观点：此次事件是“敌对势力”在对他进行“有组织，有预谋”的抹黑。&lt;/p&gt;
&lt;p&gt;而事情发展至今又有新的亮点，那便是CSDN的编辑同志们将此次事件相关的文章放上了首页。在此截图留念：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/csdn-0bug.png" alt="" /&gt;
&lt;p&gt;哈，前两篇都是。&lt;a href="http://blog.csdn.net/Raptor/archive/2010/02/05/5290875.aspx" target="_blank"&gt;第一篇文章&lt;/a&gt;指出了0 bug老师在此次事件中的问题所在，其中一点正好回应了0 bug老师的观点：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;按我以前接触过的国内出版业人士来看，肖老师在BLOG里说的“书黑”这种事情在中国的确很可能发生。但是他的错误在于，把所有提意见的读者都当成了 书黑，这未免有点被迫害妄想过头了吧。要知道，请一帮网络黑社会也是要花不少钱的，一个编辑做一本书赚的钱估计是不够的，更何况目标还是这样一技术含量比 较高的书。 &lt;/p&gt;
&lt;p&gt;其实光是从Milo指出的几个问题来看，他就不可能是什么书黑，哪有C++水平这么高的书黑——要是C++功力这么深还当什么书黑啊，书黑能赚几个钱。而作者连这点都看不出来，显然他的C++功力也不怎么样，以此推断，那本书显然也的确不怎么样。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而&lt;a href="http://blog.csdn.net/tonyxiaohome/archive/2010/02/05/5290195.aspx" target="_blank"&gt;第二篇文章&lt;/a&gt;的作者正是0 bug老师本人，其主要意思是指目前指出的问题似乎都有“无中生有”的感觉，因为这些“攻击”根本没有找准位置。&lt;/p&gt;
&lt;p&gt;0 bug老师是&lt;a href="http://student.csdn.net/" target="_blank"&gt;CSDN学生大本营&lt;/a&gt;的头牌，因此CSDN的态度对于这个事件的意义重大。而这次CSDN首页推荐的作法，我个人看来已经是一种表态了。因为这两篇文章，无论是对“技术”及“产业”来说都几乎没有意义，推荐它们的原因似乎只是为了揭露0 bug事件本身。很明显，0 bug事件对于CSDN来说并不光彩，而CSDN的编辑同志没有遮掩，将其公开地表达出来，我想他们在这个问题上的确值得我们尊敬。&lt;/p&gt;
&lt;p&gt;就我的看法，0 bug事件可以说是继《&lt;a href="http://blog.zhaojie.me/2009/09/1572868.html" target="_blank"&gt;JavaScript征途&lt;/a&gt;》之后又一个和技术图书出版有关的经典案例了，两者的相同之处在于作者对于读者所指出的“硬伤”都采取了类似的态度。上次的事件似乎已经平息，只有&lt;a href="http://www.google.com/search?hl=en&amp;ei=_8ttS5DKBsyIkAW4zrHUBw&amp;sa=X&amp;oi=spell&amp;resnum=0&amp;ct=result&amp;cd=1&amp;ved=0CBcQBSgA&amp;q=JavaScript+%E5%BE%81%E9%80%94&amp;spell=1" target="_blank"&gt;搜索引擎中的头条&lt;/a&gt;清楚地记录着相关内容。我真的希望图书出版行业的这类经典案例可以少一些——亦或是多出现一些，以此推动一个革命，最终改变目前令人难堪的现状？&lt;/p&gt;
&lt;p&gt;在推特上，&lt;a href="https://twitter.com/jasonlai" target="_blank"&gt;@jasonlai&lt;/a&gt;同学发表了一些看法：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;老话，咱圈真乱。另外，国内技术媒体和出版圈子还是需要提高一下道德底线啊，出书审校不负责任，写软文换赞助的事情比比皆是。最近小关注了一下&lt;a href="http://www.techcrunch.com/2010/02/04/an-apology-to-our-readers/" target="_blank"&gt;TechCrunch炒掉写软文实习生的事件&lt;/a&gt;，感触颇深，能那样做才是受尊重的媒体。&lt;/p&gt;
&lt;p&gt;仔细看了某口水战事件的讨论始末。有知识没文化真恐怖啊，某“大师”的气度，&lt;a href="http://www.danielbru.com/2010/02/the-line-was-crossed/" target="_blank"&gt;还不如一个17岁小孩&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;说到这里，我想起在我的博客上有朋友回复说，写《JavaScript征途》的朱老大最近又有一本新书《&lt;a href="http://www.china-pub.com/49015" target="_blank"&gt;Flash CS4基础与案例教程&lt;/a&gt;》出版发行了。我在这里谨代表我个人（请注意，不代表其他人哦）表示恭喜，并对国内有如此高产的作者感到自豪。让我们欢呼吧！&lt;/p&gt;
&lt;h1&gt;交大ACM夺冠&lt;/h1&gt;
&lt;p&gt;交大牛啊，继2002及2005年之后，他们&lt;a href="http://news.csdn.net/a/20100205/216923.html" target="_blank"&gt;再次获得了ACM竞赛的世界冠军&lt;/a&gt;！想当年我也在信息学奥林匹克竞赛的道路上探索过，但由于直升大学时被交大拒绝，一气之下报考复旦大学，从此改变了我的人生轨迹——呃，扯远了，没别的意思，还是回到这则新闻上来。&lt;/p&gt;
&lt;p&gt;不过，奇怪的是，似乎很多人的对这个事件还是发表了许多在我看来毫无道理负面评价（当然并不是所有的负面评价都是没有道理的，例如说ACM夺冠对于国内普遍现状几乎没有帮助，这我同意）。具体地就不多提了，您可以自己去看新闻后面的回复。我想说的是，我这次真的想用“喷子”来形容某些人了。&lt;/p&gt;
&lt;p&gt;的确，国内大学教育是有很多问题，你们的失望我可以理解，但是为什么那么倾向于“轻视”一个东西？的确，交大的弟兄们是非常重视ACM竞赛，但是他们的确通过刻苦训练拿到了世界冠军，这一点不假。嗯，你可能会说“ACM这种比赛没有什么意义，考题海战术取胜，胜在中国人最擅长的应试教育，否则为什么拿了那么多次世界冠军，那些搞ACM的人最终成功的有几个？”那么我们现在就来讨论这个问题吧。&lt;/p&gt;
&lt;p&gt;其实以前也有过类似的问题，便是“中科大少年班”。有许多人质疑对此类少年天才的培养方式——的确，可能这种方法自有其不科学之处，但是类似于“除了张亚勤之外又有谁成功了”这样的论据我是非常不屑与之辩驳的。对此我只想问几个问题：成功的标准是什么？所有成功的人你都认识吗？&lt;/p&gt;
&lt;p&gt;这里我不想谈什么“金钱不是唯一标准”等会被人耻笑为“幼稚”的道理，我们就拿钱来说吧。我举个例子，世界上有许多大型银行或是企业，他们的总裁，或是副总等高管都是有钱人，可谓非常成功，但是你现在能够说出其中几个人的名字？再问，就拿微软来说，除了盖兹，鲍尔默等人，你又能说出多少人呢？微软的&lt;a href="http://www.microsoft.com/presspass/exec/techfellow/default.mspx" target="_blank"&gt;Technical Fellows&lt;/a&gt;以及&lt;a href="http://www.microsoft.com/presspass/exec/de/default.mspx" target="_blank"&gt;Distinguished Engineers&lt;/a&gt;也都很成功（即使只谈钱），但是这几十人中你又认识多少人呢？&lt;/p&gt;
&lt;p&gt;是啊，成功的人太多了，不能因为你没有听说过就“认定”他们不成功。事实上，无论是ACM冠军选手或是中科大少年班的成员，他们中的大部分在社会地位还是经济方面都是普通人难以项望其背的。只不过，他们没有让你们知道而已。例如，他们可能出国深造，成为顶尖的科研人员或是教授，享受着几十万美元的年薪，过着滋润的生活。你可能连Jim Gray都不知道是谁，不知道他们不是很正常的事情吗？&lt;/p&gt;
&lt;p&gt;其实我在学校的时候也一直关注ACM成员，事实上我就没有发现有哪个ACM高手是写不好程序的。&lt;/p&gt;
&lt;p&gt;Oren Eini写过&lt;a href="http://ayende.com/Blog/archive/2009/12/12/setting-the-record-straight-i-am-not-the-main-contributor.aspx" target="_blank"&gt;这么一篇文章&lt;/a&gt;，其中心思想是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am not the main contributor (of NHibernate), I am just the loudest one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这句话的说法一点没错。就拿我来说，我&lt;font color="#ff0000"&gt;不是&lt;/font&gt;最好的.NET程序员，我只不过是在博客园积分最多，并且可能最积极参与社区活动而已。如果要正确定位我在社区中的表现，也只（可能）是loudest，而远远谈不上，甚至永远不可能是best。要在技术社区中产生正面的影响力，水平只是一方面，而“其他某些方面”也是非常重要的。记得网络红人&lt;a href="http://blog.sina.com.cn/ayawawa" target="_blank"&gt;ayawawa&lt;/a&gt;说过这么一句话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;比我漂亮的都没我聪明，比我聪明的都没我漂亮。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;那么我也来说一句类似的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;比我会吹牛的技术都没我好，技术比我好的都没我会吹牛。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以，我也就是一个小样儿而已——但是我还是自信比ACM事件中大部分无理由的喷子们要强上不少。&lt;/p&gt;
&lt;p&gt;五毛与无美分无异。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/02/0-bug-and-sjtu-acm-champion.html#comments</comments>
      <pubDate>Sat, 06 Feb 2010 19:51:00 GMT</pubDate>
      <lastBuildDate>Sat, 06 Feb 2010 19:51:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>李笑来激起千层浪，赵姐夫力拒众强敌</title>
      <link>http://blog.zhaojie.me/2010/02/twitter-talk-about-ms-dev-at-20100201.html</link>
      <guid>http://blog.zhaojie.me/2010/02/twitter-talk-about-ms-dev-at-20100201.html</guid>
      <description>&lt;p&gt;昨天晚上，&lt;a href="http://www.lixiaolai.com"&gt;李笑来&lt;/a&gt;（&lt;a href="https://twitter.com/xiaolai"&gt;&amp;#64;xiaolai&lt;/a&gt;）老师的无心之语却引起了推特上一次前后长达1个多小时的讨论——当时他似乎只是随手发了一句“Apple告诉我们的铁律是：表面功夫一定要做足”便不见了踪影，但是这句话立即引起了众果粉的共鸣。此后，我（&lt;a href="https://twitter.com/jeffz_cn"&gt;&amp;#64;jeffz_cn&lt;/a&gt;）的一句评论又引起了众人对微软开发平台的批判之声。在这次讨论中，几乎只有我孤军奋战为.NET平台进行辩解。因此事后有人给出一副对联为此次争论作出总结：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;上联：李笑来激起千层浪&lt;/p&gt;    &lt;p&gt;下联：赵姐夫力拒众强敌&lt;/p&gt;    &lt;p&gt;横批：全民扯谈&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;自然，无论是我还是其他人，在参与讨论的时候都抱有明显的个人倾向性。不过与常见的吵架不同，虽然大家观点向左，但是并没有任何谩骂的成份，同时也没有假惺惺的客套话。可以说所有人从头到底都保持着就事论事，据理力争。因此从旁观者的角度来看，这次讨论并非只是意气之争，其中还是包含了比较丰富的内容。&lt;/p&gt;  &lt;p&gt;参与讨论的&lt;a href="http://blog.devep.net/virushuo/"&gt;霍炬&lt;/a&gt;（&amp;#64;virushuo）和&lt;a href="http://tiny4.org/myhome/"&gt;郝培强&lt;/a&gt;（&amp;#64;tinyfool）都是老程序员，他们在上世纪末也都是微软平台的开发人员，但是因为难以忍受微软在那时候“毫无克制”的技术更迭（如VC =&amp;gt; COM =&amp;gt; .NET），最终一前一后都转投了*nix平台。我昨天谈到，我&lt;a href="http://blog.zhaojie.me/2010/02/use-mac.html"&gt;加入水果党的主要原因&lt;/a&gt;之一是想了解苹果机的妙处究竟在哪里，而他们两位便是让我产生这一想法的重要因素。而我，由于入行较晚，虽然“从理论上”说也经历过这一历史阶段（如VB，Delphi，以及Java开发环境混战的那一时期），但是在真正全身心投入微软平台时已经是.NET时代了，因此对于霍郝两位的观点并没有切身体会，而我坚持的观点便是：.NET平台发布至今并没有“革命性”的改变，而目前也可以看出微软已经在.NET平台上投入了未来5年甚至10年的心力，因此如今.NET程序员并不用担心遭遇当年的悲剧。&lt;/p&gt;  &lt;p&gt;从这次讨论中可以了解到一些老程序员对（当年）微软开发平台的一些典型看法，这些看法放到现在究竟正确与否我认为并不重要，重要的是我们能够从中总结出哪些信息，这些信息又可以如何对我们将来的发展产生借鉴意义。因此，我详细地总结了这次讨论的完整内容——不过毕竟是人肉整理，不排除遗漏少量条目的可能。因此，我建议您可以上一下推特，follow一些人，这样下次再出现有价值的讨论也不会遗漏了。&lt;/p&gt;  &lt;p&gt;由于讨论内容较多，我还是把它们放在下面的链接中了。其中，缩进代表了“回复”关系，但是由于推特的谈话性质，条目的上下位置并不表示发表时间的先后。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://docs.google.com/View?id=dgpjrmdf_141cgbw5gfx"&gt;http://docs.google.com/View?id=dgpjrmdf_141cgbw5gfx&lt;/a&gt;&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/02/twitter-talk-about-ms-dev-at-20100201.html#comments</comments>
      <pubDate>Tue, 02 Feb 2010 16:49:00 GMT</pubDate>
      <lastBuildDate>Tue, 02 Feb 2010 16:49:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>光有逻辑也是万万不能的</title>
      <link>http://blog.zhaojie.me/2010/01/logic-is-not-everything.html</link>
      <guid>http://blog.zhaojie.me/2010/01/logic-is-not-everything.html</guid>
      <description>&lt;p&gt;之前我多次强调“逻辑”在讨论问题时的重要性，我也多次表示说，如果大家都运用合适的逻辑思维来讨论问题，那么论坛上8成吵架可以避免。现在我也想再次探讨一下这个话题，只不过这次我想反过来说：光有逻辑也是万万不能的。除了“逻辑”这个东西之外，讨论问题时还有很多其他东西值得注意。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lixiaolai.com"&gt;李笑来&lt;/a&gt;老师是国内最著名的“讲道理”倡导者之一。前一段时间对于“孔子”这部电影，他在推特上说了这么一句话：“坚决不去电影院看《孔子》的请举手！”。于是我和其他一些朋友就问到：“发生什么了？”不久，笑来老师就在博客上&lt;a href="http://www.lixiaolai.com/index.php/archives/8588.html"&gt;谈了这个问题&lt;/a&gt;，摘录如下：&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“抵制”的意思是说，有一样东西对你是有吸引力的（不管好坏），但是，你不要它。比如“抵制日货”，“日货”挺不错的，但是，基于某种原因有些人就“抵制”了它。抵制“法货”也是如此，抵制“诱惑”亦如是。&lt;/p&gt;    &lt;p&gt;我们只是纷纷表示自己不会去看，这不叫“抵制”，只是“表态”——犯得着去抵制一个连诱惑都不是的东西吗？它甚至连日货法货都不是。甚至没有“号召”的意思，“号召”的意思是说，给别人一个信服的理由，令他们做出与原本可能不一样的决定。&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;笑来老师的意思是，他只是在表态，他不是在号召大家不去看。从字面上看，“请举手”的确没有在“号召”，例如“喜欢吃红烧肉的请举手”，相信没有人会认为这有其他意思。但是，为什么包括我在内的一些朋友就认为笑来老师是在号召大家不去看这部电影呢？仔细思考之下，我认为可能是这两个原因。&lt;/p&gt;  &lt;p&gt;首先，在此之前笑来老师说过或转推过一些对于“孔子”电影的反面意见。在大部分情况下，某个人说的话都是有上下文的，在不同的上下文说同样的话，理解其起来也不一样。为什么说某些媒体没有道德？其中一个表现便是在转述别人的话时剥离上下文，以此曲解别人的意思，甚至让意思完全相反。因此，虽然经过分析之后，我能够理解笑来老师的确没有“号召”的意思，但在当时，这句话的确给人以不一样的感觉。&lt;/p&gt;  &lt;p&gt;其次，这句话的表述是反面的，此外其用词比较强烈，如“坚决”。人类的语言是神奇的，一句话除了“最表面的意思”之外，其说话方式、用词的不同，都会影响别人对这句话的理解——这也是语言表达的非常重要的一部分。例如一个多月前在图灵俱乐部中，有朋友认为现在许多文字或翻译越来越不简练了，他认为“我和你要做一次私下的谈话”是典型的英文式中文，应该“我想和你私下谈谈”。但是，&lt;a href="http://ozzzzzz.javaeye.com/blog/"&gt;o6z&lt;/a&gt;的回复反驳了这个看法，认为“这个例子举的太差，这两句话的语气和目的差别太远。其实类似的表达还有很多，但是里面的含义却大有不同”：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;我和你要做一次私下的谈话----将来做一次正式的但是非公开的谈话。&lt;/li&gt;    &lt;li&gt;我要和你做一次私下的谈话----现在马上就要跟你做一次正式的私下谈话。&lt;/li&gt;    &lt;li&gt;我想和你私下谈谈----我想找个机会私下和你谈谈，更加具有私人性质的交谈，而不是上面两句更加具有工作或者官方色彩。&lt;/li&gt;    &lt;li&gt;我想和你谈谈，私下的----直接的表达出我要跟你聊点不适宜公开的事情，有要搞阴谋的味道。&lt;/li&gt;    &lt;li&gt;找个时间咱俩聊聊吧----更多的是客气话，希望拉近关系。&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;最近还有一个非常著名的例子便是“Google离开中国事件”。当时我说：“事情闹这么大，Google要么离开被人看作爷们，要么留下给人看作笑话”。最后的结果大家应该也就见到了，这几乎就是一场闹剧。这次事件继续在给Google的“不作恶”原则抹黑。但是也有人说，Google本来没什么啊，都是媒体炒作害苦的。没错，Google从头到底没有说“一定离开中国”，它只是说“考虑离开中国”。从逻辑上看，它最终选择留下并没有违背它说过的话，因此也不会有人追究它的责任（如，罚款）。但是，为什么似乎大部分人（还是我自动过滤了意见不同的看法？）觉得Google这次“吃了吐”呢？这就是它的“行为”和“说法”给人的“感觉”，在这方面“逻辑”不是唯一的评价依据。&lt;/p&gt;  &lt;p&gt;这也是为什么有了“逻辑”还是会发生“争吵”的原因，尤其是在技术圈子里。因为，即使每句话都包含逻辑，许多话“还是不那么好听”，给人的感觉还是“话里有话”，慢慢大家的情绪都调动起来，争论难以避免。此外，在技术圈里，大家都是聪明人，能够很轻易地发现平时交流中对方话语中的问题——毕竟，例如论坛发帖时很少有人会字斟句酌。于是，我反驳不了你的“理由”，我反驳你的“说法”不也可以吗？只可惜，我们只有如“法庭辩论”这样的环境下才需要如此运用“逻辑”。平时，有必要吗？&lt;/p&gt;  &lt;p&gt;此外，“逻辑”也可以用来“诡辩”，无理也可以说成有理——大家都是聪明人，这方面的能力总是不缺的。以下便是一例：&lt;/p&gt;  &lt;p&gt;上个星期还发生了“0 bug门”事件：。简单地说，那是因为有人对于《&lt;a href="http://www.douban.com/subject/4149139/"&gt;0 bug——C/C++商用工程之道&lt;/a&gt;》写了一个书评，&lt;a href="http://www.douban.com/review/2949973/"&gt;指出书中的一些问题&lt;/a&gt;。于是作者，&lt;a href="http://blog.csdn.net/tonyxiaohome"&gt;肖舸&lt;/a&gt;（后文称o bug老师）不干了，认为评论者是故意来抹黑，认为评论者能力不够。但事实上，评论者&lt;a href="http://cn.linkedin.com/in/miloyip"&gt;Milo Yip&lt;/a&gt;的批评完全只是针对书上的内容，语气也非常委婉，反倒是0 bug老师在不断对评论者进行谩骂——并一再坚持评论者公开身份。后来，大家发现Milo其实是大牛，因此对其能力不足的的说法也不攻自破了……不知道当时0 bug老师心里是什么滋味。&lt;/p&gt;  &lt;p&gt;那么现在结果怎么样呢？没怎么样，0 bug老师已经删除了自己的所有回复。只可惜，Google快照功能保留了一切，而这些结果也已经被&lt;a href="http://blog.csdn.net/lanphaday/archive/2010/01/27/5260427.aspx"&gt;截图留档&lt;/a&gt;。但即便如此又如何呢？0 bug老师还是义正词严地&lt;a href="http://blog.csdn.net/tonyxiaohome/archive/2010/01/28/5265573.aspx"&gt;发表了一篇文章阐述了自己的不公遭遇&lt;/a&gt;——都是聪明人，这方面的能力总是不缺的。再由于“谁的地盘谁作主”，0 bug老师的博客上只能看到众粉丝的溢美之辞。&lt;/p&gt;  &lt;p&gt;所以，如果要形成良性讨论，光有逻辑也是万万不行的。我们还是需要点别的东西，例如控制情绪，与人宽容等等。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/01/logic-is-not-everything.html#comments</comments>
      <pubDate>Sun, 31 Jan 2010 16:14:00 GMT</pubDate>
      <lastBuildDate>Sun, 31 Jan 2010 16:14:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>2009年末，多少进行一些总结和展望吧</title>
      <link>http://blog.zhaojie.me/2009/12/summary-2009.html</link>
      <guid>http://blog.zhaojie.me/2009/12/summary-2009.html</guid>
      <description>&lt;p&gt;时间就这样悄无声息地到了2009年的最后一天，回首我这过去的一整年，可以用一句废话来总结，那就是“既有遗憾，也有收获”。不管怎么样，多少也应该总结一下吧——尤其是此时此刻，对我来说可谓是一个新的起点。自然，在技术博客上，终究还是围绕着“事业”谈谈吧。&lt;/p&gt;  &lt;p&gt;说起“事业”，就无法不谈“工作”。过去这两年半来我一直在“创业”，也算是经历了一个完整从无到有，从热情到平静的过程。记得一开始热情似火，似乎美好的生活就在眼前，我们正在开创一个时代。但是在进行的过程中，该出现的问题总该出现。对我来说，从最初开始创业，似乎并不是一个好的选择。因为我是一个希望专注的人，而初创时期的资源匮乏，不得不让我考虑许多技术以外的问题。回首过往，无论是技术还是非技术方面，我都走了不少弯路。但这些弯路也是难得的收获，让我进一步认清了自己的兴趣和发展方向。如果下次再进行创业，我想我会做得更好。&lt;/p&gt;  &lt;p&gt;不得不承认，当年选择离开大公司去创业，“冲动”是一个很关键的因素。现在看来，最能激发我热情的还是“技术”而不是其他一些东西——我真是十足的程序员，不是吗？公司规模最大的时候也有超过20个人，其中技术部门占了一半人数。可惜，我们把这些生产力浪费了，公司走向是一方面，而另一方面则在于我自身——我似乎不适合带领团队进行开发。&lt;/p&gt;  &lt;p&gt;在创业之前，我在一家较大的民营企业工作，也算是一个“小头目”，可那段时间对我来说也是比较痛苦的，如何带领大家一起开发，始终是个问题。我可以照顾好我自己，我可以保证自己的生产力，但是如果我还要关注别人的话，不光没有给兄弟们带来帮助，连自己的生产力似乎也无法发挥出来。现在看来，这两年半的时间并没有让我这方面能力有明显的提高。我还是一个纯粹的程序员，我希望过一个技术人员的生活。&lt;/p&gt;  &lt;p&gt;幸运地遭受了百年一遇的金融风暴以后，公司终于又回到了十人以下的规模（其中大半是非技术人员）。在经过了不断的犯错与重试，公司似乎终于走上了正确发展的道路。但是，我在这个时候却打算离开，因为我认清自己的特点之后，认为我并不能给现在的公司带来价值。同样的，公司也无法在技术上给我带来更好的挑战和机遇。与其整天浑浑噩噩地过日子，不如重新寻找更好的发展方向。在这段时间里里，我也积累了不少想法，现在感觉也是时候进行落实了。&lt;/p&gt;  &lt;p&gt;我不想去大型外企工作，无论是微软、谷歌还是如SAP，尽管待遇很好，但那里的生活似乎过于安逸。而且我在看了一些职位的描述信息之后，发现经过两年半的创业生活以后，我已经难以适应大型外企的工作方式了。在那里，每个人都是一个螺丝钉，每个人都要在严谨的工作流程中做好螺丝钉的职责。而我，更希望在一个有挑战，并且在一定程度上发挥创造力的地方工作——没错，创造力，我认为许多国内企业，在这方面做得比国外的大公司要优秀很多。&lt;/p&gt;  &lt;p&gt;不继续创业的另一个原因，是最近所发生的一系列事情，让我对目前国内的互联网创业环境十分悲观，因此我认为抱大腿——也就是进入大公司工作似乎是一个更合适的选择，如腾讯，百度，盛大，阿里……兄弟们，赐予我力量吧。&lt;/p&gt;  &lt;p&gt;对于我来说，“事业”的另一个重要组成部分，便是我这个技术博客了。如果说我在技术博客上投入了无人能及的精力，相信也不会有太多朋友对此持反对意见。博客对我来说，是一个交流手段。我写博客，除了总结自己的感受之外，更重要的是进行讨论。今天刚好看到一篇文章，说是一些&lt;a href="http://www.lifebeyondcode.com/2009/12/26/why-some-smart-people-are-reluctant-to-share/"&gt;聪明的朋友却不太愿意分享&lt;/a&gt;，其主要原因是他们“知道的越多，也越感觉自己无知，或自己所知之浅薄”。我没有这方面的顾虑，因为我的目的不是提供指导，而是为了引起讨论。我虽然希望有一个高大威猛的形象，却也不怕表现自己的无知——这样看来，我似乎不太适合写书，不是吗？:)&lt;/p&gt;  &lt;p&gt;在这一年中，其实出版社多次问我是否有些书的意向，我都婉言谢绝了。我的考虑有多方面，因为从我观察到的结果，只要开始写书，原本再勤快的博客作者也会停止更新博客——而且停止地很彻底。这不光是时间上的考虑（因为时间多少总是挤得出来的），也有“思维方式”上的问题。写书和写博客的方式是不同的，要在两种思维方式上进行切换，似乎并不那么容易——最终的结果便是“懒于”调整，不写博客了。因此，一个技术作者，可能只会在博客上写一点非技术的话题，或者是一些技术感悟吧。&lt;/p&gt;  &lt;p&gt;我想，我也很难逃出这个魔咒。我不想停止博客的写作，既然已经养成了好习惯，那么又何必中断呢？而且在我看来，与其成为一个半吊子的技术图书作者，为国内混乱的市场添砖加瓦，倒不如用心打造一个国内领先的技术博客来的有价值。如果真的有合适的写书机会，厚积薄发，一炮打响，岂不快哉？&lt;/p&gt;  &lt;p&gt;今年是我开始写技术博客的第四个年头，也是投入最大的一年——甚至说，我怀疑以后再也不会向今年一样写那么多了。我简单的估计了一下，大约有500千字吧。这是个什么概念呢？找了些参考物，发现这大约是一本400页左右的技术书籍。这样看来，其实这个数字也不是很多，毕竟这是整整一年写作的结果。天下间有无数技术图书的作者可以在一年时间里写出这样一本书，个别高产者甚至可以有数倍的产出。但是，如果作为技术博客来说，我想这已经是一个非常可观的数字了。但是我相信，通过博客我获得的交流远比写这么一本书来的多，来得实在，来得“敏捷”——那么我为什么要写书呢？:P&lt;/p&gt;  &lt;p&gt;创业，也给了我发展博客的空间。因为我可以毫无顾忌地将我工作的内容，思考及尝试写将出来。如果您关注我的博客内容，可能会发现我不太会写一些长篇的系列，而大都是一些零碎的纪录，没有太多的连续性，想到什么便写什么——这便是我心目中在“博客”中该写的东西。我不是老师，博客不是我的教学平台，我在写博客，没有写书。&lt;/p&gt;  &lt;p&gt;明年，我打算降低写作的频率（当然是相对于今年来说）。因为考虑到换工作对我的影响，我可能无法保证博客如今年那样频繁更新。换工作后，我的工作方向并不一定和目前相同（我的兴趣也是如此），因此可能会将过去一段时间中的所想所得进行一番总结。在我看来，投入过思考的东西，无论成熟与否，都应该记录下来，否则随着时间的推移，收获也会越来越小——而且，能记录下自己发展的轨迹，也是一件很有趣味的事情。&lt;/p&gt;  &lt;p&gt;年，我打算在技术方面进行一些更深入的钻研及思考，因此博客内容可能也会显得更为专一和连贯一些。我选择加入技术氛围浓厚的大公司，也是希望可以和更多技术高手一起来交流，并借助大公司的平台进行更多尝试、或是检验自己想法的机会——成功最好，失败也是收获。现在我真的堆积了不少想法，无从释放，再这样下去要郁郁而终了。工作引发思考，思考带来记录。工作内容永远是我博客内容的源泉。&lt;/p&gt;  &lt;p&gt;此外，我还是想对博客开展进一步的建设和推广，并且希望能够以此带动博客园，甚至更大范围内的写作与交流氛围。大家好才是真的好，毕竟我还年轻，我的负担还相对较少，我还没有放弃某些理想。如果您有什么好的想法，也请随时给我意见和建议——接受群众广泛监督是我立博之本。此外我也想为社区贡献一些有价值的“作品”——如果真能做到那就再好不过了。写到这里，我似乎又有些激动起来，这算是对未来“美好生活”的向往吗？&lt;/p&gt;  &lt;p&gt;那么，便以此篇，作为今年最后一篇博文，为我2009年博客写作划上句号吧。&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/summary-2009.png" /&gt;   &lt;p&gt;敝人老赵，于2009年写作博客250篇，特此留念。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/12/summary-2009.html#comments</comments>
      <pubDate>Wed, 30 Dec 2009 16:11:00 GMT</pubDate>
      <lastBuildDate>Wed, 30 Dec 2009 16:11:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>到底博客园首页的标准是什么？</title>
      <link>http://blog.zhaojie.me/2009/10/1589474.html</link>
      <guid>http://blog.zhaojie.me/2009/10/1589474.html</guid>
      <description>&lt;p&gt;博客园首页的标准是什么？它是有客观依据的，有案例可查的标准，还是仅仅是靠每个人心里自己的主观感觉来衡量的？现在的主要矛盾似乎就在于首页是个聚集区，大家靠自己的对自己文章的评价标准发上首页，用自己对别人文章的评价作为标准认为某某文章应该撤下首页，博客园管理团队也是使用自己的标准来操作——博客园团队也是人，我不知道有几个人，但肯定不会多，所以窃以为同样不能算是“集体智慧”。&lt;/p&gt; &lt;p&gt;首页是博客园的“圣地”，无论是什么文章，只要丢上首页就有无数人关注，如果只是放在自己的博客上，那么就会闻者寥寥。从我个人的经验看来，如果放上首页的文章，会比不放上首页的浏览量高3到5倍——而且，放上首页的时机也很重要，如果在大家访问博客园高峰的时候，你的文章已经在首页的下方，那么访问量相对较少——更别说第2、第3页了。因此，首页可谓是“兵家”必争之地。&lt;/p&gt; &lt;p&gt;但是，首页的标准在哪里？我找不到。可能标准只有这个，在发表文章的时候有这样一句话：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;对发布到首页精华区的随笔要求：&lt;b&gt;原创、思考与写作时间在1小时以上，能够让读者有真正的收获。&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;我想用毛主席的话来总结一下我的看法：这两个条件一是个人主观上的，二是别人主观上的，不过说到底，它们都博客园管理团队主观上的。&lt;/p&gt; &lt;p&gt;1小时，这个标准谁来验证？我发表了一篇文章，因为只有500字，所以就是1小时以内？但是这500字是我过去一个星期思考的总结，这个“思考”时间怎么算？原创——别人可以说，这明明也有人写过了嘛，你写的也没有什么新意。此外，首页上不还有翻译吗？翻译不是不能上首页的吗？那么为什么大家都能接受翻译呢？所以，我想大家都能接受的是“努力”和“质量”，而不是究竟这篇文章有没有1小时。&lt;/p&gt; &lt;p&gt;不过后一点就扯淡了：“能够让读者有真正收获”。这个扯谈不是指条件不合理，而是指基本上没有操作性。例如我写的文章，也有许许多多朋友跑过来说“没有收获”，也有客气点的说法是“希望以后可以看懂”。那么，我的文章到底应不应该留在首页上呢？同样，我看首页很多文章，我觉得“这个简单，那个没到点子上，这个话题有意思，不过我已经知道了”。那么，这些文章的确也没能给我收获，它们可以放在首页上吗？如果我贸贸然冲上去说“没意思，撤下首页吧”，那么肯定会被一阵猛踩——虽然我也没想要这么说，因为我知道，这篇文章只要没错，总归会对某些有帮助的，所以我要客观地思考。但是更重要的是——我这个“客观”的思考到底是不是客观，谁知道啊，它毕竟还是我自己脑子里的感觉啊。因此，其实博客园目前主要矛盾，是博客园管理团队的观点和群众观点相悖——而且，其实群众也没有统一观点。&lt;/p&gt; &lt;p&gt;至于一篇文章是否有错，有错的文章是不是就不能发布在首页了？我不同意。首先是我相信博客园没有人会故意写错误的东西吧，至于写出来了，也是觉得自己的正确的。而且，写给更多人看，也就是在接受群众批评和监督。例如我那几篇NHibernate的文章，我说它&lt;a href="http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-3-collection-support.html"&gt;没法支持自定义集合&lt;/a&gt;，于是有高手跑出来说是可以的，告诉我一些链接，我研究后“&lt;a href="http://blog.zhaojie.me/2009/10/nhibernate-custom-collection-1-basics.html"&gt;填补了国内互联网资源空白&lt;/a&gt;”。同样，我说&lt;a href="http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-4-interceptor.html"&gt;Interceptor机制好&lt;/a&gt;，又有高手们跑出来说应该用Event Listener。这样看，我写的东西也有错误和不确切的地方，但是在写文章的时候“我以为我是正确的”。如果我的文章&lt;a href="http://blog.zhaojie.me/2009/10/testability-driven-development-1.html"&gt;引起了讨论&lt;/a&gt;，它的效果似乎比我丢出一篇最最正确无可挑剔的文章要有更多价值。&lt;/p&gt; &lt;p&gt;啥是社区？不就是给人交流吗？“纠错”也要有范例才行，不是吗？大家都是正确的，大家都在打哈哈“李兄高明，杜兄久仰，赵兄实在”，这就不是社区了。&lt;/p&gt; &lt;p&gt;除了博客园管理团队和部分群众观点相悖以外，还有一个问题就是博客园管理团队的操作不够透明。例如有人指出管理团队有双重标准，对于某些人的文章特别宽松，进而猜测博客园管理团队是为了人气而故意这么做的。这还真没法说下来了，呵呵。&lt;/p&gt; &lt;p&gt;这就是我认为现在博客园首页标准的问题，接下来我谈谈我对解决这个问题的一些看法，可能有些幼稚，一定很不成熟，兄弟们姑妄听之吧。大家也可以谈谈自己的看法。&lt;/p&gt; &lt;p&gt;既然主要矛盾是博客园管理团队和部分群众观点相悖，而且群众本身的观点也不统一，因此博客园管理团队无论怎么做，肯定会得罪一部分群众，其结果也不见得会比现在好到哪里去。那么不如就把决定权交给广大人民群众吧。例如，让群众可以对上首页的文章进行投票，或顶或踩，当“踩”的数量超过50人，且超过“顶”的20%，那么就让它在首页上消失——当然也可以在被人“拉”回来。至于有朋友提出，某些权威网友的权重是不是应该更高，这我持反对意见，原因还是我认为自己做不到完全客观。现在的digg机制完全是摆设，博客园的开发力量没有用足。&lt;/p&gt; &lt;p&gt;此时，博客园其实要关心的就是技术层面的东西了，例如防止恶意投票，禁止某些人注册帐号不建立博客不写文章——只是为了投票。这方面可以简单，如规定只有注册时间超过1个月，写了10篇以上技术文章，并且不是“为了投票而贴文充数”的人才能投票。也可以复杂一些，使用某些分析方式来找出哪些是有效投票，哪些是无效投票。投票时不妨要求加入评语，据我观察这并不会给用户带来太多麻烦，因为用户本身就都会发表很多评论。&lt;/p&gt; &lt;p&gt;当然，这点需要博客园投入人力开发新功能，因此我想另一种方式可能更容易执行。目前还有一个矛盾就是博客园的“执法”并不透明。例如，没有人知道哪些文章被撤下首页了，理由是什么。因此，我想博客园管理团队在“工作”的时候，可以把自己的工作结果公开：“哪篇文章在哪个时候由于什么原因被撤下首页”。这样亦有“案例”可查，是否存在“双重标准”也容易被监督或自我监督。从现在看起来，“规章制度”效果实在有限，因为不同的人对同一句话的理解相差还是太大。&lt;/p&gt; &lt;p&gt;不过，发首页“要求”还是需要的，但是要尽可能地没有争议。一些“1小时”，“有收获”的套话就可以免了。我觉得，“哪些可以发”这样的要求其实大都难以执行。例如原创可以发，翻译能不能发？翻译不行，那么我“译注”有行不行？可能“哪些文章不可以发”能有操作价值，例如博客园也写着“以下文章不允许发到首页精华区”：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;转载的文章&lt;/li&gt; &lt;li&gt;只有代码的文章&lt;/li&gt; &lt;li&gt;只是提问的文章&lt;/li&gt; &lt;li&gt;软件发布的文章&lt;/li&gt; &lt;li&gt;招聘类的文章&lt;/li&gt; &lt;li&gt;推广、宣传、广告性质的文章&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;但这写的还是不够，为什么？因为您没有看到最近一段时间关于Win 7的推广、宣传、广告性质的文章也铺天盖地吗？&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/1589474.html#comments</comments>
      <pubDate>Sun, 25 Oct 2009 06:51:00 GMT</pubDate>
      <lastBuildDate>Sun, 25 Oct 2009 06:51:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>谈吉日嘎拉的《白话反射技术》及其他（吵架篇）</title>
      <link>http://blog.zhaojie.me/2009/10/jiri-reflection-argue-2-non-tech.html</link>
      <guid>http://blog.zhaojie.me/2009/10/jiri-reflection-argue-2-non-tech.html</guid>
      <description>&lt;p&gt;在技术社区还是以技术为先，在&lt;a href="http://blog.zhaojie.me/2009/10/jiri-reflection-argue-1-tech.html"&gt;上一片文章&lt;/a&gt;里我谈了技术方面内容，那么这次就来谈谈非技术的。&lt;/p&gt; &lt;p&gt;我反感这种社区氛围，火药味不是问题，但是谈技术时不好好谈技术，总是扯上这人如何那人如何，你吃饱了撑的他良心被狗吃了，我实在心烦的慌。&lt;/p&gt; &lt;p&gt;先来谈谈我对吉日嘎拉的看法。说实话，许多朋友不喜欢他，但是我对他没有感觉。我的确非常不喜欢他对待技术的态度：随意，无所谓，将就——但是我对他的个人实在没有什么看法。我也不同意他说为了赚钱而作软件，为了赚钱而写文章，但是我又能用什么来批驳他？我能“视金钱如粪土”吗？我做不到，我无法向FSF一样提倡自由（Free），我最多提倡开源（Open Source）。吉日嘎拉是很招摇，再加上会抛出一些又一些似是而非的结论，在一定程度上的确会误导初学者。但是，如果我们动辄刷的高举反对吉日的旗帜，众人一拥而上进行口诛笔伐，言辞激烈，出口成脏，非黑即白，这又能带给初学者什么帮助？既然吉日的文章是从技术角度误导消费者，为什么我们不能从技术的角度来纠正他，而要用&lt;a href="http://www.cnblogs.com/Jax/archive/2009/10/16/1584527.html"&gt;这种方式&lt;/a&gt;？&lt;/p&gt; &lt;p&gt;包同学的文章中，除了列举了Jimmy Zhang的几篇非常优秀的文章和一本书之外，就只有这句话和“反射”有些关系了：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;最后，不要怀疑反射的应用，三层架构中的数据层和ＤＢ的Mapping，AddIn架构，都离不开反射。这个话题说起来就大了，没有几年的项目实际是感受不到的。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;但是，这除了让人知道反射这个话题很大，没有几年实际项目经验是感受不到……之外，别人又获取了什么信息呢？更让我奇怪的是，包同学举出的两个示例，恰好符合吉日文章中的几个观点（这点在&lt;a href="http://blog.zhaojie.me/2009/10/jiri-reflection-argue-1-tech.html"&gt;前文中已经有所指出&lt;/a&gt;），这种缺乏条理的思维“碰撞”又能给出者带来什么呢？Jimmy Zhang的文章的确好，但是这几篇文章写的是反射的“使用方式”，而吉日的文章写的是反射的“使用场景”，两者完全不构成冲突，又能说明什么问题呢？Jimmy老大的文章是非常正确的，但这不能证明吉日是错的——请注意，我并没有说吉日“一定没错”。我在包同学的文章里也&lt;a href="http://www.cnblogs.com/Jax/archive/2009/10/16/1584527.html#1673560"&gt;表达过类似的意思&lt;/a&gt;：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Jimmy Zhang的确写的好，但是他和吉日写的完全不搭界。Jimmy Zhang写的是怎么用反射的类库，框架，怎么调用等等。而吉日写的是反射的一个使用案例，说白了也就是传统的反射工厂生成一个数据访问层接口的实例。我虽然不同意他对于技术的态度，但是就这个案例本身，虽无闪光点，但又错在什么地方？&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;但是直接被包同学当头一棒：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;你真是扯蛋，我文章的最后一句话就是写给你的。 &lt;p&gt;你俩就惺惺相惜吧。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;而那“最后一句话”：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;最后，质疑那些为其鼓掌叫好的看客，包括一些沽名钓誉的狗屁大腕儿，你们的脑子都进水了？你们到底从中看明白了啥？你们还是做技术的么？你们的技术就全都是这么做的？你们吃饱了撑的在那里摇旗呐喊称兄道弟？你们的良心都让狗吃了？&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;天地良心，我什么时候把吉日文章中错的东西说成是对的了？想了想，我唯一“夸”吉日的话应该&lt;a href="http://www.cnblogs.com/jirigala/archive/2009/10/14/1583396.html#1671762"&gt;只有这句&lt;/a&gt;：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;吉日兄很直接，这点很好。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;我喜欢直接的人，不喜欢娇柔造作的人，所以我说这句话。而我喜欢的也只是吉日的“说话风格”而已，这就说明我支持他说的东西？为什么没有看到我对他文章中错误内容的评价，以及一次又一次对他“无所谓态度”的反驳？为什么我在谈论技术，就非要立马对于个人一顿臭骂？&lt;/p&gt; &lt;p&gt;支持一个人的部分，就说明支持他的全部？别人不能有任何对他的反对，否则就一阵劈头盖脸？&lt;/p&gt; &lt;p&gt;反对一个人的部分，就一定要打击他的全部？别人也不能有任何对他的支持，否则就一阵劈头盖脸？&lt;/p&gt; &lt;p&gt;其实包同学看不惯吉日，只是“风格”上的冲突，“意识形态”的冲突，本和技术无关，或者说完全可以通过技术方面的交流，探索，甚至是“搏斗”都可以解决，但为什么一定要用一些恶毒的语言进行人身攻击？这种讨论技术的态度不可取，尤其是举的例子本身就不恰当——我还是想说，包同学和吉日对于反射的使用场景问题上是统一的，其实唯一的“冲突”也就是“一个认为重要，一个认为不重要”。但是“重要”本身就是个无法量化的程度，这是一个非要拼个你死我活的问题吗？&lt;/p&gt; &lt;p&gt;我不认为兄弟们不知道正确地反驳一个人文章的方式是什么，但是许多朋友一定是被“冲动”二字搞坏了。冲动是魔鬼，这点实在不假，我也是靠着冲动在写这篇文章——不冲动就不是年轻人了。但是，在冲动的时候，还是尽量让“理智”占据上风吧。社区里吵架，吵着吵着就都变成面子问题了，何必呢？&lt;/p&gt; &lt;p&gt;我一直不喜欢“和谐”也不喜欢“和稀泥”，但是我同样不喜欢技术范畴外的冲突。如果要反驳，我们可以着眼于技术。例如，&lt;a href="http://codemonkeyism.com"&gt;Stephan Schmidt&lt;/a&gt;在博客中发表了题为《&lt;a href="http://codemonkeyism.com/generation-java-programming-style/"&gt;下一代Java编程风格&lt;/a&gt;》的文章，阐述了他眼中Java编程风格的改变，以及未来的走向。于是有许多人发表了不同看法，如&lt;a href="http://beust.com/weblog/"&gt;Cedric Otaku&lt;/a&gt;发表了文章《&lt;a href="http://beust.com/weblog/archives/000517.html"&gt;下一代Java与现在差不多&lt;/a&gt;》，逐条批驳。还例如，Patricks Smacchia认为&lt;a href="http://ayende.com/Blog/archive/2009/07/29/what-is-maintainable.aspx"&gt;NHibernate代码不稳定&lt;/a&gt;，Oren Eini不干了，&lt;a href="http://ayende.com/Blog/archive/2009/07/21/answering-to-nhibernate-codebase-quality-criticism.aspx"&gt;逐条批驳&lt;/a&gt;，Patricks老大又&lt;a href="http://codebetter.com/blogs/patricksmacchia/archive/2009/07/29/maintainability-learnability-component-layering.aspx"&gt;撰文反驳&lt;/a&gt;，Oren也&lt;a href="http://ayende.com/Blog/archive/2009/07/29/what-is-maintainable.aspx"&gt;继续&lt;/a&gt;，最后我看着爽，就&lt;a href="http://www.infoq.com/cn/news/2009/08/what-is-maintainable"&gt;总结出一片InfoQ的新闻&lt;/a&gt;。同样的讨论还有譬如“&lt;a href="http://www.infoq.com/cn/news/2009/09/virtually-everything"&gt;所有的成员都应该是virtual的吗？&lt;/a&gt;”，还有前一段时间的&lt;a href="http://www.google.com/search?hl=en&amp;amp;source=hp&amp;amp;q=Duct+tape+Programmer&amp;amp;aq=f&amp;amp;oq=&amp;amp;aqi="&gt;Duct Tape Programmer事件&lt;/a&gt;，都可谓是互联网上的高质量辩论，无数人&lt;strong&gt;独立撰文&lt;/strong&gt;发表了自己的看法。这些才是技术人员应有的风范。&lt;/p&gt; &lt;p&gt;您觉得吉日的文章误导初学者吗？写文章反驳吧！&lt;/p&gt; &lt;p&gt;您觉得吉日的文章充满铜臭味吗？写文章反驳吧！&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.cnblogs.com/Ivony/"&gt;Ivony…&lt;/a&gt;在&lt;a href="http://www.cnblogs.com/Ivony/"&gt;包同学的文章中回复&lt;/a&gt;的我认为很好，摘录如下：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;博客园不应该是一个只能听到权威的声音的地方。或者说我们不能强求首页的每一篇文章都是对的，都是出自某个权威的人士之口。我们只能要求首页的每一篇文章，都是作者用心写的，而不论其对错影响。  &lt;p&gt;甚至于说，文章放在首页就是接受大家的检验的。首页是讨论区而不是公告区。  &lt;p&gt;话说回来，吉日写的文章就算是胡诌乱侃，那又能影响多少初学者呢？或者说一篇胡说八道的文章在首页误导了一大堆初学者，这里面难道没有初学者，以及所谓大牛的责任？初学者不辨是非，大牛们看见错谬而不予指出。  &lt;p&gt;我觉得至少有一点，吉日的文章并不是一无是处，它可能会对初学者产生误导，但避免这一点难道的做法就是牺牲一个人自由发表文章的权利而不是群众的监督么？这未免太过于残忍。  &lt;p&gt;我们今天打跑了一个吉日，难到明天不会冒出另一个吉日？任何时候群众的监督都是有必要的（如果真的有误导的话）。  &lt;p&gt;我不否认吉日的问题很多，标题党，口水文，喊口号，拉旗帜。但如果这些东西真的能误导无知菜鸟的话，我想这些无知菜鸟自己也要负一部分责任才是。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;包同学认为，如果写文章那就是&lt;a href="http://www.cnblogs.com/Jax/archive/2009/09/01/1558156.html"&gt;在用自己的名气打吉日的知名度&lt;/a&gt;。以前记得也有朋友告诉我说，写了一篇批驳某本书的文章后，过一段时间就删了吧，否则还是变相打广告。炒作的越多，书卖的越好，吉日也越出名。但是我认为，书卖的多，吉日出名有什么关系呢？我们的目标是引导初学者，并不是要阻止别人卖书或要打压吉日出名，我们是在追求一个真理。当社区里批驳吉日的（有价值的）文章越来越多，到底什么是对的什么是错的也就一目了然，就算吉日名气再响又如何？我批驳一本书，我还希望这篇文章能够满山遍野的转载，让任何一个买书的人都能看到我的文章。有人是会感兴趣，然后去买，那又如何，他看了大量的驳文，自然知道什么是对的，什么是错的。&lt;/p&gt; &lt;p&gt;排错，也是需要教材的，不是吗？&lt;/p&gt; &lt;p&gt;我已经&lt;a href="http://blog.zhaojie.me/2009/10/jiri-reflection-argue-1-tech.html"&gt;写了一篇文章&lt;/a&gt;，接下来就要靠大家了。挑出你最不满的吉日的文章，逐条反驳吧。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.tudou.com/programs/view/zDGo3z2HZ-0"&gt;吵，吵个大西瓜。&lt;/a&gt;&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/jiri-reflection-argue-2-non-tech.html#comments</comments>
      <pubDate>Fri, 16 Oct 2009 13:08:00 GMT</pubDate>
      <lastBuildDate>Fri, 16 Oct 2009 13:08:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>谈吉日嘎拉的《白话反射技术》及其他（技术篇）</title>
      <link>http://blog.zhaojie.me/2009/10/jiri-reflection-argue-1-tech.html</link>
      <guid>http://blog.zhaojie.me/2009/10/jiri-reflection-argue-1-tech.html</guid>
      <description>&lt;p&gt;社区又掀起了腥风血雨，这次又是吉日嘎拉这一博客园的众矢之的所引发的惨案。他的一篇《&lt;a href="http://www.cnblogs.com/jirigala/archive/2009/10/16/1584408.html"&gt;白话反射技术&lt;/a&gt;》发表之后，被包同学一篇文章&lt;a href="http://www.cnblogs.com/Jax/archive/2009/10/16/1584527.html"&gt;狠狠地踩在脚底下&lt;/a&gt;，言辞之激烈令人罕见。从两片文章的内容与评论来看，大家的眼光似乎都没有集中在技术本身，而是针对个人在你来我往。有评论称这是“门派之争”，虽然看不出到底哪门哪派，但看上去也还真像那么一回事情。不过这真是技术社区该有的讨论氛围和方式？如果觉得吉日嘎拉在技术上有问题，难道不应该条条指出吗？既然没有人做这件事情，那么就还是我来吧，反正我写博客也成习惯了。&lt;/p&gt; &lt;p&gt;文章还是分两篇吧。先谈技术，再谈非技术——这样某些朋友也可以有选择地忽略某个部分。&lt;/p&gt; &lt;p&gt;反驳一个人的观点，我认为最简单而直接的方式是逐条批驳，必要的时候可以引用原文。首先，吉日写到：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;使用反射有几个误区：反射的性能慢？其实未必反射的性能是慢的，说不定有些场合，反射的性能是更快更高效的，不用它的优点，用了他的弱点，那就无法达到高效的目的了，文章的结尾也说说我的观点。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;我同意他的部分观点。“反射性能差”的确是相对的，例如反射调用一个方法，访问一个属性的确比直接访问要慢上许多。但是对于一个普通应用程序来说，反射几乎不会成为性能瓶颈，因为性能瓶颈往往是由外部IO操作造成的。例如，一个数据库访问，一个Web Service调用，就算是有朋友认为的Remoting这个性能非常高的分布式调用方式，它的通信性能也远比反射要慢好几个数量级。假设一个反射消耗的时间是0.0001秒，那么它的确比直接调用消耗的0.0000001秒慢上一千倍，但是它还是可以在1秒钟执行1万次，不是吗？但是我们平时的SQL查询，有哪个可以如此高效？&lt;/p&gt; &lt;p&gt;此外，我们现在也有很多方法可以加快反射调用的性能，例如我曾经写过的一个&lt;a href="http://blog.zhaojie.me/2009/01/fast-reflection-library.html"&gt;简单小类库&lt;/a&gt;，可以保持反射调用的方法不变（如只是把Invoke方法调用变成了FastInvoke），但是性能也接近了直接调用。这是因为使用了Emit动态生成了IL代码，这样在调用的时候便和直接调用如出一辙。对于需要大量使用反射的场景，例如NHibernate需要通过反射为属性一个一个赋值，那么它一般也会使用类似的机制来提高性能。&lt;/p&gt; &lt;p&gt;至于是否有“某些场合”反射的性能是更快更高效的，我想不出来。不过如果只是“利用了它的弱点”，那一定是不合适的，这就是所谓的“滥用”。&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;我在日常开发中反射常用的几个环节，其实架构师架构系统反射等用得多，程序员日常开发里，其实不懂也没啥大不了的。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;我“直觉上”不同意这种使用“架构师”、“架构系统”来划分反射作用适用性的方式，但事实上我也无法在这方面说出个所以然来。或者说，我只能说一句废话：“&lt;font color="#ff0000"&gt;该用反射的时候就使用反射&lt;/font&gt;”，普通程序员还是一定要懂反射的。&lt;/p&gt; &lt;p&gt;在很多时候反射也是唯一的选择。为什么我们会选择使用反射？因为我们没有办法在&lt;font color="#ff0000"&gt;编译期&lt;/font&gt;通过&lt;font color="#ff0000"&gt;静态绑定&lt;/font&gt;的方式来确定我们要调用的对象。例如一个ORM框架，它要面对的是通用的模型，此时无论是方法也好属性也罢都是随应用场景而改变的，这种完全需要&lt;font color="#ff0000"&gt;动态绑定&lt;/font&gt;的场景下自然需要运用反射。还例如插件系统，在完全不知道外部插件究竟是什么东西的情况下，是一定无法在编译期确定的，因此会使用反射进行加载。其实，包同学的反驳文章里也是持这种观点的：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;最后，不要怀疑反射的应用，三层架构中的数据层和DB的Mapping，AddIn架构，都离不开反射。这个话题说起来就大了，没有几年的项目实际是感受不到的。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;“数据层和DB的Mapping”或是“AddIn架构”，其实都是架构层面的内容，刚好符合日吉的观点“其实架构师架构系统反射等用得多”，那么这架究竟是怎么吵起来的呢？&lt;/p&gt; &lt;p&gt;接下来吉日展示了他使用反射的常见场景。其中提到：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;两个类，需要互相调用了&lt;/strong&gt;，不能直接进行互相引用了，那不是死循环了？例如我这里2个包里的窗体之间，需要互相调用，就用了反射技术，直接动态的从dll 包里把相应的窗体呼叫出来，当然我也不想用反射但是不用不行了，没有其他更好的解决方法了，我不是为了玩技术用技术，而是实际开发中遇到问题了不用不行了，才用反射技术。&lt;/p&gt; &lt;p&gt;……&lt;/p&gt; &lt;p&gt;我们在开发大型软件项目时经常会遇到，系统很庞大了有几百M的代码了，主程序启动时，总不能把这些都引用了吧？全部加载在内存里？那程序的启动速度，不知道会不会慢如老牛推车了？这时候也会用一些反射技术等，用到哪个窗体，就动态加载哪个那个窗体，总感觉比较清爽一些。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;在我看来，这段话可谓&lt;font color="#ff0000"&gt;完全是错误的&lt;/font&gt;。&lt;/p&gt; &lt;p&gt;两个类，如果需要互相引用，那也就是产生了双向依赖。如果这是设计上的问题，那就应该从设计的角度来解决。如果“直接动态从dll包里把相应的窗体呼叫出来”，这难道还不是一种双向依赖吗？难道因为“编译期”可以通过了，在“运行时”就解耦了？这只是把依赖关系给隐藏起来了，“总感觉清爽一些”，这平白无故的感觉要不得。这种反射的使用方式在我看来就是一种滥用，因为这完全可以在编译期通过静态绑定的方式来确定调用目标。如果使用反射，那么就无法由编译期来进行检查，这样项目的第一道防线也就丢失了。&lt;/p&gt; &lt;p&gt;根据吉日的观点：“系统有几百M的代码，主程序启动时把所有的代码都加载了”。事实上，CLR并不会这么做。&lt;a href="http://www.informit.com/articles/article.aspx?p=30601&amp;amp;seqNum=5"&gt;如Essential .NET所云&lt;/a&gt;：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;The CLR loader is responsible for loading and initializing assemblies, modules, resources, and types. &lt;font color="#ff0000"&gt;The CLR loader loads and initializes as little as it can get away with. Unlike the Win32 loader, the CLR loader does not resolve and automatically load the subordinate modules (or assemblies). Rather, the subordinate pieces are loaded on demand only if they are actually needed (as with Visual C++ 6.0's delay-load feature).&lt;/font&gt; This not only speeds up program initialization time but also reduces the amount of resources consumed by a running program.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;事实上，CLR只有在真正需要某个程序集的时候才会进行加载，因此不会因为程序庞大而“启动速度慢如老牛推车”。&lt;/p&gt; &lt;p&gt;而接下来，吉日写的是大家最常见不过的“通过反射加载数据访问层来应对不同数据库”：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;我只写一份商业逻辑，但是希望能跑在多种数据库上&lt;/strong&gt;，我配&lt;strong&gt;套每种数据库的商业逻辑部&lt;/strong&gt;分都相应的写一份，那我的工作量是加倍的，每个包都要进行测试、维护、升级、改进、调试、优化，世界超级大国美国也只能同时进行2个局部战争，你能同时谈3-4个女朋友，那我真服了有本事啊，一般会没多久就会穿帮了，维护几个数据库访问方法倒是不会工作量很大，相对来讲是有限的。&lt;/p&gt; &lt;p&gt;……&lt;/p&gt; &lt;p&gt;配置文件里，明确指出，我需要用什么数据库，什么连接串等。&lt;/p&gt; &lt;p&gt;……&lt;/p&gt; &lt;p&gt;我的数据库访问工厂里，按配置读取相应的数据库连接类、实例化相应的类。&lt;/p&gt; &lt;p&gt;……&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;这也是典型的使用方式，被无数人翻来覆去写过，被更多人翻来覆去使用过的方法。PetShop也是这种做法，因此虽然我不喜欢这个，但我也的确挑不出毛病来。&lt;/p&gt; &lt;p&gt;我说我不喜欢这种方式，是因为我认为这种数据访问层的写法过于机械，也比较难以使用，代码较多，经历了几个项目之后我被搞得非常疲惫。我目前比较欣赏的方式是基于ORM框架编写的数据访问层。我接下来也打算谈谈我理想中的设计，不过这里就不多谈了。&lt;/p&gt; &lt;p&gt;我发现，其实这也是包同学提出的反射场景之一……我真的搞不明白，这一架究竟是怎么吵起来的！？&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;这些用到的反射、系统架构时调试通过了，别人也根本没兴趣研究了，也不需要所有的人都折腾反射，偶尔需要用时，照葫芦画瓢就可以了，先copy然后past，然后修改几个名称什么的，然后run，运行正常了，就懒得管了，不行就dbug。&lt;/p&gt; &lt;p&gt;我们公司没几个人用到反射，公司里估计就2个人，其中一个也是用DNT的现成的，我这个是自己折腾出来的。实际工作中需要了，就用用，或者想学技术，就自己弄弄，没必要为了显示你技术都少厉害非牵扯个反射出来。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;“没必要为了显示你技术多少厉害非牵扯个反射出来”，我同意。技术的确是为了用的，不是为了显摆的，但是这并不是“不去学反射”的理由。这也是我不喜欢吉日最主要的原因，就是他对于技术的一种“无所谓”的“将就”态度。一直听到这种说法，技术不用特地学，等用到了再学，边学边用。但是，如果你不去学技术，又如何可以得知哪个技术适合你目前的使用场景？有很多朋友说工作就是日复一日的重复，没有长进。这可能是多种原因造成的，但是我想如果抱着“不主动学习技术”的心态，那么不断重复还真不是“无法想象”的情况。&lt;/p&gt; &lt;p&gt;但也有朋友会回复说，有些人他的确不是热爱技术的人，也只喜欢过普通的日子，我和他们不是一个情况，无法理解。的确，我可能真的无法理解，因此我也只能不断地推广、表达、推广我对技术的理念，而不会，也无法把自己的观点强加给别人。&lt;/p&gt; &lt;p&gt;最后，吉日谈了他最讨厌的反射使用场景：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;or mapping 什么的，一个类里的属性，方法通过循环读取出来，然后一个类的保存，读取，能自动实现什么的，若有10000个对象的，每个对象有50个属性，那得循环多少次？不是循环死人啊？还有就是 .net 的类型与数据库类型的转换匹配，null 的匹配等空日期的匹配转换，多种数据库类型的转换，我看了这样的代码，就恶心想吐，为了提高性能还需要延迟加载什么的搞得死去活来，我们不是搞研究玩技术的，把项目又快又好又简单的做好，客户满意，能及时拿到项目款就可以了，杀鸡用刀就可以了，别还先打一会儿太极，再品茶啥的，赶紧杀鸡啊，我看着都心急。  &lt;p&gt;后来事实证明，代码生成器还是蛮好用的，不是靠反射循环搞定问题，而是通过机器来产生代码，这个的确比较好，我也喜欢。我也曾经用过很多乱八七糟的技术，现在懒得玩，懒得学习了，跟着微软屁股后面跑微软哪个成熟了，我就玩那个，平时关注一下发展动向，不是微软的能不用就不用了，我不想折腾了。  &lt;p&gt;单个技术，都是非常好的，但是组织到一起就容易乱套了，不伦不类，而且把性能优化到最好需要更高的水平了。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;ORM是大量使用了反射，它的代码的确也“不甚美观”，因为反射本身是很丑陋（好吧，应该说是“麻烦”）的调用方式（C# 4.0的dynamic关键字则很好的解决了这个问题）。但是这不正常吗？我曾经在互联网上看到过这个说法：“任何美丽的接口后面都有丑陋的实现”，美妙的接口，好用API，它的目的就是帮你在项目中避免“亲自”操作这些丑陋的内容。&lt;/p&gt; &lt;p&gt;ORM框架的作用就是为了帮助开发人员更好的完成项目，把大量复杂的实体和数据库的关系映射起来，并且实现了常用的CRUD和具有一定程序灵活性的查询方式。我现在是完全离不开ORM了，我理想中的数据访问层设计也是沿袭了ORM的&lt;font color="#ff0000"&gt;使用方式&lt;/font&gt;。而NHibernate的首席开发人员&lt;a href="http://ayende.com/Blog/"&gt;Oren Eini&lt;/a&gt;还在&lt;a href="http://ayende.com/Blog/archive/2009/04/22/using-active-record-to-write-less-code.aspx"&gt;他的一次NDC的演讲中认为&lt;/a&gt;不该为数据访问层花费&lt;strong&gt;任何&lt;/strong&gt;时间，应该把时间放在和业务相关的代码上面，否则就是浪费金钱。&lt;/p&gt; &lt;p&gt;换句话说，使用ORM框架，其实就正好符合吉日“把项目做的又快又好又简单”的要求。的确，学习ORM需要成本，但也有俗话说“磨刀不误砍柴功”。如果说为了某个项目特地磨刀是浪费时间，加大风险，那么为什么不就在平时点滴时间内进行学习呢？如果你不学，那么你下个项目还是不会用，这样“要用再学”也永远只能是个梦想了。&lt;/p&gt; &lt;p&gt;至于代码生成器，的确好用，我也推荐多用。吉日在这里至少比手动硬写数据访问层的人聪明多了。他对于技术的态度，我还是不喜欢，但是可能的确可以反应一部分人的想法。&lt;/p&gt; &lt;p&gt;对于吉日文章的技术部分评价我就写到这里了，的确有不少问题，但也并非无一可取之处。看许多朋友和吉日的冲突，也大都是“意识形态”方面的问题吧。但既然是技术社区，那么我们至少也应该在技术角度上“率先”给予反馈——或反击吧？&lt;/p&gt; &lt;p&gt;嗯，我已经处理完技术方面的问题，那我也立即开始非技术方面的准备了（&lt;a href="http://blog.zhaojie.me/2009/10/jiri-reflection-argue-2-non-tech.html"&gt;“吵架篇”在此&lt;/a&gt;）。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/jiri-reflection-argue-1-tech.html#comments</comments>
      <pubDate>Fri, 16 Oct 2009 11:16:00 GMT</pubDate>
      <lastBuildDate>Fri, 16 Oct 2009 11:16:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>博客二三事</title>
      <link>http://blog.zhaojie.me/2009/10/talk-about-blogging.html</link>
      <guid>http://blog.zhaojie.me/2009/10/talk-about-blogging.html</guid>
      <description>&lt;p&gt;其实我一直想写篇文章来谈谈博客这些方面的事情。我虽然在博客上投入了很多，它也是我工作和生活中非常重要的一部分，也自认为写的不少亦不差，但是一直缺少对这方面的总结，以及系统的思考。即便是看着一轮又一轮地“年度总结”过去，我也没有针对我的博客讨论过什么内容。之前也有过朋友问过我博客方面的事情，也有一些讨论引起我的思考，但都没有下决心写点文章。而这次就趁着一些冲动，细细谈一下博客方面的事情吧。&lt;/p&gt;&lt;a href="http://spreadsheets.google.com/pub?key=trKisr-Yy-y5KQihKkezyiA&amp;amp;oid=1&amp;amp;output=image" target="_blank"&gt;&lt;img class="floatRight" src="http://spreadsheets.google.com/pub?key=trKisr-Yy-y5KQihKkezyiA&amp;amp;oid=1&amp;amp;output=image" width="250"&gt;&lt;/a&gt;  &lt;p&gt;从2006年开始写第一篇博客至今，我已经写了整整三年的技术博客了。从我博客右侧的“随笔档案”一栏，可以观察到我每个月&lt;a href="http://spreadsheets.google.com/pub?key=trKisr-Yy-y5KQihKkezyiA&amp;amp;output=html"&gt;写博客的趋势&lt;/a&gt;（如图）。记得起先我是靠分析ASP.NET AJAX源代码得到社区肯定的，不过在一开始并不顺利，因为当年在ASP.NET AJAX方面的社区领袖是&lt;a href="http://www.cnblogs.com/dflying/"&gt;Dflying Chen&lt;/a&gt;，声势如日中天。当时ASP.NET AJAX还处于CTP版，还叫Atlas。直到有一天，微软发布了Beta 1，推翻了CTP中的几乎一切。在社区一片抱怨声中，我在一个周末翻译了ASP.NET AJAX Quick Start的全部7篇（还是9篇）内容，发表在博客上。从这时候起，我开始得到了社区群众的认同。&lt;/p&gt; &lt;p&gt;这几年博客园发生的事情大都记不清了，不过上面情况还可谓历历在目——不过这些不是重点，我想说的是，有朋友说我能写，写得多，产量高，其实这也是阶段性的。&lt;/p&gt; &lt;p&gt;从图表上来看，一开始的几个月更新比较多，之后我也开始有些懈怠，博客的更新频率也减少到了每月10篇左右，中间在07年的8月和9月还有过停止（具体原因记不清了），不过最终还是保持了一定的写作频率。不过到了08年春节后，基本上就很少更新博客了，其中的少量文章也大都和技术无关，直到09年开始我才重新开始有规律的博客更新。这大半年的时间里，我大都把精力扑在工作上，还有便是减肥（&lt;a href="http://blog.zhaojie.me/2009/03/lose-weight.html"&gt;效果相当明显，前后总共减了80斤&lt;/a&gt;，而且保持到现在还没有反弹）。进入了09年，我开始加大了博客的写作力度。其中最主要的原因是在这停滞的大半年中，积累了非常多的素材。慢慢的，写博客也成为了我的习惯，几乎一天不写就会感觉不对，写作频率也越来越高，几乎到了一天两篇的地步。&lt;/p&gt; &lt;p&gt;所以我认为，产量高只是一个“现象”，而最终的关键还是两个点：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;积累素材  &lt;li&gt;养成习惯&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;记得从小写作文就被教育说，要注意观察生活，要拿个小本子记录点滴。如果放到了技术方面，它其实也就相当于保持对技术的敏感程度，多进行思考和记录。我一直劝别人写技术博客，但经常有人回应我说“没有内容好写”。我觉得很奇怪，因为我觉得工作会给你带来许许多多的素材。例如，对今天的产出是否满意，该如何提高效率，怎么做可以更好等等。当看到某个新技术新名词时，可以和自己以前接触过的内容进行交叉比较和联想，这也可以产生题材。我认为，只要我们在不断的吸收新东西，不断地寻求改进，总是有东西可以写的。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/168980/o_kindle-dx.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/168980/r_kindle-dx.jpg" width="250"&gt;&lt;/a&gt;
&lt;p&gt;有朋友猜测我是个技术狂人，生活中只有技术。不过我个人认为，我的生活其实还是挺丰富多彩的，每周要去健身房三次，周六整天基本上是用来看电影看美剧和玩游戏。但是，我基本上不会让自己的思考停顿。例如，我在每次跑步之前，都会特地在脑子中记录一些需要思考的问题，如果在去健身房的路上忽然发现脑子空了，我甚至会回到电脑前“自寻烦恼”，例如快速地浏览某个语言特性思考它能怎么改进API设计，例如查看To-Write List中某个可写的话题，思考我该使用哪些示例如何论证等等。这样，我在枯燥乏味的跑步和洗澡过程中也能最大限度地利用时间，而且此时你会发现，5000米的距离不知不觉就跑完了。同样的，我每天上下班时单程要花费1小时15分钟甚至1个半小时的时间，但是在这段时间里我会抓紧时间，在漆黑的路上想问题或看手机，在地铁等有灯的环境里看书。后来为了保证效率，我又下狠心投资了四千多元钱买了一个&lt;a href="http://www.amazon.com/Kindle-Wireless-Reading-Display-Generation/dp/B0015TCML0"&gt;Kindle DX&lt;/a&gt;（如图），这样我便可以在其中放入许多不同的书，根据当前的心情，想看技术内容就看技术，没心情就看点小说或历史等等。看得多，思考的多，自然可写的内容也多。目前在我的To-Write List中还有大约20条左右的纪录，虽说并不都能成文，但也至少已经可以保证我下个星期的写作内容了。&lt;/p&gt; &lt;p&gt;不过，三心二意也有副作用，例如我不止一次把换下来的运动衫留在健身房，拎着空包离开了——还好我大都能及时回去拿。&lt;/p&gt; &lt;p&gt;有人问我，你每天要写那么多博客又回复那么多，那么你要花多少时间？我承认，的确不少，但是应该也没有你想象中多。因为我打算写的内容，都是事先准备好的，可能在此之前已经利用零碎的时间想的清清楚楚明明白白，甚至连提纲也已经列好，只等“码字”。如果您已经完全想清楚要写什么东西的时候，其实写作的速度是很快的。记得在高考时，往往都要求在30-40分钟内写出1000字的文章，其实我写文章的速度也和它差不多。但是我写文章和高考时的区别便是，高考是在绞脑汁憋字眼（好吧，我只能说我是这样的），而现在我更像是“倾斜而出”，或是“整理”和“组织”。一般来说，现在我可以在1小时内写大约2000字的“纯文本”，或者1000多字带有代码的文章。代码是时间杀手，它会打断思路，让它变得美观也是一件需要耗时调整的事情。在一段时间内它让我有些苦恼，不过现在也已经熟练了，配合着色插件，效率有了质的提高。这也是合适工具的威力。&lt;/p&gt; &lt;p&gt;从我在博客上出没的时间上来看，我的确是在工作时间访问博客园，甚至写博客。不过由于我文章写得比较快，因此一般9点到公司后会立即动手，而中午花15分钟吃完饭（有食堂就是快）之后，又进入了中下午的写作时间。基本上来说，目前的做法不会影响工作。还有便是，我的工作比较自由，老板也对我比较放心，因此我可以在博客上花比别人相对更多的时间。我必须承认，博客是为我自己而写的，但是我也想表达这样的意思，就是我写博客，公司也可以获利。因为我的博客是我的思想总结，几乎全部是我工作中的体会，而这个总结是公开的，这也是公司其他员工可以访问的资源。例如，有许多情况下，在同事遇到某些问题的时候，我会给出自己之前写过的某篇文章给他作为参考。相对的，如果我为他解决了这个问题，我也会尽早将其写成博客。此外，写博客对我个人的提高，我的提高最终还是可以反映到公司的效绩上。在这种“思维方式”的驱动下，我占用工作时间写博客可以说是心安理得。而且，似乎也不是我一个人这样想的，例如有人认为&lt;a href="http://codebetter.com/blogs/karlseguin/archive/2009/05/07/part-of-your-job-should-be-to-learn.aspx"&gt;学习必须是工作的一部分&lt;/a&gt;，你应该向你的老板提出这一点。我想，一个坚持博客的人，他一定会有良好的表达能力，这是成为一个优秀技术人员的基础。&lt;/p&gt; &lt;p&gt;但是，既然学习是工作的一部分，那么学习也必须要有可以衡量的产出。我看到有些朋友会抱怨说在工作中很忙，而且学不到东西。我想说的是，如果你确定要学习，就要“证明”你真的学习并提高了。而证明你学到东西的最好方式之一，便是写出总结或心得体会，而这自然而然就成为博客了。我一直也劝我的同事写博客，我想如果大家都写博客，那么相当于在公司内积攒起了大量的Knowledge Base，便可以相互交流，共同提高——可惜，效果几乎没有。因此我认为，对于大多数人来说，不写博客的根本原因还是在于自身，并不是公司等外部环境。&lt;/p&gt; &lt;p&gt;博客也是个人的经验的总结，坚持一段比较长的时间之后，你便可以通过回顾之前的内容来了解自己思维方式的变化。我从自己的博客中看到了自己明显的成长轨迹，以及对待相同事物的看法。回想一下，您是否还记得去年的今天你在做什么，对于目前你手头的工作会有什么看法？事实上，对于一个人来说，了解别人的发展轨迹都比了解自己来的彻底。如果没有文字这种记录形式，日子一天天地过去，真也就过去了。我不时会听到一些朋友抱怨说，以前某某事情明明知道怎么解决的，现在冥思苦想也回忆不起来了。此时我就会想说，既然互联网上找不到解决方案，以前你又知道该怎么做，为什么当时没有写一篇博客记录下来呢？&lt;/p&gt; &lt;p&gt;此外，当你有了博客，当你在互联网上用这种持久性的方式来展示你自己时，也能获得很多回报——即使你的本意并不是这些。例如，你可以认识更多的朋友，你可以提高自己在社区的知名度，获得更多的机会，也从来不会缺少“猎头”，博客就是我最好的简历。因此在我看来，专业博客应该属于一个人职业发展中非常重要的组成部分。例如我自己，我在写技术博客之初，并没有想过要如何如何，在当时我看到社区中的专家也是敬仰万分，更没有想到我会在.NET技术社区留下一些印记。但是坚持博客之后，我发现我也能做到很多东西。例如，我也可以轻松地申请到MVP，我也有机会在MSDN Web Cast和TechED等技术会议上作演讲。诚然，获得机会的同时也会带来压力，但压力在一定程度上也是一种动力。例如，我为了维护在社区中的“光辉形象”，就必须先于大部分人把一个问题给挖深挖透，这样才不至于“露陷”。例如，我在做了InfoQ中文站的编辑之后，就必须订阅大量博客，并且在关注世界范围内的技术讨论，必须让自己用客观的头脑去思考，去比较，去分析。久而久之，这些原本是在压力下“不得已”的做法慢慢变成了习惯，最终提高的还是我自己。&lt;/p&gt; &lt;p&gt;有人说，真正的高手哪会写博客，他们的工作很忙，写博客的都只是半桶水。我不这么认为，你看我博客栏右侧收集的博主们，有哪个你认为是半吊子？这只是一个做事方式和习惯问题而已。习惯真的很重要，它可以让一件事情成为自然，如自然而然的写博客，让你在享受便利的同时也不会觉得有任何负担。但习惯也是需要坚持的，我在国庆8天内放纵了8天，差点都没有心思写博客了。幸好，我还是坚持了下来。&lt;/p&gt; &lt;p&gt;在这三年时间里，我的写作风格也是在不断变化。从一开始，我是抱有“讨论”的心态来写文章，虽然一贯追求严谨，但还是比较自然，随意。后来我在得到社区认可之后，心态也慢慢发生了变化，写文章的目的也慢慢变成了“传道授业解惑”。如果您观察我几个月到半年前的文章，会发现它们是我写博这段时间内质量最高的，文章都很长，几乎篇篇三五千字，因为我几乎都是以写书的要求在写文章——虽然我从没写过书，那么就算是“理想”中的书吧，希望能够“无可挑剔”。那段时间是我写博客最痛苦的时段，对脑力的消耗很大。忽然有一天我意识到这并不是我所期望的方式，我并不是想通过“教别人”什么东西来获得满足感，我需要的是讨论，是提高。于是，我几乎在一刹那间完成了写作方式上的改变。例如现在，我会写越来越多我自己的心得体会，我犯的错误，甚至是我自己还不够成熟的猜想。于是，文章数量自然而然就上升了，而且评论也热闹了很多，我有时候可以静静的在一边看别人争论，从中吸取灵感——于是又冒出了下一篇博客的素材。写作——讨论——思考——再写作……这是一个良性循环。&lt;/p&gt; &lt;p&gt;我也乐于讨论，也乐于看到别人指出我的错误，因为在这时候我得到了反馈，就好比别人在指点我，最终提高的是我自己。所以，我有时候很不理解某些作者会说“我写博客是我的事情，你凭什么来指手画脚”。在我看来，写博客的目的便是引发讨论（你说放在首页却不希望别人评论……）如果只是看到“顶”、“学习”之类的支持，虽然是善意，但又有什么意义呢？让别人多多指出问题还可以避免在一片赞扬声中沉迷，我认为社区是盲目的，会盲目地认为一个人是专家，进而盲目认为一个人是权威，进而对他的言论不产生任何怀疑。我承认，被人吹捧的感觉很好，但是在短时间的飘飘然之后我也会提醒自己，我不是来要满足感的，我是来讨论的，社区群众的盲目支持和追捧是有害的。同样，当看到一个人对我有批评，我肯定还是会不爽，但我也会提醒自己吸取好的——可惜我在认为自己正确，而对方在不停“乱来”（甚至故意找茬）的情况下还是会心急。&lt;/p&gt; &lt;p&gt;因此我认为，写博客真可谓“有百利而无一害”，我在招聘的时候也会更倾向于接受能坚持对自己的学习过程进行总结的人，&lt;a href="http://haacked.com/archive/2007/01/27/On_Hiring_Bloggers_and_Open_Source_Developers.aspx"&gt;也不仅仅只有我这么做&lt;/a&gt;，&lt;a href="http://haacked.com/archive/2006/10/04/Better_Recruiting_Through_Blogistry.aspx"&gt;把博客作为招聘依据&lt;/a&gt;也比看简历、看“年份”要靠谱多了。所以，如果您还没有写技术博客的习惯，现在就开始写吧。如果您是公司的Leader，也请在团队里建议大家写一些技术博客吧。&lt;/p&gt; &lt;p&gt;我也会坚持下去的。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/talk-about-blogging.html#comments</comments>
      <pubDate>Thu, 15 Oct 2009 17:03:00 GMT</pubDate>
      <lastBuildDate>Thu, 15 Oct 2009 17:03:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>关于排错：专注思考，细心观察，步步为营</title>
      <link>http://blog.zhaojie.me/2009/10/about-debugging.html</link>
      <guid>http://blog.zhaojie.me/2009/10/about-debugging.html</guid>
      <description>&lt;p&gt;时常有朋友发邮件给我，说遇到了一个什么什么奇怪的问题，不知道是怎么回事，希望我帮忙看看。我基本上每天都会抽出或长或短的时间来回复这些邮件，不过也经常发现，其实许许多多的问题都完全是有能力自行解决的。在很多时候，我发现许多朋友还缺乏最基本的解决问题，分析问题的方式。其实我在平时工作中也会遇到各种各样的问题，有时候甚至异常古怪，但是在仔细分析之下，往往都能解决。于是我现在打算谈点解决问题的基本方式，希望可以帮到一些朋友。&lt;/p&gt; &lt;p&gt;如果您也有着方面的体会，也可以分享一下，即使是某个简单案例也是很有帮助的。&lt;/p&gt; &lt;p&gt;要解决问题，首先是要定位问题，配合正确的推理方式，再仔细分析，“动手尝试”很可能只是验证推理是否正确的手段而已，其实大部分的情况都可以用思考来得出（或排除）。要定位问题，很重要的一点便是要把概念理清。很多朋友会轻视概念，认为那种“理论”有什么重要的，最关键的是“动手”——但殊不知概念能让您的“动手”少走很多弯路。&lt;/p&gt; &lt;p&gt;例如，在一个问题出现之后，我往往会心想，这到底是“开发时”还是“运行时”的问题。我们在做开发时会用到许多概念，有些是“开发时”的概念，有些则是“运行时”的概念。我们开发会用到很多工具，Visual Studio是一个大工具，但是它也会把很多功能，如“编译”等操作委托给外部的命令，VS只负责捕获那些输出而已。而在运行的时候，根本不会关VS什么事情。之前我写过一篇文章，&lt;a href="http://blog.zhaojie.me/2008/08/the-csproj-file.html"&gt;指出csproj，sln等等都是开发时的概念&lt;/a&gt;，它们离开了Visual Studio，MSBuild等开发工具之后，就没有任何作用了。同样，“项目模板”也是Vistual Studio才知道的东西，而运行的根本不会关心所谓的ASP.NET Web Site还是Web Application。&lt;/p&gt; &lt;p&gt;于是，许多问题的排错就可以有大致的方向了。许多做ASP.NET的朋友都会问：“为什么我创建的ASP.NET AJAX项目可以运行”，但是用“ASP.NET Web Application”创建的项目就没法使用ASP.NET AJAX了呢？很明显，这个问题的关键不在“使用什么模板创建的项目”，而是这个项目中的内容是否可以执行，更确切地说，是某个文件夹下的内容能否使用ASP.NET AJAX——因为对于IIS来说，它不会关心“项目”（也就是csproj文件）在管理哪些资源，它只知道“网站目录”。&lt;/p&gt; &lt;p&gt;好，既然知道是网站内容的问题，那么接下来就应该比较的是“一个可以运行的网站”和“一个不能运行的网站”究竟有什么区别。ASP.NET站点最关键的东西便在于web.config，“能够运行”往往也是web.config来决定的。例如，你有没有正确配置HttpModule或HttpHandler。在许多情况下，解决了ASP.NET站点的web.config，问题也就解决了大半。同样的情况还会有，为什么同样的代码（标记）在有的aspx上就能解析成功，有的就不行？那可能是web.config中没有引入正确的control标记或命名空间造成的。&lt;/p&gt; &lt;p&gt;有朋友可能会说，你知道web.config的那么多节点是做什么的，自然容易排错，我都不知道，怎么知道问题在哪里？其实，我也不知道很多东西，但是我会比较。我一开始用VS写F#程序的时候，都只是用一个文件来练习。后来想要用多个模块了，于是就创建新的源文件。但是我发现，main方法总是说写在新文件里的模块“还没有定义”，这让我很困惑。于是乎，我去网上找一些示例——不是普通代码片断，而是一些用VS编辑的小型项目，它们自然是能够编译通过的。例如，我拿到了项目A，我就开始比较它和我的写法究竟有什么问题——观察下来没有任何收获，我还是觉得我的做法没有任何问题。于是我尝试着在A项目中添加我的模块——奇怪，在A的main方法中还是访问不到新模块——这不是欺负人么！&lt;/p&gt; &lt;p&gt;于是我进行更深入的比较，比较除了源文件之外，它的项目设置和我的项目设置有什么区别——还是没有！我抱着最后一丝希望，将A项目中的代码添加到我的项目中来，编译，还是失败！但是看到这个结果，我反而看到了解决问题的曙光。因为我都已经把源代码统一了，这样可能发生错误的地方可谓少之又少。刚才我提到，VS将编译工作交给外部命令执行，对于F#也一样。于是我就比较项目A和我的项目在编译时的输出，终于发现两者的区别在于调用fsc.exe的时候，参数顺序不同。F#的编译器和C#编译器不同的地方在于，它对源文件指定的顺序是有要求的，只有放在后面文件中的代码才能访问到前面文件中定义的内容，反之则不行。这意味着，main方法必须作为最后一个源文件存在。但是，VS并没有提供一个选项来调整源文件的顺序，既然这样，那就手动编辑fsproj文件吧。至此，问题解决。&lt;/p&gt; &lt;p&gt;我被这个问题困扰很久的原因，就是在于我从来没有去怀疑过F#编译器对源文件的指定顺序是有要求的。我之前也观察过fsc.exe的参数，但是并没有“看出”什么问题出来。但是，我会和一个成功的项目慢慢比较，把我的项目和它慢慢靠拢，我用这种方式排除了各种错误可能性，最终把我的关注点又“逼迫”到编译器的参数上。进行比较，尝试，最终解决问题。再此之前，我也不知道这一点，不是吗？您其实也一样，如果遇到了一个奇怪的问题，没关系，找一个成功的案例，详细比较为什么它能行而我不行，慢慢地向它靠拢。最终解决问题的时候，就是你获得新知识的时候。这样，你的“经验”增加了。&lt;/p&gt; &lt;p&gt;类似的做法还有：不时有朋友会问到，它的WebForm项目出现了这样那样的问题，例如在PostBack之后事件没有执行，状态没有恢复，读不到某个值等等。从我的经验上来说，这是遇到了生命周期的问题。但是，生命周期是个复杂的玩意儿，除非我亲手进行尝试，我也不可能知道某个特定项目特定问题的解决方案。其实对于这种问题，最好的方法之一，便是从最简化的模型开始尝试。例如，您可以准备一个空白页面，添加一些控件和代码，执行，成功。然后，您将这个简单的页面向您的项目进行靠拢，一次增加一小部分，然后执行看看是否成功。直到某段代码添加之后发现失败了，您就知道到底是什么原因引起的。可能是新的代码有问题，也可能是新代码让之前代码的问题暴露出来了。&lt;/p&gt; &lt;p&gt;对于排错来说，最关键的是&lt;font color="#ff0000"&gt;思考和分析，而不是动手&lt;/font&gt;。我有时候见到一些同事在遇到错误之后就开始盲目地修改代码，重试，最后就算把问题碰对了，时间也浪费了——而且还可能把原有正确的地方改坏了。要进行思考和分析，就要&lt;font color="#ff0000"&gt;细心观察&lt;/font&gt;，例如您有没有看清异常的信息是什么？有没有顺着InnerException一级一级往下看，看看最终是哪行代码出的问题？如今的框架，一般都会把错误信息写的非常完整。记得之前做WCF的时候，它甚至会告诉你可以尝试着修改配置中的哪个节点！如果您直接忽视这些，就丧失了第一手信息了。&lt;/p&gt; &lt;p&gt;还有，别怕英文，就个错误信息而已，没几个词的。&lt;/p&gt; &lt;p&gt;但是我可以这么说，许多朋友都缺少思考。因为从他们给我的邮件上来看，根本没有把问题描述清楚。我相信“&lt;font color="#ff0000"&gt;如果说不清楚，那说明没想清楚&lt;/font&gt;”。事实上，如果能把问题描述清楚了，一般也可以找出用什么关键字去搜索引擎上查找信息。我很奇怪，许多朋友还不会用搜索引擎，例如他们会对搜索引擎说很长一句话，而不是提取出中间的“关键字”进行查询。更严重的问题是“造词”。例如“注入”，这个词很流行啊，脚本注入，SQL注入。于是很多人在提问的时候也一直“注入”，但事实上他的问题和任何一种“现存的注入”的含义都不同。当然，您觉得这是“注入”也没有关系，但是至少描述一下在您的场景下“注入”是什么意思，对不对？而且，如果你用“注入”去搜索引擎上查询，就会发现基本上找不到你想要的东西，因为“注入”这个词在互联网上有别的含义，它和你的含义完全不同，又能给你什么信息呢？&lt;/p&gt; &lt;p&gt;此外，查到内容之后，也要进行基本的信息筛选。例如，一些小站，垃圾站的信息就不要关心了吧。直接找一些著名的大站，如官方社区，文档，博客就行了。&lt;/p&gt; &lt;p&gt;最后一点是为我个人而说的。如果您希望让我分析代码，还请把所有可运行的东西打一个包给我，并告诉一个略为详细的步骤，让我可以直接双击打开编译执行并重现问题。如果您只给我一个代码片断，还无法编译通过，或者还需要我自己去补充各类库，那我就只能说声抱歉了。同样，如果涉及到数据库，那么请给一个用于创建脚本和测试数据的SQL文件。此外，如果项目太大，最好也新建一个项目，只放一些核心的东西即可，关键在于重现问题。而且就我个人经验来说，经过“提炼”之后，说不定您自己就已经发现问题所在了。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/about-debugging.html#comments</comments>
      <pubDate>Wed, 14 Oct 2009 06:27:00 GMT</pubDate>
      <lastBuildDate>Wed, 14 Oct 2009 06:27:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>我对NHibernate的感受（3）：有些尴尬的集合支持</title>
      <link>http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-3-collection-support.html</link>
      <guid>http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-3-collection-support.html</guid>
      <description>&lt;p&gt;长假休息了好多，那么继续谈谈我对NHibernate的感受。&lt;/p&gt; &lt;p&gt;既然是一个ORM框架，那么自然是将O这一端映射R上。至于集合，是O这方面最常见，也是R这一边非常容易表示的关系。例如，一个问题（Question）可以包含多个回答（Answer），于是我的代码里就有这样的结构：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Question
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public virtual int &lt;/span&gt;QuestionID { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }

    &lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;Name { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }

    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt; m_answers;
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt; Answers
    {
        &lt;span style="color: blue"&gt;get
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;this&lt;/span&gt;.m_answers == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
                &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_answers = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HashedSet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt;();

            &lt;span style="color: blue"&gt;return this&lt;/span&gt;.m_answers;
        }
        &lt;span style="color: blue"&gt;private set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_answers = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        }
    }
}

&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Answer
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public virtual int &lt;/span&gt;AnswerID { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }

    &lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;Name { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }

    &lt;span style="color: blue"&gt;public virtual &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Question &lt;/span&gt;Question { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;
&lt;p&gt;于是这里就有个问题：为什么Answers属性需要同时读写？有的朋友可能会说，NHibernate支持对私有变量的直接读写，这样就可以对外暴露出只读的属性了。这个说法的确没错（而且我已经在这里使用private set了），不过这并不是我这里不满意的地方。更准确的说，我的质疑是“&lt;font color="#ff0000"&gt;为什么NHibernate会需要设置整个集合容器&lt;/font&gt;”？试想一下，在平时的开发中，我们的操作都是向一个集合中添加/删除对象，而不会傻傻地修改对象的集合属性。因为这个集合是对象自己维护的，而不是交给外界去“一锅端”地设置。&lt;/p&gt;
&lt;p&gt;可以设置的容器属性并不仅仅是“感官”上的问题。假如，我使用了上面代码，那么我在向数据库插入数据时可能就是这样做的：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;question = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Question&lt;/span&gt;();
question.Answers.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Answer &lt;/span&gt;{ Name = &lt;span style="color: #a31515"&gt;"Answer 1"&lt;/span&gt;, &lt;span style="color: red"&gt;Question = question &lt;/span&gt;});
question.Answers.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Answer &lt;/span&gt;{ Name = &lt;span style="color: #a31515"&gt;"Answer 2"&lt;/span&gt;, &lt;span style="color: red"&gt;Question = question &lt;/span&gt;});

&lt;span style="color: green"&gt;// put it into session&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;看看这两句红色的代码是不是有些多余？不仅仅是多余，这儿的问题在于，如果可以这样自由设置Question属性的话，那么我们是不是也有可能“一不小心”造成Answer与所在Question不匹配的问题呢？仅仅是创建还好，如果在一个场景下需要同时操作两个Question或Answer，它们的关系可能就复杂了。NHibernate就是这样，它需要我们手动地维护Question和Answer的双向引用，否则插入/删除/更新都可能不正确。&lt;/p&gt;
&lt;p&gt;有些人的解决方法是添加额外的方法，例如AddAnswer：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Question
&lt;/span&gt;{
    ...

    &lt;span style="color: blue"&gt;public void &lt;/span&gt;AddAnswer(&lt;span style="color: #2b91af"&gt;Answer &lt;/span&gt;answer)
    {
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(answer.Question != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
        {
            answer.Question.Answers.Remove(answer);
        }

        answer.Question = &lt;span style="color: blue"&gt;this&lt;/span&gt;;
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.Answers.Add(answer);
    }
}&lt;/pre&gt;
&lt;p&gt;使用AddAnswer方法便可以自动地剥离Answer与原有Question的关系，并且与新的Question建立联系了。同理，从一个Question对象中删除一个Answer对象，或者修改Answer对象的Question属性，应该都会引起双方关系的变化。但是，即便我们提供了完整的关系维护手段，Question.Answers还是对外暴露，开发人员还是可以修改Answers集合。&lt;/p&gt;
&lt;p&gt;因此，最好的办法其实应该是在集合中提供一种维护关系的方式。例如LINQ to SQL在这一点上便做的不错：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public partial class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Question&lt;/span&gt;&lt;span style="color: #2b91af"&gt;
&lt;/span&gt;{    
    &lt;span style="color: blue"&gt;private static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangingEventArgs &lt;/span&gt;emptyChangingEventArgs = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangingEventArgs&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Empty);
    
    &lt;span style="color: blue"&gt;private int &lt;/span&gt;_QuestionID;
    
    &lt;span style="color: blue"&gt;private string &lt;/span&gt;_Name;
    
    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EntitySet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt; _Answers;
&lt;span style="color: blue"&gt;    
    public &lt;/span&gt;Question()
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;._Answers = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EntitySet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt;(
            &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;this&lt;/span&gt;.attach_Answers),
            &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;this&lt;/span&gt;.detach_Answers));
    }
    
    &lt;span style="color: blue"&gt;public int &lt;/span&gt;QuestionID { ... }
    
    &lt;span style="color: blue"&gt;public string &lt;/span&gt;Name { ... }
    
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EntitySet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt; Answers
    {
        &lt;span style="color: blue"&gt;get
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;return this&lt;/span&gt;._Answers;
        }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;this&lt;/span&gt;._Answers.Assign(&lt;span style="color: blue"&gt;value&lt;/span&gt;);
        }
    }
    
    &lt;span style="color: blue"&gt;private void &lt;/span&gt;attach_Answers(&lt;span style="color: #2b91af"&gt;Answer &lt;/span&gt;entity)
    {
        entity.Question = &lt;span style="color: blue"&gt;this&lt;/span&gt;;
    }
    
    &lt;span style="color: blue"&gt;private void &lt;/span&gt;detach_Answers(&lt;span style="color: #2b91af"&gt;Answer &lt;/span&gt;entity)
    {
        entity.Question = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
    }
}&lt;/pre&gt;
&lt;p&gt;看看LINQ to SQL对我们多体贴，自动生成的代码会帮我们维护Question与Answer之间的双向关系。当然，还有一部分逻辑是在Answer类的Question属性中，如果您感兴趣可以自己去观察一下。不过，LINQ to SQL的问题在于它使用了特殊的类型EntitySet，它会使用两个回调函数对外公布集合内元素的添加/删除情况。按理来说，如果我们想要在NHibernate中采用这种“自动维护”的方式，可以使用自定义的集合类型，例如：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt; m_answers;
&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt; Answers
{
    &lt;span style="color: blue"&gt;get
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;this&lt;/span&gt;.m_answers == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_answers = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CallbackSet&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Answer&lt;/span&gt;&amp;gt;(...);

        &lt;span style="color: blue"&gt;return this&lt;/span&gt;.m_answers;
    }
    &lt;span style="color: blue"&gt;private set
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_answers = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
    }
}&lt;/pre&gt;
&lt;p&gt;只可惜，在新建对象的时候我们自然利用到CallbackSet&amp;lt;Answer&amp;gt;，其中包含了我们定义的逻辑。但是如果是这样的代码呢？&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;question = session.Get&amp;lt;&lt;span style="color: #2b91af"&gt;Question&lt;/span&gt;&amp;gt;(1);
question.Answers.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Answer &lt;/span&gt;{ Name = &lt;span style="color: #a31515"&gt;"Answer 1"&lt;/span&gt;, Question = question });
question.Answers.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Answer &lt;/span&gt;{ Name = &lt;span style="color: #a31515"&gt;"Answer 2"&lt;/span&gt;, Question = question });
session.Flush();&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;在从数据库中获取Question对象的时候，NHibernate便会“自作主张”地将Answers属性“整个”设为自己的ISet&amp;lt;Answer&amp;gt;对象——因为实现延迟加载，它也并不一定是HashedSet&amp;lt;Answer&amp;gt;。换句话说，&lt;a href="http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-1-lazy-loading.html"&gt;NHibernate虽然能够保持属性的逻辑&lt;/a&gt;，但&lt;font color="#ff0000"&gt;它不能保持自定义集合的逻辑&lt;/font&gt;。在我看来，NHibernate完全可以做到放弃集合属性的set操作，把所有的对象都通过集合的Add方法添加进去。其实这样做同样可以实现集合的延迟加载，就好比&lt;a href="http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-2-virtually-everything.html"&gt;放弃对所有方法的强制virtual要求，也能实现对象的延迟加载&lt;/a&gt;一样。&lt;/p&gt;
&lt;p&gt;为了避免像上次那样误解NHibernate，我刚才又作了一次测试——这次我应该没有搞错。当然，如果NHibernate支持对自定义集合类型那就再好不过了，我们就有办法解决这个问题。但是我不知道该怎么做，如果您知道的话，请告诉我。在我看来，目前的问题是NHibernate对于POCO支持有缺陷造成的。如果是这样的话，那我们的Model就不得不继续迁就NHibernate了。&lt;/p&gt;
&lt;p&gt;关于NHibernate集合还有一个有趣的问题是——请关注上面这4行代码（Get-Add-Flush这段），这是一个非常标准也是非常常见的添加Answer对象的方式。只可惜，在调用ISet&amp;lt;Answer&amp;gt;的Add方法添加Answer对象的时候，会引发一次数据库查询操作，加载当前Question下的所有Answer——但是在我看来这根本没有必要啊。我只是“添加”，并没有要查询。其实NHibernate帮我把新的Answer对象保存起来就可以了，为什么要增加无畏的开销呢？当然我承认，这个做法会产生一些麻烦，例如需要将集合的操作分为“读”和“写”两类，当“写”操作发生时不会加载数据，而只有在第一次“读”的时候才去数据库查询。&lt;a href="http://en.wikipedia.org/wiki/Command-query_separation"&gt;“读”和“写”分离&lt;/a&gt;，本来就应该这样。&lt;/p&gt;
&lt;p&gt;那么谁又做到这一点了呢？又是LINQ to SQL。其实LINQ to SQL在细节上有非常多的考虑，使用起来也是非常容易的——如果我不是被它“宠坏”的话，可能也就不会在意NHiberante的这个问题了。&lt;/p&gt;
&lt;p&gt;只可惜，对于ORM的生命“映射方式”上，LINQ to SQL的支持过于有限，这也大大限制了项目对它的接受程度。&lt;/p&gt;&lt;h1&gt;相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-1-lazy-loading.html"&gt;我对NHibernate的感受（1）：对延迟加载方式的误解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-2-virtually-everything.html"&gt;我对NHibernate的感受（2）：何必到处都virtual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;我对NHibernate的感受（3）：有些尴尬的集合支持&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-4-interceptor.html"&gt;我对NHibernate的感受（4）：令人欣喜的Interceptor机制&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;注：经各位高手指点，已成功总结出NHibernate中&lt;a href="http://blog.zhaojie.me/2009/10/nhibernate-custom-collection-1-basics.html"&gt;使用自定义集合的方式&lt;/a&gt;。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-3-collection-support.html#comments</comments>
      <pubDate>Thu, 08 Oct 2009 13:59:00 GMT</pubDate>
      <lastBuildDate>Thu, 08 Oct 2009 13:59:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/reading/">阅读相关</category>
      <title>谈谈我对《ThoughtWorks文集》中多语言开发部分的看法</title>
      <link>http://blog.zhaojie.me/2009/09/talk-about-muti-language-programming-in-thoughtworks-anthology.html</link>
      <guid>http://blog.zhaojie.me/2009/09/talk-about-muti-language-programming-in-thoughtworks-anthology.html</guid>
      <description>&lt;p&gt;一早看&lt;a href="http://www.cnblogs.com/guaiguai/"&gt;怪怪&lt;/a&gt;同学评论《&lt;a href="http://www.china-pub.com/196006"&gt;ThoughtWorks文集&lt;/a&gt;》公开的&lt;a href="http://www.china-pub.com/ureader/product.asp?bookid=196006"&gt;样章&lt;/a&gt;，一谈&lt;a href="http://images.china-pub.com/ebook195001-200000/196006/ch05.pdf"&gt;多语言开发（第5章）&lt;/a&gt;，二谈&lt;a href="http://images.china-pub.com/ebook195001-200000/196006/ch13.pdf"&gt;测试（第13章）&lt;/a&gt;。怪怪同学的&lt;a href="http://www.cnblogs.com/guaiguai/archive/2009/09/26/1574322.html"&gt;看法&lt;/a&gt;是贬前者而捧后者，并提出“同样一个包装下、同一个公司不同的作者，差异如此之大，那么在我们的学习过程中，就要注意去芜存菁了”。说实话，我没有理解他对第5章的评价，如在“抽象方式”方面的说法我没有太深的理解。如果怪怪看到我这篇文章能够再详细说说抽象方法的看法就再好不过了——目前我只能说我同意他的论点（讨论软件思想学习这方面），但是没有理解他的论据，呵呵。&lt;/p&gt; &lt;p&gt;我对第5章有自己的看法，讲的是多语言开发。我是非常提倡多语言开发的，原因可能一是因为我是语言爱好者，二是因为.NET平台是多语言共存的一个良好环境，我以前也经常提出过用IronPython作动态逻辑的“宿主”，用F#作并行开发等等。因此，我是拥护“混合开发”的一个人。但是，很巧，对于这第5章，我还是同意它的论点（或描述），而不同意它的论据（即示例）。&lt;/p&gt; &lt;p&gt;例如，书中举的第一个例子是使用Groovy的方式读取文打印文件每一行，并在每行之前加上行号：&lt;/p&gt;&lt;pre class="code"&gt;def number = 0
new File(args[0]).eachLine { line -&amp;gt;
    number++
    println "$number: $line"
}&lt;/pre&gt;
&lt;p&gt;与书中举出的二十多行Java代码（样章的代码是图片，我不想敲一遍了）相比，Groovy的确是简单了很多。但是在我看来，这个例子是很不妥当的。如果您看一下书中的Java代码就会发现，复杂的Java版本是在于使用了类似C#中StreamReader的做法，以及一个古怪而复杂的LineNumberReader，需要打开文件，再一行一行地读，并且加上异常处理。为什么不使用一个number变量，而且Groovy代码的异常处理在哪里呢？也就是说，Groovy版本并没有完成Java版本所处理的所有问题。&lt;/p&gt;
&lt;p&gt;当然，有人可能会说，我们目标是完成工作，本就不需要关心异常，而Java中的异常处理代码是因为语言特性，迫使我们必须这么做。但问题就在于，这其实涉及的是“类库”方面的内容。例如，您看这段C#代码：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;number = 0;
&lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;string &lt;/span&gt;line &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.ReadAllLines(&lt;span style="color: #a31515"&gt;&amp;#64;"C:\test.txt"&lt;/span&gt;))
{
    number++;
    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(number + &lt;span style="color: #a31515"&gt;" " &lt;/span&gt;+ line);
}&lt;/pre&gt;
&lt;p&gt;这和那段Groovy代码有本质区别吗？但是，在这里代码里有没有使用Java所无法实现特性呢？没有。也就是说，Java代码麻烦是麻烦在“缺少类库”，而不是“语言特性”。因此在我看来，用这个例子证明Java是种生产力低下的语言是不恰当的——远不如我之前&lt;a href="http://blog.zhaojie.me/2009/08/from-delegate-to-others-2.html"&gt;谈委托时的示例&lt;/a&gt;有说服力。&lt;/p&gt;
&lt;p&gt;样章中还举了其他一些例子，如判断是个字符串是否为空所使用的isBlank方法，Java需要写在一个额外的StringUtils类中，而Ruby直接打开String类型并添加新方法就可以了：&lt;/p&gt;&lt;pre class="code"&gt;class String
  def blank?
    empty? || strip.empty?
  end
end&lt;/pre&gt;
&lt;p&gt;这个示例与Jaskell（JVM上的Haskell语言）中SafeArray的示例相对就有说服力多了——但是它后面又举了一例：Haskell的函数惰性求职特性可以轻易生成无限长的列表：&lt;/p&gt;&lt;pre class="code"&gt;makeList = 1 : makeList&lt;/pre&gt;
&lt;p&gt;这点在Java语言中就不可以了吗（您可以用C#语言想一下可以怎么编写一个辅助方法来实现这个功能——但不要使用yield）？我在读这些文字的时候会有一种感觉，作者是一个动态语言的爱好者，但是在举这些示例的时候并没有想过这些示例的说服力如何，是否真的可以体现出与Java的差距，这差距究竟是语言上的还是类库上的。&lt;/p&gt;
&lt;p&gt;而在下一个使用Ruby进行单元测试的示例中，我脑子里差点就冒出“骗子”两个字。为什么这么说呢？首先，您可以去看看样章里Java和Ruby两个语言的测试代码。如果您熟悉单元测试，如果你可以区分&lt;a href="http://www.google.com/search?hl=en&amp;amp;source=hp&amp;amp;q=Mock+Stub&amp;amp;aq=f&amp;amp;oq=&amp;amp;aqi=g10"&gt;Mock和Stub两个概念的区别&lt;/a&gt;，您应该也可以看出其中的问题来。&lt;/p&gt;
&lt;p&gt;简单的说，Java代码的单元测试使用的是Mock，使用了非常接近于Record/Playback的方式，而Ruby代码使用的是Stub，是单元测试的AAA（Arrange，Act，Assert）模式。Record/Playback是早些年较为流行的测试方式，它首先通过Mock对象“录制”待测试对象的行为，然后交给待测试对象进行测试，最后验证它和“录制”的结果是否相同。这种做法本身就较为复杂，因此目前在很多情况下已经被AAA给替代了。从名字上便可看出，AAA的做法是先安排，再行动，最后验证。它关心的只是被模拟对象“在某些调用时的反应”，而并不在意被模拟对象的整体行为。打个比方，在样章中举的Java示例，其中有这样的代码：&lt;/p&gt;&lt;pre class="code"&gt;warehouseMock.expects(once()).method("remove")
    .with(eq(TALISKER, eq(50))
    &lt;font color="#ff0000"&gt;.after("hasInverntory")&lt;/font&gt;;&lt;/pre&gt;
&lt;p&gt;看到这个after语句了吗？这个after表明remove方法的执行需要在hasInverntory方法调用之后执行。这就是Record/Playback的特征之一：“录制”的行为是可以要求严格按照顺序的。而AAA模式只关心待模拟的对象在某些调用时的反应状况（所以叫做Stub），因此它在“顺序严格”的情况下反而会麻烦一些。例如，如果您要确保一个ITransaction对象的Commit方法必须在Begin之后调用，使用AAA的方式，可能就要自己准备一个order变量，在Begin和Commit方法中引发回调，并检查order的当前数值了。&lt;/p&gt;
&lt;p&gt;在来看看Ruby的代码，它使用的便是Stub，并且——它并没有去确认remove方法和hasInverntory方法的调用顺序。如果要确认的话，使用的代码便会复杂一些了。也就是说，Ruby版本使用的本身就是简单的AAA模式，且功能实现的并不如Java版本的完整。以此说明Ruby用于测试更加方便，是不是有点“忽悠”的嫌疑呢？&lt;/p&gt;
&lt;p&gt;顺便一提，大名鼎鼎的Oren Eini&lt;a href="http://ayende.com/Blog/archive/2009/09/03/planning-for-rhino-mocks-4.0.aspx"&gt;正打算Rhion Mocks 4.0的开发&lt;/a&gt;，计划之一便是移除Record/Playback模式的支持，仅保留AAA方式。而后起之秀Moq框架从一开始就只支持AAA方式。&lt;/p&gt;
&lt;p&gt;上周我读了样章的作者Neal Ford的另一本书《卓有成效的程序员》（一本200多页的小册子），其中“元编程”一章中他也提到了使用Groovy进行单元测试比Java方便很多，在我看来这同样也是类库的问题。因为Groovy可以使用普通方法调用的方式去访问一个对象的private成员，而Java中使用反射会麻烦很多（和C#差不多，因此您可以想象一下）。但是，这完全也可以通过补充一些辅助方法来完成工作。此外，Java代码中最麻烦的还是checked exception特性，Neal使用的Java代码中大部分还是在try...catch。&lt;/p&gt;
&lt;p&gt;《卓》是好书，但是Neal在两本书中对多语言编程的论述的确不能让我感到满意。可能混合编程是个大话题，不是一句两句话能说清的吧。&lt;/p&gt;
&lt;p&gt;最后，样章提出ThoughtWorks的第一个商业产品Mingle使用了JRuby进行开发，但我认为这不是混合编程的优秀示例。因为——它还是只用了Ruby，即使是运行在JVM上，Ruby语言还是Ruby语言。因此Mingle的成功可以证明JVM上运行Ruby的可靠性，可以证明Ruby的生产力比Java高，但我认为它不能作为混合编程的典型案例。&lt;/p&gt;
&lt;p&gt;我想讲的东西讲完了，其实挺矛盾的。一则是我在为自己一直鄙视的Java说好话，二是我“反对”了别人对混合编程的论证，而混合编程也是我一直提倡的东西。不过，毕竟要达成目的也必须通过正确的方式。对就是对，错就是错，虽然我坚持技术人员的信仰，但我也认为个人情感不应该左右判断。如果我看到鄙视Java的说法就叫好，那和某些人无端对微软技术搞FUD又有什么区别。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/09/talk-about-muti-language-programming-in-thoughtworks-anthology.html#comments</comments>
      <pubDate>Sat, 26 Sep 2009 09:44:00 GMT</pubDate>
      <lastBuildDate>Sat, 26 Sep 2009 09:44:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>我对NHibernate的感受（2）：何必到处都virtual</title>
      <link>http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-2-virtually-everything.html</link>
      <guid>http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-2-virtually-everything.html</guid>
      <description>&lt;p&gt;&lt;a href="http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-1-lazy-loading.html"&gt;上一篇文章&lt;/a&gt;主要是在夸NHibernate实现的好，而这篇就完全是来抱怨的了。NHiberante有个毛病，就是如果是和数据库产生映射的类，就要求所有的public成员和protected成员必须是virtual的。请注意这里的要求有两个细节：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;即使是方法，也必须标记为virtual  &lt;li&gt;即时是不和数据库有映射关系的属性，也必须标记为virtual&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;这就让我觉得无厘头了，为什么没有任何关系的东西也要受到限制？我知道NHiberante要求将属性标记为virtual是为了延迟加载，因为只有这样它才能生成如上一篇文章中那样的延迟代理类，这样就可以实现只在第一次访问属性的时候才进行“加载”操作，从而访问数据库并获得数据，再填充字段。不过我认为这也不是合适的理由，因为这又关没有映射的属性，甚至方法什么事情呢？我在很长一段时间内一直没有想明白这个问题。&lt;/p&gt; &lt;p&gt;直到看了NHibernate开发团队成员&lt;a href="http://davybrion.com/blog/"&gt;Davy Brion&lt;/a&gt;的文章《&lt;a href="http://davybrion.com/blog/2009/03/must-everything-be-virtual-with-nhibernate/"&gt;Must Everything be Virtual with NHiberante？&lt;/a&gt;》之后，我才了解了他们的设计思路——虽然我还是不认同。&lt;a href="http://blog.zhaojie.me/2009/08/virtually-necessary-members.html"&gt;我真的不喜欢到处virtual&lt;/a&gt;。&lt;/p&gt; &lt;p&gt;要求类中所有的公开成员（public/protected）都是virtual，是因为NHibernate想要保证在“访问任何公开成员”之前，数据已经被加载了。也就是说，无论您是想调用它的ToString方法，还是您自己写的辅助方法/属性，在真正进入您自定义的逻辑之前，数据肯定已经存在了——例如，存在于私有的域字段中：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Article
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private string &lt;/span&gt;m_tagNames
    &lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;TagNames
    {
        &lt;span style="color: blue"&gt;get
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;return this&lt;/span&gt;.m_tagName;
        }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_tagNames = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        }
    }

    &lt;span style="color: blue"&gt;public void &lt;/span&gt;DoSomethingWithTagNames()
    { 
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(this.m_tagNames);
    }
}
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;虽然NHibernate可以在TagNames属性第一次访问时加载数据，但是如果我们的DoSomethingWithTagNames方法直接访问m_tagNames字段，数据自然无法加载了。因此，NHibernate必须确保有能力在代理类中覆盖DoSomethingWithTagNames方法才行。这就是virtual方法的由来。&lt;/p&gt;
&lt;p&gt;但是在我看来，我们真的有多少情况会去访问私有字段呢？事实上对于大部分情况，我们会使用C#中“自动属性”特性来定义属性，这样自然只有属性，没有字段。即使我们使用了自定义的私有字段来保存属性的值，NHibernate也可以“叮嘱”我们应该访问属性，而不要直接访问私有字段——其实在编程上两者并没有差别。现在这样被强迫的感觉不好。&lt;/p&gt;
&lt;p&gt;不过昨天我忽然想到，这似乎也是可以理解NHibernate这么做的原因：因为Hibernate要照顾到Java语言开发人员的使用感受——请注意是Hibernate，没有N。不管怎么说，NHibernate是从Hibernate移植过来的。NHiberante的主力开发人员Oren Eini曾在博客中写道（可惜一时没找到），NHiberante刻意与Hibernate的实现保持同步，这样容易进行双向的同步，例如Hibernate解决了一些bug或性能问题，也可以较为轻易地在NHibernate上修补。&lt;/p&gt;
&lt;p&gt;不过这还是没有解释为什么Hibernate要一切都是virutal的原因啊。其实您只要看一下这段Java代码就应该明白了：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Product
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;m_tagNames;

    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;getTagNames()
    {
        &lt;span style="color: blue"&gt;return this&lt;/span&gt;.m_tagNames;
    }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;setTagNames(&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;value)
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_tagNames = value;
    }
}
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;这是上面C#中Product的等价Java代码。由于Java里没有“属性”概念，因此Java语言自身一直有一个“约定”：getXxx和setXxx两个方法即为一个属性。这个约定用在很多地方，如IDE就会把它当作是一个属性方便设置及导航，框架在进行序列化时候也知道哪些东西是“属性”。这“约定”本没有问题，但是这就给Java开发人员造成了一定困扰：使用起来实在是太麻烦了。例如，Product有个属性叫做ViewCount，我们想要把它加1，在C#中我们可以写：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;.ViewCount++;&lt;/pre&gt;
&lt;p&gt;而在Java中则必须是：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;.setViewCount(&lt;span style="color: blue"&gt;this&lt;/span&gt;.getViewCount() + 1);&lt;/pre&gt;
&lt;p&gt;因此，如果是你的话，在写Java代码的时候，是愿意使用getXxx()这样的方法，还是直接访问类中的私有字段？因此我认为，是Java语言的特性，导致Java开发人员倾向于直接访问类中的私有字段，从而导致Hibernate需要避免未加载的私有字段，进一步导致Hibernate的代理类会去覆盖所有的公开方法（只有方法，因为Java语言没有“属性”）——最终，由于NHibernate在“统一大业”上的策略，使得我们.NET开发人员也必须把所有成员标记为virtual，无论是方法还是属性。&lt;/p&gt;
&lt;p&gt;您可能会说，但也没见Java程序员嚷嚷啊。没错，因为在Java语言中，默认情况下所有的成员都是virtual的。而在.NET平台下情况正好相反。因此在我看来，我们这里必须到处标记virtual所造成的不便，和Java语言本身有着非常大联系——我们需承受Java语言所带来的痛苦。&lt;/p&gt;
&lt;p&gt;虽然我理解NHibernate，但这又怎能让我满意呢？&lt;/p&gt;
&lt;p&gt;哦，对了。在未来的Java 7中，我们可歌可泣的Java语言终于有了a –&amp;gt; property这样的属性访问语法了。&lt;/p&gt;
&lt;p&gt;可惜，迟了。&lt;/p&gt;
&lt;h1&gt;相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-1-lazy-loading.html"&gt;我对NHibernate的感受（1）：对延迟加载方式的误解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;我对NHibernate的感受（2）：何必到处都virtual&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-3-collection-support.html"&gt;我对NHibernate的感受（3）：有些尴尬的集合支持&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-4-interceptor.html"&gt;我对NHibernate的感受（4）：令人欣喜的Interceptor机制&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-2-virtually-everything.html#comments</comments>
      <pubDate>Thu, 24 Sep 2009 07:09:00 GMT</pubDate>
      <lastBuildDate>Thu, 24 Sep 2009 07:09:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>我对NHibernate的感受（1）：对延迟加载方式的误解</title>
      <link>http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-1-lazy-loading.html</link>
      <guid>http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-1-lazy-loading.html</guid>
      <description>&lt;p&gt;&lt;a href="http://nhforge.org"&gt;NHibernate&lt;/a&gt;是.NET平台上最著名的ORM框架，虽说出身于Java平台上的Hibernate，但是从外部看来这几乎就是一个.NET平台上的原生产品：有自己的社区，有自己的用户，有自己的商业支持，有利用C#特性的独立扩展。它不像Lucene.NET那样，一眼就能看出浓重的Java气息，Java的命名方式等等。我用NHibernate时间不长，而NHibernate的复杂程度也决定了我无法像了解LINQ to SQL那样容易。不过在使用了一段时间过后，还是对它有一定体会。有欣喜，有误解，也有抱怨。&lt;/p&gt; &lt;p&gt;这几篇文章里我不打算多谈NHiberante的优点，因为它的优势实在过于明显。如果不考虑&lt;a href="http://www.telerik.com/products/orm.aspx"&gt;Telerik ORM&lt;/a&gt;这样的商业框架（因为我没用过，完全不了解），.NET平台上开源和免费的ORM工具几乎没有NHibernate的对手：LINQ to SQL使用的确容易，上手非常快，某些功能也非常细致（稍后会谈到），但对于ORM工具的灵魂“Mapping能力”实在是不敢恭维。前一段时间我也简单了解了一下微软新出的Entity Framework，虽然也秉承了微软一贯的易用性（如强大的LINQ支持），在Mapping能力上也有切实的提高，但是在功能和一些细节控制上还远不如NHibernate。毕竟NHibernate是经历了多年发展，对于各种情况几乎都有应对措施。如延迟与否，是使用select还是join获取数据，是否在集合加载时附加条件。此外，NHibernate的Interceptor能力所带来的扩展性也是让我比较满意的，不过这点有机会再详细谈一下。&lt;/p&gt; &lt;p&gt;总之，目前NHibernate是我最满意的ORM框架。&lt;/p&gt; &lt;p&gt;那么现在进入正文内容。首先我想谈一下自己对NHibernate实现方式上的一个误解，这个误解让我对NHibernate一直有着错误的抱怨，我还在几篇文章里不断重复对NHibernate的错误指责，目前已经纠正，希望不会造成太大问题。&lt;/p&gt; &lt;p&gt;这个误解，是我一直认为NHibernate使用了一种简单的延迟加载方式。例如有这样一个对象：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Article
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public virtual int &lt;/span&gt;ArticleID { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;TagNames { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;
&lt;p&gt;在延迟加载的时候，我一直以为NHibernate只是通过Emit生成一个Article的子类，然后把属性覆盖成简单读写，例如：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Article$LazyProxy &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Article
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private string &lt;/span&gt;m_tagNames;
    &lt;span style="color: blue"&gt;public override string &lt;/span&gt;TagNames
    {
        &lt;span style="color: blue"&gt;get
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;return this&lt;/span&gt;.m_tagNames;
        }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_tagNames = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        }
    }
}
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;这么做的问题自然是让TagNames属性原本的逻辑丢失了。如果对于失血的DTO模型，这自然没有关系，因为这些属性本身内部没有逻辑。但是，我习惯使用领域驱动设计（DDD）的方式来为产品建模，因此在这些属性中很可能拥有一些业务逻辑。例如改变对象的其他一些状态，同步至其他字段，或是触发事件等等。因此，丢失属性逻辑对我的影响是致命的，这意味着我必须“照顾”NHibernate的特性进行编程，而在进行建模时就开始考虑持久化逻辑是DDD实践中的一大问题——虽然软件开发不是理想化的，权衡是正常的，但如果NHiberante只能应付失血的DTO模型，那么它就对不起它的业界盛名了。&lt;/p&gt;
&lt;p&gt;可惜的是，NHibernate没有在这里翻船——所以可能更应该说“值得庆幸”——它使用了一种维持原有业务逻辑的延迟代理写法：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ArticleLazyProxy &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Article
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public override string &lt;/span&gt;TagNames
    {
        &lt;span style="color: blue"&gt;get
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;var &lt;/span&gt;tagNames = ... &lt;span style="color: green"&gt;// 加载数据
            &lt;/span&gt;&lt;span style="color: blue"&gt;base&lt;/span&gt;.TagNames = tagNames;
            &lt;span style="color: blue"&gt;return base&lt;/span&gt;.TagNames;
        }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;base&lt;/span&gt;.TagNames = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        }
    }
}
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;当然，这是我从“测试效果”中反推出来的情况，NHiberante的实际做法应该不会那么简单。如果您关注我的文章，会发现这就是我之前提出的&lt;a href="http://blog.zhaojie.me/2009/09/standard-lazy-proxy.html"&gt;最为理想的延迟代理实现方式&lt;/a&gt;，也是我在&lt;a href="http://Eazy.codeplex.com"&gt;Eazy&lt;/a&gt;类库中&lt;a href="http://blog.zhaojie.me/2009/09/how-to-use-fragment-cache-lazy-load-and-library-eazy.html"&gt;使用的做法&lt;/a&gt;。我在实现了Eazy的基本功能之后，还因为它满足了我的要求而微微沾沾自喜了一把，谁知这一切早已被NHibernate拿下。我昨天晚上试验出这个结果之后也震惊了一把，不是因为NHibernate的强大（因为它本不该犯此低级错误），而是因为我不理解自己之前为什么会轻易地臆断NHibernate的做法？想象我还在多篇文章中抱怨过这点，昨天试验过后，我立即把自己能想到的无稽之谈都修改了。惭愧啊。&lt;/p&gt;
&lt;p&gt;哎，&lt;a href="http://aimingoo.spaces.live.com/blog/cns!F9303C43D5CEAFB3!906.entry"&gt;莫装B，装B被雷劈&lt;/a&gt;。&lt;/p&gt;
&lt;h1&gt;相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;我对NHibernate的感受（1）：对延迟加载方式的误解&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-2-virtually-everything.html"&gt;我对NHibernate的感受（2）：何必到处都virtual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-3-collection-support.html"&gt;我对NHibernate的感受（3）：有些尴尬的集合支持&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/10/my-view-of-nhibernate-4-interceptor.html"&gt;我对NHibernate的感受（4）：令人欣喜的Interceptor机制&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-1-lazy-loading.html#comments</comments>
      <pubDate>Thu, 24 Sep 2009 06:04:00 GMT</pubDate>
      <lastBuildDate>Thu, 24 Sep 2009 06:04:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>一些技术图书编写、推荐、出版人员需要自重</title>
      <link>http://blog.zhaojie.me/2009/09/1572868.html</link>
      <guid>http://blog.zhaojie.me/2009/09/1572868.html</guid>
      <description>&lt;a href="http://img.zhaojie.me/blog/170283/o_js_1.gif" target="_blank" class="floatRight"&gt;&lt;img src="http://img.zhaojie.me/blog/170283/o_js_1.gif" width="150"&gt;&lt;/a&gt;  &lt;p&gt;最近在互联网上出现了一个让我比较气愤的技术图书相关的事件，事情由《JavaScript征途》一书&lt;a href="http://bbs.51js.com/viewthread.php?tid=85328&amp;amp;extra=&amp;amp;page=1"&gt;在51JS上的贴子&lt;/a&gt;引起，有人提出这本书的样张里出现了太多错误，但是慢慢的由于作者（即css8）的“死撑”，“事态慢慢升级”，一发不可收拾。&lt;/p&gt; &lt;p&gt;今早我看了hax写的&lt;a href="http://hax.javaeye.com/blog/474725"&gt;炮轰这本书的文章&lt;/a&gt;，文章里的话写的比较重，可能是由，但至少有理有据，考证严谨，引用充分，而且我完全同意hax对技术内容的评价。刚才我奈着性子看完了原贴，基本感觉一致，作者为了面子死撑，自比于丹，亦将这本书比作脑白金，看了不知该笑还是该哭。&lt;/p&gt; &lt;p&gt;国内技术图书市场其实从来不缺这样的图书，而且这本书从质量上看应该也不会最差的一本。这次可能也是由于作者在论坛上的态度引起的，可以说作者本人一手将此书捧为了典型。不过这本书的确是典型，因为“推荐”这本书的人大都是业界著名人物，有头有脸，对于初学者来说的确是一个个高大的形象。但正是这些专家级人物，却联手推荐这样一本书，更有&lt;a href="http://www.ubbcn.com/flog/post/000142.htm"&gt;看了目录就写书评&lt;/a&gt;的情况，可见国内技术图书出版行业吹捧之风有多么盛行了。&lt;/p&gt; &lt;p&gt;我一直想，是不是有人可以获得每本书到底有哪些人推荐的情况，然后整理出来一定非常有意思。技术人员的圈子其实并不大，因此各专家普遍会遇到“盛情难却”的情况，于是在“盛情难却”之下不得不出手。事实上，如果联名推荐的专家团中，如果对书中的内容进行技术审阅的话，相信就能避免很多低级错误——就像现在这本书那样。但技术审阅是需要时间的，各位专家的时间自然非常宝贵，但是写推荐的时候，难道就不该把书“浏览”一遍吗？&lt;/p&gt; &lt;p&gt;写推荐和书评往往有一种方式，例如对于写ASP.NET的书，推荐的时候可以大谈特谈ASP.NET技术——ScottGu为“国内第一本ASP.NET技术”写推荐时就这样，虽然我不知道ScottGu在写这段话的时候是否知道这篇文章的作用是什么。在国内的小圈子里，推荐者则可以再谈谈与作者本人的私交以及对方在平时的表现，则内容又一下子充实了许多。&lt;/p&gt; &lt;p&gt;有人说，群众的眼光是雪亮的。我不认同，至少在技术图书方面。我认为，初学者最不擅长的东西之一便是判断一本书的好坏，所以需要专家来“引导”，但是如果专家自己不自重的话，又如何对得起广大人民群众的支持？如果您关注一下就会发现，一些较有名气的朋友会给多本书写推荐序，但是在仔细观察一下，您还会发现，这本书并不是此人的专长。这也是初学者盲目的地方，一处牛，似乎就意味着处处牛。更混乱的是，在国内社区被当作牛人实在不难，可能只要找个话题，找本书来翻译一下，再学会装腔作势即可——真的，您也可以，很少有人会关注翻译质量的。而图书出版方看中的也就是个推荐者的名气，不过对他们来说这就够了。&lt;/p&gt; &lt;p&gt;国内图书市场已经很不健康了，虽然现在许多出版社、编辑和作者的努力都看得到，但是总有更多的书冒出来拖他们的后腿。对于普通人来说，有多少人会区分出版社，区分作者呢？因此，我真希望技术图书的编写、推荐和出版人员还是要自重，写不好书就不要写，出不了好书就不要吹，没看过书就不要推。图书产业虽然也早已商业化，但是这毕竟还代表了知识，有其特殊性，经济利益不该是你们唯一考量的东西。&lt;/p&gt; &lt;p&gt;最后，对于书籍的“消费者”来说，也要具有一定的识别能力。有时候，判断一本书好坏最方便的做法便是看看&lt;a href="http://www.china-pub.com/s/?key1=%d6%ec%d3%a1%ba%ea"&gt;作者在短期内究竟写了多少书&lt;/a&gt;。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/09/1572868.html#comments</comments>
      <pubDate>Wed, 23 Sep 2009 12:04:00 GMT</pubDate>
      <lastBuildDate>Wed, 23 Sep 2009 12:04:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/asp-net/">ASP.NET</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>从ASP.NET的PHP执行速度比较谈起</title>
      <link>http://blog.zhaojie.me/2009/09/aspnet-php-benchmark-and-more.html</link>
      <guid>http://blog.zhaojie.me/2009/09/aspnet-php-benchmark-and-more.html</guid>
      <description>&lt;p&gt;上星期我在InfoQ发表了&lt;a href="http://www.infoq.com/cn/news/2009/09/aspnet-php-benchmark"&gt;一篇新闻&lt;/a&gt;，对&lt;a href="http://misfitgeek.com/"&gt;Joe Stagner&lt;/a&gt;在博客上发表的三篇关于ASP.NET与PHP性能对比的文章进行了总结。写新闻其实挺不爽的，因为不能夹杂个人的看法，只能平铺直叙陈述事实。当然，如果像&lt;a href="http://news.cnblogs.com/n/49128/"&gt;某些新闻&lt;/a&gt;那样“换一种说法”是可以骗过一些“不明真相的群众”，但是这就有违道德了。因此，在客观陈述完新闻内容之后，我只能选择把自己的感想、评论等内容放在自己的博客上。&lt;/p&gt; &lt;p&gt;Joe Stagner的背景挺特殊，它是PHP的老用户，在ASP.NET出现之前就是PHP的重量级开发人员了。后来不知哪一天开始他加入了微软，我们就可以在一些如介绍ASP.NET AJAX的文章、视频中看到他。这次他又涉及了一个敏感话题：性能比较。要知道每次这种比较都会惹来一阵争论……我不想用“口水战”来形容，我认为它和“争论”的性质不同。Joe也承认，每次他说PHP好话就会被微软的同事指责，而说.NET好话就要被PHP阵营说是微软的托。&lt;/p&gt; &lt;p&gt;我深信优秀的技术人员都是有信仰的，都有技术倾向性。因此如Joe夹在中间的人的确比较尴尬。但是我认为，有信仰，和“客观”是不冲突的。信仰涉及到倾向性，而客观则意味着有倾向性之后的办事方式。&lt;/p&gt; &lt;p&gt;至于比较结果，您可以关注一下&lt;a href="http://www.infoq.com/cn/news/2009/09/aspnet-php-benchmark"&gt;新闻内容&lt;/a&gt;，总体来说，ASP.NET从纯粹的执行效率上来说是大幅领先于PHP的。这并不令人惊讶，一个是编译为机器码的执行方式，一个是解析执行（即时缓存了op-code也并不是机器码），性能自然天差地远。&lt;/p&gt; &lt;p&gt;Joe也知道会引发争论，因此他在文章后面写道：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;我知道某些人会被这个测试结果激怒，欢迎发表评论及反对意见，但是如果你无法保持礼貌的话，我会删除你的评论并阻止你的IP。&lt;/p&gt; &lt;p&gt;如果你不喜欢，并拒绝接受这个结果——那么你也来测试一下。用数据支持你的观点，使用我的代码或你自己的，然后围绕事实再来争论&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;自然，Joe也给出了测试代码及测试环境的描述。&lt;/p&gt; &lt;p&gt;文章的&lt;a href="http://misfitgeek.com/blog/aspnet/php-versus-asp-net-ndash-windows-versus-linux-ndash-who-rsquo-s-the-fastest/#comments"&gt;评论&lt;/a&gt;自然是很有看头的，说法很多，有许多人说VS的IDE好，有人说PHP永远只能写出半专业的程序。Joe一一&lt;a href="http://misfitgeek.com/blog/aspnet/comments-on-my-recent-benchmarks/"&gt;进行了回应&lt;/a&gt;，我个人认为回应的还是很客观的，紧紧围绕在测试的中心。他表示，虽然VS非常优秀，但是PHP也有很好的IDE。而能否写出专业的程序是看人，而不是由PHP决定的，有丑陋的PHP程序，也能写出如C++一般工整美观的代码。&lt;/p&gt; &lt;p&gt;从表面上看，ASP.NET在性能上胜出PHP一大截，作为ASP.NET的忠实用户我应该非常乐意接受这个“结果”。但是，我并不关注这个，因为这种运行时上纯粹的速度对于一个Web应用程序来说实在微不足道。例如Joe的&lt;a href="http://misfitgeek.com/blog/aspnet/php-linux-windows-asp-net-performance-ndash-redux/"&gt;第三篇文章&lt;/a&gt;里列举出的PHP高手的应对方式：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;ASP.NET在性能上的领先不会对我有什么影响。PHP是我的最爱，我的应用程序已经足够快了。  &lt;li&gt;没错，ASP.NET在基础性能上是比较快，但是我的应用程序可以通过优秀的页面实现和JavaScript实践把这部分性能补回来。  &lt;li&gt;我在进行Drupal开发，我对PHP最熟悉，因此我宁愿多花一些硬件来保持更好的开发效率。&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;以及InfoQ上的一条评论：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;在WEB上便捷的开发，与各种系统之间灵活的搭配，像胶水一样将各种不同的物件拼装起来呈现给Web,(python在这方面也做得非常棒)。这才是PHP能有今天的本质原因。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;之前我批评Java是一种&lt;a href="http://blog.zhaojie.me/2009/04/why-i-do-not-like-java.html"&gt;不思进取的低生产力语言&lt;/a&gt;，回应很多。其中也有类似的说法，如说Java&lt;font color="#ff0000"&gt;平台&lt;/font&gt;上开源多，项目多等等。没错，这我在对Java&lt;font color="#ff0000"&gt;语言&lt;/font&gt;发起非难之前就已经反复强调了。我同意这个观点——但是，如果是这样的“结论”肯定是站不住脚的：“因为Java&lt;font color="#ff0000"&gt;平台&lt;/font&gt;开源多，项目多，因此Java&lt;font color="#ff0000"&gt;语言&lt;/font&gt;并不是不思进取的语言”。这就好比有人说“他熟悉PHP，PHP的项目多，因此PHP的性能比ASP.NET快”一样，把两种东西混淆起来了。&lt;/p&gt;&lt;p&gt;奇怪的是，Joe没有让人不要用PHP，我也没有让人不要用Java平台（不过我现在一直建议别人用Scala代替Java语言）。&lt;/p&gt; &lt;p&gt;许多国内技术人员总有这样的“毛病”，见不得自己使用东西有一点点“瑕疵”。既然我是Java平台开发人员，我使用Java语言，我就见不得别人说Java语言一丁点不好。其实做技术就是做权衡，“没有银弹”就意味着没有技术是完美无缺的，我们选择技术是在优势和劣势之间进行平衡后的结果。只有承认了缺点，认识到缺点，才能吸取其他技术的长处，来作出更好的权衡。&lt;/p&gt; &lt;p&gt;因此我一直认可的是，SQL Server的确贵，数据存储就用*nix平台上的吧。选择多，性能多。&lt;/p&gt; &lt;p&gt;当然，这不是国内技术人员的毛病，这是一个广泛的问题。很巧，李笑来老师昨天写了&lt;a href="http://www.lixiaolai.com/index.php/archives/7461.html"&gt;一篇博文&lt;/a&gt;，似乎刚好谈论了这方面的问题。文章很短，就全文摘录了：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;无论是谁，一生中总是在不停地“选择”（姑且不论所谓选择之中有多少是真实的有多少是幻象而已）。每个人都在尽量在众多选项中选择“最好”的那个。一生有2&lt;sup&gt;n&lt;/sup&gt;选择，可&lt;a href="http://www.lixiaolai.com/index.php/archives/131.html"&gt;最终只有一条路属于自己&lt;/a&gt;。  &lt;p&gt;走在自己正在走的那条路上，人们对其它可能性可以抱有两种态度：“好奇”——通常因对现状不满而表现为“后悔”；或者“自负”——更多人最终选择的是这个，因为另外一个选择所表现出来的“后悔”通常被认为是负面情绪，而与之相反的“无怨无悔”好像更加理直气壮更加毅然决然（尽管并不总是正确）。  &lt;p&gt;时间长了，人们就不知不觉把“我一直在尽量选最好的”和“我选的就是好的”等同起来，进而外演为“与我选的不一样的选择就是不好的”，再进一步演化为“既然选的是‘不好’的，那他要么是笨，要么是‘坏’，反正跟我不一样！”  &lt;p&gt;根源就在这里了。以自我为中心也好，过度自恋也好，沙文主义、大男子主义、狭隘民族主义也罢，都大抵上如此。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;还有一个问题，之前也多次谈过，国内技术人员太容易轻视一个问题。例如在这篇新闻中不止一个用户觉得这个测试很无聊。为什么“无聊”？可能是觉得“这点性能不是关键”因此这个实验没有意义吧。我想说，其实最无聊的不是做实验的人，而是纠结与实验结果的人。或者说，无聊的不是实验，而是纠结于实验结果。与此相比，我反而强烈怀疑，轻易认为这个实验无聊的人，倒是真正只关注与“谁快谁慢”，而不关注过程和结果所表达出的内容。不去推测，不去思考。那么以后到了需要决策的时候，决策所需的依据从哪里来呢？应该都已经被“无聊”走了吧。&lt;/p&gt; &lt;p&gt;Joe的这几篇文章，以及我总结的时候，都刻意的详细列出了测试的过程和“运行性能”以外的结果。除了保持公正，客观之外，因为它们也是重要的数据。例如，我现在知道了在Windows上访问MySQL的驱动程序实现很差，而不同平台上访问PostgreSQL性能则相差无几。我知道，在Windows上进行大文件复制，受ACL影响性能较差。而如果关注Windows上运行PHP情况的朋友们则可以获得更多信息。&lt;/p&gt; &lt;p&gt;我不知道是不是国内技术人员的普遍水平较高，总是容易感觉国外的一些讨论无聊。例如有人&lt;a href="http://www.infoq.com/cn/news/2009/06/java-without-primitives"&gt;讨论Java的原生类型&lt;/a&gt;时有人回复“是不是经济危机老美太闲了”。而上次有人和别人讨论ppt的缩写是怎么来的，就给软件最初的编写者写了一封英文信求证，老外非常详细解答了这个问题，还纠正了简称和缩写的差异。作者把信贴出来写了篇blog，原站上评论都是赞同。转帖评论齐刷刷都是骂该作者闲的蛋疼。&lt;/p&gt; &lt;p&gt;我不知道这算是学术态度的问题，还是只能说“对工作没有热情，对生活没有好奇”？在《原生类型》那片文章里，有朋友回复的好：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;西方人这种看似无聊的争论才让他们达到了今天的高度，争论是不是一切量都可以用有理数表示，争论什么是运动，争论地球是宇宙的中心还是太阳是宇宙的中心，争论撒旦是如何诞生的，争论行星是如何运行。而我们很只注重实用，所以无法达到西方在理论上的高度，永远只能等别人争论完了，出结果了。我们拿来用用，仅此而已。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;不过，嫌外国人无聊的人，往往也是嫌国内没有技术含量的人。是不是很奇怪？&lt;/p&gt; &lt;p&gt;同样，Erlang之父Joe Armstrong写&lt;a href="http://www.sics.se/~joe/bluetail/vol1/v1_oo.html"&gt;Why OO Sucks&lt;/a&gt;；&lt;a href="http://www.codemonkeyism.com/"&gt;Stephan Schmidt&lt;/a&gt;写Clojure vs Scala（&lt;a href="http://codemonkeyism.com/scala-vs-clojure/"&gt;上&lt;/a&gt;，&lt;a href="http://codemonkeyism.com/clojure-scala-part-2/"&gt;下&lt;/a&gt;），Java平台语言Groovy创始人James Strachan认为&lt;a href="http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for.html"&gt;Scala是Java未来的替代品&lt;/a&gt;，他和JRuby的核心维护者James Gosling、Charles Nutter对Scala vs. Java的话题&lt;a href="http://www.infoq.com/cn/news/2009/07/scala-replace-java"&gt;讨论的不亦乐乎&lt;/a&gt;。这些都是在批评一个事物，或是在进行“语言比较”这一“无聊”的话题。那么他们是不是也都闲得慌了？&lt;/p&gt; &lt;p&gt;我在想，如果把他们的文章翻译过来，匿个名，或者让&lt;a href="http://www.cnblogs.com/jirigala/"&gt;吉日嘎拉&lt;/a&gt;这样的“众矢之的”来发表，会不会被人指责不懂OO，不懂Java？您别说，我还真见过这样的事情，谁让国内翻译转载常常不留出处呢？&lt;/p&gt; &lt;p&gt;其实这又是个逻辑问题了，这近似于《&lt;a href="http://www.yeeyan.com/articles/view/65452/28581"&gt;常见逻辑谬误&lt;/a&gt;》一文提到“人身攻击及‘你也一样’”，也就是指并不关心问题本身，而是把论据转移到“对方”身上。其实，一个命题是否正确，和它是由哪个人提出的有联系吗？我们一直指责某些人“屁股决定脑袋”，可别人真的用脑袋说话了，我们每次还是盯着别人的屁股看。&lt;/p&gt; &lt;p&gt;如果用博客园里常见的现象就是，如果一个人在说比较微软技术和其他技术，而“恰好”那人又在说微软好话，又“恰好”那人是MVP。那么好，肯定会出现许多人说MVP是微软的托。我承认，有些MVP因为个人利益而会作微软的托。例如您现在在Google上搜索“MVP TFS”的第一条便是一则&lt;a href="http://flux88.com/blog/a-deleted-response-to-a-tfs-blog-post/"&gt;不光彩的事件&lt;/a&gt;。Ben Scheirman在一个TFS的MVP博客里回复说“即使有钱，也会用免费工具，因为更好用”，结果这条回复被删除了。对方私下写信说，这是因为他在用TFS咨询赚钱。&lt;/p&gt; &lt;p&gt;这不正说明MVP是托吗？不过这显然是MVP的个人行为，而不是MVP的群体做法。原因很简单，因为Ben自己也是个MVP，所以现在是“一个MVP说微软产品不好，其回复被另一个MVP删除了”。那么您说，MVP是否是微软的托？还有，您说我是不是微软的托？&lt;/p&gt; &lt;p&gt;同样道理，Oracle认证工程师说Oracle好，Rails爱好者说Rails好，是不是都是托呢？开源爱好者是不是开源的托？我还是认为，优秀的技术人员一定是有信仰的，也是有倾向性的。但是，他们的说得东西本身是否正确，并不以他们的倾向性而转移，那些东西的正确性是客观确定的。&lt;/p&gt; &lt;p&gt;我认为，如果社区要蓬勃发展，就要接受这种倾向性，并尽力保持客观的头脑，经常“&lt;a href="http://www.lixiaolai.com/index.php/archives/7367.html"&gt;换一种方式想问题&lt;/a&gt;”。我们要的不是和谐，而是争论，对客观事物的争论，而不是对个人的人身攻击。我认为，这方面我们做的还很不够，要继续努力。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/09/aspnet-php-benchmark-and-more.html#comments</comments>
      <pubDate>Fri, 18 Sep 2009 04:14:00 GMT</pubDate>
      <lastBuildDate>Fri, 18 Sep 2009 04:14:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/asp-net/">ASP.NET</category>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <title>一份值得阅读的幻灯片：微软对PHP支持的改进，及其它一些胡言乱语</title>
      <link>http://blog.zhaojie.me/2009/09/php-on-windows-and-more.html</link>
      <guid>http://blog.zhaojie.me/2009/09/php-on-windows-and-more.html</guid>
      <description>&lt;p&gt;这里有一份我觉得值得推荐给大家的幻灯片（&lt;a href="http://cid-fa447a56f6b57df5.skydrive.live.com/self.aspx/PHP/WordCamp2009PHPonWindows.pdf"&gt;下载链接&lt;/a&gt;）。这个幻灯片是不久前举办的&lt;a href="http://2009.wordcampchina.org/"&gt;WordCamp China 2009&lt;/a&gt;上微软&lt;a href="http://blogs.msdn.com/cqwang/"&gt;王超群&lt;/a&gt;的演讲，演讲主题是《熟悉的陌生人：微软对PHP的新支持使WordPress在IIS7上雄起》。WordCamp是业界著名的PHP大会，不过我这里推荐这个幻灯片不是为了为了推广PHP，而是为了说明一些其他问题——当然也有关于技术的有价值的内容，这些您看了幻灯片和我的文章之后就会明白了。&lt;/p&gt; &lt;p&gt;对了，之前我已经在InfoQ上&lt;a href="http://www.infoq.com/cn/news/2009/08/php-on-iis-7"&gt;写了一篇新闻报道了这次事件&lt;/a&gt;。不过新闻归新闻，目的是客观说明情况而不是发表个人观点。不过博客是个人地盘，我就打算在此畅所欲言了。&lt;/p&gt; &lt;p&gt;说到PHP，可能最容易让人想起的就是著名的LAMP架构（Linux + Apache + MySQL + PHP），而这全开放的平台似乎和“封闭”的微软技术距离比较远。不过微软其实一直没有放弃对PHP的“追求”，这次演讲谈的就是微软在这方面的努力，以及取得的成果。我推荐这个幻灯片的主要原因之一，便是它写的非常有水平，尤其是开头一部分。在幻灯片一开始阐述了微软对待开源的态度，希望和PHP的同志们拉近一些距离：&lt;/p&gt;&lt;a href="http://img.zhaojie.me/blog/168980/o_this-is-not-your-fathers-ms.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/168980/r_this-is-not-your-fathers-ms.png" width="450"&gt;&lt;/a&gt;&lt;p&gt;嗯，就是这个观点：“微软已经不是当年的微软了”，它变了，变得怎么样了呢？变得拥抱开源了：“开源的朋友们，不要看到“微软”两个字就心生厌恶，来，抱一个”。此外还引用了微软首席软件架构师Ray Ozzie（如果我没有认错的话）的言论：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;I think any company these days, any technology provider, even Microsoft, has to find the right balance of being a contributor and user of open source.  &lt;p&gt;我认为如今任何的公司及技术提供商，即使是微软，也必须在开源的用户和贡献者中寻找一个合适的平衡点。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;如果说Ray Ozzie可能还是在“王婆卖瓜”的话，那么Linux创建者、开源领袖Linus Torvald&lt;a href="http://www.linux-mag.com/cache/7439/1.html"&gt;最近发表的话语&lt;/a&gt;应该更有“参考价值”：&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Oh, I’m a big believer in “technology over politics” ... There are “extremists” in the free software world, but that’s one major reason why I don’t call what I do “free software” any more. &lt;font color="#ff0000"&gt;I don’t want to be associated with the people for whom it‟s about exclusion and hatred.&lt;/font&gt;  &lt;p&gt;哦，我强烈认为“技术高于政治”……自由软件世界中有一些“极端主义者”，这也是我不再把我做的事情称作“自由软件”的主要原因。&lt;font color="#ff0000"&gt;我不想和那些有排斥和憎恶心态的人产生关系。&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;这句话在有人反对“微软为Linux提交GPL代码以提高Hyper-V的兼容性”时说的。Linus的意思再明确不过了：“技术就是就是技术，不要有门户之见”。顺便一提，开源软件（Open Source）和自由软件（Free Software）是有很大区别的，不应该混为一谈。就我个人而言，我喜欢“开源”而不喜欢“自由”。我也不喜欢FSF&lt;a href="http://news.cnblogs.com/n/48730/"&gt;觉得微软永远是错的&lt;/a&gt;，不喜欢它&lt;a href="http://www.cnbeta.com/articles/92227.htm"&gt;搞某些东西的方式&lt;/a&gt;。不过肯定也有人喜欢，每个人都可以有自己的观点。&lt;/p&gt; &lt;p&gt;好像有点说歪了。其实我也不知道微软是不是只是“口头”上讨好开源界，但是我至少看出，微软在想办法证明自己——不管这个证明是不是有什么陷阱，有什么“不可告人的秘密”。在这方面，微软至少在摆事实，讲道理，而不是随口说“我就是拥抱开源”。我觉得，在中学里学写议论文的时候，大家都应该已经知道就被告知论述的基本方式是“摆事实”，“讲道理”。可是从平时讨论的时候，我却又觉得根本不是那么一回事情。说句得罪人的话，我觉得许多朋友&lt;a href="http://blog.zhaojie.me/2009/04/be-a-professional-arguer.html"&gt;缺乏必要的逻辑思维能力&lt;/a&gt;，会产生非常多的&lt;a href="http://www.yeeyan.com/articles/view/65452/28581"&gt;逻辑谬误&lt;/a&gt;出来，但是却都还&lt;a href="http://www.lixiaolai.com/index.php/archives/7356.html"&gt;坚持自己是正确的&lt;/a&gt;。搞到最后，吵起架来彼彼皆是。而且往往在这个时候，无数匿名兄弟就跳出来发挥自己的聪明才智，各种讽刺挖苦谩骂的奇思妙语一个接一个，令人宛如置身于天上“猫扑”，人间“天涯”。&lt;/p&gt; &lt;p&gt;其实坚持自己是正确的不要紧，我也喜欢坚持自己的意见，谁不希望自己是正确的呢？但是要拿出理论根据来。其实作为技术从业人员，在许多问题上拿出根据来非常简单，例如写一个程序便知&lt;a href="http://blog.zhaojie.me/2009/05/generic-performance-test.html"&gt;泛型会不会降低性能&lt;/a&gt;。如果有些问题很难用数据说明问题（如数据获取太难），那么至少也要找出一些别人的看法来支持自己的观点。如果一味地“我认为”，“我觉得”效果自然就大打折扣了。因此，我现在也经常会有意地在文章中引用自己或其它的人的说法，至少可以让自己有“底气”一些，而不会感觉像是在扯淡。&lt;/p&gt; &lt;p&gt;我个人比较反感“光说不练”的人，我希望看到的不是“个人说法”，而是多个人的观点，或者是实际效果。例如前几天有个匿名朋友在我博客上留言，偏要坚持“静态方法的调用会阻塞其它线程访问”，我说“你试试看就知道了”，他也原样复制一遍发回给我，针锋相对，不屈不饶。不知道他最后是否认为他达到了论证“我在误导初学者，为自己的书作广告”的目的（我写过书吗？），至少我当时，既无奈，又窝火。&lt;/p&gt; &lt;p&gt;既然谈到了技术，那就再谈远一些。这位认为“静态方法的调用会阻塞其它线程访问”的朋友证明了他自己在某个方面学的有问题，而我前几天发表的&lt;a href="http://blog.zhaojie.me/2009/09/double-check-failure.html"&gt;Double Check文章中&lt;/a&gt;，有许多朋友提出“怎么能lock在一个实例字段上”，“应该lock在一个静态字段才能产生效果”。换句话说，在这些朋友看来，一个实例方法是不会产生线程安全问题的——虽然&lt;a href="http://blog.zhaojie.me/2009/08/asp-net-mvc-defaultcontrollerfactory-thread-unsafe.html"&gt;ASP.NET MVC框架的DefaultControllerFactory就出现了这样的毛病&lt;/a&gt;。这说明了在多线程开发方面，社区的整体意识还处于一个非常薄弱的程度——希望我这么说不会引起各位的不满。&lt;/p&gt; &lt;p&gt;此外，昨天我意识到原来很多朋友用了很久的for却无法写出其等价的while写法，又想起之前发现公司里的大部分同事不知道C#中使用&amp;#64;开头的字符串表示法中如何包含一个双引号。这应该都是基础中的基础，应该人人知道，不是吗？但事实就是让我感到惊讶，许多朋友认为自己不停地在学东西，ASP.NET MVC、Sliverlight，WPF一个一个地学，但是最后最普通的东西却不知道。结果工作找不好，薪水拿不高，最后一崩溃又开始叫嚷着这个行业没前途。那么，有没有想过换一种思路来学习，例如，不要随意轻视一些东西？&lt;/p&gt; &lt;p&gt;说到这里，我又想起其它一些事情，那就是我觉得如今社区里的“风气”出现了比较严重的问题。例如最近不止一次发生&lt;a href="http://www.cnblogs.com/MichaelTao/archive/2009/08/04/1536983.html"&gt;围攻面试者的“群体性事件”&lt;/a&gt;，每次有人发表面试对方的题目之后，就有大量朋友上前表示不满，对于简单的题目认为太基础了，考不出能力。对于困难的题目，就认为它太难，钻牛角尖，“又不是在招算法研究人员”。总之我发现，似乎只要是遇到了回答不出的问题，都会遭到许多人的反对。似乎社区中许多朋友都认为自己怀才不遇，“我来面试你，你也过不了”，都认为“千里马常有，而伯乐不常有”。有朋友问我，你面试别人时问些什么？我难以启齿啊，因为我问的&lt;a href="http://blog.zhaojie.me/2009/08/from-delegate-to-others.html"&gt;往往也是那些问题&lt;/a&gt;，可是一下子就被鄙视了。其实没有什么东西是简单的，有时候问问题并不是要得到结果，而是想从中看出一些细节来，例如一个人的思考方式和深度——我问某某和某某在写法上的区别，不是在搞“茴香豆”，是由其他目的。不知您是否相信，我在面试时会让对方谈一下最喜欢的体育运动的规则？&lt;/p&gt; &lt;p&gt;最近似乎认为我“无聊”的朋友也多了起来，认为我写的东西&lt;a href="http://blog.zhaojie.me/2009/08/recursive-lambda-expressions.html"&gt;没有什么实际意义&lt;/a&gt;，认为我写这些东西都是在“炫耀”。其实，我的文章都是源于实际工作中的想法，我认为对于实际工作是非常有帮助的。我不喜欢《XX编程三百例》式的文章，我认为那是“鱼”而不是“渔”。我不知道那些朋友希望我写什么样的文章才算有实际意义，但是我想最有意义的应该是提高您的能力，而正是如此，我认为您更应该关注我在成长过程中想到的这些问题。&lt;font color="#ff0000"&gt;轻易&lt;/font&gt;鄙视这个鄙视那个，就好像鄙视面试者那样，这可不好。鄙视一个东西不要紧，但关键是，你思考了没有？不要鄙视了半天，但是&lt;a href="http://www.lixiaolai.com/index.php/archives/7382.html"&gt;到最后也不知道发生了什么事，盲目地忙碌&lt;/a&gt;。&lt;/p&gt; &lt;p&gt;思考很重要，例如&lt;a href="http://www.lixiaolai.com/index.php/archives/7367.html"&gt;换一种思考方式就会得到不同凡响的结果&lt;/a&gt;。至少，这也是锻炼逻辑的一种有效方式。想要验证自己想清楚了没，我认为最好的方式就是写一篇文章。如果您想明白了，一定能把它说清楚。反过来说也一样，如果您说不清楚，基本上就是因为您没有想明白。&lt;/p&gt; &lt;p&gt;说了好多，越扯越远，喝口水，回来继续吧。&lt;/p&gt; &lt;p&gt;PPT的正题自然是讲述微软在PHP平台上做出的努力和取得的成果，其中列举了之前与康盛创想合作进行的&lt;a href="http://cid-fa447a56f6b57df5.skydrive.live.com/self.aspx/PHP/LAMPvsWIMP.COMSENZ.ppt"&gt;性能评估结果&lt;/a&gt;，证明在Windows Server 2008 + IIS上运行PHP，从平均相应时间，每秒处理的请求数，以及数据吞吐量等多方便均显著优于Linux + Apache的托管方式。当然，这个结果也受到了一些质疑，例如为什么在Apache中使用了mod_php而不是在大多数情况下性能更好的FastCGI。关于这点我没有测试过，我不清楚。不过这并不要紧，我想说的是：Windows的性能真的不差。&lt;/p&gt;&lt;a href="http://img.zhaojie.me/blog/168980/o_iis7-perf.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/168980/r_iis7-perf.png" width="450"&gt;&lt;/a&gt;  &lt;p&gt;这也是幻灯片的截图之一。从中可以看出IIS 7的吞吐量完全可以达到静态文件请求20K，ASP.NET请求5K RPS（每秒请求数）的吞吐量。这是100%的事实，我可以担保，因为在我07年在微软的时候，曾经在自己工作用的普通 32位workstation上试验过，请求静态文件轻松超过了10K。算上IIS 7的性能增强，以及测试机的性能因素，得到上图的结果完全没有问题。至于ASP.NET动态请求的性能，5000多完全就是一个没有意义的数字了——我不是说它假，我只是说它没有意义。因为对于动态请求来说，纯粹比这种“空请求”的吞吐量，几乎没有任何实际参考价值。因为，我们有其它的性能瓶颈，根本达不到IIS本身的性能限制。&lt;/p&gt; &lt;p&gt;对于普通Web应用程序来说，如果在实现上没有大的问题，几乎不会让Web服务器（指IIS这种，不是指“机器”）成为性能瓶颈。性能瓶颈往往是在外部服务器调用，或者外部数据访问上。例如耗时的SQL查询一多，应用程序整体性能自然就下来了。因此，业界最为热烈的讨论往往是基于“缓存”和各种数据存储方式的，因为到目前为止它们都是最有可能成为性能瓶颈的。对于Web服务器本身性能的讨论也不是没有，只是相对就少很多了，要有，大部分也是基于静态请求的性能比较。&lt;/p&gt; &lt;p&gt;对于Web 2.0的网站来说，由于变化太多太快，几乎无法生成静态页。因此，这样的Web应用程序在一台机器上的吞吐量根本达不到5K，即时是1K也几乎做不到。在一台目前普通配置的服务器上，如果可以达到每秒100多的动态请求，基本上已经做的相当不错了，甚至50、60多也已经“够意思”了——像当年&lt;a href="http://www.douban.com"&gt;豆瓣&lt;/a&gt;鬼神般的5、600（如果我没有记错的话）几乎难以再现。不过100 RPS也已经是一个很了不起的数字了，如果按6小时的密集请求来算，您想一下这样一个动态站点的日访问量是多少呢？&lt;/p&gt; &lt;p&gt;当然，Windows不是没有性能问题，我只是说在IIS，Web开发等方面不会出现性能问题。有人说Windows的文件系统，也就是NTFS的性能很差，尤其是在处理零碎地文件时候。这我也有所耳闻，平时也有类似的感觉，但是没有经过这方面的实践，所以并无法说出准确的结论。不过真的性能差，也要去好好了解它，这样我们就可以设法避免一些薄弱的环节。随意举个例子，我们可以优化自己程序的存储方式，尽量读取连续的数据，让文件系统的性能问题可以缓解一下。SQL Server不也是在NTFS上构建出高效数据应用的吗？&lt;/p&gt; &lt;p&gt;使用Windows系统的另外的问题，也是被人提及很多次的问题，便是授权协议。Linux使用是不要钱的，而Windows是要花钱买的，这个自然应该算入成本。不过在我看来，其实Windows并不贵。为什么呢？您可以去Dell的网站上看一下一台预装了Windows Server的服务器的价格，一个Web Edition的Windows Server操作系统的价格大约是3000多元，这也就相当于一个普通程序员1个月的薪水而已，更何况操作系统可以算作是一次性投资。对于一个公司来说，每天开一次门就相当于几千几万的钱花出去了，购买一个Web Edition的Windows Server价钱根本算不了什么。至于开发成本，这是一个太“虚”的东西，暂时就不讨论了吧——我想，应该也没有什么理由可以有力证明使用ASP.NET会加大开发成本。&lt;/p&gt; &lt;p&gt;事实上，Web Edition已经足够部署ASP.NET应用程序了，Enterprise Edition自然要贵上十几倍甚至更多，但是您根本用不着。用盗版操作系统时带来的坏习惯“要用就用最好的”，在产品环境中一定要改一下。哦，对了，微软对于年收入低于100万的公司，或是非盈利机构都有非常大的折扣，甚至免费的策略（如&lt;a href="http://www.microsoft.com/Bizspark/Default.aspx"&gt;BizSpark计划&lt;/a&gt;）。您不应该错过。&lt;/p&gt; &lt;p&gt;因此我认为，在Windows平台上使用ASP.NET，是一个非常合适的Web应用程序开发/运行平台。即时是对于创业型小公司来说，我也会选择使用Windows + ASP.NET。&lt;/p&gt; &lt;p&gt;但是……微软平台上的授权价格并非总是个可以忽视的问题。因为SQL Server实在是太贵了，而免费的Express版本是不可以用于商业应用的（存疑，求证）。如果我们想要使用SQL Server，那么成本的确会哗哗地上升，尤其对于创业公司来说这是比不可忽视的支出（当然如果加入了BizSpark计划……）。因此可以这么说，运行ASP.NET的Windows很便宜，但是SQL Server，以及运行SQL Server的Windows会非常昂贵。因此，对于数据存储来说，我会选择Linux下的免费及开源的产品。而且我可以有更多的选择，无论是关系型数据库，键/值存储方式，还是现在慢慢再兴起的如&lt;a href="http://www.infoq.com/cn/news/2009/09/mongodb"&gt;MongoDB&lt;/a&gt;那样的无架构，文档型数据库，都可以合理组装使用。&lt;/p&gt; &lt;p&gt;所以我现在越来越推荐Windows + *nix的合作关系，至于在Windows和*nix项目的通讯问题上，其实丝毫不用担心。如今各个项目都是基于标准的通讯协议（如TCP/IP，甚至HTTP），使用通用的或自定义的格式进行数据交换。对于一个Linux下的数据库来说，它根本不会关心与它连接的是Windows还是Linux，也不会关心发起调用的是.NET还是Java，Python或Ruby平台。大家根据协议办事即可。&lt;/p&gt; &lt;p&gt;那么为什么业界总是认为Windows性能差呢？原因可能是因为微软的“声誉”不太好，而业界声音最响，最为活跃的大都是开源工作者或自由人士，他们自然会不遗余力地支持自己的环境——这很正常，优秀的程序员一定是有信仰的，我一直这么认为——当然也会产生一些不客观的FUD行为。还有便是，Windows进入服务器领域时间比较晚，而且在IIS 5那些年代，Windows在服务器领域的表现的确不怎么好。因此，那时候留下的负面印象自然也会产生不好的影响。但是微软是在发展的，微软牛人非常多，微软研究院的论文年年占据各大会议相当比例，而微软的产品的质量也已经足够了得了。如果继续用10年前的印象来判断如今的微软是不正确的——当年微软系统在服务器这块没有丝毫占用率（几乎都是Unix，Oracle的天下），现在已经占据中小公司80-90%，世界五百强50%的份额，这还不够说明问题吗？&lt;/p&gt; &lt;p&gt;关于这点，作为Windows平台下的程序员，我们应该有足够的自信，管别人怎么“怀疑”我们呢。&lt;/p&gt; &lt;p&gt;对了，还有一个可能的原因是由于微软的技术太容易入门，导致给人不够“牛逼”的感觉。这也是没有必要的，就好比说，一个国家的初等教育水平高，能证明它的高等教育水准不行吗？这只是定位的问题，当然这可能也是微软的策略——但不是微软的错，也不是微软技术没有价值的证据。当然，作为Windows平台上的程序员，提高自己的能力是没有错的。不光没有错，是一定必须要这么做的！&lt;/p&gt; &lt;p&gt;不过必须承认的是，Windows有个硬伤，就是您无法在上面捣鼓某些东西，例如换一个文件系统，改一改内核。如果你是热衷于这方面的Geek，那么自然不适合使用Windows。&lt;/p&gt;&lt;p&gt;最后，还是用幻灯片里的内容收尾吧。在这份幻灯片的末尾附有30多页的IIS Web应用程序配置最佳实践，是一个非常不错的参考，您一定要看一下。&lt;/p&gt; &lt;p&gt;就写到这里吧，虽然结尾有些仓促，但我真的已经很困了。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/09/php-on-windows-and-more.html#comments</comments>
      <pubDate>Thu, 03 Sep 2009 18:17:00 GMT</pubDate>
      <lastBuildDate>Thu, 03 Sep 2009 18:17:00 GMT</lastBuildDate>
    </item>
  </channel>
</rss>
