<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>重中之重 - 老赵点滴 - 追求编程之美</title>
    <link>http://blog.zhaojie.me/essential/</link>
    <description>先做人，再做技术人员，最后做程序员。打造国内最好的.NET技术博客。</description>
    <language>zh-cn</language>
    <managingEditor>jeffz@live.com (老赵)</managingEditor>
    <webMaster>jeffz@live.com (老赵)</webMaster>
    <pubDate>Wed, 21 Apr 2010 16:20:07 GMT</pubDate>
    <lastBuildDate>Wed, 21 Apr 2010 16:20:07 GMT</lastBuildDate>
    <ttl>60</ttl>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/life/">生活心情</category>
      <title>我们不是牛人，所以还是老老实实跟着兴趣走吧</title>
      <link>http://blog.zhaojie.me/2011/02/piano-life-and-interests-driven-practice.html</link>
      <guid>http://blog.zhaojie.me/2011/02/piano-life-and-interests-driven-practice.html</guid>
      <description>&lt;p&gt;前几天周筠老师&lt;a href="http://blog.sina.com.cn/s/blog_6242cc7f0100oonu.html"&gt;写了篇博客&lt;/a&gt;，她认为兴趣十分重要，没有兴趣很难做成事情。我对此十分同意，有亲身经历为证。更值得一提的是，这个亲身经历和技术或是职业方面的关系真不大，我对许多技术都感兴趣，一时还真难找出对比反差明显的东西。这次来说说我近几个月找到——或者说“找回”的兴趣，弹钢琴。在看来，这对我来说实在是“兴趣”的最佳例证了。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/piano-mbp-score.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/piano-mbp-score.jpg" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;以上是我的装备，CASIO PX-130，相当著名的低端电钢琴。必要时前方放一纸箱，侧卧一个笔记本用于看谱，效果还算不错。对于在线的乐谱，我会把它截屏至PowerPoint中播放，再接个鼠标放地上，作为脚踏板用于翻页。电钢琴的声音和触键与真钢琴相比自然差一大截，但它的好处在于不会扰民，可以允许我半夜两三点尽情抒发情怀。等老子有钱了，一定搞间隔音好的屋子，放台斯坦威大三角，就像白天做梦时梦到的那种样子。&lt;/p&gt;

&lt;p&gt;就像大部分琴童那样，我从三四岁的时候开始学琴。当时家里花了大笔积蓄，也就是二十多年前的5000块钱，买了台现在也差不多值5000块钱的聂耳牌立式钢琴——话说这台钢琴已经破败不堪，许多键已经松弛疲软，延音踏板踩下去也没有延音效果了。过段时间打算找人来调试修理一下，然后给我妈用，她报名的老年班月底就要开始上课了。现在，再给这部老爷琴留个影吧。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/home-old-piano.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/home-old-piano.jpg" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;还是和大部分琴童那样，我没能在七八岁时达到演奏肖练的水平，在那个时候钢琴给我带来的似乎只有痛苦。这么想吧，一个小破孩儿，每天在同学朋友都在疯跑玩耍的时候，被父母逼着坐在钢琴前进行枯燥的练习。此外身边同时常常伴随着耳光皮带拖鞋板，所以我如今皮糙肉厚反应灵敏也非一朝一夕之功。您可能会说弹钢琴件多么美妙的事情哪，但是对于对于当年的我，乃至绝大部分琴童来说，要“享受”钢琴几乎是件不可能的事情。&lt;/p&gt;

&lt;p&gt;首先，除了某些天才型选手，很难有琴童能在一开始的几年里有能力驾驭钢琴，因此只能不断地弹奏特定的简单作品或是练习曲等等。其次，即便有了一定程度的技术水平，也不一定能够真正体会到音乐的美妙。其中第二点原因尤其关键。对琴童来说，弹琴必然意味着考级，而即便是业余十级水平关注的还是技术——我并没有觉得这点有太大问题，因为钢琴演奏首先的确是个技术活。只可惜，在应试教育的一贯优秀传统下，可怜的琴童们被强迫不断地练习，只为“跑完”整首曲目，“体会”也好“精雕细琢”也罢就先放一边吧。&lt;/p&gt;

&lt;p&gt;这真的很讽刺。我前段时间翻出90年代初的考级用书，发现其中的确也包含了丰富的著名曲目，但是我当时完全没有意识到这一点。我只是个苦恼地一边弹琴一边哭哭啼啼的小破孩，时刻准备着偷懒。终于，在上初中以后，我以学业为由终止了钢琴演奏，直到几个月前，期间十几年没有摸过钢琴。&lt;/p&gt;

&lt;p&gt;一切是从我上大学开始改变的。不知道是什么原因，我第一次迷上古典音乐，后来总结了一下，至少听了千余盘CD，其中大部分是钢琴演奏。名家作品名家演绎几乎一个不拉，包括&lt;a href="http://www.naxosdirect.co.uk/Liszt-The-Complete-Piano-Music/title/CDS44501/98/"&gt;Leslie Howard在Naxos录制的李斯特大全集&lt;/a&gt;在内的许多整套录音都听了不止一遍，如肖邦舒伯特莫扎特贝多芬钢琴作品全集这样的“流行音乐”更是反复欣赏比较了好几个甚至十几个不同的版本。逐渐，我自然无法满足与单纯地“聆听”，而想亲手体会一下这些乐章的美妙。但是，几次重新接触琴键，唯一的感觉还是只有痛苦。这样的痛苦尤甚小时候初学钢琴时，因为我发现自己完全无法控制自己的双手，技术也已经远不如童年的巅峰时期，一些基本的音阶琶音和弦已经完全无法跑下，只想剁手。&lt;/p&gt;

&lt;p&gt;但是，我现在还是在坚持，因为王力宏有首歌唱得好：“欺骗世界、欺骗自己”。和小时候相比，我除了身高体重之外，最大的长进可能就是自欺欺人的功夫了。我时刻告诉自己，我还能够练好；只要坚持，终有一天我的手下也会出现名家的演绎水准。我时常也会翻出些著名的曲目，演奏其中一些不是太难的片段，自我安慰/享受一番，以免自己重新迷失在枯燥的基础练习中。如今，在我编程疲惫之余以弹琴作为放松，反之亦然；为了能够在午休的时候也能摸上琴键，我还自费购买了一台电钢琴放在公司。使用这种方式，我居然也硬扛下来贝多芬“悲怆”钢琴奏鸣曲的第一乐章——这也是促使我重新开始弹琴的曲目。当然，只能算是半熟不熟地跑下而已，毫无质量可谈。总而言之，如今我痛并快乐着。&lt;/p&gt;

&lt;p&gt;在钢琴演奏方面，可谓“兴趣”是我的唯一动力。小时候的技术比现在好得多，但却体会不到如今的快乐。其中唯一的区别就是兴趣了。我想，如果重来一次，我有机会可以引导小时候的我领悟一些简单的音乐之美，甚至只需要播放一些录音，可能一切就都会不一样了。说起来，我也打算引导（但不强迫）我的小孩学习钢琴，因为这的确是个美妙的事物。我们都不是&lt;a href="http://www.douban.com/group/topic/17278934/"&gt;郎朗般的牛人&lt;/a&gt;，还是跟着兴趣走下去吧。&lt;/p&gt;

&lt;p&gt;没有兴趣？培养兴趣也要产生兴趣。“欺骗世界，欺骗自己”。&lt;/p&gt;

&lt;embed src="http://www.tudou.com/v/vFMiG7X9K3A/&amp;rpid=55026969/v.swf" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="480" height="400"&gt;&lt;/embed&gt; 

&lt;p&gt;以上是我目前的水平（各位暂时先不要苛求电钢琴那单薄的录音效果了），一年后我们再来看。&lt;/p&gt;

&lt;p&gt;&lt;font color="#ff0000"&gt;广告时间：&lt;/font&gt;第三届nBazzar技术交流会所有演讲资料已经发布，&lt;a href="http://nbazaar.org/"&gt;欢迎关注&lt;/a&gt;。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/02/piano-life-and-interests-driven-practice.html#comments</comments>
      <pubDate>Wed, 09 Feb 2011 17:28:51 GMT</pubDate>
      <lastBuildDate>Thu, 10 Feb 2011 08:07:27 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/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/reading/">阅读相关</category>
      <title>国内计算机图书真的不贵</title>
      <link>http://blog.zhaojie.me/2010/10/tech-books-published-in-china-are-not-expensive.html</link>
      <guid>http://blog.zhaojie.me/2010/10/tech-books-published-in-china-are-not-expensive.html</guid>
      <description>&lt;p&gt;经常看到社区里有朋友抱怨说，现在的书好贵啊。但事实上我想要指出的一点是，在国内计算机图书真的不贵。不信我们一起来看看国外计算机图书的价格如何。&lt;/p&gt;

&lt;p&gt;原版计算机图书，视书籍包装、厚度、出版社、种类，价格会有很大差距，但是一般都在40美金以上。例如一本软壳460页的《&lt;a href="http://www.amazon.com/gp/product/073562609X/"&gt;Microsoft .NET: Architecting Applications for the Enterprise&lt;/a&gt;》价格为45美元，而一本差不多厚度的硬壳《&lt;a href="http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613/"&gt;Framework Design Guidelines (2nd Edition)&lt;/a&gt;》是55美元。普通的技术图书定价不会相差太远，但是有一种会特别昂贵，那就是教科书。我手上有几本非常出名的教科书：其中《&lt;a href="http://www.amazon.com/Computer-Systems-Programmers-Perspective-2nd/dp/0136108040/"&gt;Computer Systems: A Programmer's Perspective (2nd Edition)&lt;/a&gt;》（即传说中的CSAPP）是108美元，《&lt;a href="http://www.amazon.com/Compilers-Principles-Techniques-Tools-2nd/dp/0321486811/"&gt;Compilers: Principles, Techniques, and Tools (2nd Edition)&lt;/a&gt;》（即传说中的龙书，Dragon Book）是106美元，而《&lt;a href="http://www.amazon.com/Introduction-Algorithms-CD-Rom-Thomas-Cormen/dp/0072970545/"&gt;Introduction to Algorithms (2nd Edition)&lt;/a&gt;》（即传说中的算法导论，CLRS）更是达到了111美元（不过奇怪它新出的&lt;a href="http://www.amazon.com/Introduction-Algorithms-Third-Thomas-Cormen/dp/0262033844/"&gt;第3版&lt;/a&gt;反而降到87美元了）。这些教科书虽然都是硬壳，但由于页数太多但又不好太厚，因此纸张可谓“薄如蝉翼”。&lt;/p&gt;

&lt;p&gt;那么这种原版书这些价格是什么概念呢？我们可以考虑美国人民群众手中美金的购买力。我今天在推特上调查了一小下，身居硅谷的&lt;a href="http://twitter.com/lordhong"&gt;@lordhong&lt;/a&gt;同学&lt;a href="http://twitter.com/lordhong/status/28761888222"&gt;告诉我&lt;/a&gt;，一美元大约可以买：“3磅香蕉，一罐1磅的盐，一杯小咖啡，一个麦当劳小汉堡，一罐可乐，40来根葱，5两鸡肉/猪肉”，再加上其他一些同学的讨论结果，大约可以得出“1美元在美国”与至少“2元人民币在国内”的购买力差不多（甚至要更多）。当然，在美国买一些汽车、首饰的价格甚至比国内还要便宜，但是我想，比较生活必需品显然更为合适。那么换句话说，在美国购买一本100美元的书，相当于在国内购买一本200元人民币的书。您在国内买过200元计算机图书吗？至于收入，微软在美国的Entry Level是5到6万美金一年，国内是十到十二万人民币，也是差不多的比例。当然，我知道国内有不少两三千元月薪的人，我不太清楚美国一两千元月薪的人是什么情况。&lt;/p&gt;

&lt;p&gt;上面提到的一些书，在国内大都有影印版或是翻译版。例如《&lt;a href="http://www.amazon.cn/mn/detailApp/ref=sr_1_1?_encoding=UTF8&amp;amp;s=books&amp;amp;qid=1288102600&amp;amp;asin=B003Q97N8E&amp;amp;sr=8-1"&gt;Microsoft .NET企业级应用架构设计&lt;/a&gt;》为69元，《&lt;a href="http://www.amazon.cn/mn/detailApp/ref=sr_1_fkmr0_1?_encoding=UTF8&amp;amp;qid=1288102692&amp;amp;asin=B00332FM9Q&amp;amp;sr=1-1-fkmr0"&gt;.NET设计规范:约定、惯用法与模式（第2版•英文版）&lt;/a&gt;》为60元，《&lt;a href="http://www.amazon.cn/mn/detailApp/ref=sr_1_2?_encoding=UTF8&amp;amp;s=books&amp;amp;qid=1288102784&amp;amp;asin=B0011C9L24&amp;amp;sr=1-2"&gt;深入理解计算机系统（英文版）&lt;/a&gt;》为89元，《&lt;a href="http://www.amazon.cn/mn/detailApp/ref=sr_1_1?_encoding=UTF8&amp;amp;s=books&amp;amp;qid=1288102858&amp;amp;asin=B001NGO85I&amp;amp;sr=1-1"&gt;编译原理（第2版）&lt;/a&gt;》为89元，《&lt;a href="http://www.amazon.cn/mn/detailApp/ref=sr_1_1?_encoding=UTF8&amp;amp;s=books&amp;amp;qid=1288102908&amp;amp;asin=B0011BVTRK&amp;amp;sr=1-1"&gt;算法导论（原书第二版）&lt;/a&gt;》为85元。可见国内计算机图书的价格甚至比原价的美金数值还低，更别说折算后的购买力了。难怪上次&lt;a href="http://blog.zhaojie.me/2010/04/something-about-groovy-and-fsharp-from-qcon.html"&gt;在QCon 2010&lt;/a&gt;陪&lt;a href="http://blogs.msdn.com/timng/"&gt;Timothy Ng&lt;/a&gt;（F#的Dev Lead）逛书摊时他惊呼“实在太便宜了”。更重要的是，如今国内图书的质量也越来越好，如《.NET设计规范》除了不是硬壳封面，无论从纸张还是印刷方面和原版几乎一模一样。&lt;/p&gt;

