克努特优化原则(Knuth’s optimization principle):过早优化是万恶之源。
“过早优化是万恶之源”是软件开发届的一句名言。它来源于Donald Knuth的书《计算机编程艺术》(最早由Tony Hoare提出),以下是引用:

这句关于过早优化的原话来自于20世纪60年代出版的书。那是一个不同的时代,那时大型机和穿孔卡很常见,CPU处理周期很稀缺。所以程序优化得不好,可能会运行很长时间。
过早优化在今天该怎么理解?
今天,大多数开发团队都习惯于不断地量产代码并快速迭代,采用敏捷开发方法。如果软件中存在错误,可以很容易地将修复程序部署到Web服务器上。
现代研发过程中仍然存在过早优化的情绪。过早优化是开发人员应该一直考虑的事情,是在日常工作中应该尽量避免的事情。 防止过早优化在大型机时代适用,今天仍然适用。
一个典型的例子是一家创业公司花费大量时间试图找出如何扩展其软件以满足数百万用户。 这是一个非常值得考虑的问题,但不一定要付诸行动。 在担心处理数百万用户之前,你需要先确保100个用户喜欢并且想要使用你的产品。需要首先验证用户反馈。
因此业务模式在反复试错或高速迭代阶段,过多的优化,显得很不划算。身处业务线,经常感到被需求压得喘不过气,其实是因为产品经理会更多的关注用户需求,关注业绩提升。
随着计算机系统性能从MHz,数百MHz到GHz的增加,计算机软件的性能已经不是最重要的问题(落后于其他问题)。今天,有些软件工程师将这个格言扩展到“你永远不应该优化你的代码!”,他们发现,有时候代码怎么写似乎问题都不大。
然而,在许多现代应用程序中发现的臃肿和反应迟钝的问题,迫使软件工程师重新考虑如何将Hoare的话应用于他们的项目。
查尔斯库克(http://www.cookcomputing.com/blog/archives/000084.html)的一篇简短的文章,其中一部分我在下面转载,描述了在Hoare的陈述中的问题:
我一直认为这句话经常导致软件设计师犯严重错误,因为它已经被应用到了不同的问题领域。这句话的完整版是“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.”
我同意这一点。在性能瓶颈明显之前,通常不值得花费大量时间对代码进行细枝末节的优化。但是,在设计软件时,应该从一开始就考虑性能问题。一个好的软件开发人员会自动做到这一点,他们大概知道性能问题会在哪里出现。没有经验的开发人员不会关注这个点,错误地认为在后期进行一些微调可以解决任何性能问题。
Hoare和Knuth真正说的是,软件工程师在担心微观优化(比如一个特定语句消耗多少CPU周期)之前,应该先担心其他问题(比如好的架构设计和这些架构的良好实现)。即微观优化的优先级是很低的,至少低于宏观优化(架构设计)、业务需求分析等。
过早优化的原因
1、过早优化出现在一些相对容易解决的问题上。 例如,有人对应用程序有所了解,但不确定如何开发它,那么他可能花费大量时间考虑他可以处理的不重要的事情,例如徽标设计是否会使系统看起来变得高大上。我以前在国企貌似经常发生这样的事。也许这是因为没有一个能总览全局的架构设计师,导致不太懂技术的领导或者客户钻牛角尖。
2、过早优化是一种“美好的愿景”。 例如,想要开始新的爱好的人,如打羽毛球,可能会花费数小时挑选高级装备并在他们开始训练之前规划未来的行动方案,因为这样做很有趣,而且比实际开始训练更简单!在球馆时不时就能看到,除了球技其它都很专业的“爱好者”。
3、过早优化是由于未能正确对任务进行优先级排序。 例如,正在开发软件的人可能过早地优化事情,不是因为要解决(架构、性能)问题,而是因为他们根本不知道如何制定各个研发阶段的计划,识别出各个阶段应该做的工作。这也很有可能因为团队里没有一个能总览全局的架构设计师。
该怎么做?
前几天QCon的围炉夜话,听毕玄说,“09年之前,阿里的技术团队都处于陪(业务)跑状态”。公司在不同阶段,技术团队的重心会不同。初创阶段更多重视业务,业务稳定(垄断)阶段更重视技术本身。 有经验的管理者会通过职位设置,研发力量投入比例来调节业务与“优化”之间的关系。从组织的角度,是希望大多数同学做好本职工作就能很好的平衡业务与“优化”之间的关系。例如在公司发展的某个阶段,出现了架构师这个角色。
作为研发工作的具体参与者和执行者该怎么做呢?从本质上讲,在确定是否应该优化某些内容时,应该考虑以下几个因素,应该问自己的几个重要问题:
1、为什么要优化?你认为在这个阶段,这种优化是必要的,这意味着它将对你的工作产生显著的、积极的影响,还是你现在仅仅关注它,因为你试图避免处理其他事情?
2、优化的好处是什么?从优化中你能得到什么?
3、优化的成本是多少?为了进行这种优化,你需要花费什么资源?
4、优化可能带来的负面后果是什么?这种优化在将来会给你带来什么样的问题?
5、这种优化有多大可能会过时?你现在正在做的优化工作以后是否有重大意义,或者这种优化是否可能过时?请注意,仅仅因为某些东西稍后可能会过时并不意味着你现在不应该处理它,但是这种情况发生的可能性,它发生之前需要的时间以及你在此期间将获得的好处,都是你决定是否优化应考虑的因素。
6、推迟这种优化有哪些优点和缺点?推迟这个特定的优化有什么坏处吗?或许以后你会获得更多的相关信息,你会更好地处理它?
7、你还能做什么?如果你不把时间和资源花在优化上,你会把它们花在什么上?如果你有其他的事情可以做,你是否从中获益更多?
基于这些标准,可以对必须完成的不同任务进行优先级排序,并找出在哪个阶段应该处理哪些任务,以确保避免过早地进行优化。
但是,每次评估潜在任务时,不必问自己所有这些问题。小任务尤其如此,与使用所有这些标准进行评估相比,简单地完成一个2分钟的小任务可能花费更少的时间和精力。
要意识到这些考虑因素,在必要时至少在某种程度上使用它们来评估任务。任务看起来越大,需要的资源越多,或它将产生的影响越大,你应该越谨慎,应该越多地使用这些标准来评估它。
并非所有优化都为时过早
避免过早优化并不意味着你应该完全避免优化。相反,它只是意味着在决定投入资源优化某些东西之前,应该仔细考虑。
人们经常重复“过早优化是万恶之源”的观点,而没有注意到完整的引用,其中说“我们应该忘记细枝末节的优化。在97%时间,过早的优化是所有邪恶的根源。然而,我们不应该在那个关键的3%中放弃我们的机会”。
这意味着评估情况并决定优化某些东西是完全合理的,即使它处于相对较早的阶段。例如你认为小的修改可以带来显着的好处,或者优化可以解决你工作中遇到的瓶颈,或者不优化可能会导致显着的技术债务。
在关于该主题的原始引用中,说这个概念适用于大约3%的情况,但是有效优化的临界值可能高于或低于这个值。例如,一个具有共识原则是Pareto原理(二八规则),在这种情况下,表明80%的积极成果将来自你20%的工作(多做点优化工作也没问题)。
总的来说,为了避免过早优化,应该首先评估情况,并确定在那个时间点是否需要预期的优化。但是,这种方法不应成为完全避免优化的借口,而应该作为尽可能有效地确定任务优先级的方法。
总结
过早优化是试图为时尚早的阶段提高效率的行为,例如,尽管有更重要的任务需要你去处理,你却在业务的一些琐碎的方面开展工作。
过早优化是有问题的,因为它会导致你浪费资源,气馁,在你没有足够的信息时采取行动,或者陷入次优的行动过程中。
人们过早地优化事物的最常见原因是没有正确地确定任务优先级,或者过早优化对于他们来说相对容易处理,这个优化即使不必要也能接受。
为了避免过早地优化事情,在开始之前,你应该确保问问自己为什么要优化,这样做的成本和好处是什么,这种优化可能带来的负面后果是什么,等待的优点和缺点是什么,以及你还可以做些什么。
记住,这并不意味着你应该完全避免优化,而是应该仔细考虑并评估情况,然后再决定进行某种优化。
边际效应递减,应该把资源用在能使效益最大化的地方。
参考
https://cloud.tencent.com/developer/article/1525574
当时内部的过度设计有两个结果:一些设计根本不可能用上,另一些等到用上的时候,发现当初设计的时候考虑不全,还不能用,正所谓半吊子。
很赞同不要过度设计,能满足现在的需求并且做好应对未来变化的准备就够了。刚开始学习编程的时候也是力求设计完美后再开工,后来发现非常痛苦,过于复杂的设计带来了高额的成本,实际上却很难用到。最近看一本介绍Ruby语言OOP的书,提到一个概念:“不要预测未来”,深以为然。
奥卡姆剃刀原则:如无必要,切勿添加。
原文并非谈需求,就是纯粹谈程序性能优化。
Donald Knuth 1974 年在 ACM Journal 上发表的文章 “Structured Programming with go to Statements” 中写道:
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
简言之,没有量化的性能测试检测到真正的性能问题之前,在代码层面各种炫技式优化,不仅可能提升不了性能,反而更会导致更多 bugs。
这条程序开发经验被奉为经典,一方面因为提出之人,另外,确实是“伟大的人生经验”。可以有多方面多层面的解读:
需求版本:先骗到合同,再扩容优化。
敏捷版本:先可用,再迭代。
雷军版本:战术上的勤奋掩盖不了战略上的懒惰。
禅师版本:空杯子里面应该先放大石头,这样能装的更多。
山寨版本:先抄袭,后修改。
创业版本:先上线,后优化。
婚姻版本:先结婚,后恋爱。
总之,他们强调先可用、可行、可赚,然后在了解到真正的问题之后,再做调整和优化。
总之,这是典型的贪心算法,尽管并不一定保证最终最优,但能让你浪费最少。
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
字面意思是97%优化是不值得也不应该做的,“过早”的那类优化是指这97%,关键点的优化,也就是剩下的3%仍是绝对必要的,虽然作者并没有直接说“这3%应该尽早做”,但某种程度上“we should not pass up our oppurtunities”大概已经包含了这层意思。作者并不反对优化,而且强调作关键优化的必要性。直白地说,他的意思是:不要浪费时间做那些根本不重要的优化。
很多时候,代码架构的很大部分就是关于如何优化,但把这个部分做对是很有必要的,这是那3%里的情况,并不“过早”,因为系统性能和伸缩性其实主要靠好的架构设计,而不是局部优化。
因为需求会变。
很多时候可能你都不知道需求是什么,原型已经开始架构了。
用户可能也不知道他们的真实需求,很多时候当他们看到原型时,才逐步明确需求。常规领域中,90%以上的优化都产生不了用户可感知的价值,所以不要在早期浪费时间,事后进行剖析和优化就是了。
Make it Work.
Make it Right.
Make it Fast.
不要跳过前面两个直奔第三个!
先第一个版本尽快上线抢占市场再说,大多数没赚到钱的项目都活不过几个月,赚到钱了才有闲情在第2、第3个版本慢慢优化,有钱了还可以请技术大牛来优化。
英文”premature optimization”,我觉得“过早”翻译得不确切,premature实际上不是指一个时间概念,而是指没有充分证据的、未经论证的、盲目的优化。应该叫“盲目优化是万恶之源”。用中国老话就是要“不见兔子不撒鹰”。
什么叫“过早”?这个没说清楚。
我看不同的人有不同定义,这里我说两个最重要的:
1. 优化,一定要有证据,这是最重要的。最明显的证据就是跑分,要想跑分就得先通过测试,否则错误的程序谈跑分没有任何意义。要想通过测试,程序就必须能够正确运行,要想正确运行,程序就必须起码写完能运行。换句话说,“没有足够证据支撑的优化是万恶之源”。 2. 第二个,任何性能上的优化都会损失可读性和可维护性,这是必然的。过早优化就可能需求还没稳定。如果需求大改的话,优化也就废了。如果需求小改,那么优化前的代码肯定比优化后的代码容易改。这应该也是一个因素。
总之应该就是想迭代思维那样,“允许不足,增量弥补”,而不是一锤子买卖,那项目的抗风险能力就很低了。
像生命一样会进化的系统才是最适应环境的系统!不会随着环境的变化而进化的物种都被淘汰了。
1个程序跑1分钟,要不要优化?刚毕业的学生会说:太慢了,要优化。
但如果加上一个条件,这个程序只占据整个流程的1%,其余流程要跑3天,你还会不会优化它?
不同场景,不同需求,不同系统,要具体分析,抓大放小。
就像我小时候穿的衣服,我妈总给我买大一号的,可我的生长速度没那么快,每次都是穿烂了都还大。现在轮到我女儿了,姥姥奶奶再给买衣服,我都是让她们直接买正好的就行。
「过早的优化是万恶之源」这句话是我非常喜欢的一句话。虽然是起源于软件开发领域的一句话,但我发现在工作和生活中,在时间管理中,在恋爱中,都有过早优化的问题,牢记这句话可以解决很多问题,甚至是根本性的问题。简单地说,就是计划赶不上变化。
参考
https://www.zhihu.com/question/24282796
怎么理解“premature optimization is the root of all evil”?
个人经验是在web开发中,如果早期不考虑数据库结构,各种数据接口的话,后期的扩展和优化会很难做,这句话是不是放之四海而皆准呢?如果不是这段Donald Knuth的名言该如何理解?
