﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-专家区</title><link>http://www.cnblogs.com/expert/</link><description>程序员的网上家园</description><language>zh-cn</language><lastBuildDate>Wed, 10 Feb 2010 01:33:02 GMT</lastBuildDate><pubDate>Wed, 10 Feb 2010 01:33:02 GMT</pubDate><ttl>60</ttl><item><title>如何通过VPC在本机搭建局域网</title><link>http://www.cnblogs.com/artech/archive/2010/02/08/1665602.html</link><dc:creator>Artech</dc:creator><author>Artech</author><pubDate>Sun, 07 Feb 2010 16:06:00 GMT</pubDate><guid>http://www.cnblogs.com/artech/archive/2010/02/08/1665602.html</guid><description><![CDATA[<p>阅读: 973 评论: 14 作者: <a href="" target="_blank">Artech</a> 发表于 2010-02-08 00:06 <a href="http://www.cnblogs.com/artech/archive/2010/02/08/1665602.html" target="_blank">原文链接</a></p><p>前几天在家里测试一个基于WS-AT的分布式应用，但是连接公司网络的VPN出现了问题，不得不采用VPC在本机搭建一个局域网。虽然以前也做过这样的尝试，可能是很久没有弄过了，一些细节记不清了，所以也折腾了好一阵子。在这里，我特意写一篇文章来介绍基于VPC搭建局域网的整个步骤，没有什么技术含量，只当给具有相同需要的朋友多一个参考。</p>  <p>我现在的Host Machine为Windows 7 Ultimate （X64） ，Virtual Machine为Windows Server 2008 （X86），都是现成的。本篇文章不会涉及如何安全VPC的问题，仅仅涉及到如何将Host PC和VPC成为同一个局域网中两台可以互相链接的主机，下面是对3个主要步骤的：</p>  <h1><font size="4"><strong>步骤一：安装Microsoft Loopback Adapter网络适配器</strong></font></h1>  <p>打开Device Manager，右键选择主机名称，在探出的上下文菜单中选择"Add legacy hardware&#8221;。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_2.png" target="_blank"><img style="border-width: 0px; display: inline; margin-left: 0px; margin-right: 0px;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb.png" border="0" width="397" height="263" /></a> </p>  <p>出现如下一个Welcome to the Add Hardware Wizard 对象框，点击"Next&#8221;按钮。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_6.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_2.png" border="0" width="394" height="290" /></a> </p>  <p>进入如下一个对话框，选择第二个选项"Install the hardware that I manually select from a list (Advanced) "，然后点击"Next"按钮。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_8.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_3.png" border="0" width="396" height="291" /></a> </p>  <p>弹出如下一个硬件类型选择对话框，硬件类型列表中选择"Network adapter"，然后点击"Next"按钮。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_10.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_4.png" border="0" width="394" height="290" /></a> </p>  <p>硬件安装向导进入如下一个"Select Network Adapter",在硬件厂商列表中选择"Microsoft",在网络适配器列表中选择"Microsoft Loopback Adapter",然后点击"Next"按钮。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_12.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_5.png" border="0" width="397" height="292" /></a> </p>  <p>在弹出的"The wizard is ready to install your hardware"对话框中，然后点击"Next"按钮，开始安装硬件。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_14.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_6.png" border="0" width="393" height="289" /></a> </p>  <h1><font size="4"><strong>步骤二、将VPC的网络适配器设置为Microsoft Loopback Adapter</strong></font></h1>  <p>打开Virtual PC Console，选择相应的VPC，点击Setting按钮对其进行设置。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_16.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_7.png" border="0" width="389" height="275" /></a> </p>  <p>在VPC设置面板中设置项目中选择"Networking",选择我们刚才安装的"Microsoft Loopback Adapter"作为网络适配器，点击OK确认。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_20.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_9.png" border="0" width="389" height="277" /></a> </p>  <p><font size="4"><strong>步骤三、设置Host Machine和Virtual Machine的IP</strong></font></p>  <p>在Host Machine中，打开Network and Sharing Center，点击Channe Adapter Setting链接，进入Network Connections窗口。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_18.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_1.png" border="0" width="400" height="190" /></a> </p>  <p>右击选择基于Microsoft Loopback Adapter的连接（这里是Local Area Connection 2），在上下文菜单中选择Proeprties，进入连接的属性窗口。</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_22.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_8.png" border="0" width="399" height="501" /></a> </p>  <p>选择Internet Protocol Version 4（TCP/IPv4),点击 Properties按钮，进行相应的IP设置，在这里IP地址和子网掩码分别为192.168.0.6和255.255.255.0.</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_24.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_10.png" border="0" width="386" height="429" /></a> </p>  <p>然后对Virtual Machine相应的链接按照上面的步骤设置IP地址，需要设置成相同的网段，我采用的IP地址和子网掩码分别为192.168.0.8和255.255.255.0.</p>  <p><a href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_26.png" target="_blank"><img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_11.png" border="0" width="384" height="426" /></a> </p>  <p>到此为止，Host Machine和Virtual Machine就成为了同一个局域网中的两个主机。你可以直接利用VPC界面操作Virtual Machine，不过我个人习惯使用Remote Desktop。此外，你可以根据具体安全需求，对防火墙进行相应设置。</p>  <p><a target="_blank" href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_28.png"><img style="border: 0px none; display: inline;" title="image" alt="image" src="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/VPC_1098E/image_thumb_12.png" border="0" width="398" height="203" /></a> </p>  <div id="MySignature">作者：<a href="http://artech.cnblogs.com/" target="_blank">Artech</a>     <br />出处：<a href="http://artech.cnblogs.com/" target="_blank">http://artech.cnblogs.com</a>     <br />本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。 </div><img src="aggbug/1665602.html?type=0" width="1" height="1" alt=""/><p>评论: 14　<a href="http://www.cnblogs.com/artech/archive/2010/02/08/1665602.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/artech/archive/2010/02/08/1665602.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>笑谈PDD——仅为调侃</title><link>http://www.cnblogs.com/kym/archive/2010/02/07/1665576.html</link><dc:creator>飞林沙</dc:creator><author>飞林沙</author><pubDate>Sun, 07 Feb 2010 14:57:00 GMT</pubDate><guid>http://www.cnblogs.com/kym/archive/2010/02/07/1665576.html</guid><description><![CDATA[<p>阅读: 877 评论: 21 作者: <a href="" target="_blank">飞林沙</a> 发表于 2010-02-07 22:57 <a href="http://www.cnblogs.com/kym/archive/2010/02/07/1665576.html" target="_blank">原文链接</a></p><p><font color="#0000ff" face="微软雅黑"><strong>1. 何为PDD</strong></font></p>
<p><font color="#000000" face="微软雅黑">中国是一个不擅长创造概念的国家，然而，在软件的世界里，中国却开创了一个新的名词&#8212;&#8212;称之PDD。</font></p>
<p><font color="#000000" face="微软雅黑">PDD&#8212;&#8212;Page-Driven Develop(页面驱动开发)。</font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>2. 适从于企业的软件开发</strong></font></p>
<p><font color="#000000" face="微软雅黑">中国大多数的公司是什么开发现状我不清楚，只知道太多的人说：敏捷不适合我们，TDD不适合我们，XP不适合我们，螺旋也不适合我们。</font></p>
<p><font color="#000000" face="微软雅黑">那么我们要做什么呢？我们要找到一条我们企业自己的软件开发理论。于是乎，太多的企业开始的自己的探索之路。创造出了&#8220;XXXX公司&#8221;的软件工程，&#8220;适用于中国互联网&#8221;的软件工程&#8230;&#8230;</font></p>
<p><font color="#000000" face="微软雅黑">在某次培训后，老大大笔一挥，我们要在项目中适用TDD。</font></p>
<p><font color="#000000" face="微软雅黑">组长下令：</font></p>
<p><font color="#000000" face="微软雅黑">&#8220;OK。然而，TDD不适合于我们的项目，也不适合我们企业。那我们灵活应对，TDD的核心是什么，是&#8221;DD&#8221;，我们把握住这个DD，先做页面&#8230;&#8230;&#8221;</font></p>
<p><font color="#000000" face="微软雅黑">我笑，控制不住的笑，我又接触到了一个名词，那就叫PDD吧。</font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>3. 浅解PDD</strong></font></p>
<p><font color="#000000" face="微软雅黑">谈起PDD，也许大家都很陌生，但是我想当我详解PDD之后，大家会觉得：哦！原来是这么一回事啊，在我刚刚学软件的时候，原来我们一直都在用PDD的开发模型。</font></p>
<p><font color="#000000" face="微软雅黑">什么是PDD。PDD就是一切以页面为核心，然后每个程序员针对每个页面来找到功能点，从而以页面为单位进行任务交付。</font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>4. PDD之诡辩</strong></font></p>
<p><font color="#000000" face="微软雅黑">为什么要采用PDD呢？</font></p>
<p><font color="#000000" face="微软雅黑">我们按照传统的思维来走，一切应该是以业务来驱动开发，我们甚至可以称之为BDD(Business-Driven Develop)。那么业务从哪里来？从界面来，所以我们要以页面为单位来驱动开发程序。</font></p>
<p><font color="#000000" face="微软雅黑">有一种说法是，开发未动，页面先行，这也是PDD的一个理论基础。</font></p>
<p><font color="#000000" face="微软雅黑">这就是PDD的由来。</font></p>
<p><font color="#000000" face="微软雅黑">那下面就来剖析下PDD究竟错在哪里。</font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>5. 业务从何而来</strong></font></p>
<p><font color="#000000" face="微软雅黑">页面从页面而来，这似乎成了PDD最大的理由。这里我想说：也许业务逻辑可以从界面而来，但是他在这里忽略了角色的概念。</font></p>
<p><font color="#000000" face="微软雅黑">在一个项目团队中，一定要有着一个人来承担着，需求产品方与开发人员之间的桥梁，这个人员按照常理上应该叫做&#8221;需求分析人员&#8220;。在很多企业中，这个角色一般由项目经理&amp;&amp;开发经理来担任。</font></p>
<p><font color="#000000" face="微软雅黑">需求调研的方式有很多，比如问答，调查问卷，甚至于是说从页面而来。</font></p>
<p><font face="微软雅黑">但是<font color="#ff0000"><strong>对于开发人员来说，这些一切都是透明的，业务从何而来？是从项目经理的文档中而来。对于一个项目来说，应该是从设计文档中而来。而绝不是页面。</strong></font></font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>6. TDD的核心</strong></font></p>
<p><font color="#000000" face="微软雅黑">个人一直认为，如果当你对一个概念，对一个理论没有充分地理解时，千万不要对其随便去改造，变化。</font></p>
<p><font color="#000000" face="微软雅黑">TDD的核心是什么，不是DD，而是那个T。</font></p>
<p><font color="#000000" face="微软雅黑">TDD强调的是：开发为做，测试先行。保证了每个完整的业务逻辑都是正确的，更重要的还有一点就是这个T的可重用性。</font></p>
<p><font color="#000000" face="微软雅黑">个人对TDD并没有什么认识，在此就不多说了。</font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>7. 什么叫页面先行</strong></font></p>
<p><font color="#000000" face="微软雅黑">什么是页面先行，也许很多人都被这个页面误导了。在我看来，<font color="#ff0000"><strong>与其说页面先行，倒不如说原型先行来得更合适</strong></font>。</font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>8. PDD的坏处</strong></font></p>
<p><font color="#ff0000" face="微软雅黑"><strong>A. PDD的代码是不可重用的：</strong></font></p>
<p><font color="#000000" face="微软雅黑">最简单的逻辑，如果分给每个开发人员若干个页面，让开发人员依照这些页面进行开发，那么每个开发人员都会去找，每个按钮是做什么的，每个下拉框要回发什么数据。这就必然导致，每个人都是双击Button，然后在后台编写Button_Click方法，这样是最快的，也是最贴近开发人员思维的。</font></p>
<p><font color="#000000" face="微软雅黑">这样就必然导致了，每个开发人员的代码是不可重用的。因此想用PDD来开发出真正分层的程序，真的是异想天开。<font color="#ff0000"><strong>分层是先有层，后有代码。而绝非先有代码，后有层</strong></font>。</font></p>
<p><font color="#000000" face="微软雅黑">由于太多的企业这样去做，所以在后台代码出现了上百行，甚至上千行代码，也不是不可理解了。错在哪？不是开发人员，而是领导人员。</font></p>
<p><font color="#ff0000" face="微软雅黑"><strong>B. PDD是无法知人善用的</strong></font></p>
<p><font color="#000000" face="微软雅黑">我在<a href="http://www.cnblogs.com/kym/archive/2010/01/26/1656374.html" target="_blank">读大道至简之我见1&#8212;&#8212;团队管理</a>中提到：作为一个管理者，必须具备&#8221;知人善用&#8220;的素质。</font></p>
<p><font color="#000000" face="微软雅黑">那么，PDD是以页面为功能切分功能的，这样也就意味着，每个开发人员都需要具备从前台CSS/Javascript，到C#，到SQL一系列的能力。</font></p>
<p><font color="#000000" face="微软雅黑">人无全才，很少有人既是Javascript牛人，又是DBA的数据库级别，因此，这样写出的代码，不可能是完整的。必然会导致，每个功能点都会有着这样的或者是那样的缺憾。</font></p>
<p><font color="#ff0000" face="微软雅黑"><strong>C. PDD是在整体项目进度上是缓慢的</strong></font></p>
<p><font color="#000000" face="微软雅黑">对于一个商务项目来说，应该是以业务为驱动的，这样，每个人都可以负责自己专属的一部分。</font></p>
<p><font color="#000000" face="微软雅黑">例如SQL开发人员，前台美工，Javascript开发人员，后台开发人员，每个人都有自己的关注点，前台人员，后台人员不需要关心后台数据库的逻辑，就不至于每个开发人员在开发之前都需要先来了解前台的美工布局，又需要了解后台数据库的表结构，这样如果一个项目过大，就必然会让人做着无数重复的工作，比如我们每个人都需要详细了解表结构。</font></p>
<p><font color="#000000" face="微软雅黑">其实，采用PDD方式，实际上是会让项目减缓的。</font></p>
<p><font color="#ff0000" face="微软雅黑"><strong>D. PDD和面向对象的不兼容性</strong></font></p>
<p><font color="#000000" face="微软雅黑">简而言之：<font color="#ff0000"><strong>面向对象是先有对象，后组装，而PDD是先有功能，后拆分</strong></font>，因此，PDD不可能开发出面向对象的程序。</font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>9. PDD的产生原因</strong></font></p>
<p><font color="#000000" face="微软雅黑">PDD因何产生，我个人总结出如下几点：</font></p>
<p><font color="#ff0000" face="微软雅黑"><strong>A. 从玩具到项目的过渡</strong></font></p>
<p><font color="#000000" face="微软雅黑">在校园里，很少有学生来能从头开始面对一个完整的大项目，而都是一些项目模块，或者是一些如&#8221;图书馆管理系统&#8220;之类的小项目。</font></p>
<p><font color="#000000" face="微软雅黑">在这样的项目中，开发人员较少，甚至是独立开发。系统简单，逻辑清晰，从界面开发没有什么不可以的。但是到了工作中，你面对的不在是一个简单的&#8221;玩具&#8220;系统，而是一个真实的项目，里面可能会涉及到较为复杂的业务逻辑，会涉及到系统的，子模块之间的集成，也涉及到多人的团队合作开发。</font></p>
<p><font color="#000000" face="微软雅黑">这样，再由于惯性才用PDD方式其实是并不适用的。</font></p>
<p><font color="#ff0000" face="微软雅黑"><strong>B. 信任危机</strong></font></p>
<p><font color="#000000" face="微软雅黑">这个是非技术原因，仅为企业原因。</font></p>
<p><font color="#000000" face="微软雅黑">对于很多项目经理，开发主管，产品经理等来说，他们很多是不信任手下的开发人员的，他们需要每天都能看到，我手下的人，今天做了哪些工作。</font></p>
<p><font color="#000000" face="微软雅黑">那么什么是最直观的呢？页面。我今天做了十个页面，恩&#8230;. 不错。你今天做了一个页面，开除&#8230;.</font></p>
<p><font color="#000000" face="微软雅黑">所以，我要求把整个项目拆分成若干个页面，每个开发人员负责几个页面，每天把你负责的页面完成，让我每天都能感觉到，你今天确实在工作。</font></p>
<p><font color="#000000" face="微软雅黑">这也就是我所说的：信任危机。</font></p>
<p><font color="#ff0000" face="微软雅黑"><strong>那么既然有了原因，应对之道是很简单的吧。</strong></font></p>
<p><strong><font color="#0000ff" face="微软雅黑">10. PDD的应对之道</font></strong></p>
<p><font color="#0000ff" face="微软雅黑"><span style="color: #000000">提出了问题，就要解决问题，那么我们如何来应对PDD（不知道这能否算是一种反模式的解决方案）。</span></font></p>
<p><strong><font color="#ff0000" face="微软雅黑"><strong>A. 观念的转变</strong></font></strong></p>
<p><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #000000">在项目中，不要因循守旧，说&#8220;我曾经是怎么做的&#8221;，我在前文中提过：成功是对过去经验的总结，而并非对过去经验的复制。我们要时刻记得，我是在做项目，不是在做玩具。</span></span></font></p>
<p><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #000000">因此，我们不要为了贪图方便，为了觉得&#8220;减少时间&#8221;而PDD，而是以业务逻辑为驱动。</span></span></font></p>
<p><strong><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #ff0000"><strong><strong>B. 时刻考虑重用</strong></strong></span></span></font></strong></p>
<p><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #000000">对于一个打算长期发展的公司来说，重用性和维护性都是非常重要的。那么如果时刻考虑重用，那么PDD就是行不通的。</span></span></font></p>
<p><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #000000">什么是重用性最高的代码，我总结为有两种特征：&lt;1&gt; 原子性高的代码 &lt;2&gt; 业务性较弱的代码</span></span></font></p>
<p><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #000000">第一点不用说，你的颗粒越小，能用到你的地方越多。就像1+1=2能被很多地方用到，但是1+1+1+1+1=5就很少有地方会用到。第二点，业务无关的代码可以被任何业务所使用，并不是说我插入图片的操作，我需要首先验证图片类型，然后保存到服务器，然后存到数据库，这属于一个完整的业务逻辑，今后其他地方只要上传图片，比如说，我的安全级别较低，不需要验证图片，那么我的这个方法就不能被重用。</span></span></font></p>
<p><strong><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #ff0000">C. 信任下属</span></span></font></strong></p>
<p><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #000000">用人不疑疑人不用，这个道理应该是每个人都懂的，可是能做到的人很少。</span></span></font></p>
<p><strong><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #ff0000">D 设立正确的作业和里程碑</span></span></font></strong></p>
<p><font color="#ff0000" face="微软雅黑"><span style="color: #000000"><span style="color: #000000">我在9中提到，很多主管以页面为交付单位，这就必然会造成PDD，那么我们是否考虑放弃以页面为交付作业和里程碑，而是以函数实现，类实现作为我们的交付基本单位呢？</span></span></font></p>
<p><font color="#0000ff" face="微软雅黑"><strong>11. 总结</strong></font></p>
<p><font color="#000000" face="微软雅黑">以上就是我对PDD的一些概括，仅为调侃之文。</font></p>
<p><font color="#000000" face="微软雅黑">拍吧&#8230;&#8230;..</font></p>
<p><font face="微软雅黑"></font></p>
<p><font face="微软雅黑"></font></p>
<p><font face="微软雅黑">&nbsp;</font></p><img src="aggbug/1665576.html?type=0" width="1" height="1" alt=""/><p>评论: 21　<a href="http://www.cnblogs.com/kym/archive/2010/02/07/1665576.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/kym/archive/2010/02/07/1665576.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>深入Android 【四】 —— 组件调用</title><link>http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html</link><dc:creator>duguguiyu</dc:creator><author>duguguiyu</author><pubDate>Sun, 07 Feb 2010 14:09:00 GMT</pubDate><guid>http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html</guid><description><![CDATA[<p>阅读: 815 评论: 4 作者: <a href="" target="_blank">duguguiyu</a> 发表于 2010-02-07 22:09 <a href="http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html" target="_blank">原文链接</a></p><span class="Apple-style-span" style="font-family: Verdana; line-height: normal; font-size: 13px; "><br /><span class="Apple-style-span" style="font-family: Georgia; font-size: xx-large; font-weight: bold; ">Intent解析</span><br /><br /><div style="margin-top: 0px; margin-bottom: 0px; ">基于组件的架构体系，除了有定义良好的组件，如何把这些组件组装在一起，也是一门艺术。在Android中，<strong>Intent</strong>（貌似通常译作：<strong>意图</strong>...），就是连接各组件的桥梁。</div><div style="margin-top: 0px; margin-bottom: 0px; ">前段时间看同事们做Symbian平台的<a href="http://zsy.163.com/help" id="ds0." title="网易掌上邮" target="_blank"><strong>网易掌上邮</strong></a>（真的是做的用心，NB的一米，热情欢迎所有163邮箱的S60v3用户，猛点击之...），有个功能是为邮件添加附件，比如你想要通过邮件发送一副图片泡mm，可能需要有个很直观的方式从本地选一副珍藏美图，抑或是拿相机来个完美自拍。在Symbian中，这样的功能，都需要你用底层的API，自己一点点写。为了让选图片体验更好，可能需要做一个类似于图片浏览器之类的东西，为了把拍照做的更为顺畅，甚至需要实现从聚焦到调节亮度之类一整套的相机功能。</div><div style="margin-top: 0px; margin-bottom: 0px; ">而其实呢，用户的手机中可能本身就装了其他的专业图片浏览器、相机等应用，这些应用已经非常出色好用，而用户也已然能很纯属使用它们，如果能进行调用，对邮箱的开发者和用户而言，都会是个更好的选择。但在Symbian这样残败的系统里，应用和应用之间的结合能力奇弱无比，想复用，基本比登天还难，作为开发者，只能忍住一次又一次的恶心，为了用户，做这些重复造轮子吃力不讨好的附加工作。</div><div style="margin-top: 0px; margin-bottom: 0px; ">还好还好，在Android中，一切变得美好多了，它将开发者从接口和对象的细节中解救出来，让我们有更多精力投入到核心功能的开发中去。在Android中，如果你需要选个图拍个片，只需要构造一个描述你此项意愿的Intent，发送出去，系统会帮你选择一个能够处理该项业务的组件来满足你的需求，而不再需要纠结在具体的接口和实现上，Perfect World，便应如此。</div><br /><h2 style="font-size: 14pt; ">Intent构成</h2>Intent被译作意图，其实还是很能传神的，Intent期望做到的，就是把实现者和调用者完全解耦，调用者专心将以意图描述清晰，发送出去，就可以梦想成真，达到目的。<div style="margin-top: 0px; margin-bottom: 0px; ">当然，这么说太虚了，庖丁解牛，什么东西切开来看看，也许就清晰了。<strong><a href="http://androidappdocs.appspot.com/reference/android/content/Intent.html" id="z.s2" title="Intent" style="color: #551a8b; " target="_blank">Intent</a></strong>（<strong>reference/android/content/Intent.html</strong>），在Android中表现成一个类，发起一个意图，你需要构造这样一个对象，并为下列几项中的一些进行赋值：</div><br /><ol style="margin-top: 0px; margin-bottom: 0px; "><li style="margin-top: 0px; margin-bottom: 0px; "><strong>Action</strong>。当日常生活中，描述一个意愿或愿望的时候，总是有一个动词在其中。比如：我想<strong>做</strong>三个俯卧撑；我要<strong>看</strong>一部x片；我要<strong>写</strong>一部血泪史，之类云云。在Intent中，Action就是描述看、做、写等动作的，当你指明了一个Action，执行者就会依照这个动作的指示，接受相关输入，表现对应行为，产生符合的输出。在Intent类中，定义了一批量的动作，比如<strong>ACTION_VIEW</strong>，<strong>ACTION_PICK</strong>，之类的，基本涵盖了常用动作，整一个降龙十八掌全集。当然，你也可以与时俱进，创造新的动作，比如lou这样的。与系统预定义的相比，这些自定义动作的流通范围很是有限，除非做了非常NB的应用，大家都需要follow你，否则通常都是应用内部流通。</li><li style="margin-top: 0px; margin-bottom: 0px; "><strong>Data</strong>。当然，光有动作还是不够的，还需要有更确切的对象信息。比如，同样是<strong>泡</strong>这个动作，但<strong>泡咖啡</strong>，和<strong>泡妞</strong>，就差之千里了。Data的描述，在Android中，表现成为一个<strong>URI</strong>。用在内部通信中，可能描述是Content Provider用的形如<strong>content://xxxx</strong>这样的东东，抑或是外部的一个形如<strong>tel://xxxx</strong>这样的链接。总而言之，是能够清楚准确的描述一个数据地址的uri。</li><li style="margin-top: 0px; margin-bottom: 0px; "><strong>Type</strong>。说了Data，就必须要提Type，很多时候，会有人误解，觉着Data和Type的差别，就犹如<strong>泡妞</strong>和<strong>泡马子</strong>之间的差别一样，微乎其微。但其实不然，Type信息，是用<strong>MIME</strong>来表示的，比如<strong>text/plain</strong>，这样的东西。说到这里，两者差别就很清晰了，Data就是门牌号，指明了具体的位置，具体问题具体分析，而type，则是强调物以类聚，解决一批量的问题。实际的例子是这样的，比如，从某个应用拨打一个电话，会发起的是action为ACTION_DIAL且data为tel:xxx这样的Intent，对应的人类语言就是<strong>拨打xxx的电话</strong>，很具象。而如果使用type，就宽泛了许多，比如浏览器收到一个未知的MIME类型的数据（比如一个视频...），就会放出这样的Intent，求系统的其他应用来帮助，表达成自然语言应该就是：<strong>查看pdf类文档</strong>，这样的。</li><li style="margin-top: 0px; margin-bottom: 0px; "><strong>Category</strong>。通过Action，配合Data或Type，很多时候可以准确的表达出一个完整的意图了，但也会有些时候，还需要加一些约束在里面才能够更精准。比如，如果你虽然很喜欢做俯卧撑，但一次做三个还只是在特殊的时候才会发生，那么你可能表达说：<strong>每次吃撑了的时候</strong>，我都想做三个俯卧撑。吃撑了，这就对应着Intent的Category的范畴，它给所发生的意图附加一个约束。在Android中，一个实例是，所有应用主Activity（就是单独启动时候，第一个运行的那个Activity...），都需要能够接受一个Category为CATEGORY_LAUNCHER，Action为ACTION_Main的意图。</li><li style="margin-top: 0px; margin-bottom: 0px; "><strong>Component</strong>。在此之前，我们企图用Action，Data/Type，Category去描述一个意图，这是Android推荐，并期望大家在大多数时候使用的，这样模式在Android中称做<strong>Implicit Intents</strong>，通过这种模式，提供一种灵活可扩展的模式，给用户和第三方应用一个选择权。比如，还是一个邮箱软件，他大部分功能都好，就是选择图片的功能做的很土，怎么办？如果它采用的是Implicit Intents，那么它就是一个开放的体系了，手机中没有其他图片选择程序的话，可以继续使用邮箱默认的，如果有，你可以任意选择来替代原有模块完整这功能，一切都自然而然。但这种模式，也不是没有成本，需要付出的是一些性能上的开销，因为毕竟有一个检索过程。于是，Android提供了另一种模式，叫做<strong>Explicit Intents</strong>，就需要Component的帮助了。Component就是<strong>类名</strong>，完整的，形如<strong>com.xxxxx.xxxx</strong>，一旦指明了，一切都清晰了，找的到这个类（当然会是一个特定的子类...），成功，反之，失败。这个好处，自然是速度，适合在你明确知道这就是一个内部模块的时候，使用它。</li><li style="margin-top: 0px; margin-bottom: 0px; "><strong>Extras</strong>。通过上面的这些项，识别问题，基本完美解决了，剩下一个重要的问题，就是传参。Extras是用来做这个事情的，它是一个<a href="http://androidappdocs.appspot.com/reference/android/os/Bundle.html" id="ldre" title="Bundle" target="_blank"><strong>Bundle</strong></a>类的对象，有一组可序列化的<strong>key/value对</strong>组成。每一个Action，都会有与之对应的key和value类型约定，发起Intent的时候，需要按照要求把Data不能表示的额外参数放入Extras中（当然，如果不需要额外附加参数，就算了...），否则执行者拿到的时候会抓狂的。</li><li style="margin-top: 0px; margin-bottom: 0px; "><strong>Flags</strong>。能识别，有输入，整个Intent基本就完整了，但还有一些附件的指令，需要放在Flags中带过去。顾名思义，Flags是一个整形数，有一些列的标志位构成，这些标志，是用来指明运行模式的。比如，你期望这个意图的执行者，和你运行在两个完全不同的任务中（或说进程也无妨吧...），就需要设置<strong>FLAG_ACTIVITY_NEW_TASK</strong>的标志位。</li></ol><br /><div style="margin-top: 0px; margin-bottom: 0px; ">有了上述这些，一个Intent的形象就跃然纸上了，如此丰富的内容，决定了它比传统的模式，都来得强大。</div><br /><h2 style="font-size: 14pt; ">Intent匹配</h2><div style="margin-top: 0px; margin-bottom: 0px; ">上次在moto dev上，听人做Android的讲座，下面有很多听客都对Intent这个概念表示出了强烈的兴趣，拿出自己熟悉领域的各类概念进行类比，比如事件、消息之类。当时我在想，Intent作为组件间的通信协定，与一般的简单的通信方式不同，首先，从前面部分可以看到，它的描述是针对需求而不是实现者来进行的。其次，它的解析是依托第三方而不是两方直接进行。</div><div style="margin-top: 0px; margin-bottom: 0px; ">这个概念和设计模式中的中介模式（<a href="http://en.wikipedia.org/wiki/Mediator_pattern" id="il70" title="Mediator Pattern" style="color: #551a8b; " target="_blank">Mediator Pattern</a>）是一脉的，即所有的外围组件，都只和系统的核心模块发生联系，通过它进行中转，组件之间不直接勾搭。</div><br /><div style="margin-top: 0px; margin-bottom: 0px; "><img src="http://images.cnblogs.com/cnblogs_com/duguguiyu/2.png" width="400" height="211" alt="" /><br /></div><br />如上图所示，要想跑通整个流程，另一个很重要的东西，就是<a href="http://androidappdocs.appspot.com/reference/android/content/IntentFilter.html" id="e6lb" title="Intent Filters" style="color: #551a8b; " target="_blank"><strong>Intent Filters</strong></a>，它是用来描述一个Activity或Serveice等组件，期望能够响应怎么样的Intent。如果一个组件，只希望别的组件通过Explicit Intents（就是指明Component...）的方式来找到它，那么就不需要添加Intent Filters，反之，一定需要一个或若干个Intent Filters。Intent Filter的各个项，犹如Intent照镜子过来的效果，包括Action，Catagory，Data，Type等。<div style="margin-top: 0px; margin-bottom: 0px; ">Intent Filters可以写到配置文件中，和那些组件的配置一起（不记得什么是配置文件了，可以看<a href="http://www.cnblogs.com/duguguiyu/archive/2010/01/30/1659980.html" id="vrpk" title="这里" style="color: #551a8b; " target="_blank">这里</a>...），若干的实例可以在Intent介绍页面上找到（<a href="http://androidappdocs.appspot.com/reference/android/content/Intent.html" style="color: #551a8b; " target="_blank"><strong>reference/android/content/Intent.html</strong></a>）。同样，Intent Filters可以在代码中，动态插拔，这个是和动态插拔的<strong>Broadcast Receiver</strong>是配套使用的。</div><div style="margin-top: 0px; margin-bottom: 0px; ">系统核心的模块，会负责收集这些Intent Filters，和它们对应的组件信息。当请求者需要一个组件帮忙，并构造了描述它需求的Intent发送到系统核心，系统核心会将其与已知的各个Intent Filters进行匹配，挑选一个符合需求的组件返回。如果有多个符合的，会尝试看看有没有默认执行的，如果没有默认的，就会构造UI，让用户帮助抉择，如是，整个流程就跑通了。</div><br /><h2 style="font-size: 14pt; ">Intent实现</h2><img src="http://images.cnblogs.com/cnblogs_com/duguguiyu/3.png" width="600" height="240" alt="" /><br /><br /><br />上图，是请求一个Activity组件的简单实现流程图，算是用的最多的Intent解析实例。流程从调用<a href="http://androidappdocs.appspot.com/reference/android/content/Context.html#startActivity(android.content.Intent)" id="s0hr" title="Context.startActivity(Intent)" style="color: #551a8b; " target="_blank"><strong>Context.startActivity(Intent)</strong></a>开始，调用者传入构造好的Intent对象，然后流程会让实际的执行者，是<a href="http://androidappdocs.appspot.com/reference/android/app/Instrumentation.html" id="capl" title="Instrumentation" style="color: #551a8b; " target="_blank"><strong>Instrumentation</strong></a>对象来完成。它是整个应用激活的Activity管理者，集中负责该应用内所有Activity的起承转合生离死别。它有一个隐藏的方法<strong>execStartActivit</strong>y方法，就是负责根据Intent启动Activity的。去掉一些细节，它做得最重要的事情，就是将此调用，通过RPC的方式，传递到<strong>ActivityManagerService</strong>。<br />前面一直再说，<strong>系统核心层</strong>，其实这里所谓的系统核心层，就是负责Android一些关键事务的<strong>一组服务</strong>。它们同样运行在虚拟机上，和普通的Service实现机理是一致的，只不过它们不抛头露脸只是默默的在下层服务，故谓之核心嘛。AcitivityManagerService，是负责Activity调度的服务，也许日后提及调度细节的时候还会有涉及。<div style="margin-top: 0px; margin-bottom: 0px; ">在这里，AcitivityManagerService会分两个步骤完成相关操作，首先把Intent递交给另一个服务<strong>PackageManagerService</strong>，此服务掌握整个软件包及其各组件的信息，它会将传递过来的Intent，与已知的所有Intent Filters进行匹配（如果带有Component信息，就不用比了...），找到了，就把相关Component的信息通知回AcitivityManagerService，在这里，会完成启动Activity这个很多细节的事情。</div><div style="margin-top: 0px; margin-bottom: 0px; ">由此可知，启动Activity，要经过多个服务的处理，并不是非常轻量的过程，在Android随机文档<a href="http://androidappdocs.appspot.com/guide/practices/design/performance.html#samples" id="sytu" title="介绍性能" style="color: #551a8b; " target="_blank">介绍性能</a>的一节中，对此有一个评估。但这样的操作不是会放在循环里反复折磨的那种，因此整体效果与其付出的性能代价相比，觉得是物超所值的。</div></span><img src="aggbug/1665544.html?type=0" width="1" height="1" alt=""/><p>评论: 4　<a href="http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/duguguiyu/archive/2010/02/07/1665544.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>总结：史上第一混乱、程序员的爱情、Nobody &amp;amp; Sorry Sorry</title><link>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/play-novel-nobody-sorry-sorry.html</link><dc:creator>Jeffrey Zhao</dc:creator><author>Jeffrey Zhao</author><pubDate>Sun, 07 Feb 2010 13:19:00 GMT</pubDate><guid>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/play-novel-nobody-sorry-sorry.html</guid><description><![CDATA[<p>阅读: 4057 评论: 62 作者: <a href="" target="_blank">Jeffrey Zhao</a> 发表于 2010-02-07 21:19 <a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/play-novel-nobody-sorry-sorry.html" target="_blank">原文链接</a></p><p>星期六是我的休息日，这天一般我不安排自己做什么和工作有关的事情，一般就是去看看电影，出去逛逛，或者在家上上网吹吹牛。昨天<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/0-bug-and-sjtu-acm-champion.html">总结</a>了一部分由<a href="https://twitter.com">推特</a>上的讨论，现在继续剩下的一部分。不过，这次的内容可能就要和技术或产业略远一些了，其中大部分是我自己的一些体会和感想。现在我打算谈三个东西，一是《史上第一混乱》这部话剧，《程序员的爱情》这本小说，以及Nobody和Sorry Sorry（您不知道这是啥？你成奥特曼啦！）。</p>  <h1>史上第一混乱</h1>  <p>上周五公司开年会，其间我侥幸拿下喝啤酒比赛第一，赢得价值300元的电磁炉一个——这还是整场年会中唯一比蛮力的项目，我那个自豪啊。呃，扯远了，其实下一件事才和我要谈的事情有些联系。那就是后来我又在年会上表演节目，唱了两首歌，因此拿到了昨天晚上《史上第一混乱》话剧的门票。至于为啥是这个话剧，后来我才意识到原来这个话剧改编自盛大文学旗下<a href="http://www.qidian.com">起点中文网</a>上的<a href="http://www.qidian.com/Book/174075.aspx">同名小说</a>，如此说来盛大准备几张该话剧的门票自然就顺理成章了。</p> <img class="floatRight" src="http://images.cnblogs.com/cnblogs_com/jeffreyzhao/ssdyhl.jpg" />   <p>昨天下午先去看了场电影，锦衣卫，甄子丹演的，我对于此类动作片的兴趣始终不减，不过看完后倒也没有什么留下什么深刻的印象。看完后吃了晚饭，发现时间尚早，想票子不要浪费了吧，于是便去看了这场话剧。座位不太好，第一排，需要一直仰着头。不过由于距离够近，因此可以清晰地看到演员横飞的唾沫星子，还有演女人的mm身材也不错，腿细胸大的。</p>  <p>提起话剧内容，您可以将其理解为是一个非常单纯的，不包含任何思想在内的，完完全全的无厘头闹剧。总之，就是把最近各种流行的玩艺儿，笑话，网络词，广告串在一起。虽说笑果扑面而来，但听得多了倒也会有些疲劳——因此某些情况下其他观众哈哈大笑的时候我却有点无动于衷。不过也有不少地方挺有创意的，虽说都是耳熟能详的东西，但是在令人意想不到的地方跑出来确实也有眼前一亮的感觉。其中也有很多桥段在为80后的童年生活致敬，如蓝精灵，葫芦娃，黑猫警长，北斗神拳，颇为亲切。</p>  <p>按常理说我不太会喜欢这样的东西，不过可能是由于事先已经了解过这部话剧/小说的背景，再加上“童年回忆”的影响，我倒也并不讨厌这部话剧（但也没推荐啊）。事实上，可能的确是由于平时天天山珍海味，忽然来了一顿粗茶淡饭似乎也别有一番风味。前一段时间<a href="http://blog.tianya.cn/blogger/post_show.asp?idWriter=0&amp;Key=0&amp;BlogID=41917&amp;PostID=19055487">发生了这样一个著名的事件</a>：</p>  <blockquote>   <p>天涯的“天涯时代”版块，本月举办了一次“天涯车友会Logo征集大赛”，参赛作品约30件，最后著名的“27号”勇夺桂冠。再总共3227张投票中，27号作品获得1627票的支持，支持率超过50%，而第二名的得票数还不到它的五分之一。绝对的、毫无争议的、毋庸置疑的众望所归。</p> </blockquote>  <p>而这27号参赛作品的设计是这样的：</p> <img src="http://images.cnblogs.com/cnblogs_com/jeffreyzhao/tianya-car-logo.jpg" />   <p>有人认为这是一次“反智主义”的胜利：</p>  <blockquote>   <p>回到我们前面谈到这个“27号”，它为什么表现了反智主义？很显然，在众多的设计作品中，有一些是由“知识精英”创作的，那些作品有他们的设计思想、美学理念，这些都可以统称为一种“知识性”或者“智识性”。而粗陋的27号与之相比基本上没有什么知识性可言，但是它获胜了，这说明，广大的投票者普遍地带有一种蔑视、否定设计知识的倾向，具有一种反智主义的态度，“恶意地”支持这样一个很糟糕的作品。</p> </blockquote>  <p>试想，如果您参与到这样一次投票中去，当每个参赛者都在不断展现他们优秀的设计，不断阐述这些设计背后的理念，原理，思考，含义，您的感觉如何？对我来说，我可能会感到不知所措。似乎现代人常常会有选择恐惧症，例如我去餐馆吃饭，在面临一大堆琳琅满目的选择时往往会不断左右摇摆，这也可以那也不错。此时，我最终可能就会选择那些“无需选择”的东西，例如我会每天去吃套餐，因为餐厅每天都会自行为我进行搭配，我要做的选择可能只是从3个荤菜里选择一个就行了。</p> <a href="http://images.cnblogs.com/cnblogs_com/jeffreyzhao/xyyyhtl-hhsw-1.jpg" target="_blank"><img class="floatRight" src="http://images.cnblogs.com/cnblogs_com/jeffreyzhao/xyyyhtl-hhsw-1.jpg" width="300" /></a>   <p>其实在知识扑面而来的现在，想要寻求一种纯粹的宁静的时刻也并非那么容易。最近还有一部动画电影非常火爆：“喜羊羊与灰太狼2：虎虎生威”，这部原本纯粹为儿童准备的动画片似乎也吸引了许多成年观众——包括我。在我看来，这部动画片与众不同的地方便是在众多商业大片的包围中显得如此富有童真，如此轻松愉快。它没有“2012”和“阿凡达”的惊人画面，甚至也远不如日式动画片中精美成熟的效果，但是在看这部片子的时候我不会想到玛雅文明与地球毁灭，强拆与钉子户，或是动画水平差距与<a href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=%E8%9C%A1%E7%AC%94%E5%B0%8F%E6%96%B0+%E6%8A%84%E8%A2%AD&amp;aq=f&amp;aqi=&amp;oq=">大嘴巴小新</a>——看过，笑过，忘掉，然后带着轻松的心情继续工作，继续生活，这可能也就够了。</p>  <p>简单点，有时也没什么不好的。</p>  <h1>程序员的爱情</h1>  <p>诚蒙机械工业出版社朋友们的垂青，他们会不定期地，在我丝毫不知情的状况下给我寄一些书来看。惊喜之余，这样做的毛病也就体现出来了——他们把书寄到我上一个公司的地址去了，因此我也才刚拿到这两本书：《<a href="http://www.douban.com/subject/4196673/">程序员的爱情</a>》和《<a href="http://www.douban.com/subject/4188128/">林立立成长记</a>》。</p> <a href="http://images.cnblogs.com/cnblogs_com/jeffreyzhao/programmer-love.jpg" target="_blank"><img class="floatRight" src="http://images.cnblogs.com/cnblogs_com/jeffreyzhao/programmer-love.jpg" width="150" /></a>   <p>我昨天出门前捎上了这本书，在路上将这本300页不到的书从头到尾匆匆翻了一遍。总体来说，我觉得这本书没什么价值。</p>  <p>为什么这么说呢？因为在我看来，这本书仅仅是打着的程序员的旗号而已。其中的男主人公的确是一个程序员，但是几乎没有对程序员的工作，程序员的生活有太多描写。换句话说，我们可以很轻易地将主人公改写为其他的职业——“程序员”在书中仅仅是一个标记，一个可有可无的东西，也并没有对小说的内容产生什么影响。在书的封面中写着“告诉你收获爱情的秘密”，但是书中男主人公最终的归宿，是和原本就一直喜欢他的海归漂亮姑娘结婚，而他们在一起的“方式”居然是因为男方失恋酒后乱性……哪儿有什么秘密啊，唯RP耳。</p>  <p>其实有时候我也怀疑作者是否真的是一个程序员（当然作者简介里给出了肯定的答案啦），因为对于程序员生活的描写很少，又基本是停留在表面，因此我觉得写出这些内容并不需要有亲身体会——从一些表面渠道来了解就行了（例如找个程序员朋友聊聊天，听听他们的抱怨）。此外，书中还有一些不符合实际的内容，例如第16章的开始：</p>  <blockquote>   <p>陈旭（男主人公）被提拔为项目组长后，主要负责协调和管理方面的工作，不再需要他编写代码了，但他依旧保持着对学习技术的巨大的热情，坚持要求自己每天写几百行代码。</p> </blockquote>  <p>我看到这“几百行”后立刻就被雷翻了。</p>  <p>这部小说是一个普通的故事，没有华丽的词藻，没有跌宕起伏的剧情，甚至包含一些奇怪的情景——例如男主人公的好友莫名其妙地车祸身亡，这似乎没有任何意义。但也正是这样的“普通”，我很愿意相信这个故事有个真实的蓝本，如果作者的确是一个程序员而不是个职业写手，如果作者并非是为了名利而是为了兴趣进行写作，那么我对于这部小说和作者本人还是非常尊敬的。</p>  <p>虽然我还是不喜欢，如果我是编辑，也不会出版这本书。如果您对它感兴趣，我觉得您可以去书店里捧着这本书看2个小时，或是先在CSDN上<a href="http://blog.csdn.net/theloveofprogrammer">浏览其连载</a>。</p>  <p>不知道什么时候开始流行起程序员小说了，例如之前有比较著名的《疯狂的程序员》，现在又出了这两本书。这两本书看起来还是挺受程序员群体追捧的。但是我读下来其实感觉都不怎么样，难道是因为程序员群体看到“亲切”的内容因此产生了好感吗？对于我在推特上对《程序员的爱情》的看法，图灵出版社的主编刘江老师评论到：</p>  <blockquote>   <p>其实小说比较代码难写多了，是门高超的技术，可惜有些出版社和某些作者就是不信。</p> </blockquote>  <p>我也很同意陈猫（@catchen）的说法：</p>  <blockquote>   <p>向人比較准確無誤地傳達信息，比向電腦准確無誤地傳達信息，要難得多，因為向人傳達嘅信息需要包括情感。程序員習慣無需向電腦傳達情感，所以……</p> </blockquote>  <p>当然，我还是十分建议程序员朋友们总结自己的所做所想，也算是锻炼自己的表达能力。事实上表达能力是优秀程序员的基本素养之一。呃……其实我觉得这句话有些奇怪，因为这本应该是每一个正常的“社会人”所具备的能力，但是慢慢地程序员似乎变成了木讷、不善言辞的群体。当然我遇见过许多不善表达的的程序员，他们可能连一个简单的问题也表达不清楚，但我也认识不少善于表达的程序员。</p>  <p>例如，我现在在盛大创新院的同事们，他们大都是很有想法，并乐于表达自己观点的人——甚至我觉得有时候这样的人太多，聚在一起时反而会有烦恼。上周在进行集体讨论的时候，要不是由主持人进行控制，一个人说着说着就很可能就停不下来了……我这个准话唠真有些插不上话的感觉。</p>  <p>兄弟们一定要锻炼好自己的表达能力（<a href="http://www.programmer.com.cn/1798/">Joel也这么说</a>）——而写写小说可能也是不错的方式。</p>  <h1>Nobody &amp; Sorry Sorry</h1>  <p>最近是各公司的举行年会的日子，每个公司年会上的节目自然大不相同。但是，如果把所有公司年会的节目取一个交集，您会发现必然会涉及到一个节目，那便是一个叫做Nobody的东东。</p> <a href="http://images.cnblogs.com/cnblogs_com/JeffreyZhao/168980/o_wg_nobody_pic1.jpg" target="_blank"><img src="http://images.cnblogs.com/cnblogs_com/JeffreyZhao/168980/r_wg_nobody_pic1.jpg" width="200" class="floatRight"/></a>   <p>如果您还不知道啥是Nobody，那么您实在是奥特曼了（如果您也不知道奥特曼是啥意思……）。话说由棒子国的几个“卖馄饨的小姑娘”组成了一个团体，<a href="http://www.youtube.com/results?search_query=Sorry+Sorry&amp;search_type=&amp;aq=f">Wonder Girls</a>，而她们最被人熟悉的单曲便是<a href="http://www.youtube.com/results?search_query=Wonder+Girls+Nobody&amp;search_type=&amp;aq=f">Nobody</a>。这首曲子已经被翻译为多种文字，这些小姑娘们也已经在全世界转了一大圈（去年底也来过上海）。当然，我一直觉得棒子文没啥好听的，而Nobody的流行也不是因为音乐或歌词，而是——扭啊扭，基本上就是用来诱惑男人的舞蹈。</p>  <p>有时候我们不得不佩服棒子国的编舞能力。Nobody能够在世界范围内的成功不是偶然，也不是靠着强大的整容技术搞出一个个近乎完美的身材相貌（许多朋友看“<a href="http://www.youtube.com/results?search_query=girls+generation&amp;search_type=&amp;aq=f">少女时代</a>”就是去看大腿的）。这方面另一个佐证便是<a href="http://www.youtube.com/results?search_query=Wonder+Girls+Nobody&amp;search_type=&amp;aq=f">Sorry Sorry</a>，而且这次是一群男人。现在Sorry Sorry的流行程度已经不亚于Nobody，不知道吸引了多少小女孩们的视线。而我看了<a href="http://www.youtube.com/watch?v=bqMq82S7OVQ&amp;feature=related">它的MV</a>也不得不承认，这帮小子真tmd的很帅。</p>  <p>如果你还是对它们的流行程度没有概念的话，看看菲律宾监狱集体版的<a href="http://www.youtube.com/watch?v=iVkKBHCVVbg">Nobody</a>和<a href="http://www.youtube.com/watch?v=_43TO_OPj-8&amp;feature=related">Sorry Sorry</a>吧——记得接着下巴哦。</p>  <p>当然，要说舞蹈技术，看过<a href="http://so.youku.com/search_video?q=%E8%88%9E%E6%9E%97%E4%BA%89%E9%9C%B8&amp;searchdomain=http%3A%2F%2Fso.youku.com&amp;searchType=video&amp;sbts=bar">舞林争霸</a>的人根本不会觉得棒子们有什么厉害的——那群百老汇级别的牛人们是真正的舞蹈家，他们的力量，技巧都非一朝一夕之功。<a href="http://v.youku.com/v_show/id_XMTQ3MjUwNjM2.html">他们的舞蹈</a>更令人震撼，但是远没有Nobody和Sorry Sorry那么流行，甚至永远不可能像后两者那样被那么多人模仿。道理很简单，因为棒子艺人的舞蹈能力有限，因此编舞只能设计一些技巧性不那么强的舞步，因此许多业余人士，学生，老师，警察，程序员……人人都能模仿，人人都能“传跳”。</p>  <p>其实这样的二分选择还有很多，各个行业都是如此。例如，李斯特的曲目在当时几乎只有他才能演奏（现在音乐学院的学生几乎个个不在话下），这给他带来了无限声望；而肖邦的许多作品在技术上容易许多，也更被人广泛接受——尤其是在我等业余人士中。那么，如果是您，您的选择是什么呢？</p>  <p>呃，Sorry Sorry的确不错，有机会我也要尝试一下。</p><img src="aggbug/1665473.html?type=0" width="1" height="1" alt=""/><p>评论: 62　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/play-novel-nobody-sorry-sorry.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/play-novel-nobody-sorry-sorry.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>总结：0 bug事件、交大ACM夺冠</title><link>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/0-bug-and-sjtu-acm-champion.html</link><dc:creator>Jeffrey Zhao</dc:creator><author>Jeffrey Zhao</author><pubDate>Sat, 06 Feb 2010 19:51:00 GMT</pubDate><guid>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/0-bug-and-sjtu-acm-champion.html</guid><description><![CDATA[<p>阅读: 7380 评论: 53 作者: <a href="" target="_blank">Jeffrey Zhao</a> 发表于 2010-02-07 03:51 <a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/0-bug-and-sjtu-acm-champion.html" target="_blank">原文链接</a></p><p>如果您还没有上<a href="http://twitter.com/" target="_blank">推特</a>（或是还没有想到办法上），那您失去的不光是一个风靡世界的网络应用，您同时还失去了一个优秀的信息获取平台及讨论环境。目前国内大部分靠谱的技术专家都在推特上有帐号，您几乎不会错失任何有价值的信息，更可以<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/03/twitter-talk-about-ms-dev-at-20100201.html" target="_blank">参与一些有价值讨论</a>。周六是休息日，因此也在推特上和大家聊得不亦乐乎。不过推特的一个缺陷可能便是难以留住有价值的信息，它们会随着时间推移渐渐消失，因此还是及时记录一下吧。</p>
<h1>0 bug事件</h1>
<p>0 bug事件原本什么都不是，只不过是有人使用非常普通、就事论事地方式，在豆瓣上指出了《0 bug》一书中不妥的地方。但是由于作者令人费解地谩骂和指责使&#8220;事态升级&#8221;。再由于网络上围观群众（<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/01/logic-is-not-everything.html" target="_blank">其中也有我的份</a>）与作者本身不断地进行&#8220;交锋&#8221;，0 bug事件终究一发不可收拾了。</p>
<p>其实我对这件事情已经不太在意了，因为我本来就是围观群众，而且目前0 bug事件已经出离了纯粹的技术讨论。不过现在我继续谈这个问题，是因为直接参与此次事件的双方又有新的动作了。首先是大牛<a href="http://www.cnblogs.com/miloyip/" target="_blank">Milo Yip</a>已经在园子里建立博客了，他的原话是希望&#8220;<font color="#ff0000">將會陸續把牆外的技術文章整理及分享</font>&#8221;，不过第一篇文章是<a href="http://www.cnblogs.com/miloyip/archive/2010/02/06/1665099.html" target="_blank">对0 bug事件的过程进行了系统的总结</a>；当然<a href="http://blog.csdn.net/tonyxiaohome/" target="_blank">0 bug</a>老师也没有闲着，他这几天还在勤劳地进行辩解。不久前又转载了一篇雄文《<a href="http://blog.csdn.net/tonyxiaohome/archive/2010/02/05/5291216.aspx" target="_blank">五毛党与网络打手</a>》，从始至终地坚持他的观点：此次事件是&#8220;敌对势力&#8221;在对他进行&#8220;有组织，有预谋&#8221;的抹黑。</p>
<p>而事情发展至今又有新的亮点，那便是CSDN的编辑同志们将此次事件相关的文章放上了首页。在此截图留念：</p>
<img src="http://images.cnblogs.com/cnblogs_com/jeffreyzhao/csdn-0bug.png?time=1265480825768" alt="" />
<p>哈，前两篇都是。<a href="http://blog.csdn.net/Raptor/archive/2010/02/05/5290875.aspx" target="_blank">第一篇文章</a>指出了0 bug老师在此次事件中的问题所在，其中一点正好回应了0 bug老师的观点：</p>
<blockquote>
<p>按我以前接触过的国内出版业人士来看，肖老师在BLOG里说的&#8220;书黑&#8221;这种事情在中国的确很可能发生。但是他的错误在于，把所有提意见的读者都当成了 书黑，这未免有点被迫害妄想过头了吧。要知道，请一帮网络黑社会也是要花不少钱的，一个编辑做一本书赚的钱估计是不够的，更何况目标还是这样一技术含量比 较高的书。 </p>
<p>其实光是从Milo指出的几个问题来看，他就不可能是什么书黑，哪有C++水平这么高的书黑&#8212;&#8212;要是C++功力这么深还当什么书黑啊，书黑能赚几个钱。而作者连这点都看不出来，显然他的C++功力也不怎么样，以此推断，那本书显然也的确不怎么样。</p>
</blockquote>
<p>而<a href="http://blog.csdn.net/tonyxiaohome/archive/2010/02/05/5290195.aspx" target="_blank">第二篇文章</a>的作者正是0 bug老师本人，其主要意思是指目前指出的问题似乎都有&#8220;无中生有&#8221;的感觉，因为这些&#8220;攻击&#8221;根本没有找准位置。</p>
<p>0 bug老师是<a href="http://student.csdn.net/" target="_blank">CSDN学生大本营</a>的头牌，因此CSDN的态度对于这个事件的意义重大。而这次CSDN首页推荐的作法，我个人看来已经是一种表态了。因为这两篇文章，无论是对&#8220;技术&#8221;及&#8220;产业&#8221;来说都几乎没有意义，推荐它们的原因似乎只是为了揭露0 bug事件本身。很明显，0 bug事件对于CSDN来说并不光彩，而CSDN的编辑同志没有遮掩，将其公开地表达出来，我想他们在这个问题上的确值得我们尊敬。</p>
<p>就我的看法，0 bug事件可以说是继《<a href="http://www.cnblogs.com/jeffreyzhao/archive/2009/09/23/1572868.html" target="_blank">JavaScript征途</a>》之后又一个和技术图书出版有关的经典案例了，两者的相同之处在于作者对于读者所指出的&#8220;硬伤&#8221;都采取了类似的态度。上次的事件似乎已经平息，只有<a href="http://www.google.com/search?hl=en&amp;ei=_8ttS5DKBsyIkAW4zrHUBw&amp;sa=X&amp;oi=spell&amp;resnum=0&amp;ct=result&amp;cd=1&amp;ved=0CBcQBSgA&amp;q=JavaScript+%E5%BE%81%E9%80%94&amp;spell=1" target="_blank">搜索引擎中的头条</a>清楚地记录着相关内容。我真的希望图书出版行业的这类经典案例可以少一些&#8212;&#8212;亦或是多出现一些，以此推动一个革命，最终改变目前令人难堪的现状？</p>
<p>在推特上，<a href="https://twitter.com/jasonlai" target="_blank">@jasonlai</a>同学发表了一些看法：</p>
<blockquote>
<p>老话，咱圈真乱。另外，国内技术媒体和出版圈子还是需要提高一下道德底线啊，出书审校不负责任，写软文换赞助的事情比比皆是。最近小关注了一下<a href="http://www.techcrunch.com/2010/02/04/an-apology-to-our-readers/" target="_blank">TechCrunch炒掉写软文实习生的事件</a>，感触颇深，能那样做才是受尊重的媒体。</p>
<p>仔细看了某口水战事件的讨论始末。有知识没文化真恐怖啊，某&#8220;大师&#8221;的气度，<a href="http://www.danielbru.com/2010/02/the-line-was-crossed/" target="_blank">还不如一个17岁小孩</a>。</p>
</blockquote>
<p>说到这里，我想起在我的博客上有朋友回复说，写《JavaScript征途》的朱老大最近又有一本新书《<a href="http://www.china-pub.com/49015" target="_blank">Flash CS4基础与案例教程</a>》出版发行了。我在这里谨代表我个人（请注意，不代表其他人哦）表示恭喜，并对国内有如此高产的作者感到自豪。让我们欢呼吧！</p>
<h1>交大ACM夺冠</h1>
<p>交大牛啊，继2002及2005年之后，他们<a href="http://news.csdn.net/a/20100205/216923.html" target="_blank">再次获得了ACM竞赛的世界冠军</a>！想当年我也在信息学奥林匹克竞赛的道路上探索过，但由于直升大学时被交大拒绝，一气之下报考复旦大学，从此改变了我的人生轨迹&#8212;&#8212;呃，扯远了，没别的意思，还是回到这则新闻上来。</p>
<p>不过，奇怪的是，似乎很多人的对这个事件还是发表了许多在我看来毫无道理负面评价（当然并不是所有的负面评价都是没有道理的，例如说ACM夺冠对于国内普遍现状几乎没有帮助，这我同意）。具体地就不多提了，您可以自己去看新闻后面的回复。我想说的是，我这次真的想用&#8220;喷子&#8221;来形容某些人了。</p>
<p>的确，国内大学教育是有很多问题，你们的失望我可以理解，但是为什么那么倾向于&#8220;轻视&#8221;一个东西？的确，交大的弟兄们是非常重视ACM竞赛，但是他们的确通过刻苦训练拿到了世界冠军，这一点不假。嗯，你可能会说&#8220;ACM这种比赛没有什么意义，考题海战术取胜，胜在中国人最擅长的应试教育，否则为什么拿了那么多次世界冠军，那些搞ACM的人最终成功的有几个？&#8221;那么我们现在就来讨论这个问题吧。</p>
<p>其实以前也有过类似的问题，便是&#8220;中科大少年班&#8221;。有许多人质疑对此类少年天才的培养方式&#8212;&#8212;的确，可能这种方法自有其不科学之处，但是类似于&#8220;除了张亚勤之外又有谁成功了&#8221;这样的论据我是非常不屑与之辩驳的。对此我只想问几个问题：成功的标准是什么？所有成功的人你都认识吗？</p>
<p>这里我不想谈什么&#8220;金钱不是唯一标准&#8221;等会被人耻笑为&#8220;幼稚&#8221;的道理，我们就拿钱来说吧。我举个例子，世界上有许多大型银行或是企业，他们的总裁，或是副总等高管都是有钱人，可谓非常成功，但是你现在能够说出其中几个人的名字？再问，就拿微软来说，除了盖兹，鲍尔默等人，你又能说出多少人呢？微软的<a href="http://www.microsoft.com/presspass/exec/techfellow/default.mspx" target="_blank">Technical Fellows</a>以及<a href="http://www.microsoft.com/presspass/exec/de/default.mspx" target="_blank">Distinguished Engineers</a>也都很成功（即使只谈钱），但是这几十人中你又认识多少人呢？</p>
<p>是啊，成功的人太多了，不能因为你没有听说过就&#8220;认定&#8221;他们不成功。事实上，无论是ACM冠军选手或是中科大少年班的成员，他们中的大部分在社会地位还是经济方面都是普通人难以项望其背的。只不过，他们没有让你们知道而已。例如，他们可能出国深造，成为顶尖的科研人员或是教授，享受着几十万美元的年薪，过着滋润的生活。你可能连Jim Gray都不知道是谁，不知道他们不是很正常的事情吗？</p>
<p>其实我在学校的时候也一直关注ACM成员，事实上我就没有发现有哪个ACM高手是写不好程序的。</p>
<p>Oren Eini写过<a href="http://ayende.com/Blog/archive/2009/12/12/setting-the-record-straight-i-am-not-the-main-contributor.aspx" target="_blank">这么一篇文章</a>，其中心思想是：</p>
<blockquote>
<p>I am not the main contributor (of NHibernate), I am just the loudest one.</p>
</blockquote>
<p>这句话的说法一点没错。就拿我来说，我<font color="#ff0000">不是</font>最好的.NET程序员，我只不过是在博客园积分最多，并且可能最积极参与社区活动而已。如果要正确定位我在社区中的表现，也只（可能）是loudest，而远远谈不上，甚至永远不可能是best。要在技术社区中产生正面的影响力，水平只是一方面，而&#8220;其他某些方面&#8221;也是非常重要的。记得网络红人<a href="http://blog.sina.com.cn/ayawawa" target="_blank">ayawawa</a>说过这么一句话：</p>
<blockquote>
<p>比我漂亮的都没我聪明，比我聪明的都没我漂亮。</p>
</blockquote>
<p>那么我也来说一句类似的：</p>
<blockquote>
<p>比我会吹牛的技术都没我好，技术比我好的都没我会吹牛。</p>
</blockquote>
<p>所以，我也就是一个小样儿而已&#8212;&#8212;但是我还是自信比ACM事件中大部分无理由的喷子们要强上不少。</p>
<p>五毛与无美分无异。</p>
<img src="aggbug/1665244.html?type=0" width="1" height="1" alt=""/><p>评论: 53　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/0-bug-and-sjtu-acm-champion.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/07/0-bug-and-sjtu-acm-champion.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>每一个社区成员，用你的努力为微软平台的开发技术添上一把柴！</title><link>http://www.cnblogs.com/Barton131420/archive/2010/02/05/1664559.html</link><dc:creator>双鱼座</dc:creator><author>双鱼座</author><pubDate>Fri, 05 Feb 2010 09:18:00 GMT</pubDate><guid>http://www.cnblogs.com/Barton131420/archive/2010/02/05/1664559.html</guid><description><![CDATA[<p>阅读: 1752 评论: 55 作者: <a href="" target="_blank">双鱼座</a> 发表于 2010-02-05 17:18 <a href="http://www.cnblogs.com/Barton131420/archive/2010/02/05/1664559.html" target="_blank">原文链接</a></p><p>我必须先声明，我不愿意陷入平台之争，如果有人要争，恕不奉陪。</p><p>昨天园子里有篇文章，就一个Session的访问问题写了一篇<a target="_blank" href="http://www.cnblogs.com/tsoukw/archive/2010/02/04/1663814.html">文章</a>，批评ASP.NET的不足，而且莫名其妙的一个结论是&#8220;ASP.NET不能构建大型Web应用&#8221; 。无厘头。<br /></p><p>其实这个很正常，毕竟这么大一个社区鱼龙混杂的。 不正常的是有些社区大佬们没有站出来，反而有点站在旁边看热闹的味道。我想说的是，你以为与你无关吗？<br /></p><p>昨天一进入博客园，看到编辑推荐：<a target="_blank" href="http://news.cnblogs.com/n/56508/">微软创新性忆遭毁灭</a>。无独有偶。前几天和一个以前的同事聊天，他告诉我，他们所签的项目，基本上都在50万以上(非微软平台)，很多都可以由一个应届生在一两周内搞定。而同样的项目，在你们公司最多只能签10万(因为我们用的是微软平台)。当然，这是客户的选择，我们没有理由说三道四，也不必气馁。不过我想说的是，你不要以为客户的选择与你无关。如果你选择了微软平台，你的利益、你的前途通通与微软平台捆在一起。你的呼声、你的诉求很多时候会影响到你的周围。<br /></p><p>并不是因为我对微软有多么拥趸，而是我们天天都在面临实实在在的不公平。由于微软在业界的垄断地位，很多人，当然主要是竞争对手，他们是希望这个巨人倒下来的，种种的不公平也就是一件非常自然的事情。当然，我从来不担心微软真的会倒掉。问题是作为微软平台受益者的你我，是否有勇气站出来喊一声NO！至少对于我来说，当我能够用Lambda高效地写出代码的时候；当我们使用WCF、WPF、WF和SL等技术的时候，我觉得微软在开发平台方面要领先其他平台开发技术5年以上，并且这个距离正在迅速拉大！<br /></p><p>从来就没有什么救世主，一切靠我们自己！所以，我邀请所有微软平台的开发者们，向你周围的人公正地宣传微软技术，用你精湛的技艺给属于你的微软平台的开发技术增加光彩！<img src="http://www.cnblogs.com/Emoticons/qface/055243929.gif" alt="" /></p><img src="aggbug/1664559.html?type=0" width="1" height="1" alt=""/><p>评论: 55　<a href="http://www.cnblogs.com/Barton131420/archive/2010/02/05/1664559.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/Barton131420/archive/2010/02/05/1664559.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>创造自己的“最佳实践”</title><link>http://www.cnblogs.com/tengzy/archive/2010/02/04/1664022.html</link><dc:creator>Daniel Teng</dc:creator><author>Daniel Teng</author><pubDate>Thu, 04 Feb 2010 15:10:00 GMT</pubDate><guid>http://www.cnblogs.com/tengzy/archive/2010/02/04/1664022.html</guid><description><![CDATA[<p>阅读: 1193 评论: 8 作者: <a href="" target="_blank">Daniel Teng</a> 发表于 2010-02-04 23:10 <a href="http://www.cnblogs.com/tengzy/archive/2010/02/04/1664022.html" target="_blank">原文链接</a></p><span style="border-collapse: separate; color: #000000; font-family: Arial; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; "><div><font color="#000000" face="Arial" size="3"><span style="font-size: 12pt; ">二战时期的南太平洋Tanna小岛(瓦努阿图，<font color="#000000" face="Arial" size="3"><a href="http://news.bbc.co.uk/2/hi/asia-pacific/6370991.stm" target="_blank"><span style="font-size: 12pt; ">http://news.bbc.co.uk/2/hi/asia-pacific/6370991.stm</span></a><font color="#000000" face="Arial" size="3"><span style="font-size: 12pt; ">)上，由于盟军把岛屿作为基地，飞机不断地把包括食品，生活用品在内的各种补给送到岛上。幸运的岛上土著居民也分享了很多免费食品，生活用品。二战结束以后盟军撤离了该岛，但是居民对这种免费午餐还是念念不忘，始终希望好运能够再次降临。于是他们开始模仿占领部队的种种行为。居民们精心制作了军服，把木头雕成枪的样子，他们甚至用最基本的原材料组装了一架与真实飞机一样大小的&#8220;飞机&#8221;。他们甚至还模仿盟军当年训练的样子在村庄内行军...。这甚至成了一种宗教。人们把这种现象叫做<a href="http://en.wikipedia.org/wiki/Cargo_cult" target="_blank"><span style="font-size: 12pt; ">货物崇拜</span></a></span><span style="font-size: 12pt; ">。大家肯定觉得这很好笑，因为任何明眼人都会看出这些土著居民没有理解发生在他们周围这些事情背后的原理，而这种通过片面模仿外部表象是没有可能再得到&#8220;上天&#8221;的眷顾的。</span></font></font></span></font></div><p><img src="http://images.cnblogs.com/cnblogs_com/tengzy/FrumParade.jpg" width="280" height="308" alt="" />&nbsp;<img src="http://images.cnblogs.com/cnblogs_com/tengzy/vanuatu.jpg" width="300" height="300" alt="" /><img src="http://images.cnblogs.com/cnblogs_com/tengzy/cargo-cult-plane.jpg" width="500" height="376" alt="" /><img src="http://images.cnblogs.com/cnblogs_com/tengzy/cargo-cult-waiting.jpg" width="300" height="205" alt="" /></p><div><span style="font-size: 12pt; ">其实这种现象在号称&#8220;成功&#8221;实施敏捷团队中也十分普遍，以至于敏捷社区给这种现象起了一个专有名词，&#8220;货物崇拜敏捷&#8221;(</span><a href="http://jamesshore.com/Blog/Cargo-Cult-Agile.html" target="_blank"><span style="font-size: 12pt; ">Cargo Cult Agile</span></a>&nbsp;<div><font color="#000000" face="Arial" size="3"><font color="#000000" face="Arial" size="3"><span style="font-size: 12pt; ">)</span><font color="#000000" face="Arial" size="3"><font color="#000000" face="Arial" size="3"><font color="#000000" face="Arial" size="3">&nbsp;</font><span style="font-size: 12pt; ">。Jeff Sutherland说过75%的Scrum团队都不是在做Scrum而是ScrumBut。很多团队不能做到自主管理；很多不能在Sprint的结束时候发布测试过的产品；很多Sprint Backlog中所谓的用户故事对客户根本没有价值；不少号称用故事点来进行计划估算的Scrum团队，团队成员甚至不知道一个故事点代表什么，因为他们是被告诉下一个迭代需要完成什么，大约是多少故事点；很多团队的Retrospective和Review流于形式。尽管绝大多数团队都在实践Scrum的各种实践，都有Sprint计划，Daily Scrum，都有Retrospective，都在用用户故事&amp;故事点。这绝不是Scrum。他们只看到Scrum的形，没有领会到Scrum的神、价值观，也不明白Scrum、用户故事背后的道理。而这其实就是敏捷过程与传统的软件模型的最大区别。传统方式更在乎的是形式，而敏捷更加在乎的是<strong>价值观</strong>、<strong>原则</strong>。</span></font></font></font></font></div></div><div><font color="#000000" face="Arial" size="3"><font color="#000000" face="Arial" size="3"><span style="font-size: 12pt; ">我们整个行业都十分热衷于&#8220;最佳实践&#8221;，出版社为了迎合市场，也会出版很多&#8220;最佳实践&#8221;类的书籍。为什么？因为简单！不需要思考，只要把书上的东西原封照搬下来就可以用了。但是这样做十分危险，因为任何&#8220;最佳实践&#8221;都是有一个应用环境的。脱离了应用环境，&#8220;最佳实践&#8221;就不那么有效了。很多团队其实就是照着Henrik Kniberg的&#8220;</span><a href="http://www.infoq.com/cn/minibooks/scrum-xp-from-the-trenches" target="_blank"><span style="font-size: 12pt; ">硝烟中的Scrum和XP</span></a><span style="font-size: 12pt; ">&#8221;开始实践Scrum，认为Scrum就是这样子。但是他们忽略了Henrik在书中的很重要的免责声明&#8220;</span><em style="font-size: 12pt; ">这篇文档讲述的不是&#8220;正确&#8221;实现Scrum的方式！它只是表明了一种方式，是我们在一年内不断修正调整后的结果。你也可以认为我们的做法是完全错误的。</em>&#8221;Scrum的创始人Ken Schwaber也说过&#8220;<em>如果你是从一本Scrum烹饪手册照搬来实践Scrum，那就你做的就不是Scrum了。</em>&#8221;</font></font></div><div><font color="#000000" face="Arial" size="3"><font color="#000000" face="Arial" size="3"><span style="font-size: 12pt; ">最近读Don Reinersten比较多，深受其影响（</span><a href="http://www.amazon.com/Managing-Design-Factory-Donald-Reinertsen/dp/0684839911" target="_blank"><span style="font-size: 12pt; ">Managing the Design Factory</span></a><span style="font-size: 12pt; ">，</span><a href="http://www.infoq.com/presentations/2nd-gen-lean" target="_blank"><span style="font-size: 12pt; ">Second Generation Lean Product Development: From Cargo Cult to Science</span></a><span style="font-size: 12pt; ">），感触最深的就是我们对待任何事情都应该采用一种</span><strong style="font-size: 12pt; ">Science Approach</strong><span style="font-size: 12pt; ">而不是</span><strong style="font-size: 12pt; ">Faith Approach</strong><span style="font-size: 12pt; ">。任何的实践和工具没有好坏，都有其适用的环境及背后的原理。如果我们总是盲目跟着流行走，跟着书本或者大师们走，那其实就是Faith Approach，那我们跟Tanna小岛上的土著居民没有区别。因此我们要有意识的使用Science Approach，去了解这些实践和工具背后的原理。了解为什么要Limit WIP？什么时候用Pull？什么时候用Push？是不是要不停的Eliminate Waste？什么时候用Kanban？什么时候用Scrum？产品开发的测试应该怎样做？产品生产的测试应该怎样做？等等。了解了这些工具背后的原理和理论（排队理论Queueing Theory、约束理论Theory of Constraints、信息理论Information Theory、系统化思维System Thinking等等），很容易就能创造出自己的"最佳实践"。</span></font></font></div></span><img src="aggbug/1664022.html?type=0" width="1" height="1" alt=""/><p>评论: 8　<a href="http://www.cnblogs.com/tengzy/archive/2010/02/04/1664022.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/tengzy/archive/2010/02/04/1664022.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>事务与系统架构设计</title><link>http://www.cnblogs.com/WizardWu/archive/2010/02/04/1663127.html</link><dc:creator>WizardWu</dc:creator><author>WizardWu</author><pubDate>Wed, 03 Feb 2010 19:18:00 GMT</pubDate><guid>http://www.cnblogs.com/WizardWu/archive/2010/02/04/1663127.html</guid><description><![CDATA[<p>阅读: 1736 评论: 7 作者: <a href="" target="_blank">WizardWu</a> 发表于 2010-02-04 03:18 <a href="http://www.cnblogs.com/WizardWu/archive/2010/02/04/1663127.html" target="_blank">原文链接</a></p><p>做项目或系统设计时，依需求的不同，适必有不同的解决方案，有的以性能为主，有的以可扩展性为主，有的为了日后易于维护而做大量的组件化。本帖依此提供三种不同特性的「事务」ASP.NET 示例下载，包括：用一个数据库 Connection 即可高性能跨数据库写入、透过组件的函数调用即可参与事务、异步 (Asynchronous) 执行事务。</p>
<p>&nbsp;</p>
<p>三个 ASP.NET 示例，其「事務」特性分別為：</p>
<p>(1) <span style="background-color: #c0c0c0;">兼顾性能与功能</span> - 利用 SqlConnection 类的 ChangeDatabase 方法，在单一个 Connection 中，跨越本机的两个数据库做 LTE (轻量级) 事务。<br />(2) <span style="background-color: #c0c0c0;">追求良好的架构、组件化及可维护性</span> - 利用 TransactionScope 类 + MS DTC，直接经由各组件之间的函数调用，将其纳入同一个事务，亦可升级为 OleTx 分布式事务。<br />(3) <span style="background-color: #c0c0c0;">重视回应速度与用户体验</span> - 利用 CommittableTransaction + AsyncCallback 类，进行明确式的「异步 (Asynchronous)」事务。</p>
<p>&nbsp;</p>
<p>-------------------------------------------------<br />本帖的示例下载点：<br /><a href="http://files.cnblogs.com/WizardWu/100204.zip">http://files.cnblogs.com/WizardWu/100204.zip</a><br />(执行第一個示例，需要 SQL Server 的 Northwind、AdventureWorksDW 数据库，不需要 DTC)<br />(执行第二個示例，需要 SQL Server 的 Northwind 数据库，并事先设置好 Windows 上的&nbsp;DTC 分布式事务处理协调器)<br />(执行第三個示例，需要 SQL Server 的 Northwind 数据库，不需要 DTC)<br />---------------------------------------------------</p>
<p>&nbsp;</p>
<p><span style="color: #008080;">(一) 示例一：兼顾性能与功能</span></p>
<p><span style="color: #008080;">&nbsp;</span>&nbsp;</p>
<p>有时我们只是临时需要在某一台机器上的 SQL Server，跨越其中的两个数据库做事务处理，或是其他一些简易的本机事务处理，此时只要透过一些 ADO.NET 的小技巧，利用同一个 Connection 对象，和最传统的 SqlTransaction 即可办到。如下方代码，透过 SqlConnection 的 ChangeDatabase 方法，即可在 Northwind、AdventureWorksDW 两个数据库之间切换，无须大费周章地升级为分布式事务，或浪费资源创建两次数据库的 Connection。</p>
<p>&nbsp;</p>
<div onclick="cnblogs_code_show('ff6fd995-6aa7-4716-a1c2-0d3ed07238bb')" class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" class="code_img_closed" id="code_img_closed_ff6fd995-6aa7-4716-a1c2-0d3ed07238bb" /><img src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" onclick="cnblogs_code_hide('ff6fd995-6aa7-4716-a1c2-0d3ed07238bb',event)" class="code_img_opened" id="code_img_opened_ff6fd995-6aa7-4716-a1c2-0d3ed07238bb" style="display: none;" /><span class="cnblogs_code_collapse">示例一</span>
<div class="cnblogs_code_hide" id="cnblogs_code_open_ff6fd995-6aa7-4716-a1c2-0d3ed07238bb">
<pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">protected</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> Button1_Click(</span><span style="color: #0000ff;">object</span><span style="color: #000000;"> sender, EventArgs e)<br />    {<br />        SqlConnection cn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlConnection(</span><span style="color: #800000;">"</span><span style="color: #800000;">server=localhost;database=Northwind;integrated security=true</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br />        SqlTransaction tx </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />        </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />        {<br />            cn.Open();<br />            tx </span><span style="color: #000000;">=</span><span style="color: #000000;"> cn.BeginTransaction();<br />            SqlCommand cmd1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlCommand(</span><span style="color: #800000;">"</span><span style="color: #800000;">INSERT INTO Employees (LastName, FirstName) VALUES('Wu', 'Wizard')</span><span style="color: #800000;">"</span><span style="color: #000000;">, cn);<br />            cmd1.Transaction </span><span style="color: #000000;">=</span><span style="color: #000000;"> tx;<br />            cmd1.ExecuteNonQuery();</span></div><span style="color: #000000;"><div><br /><br />            cn.ChangeDatabase(<span style="background-color: #f5f5f5; font-family: Courier New;">"AdventureWorksDW");</span></div><div><span style="color: #000000;"><br /><br />            SqlCommand cmd2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlCommand(</span><span style="color: #800000;">"</span><span style="color: #800000;">INSERT INTO DimGeography (City) VALUES ('Taipei')</span><span style="color: #800000;">"</span><span style="color: #000000;">, cn);<br /><br />            cmd2.Transaction </span><span style="color: #000000;">=</span><span style="color: #000000;"> tx;<br /><br />            cmd2.ExecuteNonQuery();<br />            tx.Commit();<br />            Response.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">跨越两个数据库的 LTE 本机事务成功 !</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br />        }<br />        </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SqlException ex)<br />        {<br />            tx.Rollback();<br />            Response.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">发生错误: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> ex.Message);<br />        }<br />        </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"><br />        {            <br />            cn.Close();<br />            cn.Dispose();<br />        }<br />    }</span></div></span></pre>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;市面上有好几本专讲 ADO.NET 的中、英文书籍，内容都相当不错，只可惜这方面的议题较少受到重视。</p>
<p>&nbsp;</p>
<p>----------------------------------------------------------------------------</p>
<p>&nbsp;</p>
<p><span style="color: #008080;">(二) 示例二：追求良好的架构、组件化及可维护性</span></p>
<p>&nbsp;</p>
<p>有些写 Java 或比较重视架构设计的工程师，常会将一些特定的功能或商业逻辑，各自封装在多个组件或类之中 (Java 中的 Bean 或 SessionBean)。微软方面，自从 .NET 2.0 问世、TransactonScope 类和新世代的事务管理机制出现后，以往用 COM+ 的写法才能达到的功能，现在用 TransactonScope 类竟然很轻松地就能达成，这让 OOA/OOD、面向对象和 Design Patterns 的爱好者，在 .NET 平台上有了很好的解套方式。亦即可让对象的行为，在架构设计上能够独立，但却能随时决定是否要参与某个事务，或动态地决定是否要从 Local 事务升级成分布式事务。</p>
<p>例如下方的代码，为两个类 (或组件) 里各自的函数，他们可能是 ERP 中的「订单产生」组件，要调用「仓库对象」组件，去扣除一些库存量。透过「巢状 (nested)；嵌套」的二或多个&nbsp; TransactonScope 类，以及函数的直接调用，即可将对方纳入此一事务，并可自定义是否要纳入成为同一个事务，并且升级成分布式事务、启动 DTC，抑或拆分成两个事务、不启动 DTC。且不论是哪种选项，都能达到任一方抛出 Exception 时，双方都能自动 Rollback。</p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000;">Class1</span><span style="color: #000000;"><br />{<br />    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> func1()<br />    {<br />        </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> (TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope())<br />        {<br />            Class2 c2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Class2();<br />            c2.func2();    </span><span style="color: #008000;">//</span><span style="color: #008000;">调用另一个组件的函数，直接将它纳入事务</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scope.Complete();<br />        }<br />    }<br />}</span></div><div><span style="color: #000000;"><br /><br />Class2</span><span style="color: #000000;"><br />{<br />    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> func2()<br />    {<br />        </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> (TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope())<br />        {<br />            scope.Complete();<br />        }<br />    }<br />}<br /></span></div></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>下图 1 为本帖下载示例 - 示例二的执行画面。如前述，我们用两个 Class 中函数调用的做法，但 Class 1、Class 2 的 TransactionScope，其 TransactionScopeOption 都设置为 Required (若已有现存的事务，则参与该个事务)，表示双方要加入「同一个」事务中。因此 Class 1 所插入数据库的一条记录，Class 2 立即可 SELECT 得到它，因为他们是在「同一个」事务中。但代价是会启动 MS DTC、自动升级成 OleTx 分布式事务。虽然这两个 Class 是在同一台机器中，但因为在同一个事务中，开启了两条数据库的 Connection，因此仍会自动从本机的轻量级 LTM 事务管理员，升级成 OleTx 事务管理员 (依赖 RPC 远端程序调用)，也因此会自动启用 MS DTC (若 DTC 已设置好)。</p>
<p>但若您把 Class 2 的 TransactionScope，其 TransactionScopeOption 设置为 RequiresNew (不管是否有现存事务，都一律创建新的事务)，您会发现 MS DTC 不会启动了，因为他们已被拆分成「二个事务」，也因此 Class 1 所插入数据库的一条记录，Class 2 已无法立即 SELECT 取得，因为他们不在「同一个」事务中。</p>
<p>&nbsp;</p>
<p>但不论是前述哪种做法，仍都能达到任一方引发 Exception 时，双方都能自动 Rollback。若您以前，曾经梦想透过 Web Service 彼此的调用，来达到事务的完整性，会发现情形如同前述的第二种，亦即被拆分成「二个事务」，虽然任一方抛出 Exception 时，双方都能自动 Rollback，但由于是拆分成二个事务，因此第一个 Web Service 所插入数据库的一条记录，第二个 Web Service&nbsp;无法立即取得。而这点，就某些系统的设计需求上，虽然看似小瑕疵，却是不被允许的。可能有些人宁愿用第一种做法，包成「同一个」事务，宁可启动 MS DTC，牺牲一些性能，也要达成事务的高度完整性。 </p>
<p>&nbsp;</p>
<p><img src="http://pic002.cnblogs.com/img/wizardwu/201002/2010020402210667.jpg" /><br /><span style="background-color: #ffff99;">图 1　示例二的执行画面</span></p>
<p>&nbsp;</p>
<div onclick="cnblogs_code_show('6cd88f54-11b9-4a25-9baa-1b1362ecdeda')" class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" class="code_img_closed" id="code_img_closed_6cd88f54-11b9-4a25-9baa-1b1362ecdeda" /><img src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" onclick="cnblogs_code_hide('6cd88f54-11b9-4a25-9baa-1b1362ecdeda',event)" class="code_img_opened" id="code_img_opened_6cd88f54-11b9-4a25-9baa-1b1362ecdeda" style="display: none;" /><span class="cnblogs_code_collapse">示例二的 Class1 (组件一)</span>
<div class="cnblogs_code_hide" id="cnblogs_code_open_6cd88f54-11b9-4a25-9baa-1b1362ecdeda">
<pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">using</span><span style="color: #000000;"> System;<br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Data;<br /><br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Transactions;<br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Data.SqlClient;<br /><br /></span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Class1<br />{<br />    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strConnString </span><span style="color: #000000;">=</span><span style="color: #000000;"> System.Configuration.ConfigurationManager.ConnectionStrings[</span><span style="color: #800000;">"</span><span style="color: #800000;">Conn_Northwind</span><span style="color: #800000;">"</span><span style="color: #000000;">].ToString();<br /><br />    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Class1()<br />    {<br />    }<br /><br />    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> func1()<br />    {<br />        SqlConnection conn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />        SqlCommand cmd </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />        </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> intTheNewestID </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;<br />        </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strReturn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">""</span><span style="color: #000000;">;<br /><br />        </span><span style="color: #008000;">//</span><span style="color: #008000;">Insert 后，立即 Select 出数据库最新插入的这一笔记录，其 id 值 (identity, 由数据库自动增号)</span><span style="color: #008000;"><br /></span><span style="color: #000000;">        </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strSql </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">INSERT INTO Employees (LastName, FirstName) VALUES('Wu', 'Wizard') ; SELECT @@identity; </span><span style="color: #800000;">"</span><span style="color: #000000;">;<br /><br />        </span><span style="color: #008000;">//</span><span style="color: #008000;">Required 选项: 当前环境若无事务，则创建新事务，否则就加入当前环境的同一个事务</span><span style="color: #008000;"><br /></span><span style="color: #000000;">        </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> (TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope(TransactionScopeOption.Required))<br />        {<br />            </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />            {<br />                conn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlConnection(strConnString);<br />                conn.Open();<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (conn.State </span><span style="color: #000000;">==</span><span style="color: #000000;"> ConnectionState.Open)<br />                {<br />                    cmd </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlCommand(strSql, conn);<br />                    intTheNewestID </span><span style="color: #000000;">=</span><span style="color: #000000;"> Convert.ToInt32(cmd.ExecuteScalar());<br /><br />                    </span><span style="color: #008000;">//</span><span style="color: #008000;">调用 Class 2 的函数，将其也加入同一个事务</span><span style="color: #008000;"><br /></span><span style="color: #000000;">                    Class2 c2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Class2();<br />                    strReturn </span><span style="color: #000000;">=</span><span style="color: #000000;"> c2.func2(intTheNewestID);<br /><br />                    scope.Complete();<br />                }<br />            }<br />            </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception ex)<br />            {<br />                </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Exception(</span><span style="color: #800000;">"</span><span style="color: #800000;">组件一 - 发生数据库访问错误: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> ex.ToString());<br />            }<br />            </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"><br />            {<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (cmd </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br />                    cmd.Dispose();<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (conn.State </span><span style="color: #000000;">==</span><span style="color: #000000;"> ConnectionState.Open)<br />                {<br />                    conn.Close();<br />                }<br />                conn.Dispose();<br />            }<br />        }<br /><br />        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> strReturn;    </span><span style="color: #008000;">//</span><span style="color: #008000;">返回前台的网页中显示</span><span style="color: #008000;"><br /></span><span style="color: #000000;">    }<br />}<br /></span></div></pre>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div onclick="cnblogs_code_show('14ed166d-c9ef-4fee-ac7f-413aa5ae5ab2')" class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" class="code_img_closed" id="code_img_closed_14ed166d-c9ef-4fee-ac7f-413aa5ae5ab2" /><img src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" onclick="cnblogs_code_hide('14ed166d-c9ef-4fee-ac7f-413aa5ae5ab2',event)" class="code_img_opened" id="code_img_opened_14ed166d-c9ef-4fee-ac7f-413aa5ae5ab2" style="display: none;" /><span class="cnblogs_code_collapse">示例二的 Class2 (组件二)</span>
<div class="cnblogs_code_hide" id="cnblogs_code_open_14ed166d-c9ef-4fee-ac7f-413aa5ae5ab2">
<pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">using</span><span style="color: #000000;"> System;<br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Data;<br /><br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Transactions;<br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Data.SqlClient;<br /><br /></span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Class2<br />{<br />    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strConnString </span><span style="color: #000000;">=</span><span style="color: #000000;"> System.Configuration.ConfigurationManager.ConnectionStrings[</span><span style="color: #800000;">"</span><span style="color: #800000;">Conn_Northwind</span><span style="color: #800000;">"</span><span style="color: #000000;">].ToString();<br /><br />    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Class2()<br />    {<br />    }<br /><br />    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> func2(</span><span style="color: #0000ff;">int</span><span style="color: #000000;"> intTheNewestID)<br />    {<br />        SqlConnection conn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />        SqlCommand cmd1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />        SqlCommand cmd2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />        </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> intInserted </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;<br />        </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strReturn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">""</span><span style="color: #000000;">;<br />        </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strSql1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">INSERT INTO Employees (LastName, FirstName) VALUES('Lee', 'David')</span><span style="color: #800000;">"</span><span style="color: #000000;">;<br />        </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strSql2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">SELECT LastName FROM Employees WHERE EmployeeID=</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> intTheNewestID;<br /><br />        </span><span style="color: #008000;">//</span><span style="color: #008000;">Required 选项: 当前环境若无事务，则创建新事务，否则就加入当前环境的同一个事务。在此例中，会启动 DTC，第二句 Select 会成功。<br />        </span><span style="color: #008000;">//</span><span style="color: #008000;">RequiresNew 选项: 总是创建新的事务，会造成 Class1、Class2 不会处于同一个事务里。在此例中，不会启动 DTC，第二句 Select 会失败。<br />        </span><span style="color: #008000;">//</span><span style="color: #008000;">Suppress 选项: 不加入此一事务。</span><span style="color: #008000;"><br /></span><span style="color: #000000;">        </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> (TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope(TransactionScopeOption.Required))<br />        {<br />            </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />            {<br />                conn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlConnection(strConnString);<br />                conn.Open();<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (conn.State </span><span style="color: #000000;">==</span><span style="color: #000000;"> ConnectionState.Open)<br />                {<br />                    cmd1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlCommand(strSql1, conn);<br />                    intInserted </span><span style="color: #000000;">=</span><span style="color: #000000;"> cmd1.ExecuteNonQuery();<br /><br />                    </span><span style="color: #008000;">//</span><span style="color: #008000;">取得组件一里，刚刚才插入的那一笔记录，以确认组件一、组件二确实是在同一个事务中执行，而不是拆分成两个事务</span><span style="color: #008000;"><br /></span><span style="color: #000000;">                    cmd2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlCommand(strSql2, conn);<br />                    strReturn </span><span style="color: #000000;">=</span><span style="color: #000000;"> cmd2.ExecuteScalar().ToString();<br /><br />                    scope.Complete();<br />                }<br />            }<br />            </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception ex)<br />            {<br />                </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Exception(</span><span style="color: #800000;">"</span><span style="color: #800000;">组件二 - 数据库访问发生错误: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> ex.ToString());<br />            }<br />            </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"><br />            {<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (cmd1 </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br />                    cmd1.Dispose();<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (cmd2 </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br />                    cmd2.Dispose();<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (conn.State </span><span style="color: #000000;">==</span><span style="color: #000000;"> ConnectionState.Open)<br />                {<br />                    conn.Close();<br />                }<br />                conn.Dispose();<br />            }<br />        }<br /><br />        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> strReturn;    </span><span style="color: #008000;">//</span><span style="color: #008000;">返回组件一</span><span style="color: #008000;"><br /></span><span style="color: #000000;">    }<br />}<br /></span></div></pre>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>MSDN 上有一篇文章 [1]，或一些 ADO.NET 书籍，有介绍此种 Nested TransactionScope，及其 TransactionScopeOption 的设置。如下图 2，最左侧为没有事务的代码，当其调用了 scope1 时 (Required)，创建了全新的事务 Transaction A。接下来，当创建了第二个 scope2，或如本帖示例二调用了第二个组件时，由于也是 Reuqired，因此和本帖示例二的情况一模一样，双方会包在「同一个」事务 A 中，并可能会启动 MS DTC。</p>
<p>当创建了第三个 scope3，或呼叫了第三个组件时，由于是 ReuqiresNew，因此会创建「另一个」事务&nbsp;Transaction&nbsp;B。而当创建了第四个 scope4，或调用了第四个组件时，因设置为 Suppress (表示无论如何不加入事务)，因此其会独立执行，不参与任何事务。此种 Supppress 设置，适用于调用第三方厂商或协力厂商的组件，或是单纯执行 SELECT 语句，不需要或不想加入事务时的情形。</p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000;">//</span><span style="color: #008000;">Default TransactionScopeOption is "Required"</span><span style="color: #008000;"><br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;">(TransactionScope scope1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope())<br />{<br />   </span><span style="color: #0000ff;">using</span><span style="color: #000000;">(TransactionScope scope2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope(TransactionScopeOption.Required))<br />   {...}<br /><br />   </span><span style="color: #0000ff;">using</span><span style="color: #000000;">(TransactionScope scope3 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope(TransactionScopeOption.RequiresNew))<br />   {...}<br /><br />   </span><span style="color: #0000ff;">using</span><span style="color: #000000;">(TransactionScope scope4 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionScope(TransactionScopeOption.Suppress))<br />   {...}<br /><br />   </span><span style="color: #008000;">//</span><span style="color: #008000;">...</span><span style="color: #008000;"><br /></span><span style="color: #000000;">}<br /></span></div></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img src="http://pic002.cnblogs.com/img/wizardwu/201002/2010020402231663.gif" /></p>
<p><span style="background-color: #ffff99;">图 2　不同 TransactionScopeOption 设置的执行结果</span></p>
<p><br />在我先前写过的文章「<a target="_blank" href="http://www.cnblogs.com/WizardWu/archive/2009/09/22/1571499.html">网站性能优化 - 数据库及服务器架构篇</a>」，里面的<span style="background-color: #c0c0c0;">图 3 -「物理」上的分层，各种商业逻辑可能存在多台物理主机上</span>，里面有提到，这些不同功能的组件或商业逻辑，可能在同一台 AP Server&nbsp; 上，也可能分布在不同的服务器上。因此要以哪种方式来调用，或同一台机器上的组件，是否有必要牺牲一些性能、启用 DTC 来运作，以达成特定需求的系统设计，应事先做好评估。</p>
<p>&nbsp;</p>
<p>----------------------------------------------------------------------------</p>
<p>&nbsp;</p>
<p><span style="color: #008080;">(三) 示例三：重视回应速度与用户体验</span></p>
<p>&nbsp;</p>
<p>若事务访问了多个数据库，或因网络太慢，让事务时间拉太长，我们还可考虑用 CommittableTransaction 类，以「异步 (Asynchronous)」方式来处理事务。其原理为利用另一条背景线程，来等待事务处理的结果，让主程序 (客户端的浏览器) 能先进行其他的操作，避免让用户处于等待的情况。</p>
<p>如下方示例三的部分代码，执行异步事务时，需提供一个 Callback 方法，在 Commit 时自动调用，亦即下方示例的 OnCommitted 方法。当执行到这个方法时，便会从 Thread Pool 里取得一条线程，进行异步的事务确认。</p>
<p>&nbsp;</p>
<div onclick="cnblogs_code_show('e26c4f74-e0c2-4144-bcd9-668260277561')" class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" class="code_img_closed" id="code_img_closed_e26c4f74-e0c2-4144-bcd9-668260277561" /><img src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" onclick="cnblogs_code_hide('e26c4f74-e0c2-4144-bcd9-668260277561',event)" class="code_img_opened" id="code_img_opened_e26c4f74-e0c2-4144-bcd9-668260277561" style="display: none;" /><span class="cnblogs_code_collapse">示例三</span>
<div class="cnblogs_code_hide" id="cnblogs_code_open_e26c4f74-e0c2-4144-bcd9-668260277561">
<pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">using</span><span style="color: #000000;"> System;<br /><br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Data;<br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Transactions;<br /></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Data.SqlClient;<br /><br /></span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">partial</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> _Default : System.Web.UI.Page <br />{<br />    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strConnString </span><span style="color: #000000;">=</span><span style="color: #000000;"> System.Configuration.ConfigurationManager.ConnectionStrings[</span><span style="color: #800000;">"</span><span style="color: #800000;">Conn_Northwind</span><span style="color: #800000;">"</span><span style="color: #000000;">].ToString();<br /><br />    </span><span style="color: #0000ff;">protected</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> Page_Load(</span><span style="color: #0000ff;">object</span><span style="color: #000000;"> sender, EventArgs e)<br />    {<br />    }<br /><br />    </span><span style="color: #0000ff;">protected</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> Button1_Click(</span><span style="color: #0000ff;">object</span><span style="color: #000000;"> sender, EventArgs e)<br />    {<br />        SqlConnection conn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />        SqlCommand cmd </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br /><br />        </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> strSql </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">INSERT INTO Employees (LastName, FirstName) VALUES('Wu', 'Wizard')</span><span style="color: #800000;">"</span><span style="color: #000000;">;<br /><br />        </span><span style="color: #008000;">//</span><span style="color: #008000;">用 CommittableTransaction 进行明确式事务</span><span style="color: #008000;"><br /></span><span style="color: #000000;">        </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> (CommittableTransaction tran </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> CommittableTransaction())<br />        {<br />            </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />            {<br />                conn </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlConnection(strConnString);<br />                conn.Open();<br />                conn.EnlistTransaction(tran);<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (conn.State </span><span style="color: #000000;">==</span><span style="color: #000000;"> ConnectionState.Open)<br />                {<br />                    cmd </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlCommand(strSql, conn);<br />                    cmd.ExecuteNonQuery();<br /><br />                    </span><span style="color: #008000;">//</span><span style="color: #008000;">指定 Callback 函数为 OnCommitted</span><span style="color: #008000;"><br /></span><span style="color: #000000;">                    AsyncCallback ac </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> AsyncCallback(OnCommitted);<br />                    tran.BeginCommit(ac, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);    </span><span style="color: #008000;">//</span><span style="color: #008000;">开始一个异步事务<br /><br />                    </span><span style="color: #008000;">//</span><span style="color: #008000;">tran.Commit();    </span><span style="color: #008000;">//</span><span style="color: #008000;">同步事务的写法</span><span style="color: #008000;"><br /></span><span style="color: #000000;">                }<br />            }<br />            </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception ex)<br />            {<br />                tran.Rollback();<br />                Response.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">程序发生错误: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> ex.Message);<br />            }<br />            </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"><br />            {<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (cmd </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br />                    cmd.Dispose();<br />                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (conn.State </span><span style="color: #000000;">==</span><span style="color: #000000;"> ConnectionState.Open)<br />                {<br />                    conn.Close();<br />                }<br />                conn.Dispose();<br />            }<br />        }<br />    }<br /><br />    </span><span style="color: #008000;">//</span><span style="color: #008000;">执行到这个方法时，会从 Thread Pool 里取得一条线程，进行异步的事务</span><span style="color: #008000;"><br /></span><span style="color: #000000;">    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> OnCommitted(IAsyncResult ar)     </span><span style="color: #008000;">//</span><span style="color: #008000;">传入一个 IAsyncResult 参数</span><span style="color: #008000;"><br /></span><span style="color: #000000;">    {<br />        CommittableTransaction Tx;<br />        Tx </span><span style="color: #000000;">=</span><span style="color: #000000;"> (CommittableTransaction)ar;<br /><br />        </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />        {<br />            </span><span style="color: #0000ff;">using</span><span style="color: #000000;"> ((Tx))<br />            {<br />                Tx.EndCommit(ar);    </span><span style="color: #008000;">//</span><span style="color: #008000;">结束异步事务</span><span style="color: #008000;"><br /></span><span style="color: #000000;">            }<br /><br />            Response.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">异步事务完成，已成功插入一条记录。</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br />        }<br />        </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (TransactionException ex)<br />        {<br />            Tx.Rollback();<br />            Response.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">异步事务失败，错误信息为：</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> ex.Message);<br />        }<br />        </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"><br />        {<br />            </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (Tx </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br />                Tx.Dispose();<br />        }<br />    }<br /><br />}<br /></span></div></pre>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>----------------------------------------------------------------------------</p>
<p>&nbsp;</p>
<p>本帖第一、第三个示例，执行时并不会启动 MS DTC；而第二个示例，则要看 TransactionScopeOption 的设置情形，依本帖下载示例的缺省值，由于双方都为 Required，因此默认会启动 DTC；但若您将示例中 Class 2 里 func 2 改为 RequiresNew，则不会启动 DTC。因此实务上，一个系统该如何去设计，是否要为了彻底的组件化、易于日后维护和扩展，而牺牲一些事务处理上的性能 (写 Java/J2EE 的人好像常干这种事)，应视系统和项目的需求，而非永远以一套固定的设计方式或代码写法，就想套用在所有的项目中。</p>
<p><img src="http://pic002.cnblogs.com/img/wizardwu/201002/2010020402283633.jpg" /></p>
<p><span style="background-color: #ffff99;">图 3　MS DTC 统计画面</span></p>
<p>&nbsp;</p>
<p>----------------------------------------------------------------------------</p>
<p>&nbsp;</p>
<p><span style="color: #008080;">相关文章:</span></p>
<p>[1] Introducing System.Transactions in the .NET Framework 2.0<br /><a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms973865.aspx">http://msdn.microsoft.com/en-us/library/ms973865.aspx</a></p>
<p>[2] J2EE与.NET在Transaction Scope上的比较<br /><a target="_blank" href="http://www.cnblogs.com/perhaps/archive/2005/08/17/216863.html">http://www.cnblogs.com/perhaps/archive/2005/08/17/216863.html</a></p>
<p>[3] SQL Server 的 System.Transactions 集成 (ADO.NET)<br /><a target="_blank" href="http://msdn.microsoft.com/zh-cn/library/ms172070.aspx">http://msdn.microsoft.com/zh-cn/library/ms172070.aspx</a></p>
<p>[4] 谈谈分布式事务（Distributed Transaction）[共5篇] - Artech - 博客园<br /><a target="_blank" href="http://www.cnblogs.com/artech/archive/2010/01/31/1660433.html">http://www.cnblogs.com/artech/archive/2010/01/31/1660433.html</a></p>
<p>[5] WCF系列_分布式事务<br /><a target="_blank" href="http://www.cnblogs.com/chnking/archive/2010/01/10/1643362.html">http://www.cnblogs.com/chnking/archive/2010/01/10/1643362.html</a><br /><a target="_blank" href="http://www.cnblogs.com/chnking/archive/2010/01/10/1643384.html">http://www.cnblogs.com/chnking/archive/2010/01/10/1643384.html</a></p>
<p>[6] 网站性能优化 - 数据库及服务器架构篇 <br /><a target="_blank" href="http://www.cnblogs.com/WizardWu/archive/2009/09/22/1571499.html">http://www.cnblogs.com/WizardWu/archive/2009/09/22/1571499.html</a></p>
<p>&nbsp;</p>
<p>----------------------------------------------------------------------------</p>
<p>&nbsp;</p><img src="aggbug/1663127.html?type=0" width="1" height="1" alt=""/><p>评论: 7　<a href="http://www.cnblogs.com/WizardWu/archive/2010/02/04/1663127.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/WizardWu/archive/2010/02/04/1663127.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>李笑来激起千层浪，赵姐夫力拒众强敌</title><link>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/03/twitter-talk-about-ms-dev-at-20100201.html</link><dc:creator>Jeffrey Zhao</dc:creator><author>Jeffrey Zhao</author><pubDate>Tue, 02 Feb 2010 16:49:00 GMT</pubDate><guid>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/03/twitter-talk-about-ms-dev-at-20100201.html</guid><description><![CDATA[<p>阅读: 7436 评论: 162 作者: <a href="" target="_blank">Jeffrey Zhao</a> 发表于 2010-02-03 00:49 <a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/03/twitter-talk-about-ms-dev-at-20100201.html" target="_blank">原文链接</a></p><p>昨天晚上，<a href="http://www.lixiaolai.com">李笑来</a>（<a href="https://twitter.com/xiaolai">@xiaolai</a>）老师的无心之语却引起了推特上一次前后长达1个多小时的讨论——当时他似乎只是随手发了一句“Apple告诉我们的铁律是：表面功夫一定要做足”便不见了踪影，但是这句话立即引起了众果粉的共鸣。此后，我（<a href="https://twitter.com/jeffz_cn">@jeffz_cn</a>）的一句评论又引起了众人对微软开发平台的批判之声。在这次讨论中，几乎只有我孤军奋战为.NET平台进行辩解。因此事后有人给出一副对联为此次争论作出总结：</p>  <blockquote>   <p>上联：李笑来激起千层浪</p>    <p>下联：赵姐夫力拒众强敌</p>    <p>横批：全民扯谈</p> </blockquote>  <p>自然，无论是我还是其他人，在参与讨论的时候都抱有明显的个人倾向性。不过与常见的吵架不同，虽然大家观点向左，但是并没有任何谩骂的成份，同时也没有假惺惺的客套话。可以说所有人从头到底都保持着就事论事，据理力争。因此从旁观者的角度来看，这次讨论并非只是意气之争，其中还是包含了比较丰富的内容。</p>  <p>参与讨论的<a href="http://blog.devep.net/virushuo/">霍炬</a>（@virushuo）和<a href="http://tiny4.org/myhome/">郝培强</a>（@tinyfool）都是老程序员，他们在上世纪末也都是微软平台的开发人员，但是因为难以忍受微软在那时候“毫无克制”的技术更迭（如VC =&gt; COM =&gt; .NET），最终一前一后都转投了*nix平台。我昨天谈到，我<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/02/use-mac.html">加入水果党的主要原因</a>之一是想了解苹果机的妙处究竟在哪里，而他们两位便是让我产生这一想法的重要因素。而我，由于入行较晚，虽然“从理论上”说也经历过这一历史阶段（如VB，Delphi，以及Java开发环境混战的那一时期），但是在真正全身心投入微软平台时已经是.NET时代了，因此对于霍郝两位的观点并没有切身体会，而我坚持的观点便是：.NET平台发布至今并没有“革命性”的改变，而目前也可以看出微软已经在.NET平台上投入了未来5年甚至10年的心力，因此如今.NET程序员并不用担心遭遇当年的悲剧。</p>  <p>从这次讨论中可以了解到一些老程序员对（当年）微软开发平台的一些典型看法，这些看法放到现在究竟正确与否我认为并不重要，重要的是我们能够从中总结出哪些信息，这些信息又可以如何对我们将来的发展产生借鉴意义。因此，我详细地总结了这次讨论的完整内容——不过毕竟是人肉整理，不排除遗漏少量条目的可能。因此，我建议您可以上一下推特，follow一些人，这样下次再出现有价值的讨论也不会遗漏了。</p>  <p>由于讨论内容较多，我还是把它们放在下面的链接中了。其中，缩进代表了“回复”关系，但是由于推特的谈话性质，条目的上下位置并不表示发表时间的先后。</p>  <p><a href="http://docs.google.com/View?id=dgpjrmdf_141cgbw5gfx">http://docs.google.com/View?id=dgpjrmdf_141cgbw5gfx</a></p><img src="aggbug/1662320.html?type=0" width="1" height="1" alt=""/><p>评论: 162　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/03/twitter-talk-about-ms-dev-at-20100201.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/03/twitter-talk-about-ms-dev-at-20100201.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>光有逻辑也是万万不能的</title><link>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/01/logic-is-not-everything.html</link><dc:creator>Jeffrey Zhao</dc:creator><author>Jeffrey Zhao</author><pubDate>Sun, 31 Jan 2010 16:14:00 GMT</pubDate><guid>http://www.cnblogs.com/JeffreyZhao/archive/2010/02/01/logic-is-not-everything.html</guid><description><![CDATA[<p>阅读: 6101 评论: 106 作者: <a href="" target="_blank">Jeffrey Zhao</a> 发表于 2010-02-01 00:14 <a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/01/logic-is-not-everything.html" target="_blank">原文链接</a></p><p>之前我多次强调“逻辑”在讨论问题时的重要性，我也多次表示说，如果大家都运用合适的逻辑思维来讨论问题，那么论坛上8成吵架可以避免。现在我也想再次探讨一下这个话题，只不过这次我想反过来说：光有逻辑也是万万不能的。除了“逻辑”这个东西之外，讨论问题时还有很多其他东西值得注意。</p>  <p><a href="http://www.lixiaolai.com">李笑来</a>老师是国内最著名的“讲道理”倡导者之一。前一段时间对于“孔子”这部电影，他在推特上说了这么一句话：“坚决不去电影院看《孔子》的请举手！”。于是我和其他一些朋友就问到：“发生什么了？”不久，笑来老师就在博客上<a href="http://www.lixiaolai.com/index.php/archives/8588.html">谈了这个问题</a>，摘录如下：</p>  <blockquote>   <p>“抵制”的意思是说，有一样东西对你是有吸引力的（不管好坏），但是，你不要它。比如“抵制日货”，“日货”挺不错的，但是，基于某种原因有些人就“抵制”了它。抵制“法货”也是如此，抵制“诱惑”亦如是。</p>    <p>我们只是纷纷表示自己不会去看，这不叫“抵制”，只是“表态”——犯得着去抵制一个连诱惑都不是的东西吗？它甚至连日货法货都不是。甚至没有“号召”的意思，“号召”的意思是说，给别人一个信服的理由，令他们做出与原本可能不一样的决定。</p> </blockquote>  <p>笑来老师的意思是，他只是在表态，他不是在号召大家不去看。从字面上看，“请举手”的确没有在“号召”，例如“喜欢吃红烧肉的请举手”，相信没有人会认为这有其他意思。但是，为什么包括我在内的一些朋友就认为笑来老师是在号召大家不去看这部电影呢？仔细思考之下，我认为可能是这两个原因。</p>  <p>首先，在此之前笑来老师说过或转推过一些对于“孔子”电影的反面意见。在大部分情况下，某个人说的话都是有上下文的，在不同的上下文说同样的话，理解其起来也不一样。为什么说某些媒体没有道德？其中一个表现便是在转述别人的话时剥离上下文，以此曲解别人的意思，甚至让意思完全相反。因此，虽然经过分析之后，我能够理解笑来老师的确没有“号召”的意思，但在当时，这句话的确给人以不一样的感觉。</p>  <p>其次，这句话的表述是反面的，此外其用词比较强烈，如“坚决”。人类的语言是神奇的，一句话除了“最表面的意思”之外，其说话方式、用词的不同，都会影响别人对这句话的理解——这也是语言表达的非常重要的一部分。例如一个多月前在图灵俱乐部中，有朋友认为现在许多文字或翻译越来越不简练了，他认为“我和你要做一次私下的谈话”是典型的英文式中文，应该“我想和你私下谈谈”。但是，<a href="http://ozzzzzz.javaeye.com/blog/">o6z</a>的回复反驳了这个看法，认为“这个例子举的太差，这两句话的语气和目的差别太远。其实类似的表达还有很多，但是里面的含义却大有不同”：</p>  <ul>   <li>我和你要做一次私下的谈话----将来做一次正式的但是非公开的谈话。</li>    <li>我要和你做一次私下的谈话----现在马上就要跟你做一次正式的私下谈话。</li>    <li>我想和你私下谈谈----我想找个机会私下和你谈谈，更加具有私人性质的交谈，而不是上面两句更加具有工作或者官方色彩。</li>    <li>我想和你谈谈，私下的----直接的表达出我要跟你聊点不适宜公开的事情，有要搞阴谋的味道。</li>    <li>找个时间咱俩聊聊吧----更多的是客气话，希望拉近关系。</li> </ul>  <p>最近还有一个非常著名的例子便是“Google离开中国事件”。当时我说：“事情闹这么大，Google要么离开被人看作爷们，要么留下给人看作笑话”。最后的结果大家应该也就见到了，这几乎就是一场闹剧。这次事件继续在给Google的“不作恶”原则抹黑。但是也有人说，Google本来没什么啊，都是媒体炒作害苦的。没错，Google从头到底没有说“一定离开中国”，它只是说“考虑离开中国”。从逻辑上看，它最终选择留下并没有违背它说过的话，因此也不会有人追究它的责任（如，罚款）。但是，为什么似乎大部分人（还是我自动过滤了意见不同的看法？）觉得Google这次“吃了吐”呢？这就是它的“行为”和“说法”给人的“感觉”，在这方面“逻辑”不是唯一的评价依据。</p>  <p>这也是为什么有了“逻辑”还是会发生“争吵”的原因，尤其是在技术圈子里。因为，即使每句话都包含逻辑，许多话“还是不那么好听”，给人的感觉还是“话里有话”，慢慢大家的情绪都调动起来，争论难以避免。此外，在技术圈里，大家都是聪明人，能够很轻易地发现平时交流中对方话语中的问题——毕竟，例如论坛发帖时很少有人会字斟句酌。于是，我反驳不了你的“理由”，我反驳你的“说法”不也可以吗？只可惜，我们只有如“法庭辩论”这样的环境下才需要如此运用“逻辑”。平时，有必要吗？</p>  <p>此外，“逻辑”也可以用来“诡辩”，无理也可以说成有理——大家都是聪明人，这方面的能力总是不缺的。以下便是一例：</p>  <p>上个星期还发生了“0 bug门”事件：。简单地说，那是因为有人对于《<a href="http://www.douban.com/subject/4149139/">0 bug——C/C++商用工程之道</a>》写了一个书评，<a href="http://www.douban.com/review/2949973/">指出书中的一些问题</a>。于是作者，<a href="http://blog.csdn.net/tonyxiaohome">肖舸</a>（后文称o bug老师）不干了，认为评论者是故意来抹黑，认为评论者能力不够。但事实上，评论者<a href="http://cn.linkedin.com/in/miloyip">Milo Yip</a>的批评完全只是针对书上的内容，语气也非常委婉，反倒是0 bug老师在不断对评论者进行谩骂——并一再坚持评论者公开身份。后来，大家发现Milo其实是大牛，因此对其能力不足的的说法也不攻自破了……不知道当时0 bug老师心里是什么滋味。</p>  <p>那么现在结果怎么样呢？没怎么样，0 bug老师已经删除了自己的所有回复。只可惜，Google快照功能保留了一切，而这些结果也已经被<a href="http://blog.csdn.net/lanphaday/archive/2010/01/27/5260427.aspx">截图留档</a>。但即便如此又如何呢？0 bug老师还是义正词严地<a href="http://blog.csdn.net/tonyxiaohome/archive/2010/01/28/5265573.aspx">发表了一篇文章阐述了自己的不公遭遇</a>——都是聪明人，这方面的能力总是不缺的。再由于“谁的地盘谁作主”，0 bug老师的博客上只能看到众粉丝的溢美之辞。</p>  <p>所以，如果要形成良性讨论，光有逻辑也是万万不行的。我们还是需要点别的东西，例如控制情绪，与人宽容等等。</p><img src="aggbug/1660688.html?type=0" width="1" height="1" alt=""/><p>评论: 106　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/01/logic-is-not-everything.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/01/logic-is-not-everything.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56799/" target="_blank">百度第四季度净利润6270万美元 同比增48.2%</a><span style="color:gray">(2010-02-10 09:10)</span><br/>· <a href="http://news.cnblogs.com/n/56798/" target="_blank">现场直播：Google 社会化产品 Google Buzz 发布</a><span style="color:gray">(2010-02-10 09:01)</span><br/>· <a href="http://news.cnblogs.com/n/56797/" target="_blank">阿里巴巴3月推1688网络批发 胡戈韩寒出力宣传</a><span style="color:gray">(2010-02-10 08:48)</span><br/>· <a href="http://news.cnblogs.com/n/56796/" target="_blank">第一代互联网拓荒者再掀连环创业潮</a><span style="color:gray">(2010-02-10 08:47)</span><br/>· <a href="http://news.cnblogs.com/n/56795/" target="_blank">雅虎将永久性关闭科技站点Yahoo! Tech</a><span style="color:gray">(2010-02-10 08:45)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/n/56782/" target="_blank">2010年2月编程语言排行榜</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item></channel></rss>