&lt;p&gt;因此，其实国内的计算机图书可谓十分便宜，我们应该舍得为知识进行投资，知识不应该是便宜的东西。国内的计算机图书市场其实处在一个很尴尬的境地：读者嫌贵，但其实作者和出版社都赚不到什么钱。一个认真写书的作者，最后他的所得与付出相除，最后发现可能只有每月一两千元（翻译则更少）。要知道作为一个有水平的作者，本身就已经有了很高的工资，根本不愿意耗费宝贵的时光、甚至健康来换取如此“微薄”的报酬。在国外，作者可以靠一本较为畅销的技术图书养活自己，在国内除了那本前无古人后无来者的“谭浩强C语言”又有谁能做到？&lt;/p&gt;

&lt;p&gt;所以，对于每个在国内认真写书的作者，我们都应该视他们为楷模，他们实在是很不容易。我很佩服他们，因为我在权衡之后承认我做不到这种付出。我们要谴责的是那些写烂书，沽名钓誉的作者和出版社，因为正是他们还在继续扰乱国内计算机图书市场。而我们作为读者，对于图书市场也有十分关键性的力量，促进图书市场的良性循环是一种双赢的结果。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/10/tech-books-published-in-china-are-not-expensive.html#comments</comments>
      <pubDate>Tue, 26 Oct 2010 14:51:59 GMT</pubDate>
      <lastBuildDate>Tue, 26 Oct 2010 14:51:59 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/news/">新闻信息</category>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <title>为什么我要反对北大青鸟</title>
      <link>http://blog.zhaojie.me/2010/04/why-i-say-no-to-aptech.html</link>
      <guid>http://blog.zhaojie.me/2010/04/why-i-say-no-to-aptech.html</guid>
      <description>&lt;p&gt;您是否知道最近北大青鸟有什么新闻吗？嗯，最近的电脑报发表了“中国IT培训现状大调查之二”一篇题为“北大青鸟高薪就业迷雾”的文章，描述了北大青鸟的种种问题。我这里不想用“揭露”、“黑幕”等激烈的词汇，但我会全文转载这篇文章，大家可以自己阅读，自行评价。客观地说，这篇报道的内容是否属实我不敢打保票，但是我愿意相信其中的说法，因为北大青鸟及其他一些培训机构的学生于我的感觉，真的不敢恭维。&lt;/p&gt;

&lt;p&gt;加入&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;前，我在一个小公司做事，算是创业吧。在小公司里需要亲自进行许多面试，自然接触了大量北大青鸟等培训机构毕业的学生。可以这么说，我没有遇到一个可以令我满意的学员。真的不是我要求高，我的要求原本可能很高，但是随着时间的推移，我的标准已经一再放低，但是如果一个学习程序开发两三年的学生，不能写代码把一个数组反转，这能够令人接受吗？&lt;/p&gt;

&lt;p&gt;我发现，让那些学员写简单的程序是非常困难的事情。一段程序，我们可能会在其中使用顺序，条件，循环。但是，如果一段程序需要同时用到循环和条件判断，这个程序基本上就没法写出了。这是什么原因？我不知道，我只想说这种编程能力，和没有进行过编程学习有什么区别？随便找个高中毕业生培训一个月都不止这点水平。那么花那么多钱读北大青鸟是用来做什么的？&lt;/p&gt;

&lt;p&gt;每次我反对北大青鸟，都会有人提出不同意见，其中大部分人是在读的学员。我能理解你们的心情，毕竟北大青鸟的声誉会影响到你们未来的发展。但是，我想说，其实你们才是北大青鸟最大的受害者。你们维护北大青鸟，最终的结果可能只能麻痹你们自己。&lt;/p&gt;

&lt;p&gt;有人说，北大青鸟还是有高水平学生的，而且这东西主要看人。我说，那是自然，但什么东西不是看人的？一个优秀的人，不去青鸟那儿读书，都能很成功，但他为什么要去花那冤枉钱？北大青鸟收了钱，就应该负责把一个普通的学生教好。但是现在，大部分人花了一两万，最后毕业还找不到一个三千块每月的工作，他不吃不喝多少年才能赚得回来？更可恶的是，北大青鸟从招生开始便使用大量虚假广告。薪资高于211本科毕业生？包就业？去你妈的。&lt;/p&gt;

&lt;p&gt;更严重的问题是，北大青鸟将一张张白纸污染得不成样子。原本可能怀带着理想的学员，原本可能有潜力的学员，就这样被糟蹋了。如果一个初学者从一开始就被灌输一些错误的观念，这是一件多么严重的事情。有的学员会这样回答我：“我是做测试的，不是专业做开发的”，“我能写应用程序，这种纯算法题不是很擅长”。大哥大姐，这只是反转一个数组啊！&lt;/p&gt;

&lt;p&gt;此外，从一些原来北大青鸟的老师那里也可以知道，在北大青鸟内部规定教材和教学方式，严禁教师改良教材内容，这算是什么样的规定？我相信北大青鸟能有优秀的老师，但是这又能起到多少作用？&lt;/p&gt;

&lt;p&gt;剩下的内容，各位就自己看文章吧。这篇文章前两天被大量转载，但是在北大青鸟开始公关之后，许多地方已经将文章删除了。现在如果您在Google里搜索“北大青鸟高薪就业迷雾”，就会发现许多无法打开的链接。幸好这次百度立功了，我们还可以在&lt;a href="http://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece763104687270e54f7226690864822c3933fc239045c033db4fe6178505380936b6776ed131efdf142346c5537b6edcb824fdfbc972c3bcd7a742613913111c469acdc3623d654914de8df0e96bfe74591b9a3d5c82050dd52756df0fa9c2c7403bc6de76447f4a7e95f652807cb9b2713ff4e072e882230a136f8f7446810f081ca2b3a&amp;p=906dda5685cc43ff57e88e3e4e&amp;user=baidu"&gt;百度快照里看到一些内容&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;以下便是全文内容转载。&lt;/p&gt;

&lt;h1&gt;北大青鸟高薪就业迷雾&lt;/h1&gt;

&lt;p&gt;铺天盖地、无处不在的广告，“学IT，好工作，就读北大青鸟”的广告词，构成了大多数人对北大青鸟这家号称“中国第一IT培训机构”的初始印象。&lt;/p&gt;

&lt;p&gt;这其中，不难看出北大青鸟主攻的人群：对IT行业向往已久的“门外汉”。极具诱惑的关键词：高薪、零基础、速成、工作推介。花上14800元和半年时间，高中生就能摇身一变成为白领“网络工程师”？职业技能培训市场隐藏着怎样的敛财黑幕？&lt;/p&gt;

&lt;p&gt;（黄枪调查）&lt;/p&gt;

&lt;h1&gt;国内最贵的职业中介？&lt;/h1&gt;

&lt;p&gt;“就业推荐？倒是推荐了，不过是影视后期”。在北大青鸟学了2个学期Java，交了17000元学费的张敏哭笑不得。 &lt;/p&gt;

&lt;p&gt;“上学时在无锡电视台实习过，会一些影视采编基础操作”，根据这样的“特长”，培训结束后张敏被北大青鸟推荐到一家广告公司和一家网络开发公司，职位都是“影视后期”，与心中的IT工程师毫无关系。“我这还算是好的，好歹还是技术活。那一期班上同学还有被推荐去做销售的，最辛苦的是游戏地推（地面推广人员），还真是‘切合企业需求’”。 &lt;/p&gt;

&lt;p&gt;一年时间过去了，张敏始终没有成为梦想中的“工程师”，他现在在一家民营企业做文案，Java已经“丢得差不多了”。和一些“师兄”交流后才知道，所谓的 “就业推荐”，不过是根据学员特长，由培训中心代发简历给用人单位，争取一些面试机会罢了。&lt;/p&gt;

&lt;p&gt;“北大青鸟是不是国内第一IT培训机构暂且不说，但它一定是国内最贵的职业中介——花了我一万七就投了几份简历还不管你面试成不成功。”张敏对黄枪无奈笑称。 &lt;/p&gt;

&lt;p&gt;张敏当初投身北大青鸟，是被“人才奇缺+高薪就业”的行业前景迷惑，“当时很出名的宣传语是100%就业，高中生海外高薪就业，听着就让人心动啊”。再加上咨询师的巧舌如簧和ACCP、OSTA、ORACLE一大堆金牌证书的诱惑，想不“入瓮”都难。&lt;/p&gt;

&lt;p&gt;“参加培训班，我们主要是受了广告的影响。”小陈向记者展示了一份份的广告复印件。一则广告显示：北大青鸟ACCP软件工程师，国家劳动部+北京大学+印度APTECH，100%就业保障。颁发证书：国际——北大青鸟APTECH，国内——国家劳动部。另一则广告显示：助你进“名企”，拿“高薪”。联想、方正、清华同方、诺基亚、IBM……北大青鸟与1000多家名企签约等醒目字眼。 &lt;/p&gt;

&lt;p&gt;实际上，在“不上名牌大学，只读北大青鸟”的广告宣传下，对许多学员和家长而言，北大青鸟给人留下的第一印象往往是，只要学了ACCP，不仅能解决就业问题，还能成为高收入者。 &lt;/p&gt;

&lt;p&gt;根据黄枪调查，空头承诺一直是各类IT培训机构的惯用伎俩，这种情况在北大青鸟依然普遍存在。 &lt;/p&gt;

&lt;p&gt;4月中旬，黄枪以学员身份联系到了北大青鸟西苑中心，一位彭姓老师称，如不考虑就业方向，考试合格后，“就业率一定是100%”；该中心往届学员的平均工资水平为“试用期2500元以上，转正后增加800~1500元，还不算其他的福利补贴”。黄枪查阅了该中心首页，发现他们列出的明星学员的薪资颇具吸引力并且不忘强调：“即使在金融危机肆虐的2008年，西苑中心软件开发毕业学员薪资水平一直持续高于211本科毕业生的平均水平。” &lt;/p&gt;

&lt;p&gt;然而，对“100%就业率”、转正后超4000元月薪的承诺能否写入合同，彭姓老师一口拒绝，称总部规定各培训中心要使用“标准合同”，不可以私自更改。&lt;/p&gt;

&lt;h1&gt;“定向委培”子虚乌有？&lt;/h1&gt;

&lt;p&gt;那么，北大青鸟的100%就业率如何保证？彭姓老师称：“我们和很多企业都是定向委培关系，长期向他们输送人才。”对社会培训机构来说，“定向委培”确实是一块金字招牌——这几乎意味着“铁饭碗”和就业捷径，但北大青鸟真和那么多的企业签订了长期“定向委培”吗？黄枪发现，虽然极少数培训中心确实承接了一些短期的委培指标，但“委培”的效果无疑被极大夸大了，对于绝大多数学员而言，那不过是幻想。 &lt;/p&gt;

&lt;p&gt;知情人士称，各地北大青鸟在就业宣传上往往是“字斟句酌”，希望通过“创意措辞”吸引更多学员的关注，于是“不上名牌大学，只读北大青鸟”、“名企征招”、 “100%就业”等诱人词汇格外醒目，让苦于就业无门的广大学员看后“怦然心动”。 &lt;/p&gt;

&lt;p&gt;林林总总的诱人词汇中，“定向委培”最具吸引力，因为“定向委培”无疑在昭示其就业率为100%，这就使很多学员义无反顾地交上高额学费，并憧憬着不久将得到一份高薪工作。因此，各地北大青鸟在宣传中，无不强调与几十乃至几百家企业签定了“定向委培”计划。 &lt;/p&gt;

&lt;p&gt;问题是，事实真如北大青鸟宣称的么？ &lt;/p&gt;

&lt;p&gt;位于重庆高新区的北大青鸟，号称重庆西永IT企业定向培养总校，西永为重庆电子信息产业专业化园区。此前有媒体报道称，包括高新区在内的北大青鸟重庆两个中心出台了“西永IT企业定向就业计划”，工程借助中、美、印三国专家资源，定向培养实现100%的优良就业率。 &lt;/p&gt;

&lt;p&gt;4月中旬，黄枪调查时，该中心“企业定向班”正在热招，宣称主要招收西永IT企业定向就业班，受大企业委托培养IT高端人才，经北大青鸟培训后，让高中生也能进名企，直接输送到西永IT就业，月薪平均4000元——耐人寻味的是，根据重庆市统计局公布的数字，重庆市人均工资为2580元。 &lt;/p&gt;

&lt;p&gt;“主要是进入哪些企业呢？能否写入就业协议中？”黄枪问。“只要完成了三个阶段的学习并毕业后，学员将有机会进入惠普、华为、微软、博恩、艾尔卡特等知名IT企业工作，也有机会进入重庆移动、电信、自来水厂等事业单位就职。”该中心一位廖姓咨询师说。 &lt;/p&gt;

&lt;p&gt;“按照你的说法，是不是指惠普、微软、华为通过你们定向培养就业人才？”“关键是要看你自己的能力了，我们总不能把一些技术不强的人也输送过去吧。”廖姓咨询师说。 &lt;/p&gt;

