过早优化是万恶之源——克努特优化原则 (Knuth’s optimization principle)

渐进式迭代优化,先把代码写出来,定位瓶颈所在,然后优化它。

我之前的工作更多集中在架构设计及性能调优方面,会更多的鼓励研发人员追求极致。最近在业务线开展工作,在这个问题上有了一些新的体会。

软件开发中最难的是搞清楚到底该做什么。

研发人员都喜欢编写代码和构建应用,成本高且供不应求。 确保研发人员充分利用时间是最大的挑战。 我们最不希望发生的是发布用户不喜欢或不起作用的代码。 那应该花多少时间专注于性能调优和优化呢?

如果不进行任何性能调整或优化,新产品发布可能是一场彻底的灾难。 想一想有段时间全国人民是怎么骂12306的。

我们也不想浪费大量时间在无关紧要的事情上进行性能优化。 快速迭代业务需求显然更加重要。

然而实际工作中,很多最初设计不好的系统很多时候根本没法优化。架构不合理,性能上不去。重构?基本就是完全重写!

一、什么是过早优化

过早优化是试图在为时尚早的阶段提高效率的行为。过早的优化尝试通常会导致适得其反,并导致浪费大量资源,如时间、金钱和精力,同时也增加了未来出问题的可能性。

过早优化的概念在软件工程领域占据突出地位。 “过早优化是万恶之源”是软件开发人员的一句名言。 它来源于Donald Knuth的书《计算机编程艺术》(最早由Tony Hoare提出),以下是引用:

“The real problem is that programmers have spent far too much time
worrying about efficiency in the wrong places and at the wrong times;
premature optimization is the root of all evil (or at least most of it) in
programming.”

真正的问题是程序员花了太多时间
在错误的地方和错误的时间担心效率;
过早的优化是万恶之源(或至少大部分)
编程。

这句关于过早优化的原话来自于20世纪60年代出版的书。那是一个不同的时代,那时大型机和穿孔卡很常见,CPU处理周期很稀缺。所以程序优化得不好,可能会运行很长时间。

过早优化在今天该怎么理解

今天,大多数开发团队都习惯于不断地量产代码并快速迭代,采用敏捷开发方法。如果软件中存在错误,可以很容易地将修复程序部署到Web服务器上。

现代研发过程中仍然存在过早优化的情绪。过早优化是开发人员应该一直考虑的事情,是在日常工作中应该尽量避免的事情。 防止过早优化在大型机时代适用,今天仍然适用。

一个典型的例子是一家创业公司花费大量时间试图找出如何扩展其软件以满足数百万用户。 这是一个非常值得考虑的问题,但不一定要付诸行动。 在担心处理数百万用户之前,你需要确保100个用户喜欢并且想要使用你的产品。 需要首先验证用户反馈。

因此业务模式在反复试错或高速迭代阶段,过多的优化,显得很不划算。身处业务线,经常感到被需求压得喘不过气,其实是因为产品同学会更多的关注用户需求,关注业绩提升。

瓜子作为一个有一定规模的公司,即使新开辟的业务,也会有一定规模的用户基础。Knuth’s的这句话(过早优化是万恶之源),显然不能简单的理解为完全不管性能,先开发业务,再推倒重构。

很多人理解错了

随着计算机系统性能从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%的工作(多做点优化工作也没问题)。

总的来说,为了避免过早优化,应该首先评估情况,并确定在那个时间点是否需要预期的优化。但是,这种方法不应成为完全避免优化的借口,而应该作为尽可能有效地确定任务优先级的方法。

五、总结

过早优化是试图为时尚早的阶段提高效率的行为,例如,尽管有更重要的任务需要你去处理,你却在业务的一些琐碎的方面开展工作。

过早优化是有问题的,因为它会导致你浪费资源,气馁,在你没有足够的信息时采取行动,或者陷入次优的行动过程中。

人们过早地优化事物的最常见原因是没有正确地确定任务优先级,或者过早优化对于他们来说相对容易处理,这个优化即使不必要也能接受。

为了避免过早地优化事情,在开始之前,你应该确保问问自己为什么要优化,这样做的成本和好处是什么,这种优化可能带来的负面后果是什么,等待的优点和缺点是什么,以及你还可以做些什么。

记住,这并不意味着你应该完全避免优化,而是应该仔细考虑并评估情况,然后再决定进行某种优化。

参考

过早优化是万恶之源——克努特优化原则 (Knuth’s optimization principle)