<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>流程方法 | 酷 壳 - CoolShell</title>
	<atom:link href="https://coolshell.cn/category/process/feed" rel="self" type="application/rss+xml" />
	<link>https://coolshell.cn</link>
	<description>享受编程和技术所带来的快乐 - Coding Your Ambition</description>
	<lastBuildDate>Thu, 31 Dec 2020 08:45:32 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2</generator>
	<item>
		<title>什么是工程师文化？</title>
		<link>https://coolshell.cn/articles/17497.html</link>
					<comments>https://coolshell.cn/articles/17497.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Sun, 18 Sep 2016 08:23:11 +0000</pubDate>
				<category><![CDATA[技术管理]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[职场生涯]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=17497</guid>

					<description><![CDATA[<p>四年前，我在QCon上演讲了一个《建一支强大的小团队》（整理后的PPT分享于这里）提到了工程师文化，今天，我想在这里再写一篇关于工程师文化的文章，一方面是因为我...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/17497.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/17497.html">什么是工程师文化？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-full wp-image-17500" src="https://coolshell.cn/wp-content/uploads/2016/09/engineer.jpg" alt="engineer" width="300" height="203" /> 四年前，我在QCon上演讲了一个《<a href="http://www.infoq.com/cn/presentations/Form-powerful-team" target="_blank">建一支强大的小团队</a>》（整理后的<a href="http://vdisk.weibo.com/s/gN-sQ/1351485199">PPT分享于这里</a>）提到了工程师文化，今天，我想在这里再写一篇关于工程师文化的文章，一方面是因为我又有了一些想法和体会，另一方面，因为我也正走在创业的道路，毫无疑问，要建一个有浓重的工程师文化的团队或公司，所以有必要把自己的相关想法形有成白底黑字的“字据”，以供打自己的脸——“要是未来没有做到，这篇文章就打我未来的脸” || “这篇文章太幼稚了，未来的我会打我现在的脸”，当然，如果要打脸，我希望是前者。</p>
<p>Again，<strong>这篇文章不是招人的贴子，因为我觉得，招聘第一重要的事，不是发招聘广告或是找猎头挖人，而是先得让自己变成一个能配得上真正工程师的公司，然后再谈吸引人的事</strong>。</p>
<h4>为什么要工程师文化</h4>
<p>看看最近二十年来社会的发展，计算机和互联网已经渗透到了这个社会的每一个角落，各式各样的计算机技术成为了整个世界发展的强大引擎，各式各样的创新，无论是业务创新还是技术创新，都是依托于技术的快速演进，技术成了解放生产力提高社会运作的效率的中坚力量。以美帝为首的技术创新公司着着实实的改变着这个世界和人类的生活和生产习惯。</p>
<p><strong>今天，每个从事计算机行业的技术人员都应该感到幸运，因为，我们不但选对了行业，也出生在了正确的时代，可以感受到前所未有的刺激和变化，相比起我们的父辈，我们的人生，能经历这样的时代，实在是一种幸运。</strong>所以，选对了职业并出生在了正确的年代的我们，此时只需要思考的一个问题，那就是，我是否呆在了正确的地方用正确的方式做事？</p>
<p><span id="more-17497"></span></p>
<p>在我看来，这个世界上有三种商业公司，</p>
<ul>
<li><strong>运营或销售驱动型的公司</strong>。这类的公司以运营和营销见长，技术对于他们来说，更多的只是为了支持大规模的营销活动，以及成本上的控制，所以，基本上来说不太需要技术创新。这种公司最大的问题就是缺乏安全感。</li>
</ul>
<ul>
<li><strong>产品驱动型的公司</strong>。这类公司以产品见长，通过创造能提升用户生活体验的产品见长，技术对于他们来说，除了支持大规模的在线用户之外，他们会更多的去寻找那些为了增强用户体验，提高整个业务流程效率的技术创新。比如：UI的交互方面的，整个业务流程方面的。这种公司最大的问题，就是容易被别人模仿和抄袭。</li>
</ul>
<ul>
<li><strong>技术驱动型的公司</strong>。这类的公司相信技术能改变世界，他们更多的是用强大的工程技术来创造有颠覆性的东西，更多的是用各种自动化的技术取代人类。比如：近代的蒸汽机技术取代了大量的人工，数字技术取代了大量信息传递的人工，现代，这类公司还希望通过人工智能来取代愚蠢的人类来做决定。这种公司最大的问题就是可能做出叫好不叫座的东西。</li>
</ul>
<p>这三种公司都可能成功，也都有问题，但是，无一例外，他们都需要强大的技术支撑，只不过，他们把技术所放在的位置不一样。</p>
<p>无论你有多么的看不起技术人员，你都无法否认，你今天的生活相当的依赖这帮工程师，没有他们，你恐怕都不知道怎么生活了。邓爷爷几十年前就说过——“科学技术是第一生产力” ，无论什么样的科学技术的理论要落地都会依赖于工程技术有多先进。</p>
<p>所以，<strong>在今天，作为一个IT或互联网公司，“工程师文化”不是一个问题，而是一个常识</strong>！</p>
<h4>工程师文化的特征</h4>
<p>我下面罗列的这些特征，来源于：Google的《<a href="https://book.douban.com/subject/26582822/">重新定义公司</a>》，我在Amazon的工作经历，37Signals的《<a href="https://coolshell.cn/articles/9156.html" target="_blank">Rework</a>》，Quora上的 <a href="https://www.quora.com/What-makes-a-good-engineering-culture">What Makes Good Engineering Culture?</a>  Slideshare上的 <a href="http://www.slideshare.net/edmondlau/what-makes-a-great-engineering-culture">What Makes Good Engineering Culture</a>，以及我最近这半年来的一些实践。</p>
<p>简单说来，<strong>我可以简单的把这多的工程师文化的总结成两大类：“自由” 和 “效率”</strong>。</p>
<p>本来还应该有个“创新”，但我个人认为，<strong>创新的前提是——在自由的环境下对提高效率的痴迷，就一定会发生创新。</strong></p>
<p>创新不是凭空出现新的东西，其实，<strong>观察一下人类的发展史，不难发现，几乎所有的创新基本上跳出原来的思维模式用新的思维模式对原有问题的效率进行质的提升</strong>。比如：通信、交通、医疗、教育、生活……几乎全都是在优化效率。</p>
<p>所以，如果你的精神不自由，你很难跳出老的思维模式，你用老的思维模式你一定不会想到新的方法和方式，如果不是对效率的提升，这个创新可能会不接地气。</p>
<p>因此，我认为，工程师文化就是自由加效率！</p>
<h4>自由</h4>
<p>首先，工程师文化意味的创新文化，工程师都是有创新冲动的人，因为手里有创造技能的人通常都会有想创造点什么的冲动。而创新的源泉水来源于精神的解放，精神自由才会引发各式各样的奇思怪想，才会有常人觉得不可能的疯狂想法和想像力，而这些想法和想像力导致了创新。</p>
<p>精神上的自由具体表现在：</p>
<ul>
<li><strong>自我驱动</strong>。自己管理自己是最好的管理。最失败的管理就是家长和保姆式的管理。兴趣出发的工作才可能迸发出真正的动力。</li>
</ul>
<ul>
<li><strong>灵活的工作时间和地点</strong>。工程师们更多的是脑力工作，而不是体力工作，工作上时间和地点的自由安排可以让工程师们的脑力工作更有效。Remote是一个很不错的工作方式，开源社区基本上都是这钟方式。和Remote有关的话题可参看37Signals的这本书《<a href="https://book.douban.com/subject/25861795/" target="_blank">Remote</a>》</li>
</ul>
<ul>
<li><strong>信息平等</strong>。这意味着，全体员工得到的是原始信息，而不是被管理者们层层加工消化后的信息，信息的屏蔽很容易造成误解和完全错误的行为。信息的平等，大的包括战略、方向、目标、财务，小的包括文档、代码、和知识的共享等。同样，也表现在意见表达上，任何人都有可能表达自己的意见和建议的平等机会，这样才会激发出更多的思路和思辩，从而有不同的更好的思路出现。而不是，大家都看到了问题，而没有人敢说。在Google除了代码全员共享，还有Thanks God, It&#8217;s Friday的文化，每周五，高管们会出来，任员工提各种尖锐的问题，在Amazon，代码和文档基本上全员开放，包括财务报表也对员工开放，另外，除了所有的NB的Principle SDE隔三岔五都会有一个Principle Talk（有很多Talk相当令人开脑洞），还有Amazon内部的Up the River文化，每年会选出一批公司最聪明最有想法的人集思会，讨公司下一步的和战略，并可以把相应的KPI直接按给Senior VP。</li>
</ul>
<ul>
<li><strong>不害怕错误</strong>。处理错误的正确的姿势是分析总结教训，而不是惩罚故障人。前者让人改善进步，后者让人萎缩不前。最大的错误就是不敢犯错，最大的问题就是不敢直面问题。</li>
</ul>
<ul>
<li><strong>宽松的审批系统甚至没有审批系统</strong>。审批通常暗示着三件事，1）对人的不完全信任，2）繁琐的流程，3）思维上的束缚。这些都是创新和想像力的天敌。一个公司的监管、审批、流程越重，这个公司的活力也就越差。</li>
</ul>
<ul>
<li><strong>20%的自由时间</strong>。这是Google公司提出来的，员工有20%自由的时间做自己想做的项目，Gmail就是这么出来的。</li>
</ul>
<h4>效率</h4>
<p>工程师天生是追求效率的。有人说认为程序员花大量的时间做自动化的工具，还不如人肉的效率高，比如，写自动化的脚本花5个小时，而重复做这件事200次只花3个小时。有这样的理解的人根本不懂工程。</p>
<p>一方面，这个工具可以共享重用，更多的人可以从中受益，这次我花5个小时开发这个工具，下次只用1小时改一下就可以用在别的地方，这是着眼于未来而不是眼下的成本。更重要的是，这是一种文化，一种提高效率的文化，他会鼓励和激发出更多的这样的事情发生。<strong>如果你因为一个程序员花大量的时间开发自动化的工具，而认为这个程序员没有效率，对之批评甚至惩罚的话，那么你就扼杀了提高效率的文化</strong>（关于效率，大家可以看看我的另一篇文章《<a href="https://coolshell.cn/articles/10217.html" target="_blank">关于加班和效率</a>》，你会真正了解什么是效率）</p>
<p><strong>人类之所以比别的动物聪明就是会使用和发明工具</strong>，而古语也有云：“工欲善其事，必先利其器”，看看美军的装备你就知道战争工具的好坏有多重要了，<strong>一个公司的强大之处在执行力，而执行力的强大之处在于你有什么样的支持工具。这些，已经不是工程师文化，而是人类发展的文化</strong>。</p>
<p>针对于工程师文化来说，尤其是软件工程，提升工程效率的具体表现如下：</p>
<ul>
<li><strong>简化</strong>。简化不是简陋，简单的东西通常意味着用户更好理解，也意味着更容易的维护和运维。就像阿里推行的“小而美”，就像乔布期推崇的“没有产品手册简单易用的产品”，就像Amazon推行的Working Backwards里说的那样，一个新的产品或功能，产品经理需要写三个文档：媒体公关文、用户手册、常见问题，三个文档总共加起来不超过两页A4纸，且不准用任何图片说明，目的就是为了让产品简化和容易使用。</li>
</ul>
<ul>
<li><strong>残酷无情的推行自动化</strong>。编写程序的最本质的目的就是自动化，看看人类发展史上自动化了多少东西。<strong>对于自动化来说，不仅仅只是消除人肉的重复劳动，更重要的是，很多事情人完全干不过机器。</strong>比如：加一台机器，程序在秒级就可以完成，而人是永远不可能达到这样的速度的，再比如：电商中用程序管理数量巨大的订单的自动化系统，加再多的人都完成的不可能像机器那样完成的又好又快。自动化需要大力开发提高生产力的工具，比如：持续集成，持续部署，自动化运维，基础自动化运维，甚至自动化的运营工具。（Amazon的软件工程中对自动化和简代相当迷恋）</li>
</ul>
<ul>
<li><strong>避免无效率的组织架构和无效率的管理</strong>。这体现在这些方面：1）扁平化的组织架构，2）努力用自动化工具取代支持型的工作，3）不超过10个人的全栈小团队，4）不按人员的技能分工而是按其负责的产品或功能分工（关于分工，请参看《<a href="https://coolshell.cn/articles/17295.html" target="_blank">让我们来谈谈分工</a>》），5）开会不是解决问题，开会是表决提案，6）通过产品的目标或信条Tenets来减少沟通和决策过程（Amazon里的每个部门，每个团队，每个产品都有自己的Tenets，这个Tenets标明了要什么不要什么，这样可以避免很多扯皮和难缠的trade-off的决择，比如：AWS的几个信条：运维是最高优级的——这意味着只要是会让运维变得复杂的需求都可能会工程团队被拒掉，Throughput &amp; Latency不能更差——这意味着，功能要为性能让路，因为性能变差了，用户就要买更多的资源）</li>
</ul>
<ul>
<li><strong>正确的组件抽象</strong>。抽象是简化的一部份，一方面，抽象意味着重用和通用，另一方面抽象意味着强大的扩展性，以适配各种可能性。最重要的是，抽象意味着技术能力的输出，无论是内部的其它团队还外部的团队。比如：Google的MapReduce/BigTable/ProtoBuffer，FaceBook的Thrift，还有Amazon内部的WebService框架Coral Service、处理日志监控的Timber，以及全线AWS产品都用到的Amazon Lock Framework（一个分布式锁框架）……</li>
</ul>
<ul>
<li><strong>开发高质量的产品</strong>。因为高质量的代码，不但可以容易的修改和维护，还可以因为少处理线上故障，从而有更多的时间去为未来做更多创造性的工作。这意味着需要有非常严谨的Design Review，Code Review，以及测试，关于Code Review，可以参看这篇文章《<a href="https://coolshell.cn/articles/11432.html" target="_blank">从Code Review 谈如何做技术</a>》，关于严谨的测试，可以参看这篇文章《<a href="https://coolshell.cn/articles/17381.html" target="_blank">如何做性能测试</a>》</li>
</ul>
<ul>
<li><strong>不断的提高标准以及招聘最好的人</strong>。取法其上，得乎其中，取法其中，得乎其下，取法其下，法不得也。如果一个公司或一个团队想变得越来越好，越来越强大的话，就必需要不断的提高自己的工作标准，提高工作标准意味着要不断地培养和招聘更好的人。在Amazon和Google的招聘官中都有一个叫Bar Rasier的人，这个人就是为了提高招聘标准而设立的。</li>
</ul>
<ul>
<li><strong>创建一个持续改善的文化</strong>。一个好的组织，一个好的团队，是需要不断反思前进的，这需要全体员工一起来的。微观层面上，在项目做完后需要有一个总结会分析项目中的得失，在故障出现后，需要有故障分析会，反思得失，在Amazon，严重的故障，需要写一个COE（Correction of Errors）的文档，其中有一节叫“Ask 5 Whys”，让你自己问自己至少5个为什么。在宏观层面，一个公司每年都应该做一定的工作数据分析或是员工调查，比如，是否招聘到了不错的人、工作的投入产出比，员工在哪些地方花时间了，等等，然后不断的用技术手段来改善。（Amazon每年的工程师员工调查表是我活那么大见过的最细最细的调查表了， 问题除了对公司、经理、文化的，还有从，日常工作、开发环境、持结集成，测试自动化、产品质量、软件架构、软件维护、线上问题处理、年度计划、数据仓库建设、通用工具投票……这个员工调查直接导致公司的对工程的投资方向）</li>
</ul>
<h4>工程师文化如何落地</h4>
<p>如果你要让任何文化在公司内得到执行，你有下面几个手段可以选择：</p>
<ul>
<li><strong>通过政治手段：你需要把住三个地方——招聘、绩效考核 &amp; 升职</strong>。比如，你要落地工程师文化中的简化和自动化，那你你在招聘的时候，你需要把懂简化和喜欢自动化的人招进来，然后在绩效考核和升职的地方设置上一条硬性指标——你今年简化了什么？自动化了什么？如果没有，对不起不但不能升职，绩效可能还不达标。</li>
</ul>
<ul>
<li><strong>通过经济手段：让不做这事的成本 &gt; 要做这个的成本。</strong>然后，正常的人类都会选择成本低的方案。比如，如果你要推行Design/Code Review/UT以提高质量，你就把QA和OPS团队全挪到一边去，让Dev团队自己测试，自己负责，这样等这些Dev重复多次手动测试，处理多次线上的弱智故障，他们就会自然而然的写自动化测试和做Code Review了，而QA和OPS团队只是帮Dev你做工具罢了，而测试和运维的事全是你DEV的Ownership，出了故障也是Dev自己负责，于是，他们就会发现，不做Code Review和UT的成本远远大于做C Code Review/UT的成本，他们就会去做成本低的事的。</li>
</ul>
<p>最后，工程师文化要落地，还有几个小条件，</p>
<ul>
<li><strong>第一，团队要小，Ownership很重要，Eat Your Own Dog Food。</strong> 没有人帮你擦屁股，自己的屎自己吃，没有痛苦，不会产生想进步的动力。</li>
</ul>
<ul>
<li><strong>第二，热爱学习和尝试</strong>，学习尝试新的技术，开拓眼界，学习尝试新的思维方式，否则，呆在原地，原有的思维方式只会让你在原地打转转。</li>
</ul>
<ul>
<li><strong>第三，老板更多的相信技术而不是管理</strong>。相信技术会用技术来解决问题，相信管理，那就只会有制度、流程和价值观来解决问题。</li>
</ul>
<h4>其它</h4>
<p>说了这么多，时代还在发展，不过，这是我这么多年经历或看到的工程师文化的东西了。最后吐几个槽——</p>
<p>对于996和加班这个事，对于工程师来说从来都不是问题，在解决技术问题或是创造的时候，工程师是个很自觉的群体，基本不需要有别人驱动，工程师是最乐意Work Hard的人了。我相信几乎所有走上编程这个职业的人来说，基本上都是兴趣所至，觉得编程很有趣，但却被各个公司996搞得对编程毫无兴趣。为什么，你们这些公司要向中国的教育学习呢？人家本来对这事有比较高的兴趣的，但就是要通过考试/KPI/996这些东西把人家的兴趣一点一点的磨灭掉，把人变成机器、奴隶、牲口，<strong>让人对学习和工作产生了厌倦和讨厌，会是你们这些管理者们所希望的？是不是只有把人变得不思进取了，你们才会管理？</strong>就像《<a href="https://coolshell.cn/articles/4951.html" target="_blank">软件开发中的两种管理方式</a>》中说的第一种人一样？</p>
<p>另外，我不知道，为什么我一说这些东西，就会有很多人（包括程序员自己）来和我说我是个理想主义者，这些已经不是什么理想了，已被很多成功的公司用了很多很多年了。只是你没有见到过罢了。还有的人说，因为中国的国情不同。这更让我费解了。这让我想到了当年大清朝派了一堆人出国考察后回来后，说外国的那套共和的东西不符合中国国情，最终也在历史的潮流中被淹没掉了。另外，什么叫“中国的国情不同”？中国有全世界数一数二的互联网用户，也有全世界数一数二的市场，不再是以前那个一穷二白的年代了，中国的国情到底有哪些不同呢？</p>
<p>我不知道各位工程师是为什么活的？但我觉得，<strong>我们选择了一个刺激的职业，也赶上了这个行业大发展的时代，我们不妨扪心自问一下，你是否愿意让自己的能力、青春和热情就这样被磨灭了？</strong></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" id="wp_rp_first"><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="http://coolshell.cn/articles/9156.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/03/rework-150x150.jpg" alt="《Rework》摘录及感想" width="150" height="150" /></a><a href="http://coolshell.cn/articles/9156.html" class="wp_rp_title">《Rework》摘录及感想</a></li><li ><a href="http://coolshell.cn/articles/11432.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/04/code_review-150x150.jpg" alt="从Code Review 谈如何做技术" width="150" height="150" /></a><a href="http://coolshell.cn/articles/11432.html" class="wp_rp_title">从Code Review 谈如何做技术</a></li><li ><a href="http://coolshell.cn/articles/5686.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/9.jpg" alt="多些时间能少写些代码" width="150" height="150" /></a><a href="http://coolshell.cn/articles/5686.html" class="wp_rp_title">多些时间能少写些代码</a></li><li ><a href="http://coolshell.cn/articles/4951.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/2.jpg" alt="软件公司的两种管理方式" width="150" height="150" /></a><a href="http://coolshell.cn/articles/4951.html" class="wp_rp_title">软件公司的两种管理方式</a></li><li ><a href="http://coolshell.cn/articles/11656.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/06/software_development-150x150.png" alt="开发团队的效率" width="150" height="150" /></a><a href="http://coolshell.cn/articles/11656.html" class="wp_rp_title">开发团队的效率</a></li><li ><a href="http://coolshell.cn/articles/10217.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/07/Work-Overtime-150x150.jpg" alt="加班与效率" width="150" height="150" /></a><a href="http://coolshell.cn/articles/10217.html" class="wp_rp_title">加班与效率</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/17497.html">什么是工程师文化？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/17497.html/feed</wfw:commentRss>
			<slash:comments>124</slash:comments>
		
		
			</item>
		<item>
		<title>性能测试应该怎么做？</title>
		<link>https://coolshell.cn/articles/17381.html</link>
					<comments>https://coolshell.cn/articles/17381.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Tue, 05 Jul 2016 17:03:26 +0000</pubDate>
				<category><![CDATA[流程方法]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[test]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=17381</guid>

					<description><![CDATA[<p>偶然间看到了阿里中间件Dubbo的性能测试报告，我觉得这份性能测试报告让人觉得做这性能测试的人根本不懂性能测试，我觉得这份报告会把大众带沟里去，所以，想写下这篇...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/17381.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/17381.html">性能测试应该怎么做？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-full wp-image-17383" src="https://coolshell.cn/wp-content/uploads/2016/07/PerfTest.png" alt="PerfTest" width="300" height="277" srcset="https://coolshell.cn/wp-content/uploads/2016/07/PerfTest.png 300w, https://coolshell.cn/wp-content/uploads/2016/07/PerfTest-292x270.png 292w" sizes="(max-width: 300px) 100vw, 300px" />偶然间看到了阿里中间件<a href="http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A" target="_blank">Dubbo的性能测试报告</a>，我觉得这份性能测试报告让人觉得做这性能测试的人根本不懂性能测试，我觉得这份报告会把大众带沟里去，所以，想写下这篇文章，做一点科普。</p>
<p>首先，这份测试报告里的主要问题如下：</p>
<p><strong>1）用的全是平均值</strong>。老实说，平均值是非常不靠谱的。</p>
<p><strong>2）响应时间没有和吞吐量TPS/QPS挂钩</strong>。而只是测试了低速率的情况，这是完全错误的。</p>
<p><strong>3）响应时间和吞吐量没有和成功率挂钩。</strong></p>
<p><span id="more-17381"></span></p>
<h4>为什么平均值不靠谱</h4>
<p>关于平均值为什么不靠谱，我相信大家读新闻的时候经常可以看到，<strong>平均工资</strong>，<strong>平均房价</strong>，<strong>平均支出</strong>，等等这样的字眼，<span id="zoom" class="show_c">你就知道为什么平均值不靠谱了。（这些都是数学游戏，对于理工科的同学来说，天生应该有免疫力）</span></p>
<p>软件的性能测试也一样，平均数也是不靠谱的，这里可以参看这篇详细的文章《<a href="http://apmblog.dynatrace.com/2012/11/14/why-averages-suck-and-percentiles-are-great/" target="_blank">Why Averages Suck and Percentiles are Great</a>》，我在这里简单说一下。</p>
<p>我们知道，性能测试时，测试得到的结果数据不总是一样的，而是有高有低的，如果算平均值就会出现这样的情况，假如，测试了10次，有9次是1ms，而有1次是1s，那么平均数据就是100ms，很明显，这完全不能反应性能测试的情况，也许那1s的请求就是一个不正常的值，是个噪点，应该去掉。所以，我们会在一些评委打分中看到要去掉一个最高分一个最低分，然后再算平均值。</p>
<p>另外，中位数（Mean）可能会比平均数要稍微靠谱一些，所谓中位数的意就是把将一组数据按大小顺序排列，处在最中间位置的一个数叫做这组数据的中位数 ，这意味着至少有50%的数据低于或高于这个中位数。</p>
<p>当然，最为正确的统计做法是用百分比分布统计。也就是英文中的TP &#8211; Top Percentile ，TP50的意思在，50%的请求都小于某个值，TP90表示90%的请求小于某个时间。</p>
<p>比如：我们有一组数据：[ 10ms,  1s, 200ms, 100ms]，我们把其从小到大排个序：[10ms, 100ms, 200ms, 1s]，于是我们知道，TP50，就是50%的请求ceil(4*0.5)=2时间是小于100ms的，TP90就是90%的请求ceil(4*0.9)=4时间小于1s。于是：TP50就是100ms，TP90就是1s。</p>
<p>我以前在路透做的金融系统响应时间的性能测试的要求是这样的，<strong>99.9%的请求必须小于1ms，所有的平均时间必须小于1ms。两个条件的限制。</strong></p>
<h4>为什么响应时间（latency）要和吞吐量（Thoughput）挂钩</h4>
<p>系统的性能如果只看吞吐量，不看响应时间是没有意义的。我的系统可以顶10万请求，但是响应时间已经到了5秒钟，这样的系统已经不可用了，这样的吞吐量也是没有意义的。</p>
<p>我们知道，当并发量（吞吐量）上涨的时候，系统会变得越来越不稳定，响应时间的波动也会越来越大，响应时间也会变得越来越慢，而吞吐率也越来越上不去（如下图所示），包括CPU的使用率情况也会如此。所以，当系统变得不稳定的时候，吞吐量已经没有意义了。吞吐量有意义的时候仅当系统稳定的时候。</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-17382" src="https://coolshell.cn/wp-content/uploads/2016/07/BenchmarkOptimalRate.png" alt="BenchmarkOptimalRate" width="535" height="343" srcset="https://coolshell.cn/wp-content/uploads/2016/07/BenchmarkOptimalRate.png 535w, https://coolshell.cn/wp-content/uploads/2016/07/BenchmarkOptimalRate-300x192.png 300w" sizes="(max-width: 535px) 100vw, 535px" /></p>
<p>所以，<strong>吞吐量的值必需有响应时间来卡。</strong>比如：<strong>TP99小于100ms的时候，系统可以承载的最大并发数是1000qps</strong>。这意味着，我们要不断的在不同的并发数上测试，以找到软件的最稳定时的最大吞吐量。</p>
<p>&nbsp;</p>
<h4>为什么响应时间吞吐量和成功率要挂钩</h4>
<p>我们这应该不难理解了，如果请求不成功的话，都还做毛的性能测试。比如，我说我的系统并发可以达到10万，但是失败率是</p>
<p>40%，那么，这10万的并发完全就是一个笑话了。</p>
<p>性能测试的失败率的容忍应该是非常低的。对于一些关键系统，成功请求数必须在100%，一点都不能含糊。</p>
<p>&nbsp;</p>
<h4>如何严谨地做性能测试</h4>
<p>一般来说，性能测试要统一考虑这么几个因素：<strong>Thoughput吞吐量</strong>，<strong>Latency响应时间</strong>，<strong>资源利用</strong>（CPU/MEM/IO/Bandwidth&#8230;），<strong>成功率</strong>，<strong>系统稳定性</strong>。</p>
<p>下面的这些性能测试的方式基本上来源自我的老老东家汤森路透，一家做real-time的金融数据系统的公司。</p>
<p style="padding-left: 30px;"><strong>一，你得定义一个系统的响应时间latency，建议是TP99，以及成功率</strong>。比如路透的定义：99.9%的响应时间必需在1ms之内，平均响应时间在1ms以内，100%的请求成功。</p>
<p style="padding-left: 30px;"><strong>二，在这个响应时间的限制下，找到最高的吞吐量</strong>。测试用的数据，需要有大中小各种尺寸的数据，并可以混合。最好使用生产线上的测试数据。</p>
<p style="padding-left: 30px;"><strong>三，在这个吞吐量做Soak Test，比如：使用第二步测试得到的吞吐量连续7天的不间断的压测系统。</strong>然后收集CPU，内存，硬盘/网络IO，等指标，查看系统是否稳定，比如，CPU是平稳的，内存使用也是平稳的。那么，这个值就是系统的性能</p>
<p style="padding-left: 30px;"><strong>四，找到系统的极限值。比如：在成功率100%的情况下（不考虑响应时间的长短），系统能坚持10分钟的吞吐量。</strong></p>
<p style="padding-left: 30px;"><strong>五，做Burst Test。用第二步得到的吞吐量执行5分钟，然后在第四步得到的极限值执行1分钟，再回到第二步的吞吐量执行5钟，再到第四步的权限值执行1分钟，如此往复个一段时间，比如2天。</strong>收集系统数据：CPU、内存、硬盘/网络IO等，观察他们的曲线，以及相应的响应时间，确保系统是稳定的。</p>
<p style="padding-left: 30px;"><strong>六、低吞吐量和网络小包的测试。</strong>有时候，在低吞吐量的时候，可能会导致latency上升，比如TCP_NODELAY的参数没有开启会导致latency上升（详见<a href="https://coolshell.cn/articles/11564.html" target="_blank">TCP的那些事</a>），而网络小包会导致带宽用不满也会导致性能上不去，所以，性能测试还需要根据实际情况有选择的测试一下这两咱场景。</p>
<p>（注：在路透，路透会用第二步得到的吞吐量乘以66.7%来做为系统的软报警线，80%做为系统的硬报警线，而极限值仅仅用来扛突发的peak）</p>
<p><strong>是不是很繁锁？是的，只因为，这是工程，工程是一门科学，科学是严谨的。</strong></p>
<p>欢迎大家也分享一下你们性能测试的经验和方法。</p>
<p>（全文完）</p>
<p>&nbsp;<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/22242.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/05/etcd-150x150.png" alt="ETCD的内存问题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22242.html" class="wp_rp_title">ETCD的内存问题</a></li><li ><a href="https://coolshell.cn/articles/11454.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="从LongAdder看更高效的无锁实现" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11454.html" class="wp_rp_title">从LongAdder看更高效的无锁实现</a></li><li ><a href="https://coolshell.cn/articles/10910.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/01/trade-off-150x150.jpg" alt="分布式系统的事务处理" width="150" height="150" /></a><a href="https://coolshell.cn/articles/10910.html" class="wp_rp_title">分布式系统的事务处理</a></li><li ><a href="https://coolshell.cn/articles/9703.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/05/图1-3-150x150.jpg" alt="无锁HashMap的原理与实现" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9703.html" class="wp_rp_title">无锁HashMap的原理与实现</a></li><li ><a href="https://coolshell.cn/articles/9169.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/02/Disruptor-150x150.png" alt="并发框架Disruptor译文" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9169.html" class="wp_rp_title">并发框架Disruptor译文</a></li><li ><a href="https://coolshell.cn/articles/8883.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/01/linux-bash-300x225-150x150.jpg" alt="应该知道的Linux技巧" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8883.html" class="wp_rp_title">应该知道的Linux技巧</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/17381.html">性能测试应该怎么做？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/17381.html/feed</wfw:commentRss>
			<slash:comments>77</slash:comments>
		
		
			</item>
		<item>
		<title>开发团队的效率</title>
		<link>https://coolshell.cn/articles/11656.html</link>
					<comments>https://coolshell.cn/articles/11656.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 09 Jun 2014 01:06:11 +0000</pubDate>
				<category><![CDATA[技术管理]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Project]]></category>
		<category><![CDATA[效率]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=11656</guid>

					<description><![CDATA[<p>我之前写过一篇叫《加班与效率》的文章，从概念上说了一些我对“效率”的认识，但是那篇文章趋于概念化，对于一些没有经历过这样的环境的同学来说，可能会觉得太抽象了。很...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/11656.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/11656.html">开发团队的效率</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-full wp-image-11700" src="https://coolshell.cn/wp-content/uploads/2014/06/software_development.png" alt="" width="230" height="231" srcset="https://coolshell.cn/wp-content/uploads/2014/06/software_development.png 230w, https://coolshell.cn/wp-content/uploads/2014/06/software_development-150x150.png 150w, https://coolshell.cn/wp-content/uploads/2014/06/software_development-200x200.png 200w" sizes="(max-width: 230px) 100vw, 230px" />我之前写过一篇叫《<a title="加班与效率" href="https://coolshell.cn/articles/10217.html" target="_blank">加班与效率</a>》的文章，从概念上说了一些我对“效率”的认识，但是那篇文章趋于概念化，对于一些没有经历过这样的环境的同学来说，可能会觉得太抽象了。很早以前就想写一篇更具体一点的，可执行的文章与《<a title="加班与效率" href="https://coolshell.cn/articles/10217.html" target="_blank">加班与效率</a>》这篇文章相辉映，并再把我两年前在杭州QCon上的那个<a href="http://vdisk.weibo.com/s/gN-sQ/1351485199" target="_blank">“<strong>鼓吹工程师文化”的《建一支强大的小团队》</strong></a>（新浪微盘）的观点再加强一下。</p>
<p><strong>但是我遇到了一些思维方式上的麻烦——我讲的总是从我的经历背景出发，没有从其它人的经历背景来讲</strong>。这就好像，我在酷壳里说了很多东西（比如：<a title="我们需要专职的QA吗？" href="https://coolshell.cn/articles/6994.html" target="_blank">专职的QA</a>，<a title="从Code Review 谈如何做技术" href="https://coolshell.cn/articles/11432.html" target="_blank">Code Review很重要</a>，<a title="编程能力与编程年龄" href="https://coolshell.cn/articles/10688.html" target="_blank">编程年龄</a>，<a title="来信， 创业 和 移动互联网" href="https://coolshell.cn/articles/5815.html" target="_blank">创业的</a>，<a title="《Rework》摘录及感想" href="https://coolshell.cn/articles/9156.html" target="_blank">Rework</a>的……），有好些人觉得是不可能甚至太理想，其实我说的那些东西都是实实在在存在的，也是我所经历过的。于是，不同的经历，不同的环境，不同的眼界，造成了——有些人不理解我说的，而我也不能理解他们所说的。</p>
<p>所以，过去的这段时间我一有机会就找一些人交流并观察一些身边的事情，并去试着跟从和理解那些我不能理解的东西。现在觉得差不多了，所以，写下了这篇文章。（但越是去理解对方，我就越坚持我的观点，所以这篇文章可能还是会出现鸡同鸭讲的情形，无所谓了）</p>
<p>本文不讨论任何业务上的效率问题，只讨论软件开发或是软件工程中的效率问题。虽然产品和业务上的效率问题是根本，但是因为本文不是拉仇恨的，我也不想混在一起谈，所以请原谅我在这里先说开发团队的，以后重新开篇文章专门谈产品和业务的。</p>
<p>我下面会罗列几个非常典型的开发方式——<strong>软件开发中的“锁”</strong>，<strong>接力棒式软件开发</strong>，<strong>保姆式软件开发</strong>，<strong>WatchDog软件开发</strong>，<strong>故障驱动式软件开发</strong>。</p>
<p><span id="more-11656"></span></p>
<h4>软件开发中的“锁”</h4>
<p>如果你搞过并发编程，你一定知道什么是“锁”，锁就是用来同步和互斥。我发现有好些开发部门里的各个开发团队间存在很多锁。比如：</p>
<ul>
<li><strong>技术能力上的锁</strong>。有一个项目需要在不同的地方做开发，这些模块用到不同的技术，比如：Java, C/C++, Python，Javascript，但是，这个团队里的每一个开发人员就只懂一门语言，于是，需要配合，需要任务排期，同步互斥锁就很多，于是，一个本来只需要2个人干3周的的工作变成了8个人干两个月。</li>
</ul>
<ul>
<li><strong>负责模块上的锁</strong>。同理，不同的人负责不同的模块，于是一个项目要动好多模块，那么你就需要把这些模块的人找过来，和上面一样。每个人都有自己的时间安排，人越多，锁越多。于是，一个来来只需要2个人干2两周的事，变成了7、8个人干一个多月。</li>
</ul>
<p>我上面并非瞎扯，这都是事实。我们可以看到，</p>
<ul>
<li><strong>时间锁、进度锁</strong>。这堆有不同技能或是负责不同模块的开发人员有锁，有锁你就要等，他们有自己的安排，所以，要协作起来，你就需要排期，去同步。而参与的人越多，你的锁就越多。你协调他们的时间就更复杂。</li>
</ul>
<ul>
<li><strong>沟通锁、利益锁</strong>。而且，最恐怖的事情是，他们之间的沟通成本巨大。他们会花大量的时间在讨论，一个功能是实现在你那边，还是我这边，每个人都有自己的利益和算盘。无形中增加了很多推诿、官僚和政治上的东西。</li>
</ul>
<p>有时候，我们会觉得分工和分模块是产生效率的前提，但是实际情况并不是这样。我们也可以看到，<strong>所谓的“分工”被彻彻底底的滥用了</strong>。他们把“分工”当成了永远只干一件事的借口。</p>
<h5>【解决方案】</h5>
<p><strong>一个程序员应该能够掌握多个语言，也能够负责多个模块甚至不同的职责。如果一个程序员觉得多学习一门语言，多掌握一个模块是件很困难的事，那么这个程序员本质上是不合格的</strong>。</p>
<h4>“接力棒式”软件开发</h4>
<p><strong>在有各种“工作锁”的软件开发团队里，一般都无法避免“接力棒式”的开发</strong>。也就是说，底层的C程序员干完了，交给上层的Java程序员，然后再交给更上层的前端程序员，最后再交给运维人员。这就是接力棒式的开发。</p>
<p>而且，更糟糕的是，如果在引入了软件流程下，这种“接力棒的方式”真是会把你搞崩溃的。比如下游团队开发一个月，交给QA测试一个月，再交给运维分步上线一个月，然后，上游团队拿到下游开发的API后开发一个月，再交给自己的QA测试一个月，然后再交给自己的运维上线一个月，于是，半年就这样过去了。<strong>这是一个由一个一个小瀑布叠出来的一个大瀑布</strong>。</p>
<p>哦，你会说，这个好办啊，上下游不会先商定好接口么？然后做并行开发么？是的，这是其中的一个优化方式，但是需要很好的接口设计。但是，在实际过程中，你会发现（这时我并非信口开河，我说的都是事实），</p>
<ul>
<li>如果这两个上下游团队在一起还好办，要是不在一起，那么，实际情况是，后面的团队会等到前面的团队提测了，才开始开发，本质上就是串行开发的。</li>
</ul>
<ul>
<li>如果有更多的团队呢？比如：A团队 -&gt; B团队 -&gt; C团队 -&gt;D团队呢。接口就变得非常地关键了。而在实际情况下，因为没有好的接口设计人员，所以，在开发过程经常性地修改接口，或者是因为接口不好用也只得忍着。</li>
</ul>
<h5>【解决方案】</h5>
<p>我以前写过一篇叫《<a title="IoC/DIP其实是一种管理思想" href="https://coolshell.cn/articles/9949.html" target="_blank" rel="bookmark">IoC/DIP其实是一种管理思想</a>》，对于这种接力棒的方式，应该反过来，<strong>如果业务应用团队是A团队，那B/C/D团队应该把自己的做成一个开发框架也好，服务化也好，让应用团队自己来接入</strong>。比如：前端做好一个前端开发框架，PE做好一个运维开发框架、各种工具，共享模块团队做好开发框架，让应用团队自己来接入，而不是帮他做。<strong>你会发现，在这么多团队各自P2P勾兑出来的很随意的接口的所带来的成本已经远超过一个统一标准的协议</strong>。</p>
<h4>“保姆式”软件开发</h4>
<p>所谓“保姆式”软件开发就是——我只管吃饭，不管做菜洗碗，就像——衣来伸手，饭来张口的“小皇帝”一样，身边有一堆太监或宫女，不然生活不能自理。这种情况经常见于开发和测试，开发和运维间的关系。很多公司，测试和运维都成了开发的保姆。</p>
<p>我就能看到，很多开发快速写完代码后基本上都不怎么测试就交给QA去测试了，QA一测，我草，各种问题，而只会做黑盒的QA并不能马上就能确定是代码的问题还是环境的问题，所以还要花大量时间排除不是环境问题，才给开发报BUG。很多问题，可能只需要做个Code Review，做个单测就可以发现了，硬要交给QA。运维也是一样的，开发出来的软件根本就没有考虑什么运维的东西，因为有运维人员，所以我才不考虑呢。</p>
<p><strong>这和我们带孩子的道理是一样的，对于孩子来说，如果父母帮孩子做得越多，孩子就越觉得理所应当，就越不会去做</strong>。</p>
<p><strong>“保姆式”开发一般会进化成“保安式”开发</strong>。</p>
<ul>
<li>因为你的团队开发人员的能力不行，设计不行，Code Reivew/UT不做，你就只能找堆QA看着他。</li>
<li>因为Dev/QA只管功能不管运维，所以，还得找堆运维人员看着他们。</li>
<li>因为你的技术人员不懂业务，不懂需求，需要再找个BA，找个产品经理来指挥他。</li>
<li>因为你的技术人员不会管理项目，所以，再搞个项目经理，找个敏捷教练、以及SQA来管着他。</li>
</ul>
<p><strong>就这样，你不行，我找人来看着你，看你的人不行，我再找人来看着看你的人……层层保姆，层层保安。</strong>于是，你就会发现，团队或部门里的人员越来越多，你整天都在开会，整天都在互相解释，互相争吵，会扯淡的人越来越多。那还有个屁的效率。</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-11702" src="https://coolshell.cn/wp-content/uploads/2014/06/worker.jpg" alt="" width="523" height="499" srcset="https://coolshell.cn/wp-content/uploads/2014/06/worker.jpg 523w, https://coolshell.cn/wp-content/uploads/2014/06/worker-300x286.jpg 300w" sizes="(max-width: 523px) 100vw, 523px" />网络上一个非常经典的图片，来源不详，程序员在挖坑，其它人站在当监工</p>
<h5>【解决方案】</h5>
<p style="padding-left: 30px;">1）<strong>不要招只会写代码的“码农”，要招懂“需求”，注重“软件工程”和“软件质量”和“软件维护”的“工程师”</strong>。</p>
<p style="padding-left: 30px;">2）<strong>最好的管理，不是找人来管人，而是自己管自己</strong>。</p>
<p style="padding-left: 30px;">3）<strong>组织和团队中支持性工作的人越少越好，最好不要</strong>。</p>
<p style="padding-left: 30px;">4）<strong>服务化。我服务于你并不代表我要帮你干活，而是代表——我要让你干活干得更爽</strong>。</p>
<p>我在<a href="http://weibo.com/1401880315/B6hC7elDb" target="_blank">微博</a>上说过下面的话，（大家可以体会一下保姆和服务的差别）</p>
<p style="padding-left: 30px;">运维要用“云服务”的思路去做。如果一个公司内的运维团队开发出一堆工具，让做应用开发团队可以很容易地申请机器、存储、网络、中间件、安全等资源，并很容易管理、监控和部署应用，并提供运维资询。而不是帮应用开发团队干活擦屁股当保姆。那么，这个公司就会不经意地做出一个云计算平台来了。</p>
<p>&nbsp;</p>
<h4>“WatchDog式”软件开发</h4>
<p>什么是WatchDog？就是说——<strong>为了解决某个系统的问题，我要用一个新的系统去看着它</strong>。</p>
<ul>
<li>我的系统架构太复杂，出了问题不好查找。咋办？那就搞个专门的特殊的监控系统吧……</li>
</ul>
<ul>
<li>我的系统配置太复杂，容易配错了。咋办？那就加一个配置校验系统吧……</li>
</ul>
<ul>
<li>我的系统配置和真实的情况有时候可能会不一性。咋办？那就加一个巡检系统吧……</li>
</ul>
<ul>
<li>我的系统测试环境和线上环境有时候会搞混了。咋办？那就为线上环境加一个权限控制系统吧……</li>
</ul>
<ul>
<li>我的系统有单点，那就加个负载均衡器吧，负载均衡器的单点呢？那就再加个等价路由器吧……</li>
</ul>
<p><strong>做加法谁不会？就不想去简化一样系统吗？就不能不拆东墙补西墙么？</strong>这些了系统加的越来越多，我看你以后怎么运维。</p>
<p>一开始没有想清楚就放到线上，然后，出了故障后，也无法重新设计和重新架构，只能以打补丁地方式往上打，这就好像一个本来就有缺陷的楼没有盖好，你要拆了重盖是不可能的，也只能不停地打补丁了。字是一只狗，越描越丑。</p>
<h5>【解决方案】</h5>
<p style="padding-left: 30px;"><strong>1）设计想好了再做，多评估几个设计没坏处，简化，简化，简化。</strong></p>
<p style="padding-left: 30px;"><strong>2）残酷无情地还债，就算是CEO来了，也无法阻止我还债的脚步。</strong></p>
<p>&nbsp;</p>
<h4>“故障驱动式”软件开发</h4>
<p>WatchDog式的软件开发通常来说都是“故障驱动式”软件开发的产物。这种开发方式其实就是在表明自己智力和能力的不足。以上线为目的，上了线再说，有什么问题出了再改。</p>
<p>上面的老大或是业务方基本上会说，没关系，我们不一开始并不需要一个完美的系统，你先上了再说，先解业务的渴，我们后面有时间再重构再完善。而有的技术人员也会用“架构和设计是逐步演化出来的”这句话来证明“故障驱动”开发是值得的。</p>
<p>我同意逐步迭代以及架构演化论，但是，我觉得<strong>“系统迭代说”和“架构演化论”被彻彻底底地成为那些能力有限甚至不学无术的人的超级借口</strong>。</p>
<p>你们有没有搞错啊？你们知道什么叫迭代，什么叫演化吗？你们知道，要定位一个线上的故障需要花多大的力气吗？（<a href="http://blog.aliyun.com/341" target="_blank">看看这篇文章</a>你就知道了）你们知道，随随便便去应付局部上你会快，但总体上来说你会慢。</p>
<p>虽然，我看到那些系统在一个又一个的故障后得到一点又一点的改善，但是我想说，为什么一开始不认真不严谨一点呢？我从来就没有见过一个精良的系统是靠一个一个的故障和失败案例给堆出来的，就算是Windows 95/98这样史上最烂的操作系统，如果没有设计精良Windows NT的补位，Windows也早玩完了（看看IE的下场就知道了）。</p>
<h5>【解决方案】</h5>
<p style="padding-left: 30px;"><strong>1）基础知识和理论知识非常重要</strong>。多多使用已有的成熟的方案是关键。</p>
<p style="padding-left: 30px;"><strong>2）对技术要有一颗严谨和敬畏的心。想清楚了再干，坚持高标准，Design for failure! </strong>很多事情都急不得。</p>
<p>&nbsp;</p>
<h4>其它开发方式</h4>
<p>其实，这样的事情还有很多。比如：</p>
<p><strong>1）配置管理上的问题</strong>。对于源代码的配置管理，其实并不是一件简单的事情。配置管理和软件和团队的组构的结构非常有关系。我看到过两种非常没有效率的配置管理，一种是以开项目分支的方式来做项目，同时开很多分支，分支开的时间还很长，导致merge回主干要花大量的时间去解决各种冲突，另一种是N多的团队都在一个代码库中做修改，导致出现很多复杂的问题，比如某团队的改动出现了一个bug，要么所有的团队的功能都得等这个bug被修复才能被发布，要么就是把所有的改动回滚到上一个版本，包括其它团队开发的功能。很明显，软件模块的结构，软件的架构，以及团队的组织形式都会严重影响开发效率。</p>
<p><strong>2）人肉式的软件开发</strong>。大多数的软件团队和主管都会用“人手不够”做为自己开发效率不够的借口，而大多数故障发生的时候，都会使用更重的“人肉流程”来弥补自己能力的不足。他们从来没有想过使用“技术”，使用更“聪明”的方式来解决问题。</p>
<p><strong>3）会议驱动式开发</strong>。人多了，团队多了，想法也就多了，沟通也就多了，于是需要不停得开会开会开会。</p>
<p>&nbsp;</p>
<h4>总结一下</h4>
<p>综上所述，我有如下总结：</p>
<p style="padding-left: 30px;">1）<strong>软件工程师分工分得越细这个团队就越没效率，团队间的服务化是关键的关键</strong>。不管是从语言上还是从软件模块上的人员分工，越细越糟糕。服务化不是我要帮你做事，而是我让你做起事来更容易。</p>
<p style="padding-left: 30px;">2）<strong>你总需要在一个环节上认真，这个环节越往前就越有效率，越往后你就越没效率</strong>。要么你设计和编码认真点，不然，你就得在测试上认真点。要是你设计、编码、测试都不认真，那你就得在运维上认真，就得在处理故障上认真。你总需要在一个地方认真。另外一篇文章你可以看一下——《<a title="多些时间能少写些代码" href="https://coolshell.cn/articles/5686.html" target="_blank">多些时间少写些代码</a>》</p>
<p style="padding-left: 30px;">3）<strong>“小而精的团队”+“条件和资源受限”是效率的根本</strong>。只有团队小，内耗才会小，只有条件或资源受限，才会逼着你去用最经济的手段做最有价值的事，才会逼着你喜欢简单和简化。</p>
<p style="padding-left: 30px;">4）<strong>技术债是不能欠的，要残酷无情地还债</strong>。很多事情，一开始不会有，那么就永远不会有。一旦一个事情烂了，后面只能跟着一起烂，烂得越多，就越没有人敢去还债。</p>
<p style="padding-left: 30px;">5）<strong>软件架构上要松耦合，团队组织上要紧耦合</strong>。</p>
<p style="padding-left: 30px;">6）<strong>工程师文化是关键，重视过程就是重视结果</strong>。只重视结果的KPI等同于“竭泽而渔”和“饮鸩止渴”。</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/19612.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/07/1920px-Margaret_Hamilton_-_restoration-e1563697198766-1-150x150.jpg" alt="50年前的登月程序和程序员有多硬核" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19612.html" class="wp_rp_title">50年前的登月程序和程序员有多硬核</a></li><li ><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Leetcode 编程训练" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_title">Leetcode 编程训练</a></li><li ><a href="https://coolshell.cn/articles/11170.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/03/42-150x150.jpg" alt="如何用最有创造力的方式输出42" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11170.html" class="wp_rp_title">如何用最有创造力的方式输出42</a></li><li ><a href="https://coolshell.cn/articles/10217.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/07/Work-Overtime-150x150.jpg" alt="加班与效率" width="150" height="150" /></a><a href="https://coolshell.cn/articles/10217.html" class="wp_rp_title">加班与效率</a></li><li ><a href="https://coolshell.cn/articles/8387.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/10/Learnable_Programming-150x150.jpg" alt="Bret Victor &#8211; Learnable Programming" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8387.html" class="wp_rp_title">Bret Victor &#8211; Learnable Programming</a></li><li ><a href="https://coolshell.cn/articles/4951.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/19.jpg" alt="软件公司的两种管理方式" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4951.html" class="wp_rp_title">软件公司的两种管理方式</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/11656.html">开发团队的效率</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/11656.html/feed</wfw:commentRss>
			<slash:comments>153</slash:comments>
		
		
			</item>
		<item>
		<title>从Code Review 谈如何做技术</title>
		<link>https://coolshell.cn/articles/11432.html</link>
					<comments>https://coolshell.cn/articles/11432.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Sat, 12 Apr 2014 08:28:01 +0000</pubDate>
				<category><![CDATA[技术管理]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[Code Review]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=11432</guid>

					<description><![CDATA[<p>（这篇文章缘由我的微博，我想多说一些，有些杂乱，想到哪写到哪） 这两天，在微博上表达了一下Code Review的重要性。因为翻看了阿里内部的Review Bo...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/11432.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/11432.html">从Code Review 谈如何做技术</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-medium wp-image-11440" alt="" src="https://coolshell.cn/wp-content/uploads/2014/04/code_review-225x300.jpg" width="225" height="300" srcset="https://coolshell.cn/wp-content/uploads/2014/04/code_review-225x300.jpg 225w, https://coolshell.cn/wp-content/uploads/2014/04/code_review-203x270.jpg 203w, https://coolshell.cn/wp-content/uploads/2014/04/code_review.jpg 358w" sizes="(max-width: 225px) 100vw, 225px" />（这篇文章缘由我的微博，我想多说一些，有些杂乱，想到哪写到哪）</p>
<p>这两天，在微博上表达了一下Code Review的重要性。因为翻看了阿里内部的Review Board上的记录，从上面发现Code Review做得好的是一些比较偏技术的团队，而偏业务的技术团队基本上没有看到Code Review的记录。当然，这并不能说没有记录他们就没有做Code Review，于是，我就问了一下以前在业务团队做过的同事有没有Code Review，他告诉我不但没有Code Review，而且他认为Code Review没用，因为：</p>
<p style="padding-left: 30px;">1）工期压得太紧，时间连coding都不够，以上线为目的，</p>
<p style="padding-left: 30px;">2）需求老变，代码的生命周期太短。所以，写好的代码没有任何意义，烂就烂吧，反正与绩效无关。</p>
<p>我心里非常不认同这样的观点，我觉得我是程序员，我是工程师，就像医生一样，不是把病人医好就好了，还要对病人的长期健康负责。对于常见病，要很快地医好病人很简单，下猛药，大量使用抗生素，好得飞快。但大家都知道，这明显是“饮鸩止渴”、“竭泽而渔”的做法。医生需要有责任心和医德，我也觉得程序员工程师也要有相应的责任心和相应的修养。东西交给我我必需要负责，我觉得这种负责和修养不是”做出来“就了事了，而是要到“做漂亮”这个级别，这就是“山寨”和“工业”的差别。而只以“做出来”为目的标准，我只能以为，这样的做法只不过是“按部就班”的堆砌代码罢了，和劳动密集型的“装配生产线”和“砌砖头”没有什么差别，在这种环境里呆着还不如离开。</p>
<p>老实说，因为去年我在业务团队的时候，我的团队也没有做Code Review，原因是多样的。其中一个重要原因是，我刚来阿里，所以，需要做的是在适应阿里的文化，任何公司都有自己的风格和特点，任何公司的做法都有他的理由和成因，对于我这样的一个初来者，首要的是要适应和观察，不要对团队做太多的改动，跟从、理解和信任是融入的关键。（注：在建北京团队和不要专职的测试人员上我都受到了一些阻力），所以跟着团队走没有玩Code Review。干了一年后，觉得我妥协了很多我以前所坚持的东西，觉得自己的标准在降低，想一想后背拔凉拔凉的，所以我决定坚持，而且还要坚持高标准。</p>
<p><span id="more-11432"></span></p>
<p>对于Code Review很重要的这个观点，在微博上抛出来后，被一些阿里的工程师，架构师/专家，甚至资深架构师批评，我在和他们回复和讨论的过程中，居然发现有个“因为对方用户的设置”我无法回复了（我被拉黑了，还有一些直接就是冷讽和骂人了，微博中我就直接删除了）。这些批评我的阿里工程师/架构师的观点总结一下如下：（<strong>顺便说一下，阿里内还是有很多团队坚持做Code Review的</strong>）</p>
<p style="padding-left: 30px;">1）到业务团队体会一下，倒逼工期的项目有多少？订好交付日期后再要求提前1个月的有多少？现在是做到已经不容易，更不谈做得漂亮！。</p>
<p style="padding-left: 30px;">2）Code Review是一种教条，意义不大，有测试，只要不出错，就可以了。</p>
<p style="padding-left: 30px;">3）目标都是改进质量，有限的投入总希望能有最大的产出，不同沉湎改进质量的方式不一样，业务应用开发忙的跟狗一样，而且业务逻辑变化快，通用性差，codereviw的成本要比底层高。</p>
<p style="padding-left: 30px;"><span style="line-height: 1.5em;">4）现在的主要矛盾是倒排出来的工期和不靠谱的程序员之间的矛盾，我认为cr不是解决这个问题的银弹。不从实际情况出发光打正义的嘴炮实在太过于自慰了 。</span></p>
<p><strong>我们可以看到，上面观点其实和Code Review没有太多关系，其实是在抱怨另外的问题</strong>。这些观点其实是技术团队和业务团队的矛盾，但不知道为什么强加给了我的“Code Review很重要”的这个观点，然后这些观点反过来冲击“Code Reivew”，并说“Code Review无用”。这种讨论问题的方式在很常见，你说A，我说B，本来A、B是两件事，但就是要混为一谈，然后似是而非的用B来证明你的A观点是错的。（也许，这些工程师/架构师心存怨气，需要一个发泄的通道）</p>
<p><strong>我觉得，很多时候，人思考问题思考不清楚，很大一部分原因是因为把很多问题混为一谈</strong>，连我自己有些时候都会这样。引以为戒。</p>
<p>即然被混为一谈，那我就来拆分一下，也是下面这三个问题：</p>
<ul>
<li>Code Review有没有用的问题。</li>
<li>Code Review做不起来的问题。</li>
<li>业务变化快，速度快的问题，技术疲于跟命。</li>
</ul>
<h4>Code Review</h4>
<p>你Google一下Code Reivew这个关键词，你就会发现Code Review的好处基本上是不存在争议的，有很多很多的文章和博文都在说Code Review的重要性，怎么做会更好，而且很多公司在面试过程中会加入“Code Review”的问题。打开<a href="http://zh.wikipedia.org/wiki/%E4%BB%A3%E7%A0%81%E5%AE%A1%E6%9F%A5" target="_blank">Wikipedia的词条</a>你会看到这样的描述——</p>
<blockquote><p>卡珀斯·琼斯（Capers Jones）分析了超过12,000个软件开发项目，其中使用正式代码审查的项目，发现潜在缺陷率约在60-65%之间，若是非正式的代码审查，发现潜在缺陷率不到50%。大部份的测试，发现的潜在缺陷率会在30%左右。</p>
<p>对于一些关键的软件（例如安全关键系统的嵌入式软件），一般的代码审查速度约是一小时150行程序码，一小时审查数百行程序码的审查速度太快，可能无法找到程序中的问题。代码审查一般可以找到及移除约65%的错误，最高可以到85%。</p>
<p>也有研究针对代码审查找到的缺陷类型进行分析。代码审查找到的缺陷中，有75%是和计算机安全隐患有关。对于产品生命周期很长的软件公司而言，代码审查是很有效的工具。</p></blockquote>
<p><strong>Code Review的好处我觉得不用多说了，主要是让你的代码可以更好的组织起来，有更易读，有更高的维护性，同时可以达到知识共享，找到bug只是其中的副产品</strong>。这个东西已经不新鲜了，你上网可以找到很多文章，我就不多说了。就像你写程序要判断错误一样，Code Review也是最基本的常识性的东西。</p>
<p>我从2002年开始就浸泡在严格的Code Review中，我的个人成长和Code Review有很大的关系，如果我的成长过程中没有经历过Code Review这个事，我完全不敢想像。</p>
<p><strong>我个人认为代码有这几种级别：1）可编译，2）可运行，3）可测试，4）可读，5）可维护，6）可重用。通过自动化测试的代码只能达到第3）级，而通过Code Review的代码少会在第4）级甚至更高。</strong>关于Code Review，你可以参看本站的《<a title="Code Review中的几个提示" href="https://coolshell.cn/articles/1302.html" target="_blank">Code Review中的几个提示</a>》</p>
<p>可见，Code Review直接关系到了你的工程能力！</p>
<h4>Code Review 的问题</h4>
<p>有下面几个情况会让你的Code Review没有效果。</p>
<p>首当其冲的是——“<strong>人员能力不足</strong>”，我经历过这样的情况，Code Review的过程中，大家大眼瞪小眼，没有什么好的想法，不知道什么是好的代码，什么是不好的代码。导致Code Review大多数都在代码风格上。今天，我告诉你，代码风格这种事，是每个程序员自查的事情，不应该浪费大家的时间。对此，我有两个建议：1）你团队的人招错了，该换血了。2）让你团队的人花时候阅读一下《<a href="http://book.douban.com/subject/1477390/" target="_blank">代码大全</a>》这本书（当然，还要读很多基础知识的书）。</p>
<p>次当其冲的是——“<strong>结果更重要</strong>”，也就是说，做出来更重要，做漂亮不重要。因为我的KPI和年终奖based on how many works I&#8217;ve done！而不是How perfect they are ! 这让我想到那些天天在用Spring MVC 做CRUD网页的工程师，我承认，他们很熟练。大量的重复劳动。其实，仔细想一下好多东西是可以框架化，模板化，或是自动生成的。所以，为了堆出这么多网页就停地去堆，做的东西是很多，但是没有任何成长。急功近利，也许，你做得多，拿到了不错的年终奖，但是你失去的也多，失去了成为一个卓越工程师的机会。你本来可以让你的月薪在1-2年后翻1-2倍的，但一年后你只拿到了为数不多的年终奖。</p>
<p>然后是——“<strong>人员的态度问题</strong>”，一方面就是懒，不想精益求精，只要干完活交差了事。对此，你更要大力开展Code Review了，让这种人写出来的代码曝光在更多人面前，让他为质量不好的代码蒙羞。另一方面，有人会觉得那是别人的模块，我不懂，也没时间 去懂，不懂他的业务怎么做Code Review? 我只想说，如果你的团队里这样的“各个自扫门前雪”的事越多，那么这个团队也就越没主动性，没有主动性也就越不可能是个好团队，做的东西也不可能好。而对于个人来说，也就越不可能有成长。</p>
<p>接下来是——“<strong>需求变化的问题</strong>”，有人认识，需求变得快，代码的生存周期比较短，不需要好的代码，反正过两天这些代码就会被废弃了。如果是一次性的东西，的确质量不需要太高，反正用了就扔。但是，我觉得多多少少要Review一下这个一次性的烂代码不会影响那些长期在用的代码吧，如果你的项目全部都是临时代码，那么你团队是不是也是一个临时团队？关于如果应对需求变化，你可以看看本站的《<a href="https://coolshell.cn/articles/6950.html" rel="bookmark">需求变化与IoC</a>》《<a href="https://coolshell.cn/articles/7236.html" target="_blank">Unix的设计思想来应对多变的需求</a>》的文章 ，从这些文章中，我相信你可以看到对于需求变化的代码质量需要的更高。</p>
<p>最后是——“<strong>时间不够问题</strong>”，如果是业务逼得紧，让你疲于奔命，那么这不是Code Review好不好问题，这是需求管理和项目管理的问题以及别的非技术的问题。下面我会说。</p>
<p>不管怎么样，上述Code Review的问题不应该成为“Code Review无意义”的理由或借口，这就好像“因噎废食”一样。干什么事都会有困难和问题的，有的人就这样退缩了，但有的人看得到利大于弊，还是去坚持，人与人的不同正在这个地方。这就是为什么运动会受伤，但还是会人去运动，而有人因为怕受伤就退缩了一样。</p>
<h4>被业务逼得太紧</h4>
<p>被业务逼得太紧，需求乱变，这其实和Code Review没有多大关系了。对此，我想先讲一个我的故事。</p>
<p>我去年在阿里的聚石塔，刚去的时候，聚石塔正在做一个很大的重构——对架构的大调整。因此压了很多业务需求，等这个项目花了2-3个月做完了后，一下子涌入了30-50个需求，还规定一个月完成，搞得团队疲于奔命。在累了两周后，我仔细分析了一下这些需求，发现很多需求是在重复做阿里云已经做过的东西，还有一些需求是因为聚石塔这个平台不规范没有标准所产生的问题。于是，我做了这么三件事：</p>
<p style="padding-left: 30px;">1）重新定义聚石塔这个产品主要目标和范围，确定哪些该做，哪些不该做。</p>
<p style="padding-left: 30px;">2）为聚石塔制定标准 ，让阿里云的API都长得基本一样，并制订云资源的接入标准。</p>
<p style="padding-left: 30px;">3）推动重构阿里云的Portal系统，不再实现阿里云已经做过的东西，与阿里云紧密结合。</p>
<p>这些事情推动起来并不容易，聚石塔的业务方一开始也不理解，我和产品一起做业务方的工作，而阿里云也被我逼得很惨（在这里一并感谢，尤其阿里云的同学，老实说，和阿里云跨团队合作中是我这么多年来感觉最好的一次，相当赞）。通过这个事，聚石塔需求一下就有质的下降了。搞得还有几个工程师来和我说，你这么搞，聚石塔就没事可干了。姑且不说工程师对聚石塔的理解是怎么样的。 我只想说，我大量地减少了需求，尽最大可能联合了该联合的人，而不是自己闭门造车，并让产品的目标和方向更明确了。做了这些事情后，大家不但不用加班，而且还有时间充电去学技术，并为聚石塔思考未来的方向和发展。去年公司996的时候，我的团队还在965（搞得跟异教徒似的），而且还有很多时间去专研新的东西。</p>
<p>说这个故事，我不是为了得瑟，而是因为有些人在微博上抨击我是一个道貌岸然的只会谈概念讲道理的装逼犯。所以，我告诉大家我在聚石塔是怎么做的，我公开写在这里，你也可以向相关的同学去求证我说的是不是真的。也向你证明，我可能是个装逼犯，但绝不是只会谈概念讲道理的装逼犯。</p>
<p>被业务方逼得紧不要抱怨，你没有时间被逼得像牲口一样工作，这个时候，你需要的是暂停一下想一想，为什么会像牲口一样？而这正是让你变得聪明的机会。</p>
<p>我为你总结一下，</p>
<p style="padding-left: 30px;">1）你有没有去Review业务部门给你的这么多的需求，哪些是合理的，哪些是不合理的。在Amazon，开发工程师都会被教育拿到需求后一定要问——“为什么要做？业务影响度有多大？有多少用户受益？”，回答不清这个问题，没有数据的支持，就不做。所以，产品经理要做很多数据挖拙和用户调研的工作，而不是拍拍脑袋，听极少数的用户抱怨就要开需求了。</p>
<p style="padding-left: 30px;">2）产品经理也要管理和教育的。你要告诉你的产品经理：“你是一个好的产品经理，因为你不但对用户把握得很好，也会对软件工艺把握得很好。你不但会开出外在的功能性需求，也同样会开出内在的让软件系统更完善的非功能性需求。你不是在迁就用户，而是引导用户。你不会无限制地加功能，而是把握产品灵魂控制并简化功能。你会为自己要做的和不做东西的感到同样的自豪。”你要告诉你的产品经理：“做一个半成品不如做好半年产品”（更多这样的观点请参看《<a title="《Rework》摘录及感想" href="https://coolshell.cn/articles/9156.html" target="_blank">Rework摘录和感想</a>》）</p>
<p style="padding-left: 30px;">3）做事情是要讲效率的。Amazon里喜欢使用一种叫T-Shirt Size Estimation的评估方法来优先做投入小产出大的“Happy Case”。关于什么是效率，什么是T-Shirt Size Estimation，你可以看看《<a title="加班与效率" href="https://coolshell.cn/articles/10217.html" target="_blank">加班与效率</a>》一文 。</p>
<p style="padding-left: 30px;">4）需求总是会变化的，不要抱怨需求变化太快。你应该抱怨的是为什么我们没有把握好方向？老变？这个事就像踢足球一样，你要去的地方是球将要去的地方，而不是球现在的地方。你要知道球要去哪里，你就知道球之前是怎么动的，找到了运动轨迹后，你才知道球要去像何方。如果你都不知道球要去向何方，那你就是一只无头苍蝇一样，东一下西一下。</p>
<p><strong>当你忙得跟牲口一样，你应该停下来，问一下自己，自己成为牲口的原因，是不是就是因为自己做事时候像就牲口一样思考？</strong></p>
<h4>其它</h4>
<p>最后，我在给阿里今年新入职的毕业生的“技塑人生”的分享中，我给他们布置了5、6个Homework，分享几个给大家：</p>
<p style="padding-left: 30px;">1）重构或写一个模块，把他做成真正的Elegant级别。</p>
<p style="padding-left: 30px;">2）与大家分享一篇或几篇技术文章 ，并收获10-30个赞。</p>
<p style="padding-left: 30px;">3）降低现有至少20%的重复工作或维护工作</p>
<p style="padding-left: 30px;">4）拒绝或简化一个需求（需要项目中所有的Stakeholders都同意）</p>
<p>部署这些作业的原因，是我希望新入行的同学们对自己的工作坚持高的标准，我知道你们会因为骨感的现实而妥协，但是我希望你们就算在现实中妥协了也要在内心中坚持尽可能高的标准，不要习惯成自然，最后被社会这个大染缸给潜移默化了。因为你至少要对自己负责。<strong>对自己负责就是，用脚投票，如果妥协得受不了了就离开吧</strong>。</p>
<p>芝兰生于空谷，不以无人而不芳！君子修身养道，不以穷困而改志！</p>
<p>谢谢听我唠叨。</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/4875.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/06/20110620115951113-150x150.gif" alt="一个空格引发的惨剧" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4875.html" class="wp_rp_title">一个空格引发的惨剧</a></li><li ><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/10/communication-150x150.png" alt="聊聊团队协同和协同工具" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_title">聊聊团队协同和协同工具</a></li><li ><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/http_method-150x150.png" alt="“一把梭：REST API 全用 POST”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_title">“一把梭：REST API 全用 POST”</a></li><li ><a href="https://coolshell.cn/articles/22157.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/monitoring-150x150.jpeg" alt="谈谈公司对员工的监控" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22157.html" class="wp_rp_title">谈谈公司对员工的监控</a></li><li ><a href="https://coolshell.cn/articles/21589.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2021/07/knowledge_sharing-300x169-1-150x150.jpeg" alt="如何做一个有质量的技术分享" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21589.html" class="wp_rp_title">如何做一个有质量的技术分享</a></li><li ><a href="https://coolshell.cn/articles/20977.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/08/programmer.01-e1596792460687-150x150.png" alt="程序员如何把控自己的职业" width="150" height="150" /></a><a href="https://coolshell.cn/articles/20977.html" class="wp_rp_title">程序员如何把控自己的职业</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/11432.html">从Code Review 谈如何做技术</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/11432.html/feed</wfw:commentRss>
			<slash:comments>218</slash:comments>
		
		
			</item>
		<item>
		<title>由苹果的低级Bug想到的</title>
		<link>https://coolshell.cn/articles/11112.html</link>
					<comments>https://coolshell.cn/articles/11112.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 24 Feb 2014 00:12:11 +0000</pubDate>
				<category><![CDATA[C/C++语言]]></category>
		<category><![CDATA[业界新闻]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[goto]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=11112</guid>

					<description><![CDATA[<p>2014年2月22日，在这个“这么二”的日子里，苹果公司推送了 iOS 7.0.6（版本号11B651）修复了 SSL 连接验证的一个 bug。官方网页在这里：...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/11112.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/11112.html">由苹果的低级Bug想到的</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-full wp-image-11123" src="https://coolshell.cn/wp-content/uploads/2014/02/apple_goto_fail.png" alt="" width="260" height="158" /> 2014年2月22日，在这个“这么二”的日子里，苹果公司推送了 iOS 7.0.6（版本号11B651）修复了 SSL 连接验证的一个 bug。官方网页在这里：<a href="http://support.apple.com/kb/HT6147" target="_blank">http://support.apple.com/kb/HT6147</a>，网页中如下描述：</p>
<blockquote><p><strong>Impact</strong>: An attacker with a privileged network position may capture or modify data in sessions protected by SSL/TLS</p>
<p><strong>Description</strong>: Secure Transport failed to validate the authenticity of the connection. This issue was addressed by restoring missing validation steps.</p></blockquote>
<p>也就是说，这个bug会引起中间人攻击，bug的描述中说，这个问题是因为miss了对连接认证的合法性检查的步骤。</p>
<p>这里多说一句，<strong>一旦网上发生任何的和SSL/TL相关的bug或安全问题，不管是做为用户，还是做为程序员的你，你一定要高度重视起来</strong>。因为这个网络通信的加密协议被广泛的应用在很多很多最最需要安全的地方，如果SSL/TLS有问题的话，意味着这个世界的计算机安全体系的崩溃。</p>
<h4>Bug的代码原因</h4>
<p>Adam Langley的《<a href="https://www.imperialviolet.org/2014/02/22/applebug.html">Apple&#8217;s SSL/TLS bug</a> 》的博文暴出了这个bug的细节。（在苹果的开源网站上，通过查看苹果的和SSL/TLS有关的代码变更，我们可以在文件<a href="http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c" target="_blank">sslKeyExchange.c</a>中找到下面的代码）</p>
<p><span id="more-11112"></span></p>
<pre data-enlighter-language="c" class="EnlighterJSRAW" data-enlighter-highlight="12">static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
                                 uint8_t *signature, UInt16 signatureLen)
{
	OSStatus        err;
	...

	if ((err = SSLHashSHA1.update(&amp;hashCtx, &amp;serverRandom)) != 0)
		goto fail;
	if ((err = SSLHashSHA1.update(&amp;hashCtx, &amp;signedParams)) != 0)
		goto fail;
		goto fail;
	if ((err = SSLHashSHA1.final(&amp;hashCtx, &amp;hashOut)) != 0)
		goto fail;
	err = sslRawVerify(ctx,
                       ctx-&gt;peerPubKey,
                       dataToSign,				/* plaintext */
                       dataToSignLen,			/* plaintext length */
                       signature,
                       signatureLen);
	if(err) {
		sslErrorLog(&quot;SSLDecodeSignedServerKeyExchange: sslRawVerify &quot;
                    &quot;returned %d\n&quot;, (int)err);
		goto fail;
	}

fail:
    SSLFreeBuffer(&amp;signedHashes);
    SSLFreeBuffer(&amp;hashCtx);
    return err;
}</pre>
<p>注意，我高亮的地方，也就是那里有两个goto fail; 因为if语句没有加大括号，所以，只有第一个goto是属于if的，而第二个goto则是永远都会被执行到的（注：这里不是Python是C语言，缩进不代表这个语句属于同一个语句块）。也就是说，就算是前面的if检查都失败了（err  == 0），也会goto fail。我们可以看到fail标签中释放完内存后就会return err;</p>
<p>你想一下，<strong>这段程序在SSLHashSHA1.update()  返回成功，也就是返回0 的时候会发生什么样的事？是的，真正干活的 sslRawVerify()被bypass了。而且这个函数SSLVerifySignedServerKeyExchange() 还返回了0，也就是成功了！</strong>尼玛！你可能想到酷壳网上之前《<a title="一个空格引发的惨剧" href="https://coolshell.cn/articles/4875.html" target="_blank">一个空格引发的惨剧</a>》的文章。都是低级bug。</p>
<p>这个低级bug在这个周末在网上被炒翻了天，你可以<strong><a href="https://twitter.com/search?q=%23gotofail" target="_blank">上Twiter上看看#gotofail的标签的盛况</a></strong>。<strong>Goto Fail必然会成为历史上的一个经典事件</strong>。</p>
<p>如果你喜欢XKCD，你一定会想到这个漫画：</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://sslimgs.xkcd.com/comics/goto.png" alt="" width="740" height="201" /></p>
<p><span style="line-height: 1.5em;"><strong>注意</strong>：这个bug不会影响TLS 1.2版本，因为1.2版本不会用这个函数，走的是另一套机制。但是别忘了client端是可以选择版本的。</span></p>
<p>如果你想测试一下你的浏览器是否会有问题，<strong>你可以上一下当天就上线的<a href="https://gotofail.com/" target="_blank"> https://gotofail.com</a> 网站</strong></p>
<h4>一些思考</h4>
<p>下面是我对这个问题的一些思考。</p>
<h5>0）关于编译报警</h5>
<p>有人在说苹果的这个代码中的goto语句会产生死代码——dead code，也就是永远都不会执行到的代码，C/C++的编程器是会报警的。但，实际上，dead code在默认上的不会报警的。即使你加上-Wall，GCC 4.8.2 或 Clang 3.3 都不会报警，包括Visual Studio 2012在默认的报警级别也不会（默认是/W3级，需要上升到/W4级以上，但是升级到/W4上，你的工程可能会有N多的Warning，你不一定能看得过来）。gcc和Clang有一个参数叫：-Wunreachable-code，是可以对这种情况报警的，但即没有被包括在-Wall里。原因是，这个参数有很多的问题，因为编译器的优化代码的行为，这个参数并不能对每种情况都准确地报告。另请注意，GCC的新版本中剔除了这个参数。当然，其它一些静态的代码检查工具也可以检查这个低级的问题。</p>
<p>另外，是不是用IDE的代码自动化格式工具也可以帮上一点忙呢？至少可以把那个缩进变成让人一看就觉得有问题。</p>
<h5>1）关于Code Merge 和 Code Review</h5>
<p>你可以通过这里的代码比较看到这个bug的diff，也可以到<a href="https://gist.github.com/alexyakoubian/9151610/revisions" target="_blank">这里看看</a>（631行）。</p>
<blockquote style="font-size: 11px;"><p>diff -urN &lt;(curl -s http://opensource.apple.com/source/Security/Security-55179.13/libsecurity_ssl/lib/sslKeyExchange.c\?txt) \ &lt;(curl -s http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c\?txt) \</p></blockquote>
<p>通过code diff你可以看到，<strong>苹果公司是在重构代码——为很多函数去掉了ctx的参数</strong>。</p>
<p>所以，我们可以猜测，两个goto fail语句，可能是因为对code在不同branch上做merge发生的。版本工具merge代码的时候，经常性的会出现这样的问题。如果代码的diff很多，这个问题会很容易就没有注意到。就算有code review，这个有问题的代码也很难被找出来的。<strong>如果你来review下面的diff，你会注意到这个错误吗？</strong></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2014/02/gotofail.jpg" alt="" width="560" height="275" /></p>
<p>也就是说，在重构分支上的代码是对的，但是在分支merge的时候，被merge工具搞乱了。所以说，<strong>我们在做code merge的时候，一定要小心小心再小心，不能完全相信merge工具</strong>。</p>
<h5>2）关于测试</h5>
<p>很明显，这个bug很难被code review发现。对于重构代码和代码merge里众多的diff，是很难被review的。</p>
<p>当然，“事后诸葛亮”的人们总是很容易地说这个问题可以被测试发现，但是实际情况是这样的吗？</p>
<p>这个问题也很难被功能测试发现，因为这个函数在是在网络握手里很深的地方，功能 测试不一定能覆盖得那么深，你要写这样的case，必需对TLS的协议栈非常熟悉，熟悉到对他所有的参数都很熟悉，并能写出针对每一个参数以及这些参数的组合做一堆test case，这个事情也是一件很复杂的事。要写出所有的case本身就是一件很难很难的事情。关于这个叫SSLVerifySignedServerKeyExchange()函数的细节，你可以看看相关的<a href="https://tools.ietf.org/html/rfc5246#section-7.4.3">ServerKeyExchange</a> RFC文档。</p>
<p>如果只看这个问题的话，你会说对这个函数做的 Unit Test 可以发现这个问题，是的。但是，别忘了SSL/TLS这么多年了，这些基础函数都应该是很稳定的了， 在事前，我们可能不会想到要去为这些稳定了多少年的函数写几个Unit Test。</p>
<p><strong>只要有足够多的时间，我们是可以对所有的功能点，所有的函数都做UT，也可以去追求做代码覆盖和分支覆盖一样。但有一点我们却永远无法做到，那就是——穷举所有的负面案例</strong>。所以，对于测试来说，我们不能走极端，需要更聪明的测试。就像我在《<a title="我们需要专职的QA吗？" href="https://coolshell.cn/articles/6994.html" target="_blank">我们需要专职的QA</a>》文章里的说过的——<strong>测试比coding难度大多了，测试这个工作只有高级的开发人员才做得好。我从来不相信不写代码的人能做好测试。</strong></p>
<p>这里，<strong>我并不是说通过测试来发现这个问题的可能性不大，我想说的是，测试很重要，单测更重要。但是，我们无法面面俱到</strong>。在我们没有关注到的地方，总会发生愚蠢的错误。</p>
<p>P.S.，在各大网站对这个事的讨论中，我们可以看到OS X下的curl命令居然可以接受一个没有验证过的IP地址的https的请求，虽然现在还没有人知道这事的原因，但是，这可能是没有在测试中查到的一个原因。</p>
<h5>3）关于编码风格</h5>
<p><span style="line-height: 1.5em;">对于程序员来说，在C语言中，省掉语句大括号是一件非常不明智 的事情。如我们强制使用语句块括号，那么，这两个goto fail都会在一个if的语句块里，而且也容易维护并且易读。（另外，通过这个bug，我们可以感受到，像Python那样，用缩进来表示语句块，的确是挺好的一件事）</span></p>
<p>也有人说，如果你硬要用只有单条语句，且不用语句块括号，那么，这就是一条语句，应该放在同一行上。如下所示：</p>
<p><code data-enlighter-language="c" class="EnlighterJSRAW">if  (check_something)   do_something(); </code></p>
<p>但是这样一来，你在单步调试代码的时候，就有点不爽了，当你step over的时候，你完全不知道if的条件是真还是假。所以，还是分多行，加上大括号会好一些。</p>
<p>相似的问题，我很十多年前也犯过，而且那次我出的问题也比较大，导致了用户的数据出错。那次就是维护别人的代码，别人的代码就是没有if的语句块括号，就像苹果的代码那样。<span style="line-height: 1.5em;">我想在return z之前调用一个函数，结果就杯具了：</span></p>
<pre data-enlighter-language="c" class="EnlighterJSRAW" data-enlighter-highlight="6">if ( ...... )
    return x;
if ( ...... )
    return y;
if ( ...... )
    foo();
    return z;</pre>
<p>这个错误一不小心就犯了，因为人的大脑会相当然地认为缩进的都是一个语句块里的。但是如果原来的代码都加上了大括号，然后把缩进做正常，那么对后面维护的人会是一个非常好的事情。就不会犯我这个低级错误了。就像下面的代码一样，虽然写起来有点罗嗦，但利人利己。</p>
<pre data-enlighter-language="c" class="EnlighterJSRAW">if ( ...... ){
    return x;
}
if ( ...... ){
    return y;
}
if ( ...... ){
    return z;
}</pre>
<p>与此类似的代码风格还有如下，你觉得哪个更容易阅读呢？</p>
<ul>
<li>if (!p)    和  if (p == NULL)</li>
</ul>
<ul>
<li>if (p)    和  if (p != NULL)</li>
</ul>
<ul>
<li>if (!bflag)  和 if  (bflag == false)</li>
</ul>
<ul>
<li>if ( CheckSomthing() )  和 if ( CheckSomething() == true )</li>
</ul>
<p>另外还有很多人在switch 语句里用case来做if，也就是说case后面没有break。就像<a href="http://en.wikipedia.org/wiki/Duff's_device" target="_blank">Duff&#8217;s Device</a>一样，再配以goto，代码就写得相当精彩了（这里<a href="https://github.com/agentzh/luajit2/blob/master/src/host/buildvm.c#L395" target="_blank">有个例子</a>）</p>
<p><span style="line-height: 1.5em;">所以说，代码不是炫酷的地方是给别人读的。</span></p>
<p>另外，我在想，为什么苹果的这段代码不写成下面这样的形式？你看，下面这种情况不也很干净吗？</p>
<pre data-enlighter-language="c" class="EnlighterJSRAW">
if (  ((err = ReadyHash(&amp;SSLHashSHA1, &amp;hashCtx)) != 0 )
       || ((err = SSLHashSHA1.update(&amp;hashCtx, &amp;clientRandom)) != 0)
       || ((err = SSLHashSHA1.update(&amp;hashCtx, &amp;serverRandom) != 0)
       || ((err = SSLHashSHA1.update(&amp;hashCtx, &amp;signedParams) != 0)
       || ((err = SSLHashSHA1.final(&amp;hashCtx, &amp;hashOut)) != 0)) {

     goto fail;
}
</pre>
<p>其实，还可以做一些代码上的优化，比如，把fail标签里的那些东西写成一个宏，这样就可以去掉goto语句了。</p>
<h5>4）关于goto语句</h5>
<p>关于goto语句，1968年，<a href="http://en.wikipedia.org/wiki/Edsger_Dijkstra">Edsger Dijkstra</a> 投了一篇文章到Communications of the ACM。原本的标题是《A Case Against the Goto Statement》。CACM编辑<a href="http://en.wikipedia.org/wiki/Niklaus_Wirth">Niklaus Wirth</a>灵感来了，把标题改为我们熟知的 《<a href="http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html" target="_blank">Go To Statement Considered Harmful</a>》Dijkstra写的内容也是其一贯的犀利语气，文中说：“几年前我就观察到，一个程序员的品质是其程序中goto语句的密度成反比的”，他还说，“后来我发现了为什么goto语句的使用有这么严重的后果，并相信所有高级语言都应该把goto废除掉。”  （<strong>花絮</strong>：因为，这篇文章的出现，计算学界开始用&#8217; <a href="http://en.wikipedia.org/wiki/Considered_harmful">X considered harmful</a> &#8216;当文章标题的风潮，直到<a href="http://meyerweb.com/eric/comment/chech.html">有人终于受不了</a>为止）</p>
<p>为什么goto语句不好呢？Dijkstra说，一个变量代表什么意义要看其上下文。一个程序用N<code></code>记录房间里的人数，在大部分时候，N<code></code>代表的是“目前房间里的人”。但在观察到又有一个人进房间后、把N<code></code>递增的指令前的这段程序区块中，N<code></code>的值代表的是“目前房间里的人数加一”。因此，要正确诠释程序的状态，必须知道程序执行的历史，或着说，知道现在“算到哪”了。</p>
<p>怎么谈“算到哪了”？如果是一直线执行下来的程序，我们只要指到那条语句，说“就是这里”，就可以了。如果是有循环程序，我们可能得说：“现在在循环的这个地方，循环已经执行了第<code>i</code>次”。如果是在函数中，我们可能得说：“现在执行到函数<code>p</code>的这一点；<code>p</code>刚刚被<code>q调用</code>，调用点在一个循环中，这个循环已经执行了<code>i</code>次”。</p>
<p>如果有goto<code>语句了</code>呢？那就麻烦了。因为电脑在执行某个指令前，可能是从程序中许许多多goto<code></code>其中之一跳过来的。要谈某变量的性质也几乎变得不可能了。这就是为什么goto语句问题。</p>
<p>Dijkstra的这篇文章对后面很多程序员有非常深的影响，包括我在内，都觉得Goto语句能不用就不用，虽然，我在十年前的《<a href="http://blog.csdn.net/haoel/article/month/2003/05" target="_blank">编程修养</a>》（这篇文章已经严重过时，某些条目已经漏洞百出）中的<a href="http://blog.csdn.net/haoel/article/details/2876" target="_blank">第23条</a>也说过，我只认为在goto语句只有一种情况可以使用，就是苹果这个bug里的用法。但是我也同意Dijkstra，goto语句能不用就不用了。就苹果的这个问题而言，在更为高级的C++中，<a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization" target="_blank">使用RAII技术</a>，这样的goto语句已经没有什么存在的意义了。</p>
<p>Dijkstra这篇文章后来成为结构化程式论战最有名的文章之一。长达19年之后，Frank Rubin投了一篇文章到CACM,标题为《<a href="http://www.ecn.purdue.edu/ParaMount/papers/rubin87goto.pdf">&#8216; <code></code>Go To Considered Harmful&#8217; Considered Harmful</a> 》Rubin说，「虽然Dijkstra的说法既太学术又缺乏说服力」，却似乎烙到每个程序员的心里了。这样，当有人说“用goto语句来解这题可能会比较好”会被严重鄙视。于是Rubin出了一道这样的题：令<code>X</code>为<code>N * N</code>的整数阵列。如果<code>X</code>的第<code>i</code>行全都是零，请输出<code>i</code>。如果不只一行，输出最小的<code>i</code> .</p>
<p>Rubin找了一些惯用goto和不用goto的程序员来解题，发现用goto的程序又快又清楚。而不用goto通常花了更多的时间，写出很复杂的解答。你觉得呢？ 另外，你会怎么写这题的程序呢？</p>
<p>（<strong>花絮</strong>：以后几个月的CACM热闹死了。编辑收到许多回应，两个月后刊出了其中五篇。文章也包括了《<a href="http://www.ecn.purdue.edu/ParaMount/papers/acm_may87.pdf">&#8220;&#8216;GOTO Considered Harmful&#8217; Considered Harmful&#8221; Considered Harmful?</a> 》）</p>
<p><strong>对于我而言，goto语句的弊远远大于利，在99%的情况下，我是站在反goto这边的</strong>。Java和Python就没有提供Goto语句，原因就是因为goto语句很容易被滥用！</p>
<p><strong>更新：2014年3月5日</strong> &#8211; RedHat 近日也发现个GnuTLS安全问题，与苹果的类似：无法正确检验特定的伪造SSL证书，这个总是会将伪造证书识别为有效证书。虽然Redhat的代码为if加上了花括号，但还是因为没有控制好goto，造成了bug。所以说啊，goto语句的坑是很多。</p>
<ul>
<li>BUG页面：<a href="https://bugzilla.redhat.com/show_bug.cgi?id=1069865" target="_blank">https://bugzilla.redhat.com/show_bug.cgi?id=1069865</a></li>
</ul>
<ul>
<li>相关的Diff: <a href="https://bugzilla.redhat.com/attachment.cgi?id=867911&amp;action=diff" target="_blank">https://bugzilla.redhat.com/attachment.cgi?id=867911&amp;action=diff</a></li>
</ul>
<p>goto语句在写代码的时候也许你会很爽，但是在维护的时候，绝对是一堆坑！redhat的这个patch为原来本来只有一个label的goto又加了另一个label，现在两个label交差goto，继续挖坑……</p>
<h4>总结</h4>
<p>你看，我们不能完全消灭问题，但是，我们可以用下面几个手段来减少问题：</p>
<p style="padding-left: 30px;">1）<strong>尽量在编译上发生错误，而不是在运行时</strong>。</p>
<p style="padding-left: 30px;">2）<strong>代码是让人读的，顺便让机器运行</strong>。不要怕麻烦，好的代码风格，易读的代码会减少很多问题。</p>
<p style="padding-left: 30px;">3）<strong>Code Review是一件很严肃的事情</strong>，但 Code Reivew的前提条件是代码的可读性一定要很好。</p>
<p style="padding-left: 30px;">4）<strong>测试是一件很重要也是很难的事情，尤其是开发人员要非常重视</strong>。</p>
<p style="padding-left: 30px;">5）<strong>不要走飞线，用飞线来解决问题是可耻的！</strong>所以，用goto语句来组织代码的时代过去了，你可以有很多种方式不用goto也可以把代码组织得很好。</p>
<p>最后，我在淘宝过去的一年里，经历过一些P1/P2故障，尤其是去年的8-9月份故障频发的月份，我发现其中有70%的P1/P2故障，就是因为没有code review，没有做好测试，大量地用飞线来解决问题，归根结底就是只重业务结果，对技术没有应有的严谨的态度和敬畏之心。</p>
<p><span style="color: #cc0000;"><strong>正如苹果的这个“goto fail”事件所暗喻的，如果你对技术没有应有的严谨和敬畏之心，你一定会——</strong></span></p>
<p style="text-align: center; font-size: 36px; color: #cc0000; font-family: Georgia,;"><strong>Go To Fail !!!</strong></p>
<p>在这里唠叨这么多，与大家共勉！</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/20845.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/03/rust-social-wide-150x150.jpg" alt="Rust语言的编程范式" width="150" height="150" /></a><a href="https://coolshell.cn/articles/20845.html" class="wp_rp_title">Rust语言的编程范式</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/18024.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/07/api-design-300x278-2-150x150.jpg" alt="API设计原则 &#8211; Qt官网的设计实践总结" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18024.html" class="wp_rp_title">API设计原则 &#8211; Qt官网的设计实践总结</a></li><li ><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Leetcode 编程训练" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_title">Leetcode 编程训练</a></li><li ><a href="https://coolshell.cn/articles/12012.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/10/edsm-150x150.gif" alt="State Threads 回调终结者" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12012.html" class="wp_rp_title">State Threads 回调终结者</a></li><li ><a href="https://coolshell.cn/articles/11466.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/04/c99-150x150.jpg" alt="C语言的整型溢出问题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11466.html" class="wp_rp_title">C语言的整型溢出问题</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/11112.html">由苹果的低级Bug想到的</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/11112.html/feed</wfw:commentRss>
			<slash:comments>116</slash:comments>
		
		
			</item>
		<item>
		<title>为什么我反对纯算法面试题</title>
		<link>https://coolshell.cn/articles/8138.html</link>
					<comments>https://coolshell.cn/articles/8138.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 22 Aug 2012 00:20:18 +0000</pubDate>
				<category><![CDATA[流程方法]]></category>
		<category><![CDATA[职场生涯]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[面试]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=8138</guid>

					<description><![CDATA[<p>算法面试可能是微软搞出来的面试方法，现在很多公司都在效仿，而且我们的程序员也乐于解算法题，我个人以为，这是应试教育的毒瘤！我在《再谈“我是怎么招程序员”》中比较...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/8138.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/8138.html">为什么我反对纯算法面试题</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>算法面试可能是微软搞出来的面试方法，现在很多公司都在效仿，而且我们的程序员也乐于解算法题，我个人以为，这是应试教育的毒瘤！我在《<a title="再谈“我是怎么招聘程序员的”（上）" href="https://coolshell.cn/articles/4506.html">再谈“我是怎么招程序员”</a>》中比较保守地说过，“<strong>问难的算法题并没有错，错的很多面试官只是在肤浅甚至错误地理解着面试算法题的目的</strong>。”，今天，我想加强一下这个观点——<strong>我反对纯算法题面试</strong>！（注意，我说的是纯算法题）</p>
<figure id="attachment_8140" aria-describedby="caption-attachment-8140" style="width: 250px" class="wp-caption alignright"><a href="http://en.wikipedia.org/wiki/Sheldon_Cooper"><img decoding="async" loading="lazy" class="size-full wp-image-8140" title="Sheldon_Cooper" src="https://coolshell.cn/wp-content/uploads/2012/08/250px-Sheldon_Cooper.jpg" alt="" width="250" height="333" srcset="https://coolshell.cn/wp-content/uploads/2012/08/250px-Sheldon_Cooper.jpg 250w, https://coolshell.cn/wp-content/uploads/2012/08/250px-Sheldon_Cooper-225x300.jpg 225w, https://coolshell.cn/wp-content/uploads/2012/08/250px-Sheldon_Cooper-203x270.jpg 203w" sizes="(max-width: 250px) 100vw, 250px" /></a><figcaption id="caption-attachment-8140" class="wp-caption-text">图片源Wikipedia（点击图片查看词条）</figcaption></figure>
<p>我再次引用我以前的一个观点——</p>
<p style="padding-left: 30px;">能解算法题并不意味着这个人就有能力就能在工作中解决问题，你可以想想，小学奥数题可能比这些题更难，但并不意味着那些奥数能手就能解决实际问题。</p>
<p>好了，让我们来看一个示例（这个示例是昨天在<a href="http://weibo.com/1401880315/yy9pvgNi2" target="_blank">微博上的一个讨论</a>），这个题是——“<strong>找出无序数组中第2大的数</strong>”，几乎所有的人都用了O(n)的算法，我相信对于我们这些应试教育出来的人来说，不用排序用O(n)算法是很正常的事，连我都不由自主地认为O(n)算法是这个题的标准答案。<strong>我们太习惯于标准答案了，这是我国教育最悲哀的地方</strong>。（广义的洗脑就是让你的意识依赖于某个标准答案，然后通过给你标准答案让你不会思考而控制你）</p>
<h4>功能性需求分析</h4>
<p>试想，如果我们在实际工作中得到这样一个题 我们会怎么做？我一定会分析这个需求，因为我害怕需求未来会改变，今天你叫我找一个第2大的数，明天你找我找一个第4大的数，后天叫我找一个第100大的数，我不搞死了。需求变化是很正常的事。分析完这个需求后，我会很自然地去写找第K大数的算法——难度一下子就增大了。</p>
<p><span id="more-8138"></span></p>
<p>很多人会以为找第K大的需求是一种“过早扩展”的思路，不是这样的，我相信我们在实际编码中写过太多这样的程序了，你一定不会设计出这样的函数接口—— Find2ndMaxNum(int* array, int len)，就好像你不会设计出 DestroyBaghdad(); 这样的接口，而是设计一个DestoryCity( City&amp; ); 的接口，而把Baghdad当成参数传进去！所以，你应该是声明一个叫FindKthMaxNum(int* array, int len, int kth)，把2当成参数传进去。<strong>这是最基本的编程方法，用数学的话来说，叫代数</strong>！最简单的需求分析方法就是把需求翻译成函数名，然后看看是这个接口不是很二？！</p>
<p>（注：不要纠结于FindMaxNum()或FindMinNum()，因为这两个函数名的业务意义很清楚了，不像Find2ndMaxNum()那么二）</p>
<h4>非功能性需求分析</h4>
<p>性能之类的东西从来都是非功能性需求，对于算法题，我们太喜欢研究算法题的空间和时间复杂度了。我们希望做到空间和时间双丰收，这是算法学术界的风格。所以，<strong>习惯于标准答案的我们已经失去思考的能力，只会机械地思考算法之内的性能，而忽略了算法之外的性能</strong>。</p>
<p>如果题目是——“从无序数组中找到第K个最大的数”，那么，我们一定会去思考用O(n)的线性算法找出第K个数。事实上，也有线性算法——STL中可以用nth_element求得类似的第n大的数，其利用快速排序的思想，从数组S中随机找出一个元素X，把数组分为两部分Sa和Sb。Sa中的元素大于等于X，Sb中元素小于X。这时有两种情况：1）Sa中元素的个数小于k，则Sb中的第k-|Sa|个元素即为第k大数；2） Sa中元素的个数大于等于k，则返回Sa中的第k大数。时间复杂度近似为O(n)。</p>
<p>搞学术的nuts们到了这一步一定会欢呼胜利！但是他们哪里能想得到性能的需求分析也是来源自业务的！</p>
<p><strong>我们一说性能，基本上是个人都会问，请求量有多大？如果我们的FindKthMaxNum()的请求量是m次，那么你的这个每次都要O(n)复杂度的算法得到的效果就是O(n*m)，这一点，是书呆子式的学院派人永远想不到的。</strong>因为应试教育让我们不会从实际思考了。</p>
<h4>工程式的解法</h4>
<p>根据上面的需求分析，有软件工程经验的人的解法通常会这样：</p>
<p style="padding-left: 30px;">1）把数组排序，从大到小。</p>
<p style="padding-left: 30px;">2）于是你要第k大的数，就直接访问 array[k]。</p>
<p>排序只需要一次，O(n*log(n))，然后，接下来的m次对FindKthMaxNum()的调用全是O(1)的，整体复杂度反而成了线性的。</p>
<p>其实，上述的还不是工程式的最好的解法，因为，在业务中，那数组中的数据可能会是会变化的，所以，如果是用数组排序的话，有数据的改动会让我重新排序，这个太耗性能了，如果实际情况中会有很多的插入或删除操作，那么可以考虑使用B+树。</p>
<p>工程式的解法有以下特点：</p>
<p style="padding-left: 30px;">1）很方便扩展，因为数据排好序了，你还可以方便地支持各种需求，如从第k1大到k2大的数据（那些学院派写出来的代码在拿到这个需求时又开始挠头苦想了）</p>
<p style="padding-left: 30px;">2）规整的数据会简化整体的算法复杂度，从而整体性能会更好。（公欲善其事，必先利其器）</p>
<p style="padding-left: 30px;">3）代码变得清晰，易懂，易维护！（学院派的和STL一样的近似O(n)复杂度的算法没人敢动）</p>
<h4>争论</h4>
<p>你可能会和我有以下争论，</p>
<ul>
<li><strong>如果程序员做这个算法题用排序的方式，他一定不会像你想那么多</strong>。是的，你说得对。但是我想说，很多时候，我们直觉地思考，恰恰是正确的路。因为“排序”这个思路符合人类大脑处理问题的方式，而使用学院派的方式是反大脑直觉的。反大脑直觉的，通常意味着晦涩难懂，维护成本上升。</li>
</ul>
<ul>
<li><strong>就是一道面试题，我就是想测试一下你的算法技能，这也扯太多了</strong>。没问题，不过，我们要清楚我们是在招什么人？是一个只会写算法的人，还是一个会做软件的人？这个只有你自己最清楚。</li>
</ul>
<ul>
<li><strong>这个算法题太容易诱导到学院派的思路了</strong>。是的这道“找出第K大的数”，其实可以变换为更为业务一点的题目——“<strong>我要和别的商户竞价，我想排在所有竞争对手报价的第K名，请写一个程序，我输入K，和一个商品名，系统告诉我应该订多少价？</strong>（商家的所有商品的报价在一数组中）”——业务分析，整体性能，算法，数据结构，增加需求让应聘者重构，这一个问题就全考了。</li>
</ul>
<ul>
<li><strong><span style="color: #ff0000;">你是不是在说算法不重要，不用学？</span></strong>千万别这样理解我，搞得好像如果面试不面，我就可以不学。<strong>算法很重要，算法题能锻炼我们的思维，而且也有很多实际用处</strong>。我这篇文章不是让大家不要去学算法，这是完全错误的，我是让大家带着业务问题去使用算法。问你业务问题，一样会问到算法题上来。</li>
</ul>
<h4>小结</h4>
<p>看过这上面的分析，我相信你明白我为什么反对纯算法面试题了。原因就是<strong>纯算法的面试题根本不能反应一个程序的综合素质</strong>！</p>
<p>那么，在面试中，我们应该要考量程序员的那些综合素质呢？我以为有下面这些东西：</p>
<ol>
<li>会不会做需求分析？怎么理解问题的？</li>
<li>解决问题的思路是什么？想法如何？</li>
<li>会不会对基础的算法和数据结构灵活运用？</li>
</ol>
<p>另外，我们知道，对于软件开发来说，在工程上，难是的下面是这些挑战：</p>
<ul>
<li>软件的维护成本远远大于软件的开发成本。</li>
<li>软件的质量变得越来越重要，所以，测试工作也变得越来越重要。</li>
<li>软件的需求总是在变的，软件的需求总是一点一点往上加的。</li>
<li>程序中大量的代码都是在处理一些错误的或是不正常的流程。</li>
</ul>
<p>所以，对于编程能力上，我们应该主要考量程序员的如下能力：</p>
<ol>
<li>设计是否满足对需求的理解，并可以应对可能出现的需求变化。</li>
<li>程序是否易读，易维护？</li>
<li>重构代码的能力如何？</li>
<li>会不会测试自己写好的程序？</li>
</ol>
<p>所以，这段时间，我越来越倾向于问应聘者一些有业务意义的题，而且应增加或更改需求来看程序员的重构代码的能力，写完程序后，让应聘者设计测试案例。</p>
<p>比如：解析加减乘除表达式，字符串转数字，洗牌程序，口令生成器，通过ip地址找地点，英汉词典双向检索……</p>
<p><strong>总之，我反对纯算法面试题！</strong></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Leetcode 编程训练" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_title">Leetcode 编程训练</a></li><li ><a href="https://coolshell.cn/articles/8790.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/12/choice-150x150.jpg" alt="程序算法与人生选择" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8790.html" class="wp_rp_title">程序算法与人生选择</a></li><li ><a href="https://coolshell.cn/articles/4976.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/5.jpg" alt="给程序员新手的一些建议" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4976.html" class="wp_rp_title">给程序员新手的一些建议</a></li><li ><a href="https://coolshell.cn/articles/4506.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/0.jpg" alt="再谈“我是怎么招聘程序员的”（上）" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4506.html" class="wp_rp_title">再谈“我是怎么招聘程序员的”（上）</a></li><li ><a href="https://coolshell.cn/articles/4490.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/2.jpg" alt="再谈“我是怎么招聘程序员的”（下）" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4490.html" class="wp_rp_title">再谈“我是怎么招聘程序员的”（下）</a></li><li ><a href="https://coolshell.cn/articles/3345.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/12/googlequestion-150x150.jpg" alt="140个Google的面试题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3345.html" class="wp_rp_title">140个Google的面试题</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/8138.html">为什么我反对纯算法面试题</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/8138.html/feed</wfw:commentRss>
			<slash:comments>181</slash:comments>
		
		
			</item>
		<item>
		<title>持续部署，并不简单！</title>
		<link>https://coolshell.cn/articles/7657.html</link>
					<comments>https://coolshell.cn/articles/7657.html#comments</comments>
		
		<dc:creator><![CDATA[马基雅弗利]]></dc:creator>
		<pubDate>Mon, 25 Jun 2012 00:20:08 +0000</pubDate>
				<category><![CDATA[企业应用]]></category>
		<category><![CDATA[技术管理]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[CI]]></category>
		<category><![CDATA[部署]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=7657</guid>

					<description><![CDATA[<p>【感谢 @常新居士 投递此文 】 这几年，持续集成随着敏捷在国内的推广而持续走热，与之相伴的持续部署也一直备受关注。自前两年，持续交付这个延续性概念又闯进了国内...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/7657.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/7657.html">持续部署，并不简单！</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script></p>
<p style="text-align: left;">【<strong>感谢 <a href="http://weibo.com/renfake" target="_blank">@常新居士</a> 投递此文</strong> 】</p>
<p style="text-align: left;">这几年，持续集成随着敏捷在国内的推广而持续走热，与之相伴的持续部署也一直备受关注。<strong>自前两年，持续交付这个延续性概念又闯进了国内IT圈，慢慢开始在社区和会议中展露头角。许多不明真相的群众跟风哭着喊着要“上”，而许多前CI的半吊子玩家换件衣服就接着干，有的甚至衣服都来不及换……</strong>。国内的这些土财主如果不巧请了某些所谓的战略家，除了建了一堆持续集成环境，以及每天嚷嚷着要这个要那个，混乱的状况在根本上没有得到改善。本文无意费力探讨持续集成和持续交付的概念，而是打算谈谈对于大型软件企业，以持续集成为基础实现持续部署（交付）时，所要面对的问题以及可行的解决方案。地主老财们，夜黑风正猛，山高路又远，注意脚下……</p>
<p style="text-align: right;"><strong>And God Said, Let there be light: and there wa</strong>&#8212; GENSIS, Charpter 1, King James</p>
<h4>一、起步</h4>
<p>先来讲个故事……</p>
<p>几年前，一对留美的夫妇通过朋友找到我，让我帮忙在国内组建一个开发团队，该团队负责为其开发一款基于社交网络的客户关系管理软件,（暂且称之为项目A）。这个项目除了尚不清晰的需求范围和很紧的期限外，作为业内人士的老公Richard根据眼下流行的软件开发过程还提了诸多额外的要求：</p>
<ul>
<li><strong>功能要及早交付</strong>（以便拿去和潜在的投资人洽谈）</li>
<li><strong>功能在部署到生产环境前要先部署的一个测试环境</strong>（Richard要试用后给予反馈）</li>
<li><strong>功能必须经过测试</strong>（长期作为软件外包的甲方，对质量要求严格）</li>
<li><strong>要减少后期维护的工作</strong>（美国人精贵，少雇一个是一个）</li>
<li><strong>支持协同开发</strong>（以便维护人员及早介入）</li>
<li>&#8230;&#8230;</li>
</ul>
<p><span style="color: #000000;"><strong>这正是持续集成所要解决的典型场景</strong></span>。针对Richard的要求，我们只要建立一个基于Hudson（现在叫Jenkins）+Maven +SVN 的持续集成环境（再加上持续集成所要求的测试和过程）就可以很好地满足上述要要求，此方案的结构如下：</p>
<p><span id="more-7657"></span></p>
<p><a href="https://coolshell.cn/?attachment_id=7686" rel="attachment wp-att-7686"><img decoding="async" loading="lazy" class="alignnone  wp-image-7686 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/hudsonCI2.jpg" alt="" width="693" height="719" srcset="https://coolshell.cn/wp-content/uploads/2012/06/hudsonCI2.jpg 866w, https://coolshell.cn/wp-content/uploads/2012/06/hudsonCI2-289x300.jpg 289w, https://coolshell.cn/wp-content/uploads/2012/06/hudsonCI2-768x797.jpg 768w, https://coolshell.cn/wp-content/uploads/2012/06/hudsonCI2-260x270.jpg 260w" sizes="(max-width: 693px) 100vw, 693px" /></a></p>
<p>对于上述方案，让我们近距离看看各个服务器的内部情况，以及人员在这种方案下的分工协作：</p>
<p><a href="https://coolshell.cn/?attachment_id=7708" rel="attachment wp-att-7708"><img decoding="async" loading="lazy" class="alignnone  wp-image-7708 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/response.jpg" alt="" width="658" height="438" srcset="https://coolshell.cn/wp-content/uploads/2012/06/response.jpg 822w, https://coolshell.cn/wp-content/uploads/2012/06/response-300x199.jpg 300w" sizes="(max-width: 658px) 100vw, 658px" /></a></p>
<p>我们先谈谈上面的图中涉及的一些概念性问题：</p>
<h5><strong>1.1）编译时依赖</strong>和<strong>运行时依赖</strong></h5>
<p>从字面上不难理解这两种依赖的类型。但要注意虽然编译时依赖常常也是运行时依赖，但并不能推断出一方必然是另一方。比如，在开发的过程中需要某些提供API的Jar包，而运行时可能是具体API实现的Jar包。再者，被依赖的包会有其自身的依赖，因此,项目对这些包产生间接依赖（<strong>运行时依赖</strong>），依此类推，最终形成一个<strong>依赖树</strong>。当项目运行时，这些依赖树上的包必须全部就位。</p>
<p>Maven在POM中通scope来界定依赖的类型，从而帮助开发和运维人员摆脱手动处理依赖树的工作，然而运行时所依赖包最终是要安装到生产环境的，这部分工作Maven并不能自动完成。因此，一个常用方式是将运行时所依赖的包拷贝到项目文件中，比如Java Web应用的WEB-INF/lib，然后将项目总的打一个包。<strong>在安装项目包后，修改环境变量，将这些包所在的路径加入相应的环境变量中，如ClassPath</strong>。</p>
<p>再看个例子，现代的操作系统和其它系统框架都考虑到了运行时依赖树的处理问题，比如Ubuntu的apt-get，CentOS的yum，Ruby的RubyGem，Node的npm等等。</p>
<h5>1.2）依赖时的复杂度</h5>
<p>项目除了对程序包的依赖，对于运行环境也有些具体的要求，比如，Web应用需要安装和配置Web服务器，应用服务器，数据服务器等，企业应用中可能需要消息队列，缓存，定时作业，或是对其它系统以Web Service方式暴露的服务。这些可以看做项目在系统层面对外部的依赖。这些依赖有些可以由项目自行处理，而有些则是项目无法处理的，比如运行容器，操作系统等，这些是项目的运行环境。</p>
<p>总之，依赖的复杂度主要有两个：</p>
<ol>
<li>依赖包间的版本兼容性问题。兼容性问题是软件开发的恶梦</li>
<li>间接依赖，或多重依赖问题。这个问题可以类比想像一下C++中的多重继续种出现的很多问题。</li>
</ol>
<div>比如：Ａ依赖于python 2.7，A还依赖于B，但是B却依赖于python 3，而Python 2.7和Python 3不兼容。这是依赖中最恶心的事。</div>
<h5>1.3）任务分工</h5>
<p>由于项目简单，因此并不需要专门的运维人员。以一个100人左右以交付为主业（恩，就是做外包）的公司为例，由于没有任何历史项目和代码的拖累，且各个项目间也没有任何关联，故而只需要配备一个IT支持人员进行资源方面的管理：分配机器，报修，初始化系统，分配IP地址等。各个项目的运行环境、数据库、开发环境等都由具体项目的开发人员手动完成。 环境出问题怎么办？很简单，凉拌——重装系统。实际的运行效果不错。</p>
<h5>1.4）自动化部署</h5>
<p>由于Hudson这样的持续集成环境提供了自动编译（定时或触发式）的功能，而且可以在编译过程中提供了一些扩展点，因此通过提供一个部署用的脚本，就可以非常容易实现简单的自动化部署。</p>
<p>毫无疑问，持续集成就是敏捷的魔法药，它见效快、副作用小、业界的争论少。每每运用在混乱的项目中时，几周内项目就开始持续的产出经过测试的功能。对于独立项目，以持续集成为中心的持续部署绝对是不二选择。</p>
<p><strong>但是，我们有没有想过，这会是一个自动化部署的通用解决方案吗？持续集成应该位于持续交付的中心吗？</strong></p>
<h4>二、困境</h4>
<p>回到我们的故事：项目A上线两年后，运营业绩不错，投资人第一轮注资后，Richard的公司进行了扩张，他们对项目进行了重构，而且随着用户数量的增长，公司分别在美国、英国和日本等地建立了运营中心，并且对亚洲市场进行的定制功能开发（项目A+），接下来，公司又投入开发了团购系统（项目B）。在获得了新一轮投资后，各条本来比较简单的业务和功能线上越来越复杂，需要不断地细分，于是公司再度扩张（开发人员达到了300人，国内200多人，而运维团队主要在美国），随后又为项目A/A+的高级用户开发了问答系统（项目C）。目前，他们正准备开发手机系统。 看看下面的图，公司增长的过程中，整个项目环境也变得复杂。（注意，这里是一种逻辑结构，而在物理层面项目B和项目A的生产环境可能部署在相同的机器上）。</p>
<p><a href="https://coolshell.cn/?attachment_id=7694" rel="attachment wp-att-7694"><img decoding="async" loading="lazy" class="alignnone  wp-image-7694 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/sampleT1-1024x529.jpg" alt="" width="717" height="370" srcset="https://coolshell.cn/wp-content/uploads/2012/06/sampleT1-1024x529.jpg 1024w, https://coolshell.cn/wp-content/uploads/2012/06/sampleT1-300x155.jpg 300w, https://coolshell.cn/wp-content/uploads/2012/06/sampleT1.jpg 1990w" sizes="(max-width: 717px) 100vw, 717px" /></a></p>
<p>同时，原本单一的项目软件结构随着业务系统的增加也不再简单： <img decoding="async" loading="lazy" class="alignnone  wp-image-7697" src="https://coolshell.cn/wp-content/uploads/2012/06/software.jpg" alt="" width="763" height="414" srcset="https://coolshell.cn/wp-content/uploads/2012/06/software.jpg 954w, https://coolshell.cn/wp-content/uploads/2012/06/software-300x162.jpg 300w" sizes="(max-width: 763px) 100vw, 763px" /></p>
<p>而软件间的版本依赖使这个问题变得更为复杂：</p>
<p><a href="https://coolshell.cn/?attachment_id=7700" rel="attachment wp-att-7700"><img decoding="async" loading="lazy" class="alignnone size-full wp-image-7700 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/dependency.jpg" alt="" width="626" height="343" srcset="https://coolshell.cn/wp-content/uploads/2012/06/dependency.jpg 626w, https://coolshell.cn/wp-content/uploads/2012/06/dependency-300x164.jpg 300w" sizes="(max-width: 626px) 100vw, 626px" /></a></p>
<p>现在，Richard的公司已经不再是一条快乐的小鱼，而是渐渐成为一直庞大的巨兽。虽然只有四个产品，但公司却要支持几百台开发机，几十台生产服务器，还有对应的测试环境，数据库服务器，以及几十个开发小组，和一大堆的内部项目。我们尽可以使用持续集成来为我们完成自动化部署。但，<strong>当我们为各个项目建立起持续集成环境后，它能满足我们对于持续部署的要求吗？我们前期的工作可以简化我们今后项目的持续交付的工作的难度吗？它需要我们为之建立一个庞大的运维团队，还是可以让我们能节省下每一毛钱来投入到真正的业务价值中去？</strong></p>
<p><strong>让我们先来看看复杂的项目环境中的几个场景</strong>：</p>
<p><strong>场景1：环境升级</strong></p>
<p style="padding-left: 30px;">项目A和项目B都依赖于Web容器，公司决定升级Web容器版本，而公司要升级的机器有上百台，依赖人肉升级已不现实，维护团队因此针对各种软件开发了相应的自动化脚本，但当新的软件出现时，必须要开发新的脚本。而且当同时升级若干环境软件时，则难度随之增大，手工调度的方式极易出错，当升级失败时仍需要大量人工处理。由于存在大量升级脚本，有一定的维护成本。</p>
<p><strong>场景2：依赖于环境的软件升级与回滚</strong></p>
<p style="padding-left: 30px;">针对环境升级，公司为项目A和项目B开发了新的版本。但环境的升级和软件的升级不是同步进行，出错的可能性非常大（想一想间接依赖和多重依赖的情况）。当新版本部署到生产系统时，发现问题，需要回滚到之前的版本——所有运行时版本都需要回滚，而且环境也需要同步回滚。几百台机器……</p>
<p><strong>场景3：运行时依赖</strong></p>
<p style="padding-left: 30px;">在第一节的方案中，我们将所有的运行时依赖都打包到一起。当项目依赖关系复杂时，这样产生的包将非常臃肿，潜在地延长了部署的时间（想一想全世有几百台服务器，一个部署计划需要部署几百兆文件的情况），而且产生冲突的可能性非常大，而且对于不同类型的项目（Java和Ruby项目）缺乏通用性。06年左右，Nortel可是拿Excel统计过运行时依赖的，牵涉若干项目组，反复多次，没有个把月真搞不定。</p>
<p><strong>场景4：泛滥的部署</strong></p>
<p style="padding-left: 30px;">每个项目相关的持续集成环境都需要开发自己的部署脚本，重复投入大，而且各个项目的部署过程不一致，并且对于同一个项目无法同时满足不同目的部署要求，例如，环境或系统配置参数改变后，无需安装包，只需做清理和激活的工作。最后，持续集成只是支持了和代码修改有关的部署。</p>
<p><strong>场景5：不一致的环境</strong></p>
<p style="padding-left: 30px;">简单项目中，开发环境和运行环境都由开发人员搭建，当公司变大时，系统的运行环境将由运维人员搭建，而开发环境如果由运维人员搭建则工作量太大，由开发人员自己搭建则操作复杂又容易产生不一致的情况。</p>
<p><strong>场景6：热切换</strong></p>
<p style="padding-left: 30px;">对于某些部署，需要尽量减少服务的停止时间，需要在服务的同时进行部署。</p>
<p>这些场景只是以持续集成为中心的持续部署在面对大型企业时所遇到的部分问题。大型企业，人多，项目多，机器多，项目环境复杂，部署维护工作繁多。以持续集成为基础的部署可以解决各个项目的集成问题，却无法帮助企业应对复杂的项目环境和各种不同的部署要求。<strong>究其更本，大型企业中的部署不再是一个简单的问题，而是一个交付生态圈，基础设施和环境管理必须要纳入考虑之中。</strong>要实现真正意义上的持续部署，我们就必须<strong>把环境和项目同等对待</strong>，通通纳入管理之中。同时，部署本身要得到统一。<strong>一个好的部署机制，应该是易于建立，易于使用，易于维护。</strong></p>
<h4>三、任脉——环境管理</h4>
<p>什么是环境？</p>
<p>系统运行所依赖和包含的一切就是其环境：硬件、操作系统，网络资源（IP地址、域名），服务容器，服务器软件配置，环境亦是，运行时依赖的命令和包，项目本身的包和配置都是环境的一部分。对于部署而言，广义上，这些通通应该纳入环境管理的范畴，但狭义上，从软件系统的角度看，一个环境就是其运行需要的软件及其配置（我们先把操作系统和网络资源当做基础设施，其在部署时已处于就位的情况）。因此：</p>
<p><strong>项目A的生产环境 = 项目A本身的软件包 + 项目A运行时依赖的软件包 + 项目A运行时依赖的其它软件 + 项目A的配置信息</strong></p>
<p>由于，项目本身的软件包、项目运行时依赖的软件包，以及项目运行时依赖的其它软件在本质上没有区别——都是软件，上面的定义可以进一步抽象为：</p>
<p><strong>环境 = 软件包 + 配置信息</strong></p>
<p>在这个定义下，我们就必须将运行环境的软件解构，并以包的形式导入到公司的整个项目资源库中，比如Apache将作为一个包被导入，而Apache依赖的其它包也将依次被导入，并建立起正确的依赖关系。而且，在导入的过程中还必须做些相应的调整，如，环境变量的读取和设置，必须来自于环境配置模块，而不要修改系统的环境变量，防止不同环境在系统环境配置上相互影响和依赖。</p>
<p>再回头审视我们的示例，项目A的生产环境可以部署在不同的区域，对于各个区域可能有定制化的设定。这就像面向对象中的类，可以通过继承使子类重用父类的公有属性和行为并添加自己特有的信息。因此，环境的概念模型如图：</p>
<p><a href="https://coolshell.cn/?attachment_id=7725" rel="attachment wp-att-7725"><img decoding="async" loading="lazy" class="alignnone size-full wp-image-7725 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/Env.jpg" alt="" width="523" height="118" srcset="https://coolshell.cn/wp-content/uploads/2012/06/Env.jpg 523w, https://coolshell.cn/wp-content/uploads/2012/06/Env-300x67.jpg 300w" sizes="(max-width: 523px) 100vw, 523px" /></a></p>
<p>通过这样的关系，我们很容易为示例的复杂环境建立一种简单的结构，对于项目A：</p>
<p><a href="https://coolshell.cn/?attachment_id=7729" rel="attachment wp-att-7729"><img decoding="async" loading="lazy" class="alignnone size-full wp-image-7729 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/org1.jpg" alt="" width="599" height="519" srcset="https://coolshell.cn/wp-content/uploads/2012/06/org1.jpg 599w, https://coolshell.cn/wp-content/uploads/2012/06/org1-300x259.jpg 300w" sizes="(max-width: 599px) 100vw, 599px" /></a></p>
<p>这里，环境依然是处于知识层面（Knowledge Level），它并未与具体的基础设施相关联。当我们将一个环境“具现化”成一个运行系统时，我们就产生了一个真正的环境实例。在这两者之间，我们还必须要考虑环境实例的使用目的（开发？测试？……）以及安装所依赖的其它信息（如机器），因此，我们需要增加一个环境目标来集中这些信息，而且由于不同目标的环境可能会有所差别，因此，环境目标也需要配置的能力。概念模型如图：</p>
<p><a href="https://coolshell.cn/?attachment_id=7731" rel="attachment wp-att-7731"><img decoding="async" loading="lazy" class="alignnone size-full wp-image-7731 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/target.jpg" alt="" width="523" height="438" srcset="https://coolshell.cn/wp-content/uploads/2012/06/target.jpg 523w, https://coolshell.cn/wp-content/uploads/2012/06/target-300x251.jpg 300w" sizes="(max-width: 523px) 100vw, 523px" /></a></p>
<p>图中的环境实例是如何产生的呢？<strong>部署</strong>，<strong>一次部署可能会产生一个环境实例。</strong>一系列部署将产生对应于环境目标的多个环境实例，除去当前起作用的环境实例外（最新的），其它的是历史环境实例。<strong>通过在历史环境实例中切换，我们自然而然的就可以使整个环境回滚，因为项目所依赖的一切都已经成为的环境中的软件包，而且环境依赖的包的版本会随着部署具体确定下来。</strong>如此一来，我们便可以给每个环境实例分配一个版本号，再通过环境实例的版本号与软件包的版本对应起来，从而得知一次部署时应用的具体软件包，如图：</p>
<p><a href="https://coolshell.cn/?attachment_id=7732" rel="attachment wp-att-7732"><img decoding="async" loading="lazy" class="alignnone  wp-image-7732 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/version.jpg" alt="" width="669" height="394" srcset="https://coolshell.cn/wp-content/uploads/2012/06/version.jpg 743w, https://coolshell.cn/wp-content/uploads/2012/06/version-300x176.jpg 300w" sizes="(max-width: 669px) 100vw, 669px" /></a></p>
<p>目前的环境管理结构，已经可以解决场景1、2和5的问题。那<strong>么对于场景2，运行时依赖，环境管理应该如何解决呢？</strong></p>
<p>细心的朋友，可能已经发现，<strong>在环境层面上我们确定了环境依赖的软件包</strong>，这里有两个隐藏的含义：</p>
<ul>
<li>环境定义的是对软件包的运行时依赖</li>
<li>由于环境是一个逻辑上的概念，因此其所用的软件包也是一个逻辑上的概念（相对于版本控制系统中的软件包）</li>
</ul>
<p>我们也已经知道，在部署时，一个环境实例将具体的确定其依赖的软件包的版本。某个版本的软件包最终与代码库中的物理的软件包相关联。但软件包是运行时的安装包，因此，它应该是代码库中包编译的结果。在对代码库的包编译时，既要将结果打上版本保存起来，也好在两者的版本间建立关系，最后，编译结果应该是某种既定的安装包目录文件结构。</p>
<p>另外，当环境包含的包比较多时，运行时版本树会非常大，手动的指定全部的包的版本将是一个非常大的体力劳动，这部分工作也要得到简化。由此，我们必须</p>
<div>
<ul>
<li><strong>建立逻辑软件包版本和版本库中软件包版本间的关系</strong></li>
<li><strong><strong>为相互依赖的包编译并打上统一的标签</strong></strong></li>
<li><strong>简化运行时包依赖关系的生产</strong></li>
<li><strong>简化运行时包依赖的指定（可参考apt-get和RubyGem，环境只需指定直接依赖的包，间接依赖的包从运行时依赖树中自动导入）</strong></li>
</ul>
<div>一个可能的简单结构如下：</div>
<p><a href="https://coolshell.cn/?attachment_id=7736" rel="attachment wp-att-7736"><img decoding="async" loading="lazy" class="alignnone size-full wp-image-7736 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/pkg1.jpg" alt="" width="783" height="195" srcset="https://coolshell.cn/wp-content/uploads/2012/06/pkg1.jpg 783w, https://coolshell.cn/wp-content/uploads/2012/06/pkg1-300x74.jpg 300w" sizes="(max-width: 783px) 100vw, 783px" /></a></p>
<p>上述讨论还没有涉及操作系统，<strong>如果我们的运行机器要支持多个系统，我们又该怎么办？？？</strong></p>
<p>配置信息也是个大问题，大家可以思考</p>
<ul>
<li><strong>环境配置和应用配置如何区分？</strong></li>
<li><strong>如何简化环境配置工作？</strong></li>
<li><strong>如何使环境配置的效果只对具体环境有效，而不会泄露到环境外部？</strong></li>
</ul>
</div>
<p>再者，</p>
<ul>
<li><strong>如何使应用支持多运行目标？</strong></li>
<li><strong>环境管理如何能方便开发环境的调试？</strong></li>
<li><strong>要如何简化版本的选择?</strong></li>
<li><strong><strong>在多个包有编译和运行时依赖时，编译时如何检查以减少引入兼容性问题的风险？</strong></strong></li>
</ul>
<p>这些都留待大家思考。</p>
<h4>四、督脉——部署系统</h4>
<p>《持续集成》和《持续交付》中都对部署有详细的讨论，不在赘述。<strong>在我看来，部署其就是按照其目的执行一系列步骤将环境置于其目的所指向的状态中</strong>。我们一会再回国头来看这段文绉绉的话，先看看第一部分持续集成的环境下，我们部署的步骤可能会是下面这个样子：</p>
<ol>
<li>登陆目标机（ssh）</li>
<li>停止服务</li>
<li>清理环境</li>
<li>准备安装环境（创建文件夹等）</li>
<li>安装项目包（rsync，解压，权限设置等）</li>
<li>配置环境变量</li>
<li>启动服务</li>
<li>&#8230;&#8230;</li>
</ol>
<p>而在第二部分的<strong>情景4</strong>中，我们看到如果对不同的持续集成环境建立不同的部署脚本和环境维护脚本，这部署过程的维护会非常繁琐。基于第三部分的环境管理，我们可以将部署过程抽象为：</p>
<p><a href="https://coolshell.cn/?attachment_id=7737" rel="attachment wp-att-7737"><img decoding="async" loading="lazy" class="alignnone size-full wp-image-7737 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/06/deploy.jpg" alt="" width="566" height="351" srcset="https://coolshell.cn/wp-content/uploads/2012/06/deploy.jpg 566w, https://coolshell.cn/wp-content/uploads/2012/06/deploy-300x186.jpg 300w" sizes="(max-width: 566px) 100vw, 566px" /></a></p>
<p>现在回到开头那个文绉绉的描述：<strong>部署其就是按照其目的执行一系列步骤将环境置于其目的所指向的状态中</strong>。</p>
<p>由于我们已经将部署作为环境管理的一部分，而环境又是对外提供服务的最小实体，因此，对环境的部署就是要根据部署的类型，在环境上按一定的步骤执行一系列操作，从而使环境置于部署类型所要的状态，这个过程中可能会生成对应的环境实例。举例来说，我们可能会修改环境相关的一些配置，然后重启环境，显然，这种情况下不需要下载安装软件包（没有改变），因此也就不需要生成环境实例。</p>
<p>对于标准的部署——安装软件包并启动环境，可能的步骤将会是：</p>
<ol>
<li>选择将要部署的软件包的版本</li>
<li>生成新的环境实例（确定环境实例的版本和其依赖包的版本，确定环境配置等）</li>
<li>清理和准备目标机环境</li>
<li>下载包</li>
<li>设置环境配置</li>
<li>环境实例切换</li>
<li>生成部署报告</li>
<li>……</li>
</ol>
<p>好，部署系统和环境管理各就各位，我们可以将各个项目环境纳入我们的环境管理之中，甚至是持续集成环境本身。再补充一句，要让部署系统和环境管理能很好的发挥作用，我们即需要一个简单一致的UI界面（为开发人员），也需要提供一个清晰明了的服务接口（供外部系统调用，如持续部署系统）。<strong>对于与环境管理相关的机器状态管理，网络资源的配置等等，本文不再涉及，大家可以自己思考</strong>。环境管理的实现、编译系统改造以及持续部署的具体实现，另作文章探讨。</p>
<p>就技术而言（不考虑围绕持续部署的过程实践），环境管理、部署系统以及我们没有提及的编译系统改造才是生产线的真正引擎，持续部署不过是水到渠成的传送带而已。</p>
<h4>五、没完</h4>
<p>打通了任督二脉后，事还还没有完，还有很多细节上的问题。你想，这个工具实在是太好用了，于是公司里成百上千的工程师们都在使用这个自动化部署系统，我们又会面对很多很多问题：</p>
<ul>
<li><strong>部署系统的性能问题</strong>。几百号人不停地在把他们的软件部署到自己的机器上，部署到测试环境，部署到生产环境，一天之内一个人可能会要部署N次，回滚N次，不但有大量部署请求，还有大量的文件在网络上传输。你得想想这套部署系统如何解决这些性能问题，还得考虑未来更大规模的性能水平扩展问题。</li>
</ul>
<ul>
<li><strong>目标机环境的管理。</strong>在目标运行机上需要解决几个问题：1）两个环境间如果有一些的一样的包，那就没有必要再下载了，这样可以节约时间。2）每次部署都需要把老的部署环境给保留下来，这样方便在新旧环境下的切换。这两点对于在生产环境下部署非常关键。（这需要环境内所有软件的绿色安装才能更容易达到这个目标，因些，Unix/Linux会比Windows更容易做到这点）</li>
</ul>
<ul>
<li><strong>部署一致性事务问题</strong>。有时候，我们需要同时部署若干台服务器，比如：包A到机器MA，包B到机器MB，包C到机器MC，……（Web Service的SOA架构），这些包之间有运行依赖性和兼容性问题，要么一次性全部完成，要么就全部失败。回滚也是一样的，这是一个部署事务或部署一致性的问题。如何解决呢？</li>
</ul>
<ul>
<li><strong>部署环境的版本控制问题</strong>。前面说过，我们的一个环境就会和若干个包的版本耦合，环境必需管理要部署的包的版本。于是，当你的部署越来越多的时候，各个环境的包的版本开始出现混乱，各种依赖间的版本也会出现不统一的情况，也就是说，就算你有这样的一个工具，在一个高速开发的环境下，我们的部署环境的管理还是会出现很多混乱的情况，需要你不断地统一大家的开发、测试环境。</li>
</ul>
<ul>
<li><strong>部署计划</strong>。我们可能会有很多部署计划，比如：设定定时部署，提升或降低部署优先级，部署事务定义，部署策略（如：先部署10%的机器，如果没有问题，再把剩下的系统部署了），热切计划和策略…… 等等 ，等等 。</li>
</ul>
<ul>
<li><strong>部署的监控和维护</strong>。任何软件和系统都会有这样的问题，当规模上去了以后，我们的自动化部署系统的监控和维护的复杂度并不亚于一个大型的互联网应用。</li>
</ul>
<div>这样的问题会有很多，基本上来说，<strong>这样一个持续集成持续部署的自动化系统并不是那么简单的事，其开发工作量和一个标准的大型互联网业务系统没什么两样</strong>。</div>
<h4>六、总结</h4>
<p>这里只谈一点自己的看法，从传统的持续集成到面向大型软件的持续部署，我们将系统所依赖的软件环境和软件包抽象为一致的实体纳入到管理之中，并将运维人员的工作真正的分摊到开发人员身上。而云计算的出现，使得计算机本身也可以自动化的创建和回收，这样环境管理的范畴将进一步扩充。相应的，部署的能力和灵活性也是一次质的飞跃，将再一次减轻运维人员的工作压力。</p>
<p>说了这么多废话，总结一下自己的观点，对于向大型软件企业推销基于持续集成的持续部署（交付）的哥们：</p>
<ul>
<li><strong>你就是在耍流氓</strong>，如果你不解决环境管理！！！</li>
<li><strong>你就是在耍流氓</strong>，如果你不建立部署系统！！！</li>
<li><strong>你就是在耍流氓</strong>，如果你不扩展编译系统！！！</li>
<li><strong>你就是在耍流氓</strong>，如果你只是推销小团队的实践而不考虑改造大环境！！！</li>
<li><strong>你就是个流氓</strong>，如果你只是不断地告诉别人怎么做，自己却从来不动手写一个测试或建立一个持续集成环境！！！</li>
</ul>
<p>最后，用Linus最经典的话来结束本文——“ Talk is Cheap, Show me the Code！”</p>
<p>（<strong>注：本文由<a href="http://weibo.com/renfake" target="_blank">@常新居士</a>完成初稿，我做了一些编辑，主要写了第五节“没完”</strong> ）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/09/fight-150x150.jpg" alt="“单元测试要做多细？”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_title">“单元测试要做多细？”</a></li><li ><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/14.jpg" alt="Test-Driven Development？别逗了" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_title">Test-Driven Development？别逗了</a></li><li ><a href="https://coolshell.cn/articles/5625.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/19.jpg" alt="“品质在于构建过程”吗？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5625.html" class="wp_rp_title">“品质在于构建过程”吗？</a></li><li ><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/10.jpg" alt="在新浪微博上关于敏捷的一些讨论" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_title">在新浪微博上关于敏捷的一些讨论</a></li><li ><a href="https://coolshell.cn/articles/5044.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/07/hat-150x150.jpeg" alt="为什么Scrum不行？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5044.html" class="wp_rp_title">为什么Scrum不行？</a></li><li ><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="Bob大叔和Jim Coplien对TDD的论战" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_title">Bob大叔和Jim Coplien对TDD的论战</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/7657.html">持续部署，并不简单！</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/7657.html/feed</wfw:commentRss>
			<slash:comments>48</slash:comments>
		
		
			</item>
		<item>
		<title>我们需要专职的QA吗？</title>
		<link>https://coolshell.cn/articles/6994.html</link>
					<comments>https://coolshell.cn/articles/6994.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 11 Apr 2012 00:48:59 +0000</pubDate>
				<category><![CDATA[技术管理]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[QA]]></category>
		<category><![CDATA[测试]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=6994</guid>

					<description><![CDATA[<p>这个文章必然是有争议的，我在我的微博上讨论过很多次了，每次都是很有争议的。有不同的观点，有争论总是一件好事，这样可以引发大家的思考。所以，对于我的这篇博文，如果...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/6994.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/6994.html">我们需要专职的QA吗？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>这个文章必然是有争议的，我在我的<a href="http://weibo.com/haoel" target="_blank">微博</a>上讨论过很多次了，每次都是很有争议的。有不同的观点，有争论总是一件好事，这样可以引发大家的思考。所以，对于我的这篇博文，如果你赞同我的观点，我会感到高兴，如果你会去认真地深入思考，我也会高兴，如果你反对，没关系，可以讨论。</p>
<p>在此之前，我想说明一下我观点里的这个“专职QA”是怎么定义的。</p>
<ol>
<li>其是很多公司成立的专门做测试的技术人员，仅测试不开发。</li>
<li>这些QA对于软件开发技术并不熟悉，甚至不懂。</li>
</ol>
<p>我经历过一些公司都有专职的QA团队（专职的测试人员），自从上个公司我的开发团队在一个项目上被QA部门搞得一团糟，我越来越怀疑专职QA存在在意义。我的观点不一定对，但请让我鲜明地表达一下——<strong>我觉得是不需要全职的QA的，甚至不需要QA这一专职角色或部门，因为，不懂开发的人必然做不好测试。就像不懂开发的研发经理必然管不好研发团队一样。</strong>我越来越觉得Dev应该应该是做测试最合适的人选，这必然是未来的趋势 （因为我已经看到了中国程序员的进步，相比起10年前，今天的程序员已经是非常全面了，再来十年，必然证明我的观点是对的）。</p>
<p>在我正在展开说明之前，我想引用两篇文章：</p>
<h4>两篇文章</h4>
<p>一篇是  “<a href="http://sriramk.com/blog/2012/01/testing.html" target="_blank">On testers and testing</a>”(<a href="http://www.aqee.net/on-testers-and-testing/" target="_blank">中文翻译</a>)，本文的作者Sriram Krishnan是一名程序员，曾在Yahoo和微软工作过，开发过很多软件，曾被纽约时报<a href="http://www.nytimes.com/2011/02/27/business/27novel.html" target="_blank">报道</a>，写过<a href="http://amzn.to/progazure" target="_blank">一本书</a>，本文是他的一篇博客。他在文章中表达了这几个观点——</p>
<blockquote><p>大多数的开发团队并不需要一个独立的测试角色。即使要有，那么所有的开发时间比上所有的测试时间应该 &gt;20:1的。。证据吗？光看看一些从古至今最成功的软件开发团队就知道了。不论是当今的Facebook，还是30年前最初的NT团队，很多伟大的产品都是出自没有或很少测试人员的团队。</p>
<p>开发人员应该测试自己的代码。没什么可说的。背后的道理并不重要。这包括单元测试，全覆盖的自动化测试或手工测试或组合测试。如果你的开发人员不能/不愿意或认为这“不归我管”，那你需要更好的程序员。</p></blockquote>
<p>另一篇文章是邹欣的“<a id="cb_post_title_url" href="http://www.cnblogs.com/xinz/archive/2012/04/09/2439695.html" target="_blank">现代软件工程讲义 9 测试 QA 的角色和分工</a>”，这是一篇很不错的文章。他在文章里提到了分工的必要性，比如第三方的鉴定机构，<strong>并且也指出了分工的一些问题，比如，画地为牢的分工，无明确责任的分工，等，这些问题直接命中了分工的要害</strong>。我隐约觉得，我和邹欣的很多观点是相同的，我们内容上是相同的，只是形式上还有分歧。另外，我的观点太鲜明了，从而容易导向极端的理解。</p>
<p>你看，<strong>我们都同意，Dev要懂测试，QA要懂开发，只不过分工不同，既然你中有我，我中有你，那就不要分彼此了，一起携手开发测试吧</strong>。（另外，我个人觉得不懂开发的测试人员不可能测试得好）</p>
<p><em><strong>&#8212;- update&#8212;- </strong></em>{</p>
<p><span style="color: #008000;">     //本篇文章出来后，网上出现了一些对此讨论的文章，我一并更新在这里</span><br />
【 《<a id="cb_post_title_url" href="http://www.cnblogs.com/guanhe/archive/2012/04/12/response_to_do_we_need_qa.html">对《我们需要专职QA吗？》的回应</a>》作者：<a href="http://weibo.com/n/%E6%AE%B5%E5%BF%B5-%E6%AE%B5%E6%96%87%E9%9F%AC">@段念-段文韬</a> 】<br />
【 《<a href="http://blog.sina.com.cn/s/blog_55ba8b460100yawe.html" target="_blank">关于“我们需要专职的QA吗”》</a>作者：<a href="http://weibo.com/u/1764108363" target="_blank">@Jacky郭</a> 】<br />
【 《<a href="http://blog.sina.com.cn/s/blog_7022adbf0100zgqo.html" target="_blank">我们需要专职的QA吗？（评）</a>》作者：@<a title="Monkey陳曄曄" href="http://weibo.com/aiwanglinjun" target="_blank">Monkey陳曄曄</a> 】<br />
【《 <a id="blog-title-link" href="http://thinkcool.weebly.com/1/post/2012/04/qa.html" target="_blank">《我们需要专职的QA吗？》读后感</a>》作者：@ <a title="花生色魔叔" href="http://weibo.com/bluesgu">花生色魔叔</a>】</p>
<p>}</p>
<p><span id="more-6994"></span></p>
<h4>我的故事</h4>
<p>我再说说我最糟糕的QA经历吧，这个公司的QA部门只做测试，他们的leader觉得所有的test design和test 的过程都不需要Dev参与，他们是独立于Dev之外的部门，他们几乎不关心Dev的设计和实现，他们只关心能跑通他们自己设计的test case。但是去执行Test Case的时候，又需要Dev的支持，尤其在环境设置，测试工具使用，确认是否是bug方面，全都在消耗着Dev的资源，最扯的是，他们对任何线上的问题不负责，反正出了问题由Dev加班搞定。</p>
<p>我有一次私自review他们的test case的时候，发现很多的test case这样写到 &#8211; “Expected Result：Make sure every thing is fine&#8221; ，WTF，什么叫“Every thing is fine”？！而在test case design的时候，没有说明test environment/configuration 是什么？没有说明test data在哪里？Test Case、Test Data、Test Configuration都没有版本控制，还有很多Test Case设计得非常冗余（多个Test Case只测试了一个功能），不懂得分析Function Point就做Test Design。另外，我不知道他们为什么那么热衷于设计一堆各式各样的Negative Test Case，而有很多Positive的Test Case没有覆盖到。为什么呢，因为他们不知道开发和设计的细节，所以没有办法设计出Effective的Test Case，只能从需求和表面上做黑盒。</p>
<p>在做性能测试的时候，需要Dev手把手的教怎么做性能测试，如何找到系统性能极限，如何测试系统的latency，如何观察系统的负载（CPU，内存，网络带宽，磁盘和网卡I/O，内存换页……）如何做Soak Test，如何观察各个线程的资源使用情况，如何通过配置网络交换机来模拟各种网络错误，等等，等等。</p>
<p>测试做得也不认真，大量的False Alarm，都是环境问题，比如：安装新版本后没有重启服务，没有使用新的配置文件，网络配置，等等，等等。</p>
<p>在项目快要上线前的一周，我又私自查看了一下他们的Test Result，我看到5天的Soak Test 的内存使用一直往上涨，很明显的内存泄露，这个情况发生在2个月前，但是一直都没有报告，我只好和我的程序员每天都加班到凌晨，赶在上线前解决了这个问题。但是，QA部门的同学们就像没发生什么事似的，依然正常上下班。哎……</p>
<p>为什么会这样？我觉得有这么几点原因（和邹欣的观点一样）</p>
<ol>
<li>给了QA全部测试的权力，但是没有给相应的责任，</li>
<li>QA没有体会过软件质量出问题后的痛苦（解决线上问题的压力），导致QA不会主动思考和改进。</li>
<li>QA对Dev的开发过程和技术完全不了解，增加了很多QA和Dev的沟通。</li>
<li>QA对软件项目的设计和实现要点不了解，导致了很多不有效的测试。</li>
</ol>
<p><span style="color: #cc0000;"><strong>注：我无意在这里贬低QA的能力工作。只是我看到了QA因为没有参与开发的一些现实问题。</strong></span></p>
<h4>我的观点</h4>
<p>邹欣对于分工出现的问题给出了两点解决方法：</p>
<blockquote>
<ul>
<li>充分授权和信任（Empower team members）</li>
<li>各司其职，对项目共同负责（Establish clear accountability and shared responsibility）</li>
</ul>
</blockquote>
<div>我的观点是，<strong>理论上正确，操作上太虚了。这就像我们国家喊的“为人民服务”的口号一样，没有具体的方法，根本无法落实。</strong></div>
<p>我无意在这里贬低QA的工作，我也无意因为这个事走向另一个极端。但是，我在现在公司的经历，还有很多新兴公司的做法，<span style="color: #cc0000;"><strong>我越来越觉得软件开发，真的不需要专职的QA，更不需要只写代码不懂做测试的专职的Dev</strong></span>。观点如下：</p>
<p><strong>1）</strong> <strong>开发人员做测试更有效</strong></p>
<ul>
<li>开发人员本来就要测试自己写的软件，如果开发人员不懂测试，或是对测试不专业，那么这就不是一个专业的开发人员。</li>
<li>开发人员了解整个软件的设计和开发过程，开发人员是最清楚应该怎么测试的，这包括单元测试，功能测试，性能测试，回归测试，以及Soak Test 等。</li>
<li>开发人员知道怎么测试是最有效的。开发人员知道所有的function point，知道fix一个bug后，哪些测试要做回归和验证，哪些不需要。开发人员的技术能力知道怎么才能更好的做测试。</li>
</ul>
<p>很多开发人员只喜欢写代码，不喜欢做测试，或是他们说，开发人员应该关注于开发，而不是测试。这个思路相当的错误。开发人员最应该关注的是软件质量，需要证明自己的开发成果的质量。<strong>开发人员如果都不知道怎么做测试，这个开发人员就是一个不合格的开发人员</strong>。</p>
<p>另外，<strong>我始终不明白，为什么不做开发的QA会比Dev在测试上更专业？ 这一点都说不通啊</strong>。</p>
<p><strong>2）减少沟通，扯皮，和推诿</strong></p>
<p>想想下面的这些情况你是否似曾相识？</p>
<ul>
<li>QA 做的测试计划，测试案例设计，测试结果，总是需要Dev来评审和检查。</li>
<li>QA在做测试的过程中，总是需要Dev对其测试的环境，配置，过程做指导。</li>
<li>QA总是会和Dev争吵某个问题是不是BUG，争吵要不要解决。</li>
<li>无论发现什么样的问题，总是Dev去解决，QA从不fix问题。</li>
<li>我们总是能听到，线上发生问题的时候，Dev的抱怨QA这样的问题居然没测出来，</li>
<li>QA也总会抱怨Dev代码太差，一点也不懂测试，没怎么测就给hand over 给QA了。</li>
<li>QA总是会push Dev，这个bug再不fix，你就影响我的进度了。</li>
<li>等等，等等。</li>
</ul>
<p>如果没有QA，那么就没有这么多事了，DEV自己的干出来的问题，自己处理，没什么好扯皮的。</p>
<p>而一方面，QA说Dev不懂测试，另一方面Dev说QA不懂技术，而我们还要让他们隔离开来，各干各的，这一点都不利于把Dev和QA的代沟给填平了。<strong>要让Dev理解QA，让QA理解Dev，减少公说公有理，婆说婆有理的只站在自己立场上的沟通，只有一个方法，那就是让Dev来做测试，让QA来做开发</strong>。这样一样，大家都是程序员了。</p>
<p><strong>3）吃自己的狗食</strong></p>
<p>真的优秀的开发团队都是要吃自己狗食的。这句话的意思是——<strong>如果你不能切身体会到自己干的烂事，自己的痛苦，你就不会有想要去改进的动机</strong>。<strong>没有痛苦，就不会真正地去思考，没有真正的思考，就没有真正的进步</strong>。</p>
<p>在我现在的公司，程序员要干几乎有的事，从需求分析，设计，编码，集成，测试，部署，运维，OnCall，从头到尾，因为：</p>
<ul>
<li>只有了解了测试的难度，你才明白怎么写出可测试的软件，怎么去做测试的自动化和测试系统。</li>
<li>只有自己真正去运维自己的系统，你才知道怎么在程序里写日志，做监控，做统计……</li>
<li>只有自己去使用自己的系统，你才明白用户的反馈，用户的想法，和用户的需求。</li>
</ul>
<p>所以，<strong>真正的工程师是能真正明白软件开发不单单只是coding，还更要明白整个软件工程</strong>。只明白或是只喜欢coding的，那只是码农，不能称之为工程师。</p>
<p><strong>4）其它问题</strong></p>
<ul>
<li><strong>关于SDET</strong>。全称是Software Development Engineer on Test。像微软，Google， Amazon都有这样的职位。但我不知道这样的职位在微软和Google的比例是多少，在Amazon是非常少的。那么像这样的懂开发的专职测试可以有吗？我的答案是可以有！但是，我在想，<strong>如果一个人懂开发，为什么只让其专职做测试呢？这样的程序员分工合理吗？把程序员分成两等公民有意义吗？试问有多少懂开发的程序员愿意只做测试开发呢？</strong>所以，SDET在实际的操作中，更多的还是对开发不熟的测试人员。还是哪句话，不懂开发的人是做不好测试的。</li>
</ul>
<ul>
<li><strong>如果你说Dev对测试不专业，不细心，不认真</strong>，那么我们同样也无法保证QA的专业，细心和认真。在Dev上可能出现的问题，在QA也也会一样出现。而出了问题QA不会来加班解决，还是开发人员自己解决。所以，如果QA不用来解决问题，那么，QA怎么可能真正的细心和认真呢？</li>
</ul>
<ul>
<li><strong>如果你说不要QA的话，Dev人手会不够</strong>。你这样想一下，如果把你团队中现有的QA全部变成Dev，然后，大家一起开发，一起测试，亲密无间，沟通方便，你会不会觉得这样会更有效？你有没有发现，在重大问题上，Dev可以帮上QA的忙，但是QA帮不上Dev的忙。</li>
</ul>
<ul>
<li><strong>第三方中立，你会说人总是测不好自己写的东西，因为有思维定式</strong>。没错，我同意。但是如果是Dev交叉测试呢？你可能会说开发人员会有开发人员的思维定式。那这只能说明开发人员还不成熟，他们还不合格。没关系，只要吃自己的狗食，痛苦了，就会负责的。</li>
</ul>
<ul>
<li><strong>磨刀不误砍柴功</strong>。如果你开发的东西自己在用，那么自己就是自己天然的QA，如果有别的团队也在用你开发的模块，那么，别的团队也就很自然地在帮你做测试了，而且是最真实的测试。</li>
</ul>
<ul>
<li><strong>你可能会说吃狗食就是个笑话，因为如果是我，我把事干烂后，就离职走人了，让别人去吃我的狗食</strong>。这个在现实中的确会发生，也是很现实的。但是想一想，你为什么在一开始让他把事干烂了？另外，如果你的团队在设计评审和代码评审里没有把好关，让某人把事给干烂了，那么这个人的离职带来的问题还是这个团队来扛，于是整个团队都在吃自己的狗食，挺公平的。痛苦过一次，你的团队下次怎么干了，就不敢乱招人了，就不敢随意评审代码了，就不敢让人只做一块东西了。最终还是没有逃脱吃狗食的范畴。</li>
</ul>
<ul>
<li><strong>关于系统集成测试。</strong>所谓集成测试，就是把多个开发团队开发的模块集中起来测试。因为开发人员可能无法看到全局，不了解别个团队的系统，而且步调不一，所以需要有统管全局的专职的QA进行统筹规划并做测试。对这个方面，我并不反对，在实际操作过程中，好像的确用专职的做集成测试的QA统一调度各团队的时度更有效一些。不过，这还是不能让我停止去思考两个问题，1) 如果开发人员看不到全局，他能开发出更好的软件吗？2）这个全职的做集成测试的QA难道不能是各个团队的骨干Dev来组成吗？3）统一调度这个事，不更像是Project Manager要做的事吗？</li>
</ul>
<ul>
<li><strong>关于自动化测试</strong>。所谓自动化的意思是，这是一个机械的重复劳动。我想让测试人员思考一下，你是否在干这样的事？如果你正在干这样的事，那么，你要思考一下你的价值了。但凡是重复性比较高的机械性的劳动，总有一天都会被机器取代的。</li>
</ul>
<ul>
<li><strong>关于线上测试</strong>。我们都知道，无论自己内测的怎么样，到了用户那边，总是会有一些测试不到的东西。所以，有些公司会整出个UAT，用户验收测试。做产品的公司会叫Beta测试。无论怎么样，你总是要上生产线做真正测试的。对于互联网企业来说，生产线上测试有的在玩A/B测试，有的玩部分用户测试，比如，新上线的功能只有10%的用户可以访问得到，这样不会因为出问题让全部用户受到影响。做这种测试系统的人必然是开发人员。</li>
</ul>
<p>好吧，我暂时写这么多，我会视大家的讨论再补充我的观点的。</p>
<p><em><strong>&#8212;&#8211; update  2012/4/11&#8212;&#8211;</strong></em></p>
<p>一些人觉得我是在泄私愤，我能够理解为什么我会被这样误解，但是没有关系，很多新东西新观点总是会被误解的，我坦然面对。请大家抛开我的这些情感因素，单纯的思考一下，没有专职QA的的团队架构是否有积极的意义在里面？</p>
<p><strong>再补充一点，大家思考一下，QA是保证质量的，但是很多QA是在做测试，软件质量是测试出来的吗？如果不从需求分析，软件设计，代码实现上做好控制，到测试的时候你还怎么保证质量呢？</strong></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/10/communication-150x150.png" alt="聊聊团队协同和协同工具" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_title">聊聊团队协同和协同工具</a></li><li ><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/http_method-150x150.png" alt="“一把梭：REST API 全用 POST”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_title">“一把梭：REST API 全用 POST”</a></li><li ><a href="https://coolshell.cn/articles/22157.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/monitoring-150x150.jpeg" alt="谈谈公司对员工的监控" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22157.html" class="wp_rp_title">谈谈公司对员工的监控</a></li><li ><a href="https://coolshell.cn/articles/21589.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2021/07/knowledge_sharing-300x169-1-150x150.jpeg" alt="如何做一个有质量的技术分享" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21589.html" class="wp_rp_title">如何做一个有质量的技术分享</a></li><li ><a href="https://coolshell.cn/articles/20977.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/08/programmer.01-e1596792460687-150x150.png" alt="程序员如何把控自己的职业" width="150" height="150" /></a><a href="https://coolshell.cn/articles/20977.html" class="wp_rp_title">程序员如何把控自己的职业</a></li><li ><a href="https://coolshell.cn/articles/20765.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/01/remote-150x150.jpg" alt="MegaEase的远程工作文化" width="150" height="150" /></a><a href="https://coolshell.cn/articles/20765.html" class="wp_rp_title">MegaEase的远程工作文化</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/6994.html">我们需要专职的QA吗？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/6994.html/feed</wfw:commentRss>
			<slash:comments>274</slash:comments>
		
		
			</item>
		<item>
		<title>多些时间能少写些代码</title>
		<link>https://coolshell.cn/articles/5686.html</link>
					<comments>https://coolshell.cn/articles/5686.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Tue, 25 Oct 2011 00:24:44 +0000</pubDate>
				<category><![CDATA[技术管理]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=5686</guid>

					<description><![CDATA[<p>我在我的微博上说过这样一段话，我想在这里把我的这个观点阐述地更完整一些。 @左耳朵耗子：聪明的程序员使用50%-70%的时间用来思考，尝试和权衡各种设计和实现，...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/5686.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/5686.html">多些时间能少写些代码</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>我在我的微博上说过<a href="http://weibo.com/1401880315/xmYMteUWT" target="_blank">这样一段话</a>，我想在这里把我的这个观点阐述地更完整一些。</p>
<blockquote><p><a href="http://weibo.com/haoel" target="_blank">@左耳朵耗子</a>：聪明的程序员使用50%-70%的时间用来思考，尝试和权衡各种设计和实现，而用30% &#8211; 50%的时间是在忙碌着编码，调试和测试。聪明的老板也会让团队这样做。而傻逼的老板，苦逼的程序员会拿出来100%-150%的时间来忙着赶进度，返工，重构，fix 大量的bug… 所以， 越差的团队一般会越忙，而且还忙不完。</p></blockquote>
<p>在现在这个浮躁的时期，再加上敏捷咨询师们念的歪经，他们让人感觉上就像是软件产品是可以在很短的时间内高质量的完成的，这令那些管理者们很兴奋，就像巴甫洛夫的条件反射实验中的狗看到了肉就会流口水那样兴奋。他们使用TDD，快速迭代，不断重构，持续集成直至持续部署的方法在进行软件开发。</p>
<p>软件开发真是这样的吗？难道不需要花时间去思考吗？对此，有些观点在Todd的《<a title="“品质在于构建过程”吗？" href="https://coolshell.cn/articles/5625.html" target="_blank">“品质在于构建过程”吗？</a>》以及《<a title="Bob大叔和Jim Coplien对TDD的论战" href="https://coolshell.cn/articles/4891.html" target="_blank">Bob大叔和Jim Coplien对TDD的论战</a>》中谈到过了。我只想想表达下面的观点：</p>
<ul>
<li><strong>软件的精髓在于设计，设计是一件很费大脑的事件</strong>。对于软件来说，设计没有完美的，它总是一件需要取舍需要权衡的事，比如：时间换空间，空间换时间，TCP或UDP，同步还是异步，数据冗余还不冗余等等。那怕是一个小小的observers模式是pull方式还是push方式 都需要仔细讨论。这些的东西需要时间和做前期尝试。</li>
</ul>
<ul>
<li><strong>TDD</strong>、<strong>快速原型和迭代可能会对软件和团队产生负面影响</strong>。在一开始，你需要花很大的精力来让你的软件从无到有（做过软件的人都知道，从零开始写代码是很痛苦的事），但是因为你没有想好，先做再说，所以，后期你会面临更多的质量问题而让你需要花更多的时间精力。当然，那些咨询师会让你用持续集成和持续部署这样的方法。但我想告诉你，这并不解决你软件设计的缺陷。举个例子——TDD、迭代、原型只关注功能性需求，其不会关注非功能性需求，比如性能问题，高可用性问题，系统维护问题（模块的耦合问题），等等。而这些问题往往都可以让你的软件设计重新来过。</li>
</ul>
<ul>
<li><strong>重构是恶梦，重构应该越少越好</strong>。当你维护一个复杂的系统时你会知道重构是一件多么恐怖的事情（参看《<a title="重构代码的7个阶段" href="https://coolshell.cn/articles/5201.html" target="_blank">重构代码的7个阶段</a>》）。如果一开始没有想好，你要面临的不单单是re-design, re-architect，还要面对时间和人力成本的增加，最难的是你还要面对的是团队士气因为不断的rework而逐渐低落并产生厌倦和懈怠情绪。</li>
</ul>
<p><span id="more-5686"></span></p>
<p>所以，如果你能有多一些时间去和客户讨论一下需求和未来可能的变化，去调查一下实现的技术难点和细节，去和其他有经验的人讨论并推敲一下架构和设计，去思考设计上的缺陷，那么，你的coding会变得非常地直，直到你一眼就看到尽头，你的测试案例也会写得非常地好，你会几乎不需要重构，于是，你会在未来少写很多代码，从而你的软件开发会越来越轻松，直到技术开始换代。</p>
<p>我现在在做的项目，花了几乎4个月的时间来做设计，在这个过程中，我们反复思考、讨论和权衡若干种实现方法，并尽可能地穷举所有的场景和细节以及未来可能的变化（那怕是那些简单的模块），有个模块被重写了至少三次，每次都是写到一半就被推翻重写，我们整个团队不断地在和其它团队讨论，并在对系统不断地认识中对系统进行简化和优化，并力求达到完美。现在看来，没有贸然使用Scrum是明智的。</p>
<p>这就好像我们修路造桥一样，我们需要花大量的时间勘测地形地质，分析数据，思考可能出现的各种问题（各种自然灾害），评估不同的设计方案，而不是先尽快建好再说。</p>
<p>所以，<strong>多一些时间，不是让你多做几次迭代，多完成几个模块，而是可以让你少写一些代码，更快的交付一个更好的产品</strong>。</p>
<p>我相信你会有很多疑问，下面是我觉得你可能会有下面的一些观点，让我一条一条来回复：</p>
<ul>
<li><strong>首当其冲的一定会是项目的deadline，或是那种你没有活语权的项目。</strong>比如做那种“甲乙方合同式的项目”，我把这种项目统一认为是“外包项目”，在这种项目性质下，你很难有话语权。对此，我觉得，1）作为乙方的你还是应该和甲方在项目计划上争取一下，晓之以情，动之以理。2）如果不行，只能在时间、需求范围和质量上做一个权衡。另外，<strong>在这种情况下你要找一个方法，把你的压力和痛苦分担给用户和领导。</strong>（找到这个方法的前提需要你找到用户和领导他们害怕什么，嘿嘿）</li>
</ul>
<ul>
<li><strong>过度设计和纸上谈兵</strong>。有人说会不会设计太多，造成过度设计，或是在设计上花太多的时间。这有可能。我上一家公司的一个项目团队就花了1年多的时间来不停不停的开会和做设计，结果release的时候还有1000多个bug。这个问题的原因是，这个团队的设计是在纸上谈兵，开会是开神仙会，讨论的设计都是浮云。所以，<strong>设计并不是讨论和思考，还需要去尝试，</strong>我认为当你的设计完成的时候，你的骨干核心代码都基本完成了。</li>
</ul>
<ul>
<li><strong>我的团队成员水平太差，不会思考</strong>。首先，先恭喜你找到一堆码农，当然，这不怪你，这是中国教育和大环境的问题，让人不会思考。对于这样的情况，我有两个建议，1）量力而行，使多大的碗就吃多少饭。2）鼓励思考，那怕那些想法很不靠谱，因为如果不开始，那么将永远不会思考。</li>
</ul>
<ul>
<li><strong>必需使用快速迭代</strong>。很多公司都在强行上敏捷，他们希望产品越快release越好，而没有充分的时间思考和讨论。对于这种项目，我的建议是，1）找有丰富经验的人来做。2）迭代过程中力求架构和程序逻辑的简单，简单，再简单，力求代码间的高内聚，低耦合。不然，重构的时候你就好玩了。</li>
</ul>
<ul>
<li><strong>创业团队必需要快</strong>。做得快就是做得好吗？很多时候，不是谁快谁就能笑到最后的。这样的例子太多了。第一个做出来的人并不一定就会占领市场，其很有可能会成为先驱。</li>
</ul>
<ul>
<li><strong>有钱的公司才会让团队用更多的时间去思考</strong>。错了，你们没有见过有钱的公司，有钱的公司可以招一堆干不成活的人，可以把事搞乱了再新来过，甚至可以把做失败的项目换个名字再重新立项。这些真正的有钱的公司只求快，只求人多，不怕做错决定。像我们这些没钱的人，干什么事都是小心翼翼地，生怕做错决定。</li>
</ul>
<p>关于软件项目管理的文章，还可以参看《<a title="软件公司的两种管理方式" href="https://coolshell.cn/articles/4951.html">软件公司的两种管理方式</a>》，最后，欢迎大家表达观点。</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/18024.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/07/api-design-300x278-2-150x150.jpg" alt="API设计原则 &#8211; Qt官网的设计实践总结" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18024.html" class="wp_rp_title">API设计原则 &#8211; Qt官网的设计实践总结</a></li><li ><a href="https://coolshell.cn/articles/17680.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/02/gitlab-600-150x150.jpg" alt="从Gitlab误删除数据库想到的" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17680.html" class="wp_rp_title">从Gitlab误删除数据库想到的</a></li><li ><a href="https://coolshell.cn/articles/17459.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2016/08/HighAvailability-BK-150x150.png" alt="关于高可用的系统" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17459.html" class="wp_rp_title">关于高可用的系统</a></li><li ><a href="https://coolshell.cn/articles/9949.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/07/inverted-bookshelf_thumb-150x150.jpg" alt="IoC/DIP其实是一种管理思想" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9949.html" class="wp_rp_title">IoC/DIP其实是一种管理思想</a></li><li ><a href="https://coolshell.cn/articles/6775.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/24.jpg" alt="Bret Victor &#8211; Inventing on Principle" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6775.html" class="wp_rp_title">Bret Victor &#8211; Inventing on Principle</a></li><li ><a href="https://coolshell.cn/articles/5444.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/14.jpg" alt="千万不要把 bool 设计成函数参数" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5444.html" class="wp_rp_title">千万不要把 bool 设计成函数参数</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/5686.html">多些时间能少写些代码</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/5686.html/feed</wfw:commentRss>
			<slash:comments>118</slash:comments>
		
		
			</item>
		<item>
		<title>Test-Driven Development？别逗了</title>
		<link>https://coolshell.cn/articles/5531.html</link>
					<comments>https://coolshell.cn/articles/5531.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 17 Oct 2011 00:38:15 +0000</pubDate>
				<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[TDD]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=5531</guid>

					<description><![CDATA[<p>这篇文章来源于Peter Sergeant在Write More Test 博客上的《Test-Driven Development? Give me a br...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/5531.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/5531.html">Test-Driven Development？别逗了</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>这篇文章来源于Peter Sergeant在<a href="http://www.writemoretests.com/" target="_blank">Write More Test</a> 博客上的《<a href="http://www.writemoretests.com/2011/09/test-driven-development-give-me-break.html" target="_blank">Test-Driven Development? Give me a break&#8230;</a>》，在原文和<a href="http://www.reddit.com/r/programming/comments/kq001/testdriven_development_youve_gotta_be_kidding_me/">Reddit</a> 上有很大反响。这篇文章里的很多观点在《<a title="TDD并不是看上去的那么美" href="https://coolshell.cn/articles/3649.html" target="_blank">TDD并不是看上去的那么美</a>》和《<a title="再谈敏捷和ThoughtWorks中国咨询师" href="https://coolshell.cn/articles/3745.html" target="_blank">再谈敏捷和TW咨询师</a>》里都出现过（我个人觉得我的观点比其更全面一些）。就像我转的《<a title="为什么Scrum不行？" href="https://coolshell.cn/articles/5044.html" target="_blank">Scrum为什么不行</a>》 和《<a title="Bob大叔和Jim Coplien对TDD的论战" href="https://coolshell.cn/articles/4891.html" target="_blank">Bob大叔和Jim Coplien对TDD的论战</a>》一样，从这些贴子我们可以看到——<strong>这是一个全世界的问题，并不是只有在中国才有的问题</strong>。</p>
<p><strong>很多敏粉都在说我在是喷敏捷，黑敏捷，向敏捷泼脏水，我只想对这些人说——</strong><span style="color: #cc0000;">你们这样的见解很肤浅也很敏感，你们根本就没有认识到——争论，反思和不同观点的意义，你也就无法了解你们所信仰的敏捷！你们只是在肤浅和盲目地信仰和教条敏捷中的许多名词、方法和标准答案罢了</span>。</p>
<p style="text-align: center;">——————————————正文开始——————————————</p>
<p>对于程序员来说有些事有非常危险的信号（red flag）。当我听到有人开始信仰Test-Driven Development 是 One True Programming Methodology（唯一正确的编程方法论），这就是危险信号（red flag），我开始假设你是一个劣等、没有经验的程序员，或是某些敏捷咨询师。</p>
<p>测试只是一个工具来<strong>帮助你</strong>，而不是用来证明谁比谁更虔诚，或是我的屌比你的要大，等这种愚蠢的行为。测试是用来让<strong>程序员</strong>得到有帮助的、更快的反馈，从而找到正确的路径，如果你搞坏一些事，其还可以用来给后人一些警告。这根本就不是一个神秘的有魔力的方法其可以让你的代码变得更好……</p>
<p>整个Test-Driven Development的概念是麻痹和信奉，从而让其成为你的人生观。相反的：Developer-Driven Testing，它给你和你的同事一些有用的工具来解决问题，来支持你自己，而不是那种以工具或方法为中心的让你假设其应该是那样的测试。</p>
<p><span id="more-5531"></span></p>
<p>是不是在有些时候我们需要在写代码前写测试？当然是，比如，“修改已有的功能”，这会一个适用的场景，还有那些短小的和已定义完善的事物，或是对已被测试过的代码做一些改善。</p>
<p>但， 是不是你就应该需要<strong>总是</strong>要去先写测试？省省吧，别逗了。</p>
<p>这是极度白痴的行为，尤其是在设计，调查和开发的初期。让你的测试来接管你的代码（而不是影响那个模块的代码）和接管你的设计 这是一个巨大的失败，就是因为你写的那些测试范围太大太不靠谱。（陈皓注：我在《<a title="TDD并不是看上去的那么美" href="https://coolshell.cn/articles/3649.html" target="_blank">TDD并不是看上去的那么美</a>》一文中说过测试案例的测试范围的问题，敏捷社区除了对我进行人身攻击外从未对此做过正面回答。）</p>
<p>在写代码前写测试案例在一些场景下的确很不错。然后，Test Driven Development，被敏捷专家或是其它各种五花八门的江湖骗子像神给凡人宣扬一样，这就是欺骗大众。</p>
<p>行动在想法之下，于是测试必需先行（所有我已看到的，所有我正在看到的都表明这是TDD的中心思想—— 你写了测试，然后你再写代码并通过测试），于是测试成为了最有用的活动并可以帮助程序员。这是错的。</p>
<p>就算你在一开始要写一些测试案例，但只要你想让这些测试案例更有意义，那么，你要么得让这些测试案例的测试范围更小更底层更精确，要么你就得在整个软件快要写完的时候再去写测试，要不然你就得欺骗或是篡改测试案例。在为数不多的情形下，前者是正确的——测试围绕于bug，或是小的，定义地很好的功能碎片（陈皓注：我个人理解为单元测试是目前最有效的））</p>
<p>把测试变成整个活动的中心因为其对程序员有用？真牛逼。老实说，控制程序员的工作流程只可能得出一条无比正确的答案——荒谬可笑。</p>
<p>测试帮助程序员，是因为其可以帮程序员组织自动化测试，所以才帮了程序员，而不是cargo-cult（<a href="http://zh.wikipedia.org/zh/%E8%88%B9%E8%B2%A8%E5%B4%87%E6%8B%9C" target="_blank">货物崇拜</a>，参看《<a title="各种流行的编程风格" href="https://coolshell.cn/articles/2058.html" target="_blank">各种流行的编程方法</a>》中的cargo-cult编程）——信仰一种工作流程并让所有的人或事来适应于他。</p>
<p>先写测试这种方法只会在“Developer Driven Testing”（程序员自己驱动的测试）下可行——关注于选取一个正确的方法让程序员更有生产力。生成一堆测试的规则并说这是唯一的真理是不正确的。</p>
<p><strong>一些讨论和想法（在此贴发出数小时后）&#8230;</strong></p>
<p>当我这篇博文发出几个小时后，其被转到了别的地方并引发了一些讨论。</p>
<p>在 <a href="http://news.ycombinator.com/item?id=3033129" target="_blank">Hacker News</a> 上，有人说我提出了很多很不错的问题，并且那是真正的有理有据的观点。我在用用户名叫<em>peteretep </em>的回复了一些。</p>
<p>在 <a href="http://www.reddit.com/r/programming/comments/kq001/testdriven_development_youve_gotta_be_kidding_me/">Reddit</a> 上的争论更多更强。那里有很多的人觉得需要写自动化测试。并且这篇博文被大家演变成拥护测试和可实践的建议，我觉得我是误传达了我的想法，我觉得软件测试是非常重要的，而不是根据哪个方法论进行的教条主义！</p>
<p style="text-align: center;">——————————————正文结束——————————————</p>
<p>我在Reddit上看到了下面的事，我也作些评论。</p>
<ul>
<li>大家在讨论很多很多的技术细节，比如如何测试私有方法，如何测试inner class，甚至还有代码。我太喜欢了，这才是真正的讨论，而不是像酷壳这边那些敏粉们说人而不说事的讨论，<strong>那些所谓的敏捷咨询师的话里连一点技术细节都没有</strong>。</li>
</ul>
<ul>
<li>并且也有人说TDD可以让你去Design，但随后就有人说，正真的Design就是Design，而不是hack 测试来强行让你Design。后面有了附和到——有<strong>很多思想意识想用流程来代替思考，软件开发就是需要在某中上下文下去思考，而不是使用某种机制来让你思考</strong> 。</li>
</ul>
<ul>
<li>我看了两极分化的大量的争论，这是我最喜欢看到事。世界就是因为有不同的观点而美好。<strong>有反对才有争论，有争论才有思考，这才是进步的源泉，而不是统一认识，形成标准</strong>。而对于那些党同伐异的，一听到有反对声就激动就要打压的敏粉来说，我只能认为他们的人生观世界观扭曲得就像朝鲜那样。</li>
</ul>
<div>（全文完）</div>
<p><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/09/fight-150x150.jpg" alt="“单元测试要做多细？”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_title">“单元测试要做多细？”</a></li><li ><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/10.jpg" alt="在新浪微博上关于敏捷的一些讨论" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_title">在新浪微博上关于敏捷的一些讨论</a></li><li ><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="Bob大叔和Jim Coplien对TDD的论战" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_title">Bob大叔和Jim Coplien对TDD的论战</a></li><li ><a href="https://coolshell.cn/articles/3778.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="敏捷水管工" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3778.html" class="wp_rp_title">敏捷水管工</a></li><li ><a href="https://coolshell.cn/articles/3745.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/26.jpg" alt="再谈敏捷和ThoughtWorks中国咨询师" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3745.html" class="wp_rp_title">再谈敏捷和ThoughtWorks中国咨询师</a></li><li ><a href="https://coolshell.cn/articles/3766.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/02/feedback_cycle-150x150.jpg" alt="[转]TDD到底美还是不美？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3766.html" class="wp_rp_title">[转]TDD到底美还是不美？</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/5531.html">Test-Driven Development？别逗了</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/5531.html/feed</wfw:commentRss>
			<slash:comments>52</slash:comments>
		
		
			</item>
		<item>
		<title>在新浪微博上关于敏捷的一些讨论</title>
		<link>https://coolshell.cn/articles/5143.html</link>
					<comments>https://coolshell.cn/articles/5143.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Fri, 12 Aug 2011 00:22:58 +0000</pubDate>
				<category><![CDATA[技术管理]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[Scrum]]></category>
		<category><![CDATA[TDD]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=5143</guid>

					<description><![CDATA[<p>自从我发布了“Scrum为什么不行”，并被CSDN推成首页头条后，我在我的新浪微博上就经常被敏粉们@去讨论他们的一些话题。他们似乎想要从我这里听到一些不同的声音...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/5143.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/5143.html">在新浪微博上关于敏捷的一些讨论</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>自从我发布了“<a title="为什么Scrum不行？" href="https://coolshell.cn/articles/5044.html">Scrum为什么不行</a>”，并被CSDN推成首页头条后，我在我的新浪微博上就经常被敏粉们@去讨论他们的一些话题。<strong>他们似乎想要从我这里听到一些不同的声音，我很喜欢他们的这种态度，在这里先赞他们一个</strong>。既然，让我来评论他们的东西，我就不客气了，板砖自然是少不了的。 我觉得我在微博上的观点比较散，所以在这里做一个汇总。我在所有批评敏捷的文章里都重复说过我的立场，这里还要再说一遍，因为那群人很敏感——“<strong>我承认敏捷中有一些东西我是认可的，但对敏捷社区的推广和思维方式我持否定态度</strong>”。</p>
<h4>敏捷词汇表</h4>
<p>我被<a href="http://weibo.com/adamwu73">@吴穹adam</a>邀请进入了一个<a href="http://q.weibo.com/852378?source=weibohome" target="_blank">敏捷词汇表的微群</a>，这个群就是想明确的定义一下敏捷的各种词汇，比如，他们想把TDD定义成就是UT。呵呵。我对这个群仅保持了30分钟的热度，我在里面发了一个“你们不想讨论技术吗？”的帖子，就再也不想关注了。因为我的观点如下：</p>
<ul>
<li>我不知道干这件事有什么意义。标准化还是洗脑？One World, One Agile?  &#8211;<strong> horse shit!</strong></li>
<li>你能定义地好吗？定义好了大家都能干好了？ &#8211;<strong> 幼稚！</strong></li>
<li>理解不同又有什么关系？价值观不同又能怎么样？为什么不能正视并接受世界的不同呢？ &#8211;  <strong>固执！</strong></li>
</ul>
<h4><strong>敏捷宣言</strong></h4>
<p>我看到很多人又把《敏捷宣言》拿出来说事，就好象他们把敏捷宣言是软件开发的普世的价值观一样。我对此的评论是—— <span id="more-5143"></span></p>
<blockquote><p><a href="http://weibo.com/haoel">@左耳朵耗子</a>：<span style="color: #0000ff;">微博里多了很多《敏捷宣言》的话题，这让我想到了《共产党宣言》， 这两个组织里的某些人很相似，都通过宣言来树立价值观，然后通过传教的方式四处宣讲来影响大众吸收党羽，并要求对其价值观的信仰，还以一种革命者的态度来实践…… 建议程序员还是多研究技术细节，关注技术发展趋势，分析产品和用户需求。</span></p></blockquote>
<h4>博文评论</h4>
<p><a href="http://weibo.com/adamwu73">@吴穹adam</a>发表了一篇《<a href="http://blog.csdn.net/adwu73/article/details/6677908" target="_blank">为什么纯粹的Scrum在中国很难落地（一）</a>》并欢迎我去拍砖。我拍了下面几块砖：</p>
<ul>
<li>看标题还以为要谈什么中国实际的问题，结果只是一些文章的读后感。没有实际价值。</li>
<li>我对为什么在中国难落地的原因提了三条：</li>
<ul>
<li>你们总是想以Scrum为中心来改变实际情况和民众，而不是民众自发的。</li>
<li>世界是不同的，多元的，这告诉我们不要死读书，读死书，更不能教条主义。</li>
<li>世界是不完美的。有很多东西无法改变的，如人性，文化，政治…… 要学会接受并管理他们。</li>
</ul>
<li>我给<a href="http://weibo.com/adamwu73">@吴穹adam</a>的建议——<strong>只有当你开始关注实际情况的时候，你才能真正成为一个实践者</strong>。</li>
</ul>
<p>看到在<a href="http://weibo.com/1880082254/xiWv9AShm" target="_blank">评论中</a>——</p>
<blockquote><p> “<a href="http://weibo.com/n/%E5%BC%A0%E6%9D%83%E5%85%88%E7%94%9F">@张权先生</a>：团队拒绝Coach，与敏捷实践缺乏统一认知有关，书籍、网上资料中，很多信息是不统一的，混乱的局面只能从信息源头抓起，规范术语、规范表述为好”。</p></blockquote>
<p>我观点是：</p>
<ul>
<li>先得对大众洗脑，统一认识？和谐？</li>
<li>一千个人有一千个哈姆雷特，认识不同又有何妨？</li>
</ul>
<p><a href="http://weibo.com/1949520867">@蔡晓东_</a>发了一篇《<a href="http://weibo.com/1949520867/xiZRDCOr1" target="_blank">低层级的敏捷毫无意义，组织级敏捷才是敏捷的核心问题</a>》的长微博，也让我去讨论。我这样回复——“<span style="color: #cc0000;"><strong>为什么你们一定要定义哪种软件开发是敏捷？哪种不是? 为什么一定要敏捷呢？做这个划分的目的是什么？是不是只有这样搞，某些组织某些人才有饭碗呢?</strong></span>”， 我希望敏捷社区的人能正面回答我这个问题。</p>
<p>我的一个前同事回复到：</p>
<blockquote><p><a href="http://weibo.com/n/ilinux">@ilinux</a>:&#8221;低层级的敏捷毫无意义，组织级敏捷才是敏捷的核心问题&#8221;, 这口号听起来就像是要, 从生产关系上和上层建筑着手，解放全世界无产阶级码农。</p></blockquote>
<p>还有一个朋友回复到（多好的建议）：</p>
<blockquote><p>@<a href="http://weibo.com/yuyijq">横刀天笑</a> 低层次不干好，就别谈组织的了吧。。。说实话，我喜欢持续改善，讨厌重大变革。喜欢基础实践，讨厌空喊口号。</p></blockquote>
<h4>后续</h4>
<p>下面这个微博看来是怒了，敏捷社区，你能告诉我这是为什么吗？</p>
<blockquote><p><a href="http://weibo.com/silentriver">@陈加兴</a>：所谓“观其言，察其行”，别人的话摘录再多，终究是别人说的话，和你一毛钱关系都没有。言必称“敏捷”，把敏捷搞得跟唐诗三百首似的颠过来倒过去地背，却不知软件中“设计”为何物，我实在不知道这样“没有项目经验如何谈敏捷”？没有一点团队管理经验，却处处指导众生管理团队，真是神仙下凡啊。</p></blockquote>
<blockquote><p><a href="http://weibo.com/n/%E9%99%88%E5%8A%A0%E5%85%B4">@陈加兴</a>:回复<a href="http://weibo.com/n/%E5%BE%90%E6%AF%85-Kaveri">@徐毅-Kaveri</a>:对事不对人，这种混子行径我唾弃，不点名，因为可以对号入座的人，多着呢。</p></blockquote>
<p>我也认识很多混子，包括现在或曾在TW里的。</p>
<p>最后，让我再echo一下前面的话—— <strong>这两个组织里的某些人很相似，都通过宣言来树立价值观，然后通过传教的方式四处宣讲来影响大众并吸收党羽，并要求对其价值观的信仰，还以一种革命者的态度来实践…… </strong>（有几个网友在我这个微博中讨论了很多，<a href="http://weibo.com/1401880315/xiFMptHMg" target="_blank">大家可以去看看</a>。） <span style="color: #cc0000;"><strong>看这些所谓的咨询师、实践者、倡导者有没有料，你就直接和他谈技术实现，谈业务需求，谈产品分析，你就知道他有多少水水了</strong></span>。</p>
<p><em><strong>————更新2011年8月13日————</strong></em></p>
<h4>糊弄客户？</h4>
<p>在微博上看到InfoQ主编+TW咨询师<a href="http://weibo.com/n/%E5%BC%A0%E5%87%AF%E5%B3%B0">@张凯峰</a>同学的一条微博的回复（<a href="http://weibo.com/1416875735/xjiafswMq" target="_blank">原微博在这里</a>）</p>
<figure id="attachment_5152" aria-describedby="caption-attachment-5152" style="width: 458px" class="wp-caption aligncenter"><img decoding="async" loading="lazy" class="size-full wp-image-5152" title="张凯峰的微博" src="https://coolshell.cn/wp-content/uploads/2011/08/张凯峰的微博.png" alt="" width="458" height="149" srcset="https://coolshell.cn/wp-content/uploads/2011/08/张凯峰的微博.png 458w, https://coolshell.cn/wp-content/uploads/2011/08/张凯峰的微博-300x98.png 300w" sizes="(max-width: 458px) 100vw, 458px" /><figcaption id="caption-attachment-5152" class="wp-caption-text">张凯峰的微博：如果客户连需求都说不出一二来，那就太好糊弄了。</figcaption></figure>
<p>糊弄客户！所以，我可以类推他会说——“<strong>如果你不懂敏捷，那就太好糊弄了</strong>”。这就是TW的咨询师。呵呵。</p>
<p>接下来，另一个自称“Agile导师”@<a href="http://weibo.com/1849127973">张义军SH</a>说，</p>
<blockquote><p><a href="http://weibo.com/1849127973">张义军SH</a> 陈浩这次确实有点断章取义了，应该说张凯峰的说法还是很实在的 //<a href="http://weibo.com/n/%E5%B7%A6%E8%80%B3%E6%9C%B5%E8%80%97%E5%AD%90">@左耳朵耗子</a>：回复<a href="http://weibo.com/n/%E5%BC%A0%E5%87%AF%E5%B3%B0">@张凯峰</a>: 糊弄客户?! 看到了吧，InfoQ总编，TW咨询师，真面目暴露出来了吧。//<a href="http://weibo.com/n/%E5%BC%A0%E5%87%AF%E5%B3%B0">@张凯峰</a>:回复 <a href="http://weibo.com/n/weidagang">@weidagang</a>:如果客户连需求都说不出一二来，那就太好糊弄了。</p></blockquote>
<p>这就很强大啊——我到是想听听这个导师认为的“糊弄”的说法怎么个实在法？于是他回复到：</p>
<blockquote><p><a title="张义军SH" href="http://weibo.com/1849127973">张义军SH </a>：回复<a href="http://weibo.com/n/%E5%B7%A6%E8%80%B3%E6%9C%B5%E8%80%97%E5%AD%90">@左耳朵耗子</a>: 我是在看整个讨论过程。在客户没有想法没有太多思路时，他说客户容易糊弄我觉得确实如此，评级很实在。但他们后面在深入讨论这个问题，我认为您也应该看看，给一些建设性意见。</p></blockquote>
<p>呵呵，用户提不出准确的需求这太正常不过了，但是这不代表用户傻，可以糊弄。另外，尤其是那些创新的项目，哪有什么需求，只有一个大概的方向，谁都不知道该做成什么样，我现在做的就是这样的项目。不做个原型，不前期试探一下用户和市场，谁也不知道。</p>
<p>另外，我想告诉这些人，用户需求提不出来很正常，提偏了也很正常，关键在于我们的需求分析能力。福特汽车公司的创始人说过——“<strong>如果我问用户要什么，他们会告诉我他们要一匹更快的马！</strong>”，<strong>大多数平庸的人都会去饲养“一匹更快的马”，而不是分析需求后了解到用户的需求是——“更快的交通工具”。</strong></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/09/fight-150x150.jpg" alt="“单元测试要做多细？”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_title">“单元测试要做多细？”</a></li><li ><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/14.jpg" alt="Test-Driven Development？别逗了" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_title">Test-Driven Development？别逗了</a></li><li ><a href="https://coolshell.cn/articles/5044.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/07/hat-150x150.jpeg" alt="为什么Scrum不行？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5044.html" class="wp_rp_title">为什么Scrum不行？</a></li><li ><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="Bob大叔和Jim Coplien对TDD的论战" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_title">Bob大叔和Jim Coplien对TDD的论战</a></li><li ><a href="https://coolshell.cn/articles/3778.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="敏捷水管工" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3778.html" class="wp_rp_title">敏捷水管工</a></li><li ><a href="https://coolshell.cn/articles/3745.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/26.jpg" alt="再谈敏捷和ThoughtWorks中国咨询师" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3745.html" class="wp_rp_title">再谈敏捷和ThoughtWorks中国咨询师</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/5143.html">在新浪微博上关于敏捷的一些讨论</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/5143.html/feed</wfw:commentRss>
			<slash:comments>54</slash:comments>
		
		
			</item>
		<item>
		<title>为什么Scrum不行？</title>
		<link>https://coolshell.cn/articles/5044.html</link>
					<comments>https://coolshell.cn/articles/5044.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Thu, 21 Jul 2011 00:37:03 +0000</pubDate>
				<category><![CDATA[流程方法]]></category>
		<category><![CDATA[轶事趣闻]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[Scrum]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=5044</guid>

					<description><![CDATA[<p>这篇文章的原文在这里（原文链接）（下文不是全译，也不是部分译，我只是把其总结，有我自己的发挥，但是原意大致不变），这篇文章完全是在调侃Scrum的，作者第一段就...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/5044.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/5044.html">为什么Scrum不行？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright wp-image-21319 size-thumbnail" src="https://coolshell.cn/wp-content/uploads/2011/07/hat-150x150.jpeg" alt="" width="150" height="150" />这篇文章的原文在这里（<a title="Why Scrum will never work" href="http://maurits.wordpress.com/2011/07/13/why-scrum-will-never-work/" target="_blank" rel="noopener">原文链接</a>）（<strong>下文不是全译，也不是部分译，我只是把其总结，有我自己的发挥，但是原意大致不变</strong>），这篇文章完全是在调侃Scrum的，作者第一段就是一个免费声明，其说他是<a href="http://en.wikipedia.org/wiki/Scrum_(development)">Scrum</a>和其它敏捷方法的big fan， 他也认为Scrum 100% 对 软件开发可行。作者使用Scrum 5年了，也公开作过几次敏捷的分享会。他觉得写这篇文章只是为了好玩，因为他们戴上<a href="http://en.wikipedia.org/wiki/Edward_de_Bono">Edward de Bono</a> 的 <a href="http://en.wikipedia.org/wiki/Six_Thinking_Hats#Black_hat_.E2.80.93_Being_Cautious">black hat</a> （黑礼帽 &#8211; 是6个思考之帽中的一种——负面思考，思考事物的负面因素，这样才知道：它会起作用吗？缺点是什么？它有什么问题？为什么不能做。）</p>
<p>因为本人经常站在Agile的风口浪尖，所以我有必要也来一个“免责声明”。Shit！其实我想来的是“<strong>不免责声明</strong>” ——<strong>下文中的九大原因是对中国的各种Agile实践者咨询师不注重实际只重方法论的批判</strong>，<strong>本人必然要和那种只以流程方法论为中心的软件开发斗争到底</strong>。其实我没有那么嚣张，<strong><span style="color: #ff0000;">我只是想说，下面的这些东西相当的现实。</span><span style="color: #ff0000;">希望各种Scrum的实践者们认识到这些问题，从而可以让你们明白软件开发中的人的重要性</span></strong>。</p>
<p><strong>Reason 1</strong>:  <a href="http://en.wikipedia.org/wiki/Scrum_(development)">Scrum</a> 的基石是相信人。创造一个安全的环境，这样每个人都能相互学习，相互直言。但是，这是不行的，这世上有很多人并不关心这些，而且政治和竞争到处都是，办公室里无小事，你和别人交心，你相信他们，最终受伤的你自己。你真的以为那里有空间让你可以去犯错，去冒险吗？别天真了！你啊，too young, too simple, sometimes naive!</p>
<p><strong>Reason 2</strong>: <a href="http://en.wikipedia.org/wiki/Scrum_(development)">Scrum</a> 认为只要给员工足够多的自由员工就能做得最好。这该死是理论是基于什么玩意？不可能，人的天性是懒惰的，他们才不会把事做好的，他们只会做相应报酬的工作量，还可能基本还达不到其相应的报酬，大多数人都在混日子啊。尤其是和经理比起来，谁不想能尽快地成为经理或Team leader啊，因为那样他们就可以即不干活，又挣得多。另外，你给他们自由，你就会发现，他们会只会做他们感兴趣的事，要么聊QQ，要么打游戏，看闲书，反正不干正事。直到你催了，他们才动一动。</p>
<p><span id="more-5044"></span></p>
<p><strong>Reason 3</strong>: 因为前面的原因，所以，我们仍然要把一个PM放在Scrum团队的上面做管理，这样才会有产出。于是，PM给团队分配任何，管得细枝末节，事无巨细，天天让你做进度汇报，等等。直至把团队拖垮。</p>
<p><strong>Reason 4</strong>: <a href="http://en.wikipedia.org/wiki/Scrum_(development)">Scrum</a> 只不过是一个流程。这世上有太多的流程，尤其是那那些操CMMi的公司。几乎所有玩CMMi流程的公司，你都能看到的是员工都是那一副副苦逼的脸。所以，Scrum的流程同样会这样。因为这些都不是开发团队自发出来的，而是上面管你喜欢不喜欢按给你的。 Scrum 根本不可能增进你的软件质量和技术，只能是优秀的人才才可能！使用Scrum的公司都是些吝啬鬼，他们不愿花大钱招优秀的人，他们妄图使用Scrum这种东西让现有的这些廉价劳动力发挥更大的生产效率，Scrum成了push程序员最有用的工具。</p>
<p><strong>Reason 5</strong>: <a href="http://en.wikipedia.org/wiki/Scrum_(development)">Scrum</a> delivers ‘business value’。不是这样的，实际上，Scrum不可能。这有很多原因。真正了解业务的那帮人根本不可能加入项目团队，那些人谁TMD愿意和苦逼的技术人员加班啊。 那些人喜欢和我们的用户吃吃喝喝，花天酒地的，根本不会和你们那些奇怪的东西（如：backlog）或是那堆ugly的内向古怪的技术人员打交道，更别说什么技术了。所以，你的团队就像一个客服团队或救火队一样疲于奔命。</p>
<p><strong>Reason 6</strong>: 一个敏捷的团队应该是持续进步的。这就是为什么Scrum总是在问什么干得好，什么需要改进，并定义行动方案。你真的以为员工想进步吗？让他们不得不去想想自己和团队怎么进步，然后他们还不得不去执行行动方案。别天真了，人的天性是不喜欢改变的，人的天性是习惯于一些按部就般的事的，也许那样做令人讨厌，但是人家还是能干点东西出来。如果你逼着人家改变，你就是在压迫人家，人家自然会反抗。</p>
<p><strong>Reason 7</strong>: Product Owner 专注于 ‘what’ 和 ‘why’ 的问题，开发团队决定 ‘how’。很不错的分工，于是可以造就一个即高速有重质量的团队。然而，这根本不行。你的Product Owner马上就想要这个功能，他才不管你的软件开发的技术难题，人家只要快，要你meet deadline，要你给我们重要的客户做出承诺。另外，你千万不要以为你们可以哄走这个初级的product owner，因为他的后台是直接汇报到高层管理。你作为一个程序员可能只是其个小部门的一个小喽啰，或者只是外包公司，你觉得可能吗？你觉得建立信任可能吗？</p>
<p><strong>Reason 8</strong>: 软件质量和生产率成正比。也就是说，质量越高，生产率越高。如果质量不高，你开发效率就会低下，但是谁管呢？我们朝九晚五的上班，质量好了也是做8小时，质量差了也是做8小时，无所为嘛。另外，我们的 project manager (或者是Scrum master!) 总是会批评我们没有按计划完成。所以，这根本 不可能。</p>
<p><strong>Reason 9</strong>: “是的，如果我们只做需要的功能，那么我们就会最低的成本，对吗？”，为什么这世上总是会有这些幼稚的人？这种事怎么可能啊。很多很多的银行或保险公司的项目在你还没有启动项目前就谈好了一个价格（可能还会有回扣），为了打单子，销售什么都干得出来，让你去做项目是因为你是廉价劳动力，而且，他们会不断地加需求，因为软件合同谈好的价格时候，连需求都没有，你去做了才有，还是模糊和不确定或根本就是错的，然后需求是越来越多，越改越多。等你精疲力尽的时候，你才意识到，销售早就把你卖了。</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-21320" src="https://coolshell.cn/wp-content/uploads/2011/07/dilberttrust.gif" alt="" width="550" height="171" /></p>
<p>爽啊，戴着黑礼帽思考问题比我想像中的要有趣得多，现在我必需要把它摘下来了。</p>
<p><strong>看完这篇文章，你觉得是人的问题还是软件开发方法的问题？</strong></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/10.jpg" alt="在新浪微博上关于敏捷的一些讨论" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_title">在新浪微博上关于敏捷的一些讨论</a></li><li ><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/09/fight-150x150.jpg" alt="“单元测试要做多细？”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_title">“单元测试要做多细？”</a></li><li ><a href="https://coolshell.cn/articles/7657.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/06/hudsonCI2-150x150.jpg" alt="持续部署，并不简单！" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7657.html" class="wp_rp_title">持续部署，并不简单！</a></li><li ><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/14.jpg" alt="Test-Driven Development？别逗了" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_title">Test-Driven Development？别逗了</a></li><li ><a href="https://coolshell.cn/articles/5625.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/19.jpg" alt="“品质在于构建过程”吗？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5625.html" class="wp_rp_title">“品质在于构建过程”吗？</a></li><li ><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="Bob大叔和Jim Coplien对TDD的论战" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4891.html" class="wp_rp_title">Bob大叔和Jim Coplien对TDD的论战</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/5044.html">为什么Scrum不行？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/5044.html/feed</wfw:commentRss>
			<slash:comments>102</slash:comments>
		
		
			</item>
		<item>
		<title>Bob大叔和Jim Coplien对TDD的论战</title>
		<link>https://coolshell.cn/articles/4891.html</link>
					<comments>https://coolshell.cn/articles/4891.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 27 Jun 2011 00:41:23 +0000</pubDate>
				<category><![CDATA[技术读物]]></category>
		<category><![CDATA[流程方法]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[BDD]]></category>
		<category><![CDATA[CDD]]></category>
		<category><![CDATA[TDD]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=4891</guid>

					<description><![CDATA[<p>今年春节时，我写了一篇《TDD并不是看上去的那么美》，在这篇文章中我列举了一些关于使用TDD的一些难点和对TDD的质疑，后来出现了一些争论（可参见那篇文章的评论...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/4891.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/4891.html">Bob大叔和Jim Coplien对TDD的论战</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>今年春节时，我写了一篇《<a title="TDD并不是看上去的那么美" href="https://coolshell.cn/articles/3649.html" target="_blank">TDD并不是看上去的那么美</a>》，在这篇文章中我列举了一些关于使用TDD的一些难点和对TDD的质疑，后来出现了一些争论（可参见那篇文章的评论），以及Todd同学的《<a title="[转]TDD到底美还是不美？" href="https://coolshell.cn/articles/3766.html" target="_blank">TDD到底美不美</a>》，还有infoQ中文上的那个<a title="虚拟座谈会：TDD有多美？" href="http://www.infoq.com/cn/articles/virtual-panel-tdd" target="_blank">几乎没有营养离线讨论</a>。今天，有网友给我推来一个英文版infoQ的视频——“<a title="Coplien and Martin Debate TDD, CDD and Professionalism" href="http://www.infoq.com/interviews/coplien-martin-tdd" target="_blank">Coplien and Martin Debate TDD, CDD and Professionalism</a>”，这是2008年2月18日的视频，视频的主角两个人争论TDD好还是不好，一个是敏捷社区的教主级的人物——Robert Martin（大家称之为“Bob大叔”），另一个是C++，OO，多范式编程的大师<a href="http://en.wikipedia.org/wiki/Jim_Coplien" target="_blank">Jim Coplien</a>（大家都叫他Cope）。这两个人对TDD的见解有分歧。Coplien的很多观点和我之前的不谋而合，而他自己称他是坚决强烈地站在TDD的对立面上。下面是Jim的原话：</p>
<blockquote><p>I have adopted a very strong position against what particularly the XP community is calling test driven development.</p></blockquote>
<p>InfoQ的视频很多时候相当的不给力，就像有前列腺的患者撒尿一样，半天都挤不出一滴。不过，好在那里有这两个人对话的摘录。在这里，我给大家摘要一下：</p>
<p style="text-align: center;">——————————————————正文分割线————————————————————</p>
<p>Coplien首先让Uncle Bob定义了一下TDD，Uncle Bob说明了他的三个法则：（敏捷的同学一定不陌生）</p>
<ol>
<li>一个测试驱动的程序员，其不会在写出一个测试失败的Unit Test前，去写一句可用在生产线上的代码。（没有测试之前不要写任何功能代码）</li>
<li>在编写用于生产线上代码之前，不写过多的测试失败的Unit Test。（只编写刚好能体现一个失败情况的测试代码）</li>
<li>在现有代码通过Unit Test前，不写更多的用于生产线上的代码。（只编写恰好能通过测试的功能代码）</li>
</ol>
<p>Coplien说他有意见的不是这三个法则，而是因为这个三个法则是孤立说出来的。Coplien说他和一些咨询师或是Scrum Master参与过很多的项目，他们发现这些项目都有两个问题：</p>
<ol>
<li>他们使用TDD的时候，软件没有一个架构或是framework。当然，Kent Beck说——TDD可以驱使你去做架构。但是，<strong>TDD和Unit Test 是一回事吗？</strong>Unit Test是一个伟大的事，尤其是当你去写API和类库的时候。今天XP所说的TDD和UT很不一样。如果你使用TDD来驱动你的软件系统架构，那么，<strong>基本上来说，三个迭代以后，你开发的软件就会crash掉，而且无法再往前开发</strong>。 因为什么？因为连软件团队自己都受不了这三个迭代出来的架构，而且你还会发现，你根本没去去重构。</li>
<li>第二个问题是，TDD这种方法破坏了GUI（图形界面），就算是Kent也说：“<strong>你永远不可以在一个漂亮的界面后面隐藏一个糟糕的架构</strong>”，Coplien强烈地相信软件的架构是通过界面来发出其光芒。他觉得如果没有一个好的软件架构，这个会影响用户的操作。</li>
</ol>
<p>Coplien接着说，如果我们使用Uncle Bob的三条法则，我们也许没有什么问题，<strong>但Coplien想告诉大家另一个非常重要的事，那就是软件架构。并说：“我根本不接受TDD是软件专业化实践的论点”</strong>。</p>
<p><span id="more-4891"></span></p>
<p>Bob大叔说，让我们回到99年，那时的敏捷社区觉得软件架构是无关的，不需要软件架构，只需要做一堆tests，做一堆stories，以及足够快的迭代，这样就可以让那些代码魔幻式地拼装起来，这就是horse shit。对于大多数的敏捷拥护者来说，这的确是愚蠢的。今天你再和Knet说这个事，他也会说那不过是一种说法。</p>
<p>Coplien回应到，实际上，Knet在解释XP的时候，在他的书131页的位置说过，“是的，你得做些前期的架构，但也别把自己搞乱了”。</p>
<p>Bob大叔把话题转回来，继续聊关于架构方面的事，他说软件的架构很重要，他也写很一些关于架构的书，他说他也是一个架构方面的怪才，但是他认为架构自己并不会形成软件的所有的外表。他觉得好的软件架构和设计能力应该出现在若干次迭代之后。他觉得你在架构软件的时候，你会创造一些东西，也会破坏一些东西，并且会在几次迭代中做一些试验性的工作，来尝试一下不同的架构。<strong>在2到3次迭代以后，你可以知道那一种架构是对的，这样，你可以在后面的迭代中进行调整 。因此，他认为架构是需要进化和发展的，而不会因为被可执行的代码所形成，也不会因为你所写的测试而形成</strong>。</p>
<p>Coplien赞同架构进化的观点，而且他相信软件的架构的演变和进化不是因为你写的代码，也不是因为Use Case，也不是告诉你你的软件需求的范围和其中的关系，但是如果你做的方法是以增量式的，以用户驱动式的，而你却在和用户沟通时没有一些前期的业务知识，那么这一定是相当有风险的，并且你一定会把事搞砸的。</p>
<p>Coplien接着说，他在Knet早期提到TDD的时候和Knet时，提到YAGNI（陈皓注：You Aren&#8217;t Gonna Need It，XP的一个法则，也就是只做最简单的事）时，Kent说到：“让我们来做一个银行帐户，一个储蓄帐户”，储蓄帐户其实就是对余额进行一些加加减减的事，就像一个计算器一样。Copilen继续解释到，但是如果你要做一个真正的银行系统，你的软件架构根本不可能从一个储蓄帐户的对象（计算器）重构出来。因为储蓄帐户根本就不是一个对象，其是一个流程，后面有一个数据库的查帐索引事务，还有存款保证多和利息，还有一些转帐功能。就算是这样，这也只是用户的功能，你还需要支持税务人员和精算会计师等这些人，<strong>这会让银行系统成为一个错综复杂的软件架构，这绝对不是你可以用迭代干出来的事。当然，Bob大叔是可以的，因为他有40年的银行系统的经验。但是Bob大叔你的这40年可真不敏捷啊</strong>。</p>
<p>Coplien接着说， 因为Bob大叔可以在软件前期做很多很重要的决定，这让得后面的事变得相对比较简单。Coplien根本不相信只要你把代码往那一放，在上面披上一层皮，再设置好一些角色，设置好接口，在文档里写上整个业务结构，而你只有在有人花钱的时候你才会在其中填充进真正的代码，反之就违反了你的YAGNI原则。所以，你只是在你需要的时候做你要做的事，但你却还是要提前得到你的软件架构，否则你一定会把你自己逼进死角的。</p>
<p>Bob大叔辩解到，我说的可能和你说的这个有点不同。我们应该不会像你所说的往接口中写一些抽象成员函数，而是创建一些有抽象接口的对象。当然，我不会把一下子为这个对象装载上一堆方法。那些是我需要使用测试驱动或是需求驱动来做的事，我还会随时随地在看是否哪里软件架构可以让我拆分接口。</p>
<p>Coplien说，问题 是你得知道你要干什么？他说他非常同意Knet的书&#8221;XP Explained&#8221;里说的——“你不能去猜”，然后他举了一个例子，一个他曾经在一个电信项目中重新架构软件的例子，这是一个长途交换机的项目，项目组特别喜欢用面向对象，有一个人需要去做一个“Recovery Object”（应该是系统恢复对象），Coplien说这是很扯的一件事，因为系统恢复根本就不是一个对象，因为他对业务不熟，所以想这么做。而当你在细节上分析的时候，你会发现这根本就不是一个有成员方法的对象。我个人认为，Coplien想用这个例子来说Bob大叔的先定义对象的抽象接口并不是一个好的需求分析的方法。Coplien还说，这个事情今天被资本化成了SOA，真是在玩火啊。</p>
<p>Bob大叔说，这个他很同意。你的确需要知道这个对象的意义是什么。而且他和Coplien都同意应该根据可运行的代码来决定未来，而不是基于投机心理搞一个巨大无比的架构。</p>
<p>此时，Bob大叔把话题又带回原地，他问Coplien：“你需要多少的时间才能写出可运行的代码？是不是一个系统需要写200万行代码才能算？”，Coplien说，在他的经历中，200万行代码算是小项目了，他的项目都是几亿行代码的。而在让代码可以跑起来，他至少需要让所有的对象都联系起来。</p>
<p>Bob追问到，“那么你是怎么测试这些对象的连接性的？”，Coplien说，我当然要测试，我会测试系统启动和停止，看看有没有内存问题，半小时就好了。Bob大叔似乎找到了突破点，于是说到：“Excellent！那么我们间的分歧是什么呢？也许你只是不同意TDD的概念和其专业化，当然，这是另外一个话题了”。</p>
<p>然后，Coplien说了一段我非常非常认同的话——“我看到很多人正在做正确的事，来避免我们之前讨论的那些问题，当然那不是TDD的扩展，而是Dan North所说的BDD。可见，软件开发中很多人在开发软件中都是在用正确的很好的方法，而我对此有意见的是，有人把这个事说成TDD，然后人们就去买相关的书来了解TDD，并且看到“architecture only comes from tests”，我在过去6个月中听到过4次这样的说法，这就像你所说的，完全就是horse shit。而关于你所说的专业化的事，如果你没有见过一个专业化你怎么知道？”。（不是吗？大多数人都知道怎么开发软件，而不是TDD才是专业化的软件开发。）</p>
<p>然后，Bob想多谈谈专业化的事，Bob说，在今天，一个不负责任的程序会提交一段他没有跑过单元测试的代码，所以，要确定你没有把一条没有测试过的代码提交到代码库里的最佳做法就是TDD。</p>
<p>Coplien完全不同意这个说法。他觉得底层的东西是更重要的。他用了一个示例来攻击Bob大叔的这个观点，他先是说代码走查和结对编程都有好的有价值的地方，当然和这个话题不相关。然后他又说了Unit Test，想想我们的单元测试，可能我们的测试案例并不可能测试我们程序中参数的各种状态，这些状态有可能只是半打，有可能是一百个，有可能是2的32次方个，所以，我们可以命中一些状态，也会没有测试到一些状态，我们的测试真的只是试验性的，所以，如果你在测试中发现bug，你真的很幸运。</p>
<p>随后，Coplien推崇了一个叫“<a href="http://en.wikipedia.org/wiki/Design_by_contract" target="_blank">Design By Contrac</a>t” &#8211; 契约式设计的方法（我在<a title="一些软件设计的原则" href="https://coolshell.cn/articles/4535.html" target="_blank">软件设计中那些方法</a>中提到过，），这个方法认为软件有前验条件，后验条件，还有不变的。这个方法是Eiffel项目使用的一个方法，使用这个方法你可以静态的去做一些检查，相当于你做了一个基础架构来干这些事。Coplien相信这个方法有TDD所有的优点——我需要努力思考我的代码，我需要思考软件的外部接口，而且，Coplien发现这么做会比做测试更有效。这会让你对那些参数的范围考虑地更为宽广，而不是只在测试案例写几个随机分散的值来测试。</p>
<p>今天，Bertrand Meyer(Eiffel语言的创造者，他也不赞同TDD)把这个方法推进了一步，叫CDD &#8211; Contract Driven Development，这个是一种关注于对象间关系，其在程序运行前提条件和运行后的后验条中达成一种契约，可以通过对契约条件的动态或静态的检查，来对程序的功能进行验证。这样可以让你更有效地测试程序。这种方法需要对业务的重点部位非常好的了解。这是TDD很难做到的（这就是我在《<a title="TDD并不是看上去的那么美" href="https://coolshell.cn/articles/3649.html" target="_blank">TDD并不是看上去的那么美</a>》一文中说的TDD的测试范围是个很大的问题）。</p>
<p>Bob大叔似乎在努力回忆CDD和Eiffel，然后他说，TDD不就是干这个的吗？TDD就是把契约变成单元测试，不但测试输入，也测试返回值，这不就是先验条件和后验条件，而且他说，Unit Test和代码结合得更紧，而契约没有和代码结合得紧密，这是他觉得很不舒服的地方。</p>
<p>Coplien说Bob大叔创建了不应该创建的二元论。他说代码在哪里，UT就跟到哪里，代码有多臃肿，UT就有多臃肿，而UT也是代码，也会有BUG，所以，其实这真是事半功倍。还有一个最有名的示例是ADA编译器，其使用了TDD，反而增加了代码中的BUG，因为你的代码多，测试就多，代码就更多，整个代码就太过臃肿。如果你测试中使用了断言，这意味着你就耦合上了代码，你的测试案例和你的代码耦合地越多，你的代码就越难维护。这就是我在《<a title="TDD并不是看上去的那么美" href="https://coolshell.cn/articles/3649.html" target="_blank">TDD并不是看上去的那么美</a>》一文中说的TDD的代码臃肿和维护问题）</p>
<p>Bob大叔为Coplien对代码臃肿的说法感到惊讶。Coplien说，这就是他的经历，他看到的。Bob大叔承认有很多混乱的测试和混乱的代码，他觉得像XUnit这样的工具被滥用了。Coplien打断道，这不是要和你争论的，我争论的是这就是我看到大家在实践的东西。</p>
<p>Bob大叔反回到，你有没有看到CDD也被滥用的情况？Coplien说，他只觉得目前，软件业对CDD用的还不够。</p>
<p>最后，时间不够了，Bob大叔问了一个不相干的问题，他说，我们这里有BDD,CDD, TDD, 关于DD，他不知道谁是最先第一个使用带DD这个词的，他说他好像记得一个RDD &#8211; Responsibility Driven Development。</p>
<p>Coplien对这个问题可能很无语，他只能说——“DD，这是Unix的一个命令嘛，Disk Dump，但这可能算。谢谢你Bob，很高兴又一次见到你 ”</p>
<p style="text-align: center;">——————————————————正文分割线————————————————————</p>
<p>看完后，我的感觉如下：</p>
<ul>
<li>这是2008年就在讨论的事，而在2011年我发布了《<a title="TDD并不是看上去的那么美" href="https://coolshell.cn/articles/3649.html" target="_blank">TDD并不是看上去的那么美</a>》后中国这边才开始讨论。（InfoQ和 Thoughtworks怎么不去找Coplien？）</li>
<li>英语很重要，不懂英语，只看国内的东西，你就容易被洗脑，你就需要更多的时间和精力去思考那些早被人思考过的问题。</li>
<li>开发和测试，都是需要充分地了解业务，充分的思考，充分权衡后才能做得好的事。并不是你用了哪个方法后就专业了，就NB了。</li>
<li>相当BS——上不谈业务，下不谈技术，只谈方法论的人和公司，这是绝对的扭曲。</li>
</ul>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/09/fight-150x150.jpg" alt="“单元测试要做多细？”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8209.html" class="wp_rp_title">“单元测试要做多细？”</a></li><li ><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/14.jpg" alt="Test-Driven Development？别逗了" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5531.html" class="wp_rp_title">Test-Driven Development？别逗了</a></li><li ><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/10.jpg" alt="在新浪微博上关于敏捷的一些讨论" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5143.html" class="wp_rp_title">在新浪微博上关于敏捷的一些讨论</a></li><li ><a href="https://coolshell.cn/articles/3778.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="敏捷水管工" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3778.html" class="wp_rp_title">敏捷水管工</a></li><li ><a href="https://coolshell.cn/articles/3745.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/26.jpg" alt="再谈敏捷和ThoughtWorks中国咨询师" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3745.html" class="wp_rp_title">再谈敏捷和ThoughtWorks中国咨询师</a></li><li ><a href="https://coolshell.cn/articles/3766.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/02/feedback_cycle-150x150.jpg" alt="[转]TDD到底美还是不美？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3766.html" class="wp_rp_title">[转]TDD到底美还是不美？</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/4891.html">Bob大叔和Jim Coplien对TDD的论战</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/4891.html/feed</wfw:commentRss>
			<slash:comments>54</slash:comments>
		
		
			</item>
		<item>
		<title>再谈“我是怎么招聘程序员的”（上）</title>
		<link>https://coolshell.cn/articles/4506.html</link>
					<comments>https://coolshell.cn/articles/4506.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 20 Apr 2011 00:36:55 +0000</pubDate>
				<category><![CDATA[流程方法]]></category>
		<category><![CDATA[职场生涯]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[面试]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=4506</guid>

					<description><![CDATA[<p>我以前写过一篇“我是怎么招聘程序员的”的文章（在CSDN那里有很多人进行了回复）。今天，我想再谈谈关于招聘和面试这方面的东西，主要是以下这些原因： 近半年来我在...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/4506.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/4506.html">再谈“我是怎么招聘程序员的”（上）</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>我以前写过一篇“<a title="我是怎么招聘程序员的" href="https://coolshell.cn/articles/1870.html" target="_blank">我是怎么招聘程序员的</a>”的文章（在<a title="我是怎么招聘程序员（CSDN）" href="http://blog.csdn.net/haoel/archive/2009/12/18/5032418.aspx" target="_blank">CSDN那里</a>有很多人进行了回复）。今天，我想再谈谈关于招聘和面试这方面的东西，主要是以下这些原因：</p>
<ul>
<li>近半年来我在进行了大量的招聘工作，对面试有一些新的体会。</li>
<li>酷壳最近发布了几篇趣味面试题（<a title="面试题：火车运煤问题" href="https://coolshell.cn/articles/4429.html" target="_blank">面试题一</a>，<a title="又一个有趣的面试题" href="https://coolshell.cn/articles/4162.html" target="_blank">面试题二</a>，<a title="“火柴棍式”程序员面试题" href="https://coolshell.cn/articles/3961.html" target="_blank">面试题三</a>），从回复中让我有一些思考。</li>
<li>我有一个同事最近面试了一家公司，他和我分享了一个博士专家对他的面试，也让我思考了一些。</li>
<li>在豆瓣上看到“<a title="知乎上某人写面试豆瓣产品经理的经历，很欢乐" href="http://www.douban.com/note/146145117/" target="_blank">知乎上某人写面试豆瓣产品经理的经历，很欢乐</a>”(亮点是面试官现身知乎亲自作答)</li>
</ul>
<p>所以，我很想把自己的这些新的想法再次写下来的。还是和以前一样，这篇文章同样是献给面试官的。我认为，面试的好坏完全在面试官而不是面试的人。下面是我对“<a title="我是怎么招聘程序员的" href="../articles/1870.html" target="_blank">我是怎么招聘程序员的</a>”一文中的一些加强性的观点。（关于一些点评，请参看<a href="https://coolshell.cn/articles/4490.html" target="_blank">本文下篇</a>）</p>
<p>为了让我的文章有连续性，请允许我重申一下前文的几个重要观点。</p>
<ul>
<li><strong>只有应聘者真实和自然的表现，才能了解到最真实的东西</strong></li>
<li><strong>重要的不是知识，重要的是其查找知识的能力</strong></li>
<li><strong>重要的不是那个解题的答案，而是解题的思路和方法</strong></li>
</ul>
<h4>操作，知识，经验，能力</h4>
<p>我们有很多的面试官似乎分不清，什么是操作能力，什么是知识，什么是经验，什么是能力，这导致了我们的面试官经常错误地对面试者下结论，我认为分不清这些事的人是没有资格做面试官的。所以，我有必要在这里把这个问题先讲清楚。</p>
<p><span id="more-4506"></span></p>
<p><img decoding="async" title="更多..." alt="" src="https://coolshell.cn/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif" /></p>
<ul>
<li><strong>操作</strong>。我们的面试官分不清楚什么是操作技能，什么是知识，他们甚至认为操作技能就是知识甚至经验。比如他们会 问如下的问题，请问Java中的 final是什么意思？怎么查看进程的CPU利用率？怎么编写一个管道程序？怎么查看进程的程序路径？VI中的拷贝粘贴命令是什么？包括面向对象的XX模 式是什么。等等。我以为，<strong>这些能够通过查况相关操作手册或是能够google到的东西只能说明这个人的操作技术，并不能说明他有知识或有经验</strong>。</li>
</ul>
<ul>
<li><strong>知识</strong>。知识是一个人认知和学习的体现，可能会是一些基础概念和知识。比如这些问题：TCP和UDP的优缺点比 较，链表和哈希表的优缺点的比较。什么是堆什么是栈？进程间是怎么通信的？进程和线程的优缺点？同步和异步的优缺点？面向对象的XX设计模式的主要原则是 什么，等等。我以为，<strong>“知其然”只是操作技术，“知其所以然”才是真正的知识</strong>。知识不够并不代表他不能工作，会操作技能就可以应付工作，但是知识的欠缺一定会限制你的经验和能力，同样会影响你的开发质量。</li>
</ul>
<ul>
<li><strong>经验</strong>。经验通常跟一个人的经历有关系。一个人的知识范围，一个人经历过的事，通常会成为一个人经验的体现。面 试中，我们会问这些问题：你解决过最难的问题是什么？你是怎么设计这个系统的？你是怎么调试和测试你的程序的？你是怎么做性能调优的？什么样的代码是好的 代码？等等。对于工作年限不长的人来说，经历和做过的事的确会成为其经验的主要因素，尤其是业务上的有行业背景的东西。但是，我更以为，<strong>经验可能更多的是你对知识的运用和驾驭，是你对做过事情的反思和总结，是你对他人的学习，观察和交流</strong>。</li>
</ul>
<ul>
<li><strong>能力</strong>。一个人的能力并不会因为知道东西少而不行，也不会因为没有经验而没有能力。<strong>一个人的能力是他做事情的一种态度，性格，想法，思路，行为，方法和风格</strong>。<strong>只要有热情，有想法，有好的行为方法，以及好的行事风格，那么知识和经验对他来说只是一个时间问题</strong>。 比如：学习能力，专研精神，分析能力，沟通能力，组织能力，问题调查能力，合作能力等等。所以，对于一个新手来说，也许他的知识和经验有限，但并不代表他 能力上有问题，但是对于一个老手来说，如果其存在知识和经验欠缺的问题，那么通常都是其能力的问题。你可能暂时怀才不遇，但我不相信你会长期怀才不遇。如 果是的话，那么你必然些问题其让你的能力发挥不出来。而此时，“没有经历过”只会是你“没有能力”的一个借口。</li>
</ul>
<p>我不否认这四样东西对于一个优秀的程序员来说都很重要。但是，通过上述的分析，我们可以知道，能力和经验和知识需要分开对待。当然，这些东西是相辅相成的，你的能力可以让你获得知识，你的知识可以让你更有经验，你的经验又会改变你的想法和思路，从而改善你的能力。<strong>在面试中，我们需要清楚的认识到，应聘者的操作技能，知识和经验只是其能力的必要条件，并不是充要条件，而我们更应该关注于应聘者的能力</strong>。</p>
<ul>
<li>如果面试只是考查这个人的操作技能的话，那么这个面试完全失败。这是一个没有资格的面试官。</li>
<li>如果面试只是在考查这个人的知识和经验的话，那么成功了一半。因为你了解了基础知和做过的事，但这并不代表你完全了解他的真正能力。</li>
<li>如果你能够在了解这个人的知识和经验的过程中重点关注其能力（态度、性格、想法，思路，行为，方法和风格），并能正确地评估这个人的能力，那么你的面试算是非常成功的。</li>
</ul>
<p>也许用这四个词来描述定套东西并不太合适，但我相信你明白我想表达的。另外，我想说的是，<strong>我们不是出个题来考倒应聘者，而是要找到应聘者的亮点和长处</strong>。</p>
<h4>不要肤浅地认识算法题和智力题</h4>
<p>很多公司都会在面试的时候给一些算法题或是一些智力题或是一些设计题，我相信算法题或是智力题是程序员们在面试过程中最反感的事了。很多人都很BS面试官问的算法题，因为他们认为面试官问的这些算法题或智力题在实际工作当中用不到。但我想在这里说，<strong>问难的算法智力题并没有错，错的很多面试官只是在肤浅甚至错误地理解着面试中的难题的目的</strong>。他们认为，能做出算法题和智力题的人就是聪明的人就是有能力的人，这种想法实在是相当的肤浅。</p>
<p>其实，能解难题并不意味着这个人就有能力就能在工作中解决问题，你可以想想，小学奥数题可能比这些题更难，但并不意味着那些奥数能手就有实际工作能力。你可 以想一想你们班考试得高分的同学并不一定就是聪明的人，也不一定就是有能力的人，相反，这样的人往往者是在应试教育下培养出来的书呆子。</p>
<p>所以，我认为解难题的过程更重要，你要主要是通过解题查看这个应聘者的思路，方法，运用到的知识，有没有一些经验，和你一起交互时和沟通得是否顺畅，等等，这些才是你重点要去观察的。当然，最终是要找到答案的。</p>
<p>我想，让面试者解决一个难题的真正思路是：</p>
<ul>
<li><strong>看看他对知识的应用和理解</strong>。比如，他是否会用一些基础的数据结构和算法来解决算法题？</li>
<li><strong>看看他的整个解题思路和想法</strong>。答案是次要的，他的想法和行为才是重要的。</li>
<li><strong>看看他是如何和你讨论交流的</strong>。把面试者当成你未来的同事，当成你的工作伙伴，一起解题，一起讨论，这样可以看看大家是否可以在一起工作。</li>
</ul>
<p>这些方面才是考查应聘者的能力（思路，方法、态度，性格等），并顺带着考查面试者的经验和知识。下面是一些面试的点：</p>
<ul>
<li>应聘者在解算法题时会不会分解或简化这个难题。这是分析能力。</li>
<li>应聘者在解算法题 时会不会使用一些基础知识，如数据结构和基础算法。这是知识。</li>
<li>应聘者在解题 时和你讨论的过程中你有没有感到应聘者的专研精神和良好的沟通。</li>
<li>应聘者在对待这个算法题的心态和态度。如，面试面是否有畏难情绪。</li>
<li>应聘者在解题时的思路和方法是否得当，是否是比较科学的方法？</li>
<li>等等。</li>
</ul>
<p><strong>在解难题 的过程中考查应聘者的能力才是最终目的，而不是为难应聘者，不然，你只是一个傲慢而无知的面试官</strong>。</p>
<h4>模拟实际中的挑战和能力</h4>
<p>作为面试官的你，你应该多想想你的工作，以及你的成长经历。这会对你的面试很有帮助。你在工作中解决问题的实际情况是什么？你写代码的实际情况是什么？你的成长经历是什么？你是怎么获得知识和能力的？你喜欢和什么样的人工作？<strong>相信你不难会发现你工作中的实际情况和面试的情况完全是两码事，那么，你怎么可以用这种与实际情况差别那么大的面试来评估一个人的能力呢</strong>？</p>
<p>所以，最为理想的面试是一起工作一段时间。当然，这个在招聘过程中，操作起来几乎不可能，因此，这就要求我们的面试官尽可能地把面试的过程模拟成平时工作的 过程。大家一些讨论来解决一个难题，和应聘者一起回顾一下他已经做过的事情，并在回础的过程中相互讨论相互学习。下面举一个例子。</p>
<p>我们知道，对于软件开发来说，开发软件不难，难是的下面是这些挑战：</p>
<ol>
<li>软件的维护成本远远大于软件的开发成本。</li>
<li>软件的质量变得越来越重要，所以，测试工作也变得越来越重要。</li>
<li>软件的需求总是在变的，软件的需求总是一点一点往上加的。</li>
<li>程序中大量的代码都是在处理一些错误的或是不正常的流程。</li>
</ol>
<p>所 以，当我们在考查应聘者的代码能力时候，我们为什么不能模拟这样的过程呢？比如，让应聘者实现一个atoi()的函数，实现起来应该很简单，然后 不断地往上加新的需求或新的案例，比如：处理符号，处理非数字的字母的情况，处理有空格的情况，处理十六进制，处理二进制，处理“逗号”，等等，我们要看 应聘者是怎么修改他的代码的，怎么写测试案例的，怎么重构的，随着要处理的东西越来越多，他的代码是否还是那么易读和清晰。如果只是考查编码能力，一个小时，就问这一个问题，足矣。真正的程序员每天都在和这样的事打交道的。</p>
<p>如果要考查应聘者的设计能力，同样可以如法泡制。不断地加新的功 能，新的需求。看看面试者的思路，想法，分 析的方法，和你的讨论是否流畅，说没说在 点上，思想清不清晰，会应用什么样的知识，他在设计这个系统时的经验是会是什么样的，面对不断的修改和越来越复杂的需求，他的设计是否还是那么好？</p>
<p>当然，因为时间比较短，所以，你不能出太复杂的问题，这需要你精心设计一些精制的有代表性的问题。</p>
<p>（末完，<a title="再谈“我是怎么招聘程序员的”（下）" href="https://coolshell.cn/articles/4490.html" target="_blank">请参看下篇</a>）</p>
<p style="text-align: right;"><a title="再谈“我是怎么招聘程序员的”（下）" href="https://coolshell.cn/articles/4490.html" target="_blank"><strong>再谈“我是怎么招聘程序员的”（下）&gt;&gt;&gt;</strong></a></p>
<p><span style="color: #ff0000;"><strong>（请勿用于商业用途，转载时请注明作者和出处）</strong></span><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Leetcode 编程训练" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_title">Leetcode 编程训练</a></li><li ><a href="https://coolshell.cn/articles/8138.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/08/250px-Sheldon_Cooper-150x150.jpg" alt="为什么我反对纯算法面试题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8138.html" class="wp_rp_title">为什么我反对纯算法面试题</a></li><li ><a href="https://coolshell.cn/articles/4976.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/5.jpg" alt="给程序员新手的一些建议" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4976.html" class="wp_rp_title">给程序员新手的一些建议</a></li><li ><a href="https://coolshell.cn/articles/4490.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/2.jpg" alt="再谈“我是怎么招聘程序员的”（下）" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4490.html" class="wp_rp_title">再谈“我是怎么招聘程序员的”（下）</a></li><li ><a href="https://coolshell.cn/articles/3345.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/12/googlequestion-150x150.jpg" alt="140个Google的面试题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3345.html" class="wp_rp_title">140个Google的面试题</a></li><li ><a href="https://coolshell.cn/articles/1870.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2009/12/job-interview-150x150.gif" alt="我是怎么招聘程序员的" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1870.html" class="wp_rp_title">我是怎么招聘程序员的</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/4506.html">再谈“我是怎么招聘程序员的”（上）</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/4506.html/feed</wfw:commentRss>
			<slash:comments>94</slash:comments>
		
		
			</item>
		<item>
		<title>再谈“我是怎么招聘程序员的”（下）</title>
		<link>https://coolshell.cn/articles/4490.html</link>
					<comments>https://coolshell.cn/articles/4490.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 20 Apr 2011 00:35:07 +0000</pubDate>
				<category><![CDATA[流程方法]]></category>
		<category><![CDATA[职场生涯]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[面试]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=4490</guid>

					<description><![CDATA[<p>&#60;&#60;&#60;再谈“我是怎么招聘程序员的”（上） 在上篇中，我们说到了一些认识人的方法（操作，知识，经验，能力），还有一些面试的方法（算法题，实际生产...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/4490.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/4490.html">再谈“我是怎么招聘程序员的”（下）</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><strong><a title="再谈“我是怎么招聘程序员的”（上）" href="https://coolshell.cn/articles/4506.html" target="_blank"><strong>&lt;&lt;&lt;再谈“我是怎么招聘程序员的”（上）</strong></a></strong></p>
<p>在上篇中，我们说到了一些认识人的方法（操作，知识，经验，能力），还有一些面试的方法（算法题，实际生产活动中的挑战），下面我们来说说，面试的风格，还有一些点评。<strong><strong><br />
</strong></strong></p>
<h4>把应聘者当成你的同事</h4>
<p>有些公司的面试官，在面试过程中问你一个算法题，然后等着你解答了，如果你给出一个答案，然后就会问你有没有更好的答案，如果你给出了正确的答案，他们就会问你一个更难的问题，如此循环下去。他们基本上很少给你提示，甚至不停地质问你，挑战你，搞得应聘者很紧张。</p>
<p>另外，有很多问题是没有标准答案的，或者说是，同一个答案的描述方法有多种，很多面试官会觉得你没有回答到他想要的答案，因此表现得有对你不屑，并表现出你不行的样子，并觉得你的能力有问题。真是可笑了。比如我一个朋友在回答什么是异步的问题时，举例说明了异步调用就是不能处理完就返回，并且需要传递一个回调函数给调用方以便完成后回调通知结果。这样的回答并没有错，但是这并不符合面试官心里想要的答案，面试官对此并不满意，进而认为我这个朋友还需要去多读读书。</p>
<p>我相信大多数面试官都会这样干的。我想问问这样的面试官，<strong>你们有没有用面试的方式对过你的同事？在你的工作场景中，你会不会用面试的风格和你的同事进行交流和说话？</strong>不妨让我们来问我们自己下面几个问题：</p>
<ul>
<li>你在工作当中遇到难题时你是怎么解决的？你会和人讨论吗？你只用15分钟就能得出最优解吗？</li>
<li>你在工作当中解决难题时是否会有一个人在旁边质问你并给你压力吗？</li>
<li>你在工作当中会为难你的同事吗？会让你的同事紧张吗？你觉得在紧张的状态下能做好工作吗？</li>
<li>你在工作中觉得同事的回答并不是你想要的答案，不是符合你的答案，你会认为你的同事不行吗？</li>
<li>你的成长过程是什么样的？在是压力和天天被人质问的情况下成长的吗？</li>
<li>大家都知道学校里应试教育的弊端，你觉得你的面试是不是一种应试呢？<br />
（看看这么多的应聘者们都在做各种各样的算法题，这不就是一种应试吗？）</li>
</ul>
<p>想一想你的日常工作，问自己一下上面这些问题，想一想你自己的成长过程，想一想你和你的同事是怎么相处的，想一想你的日常工作中是什么样的，相信你自己也能得出结论的。</p>
<p>如果你把应聘者当成自己未来的同事，那么你的面试会有下面的收获：</p>
<p><span id="more-4490"></span></p>
<ul>
<li>面试的气氛会很不错，应聘者会放松，表现自然，更接受于真实的状态。</li>
<li>面试中的交流和互动（而不是一问一答）会让你更全面的考查和了解一个人。</li>
<li>非应试的面试，会让你了解得更多。</li>
<li>真实的了解一个人，你才能做出真正正确的结论。</li>
</ul>
<h4>向应聘者学习</h4>
<p>下面有几个观点</p>
<ul>
<li>面试的过程是一个相互学习的过程，并不是你为难面试者的过程。</li>
<li>一问一答是很一种呆板死板的过程，相互讨论相互学习，有良好的互动才是好的面试过程。</li>
<li>面试官要证明的不是你有多强有多聪明，而是要挖掘应聘者的优势和能力。</li>
<li>面试官用为自己的问题预设好一个标准答案，看看应聘者能为你带来什么。</li>
<li>向来应聘的人学习，而不是刁难。</li>
</ul>
<p><strong>无论你多牛，要难倒你实在是太容易了。出难题不是目的，难倒人也很容易，出难题只不过是用来了解应聘者能力的一个手段，而不是面试的全部</strong>。</p>
<p>我不知道你喜欢不喜欢一些竞技类的运动？比如踢球，打篮球，羽毛球，下象棋等，你一般想和什么样的人玩？是差的，还是强的？所以，<strong>能够从面试者那里学到东西，喜欢和面试者一起工作，这才是面试真正的目的</strong>。</p>
<p>对于一个团队来说，如果大家都是一样的想法，一样的主张，一样的倾向，那么这个团队最终会是一个闭塞的团队，你如果不能真正接纳不同想法的人，不同主张的人，那么你也将失去进步的机会。<strong>如果你的团队总是在招入和你一样的人，那么你的团队怎么可能会有out-of-box的想法呢？世界因为不同而美好</strong>。</p>
<p>另外，对于公司来说，<strong>如果你招进来的人还不如已经有的人，作为一个公司，你又怎么能有更好的人让你的公司进步呢</strong>？</p>
<p>所以，面试应该是向面试者学习的一个过程。当然，<strong>如果你从他身上学不到什么，那么你就教他一些吧。这样，就算是面试不通过，面试者也会欣然接受的</strong>。不然，让面试者产生一些负面情绪，出去说一些不好的话，也有损你和公司的形象。</p>
<h4>一些相关的点评</h4>
<p>下面是我根据酷壳的一些<a href="https://coolshell.cn/tag/interview" target="_blank">面试题的文章</a>后的回复、还有我朋友的经历，还有这篇有关豆瓣的产品经理的<a title="知乎上某人写面试豆瓣产品经理的经历，很欢乐" href="http://www.douban.com/note/146145117/" target="_blank">这篇文章</a>的一些点评。大家可以看看我从这些地方看到东西靠不靠谱。</p>
<p><strong>酷壳的面试题中的答复</strong></p>
<p>先说酷壳的那篇“<a title="“火柴棍式”程序员面试题" href="https://coolshell.cn/articles/3961.html" target="_blank">火柴棍式的面试题</a>”，这个面试题其实很没什么意思。主要考查你对代码逻辑的了解程度。因为设置了回复可见答案，所以这篇文章的回复量达千把条。从回复中，我看到：</p>
<ul>
<li>一些朋友想不出来就直接看答案了。我可以看出，有一些朋友习惯获得知识，而不习惯独立思考。甚至有畏难情绪，从另一方面来说，可以看出我国的教育还真不是一般的差。</li>
<li>一些朋友想不全。从这点来看，我觉得很正常，尤其是想出两种来的，我可以感觉到他们的努力思考了，可能还做了一些尝试。挺不错的。可惜我看不到你思考的方式，是在纸上画了画，还是编译了个程序跑了跑，还是别的什么。这样我会了解你更多。</li>
<li>一些朋友给出的答案中有错的。这说明了这类朋友可能不喜欢做测试，时常想当然，或是做事比较冲动，并不足够严谨。这么简单的程序，验证能花多少精力呢？</li>
<li>还有少数的朋友没有看明白题目要求。这说明了这类朋友太粗心了，在工作当中可能会表现为误解需求和别人的话。沟通有问题。</li>
</ul>
<p>再说说那篇“<a title="面试题：火车运煤问题" href="https://coolshell.cn/articles/4429.html" target="_blank">火车运煤</a>”的问题，这个面试题我觉得主要是看看大家的解题思路，表达能力。</p>
<ul>
<li>首先，我很惊喜有人很快就用数学做了解答，很不错，这个人的数学功底很不错。能用数学解题的人一般来说都是算法比较强的人。</li>
<li>有人说抱怨我没有说火车可以调头回去，所以没有想到这样的方法。如果是在面试中我会做提示的。我不会因为你不知道调头这个潜规则而否定你的。当然，如果你能想到的话说明你的脑袋还是比较灵的。</li>
<li>还有很多人说他的方法比较土，只运了400吨煤，416吨的或333吨，一看就是没有看提示的，我觉得这些人能够通过独立思考找到方法，这类的人其实已经不错了。顺着这个思路优化也只是时间的问题了。</li>
<li>更可喜的是，我看到了有一些朋友在看到别人的更好的方法后和自己的方法进行了比较，并找到了为什么自己的方法不如他的原因。这样的人我认为是懂得“总结”和“比较”的，这样的人总是在不断地学习和改善自己的。</li>
<li>还有人说到了动态规划，如果是在面试的时候，我很想向这位朋友学习一下用动态规划来解这题。</li>
<li>还有朋友说到了火车调头只能在有站的地方。这个朋友一看要么就是搞需求分析的人，要么就是较真的人。需要进一步了解。但不管怎么样，这样的朋友的观察能力是很不错的。</li>
<li>还有一些朋友给出的答案是正确的。但是表达方面比较复杂，有些没有看懂。可见，解题 的能力是有的，只是表达能力还有待提高。</li>
</ul>
<p><strong>豆瓣产品经理的面试</strong></p>
<p>再说说豆瓣上的<a title="知乎上某人写面试豆瓣产品经理的经历，很欢乐" href="http://www.douban.com/note/146145117/" target="_blank">这篇文章</a>，那篇文章里，面试官问了一个比较大的问题，那是仁者见仁，智者见智的问题，并且面试官并不满意应聘者给出的答案，并在用其主观意识强加一些东西给应聘者，并不断地和应聘者纠缠。后来，面试官回复到“重点测了两个问题：一是判别事情的标准和方法；二是在多种PK下产品经理的压力反应”。</p>
<p>下面是我观察到的：</p>
<ul>
<li>其一、这种似事而非的仁者见仁，智者见仁，一万人有一万个答案。所以，这种怎么答都可以的问题是很难有标准的，我认为豆瓣的面试官以这种问题来考查面试者的标准太有问题了。更好的问题是：比较一下新浪和twitter这两个产品。</li>
<li>其二、多种想法PK的压力反应。这点没有问题，如果有机会我想问问这位面试官，豆瓣产品经理们的PK各自的想法时是以这种纠缠的方式吗？如果是这样的话，那我很为你们担忧啊。</li>
<li>其三、很明显，应聘者不知道面试官想说什么，所以应聘者总是给出一些模棱两可的回答。回答得很政客，呵呵。</li>
<li>其四、问的问题都是一些假设性的问题，假设技术人员不可沟通。人家说了，还没有见过不能沟通的情况。结果还要继续追问。这样你既要观察不到你想要的，也搞得大家不愉快。更好的问题的：“请你给一个你和一个很难沟通的人沟通的示例”，或是当应聘者说了“坚持己见”的时候，也应该追问“能给一个你坚持己见的例子吗？”。</li>
<li>其五、整个面试过程完全是在谈一些虚的东西，就像天上的浮云，一点实实在在的东西都没有。比如下面这两个实实在在的问题：“你以前设计过什么产品？”，“你和你的技术团队是怎么合作的？”</li>
</ul>
<p>这是一个完完全全失败的面试，这个面试官根本不懂面试，甚至工作方法也可能很有问题。也许他只是想找一个能够在工作中附和他的人。</p>
<p><strong>朋友的面试</strong></p>
<p>最后说说我那个朋友的面试，我的这个朋友学习能力很强，也很好专研，工作中解决了很多很困难甚至很底层的问题。他做软件开发时间并不长，但是他对这个行业很有热情，也很执着，并有着相当不错的技术功底。这天他遇到了一个面试官，根据朋友的描述，这位面试官，主要问题了三个问题，一个是关于异步的，一个是关于性能调优的，还有一个是关于学习能力的。</p>
<ul>
<li>问到异步的问题，我这个朋友说到了多线程中的异步调用，但是他可能问的是网络或是业务中的异步，要不然就是Linux 内核中的异步，当然他也没有说清楚，但他很不满意我朋友的答案，并让我朋友回去多看看书。</li>
<li>问到性能调优的问题时，我这个朋友说了性能调优分三级，业务级，指令级和CPU级，并举例说了使用了一个叫VTune的性能分析工具。面试官却说原来你只懂Windows，有点不屑，并说他只会使用商业工具，更不屑。</li>
<li>当我朋友向他澄清问题时，面试官只是摇头，叹气。并在应聘者作答的过程中不断的打断对方。</li>
</ul>
<p>我的看法如下：</p>
<ul>
<li>对于异步来说，我认为这是一种设计或是一种想法，可能会有很多种不同的实现方式，在不同的场景中会有不同的用法。面试官并没有考查应聘者对异步方法的理解，也没有考查异步方法可以用来解决什么，异步方法的优势和劣势，等等。只是觉得应聘者没有给出他想要的答案。</li>
<li>对于性调优的问题，我认为应聘者的思路和知识都很不错，还有使用VTune的经验。无论使用Windows还是Linux，无论使用商业的还是开源的Profiler，很多东西都是相通的，怎么能够因为这个东西不对自己的口味而下结论。为什么不向人家学习一下VTune呢？使用工具只是操作技能啊。</li>
<li>面试官应该是用微笑来鼓励应聘者的，而不是用摇头和叹气，频繁打断对方也是一个相当不好的习惯。看来这个面试官很不能接受不同的东西。</li>
</ul>
<p>这位有很不错的技术能力的人，看来并不适合做一个面试官，因为他面试的东西都只在知识层次，而且这位面试官有强烈的喜好和倾向，所以，他必然会错过那些有能力但并不合他口味的人。</p>
<p>哎，面对这样的面试官，大家伤不起啊！</p>
<p>（全文完）</p>
<p><span style="color: #ff0000;"><strong>（请勿用于商业用途，转载时请注明作者和出处）</strong></span><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Leetcode 编程训练" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12052.html" class="wp_rp_title">Leetcode 编程训练</a></li><li ><a href="https://coolshell.cn/articles/8138.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/08/250px-Sheldon_Cooper-150x150.jpg" alt="为什么我反对纯算法面试题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8138.html" class="wp_rp_title">为什么我反对纯算法面试题</a></li><li ><a href="https://coolshell.cn/articles/4976.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/5.jpg" alt="给程序员新手的一些建议" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4976.html" class="wp_rp_title">给程序员新手的一些建议</a></li><li ><a href="https://coolshell.cn/articles/4506.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/0.jpg" alt="再谈“我是怎么招聘程序员的”（上）" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4506.html" class="wp_rp_title">再谈“我是怎么招聘程序员的”（上）</a></li><li ><a href="https://coolshell.cn/articles/3345.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/12/googlequestion-150x150.jpg" alt="140个Google的面试题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3345.html" class="wp_rp_title">140个Google的面试题</a></li><li ><a href="https://coolshell.cn/articles/1870.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2009/12/job-interview-150x150.gif" alt="我是怎么招聘程序员的" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1870.html" class="wp_rp_title">我是怎么招聘程序员的</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/4490.html">再谈“我是怎么招聘程序员的”（下）</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/4490.html/feed</wfw:commentRss>
			<slash:comments>73</slash:comments>
		
		
			</item>
	</channel>
</rss>