&lt;p&gt;“这和你们宣传的定向委培不是一回事吧？你能否明确告诉我，惠普、微软这些企业是不是和你们有这个定向委培计划？”黄枪反复追问。 &lt;/p&gt;

&lt;p&gt;出人意料的是，在黄枪反复追问“定向委培”具体细节时，含糊其词转移话题的廖姓咨询师却将对话转移给了另一位曹姓咨询师。当黄枪再次追问“惠普是否和北大青鸟有定向委培计划”时，曹姓咨询师和廖姓咨询师一样含糊其词转移了话题，最后对黄枪置之不理。 &lt;/p&gt;

&lt;p&gt;黄枪查询发现，该中心宣称的IT名企艾尔卡特公司子虚乌有，而按照该中心列出的“委培名单”，黄枪与其中的微软、惠普等几家企业取得了联系，在听到黄枪的表述后，这些企业感到非常诧异，不假思索断然否定。“我们从来没有采用‘定向委培’方式招聘人才，更没有委托社会培训机构进行人才培养，因为公司招人有自己严格的程序和招聘方法，并有自己成熟的培养体系，培训机构培养出的学员不可能完全符合公司用人要求。”&lt;/p&gt;

&lt;h1&gt;与劳动部合作的“猫腻”&lt;/h1&gt;

&lt;p&gt;与此同时，为了“实现”推荐就业的承诺，北大青鸟不惜上演双簧闹剧。 &lt;/p&gt;

&lt;p&gt;一位四川学员曾参加过北大青鸟的培训，2007年初培训结束后，被推荐到一家网络公司，“感觉只是走过场，问了几个很简单的问题就没有下文了”。另一个同学虽然被录用（实习期每月800元），但实习期一过就被辞退，换了新人。“就是利用实习期的廉价劳动力。不少小公司和培训机构都有协议，每接收一个学员收取中心500～1000元赞助费，这就是所谓的合作。” &lt;/p&gt;

&lt;p&gt;对广大学员而言，北大青鸟与劳动部（现整合为人力资源和社会保障部）的“合作”无疑让证书含金量极高。按照北大青鸟西苑中心彭姓老师的说法，“毕业后会获得两个证书，一个是北大青鸟的高级职业技能证书（ACCP），一个是劳动部颁发的证书（OSTA），相当于国家中级技能资格水平”。 &lt;/p&gt;

&lt;p&gt;目前有据可查的是，2010年1月，人力资源和社会保障部职业技能鉴定中心与北大青鸟签署了《与北大青鸟合作认证项目服务》，开始对北大青鸟BTEST课程培训内容体系和管理体系的认证。 &lt;/p&gt;

&lt;p&gt;电话中，人力资源和社会保障部综合处严处长表示，“职业技能鉴定中心是人力资源和社会保障部直属机构，承担对全国职业培训机构的技术指导、课程研究和标准评定，对所有培训机构一视同仁。北大青鸟方面，主要是标准的审核，谈不上合作”。也就是说，劳动部并不存在与北大青鸟“合作培养人才”一说。 &lt;/p&gt;

&lt;p&gt;然而，在街头灯箱广告、网站、报纸等铺天盖地的广告宣传中，多家北大青鸟却重点描述着与劳动部的“合作”关系——劳动部专家视察、联合认证等等，如“北大青鸟ACCP软件工程师。国家劳动部+北京大学+印度APTECH”、“国家劳动部、北大青鸟联合打造软件白领”…… &lt;/p&gt;

&lt;p&gt;OSTA则是北大青鸟和劳动部“合作”的另一条纽带。官方资料介绍，OSTA是一个反映计算机操作水平的基础性职业资格证书。与全国计算机等级考试（NCRE）不同，OSTA更侧重于一些办公软件、系统应用的初级考核，作为一些部门招聘的基础条件。对此，多家软件公司HR经理私底下对黄枪表示，对准备进入IT圈成为软件工程师的培训学员而言，这种证书含金量极低。而ACCP，只是北大青鸟的企业认证书而已，并不具备权威性。 &lt;/p&gt;

&lt;p&gt;对劳动部和北大青鸟的“合作”，一位熟悉标准评定工作的内部人士称，每个培训机构推出自己的课程体系和标准都需要职业技能鉴定中心做出指导和审核，这就好比厂家的产品要送去质监局、工商局一样，“你能说这个是和工商局合作生产的罐头吗？笑话！”&lt;/p&gt;

&lt;h1&gt;“军事标准化”的北大青鸟&lt;/h1&gt;

&lt;p&gt;对学员“高中生、零基础”要求的北大青鸟而言，极少数能力出众的学员就业前景确实不错，但多数低学历的普通学员却困难重重：北大青鸟的ACCP认证多数企业似乎并不认账，一些企业甚至为了筛掉培训学员筑起了学历门槛。深圳系统集成开发公司的一位HR对黄枪表示，“培训学员没有项目经验不说，基础比较差，学习能力不行。再说现在本科生这么廉价，谁还用培训的？” &lt;/p&gt;

&lt;p&gt;“另外一个很重要的原因是，学员创造力不强，这对软件开发是致命的。”据该HR介绍，最近一两年内，深圳不少软件开发型企业都将招聘门槛提高至本科以上，“主要就是想过滤掉这些培训学员”。 &lt;/p&gt;

&lt;p&gt;说起招聘工程师的经历，一位HR一脸无奈。有一次他所在的公司欲招聘一名网络工程师，结果应征者同时来了4名。怎样判断这4名拿了认证的网络工程师谁更符合公司需要呢？他想了一个办法：把公司网络运行中出现的问题拿出来，谁能解决就要谁。结果，4名拿着网络工程师证书的应聘者全都无法解决。 &lt;/p&gt;

&lt;p&gt;黄枪调查发现，出现上述情况，与北大青鸟的标准化教育理念有关，北大青鸟CEO杨明曾公开表示，培养“软件蓝领”，不需要太多创造力，主要是听话、肯干。 &lt;/p&gt;

&lt;p&gt;一位曾在北大青鸟工作过的知情人士透露，北大青鸟有一套标准化的咨询师手册，上面详细记录了一个咨询师应该做的事情和怎么去做这些事情。比如如何接电话、如何说第一句话、如何回答学员的咨询等。如果你想问某些问题（比如学费），保证你得不到答案。 &lt;/p&gt;

&lt;p&gt;黄枪曾多次询问北大青鸟学费，然而，接受黄枪咨询的北大青鸟咨询师均无一例外地采用了“标准化”答案：“看你的计算机基础和你选择的课程来决定，建议留个联系方式，我请我们专业老师跟你详细分析和讲解课程内容。”由始至终，除了极力邀请黄枪去进行入学测试外，最多笼统表示学费为“几千到上万元不等”，对具体学费避而不谈。 &lt;/p&gt;

&lt;h1&gt;餐馆老板也可成北大青鸟“校长”&lt;/h1&gt;

&lt;p&gt;2009年9月5日，是北大青鸟安徽蚌埠睿智中心100多名学员的“黑色周末”。在没有任何征兆的情况下，学员们发现培训中心大门紧锁，张贴了一张告示，“北大青鸟蚌埠睿智中心现出现严重的经营困难，无法运转，所有学员转学事宜，请致电北大青鸟总部”。该中心2009年7月20日开始授课，每名学员缴纳了8000～10000元不等的学费，两个月不到，人去楼空。 &lt;/p&gt;

&lt;p&gt;“北大青鸟总部让我们和合肥的培训中心联系。我们已经在蚌埠交了学费，人家没钱赚，根本不接收我们”，一位朱姓学员表示，他们至今未得到解决方案。 &lt;/p&gt;

&lt;p&gt;各方推诿的背后，与北大青鸟加盟模式有关——蚌埠这家培训中心，在工商局注册的是“睿智电脑培训学校”，后加盟北大青鸟，更名为北大青鸟蚌埠睿智中心。 &lt;/p&gt;

&lt;p&gt;为了跟上快速扩张的步伐，北大青鸟采取了加盟代理的形式。据了解，北大青鸟总部并不授课，所有分校对外都称为中心，中心分为两种情况，北大青鸟总部投资的中心称为直属中心，其他人投资的称为加盟中心，加盟中心负责人则称为“校长”。 &lt;/p&gt;

&lt;p&gt;根据北大青鸟官方资料，目前北大青鸟在国内90多个城市有200多个特许加盟伙伴，开办培训机构240余家，2008年全体系收入21.4亿元，这也导致学员无法分清各式北大青鸟网站和宣传广告，甚至根本不知道总部不会授课。 &lt;/p&gt;

&lt;p&gt;“当初加盟费是30万元，后来涨到80万元。”一位从餐饮转行成为北大青鸟“校长”的人士透露， 加上其他硬件设备采购和前期装修等，总共投资了150万元，而现在随着房租等上涨，经营一家北大青鸟培训中心大概需要220万元。 &lt;/p&gt;

&lt;p&gt;北大青鸟总部官网资料显示，加盟北大青鸟项目资金为200万元，包括场地租金、项目相关教学设备的购置、特许经营加盟费等等。加盟最重要的条件，是对北大青鸟品牌的认可，这一点北大青鸟多次反复提及——值得注意的是，黄枪反复查阅其加盟资料，并未发现对加盟伙伴有教育或培训的资质要求。 &lt;/p&gt;

&lt;p&gt;北大青鸟品牌管理部给黄枪回复的邮件中明确说明，“加盟并不需要保证金，总部会定期公开检查和暗访调查”。也就是说，各加盟店与总部关系仅是授权“挂牌经营”而已，出了事情，总部并没有保证金用以赔付。 &lt;/p&gt;

&lt;p&gt;那么，一家IT培训机构到底是怎么经营并产生盈利的？一家培训中心的营业收入按年计算较为科学，因为学员课程一般10个月一周期。按每人1.5万～1.7万元计算，满24人开班，一年有15～20个的开班频次，总营业收入在540万～720万元间。 &lt;/p&gt;

&lt;p&gt;既然以盈利为主要目的，市场主体又各不相同，北大青鸟加盟培训中心上演了一出又一出的“拉生意”好戏，触角伸到社会各个角落。安徽涡阳中学的一位高中教师称，他曾接到北大青鸟某中心发来的招生协议书，明确规定了拉学员的奖励标准 ——“1～2人1000元/人，3～4人1200元/人，5人以上1500元/人”，“身边不少老师都拿这个当买卖做，自然也帮他们说了不少好话”。 &lt;/p&gt;

&lt;p&gt;培训体制内，“拉生意”的事情也屡见不鲜。南宁状元廊中心一位吕姓学员称，学生拉一个人进来培训有300元拿。“一个同学自己都觉得没学到东西，临走还拉了两个人进来”。“拉生意”并不是孤本，而是全国“通行”，且适当“照顾”了不同地区的经济水平差异——在北京北航中心，这一标准被提升至1000元/人。 &lt;/p&gt;

&lt;p&gt;加盟模式和广告宣传放在首位，也让各中心教员队伍质量难以得到保证。黄枪曾询问多家北大青鸟中心师资问题，这些中心只是笼统表示“总部派下来的人”。 &lt;/p&gt;

&lt;p&gt;按照北大青鸟的说法，北大青鸟总部将对各中心教员进行“标准化的统一培训”，但多位北大青鸟教员透露，教员素质参差不齐，计算机水平好的老师有，但太少，很多教员都是刚毕业的学生，号称有多少年的开发经验大多是忽悠，甚至缺乏能够作为相关学科老师的教学资本。也有一些教员是大学中出来走穴的老师，走穴教学毕竟是副业，不能够占据这些老师的主要精力，因此也会大打折扣。 &lt;/p&gt;

&lt;p&gt;教员也是在“标准化”模式下，按照他们开发出来的课本教材ACCP、BENET、BTEST按部就班地讲课就行了。一位不愿透露姓名的北大青鸟教员表示，对他们而言，唯一关心的是如何让学生尽可能多地拿到相关培训的证书，学生们拿到了证书，他们也就完成了任务。问题是，现在许多考试都是电脑自动出题，题库中问题大多固定，只是打乱顺序，因此让学生背题库就成为取得好成绩拿证书的法宝。&lt;/p&gt;

&lt;h1&gt;相关链接 &gt;&gt; 北大青鸟涉嫌非法宣传？&lt;/h1&gt;

&lt;p&gt;调查中，黄枪发现，北大青鸟往往喜欢自封为“最大、最强、最久”的办学机构。比如北大青鸟重庆南岸学府江田培训中心，在百度搜索上就自封为“北大青鸟——中国最大IT职业教育品牌。” &lt;/p&gt;

&lt;p&gt;工商局人士表示，《广告法》第二章第七条规定，广告不得使用国家级、最高级、最佳等用语，北大青鸟许多中心宣称的“最大品牌”以及“100％高薪就业”，都违反这一规定，涉嫌虚假宣传。 经营者如果毫无根据地自我标榜“最大品牌”，则其行为容易使消费者对其提供的商品质量或服务产生误解，在不适当地抬高自己的同时，客观上贬低了其他同业经营者的商品及服务。这样的行为不仅违反了广告法，同时构成了不正当竞争。 &lt;/p&gt;

&lt;p&gt;此外，《广告法》中同样也规定，在商业广告中，企业不得以任何形式利用国家机关及其工作人员名义做广告，无论上述机关、工作人员是否同意，否则将构成广告违法。所以，“国家人力资源和社会保障部、北大青鸟联手打造软件英才”一说，有违法之嫌。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/04/why-i-say-no-to-aptech.html#comments</comments>
      <pubDate>Wed, 21 Apr 2010 16:20:07 GMT</pubDate>
      <lastBuildDate>Wed, 21 Apr 2010 16:20:07 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/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/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/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/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>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <title>写程序时该追求什么，什么是次要的？</title>
      <link>http://blog.zhaojie.me/2009/05/1491692.html</link>
      <guid>http://blog.zhaojie.me/2009/05/1491692.html</guid>
      <description>&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;pre class="code"&gt;array[j] = array[i] + array[j];&lt;br&gt;array[i] = array[j] - array[i];&lt;br&gt;array[j] = array[j] - array[i];&lt;/pre&gt;
&lt;p&gt;他认为，这段代码节省了额外的空间，在内存紧张的情况下很有必要。但是老赵认为，这里的损失了可读性。对于一段标准的交换代码，每个人都知道它的目的，而正在读这篇文章的您，是否可以立即反应出上面三行代码的作用？ &lt;/p&gt;
&lt;p&gt;在编程领域有一个道理被广为传播：make clean code fast远比make fast code clean要容易，这里clean无疑是“清晰”的意思。因为代码清晰，我们可以找出其性能瓶颈，然后有针对性地加以优化。要知道把一个调用10000次的过程优化了20%，比调用10次的过程优化80%（假设两个过程原本消耗接近）要明显的多。 &lt;/p&gt;
&lt;p&gt;就拿那位朋友的观点，内存紧张时该怎么办。可能他的做法的确有所节省吧（不过高级语言中的“节省”，对于最终编译后的结果又是两码事）。不过在内存紧张的时候，首要做的应该还是设法探究最耗费资源的地方时什么，然后加以优化。因此，可能会对某个问题重新设计其数据结构，例如压缩数据存放方式，共享数据空间等等，而不是设法节省一个字长的内存。那么如何可以能方便瓶颈的发现呢？ &lt;/p&gt;
&lt;p&gt;清晰。&lt;/p&gt;
&lt;p&gt;当然，上面这段代码并非不可使用，只是如果您真要这么做，请把它封装为一个子方法： &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;Swap(&lt;span style="color: blue"&gt;int&lt;/span&gt;[] array, &lt;span style="color: blue"&gt;int &lt;/span&gt;i, &lt;span style="color: blue"&gt;int &lt;/span&gt;j)
{
    array[j] = array[i] + array[j];
    array[i] = array[j] - array[i];
    array[j] = array[j] - array[i];
} 
&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;一旦你把这段逻辑给分离了，在代码里只适用Swap方法了，那么程序也会一下子变得清晰起来。而且在这时候，这三行代码也变得容易理解了，别人也可以一眼看出它的作用——因为方法名已经说得很清楚了：交换。 &lt;/p&gt;
&lt;p&gt;所以，我们在写程序的时候，不如仔细想想，如何把变量名、方法名或参数名取得清楚一些，如何把程序的逻辑表现地清晰一些，如何把你的意图更好的告诉别人。 &lt;/p&gt;
&lt;p&gt;剩下的细节优化，什么内联子过程……就统统交给编译器去处理吧。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/05/1491692.html#comments</comments>
      <pubDate>Fri, 29 May 2009 07:14:00 GMT</pubDate>
      <lastBuildDate>Fri, 29 May 2009 07:14:00 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>
      <title>关于基础与能力，谈一点我的看法</title>
      <link>http://blog.zhaojie.me/2009/04/1443234.html</link>
      <guid>http://blog.zhaojie.me/2009/04/1443234.html</guid>
      <description>&lt;p&gt;时不时会有朋友写信问老赵学习上的一些迷茫，其中都有一些共性。例如说不知道该如何学习，说不知道朝哪个方向前进。也例如大家虽然基本上都知道“算法”的重要性，但是却总觉平时用不到。说它锻炼能力，但“能力”是看不见摸不着的，学着学着就会“麻木”，感觉就“学不进去”了。当然这方面有几个原因，有主观也有客观的，有需要周围环境的改变，也有需要自己精神上“强壮度”的提高。这里呢，我们有时就不提“算法”这个太具体的名词了，而使用“基础”来表示这一类“似乎重要，但不知道重要在哪里”的东西。&lt;/p&gt; &lt;p&gt;还是先从算法，数据结构这类大家从学校里首先都会学到的东西谈起吧。如果说平时用不到算法，那肯定是不可能的。什么是算法？解决问题的方法都是算法，程序中任何对象及其关系都是数据结果。当然您可能会说，这里的说的算法和数据结构是指“有名”的那种，例如大家都耳熟能详的快速排序，图、树等等。当然，说到这个份上，可能就是要分两条路走了。一，您的确只是一直在做普通的CRUD；二，您对于这些知识理解不够，而无法感受到对它们的使用，很多时候我们运用所学的东西是自然而然的——更直接地说出来可能不太中听：“为您掌握的不好，自然觉得没用”。&lt;/p&gt; &lt;p&gt;打个比方，基本上所有的系统都会有“分类系统”，一个大分类下面有多个子分类，子分类下还会有更多子分类。那么现在有了个需求：由于需要垂直地列在一个下拉框中供用户选择，而分类之间的关系使用缩进来表示。在这里分类结构其实就是一颗树，而这个任务其实就是对树的深度优先遍历，于是可能您对书本印象比较深刻的话，就会说用递归，用回溯法。但是不少朋友虽然会解决这问题，解决的方式也不错，可是却没有意识到自己在用什么算法或是数据结构——只是解决了一个问题而已。这其实也比较正常，如果您回忆一下可能就会想起来，学习算法往往都会是依靠“演变”来的，只要具备了一定了逻辑思考能力，算法和数据结构在“一定程度”上也是较为“自然”的东西，并非需要死记硬背。老赵认识个朋友，在做题的过程中把AVL树给彻底忘了——是彻底忘了有这个东西，但是他发现二叉树的退化之后，就自己设法通过旋转来保持平衡。当然这种演变是一种“能力”，我们稍后再详谈。&lt;/p&gt; &lt;p&gt;不过很多时候出现的情况往往都是“不知道”导致“不会做”，至少也是“做不好”。打个比方，在您的程序中会用到大量的容器，您知道System.Collections命名空间下的容器都是用什么数据结构实现，适合什么样的操作吗？如果要求您在图片上打印文字，并且按照固定长度换行，您会使用类似二分法的O(logN)算法，还是直接遍历的O(N)算法呢？再比如&lt;a href="http://blog.zhaojie.me/2009/03/expression-cache-1.html"&gt;把表达式树用作缓存&lt;/a&gt;，如果您不了解&lt;a href="http://blog.zhaojie.me/2009/03/expression-cache-3-prefix-tree-cache.html"&gt;前缀树&lt;/a&gt;，&lt;a href="http://blog.zhaojie.me/2009/03/expression-cache-4-binary-search-tree-cache.html"&gt;二叉搜索树&lt;/a&gt;，以及&lt;a href="http://blog.zhaojie.me/2009/03/expression-cache-5-hash-based-cache.html"&gt;哈希表的实现方式&lt;/a&gt;，可能就只能做出&lt;a href="http://blog.zhaojie.me/2009/03/expression-cache-2-simple-key-cache.html"&gt;字符串&lt;/a&gt;这个低效的选择了。您可能又会想到说，“平时项目真的遇不到”，那么老赵还是重复刚才的话“这个可以遇到”——只是您不知道有其他选择而已。&lt;/p&gt; &lt;p&gt;如果跳出所谓算法和数据结构，其实任何的基础对您工作的作用大都类似。按照老赵之前&lt;a href="http://blog.zhaojie.me/2007/10/how-to-learn.html"&gt;举过的例子&lt;/a&gt;，很多东西都是这样：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;了解Windows，才能写出更好的.NET应用程序，或者作postmortem调试。  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/01/system-architecture-and-program-performance.html"&gt;了解计算机体系结构&lt;/a&gt;，才能在多CPU，多核时代写出真正高效而又正确的应用程序。  &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;p&gt;我们假设人脑可以存放的总信息数量确定，在这种情况下，知识太多，能力便少，则获得新知识的成本增加；知识太少，能力虽多，却在解决问题时都需要“推理演变”一番，这也是一种浪费，就好比很少有人会用“公理”去证明一个命题，因为使用“定理”或“推论”效率可以更高。因此，把“知识”和“能力”进行分配是一种艺术，只有达到一种和谐的平衡，一个人才能更好更快地解决问题。&lt;/p&gt; &lt;p&gt;老赵很笨，没有学习的诀窍，唯“埋头苦学”，“勤于思考”把字箴言尔，对我来说无论是“知识”和“能力”都由此而来。有朋友可能会说，我平时不主动学习，等需要的时候再去了解。老赵不同意这个观点，因为这里有个悖论：如果您不自主学习，又如何可以在真正遇到问题的时候知道该使用什么东西呢？做出合适的选择是一个需要积累的过程，而如果不主动学习，很可能最终只会造成重复劳动。就像刚才提到那样，我们需要对大量事物进行了解，分析，沉淀。可能有时候学不进去也要学吧，可能发现美的那一刻，只是因为量变终于引起质变了。&lt;/p&gt; &lt;p&gt;如果您不知道学什么，把大学课本翻出来从头学习，您一定会有所收获的。最近我也在构思一个《老赵书托》系列，希望可以推荐一些好书，对大家有所帮助。&lt;/p&gt; &lt;hr&gt;  &lt;p&gt;其实引发老赵写下这篇文章的原因是一次（或者说是几次）面试。某培训机构总是打电话来想要“介绍”他们一些学生来公司面试，其语言诚恳让人不忍拒绝。可是一次又一次强调我们需要基础扎实的学生，但是每一次带来的让人很不满意。我在想，他们花了那么长时间读完大学，然后再花大笔大笔的钱去培训机构“进修”，那么多年下来还是如此水平，连我都不由得为他们心痛。当然这样的情况是普遍状况，与是否是某培训机构的学生无关，这是我进行数百次面试中所发现的共同点。例如刚才培训机构的学生，没有一个人能够把一个数组中所有元素反序一下，而一题简单的字符串分割就能考倒9成的面试者。这样的能力让人如何可以接受？理由更加荒唐，有的说“我是学测试的，不是做专业开发的”，“我是做应用的，不熟悉算法”——这种问题算是专业开发吗？算是算法吗？&lt;/p&gt; &lt;p&gt;真心希望现在正在阅读文章的您，就算可以不屑这篇文章，也请你停留片刻，思考一下，您的状况究竟如何呢？&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/04/1443234.html#comments</comments>
      <pubDate>Fri, 24 Apr 2009 16:14:00 GMT</pubDate>
      <lastBuildDate>Fri, 24 Apr 2009 16:14:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/news/">新闻信息</category>
      <category domain="http://blog.zhaojie.me/translation/">翻译引进</category>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <title>所有程序员都应该至少读上两遍的十篇论文</title>
      <link>http://blog.zhaojie.me/2009/03/1401259.html</link>
      <guid>http://blog.zhaojie.me/2009/03/1401259.html</guid>
      <description>&lt;p&gt;转载自刘江老师的博文《&lt;a href="http://blog.csdn.net/turingbook/archive/2009/03/01/3946421.aspx"&gt;所有程序员都应该至少读上两遍的十篇论文&lt;/a&gt;》。关于读论文的重要性我不多作解释，事实上我也解释不清，但是可以确定的是，论文让我感受到技术之美，是一件很惬意的事情。当然，我们不一定要读“前沿”的内容，但是一些经典的论文是不能错过的。&lt;/p&gt; &lt;hr&gt;  &lt;p&gt;今天（噢，应该是昨天了）图灵在北京搞了一次Ajax群英会，盛况空前。（会议实况下周整理一下，贴过来吧。）其间&lt;a href="http://www.turingbook.com/Books/ShowBook-332.aspx"&gt;《Erlang程序设计》&lt;/a&gt;的&lt;a href="http://erlang-china.org/"&gt;赵东炜&lt;/a&gt;说到读论文的重要性。我还附和说，其实许多名家在讲治学的时候都会讲到，要读自己领域里最经典的和最重要的论文。  &lt;p&gt;很巧，刚才从&lt;a href="http://www.reddit.com/r/programming/"&gt;Reddit&lt;/a&gt;上看到了题为“10 Papers Every Programmer Should Read (At Least Twice) ”的文章，打开&lt;a href="http://blog.objectmentor.com/articles/2009/02/26/10-papers-every-programmer-should-read-at-least-twice"&gt;链接&lt;/a&gt;一看，是我们&lt;a href="http://www.turingbook.com/Books/ShowBook-196.aspx"&gt;《修改代码的艺术》&lt;/a&gt;一书的作者Michael Feathers写的。他的那本书被称为&lt;a href="http://blog.csdn.net/turingbook/archive/2007/07/13/1688703.aspx"&gt;“近十年来最有影响的计算机图书”&lt;/a&gt;之一，可是在国内的关注并不太够，这是为什么呢？  &lt;p&gt;言归正传，看看是哪10篇论文入了Feathers大师的法眼吧：  &lt;ol&gt; &lt;li&gt;&lt;a href="http://sunnyday.mit.edu/16.355/parnas-criteria.html"&gt;On the criteria to be used in decomposing systems into modules&lt;/a&gt; – David Parnas  &lt;li&gt;&lt;a href="http://research.sun.com/techrep/1994/abstract-29.html"&gt;A Note On Distributed Computing&lt;/a&gt; – Jim Waldo, Geoff Wyant, Ann Wollrath, Sam Kendall  &lt;li&gt;&lt;a href="http://portal.acm.org/citation.cfm?id=365257"&gt;The Next 700 Programming Languages&lt;/a&gt; – P. J. Landin  &lt;li&gt;&lt;a href="http://portal.acm.org/citation.cfm?id=359579"&gt;Can Programming Be Liberated from the von Neumann Style?&lt;/a&gt; – John Backus  &lt;li&gt;&lt;a href="http://cm.bell-labs.com/who/ken/trust.html"&gt;Reflections on Trusting Trust&lt;/a&gt; – Ken Thompson  &lt;li&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.6083"&gt;Lisp: Good News, Bad News, How to Win Big&lt;/a&gt; – Richard Gabriel  &lt;li&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.29.363"&gt;An experimental evaluation of the assumption of independence in multiversion programming&lt;/a&gt; – John Knight and Nancy Leveson  &lt;li&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.7565"&gt;Arguments and Results&lt;/a&gt; – James Noble  &lt;li&gt;&lt;a href="http://c2.com/doc/oopsla89/paper.html"&gt;A Laboratory For Teaching Object-Oriented Thinking&lt;/a&gt; – Kent Beck, Ward Cunningham  &lt;li&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.31.562"&gt;Programming as an Experience: the inspiration for Self&lt;/a&gt; – David Ungar, Randall B. Smith &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;这里面文章的作者大牛如云啊，图灵奖得主、IEEE和ACM的Fellow。当然，还有Beck和Cunningham这样的实干家（没有听说过？面壁十天。XP、设计模式、重构、JUnit甚至Wiki都是他们搞出来的啊。）  &lt;p&gt;Feathers的文章里还有这些论文的摘要，等有时间我把它们都翻译出来。  &lt;p&gt;这里链接有的不能直接访问，因为它们都是学术杂志文章，不开放的。是不是因为这个，Reddit上最热的文章变成了&lt;a href="http://www.reddit.com/r/programming/comments/80zae/httpportalacmorg_should_be_free/"&gt;http://portal.acm.org Should be free&lt;/a&gt;呢？  &lt;p&gt;Feathers的文章显然成了这几天网上的热门话题，我们另外一本已经获得版权的书《SOA Patterns》（Manning，2009）的作者Arnon Rotem-Gal-Oz受他启发，写了&lt;a href="http://www.rgoarchitects.com/nblog/2009/02/27/10PapersEverySoftwareArchitectShouldReadAtLeastTwice.aspx"&gt;“所有架构师都应该至少读上两遍的十篇论文”&lt;/a&gt;：  &lt;p&gt;1. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fresearch.microsoft.com%2fen-us%2fum%2fpeople%2flamport%2fpubs%2fbyz.pdf"&gt;The Byzantine Generals Problem&lt;/a&gt; (1982) by Leslie Lamport, Robert Shostak and Marshall Pease&lt;br&gt;2. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fwww.u.arizona.edu%2f%257Erubinson%2fcopyright_violations%2fGo_To_Considered_Harmful.html"&gt;Go To statements considered harmfull&lt;/a&gt; (1968) - by Edsger W. Dijkstra &lt;br&gt;3.&lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fresearch.sun.com%2ftechrep%2f1994%2fabstract-29.html"&gt; A Note on Distributed Computing&lt;/a&gt; (1994) - by Samuel C. Kendall, Jim Waldo, Ann Wollrath and Geoff Wyant &lt;br&gt;4. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fwww.laputan.org%2fmud%2f"&gt;Big Ball of Mud&lt;/a&gt; (1999) - Brian Foote and Joseph Yoder &lt;a href="http://www.rgoarchitects.com/nblog/2007/11/28/BigBallOfMudAndOtherArchitecturalDisastersNot.aspx"&gt;&lt;br&gt;&lt;/a&gt;5. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fwww.lips.utexas.edu%2fee382c-15005%2fReadings%2fReadings1%2f05-Broo87.pdf"&gt;No Silver Bullet Essence and Accidents of Software Engineering&lt;/a&gt; (1987) - Frederick P. Brooks &lt;br&gt;6. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fwww.objectmentor.com%2fresources%2farticles%2focp.pdf"&gt;The Open Closed Principle&lt;/a&gt; (1996) - Robert C. Martin (Uncle Bob) &lt;br&gt;7. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fstandards.ieee.org%2freading%2fieee%2fstd_public%2fdescription%2fse%2f1471-2000_desc.html"&gt;IEEE1471-2000 A recommended practice for architectural description of software intensive systems&lt;/a&gt; (2000) &lt;br&gt;8. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fciteseerx.ist.psu.edu%2fviewdoc%2fsummary%3fdoi%3d10.1.1.33.411"&gt;Harvest, Yield, and Scalable Tolerant Systems&lt;/a&gt; (1999) Armando Fox, Eric A. Brewer &lt;br&gt;9. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fwww.cs.cmu.edu%2fafs%2fcs%2fproject%2fvit%2fftp%2fpdf%2fintro_softarch.pdf"&gt;An Introduction to Software Architecture&lt;/a&gt; (1993) - David Garlan and Mary Shaw &lt;br&gt;10. &lt;a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;amp;url=http%3a%2f%2fmartinfowler.com%2fieeeSoftware%2fwhoNeedsArchitect.pdf"&gt;Who Needs an Architect?&lt;/a&gt; (2003) Martin Fowler  &lt;p&gt;注意到了吗，其中的第3篇是Feathers也推荐的。  &lt;p&gt;更有意思的是，我们大家熟悉的Robert Martin大叔 [也是我们图灵的作者呵呵，&lt;a href="http://www.turingbook.com/Books/ShowBook-220.aspx"&gt;《敏捷软件开发》（C#版）&lt;/a&gt;，什么，你搞.NET的居然没有读过？面壁十天。] 也因此写了&lt;a href="http://blog.objectmentor.com/articles/category/uncle-bobs-blatherings"&gt;blog&lt;/a&gt;。原来有位叫David的同学在Feathers的blog下说了几句不靠谱的话，把一向脾气很好的Bob大叔也激怒了。David小子说：“你咋不直接给出PDF呢？要是这些文章真的重要，应该免费读到不是？瞧你那口气，牛X得不行，真让人不爽。得了您吧。” 说实话，这口气咋让我觉得像是咱同胞呢……瀑布汗啊。  &lt;p&gt;Bob大叔的回复发人深省。他说，你们知道这篇文章以及其中提到的论文有多重要吗？Feathers同学读了成百上千篇论文，然后向你介绍其中最好的10篇！&lt;strong&gt;人家把金砖放在你眼前，你却说太重了，我拿不动。&lt;/strong&gt;笨蛋啊，蠢材啊！  &lt;p&gt;他接着说：“我们是自食其力而且为自己的职业负责的技术人员呢，还是指望爹妈来擦屁股的小屁孩？是你，而不是别人，要为你自己的职业负责。你的老板可没有责任管这些。提升自己的职业水平不应该指望老板。你不能指望老板给你买书（如果他们真能这样当然好，但是这不是他们的义务）。老板不买，你自己买啊！老板没有责任教你学习新语言。如果他们能送你去培训当然好，但是如果他们不送，你要自己学啊！  &lt;p&gt;“我非常忧虑，我们的福利文化已经制造出一大批喜欢哭兮兮娘娘腔的程序员，他们居然认为必须为有版权的文章花钱是不公平的。（什么？还要我出钱？那是老板的事儿！那是我老师的事儿！那是Michael Feathers的事儿！他们要想我成为好的程序员，可别指望我出钱去读那些文章，也别指望我在Google里搜索文章，他们最好到我的办公室格子里来，哦，上午9点到10点吧，一边轻捋我的头发，一边把文章读给我听！）  &lt;p&gt;“请记住，这世界可不欠你的。老板也不欠你。Michael Feathers更不欠你。”  &lt;p&gt;（沉思十分钟……）&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/03/1401259.html#comments</comments>
      <pubDate>Mon, 02 Mar 2009 02:29:00 GMT</pubDate>
      <lastBuildDate>Mon, 02 Mar 2009 02:29:00 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>
      <title>程序员兄弟们，我们的基本素质怎么样？</title>
      <link>http://blog.zhaojie.me/2009/02/1392664.html</link>
      <guid>http://blog.zhaojie.me/2009/02/1392664.html</guid>
      <description>&lt;P&gt;我至今还憧憬着“程序员”是一个拥有较高技术含量的职业。在我的想象中，程序员反应敏捷，幽默风趣，热爱生活，身边优秀的朋友们无不如此。我热爱程序员这个职业。&lt;/P&gt;
&lt;P&gt;我的博客的副标题是“&lt;A href="http://blog.zhaojie.me/2007/02/657307.html"&gt;先做人，再做技术人员，最后做程序员&lt;/A&gt;”，这句话“脱胎”于&lt;A href="http://zh.wikipedia.org/wiki/%E5%82%85%E9%9B%B7"&gt;傅雷&lt;/A&gt;先生致傅聪的一句话：“第一做人，第二做艺术家，第三做音乐家，最后才是钢琴家”。我对此深信不疑，只有具备一个“人”的基本素质，才能成为技术人员，而最终才能成为一个合格的程序员。我之前一直认为，“人”的基本素质很容易达到，但是现在却有些疑惑了，可能是原本期望太高而造成如今的巨大心理落差吧。因为工作需要，我已经面试了不少程序员兄弟，而通过电话进行交流的更是为数众多，但是我发现太多的兄弟们还欠缺一定基本素质。&lt;/P&gt;
&lt;P&gt;我之前没有好好想过一个人的基本素质究竟应该是什么，只能在接触中觉得某个人“这里做的不错”或者“那里有所欠缺”。但是现在我仔细想了想，可能我们都需要扪心自问一下，我们需要具备哪些基本素质——是“人”的基本素质，可能具备这些基本素质之后，成为一个优秀的程序员只是时间问题吧。&lt;/P&gt;
&lt;P&gt;很不中听，兄弟们姑妄听之吧。&lt;/P&gt;
&lt;H1&gt;认真负责&lt;/H1&gt;
&lt;P&gt;我们需要对自己的行为负责，相信每个人都同意这一点。在工作上最常见的要求是，一旦要做什么事情就要做好，坚持到底，这就是所谓的认真负责。既然找到了一份工作，公司发工资，其实就是希望您在8个小时内能够认真负责地完成各种任务。上级的安排，同事的协商，如果一件事情没有做好影响的不仅仅是一个人，还会涉及到个人在别人心目中的形象。如果您想要发展，前提条件是要做好本职工作，然后还有“盈余”，才能期望在以后能够有所提升。有些朋友们有种“误区”，如果能够“糊弄”那么就“糊弄”，因为做得好做得坏其实差不多。有的朋友甚至想，“如今这个社会，认真负责已经没有用了，圆滑，溜须拍马比认真负责重要多了”。&lt;/P&gt;
&lt;P&gt;我不同意。现在的社会自然有不足的地方，但是基本上很公平，一个人的努力如果没有太大意外总是能够得到回报的——个例并不能代表什么。想想我们的上一辈，动荡的社会让他们的努力付诸东流——他们还没有抱怨太多，我们有什么资格抱怨这个那个？&lt;/P&gt;
&lt;H1&gt;坚持上进&lt;/H1&gt;
&lt;P&gt;我们原本都是上进的，我们都是击败了其他数以亿计的兄弟姐妹而诞生在这个世界上。所以我们要做的，只是保持住这个劲头。&lt;/P&gt;
&lt;P&gt;有些朋友会说，我很上进啊，但是这个社会是不公平的，我难有出头之日。这没有办法，既然是棵小草一坨大粪就能埋了，只要长成参天大树，那么大粪也就变成养料了。其实社会是很公平的，别人已经努力过了，你要超越它，要么使用时间，要么加倍努力。抱怨，止步不前没有任何作用。有朋友会想，“公司就给我了我8小时的钱，我为什么要做更多呢？”——不过如果站在公司的角度，“你只做了你该做的，为什么要提升你，而不提升做了更多的人呢？”这是一组矛盾，总有人要让步。在一个集体中，很少有某个个体不能被替换的情况。对于我们个人来说，如果身边都是可以代替自己的人，那么为什么要求公司做出让步呢？换句话说，如果公司主动做出让步，你如何保证一定能做出贡献呢？&lt;/P&gt;
&lt;P&gt;坚持上进，获益的肯定是自己，别人想抢都抢不走。当自己有了本钱，到哪里都做得好。&lt;/P&gt;
&lt;H1&gt;表达沟通&lt;/H1&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://www.wodeyichu.com/"&gt;我的衣橱&lt;/A&gt;网站目前已经有了大量的功能，而技术团队将要面临着优化，改进，提高单元测试覆盖率等众多有技术含量的事情。如果您想加入我们，和我们一起提高，请把简历&lt;A href="mailto:jeffz@live.com"&gt;发送给我&lt;/A&gt;吧（经济所限，我们只能招收最初级的程序员。工作地点在上海市长宁区）。&lt;/P&gt;
&lt;P&gt;一起来看看：&lt;A href="http://www.cnblogs.com/1-2-3/archive/2009/02/18/1393540.html"&gt;到底是员工没素质，还是公司没素质？&lt;/A&gt;&lt;BR&gt;再来看看：&lt;A href="http://www.cnblogs.com/JeffreyZhao/archive/2009/02/23/1396560.html"&gt;由衷感谢希赛网和CSDN采用老赵的文章&lt;/A&gt;&lt;/P&gt;</description>
      <comments>http://blog.zhaojie.me/2009/02/1392664.html#comments</comments>
      <pubDate>Tue, 17 Feb 2009 11:07:00 GMT</pubDate>
      <lastBuildDate>Tue, 17 Feb 2009 11:07:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/essential/">重中之重</category>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <title>计算机体系结构与程序性能</title>
      <link>http://blog.zhaojie.me/2009/01/system-architecture-and-program-performance.html</link>
      <guid>http://blog.zhaojie.me/2009/01/system-architecture-and-program-performance.html</guid>
      <description>&lt;p&gt;文章原来的题目是《计算机基础对.NET程序员是否重要》，再我看来，这是一句废话。&lt;/p&gt; &lt;p&gt;当然重要。可是好像有些朋友对于这点很疑惑。最近我又收到一封邮件，一个朋友问我说，他在大学里学的那些课程，似乎都无法对工作有所帮助——当然，这是他目前对于工作的观察，其中大部分是他通过博客园的“管中窥豹”得来的结果：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;好多讲ASP.NET的文章啊，控件真好用，做网站很方便。  &lt;li&gt;ORM好像对开发很有帮助，我们也来LINQ to SQL，NHibernate一下……网站不就是CRUD吗？  &lt;li&gt;JavaScript框架XXX的效果好炫，网站越来越漂亮了。  &lt;li&gt;好像进入并行处理时代了？呀，有了微软的并行库，加上AsParallel方法就能变快了。  &lt;li&gt;……&lt;/li&gt;&lt;/ul&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://blog.zhaojie.me/2007/10/how-to-learn.html"&gt;我们到底该怎么学技术？如何成为一个优秀的技术人员？&lt;/a&gt;》。老赵自己又看了一遍，发现有朋友对文章里的这么一句话有不同看法：“如果您不了解计算机体系结构，又如何能在Multi-CPU（Multi-Core）时代写出真正高效的应用程序呢？”。他认为这个“如果”（当然也包括文章里的其他“如果”）并不成立。所以老赵现在不谈“数据结构与算法如何有助于改善编程思维有什么改善”，或是“操作系统中线程调度、内存分页机制对于开发大型应用程序的参考价值”等“虚无缥缈”之物。在这篇文章里，我想通过两个直接的例子，来说明了解计算机体系结构对于提高程序性能有什么样的作用。&lt;/p&gt; &lt;h1&gt;Locality&lt;/h1&gt; &lt;p&gt;在描述何为Locality之前，我们先来看一个例子。例如，我们现在有一个二维数组：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color: blue"&gt;int &lt;/span&gt;n = 1 &amp;lt;&amp;lt; 10;
    &lt;span style="color: blue"&gt;int&lt;/span&gt;[,] array = &lt;span style="color: blue"&gt;new int&lt;/span&gt;[n, n];

    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;x = 0; x &amp;lt; n; x++)
    {
        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;y = 0; y &amp;lt; n; y++)
        {
            array[x, y] = x;
        }
    }

    ...
}
&lt;/pre&gt;
&lt;p&gt;我们要对这个1024 * 1024的二位数组中所有元素求和。那么我们会怎么写呢？先随手写一把：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static int &lt;/span&gt;SumA(&lt;span style="color: blue"&gt;int&lt;/span&gt;[,] array, &lt;span style="color: blue"&gt;int &lt;/span&gt;n)
{
    &lt;span style="color: blue"&gt;int &lt;/span&gt;sum = 0;
    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;y = 0; y &amp;lt; n; y++)
    {
        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;x = 0; x &amp;lt; n; x++)
        {
            sum += array[x, y];
        }
    }

    &lt;span style="color: blue"&gt;return &lt;/span&gt;sum;
}
&lt;/pre&gt;
&lt;p&gt;一个二重循环，遍历二维数组中每一个元素，相加，这也太容易了吧？是啊，不过我们还是可以“换种写法”的：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static int &lt;/span&gt;SumB(&lt;span style="color: blue"&gt;int&lt;/span&gt;[,] array, &lt;span style="color: blue"&gt;int &lt;/span&gt;n)
{
    &lt;span style="color: blue"&gt;int &lt;/span&gt;sum = 0;
    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;x = 0; x &amp;lt; n; x++)
    {
        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;y = 0; y &amp;lt; n; y++)
        {
            sum += array[x, y];
        }
    }

    &lt;span style="color: blue"&gt;return &lt;/span&gt;sum;
}
&lt;/pre&gt;
&lt;p&gt;仔细看看，有没有发现区别？没错，只是内层循环和外层循环的位置换了一下。这么做的意义何在？测试一下便知：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;TestLocality(&lt;span style="color: blue"&gt;int&lt;/span&gt;[,] array, &lt;span style="color: blue"&gt;int &lt;/span&gt;n)
{
    &lt;span style="color: #2b91af"&gt;Stopwatch &lt;/span&gt;watch1 = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Stopwatch&lt;/span&gt;();
    watch1.Start();
    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0; i &amp;lt; 100; i++) SumA(array, n);
    watch1.Stop();
    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"SumA: " &lt;/span&gt;+ watch1.Elapsed);

    &lt;span style="color: #2b91af"&gt;Stopwatch &lt;/span&gt;watch2 = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Stopwatch&lt;/span&gt;();
    watch2.Start();
    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0; i &amp;lt; 100; i++) SumB(array, n);
    watch2.Stop();
    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"SumB: " &lt;/span&gt;+ watch2.Elapsed);
}&lt;/pre&gt;
&lt;p&gt;我们把两种加法各执行100次，看看结果：&lt;/p&gt;&lt;pre class="code"&gt;SumA: 00:00:04.8116776
SumB: 00:00:00.8342202&lt;/pre&gt;
&lt;p&gt;第二种做法性能是第一种做法的将近5倍。这就是Locality的威力。&lt;/p&gt;
&lt;p&gt;Locality（局部性，不知道该不该这么翻译），通俗地说，就是通过利用“缓存”来提高程序运行效率。缓存是计算机中无所不在的概念，这里先借用《&lt;a href="http://www.amazon.com/Computer-Systems-Programmers-Randal-Bryant/dp/013034074X"&gt;Computer Systems: A Programmer's Perspective&lt;/a&gt;》（下文称为CSAPP）中的一幅图来简单说明一下：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/Learn-Computer-Architecture-For-Performance/1.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/Learn-Computer-Architecture-For-Performance/1.png" width="400"&gt;&lt;/a&gt;
&lt;p&gt;金字塔的每一层皆是“存储设备”，越靠近顶端则越速度越快，当然也越为昂贵。其中最快的当属寄存器，每个寄存器大小为一个字长（请问这是多大？），数量极其有限；L3则就是我们俗称的“内存”，大小……就取决于我们的荷包了；那么L1和L2是什么，大小又分别是多少呢？&lt;a href="http://en.wikipedia.org/wiki/L1-Cache"&gt;L1 Cache&lt;/a&gt;（又称Internal Cache），顾名思义它为CPU“内置”的缓存，速度次于寄存器，但还是远远高于内存。&lt;a href="http://en.wikipedia.org/wiki/L2_Cache"&gt;L2 Cache&lt;/a&gt;原本处于主板之上（因此又称External Cache），它比L1 Cache慢，速度也远高于内存，所以它做为CPU和Chips之间的缓冲——不过如今的CPU都已经“自带”L2 Cache，主板上自然就没有了。至于L1 Cache和L2 Cache的大小，您可以使用&lt;a href="http://www.cpuid.com/cpuz.php"&gt;CPU-Z&lt;/a&gt;看看您机器CPU中Cache的情况如何。这是老赵的工作机：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/Learn-Computer-Architecture-For-Performance/2.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/Learn-Computer-Architecture-For-Performance/2.png" width="400"&gt;&lt;/a&gt;
&lt;p&gt;老赵的机器是双核，各有一个L1 Cache，分为L1 D-Cache（数据缓存）和L1 I-Cache（指令缓存），各32KB大小；两个核共用一个3MB大小的L2 Cache。Cache越大，CPU性能越高，这点毋庸置疑。&lt;/p&gt;
&lt;p&gt;L1 Cache和L2 Cache的描述中都有“64-byte line size”字样，表示Cache的Line长为64字节。Line为Cache每次向下级存储设备读取数据的大小。例如，程序在运行时寄存器会向L1请求内存中某个地址的数据（可能是4字节），如果L1中没有这个地址的值，则会向L2中读取包含该地址的一整个Line的数据——也就是64字节，但是并不保证请求的4字节在这64字节的头部或尾部，CPU自有其对齐机制；如果L2没有这个地址的数据，则会向操作系统进行请求，同样是一个Line，64字节。&lt;/p&gt;
&lt;p&gt;这就是Locality的关键。在系统中，一个好的Locality表现为，在读取某个地址之后的某个再次读取这个地址或者其附近的地址。由于在读取某个地址的数据之后，缓存中同样保留着附近地址的数据，因此如果请求临近的数据则速度就会非常快（L1 Cache无比迅速）。如果Locality很差，那么就会发现L1 Cache的失效率（Miss Ratio），甚至L2 Cache的失效率都会很高。如果CPU所需要的大量数据都要到L2 Cache甚至更为低效的内存中去读取（试想可能该次内存读取还需要从硬盘交换页上获得），那么性能不变差才令人奇怪。&lt;/p&gt;
&lt;p&gt;说了不少“理论”，那么我们来看看上面的例子中为什么第一种方法会远远慢于第二种算法。我们的二维数组每个元素的下标(x, y)如下所示：&lt;/p&gt;
&lt;table style="margin-bottom: 10px; text-align: center" cellspacing="0" cellpadding="2" border="1"&gt;
&lt;tbody&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;0, 0&lt;/td&gt;
&lt;td style="width: 60px"&gt;0, 1&lt;/td&gt;
&lt;td style="width: 60px"&gt;0, 2&lt;/td&gt;
&lt;td style="width: 60px"&gt;…&lt;/td&gt;
&lt;td style="width: 60px"&gt;…&lt;/td&gt;
&lt;td style="width: 60px"&gt;0, 1021&lt;/td&gt;
&lt;td style="width: 60px"&gt;0, 1022&lt;/td&gt;
&lt;td style="width: 60px"&gt;0, 1023&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;1, 0&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;2, 0&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;…&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;…&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;1021, 0&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;1022, 0&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style="width: 60px"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="height: 60px"&gt;
&lt;td style="width: 60px"&gt;1023, 0&lt;/td&gt;
&lt;td style="width: 60px"&gt;1023, 1&lt;/td&gt;
&lt;td style="width: 60px"&gt;1023, 2&lt;/td&gt;
&lt;td style="width: 60px"&gt;…&lt;/td&gt;
&lt;td style="width: 60px"&gt;…&lt;/td&gt;
&lt;td style="width: 60px"&gt;1023, 1021&lt;/td&gt;
&lt;td style="width: 60px"&gt;1023, 1022&lt;/td&gt;
&lt;td style="width: 60px"&gt;1023, 1023&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;在内存中，每个元素的地址按照以下顺序次序排布：&lt;/p&gt;
&lt;p&gt;(0, 0), (0, 1), (0, 2), …, (0, 1022), (0, 1023), (1, 0), (1, 1), …, (1023, 0), (1023, 1), …, (1023, 1022), (1023, 1023)&lt;/p&gt;
&lt;p&gt;假如按照SumA方法中的读取顺序，L1 Cache中的状况可能就会是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读取(0, 0)位置数据 =&amp;gt; Cache Miss =&amp;gt; L1向L2获取(0, 0), (0, 1), …, (0, 14), (0, 15)共64B数据 =&amp;gt; 返回(0, 0)位置数据 
&lt;li&gt;读取(1, 0)位置数据 =&amp;gt; Cache Miss =&amp;gt; L1向L2获取(1, 0), (1, 1), …, (1, 14), (1, 15)共64B数据 =&amp;gt; 返回(1, 0)位置数据 
&lt;li&gt;…… 
&lt;li&gt;读取(1023, 0)位置数据 =&amp;gt; Cache Miss =&amp;gt; L1向L2获取(1023, 0), (1023, 1), …, (1023, 14), (1023, 15)共64B数据 =&amp;gt; 返回(1023, 0)位置数据 
&lt;li&gt;读取(0, 1)位置数据 =&amp;gt; Cache Miss（因为L1大小有限，读取(0, 0)时放入L1的64B数据已经被其他数据替换） =&amp;gt; L1向L2获取(0, 0), (0, 1), …, (0, 14), (0, 15)共64B数据 =&amp;gt; 返回(0, 1)位置数据 
&lt;li&gt;读取(1, 1)位置数据 =&amp;gt; Cache Miss（理由同上） =&amp;gt; L1向L2获取(1, 0), (1, 1), …, (1, 14), (1, 15)共64B数据 =&amp;gt; 返回(1, 1)位置数据 
&lt;li&gt;……&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;而按照在SumB方法中的读取顺序，L1 Cache中的状况可能就会是： &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读取(0, 0)位置数据 =&amp;gt; Cache Miss =&amp;gt; L1向L2获取(0, 0), (0, 1), …, (0, 14), (0, 15)共64B数据 =&amp;gt; 返回(0, 0)位置数据 
&lt;li&gt;读取(0, 1)位置数据 =&amp;gt; Cache Hit =&amp;gt; 直接返回(0, 1)位置数据 
&lt;li&gt;读取(0, 2)位置数据 =&amp;gt; Cache Hit =&amp;gt; 直接返回(0, 2)位置数据 
&lt;li&gt;…… 
&lt;li&gt;读取(1, 0)位置数据 =&amp;gt; Cache Miss =&amp;gt; L1向L2获取(1, 0), (1, 1), …, (1, 14), (1, 15)共64B数据 =&amp;gt; 返回(1, 0)位置数据 
&lt;li&gt;读取(1, 1)位置数据 =&amp;gt; Cache Hit =&amp;gt; 直接返回返回(1, 1)位置数据 
&lt;li&gt;……&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;两种做法立分高下。&lt;/p&gt;
&lt;p&gt;其实Locality这一特性在很多系统或应用中都有体现，例如磁盘文件的顺序读取就远比随机读取要快。再举个“时髦”点的东西，Google的Map Reduce论文中就使用了一节来提到Locality——调度器往往选择GFS中文件所在的机器作为Map Worker，这样可以通过读取本地文件尽可能减少数据在网络中的传输，从而大大提高效率。&lt;/p&gt;
&lt;h1&gt;False Sharing&lt;/h1&gt;
&lt;p&gt;尽可能读取接近的数据可以通过加强Locality来提高效率，但是在目前的多核甚至多CPU的环境下，操作两个“位置接近”数据可能反而会坏事。&lt;/p&gt;
&lt;p&gt;再看一个例子。运行刚才的程序时您应该会发现CPU只用了50%左右，这是因为我们单线程的程序只能在一个核上运行。现在已经进入了并行时代，我们的程序也要与时俱进。微软推出了并行库让并行操作变得异常容易，那么我们就利用并行库来进行刚才二维数组所有元素求和。如下：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static int &lt;/span&gt;ParallelSumA(&lt;span style="color: blue"&gt;int&lt;/span&gt;[,] array, &lt;span style="color: blue"&gt;int &lt;/span&gt;n)
{
    &lt;span style="color: blue"&gt;int &lt;/span&gt;processorCount = &lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.ProcessorCount;
    &lt;span style="color: blue"&gt;int&lt;/span&gt;[] result = &lt;span style="color: blue"&gt;new int&lt;/span&gt;[processorCount];

    &lt;span style="color: #2b91af"&gt;Parallel&lt;/span&gt;.For(0, processorCount, (part) =&amp;gt;
    {
        &lt;span style="color: blue"&gt;int &lt;/span&gt;minInclusive = part * n / processorCount;
        &lt;span style="color: blue"&gt;int &lt;/span&gt;maxExclusive = minInclusive + n / processorCount;

        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;x = minInclusive; x &amp;lt; maxExclusive; x++)
        {
            &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;y = 0; y &amp;lt; n; y++)
            {
                result[part] += array[x, y];
            }
        }
    });

    &lt;span style="color: blue"&gt;int &lt;/span&gt;sum = 0;
    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0; i &amp;lt; result.Length; i++)
    {
        sum += result[i];
    }

    &lt;span style="color: blue"&gt;return &lt;/span&gt;sum;
}
&lt;/pre&gt;
&lt;p&gt;我们首先获取系统中的处理器数目（processorCount），然后根据这个数据对二维数组进行分块，每个线程负责其中一块的计算，并将其保存到一个中间值中（result数组），最后再把所有的中间值累加即可。这种做法是并行计算中常用的模式，有了并行库的帮助，代码可以变得非常简单，直观。不过还是要用数据说话，还是100次求和运算，消耗时间为：&lt;/p&gt;&lt;pre class="code"&gt;00:00:01.8105218&lt;/pre&gt;
&lt;p&gt;怎么所花时间反而比单线程要增加了！这固然有线程调度的开销在里面，但是问题的关键还是程序的写法有问题，这种写法发生了&lt;a href="http://en.wikipedia.org/wiki/False_sharing" title="False Sharing"&gt;False Sharing&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;False Sharing（错误共享）意为错误地共享了本不该共享的数据。由于每个核的L1缓存互相独立，因此CPU必须有一种机制，能够确保一个核在向它的L1 Cache中写入一个值之后，其他核内L1 Cache中包含这个数据的整个Line就会过期。这意味着其他核在读取地址相同，或者是接近的数据时会遇到L1 Cache Miss。CPU的这种同步机制就是&lt;a href="http://en.wikipedia.org/wiki/MESI"&gt;MESI协议&lt;/a&gt;。那么我们来分析一下上面的代码到底如何造成了False Sharing。&lt;/p&gt;
&lt;p&gt;上面的并行代码会将二维数组分割为独立的几块数据，并且将每一块数据之和存入result数组中。result数组很小，每次都会被完整地读入每个核的L1 Cache内，修改其中任何一个元素都会导致所有核内的result数据过期。于是，两个核在计算时可能就会发生如下情况（以下用CL0和CL1来代表两个核的L1缓存）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CL0读取result[0]的值 =&amp;gt; Cache Miss =&amp;gt; result数组被加载到CL0中 =&amp;gt; 修改CL0中result[0] 
&lt;li&gt;CL1读取result[1]的值 =&amp;gt; Cache Miss =&amp;gt; result数组被加载到CL1中 =&amp;gt; 修改CL1中result[1] 
&lt;li&gt;CL0读取result[0]的值 =&amp;gt; 由于刚才CL1修改了result[1]，导致整条Line失效，于是Cache Miss =&amp;gt; result数组被加载到CL0中 =&amp;gt; 修改CL0中result[0] 
&lt;li&gt;CL1读取result[1]的值 =&amp;gt; 由于刚才CL0修改了result[0]，导致整条Line失效，于是Cache Miss =&amp;gt; result数组被加载到CL1中 =&amp;gt; 修改CL0中result[1] 
&lt;li&gt;……&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;从此，两个核结下了不解之缘，他俩将会纠缠大部分时间，直到整个任务结束。当然，在上面的问题中，消除False Sharing非常容易：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static int &lt;/span&gt;ParallelSumB(&lt;span style="color: blue"&gt;int&lt;/span&gt;[,] array, &lt;span style="color: blue"&gt;int &lt;/span&gt;n)
{
    &lt;span style="color: blue"&gt;int &lt;/span&gt;processorCount = &lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.ProcessorCount;
    &lt;span style="color: blue"&gt;int&lt;/span&gt;[] result = &lt;span style="color: blue"&gt;new int&lt;/span&gt;[processorCount];

    &lt;span style="color: #2b91af"&gt;Parallel&lt;/span&gt;.For(0, processorCount, (part) =&amp;gt;
    {
        &lt;span style="color: blue"&gt;int &lt;/span&gt;partSum = 0;
        &lt;span style="color: blue"&gt;int &lt;/span&gt;minInclusive = part * n / processorCount;
        &lt;span style="color: blue"&gt;int &lt;/span&gt;maxExclusive = minInclusive + n / processorCount;

        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;x = minInclusive; x &amp;lt; maxExclusive; x++)
        {
            &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;y = 0; y &amp;lt; n; y++)
            {
                partSum += array[x, y];
            }
        }

        result[part] = partSum;
    });

    &lt;span style="color: blue"&gt;int &lt;/span&gt;sum = 0;
    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0; i &amp;lt; result.Length; i++)
    {
        sum += result[i];
    }

    &lt;span style="color: blue"&gt;return &lt;/span&gt;sum;
&lt;/pre&gt;
&lt;p&gt;与ParallelSumA方法的实现不同，ParallelSumB使用了一个临时变量partSum来保存每次元素相加后的结果，在最后才将partSum，也就是某一块数据计算后的最终结果写入result数组。由于partSum位于不同线程的堆栈上，因此不同线程的partSum变量的地址分布很广，很难被同时读入同一个核的L1 Cache中，自然也不会造成False Sharing。ParallelSumB方法的性能就会较为令人满意，它执行100次所花时间为：&lt;/p&gt;&lt;pre class="code"&gt;00:00:00.5366263&lt;/pre&gt;
&lt;p&gt;上面的例子说明了一点：即使从代码角度来看没有共享任何数据，False Sharing还是可能发生。这迫使我们开发人员在平时工作中需要多留个心眼，偶尔也要考虑一下不同线程频繁修改的数据地址是否非常接近。这需要开发人员对一些“黑盒”内的状况进行适当探索。例如：在.NET程序中，由于托管堆内分配空间的连续性，几乎同时分配的对象地址会比较接近。而且，由于垃圾收集机制在回收时会进行“挤压”，因此生存时间久的对象的地址会愈发接近。可见，即使有了并行库，并行开发依旧不是那么容易。&lt;/p&gt;
&lt;p&gt;回到这片文章的主题。不知道经过这两个示例，朋友们是否更进一步了解到计算机体系结构是如何对开发高性能应用程序，尤其是并行环境下的应用程序产生影响的。类似的事例还有很多，也欢迎您谈谈自己的感想。&lt;/p&gt;
&lt;h1&gt;广告时间&lt;/h1&gt;
&lt;p&gt;老赵还是要强调计算机基础课程的重要性，也因此在这里推广一个课程。这们课叫做ICS，全称叫做Introduction to Computer System，是老赵就读的复旦大学软件学院大二学生的必修课，由软件学院院长臧斌宇教授主讲。使用的教材便是之前提到的CSAPP。更为关键的是，这门课现在已经成为复旦大学的精品课程，其课件、作业、解答、甚至某些课程的录像也都会在网上公开。大家可以在&lt;a title="http://ics.fudan.edu.cn/" href="http://ics.fudan.edu.cn/"&gt;http://ics.fudan.edu.cn/&lt;/a&gt;上访问该课程。&lt;/p&gt;
&lt;p&gt;臧教授是老赵十分佩服的一位德才兼备的教授，还非常年轻。他的实验室在系统、编译、网格计算等方面成绩斐然，严谨的科研氛围也一直让我向往。老赵由他带出来的师兄师姐师弟师妹非常之牛，往往去国内其他科研机构发展的硕士生都会给那里的博士生带来很大压力。他们发布在顶级期刊上的论文不在少数（例如这次在OSDI08里就有他们的科研结果），也经常有人被美国名校录取。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/01/system-architecture-and-program-performance.html#comments</comments>
      <pubDate>Thu, 22 Jan 2009 00:28:00 GMT</pubDate>
      <lastBuildDate>Thu, 22 Jan 2009 00:28:00 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>
      <title>和谐社区，和谐技术：微软的宠儿们，为什么富人的孩子就不能早当家？</title>
      <link>http://blog.zhaojie.me/2008/12/i-cannot-bear-any-more.html</link>
      <guid>http://blog.zhaojie.me/2008/12/i-cannot-bear-any-more.html</guid>
      <description>&lt;fieldset style="margin:10px;padding:5px;"&gt;
&lt;legend&gt;声明&lt;/legend&gt;
&lt;p&gt;我在想是不是哪里写的不对。&lt;/p&gt;&lt;p&gt;老赵是从文章和讨论来看技术氛围，没有关心什么文章该上首页的问题。某些朋友也不用纠结与老赵是不是有资格评论首页文章了。&lt;/p&gt;&lt;p&gt;其他问题，讨论无妨。&lt;/p&gt;
&lt;/fieldset&gt;
&lt;p&gt;我爱微软。从刚接触计算机开始我就是沉浸在微软的技术中，DOS下开发，VB5/6，Delphi直到现在的.NET，微软让我的技术生涯充满了乐趣。我爱博客园。我是从博客园成长起来的，博客园给了我多于真实能力虚名，让我突然就变成了“赵老师”，“XXX专家”。博客园给了我很多机会，让我的工作路途变得更为通畅。&lt;/p&gt; &lt;p&gt;但是，现在却很有唱衰的欲望。&lt;/p&gt; &lt;p&gt;进入博客园这个最有影响力的.NET社区也有两年多的时间了，期间经历了微软开发技术的快速发展时期，同时也看到博客园中一批又一批朋友的到来和离去。不得不说博客园变化很大，让我感触很多，而最终让我有强烈欲望不吐不快是因为今天看到的&lt;a href="http://www.cnblogs.com/star65225692/archive/2008/12/10/1352034.html"&gt;这篇文章&lt;/a&gt;。微软发布了&lt;a href="http://www.microsoft.com/web/channel/products/WebPlatformInstaller.aspx"&gt;Web Platform Installer&lt;/a&gt;以及&lt;a href="http://www.microsoft.com/web/channel/products/WebApplicationInstaller.aspx"&gt;Web Application Installer&lt;/a&gt;两个产品，这下好，Web开发环境不用自己安装了，一键完成；常见的几个Web应用程序无需配置了，一键完成！&lt;/p&gt; &lt;p&gt;这算什么？所以我敬佩微软，更敬佩他们的产品设计人员，真是“有微软的日子里，（工作）量再多的日子也不怕”，什么东西都能做的如此“贴心，舒心，放心”，即使是面向软件开发人员。二十一世纪什么最贵？人才！人才的立身之本是专业，但是我丝毫无法想象，一个无法独立安装开发环境，一个无法根据文档配置出一个可以运行的应用程序的“开发人员”何以称为“专业”。每次想到类似的问题我都无法说服自己，这些难道不是基础中的基础吗？鄙人不才，见过能力参差不齐的开发人员也不在少数，发觉这样的人实在占了相当比例。&lt;/p&gt; &lt;p&gt;造成这一切的原因是什么？微软！是因为微软产出了如此易于使用的框架，易于使用的工具，易于使用的开发平台安装程序和应用程序安装程序。有了微软，我们何必要了解那么多？&lt;/p&gt; &lt;p&gt;很明显我在搞笑。富人家的孩子不成材怎能怪环境过于优越。微软能让开发人员“拖拖放放”地生产出一个“Web应用程序”那是它的能力，这有利于技术的推广；君不见微软最擅长在它的新品发布会中使用最简单操作来得到一个令人眩目的成果。微软给了富足的环境，但是并没有对我们做出限制，开发人员的不争气只能怪罪于自身的惰性。于是乎，许多人读完了大学和北大青鸟还不会写一个简单的方法，更别说配置IIS和和web.config文件的基本配置。我也收到很多问题在问XXX框架的文档在哪里，难道上股沟网搜索一下“XXX文档”或“XXX Documentation”就那么困难吗？&lt;/p&gt; &lt;p&gt;朋友们，思考一下吧！微软只是说“让专业人士专注于业务实现”，不是让我们“不好好学习技术”。&lt;/p&gt; &lt;p&gt;这种氛围必然也影响到社区的发展。就拿博客园来说，现在愈发充斥着浮躁之风，而脚踏实地的实践性研究型文字却少有人问津——没人写亦没人理。我始终觉得博客园技术之风的鼎盛时期是当年&lt;a href="http://www.cnblogs.com/zhenyulu"&gt;吕老师&lt;/a&gt;等人的模式讨论。而现在博客园首页充斥着各种“XXX介绍”，“XXX尝鲜”，或将官方文档进行简单的翻译重组，或充斥着对微软技术的溢美之词（当然可能的确没有错，其实我也这么相信）。这让我们成为了典型的和谐社区，我很少看到有人唱“反调”——合理的，讨论性质的，而不是CSDN中的嘲讽和骂街——是啊，没有讨论何来反调。文章后的回复基本上都是“谢谢”，“学习了”，的确我也很感激各位对我文章的评价，但是其实我更想有朋友能够指出一些改进意见或延伸话题。&lt;/p&gt; &lt;p&gt;真的，真的，真的……兄弟们别对我太客气了。&lt;/p&gt; &lt;p&gt;由于对待技术的浅薄，博客园里的许多技术人员往往都有一种无法掩饰的“自卑”，具体表现为看到一点IL、C++代码甚至几句命令行就会认为是牛人牛文，而遇到谈一些Linux，嵌入式，或者操作系统驱动程序文件系统等等更是佩服得五体投地。这本来都是在不同抽象层次上工作，何必分个高低贵贱。要说起来，在学校的时候没有用过Linux？没有写过操作系统？上玩这些必修课我们就都是牛人了？哪有那么简单。真正的牛人牛文是能够用朴实的文字把问题谈出有价值的东西，而不是用一些表面内容唬人。看似简单，却值得细品，这才是境界。例如股沟那著名的MapReduce论文，有太多难以理解的地方吗？但就是少有人能写出来，少有人能做好。因为自己缺乏资本，也就无法正确面对“纸老虎”，偶尔遇到一些“砸厂子”情况也无法进行合理还击，最终往往以骂人收场。&lt;/p&gt; &lt;p&gt;不是微软技术不行，无论是理论实践还是真实案例都是大把大把的，但是微软在技术方面受其他领域歧视（尤其是在国内）还是有很明显原因的，谁让我们吵架比不上别人呢？&lt;/p&gt; &lt;p&gt;可能是大环境如此吧，我一直很羡慕Amazon的许多书籍评论为何能写得如此具体和令人信服（无论是褒贬），而国内大都是spam、托、亦或是骂街等一句话评论。微软的一贯做法充分利用了长尾效应而取得了成功，而我们为什么不好好构建起一个真正优秀的社区呢？&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;PS：我终于忍不住写了这篇文章，虽然不像老赵一贯的“沉稳”作风，不是字字推敲，但的确也是字字肺腑。其实以前也写过类似的内容，例如《&lt;a href="http://blog.zhaojie.me/2007/10/how-to-learn.html"&gt;我们到底该怎么学技术？如何成为一个优秀的技术人员？&lt;/a&gt;》和《&lt;a href="http://blog.zhaojie.me/2007/12/986062.html"&gt;有些话不知道怎么说才好&lt;/a&gt;》，只是并没有这次那么激动吧。&lt;/p&gt;&lt;div class="blog_topic"&gt;所属话题：&lt;a href="http://www.cnblogs.com/topic/27/" target="_blank"&gt;关于社区建设的讨论&lt;/a&gt;&lt;/div&gt;</description>
      <comments>http://blog.zhaojie.me/2008/12/i-cannot-bear-any-more.html#comments</comments>
      <pubDate>Thu, 11 Dec 2008 00:57:00 GMT</pubDate>
      <lastBuildDate>Thu, 11 Dec 2008 00:57:00 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>
      <title>我们到底该怎么学技术？如何成为一个优秀的技术人员？</title>
      <link>http://blog.zhaojie.me/2007/10/how-to-learn.html</link>
      <guid>http://blog.zhaojie.me/2007/10/how-to-learn.html</guid>
      <description>&lt;P&gt;看了&lt;A href="http://www.cnblogs.com/lovecherry/archive/2007/10/28/940555.html" target=_blank&gt;不要迷失在技术的海洋中&lt;/A&gt;，深表同意。在后来的评论中大家也表达了自己的看法。让我觉得很有意思的是，大家的观点惊人地一致——几乎没有反对的声音。&lt;/P&gt;
&lt;P&gt;不过从经验上来看，意见太统一也不一定是一件好事。我有时也会小人之心地想，表示赞同的朋友们是真与&lt;A href="http://www.cnblogs.com/lovecherry/" target=_blank&gt;LoveCherry&lt;/A&gt;的想法一致，还是仅仅因为自己以前对待技术随波逐流不堪所累，现在把这篇文章作为救命稻草看待，追求自身的心理平衡呢？LoveCherry写这篇文章，是基于他对于技术和思想的深度。如果我们没有达到这样的程度，是否会误解他的意思，得到的仅仅是一种心理安慰，却失去了更多东西呢？&lt;/P&gt;
&lt;P&gt;我们到底该如何学习技术？或者说，如何成为一个优秀的技术人员？&lt;/P&gt;
&lt;H1&gt;扎实的基础&lt;/H1&gt;
&lt;P&gt;如果要成为一个优秀的技术人员——我并没有说是“开发人员”，比如也包括“测试人员”吧——一定需要扎实的基础。什么叫做扎实的基础呢？其实就是我们大学所学的课程——离散数学、算法与数据结构、操作系统、计算机体系结构、网络、编译原理等等。现在它们经常被视为“没有用”，但是我认为这些都是一个优秀技术人员成长和前进的基础。不知道大家有没有过这样的感觉：某天早上一醒来，发现对于最近接触的事物有了新一层的认识，似乎什么都不会了，却好像什么都理解了——就像张无忌练太极剑，不求剑招，只求剑意。我曾经有过两次这样的感觉，真可谓豁然开朗。其实我想，这就是所谓的“突破瓶颈”。而引起“量变到质变”的关键，可能就是您忽视的那些课程，那些一进大学就被“灌输”的知识。&lt;/P&gt;
&lt;P&gt;在面试时我经常听到这样的话：“我的理论和基础不行，但是我让我写代码是没有问题的。”这样看来，基础真的没有用吗？我并不这样认为，因为……&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;如果您不了算法和数据结构，又如何从.NET Framework（甚至包括&lt;A href="http://www.wintellect.com/PowerCollections.aspx" target=_blank&gt;Power Collections&lt;/A&gt;，在这里我强烈推荐这个组件）琳琅满目的数据结构中做出最适合目前需求的选择呢？ 
&lt;LI&gt;如果您不了解操作系统，又如何能深入Windows系统，写好.NET Framework程序，或者在postmortem环境中做调试呢？ 
&lt;LI&gt;如果您不了解计算机体系结构，又如何能在Multi-CPU（Multi-Core）时代写出真正高效的应用程序呢？ 
&lt;LI&gt;如果……&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;因为我们不光要写代码，而且要写好的代码，因此我们必须强调基础。很多时候技术人员之间能力的高低，很可能就会取决于这写基础。有朋友告诉我，这些计算机科学的基础的意义不仅仅在于知识本身，它们还能够让人的思维更符合计算机科学的发展和变革——这可能说的有点远大，但是我基本上同意这个看法。如果说得简单一些，它们让您的思维方式更适合这个行业——试想，如果您知道了计算机/程序/框架/系统是怎么想的，他们还能够为难你吗？&lt;/P&gt;
&lt;P&gt;举一个例子，微软有着大量高素质的技术人员，他们是微软惊人生产力的源泉。因此微软能够在Vista和Office开发完成之后将大量牛人派去作Windows Live产品研发。在我们很多技术人员看来，Vista是操作系统，Windows Live是Web，两者大相径庭。但是微软就是能够有大量的技术人员作此类迁移。再举一个例子，当年Google挖角Microsoft许多技术人员，难道他们跳槽去Google继续作微软产品的研发吗？正是因为那些技术人员有着扎实的基础能力，因此就能够在各种类型的技术之间游刃有余，即使它们“表面”上看来差距有多大。&lt;/P&gt;
&lt;P&gt;表面？这两个字放在这里是什么意思？因为这就是我想说的就是……&lt;/P&gt;
&lt;H1&gt;技术之间的关系&lt;/H1&gt;
&lt;P&gt;其实《不》一文的中心思想，就是不要随波逐流，不要迷失在技术的汪洋之中。我很同意，但是我也想补充一点我的看法。&lt;/P&gt;
&lt;P&gt;在《不》文的评论中，我看到了一段话，其主要意思就是：“如果一个技术不会用到，就不要去学它。当要用的时候再去学”。首先表明我的观点：我不同意。这里我想举一个例子：&lt;/P&gt;
&lt;P&gt;我是今年1月份加入目前的公司的，公司的技术团队当时使用.NET Framework 1.1进行应用开发。是时由于业务的原因需要开发一个平台以及其他一些应用，我在时在技术部门内部强烈建议将新系统使用.NET Framework 2.0 + 3.0的方式进行构建。我的理由是：“使用.NET Framework 2.0构建新平台在基础设施上不会增加任何成本，但是在功能和性能上都会有提高。而.NET Framework 3.0，尤其是WCF，是微软提供的新组件，也即将成为微软平台上通信的标准。”领导同意了我的建议，并希望我带领新的团队进行新平台的开发。过程中的细节就不一一道来了，现在回头看来过程虽有波折，但是倒也收到了较好的效果。我们经常会发现有技术人员会抱怨技术发展地太快，但是就拿我之前的例子来说，在2007年还在使用2001年出现的东西，却忽视2004年就已经成熟的技术，这究竟是技术发展的太快，还是我们没有根本没有去跟进技术呢？&lt;/P&gt;
&lt;P&gt;我想答案很明显是后者，这其实就是“如果一个技术不会用到，就不要去学它。当要用的时候再去学”。我们不会（或者很难）因为不断钻研老技术而领会新技术，掌握新技术是需要我们主动去追求的。如果一个人不追求，他就难以发展。如果人人不追求，那么整个技术团队就难以发展。不过我认为，其实只要怀着“把项目做的更好”的想法，追求新的技术和实践（例如重构、TDD）是自然而然的事情。&lt;/P&gt;
&lt;P&gt;不论您是普通开发人员、技术经理抑或是架构师，我想您都不能止步不前。有人说，领导不愿意使用新技术，我们没有办法——那么设法说服他们。如果他们不能给出让您满意的理由，如果您觉得他们妨碍了您的发展，那么可以选择离开。我想有追求的您一定不会在找工作的问题上遇到太多麻烦。:)&lt;/P&gt;
&lt;P&gt;似乎话题有些偏了，我们回到正体。新技术那么多，我们到底该怎么学呢？我这里想说的就是，新技术并非洪水猛兽。在一定程度上，我们完全可以驾驭它们。&lt;/P&gt;
&lt;P&gt;我们来想一下，新技术是怎么来的？新技术并不是某些公司的牛人们拍脑袋出来的，新技术也是发展过来的。发展需要时间，发展是一个过程。例如C# 3.0由2.0发展而来，CLR 2由CLR 1发展而来。根据我的经验，如果一个技术人员能够较好地掌握.NET Framework 1.1，他几乎能够轻而易举地过渡到.NET Framework 2.0。他之需要了解一下新特性，找一些资料比较一下前后两者的改变即可。我们并没有创造技术，我们只是在跟进。为什么总有人能够在技术出现不久就写出大量文章或书籍来进行推广呢？这就是值得我们思考的地方。&lt;/P&gt;
&lt;P&gt;举个例子，如果要从.NET 2.0升级到3.5（我不懂VB，用VB的朋友抱歉了），其实您只需要了解……&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;ListView控件：一个控件而已。 
&lt;LI&gt;集成了ASP.NET AJAX：不是新东西了。 
&lt;LI&gt;Linq To XML：一套新的语法用于解析和构建XML。 
&lt;LI&gt;Linq To Object：枚举，只是枚举。 
&lt;LI&gt;Linq To Sql：可以视作简单的一套ORM，动态生成SQL语句。 
&lt;LI&gt;Lambda Expression：即使没有接触过LISP（很幸运，我大学课程中有Functional Programming这门课:)），我想如果您了解编译原理的话，对此也应该不陌生了。 
&lt;LI&gt;……&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;真的不多。其实我觉得，跟进每个人各自领域的技术并非不可能的事情。我一再提到这么一句话：一个优秀的技术人员，他的知识架构应该成倒T字形，有着扎实的底盘，并且成为某个领域的专家。&lt;/P&gt;
&lt;H1&gt;我们究竟该如何学习基础呢？&lt;/H1&gt;
&lt;P&gt;扎实。我认为，这是关键。&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;您有扎实的基础吗？这是成为优秀技术人员知识储备。 
&lt;LI&gt;您对于每项掌握的知识或技能都学的扎实吗？这是您前进过程中的助手。 
&lt;LI&gt;您有扎实的学习目标和计划吗？这是您在技术汪洋中的指南针。&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;我的文章写完了。&lt;/P&gt;
&lt;P&gt;我很理想，我也在努力。:)&lt;/P&gt;</description>
      <comments>http://blog.zhaojie.me/2007/10/how-to-learn.html#comments</comments>
      <pubDate>Mon, 29 Oct 2007 10:47:00 GMT</pubDate>
      <lastBuildDate>Mon, 29 Oct 2007 10:47:00 GMT</lastBuildDate>
    </item>
  </channel>
</rss>
