杂谈··By/蜜汁炒酸奶

如何避免过早优化的魔咒

前言

本来处于7月份的,无奈中间出去玩了几天,现在才发。老规矩,原文如下:

How to Avoid the Curse of Premature Optimization

文章正文

这真的几乎是值得的。 从新手到专家,从架构到ASM, 从机器性能到开发人员的性能优化, 您和您的团队都在缩短你们自己的目标是非常好的。 什么?我?我的团队? 这是一个非常大的指责。让我解释下。 优化并不是圣杯,但它也同样难以获得。 我想与大家分享一些简单的提示(和一些陷阱), 帮助您将团队的阅历从自我破坏转变为和谐,实现,平衡,最终优化。

什么是过早优化?

过早优化是正在如下情况下尝试优化性能: [callout class=“info” title=“”]

  • 当第一次编码算法时
  • 在你需要确认基准之前
  • 分析在哪里进行优化是有意义的之前
  • 处于比您的项目当前要求的水平较低时

[/callout] 现在我是一名优化师, Optimus. 至少在写这篇文章时,我会假装是一个optimist。 对你来说,你可以假装名字是 Optimus,如此这将更直接地说给你。 作为技术人员,你可能有时会想,这一年可能会是怎样的一年,然而,尽管我们在不断进步,但在某种程度上来说,这是一种可以接受的标准,让人感到非常费时。你想要瘦身。高效的。极好的。有些人喜欢那些工作岗位要求的摇滚明星程序员( Rockstar Programmers),同时有领导能力。 所以当你的团队编写代码时,你鼓励他们第一次做到这一点(即使“正确”是一个高度相对的术语,在这里)。他们知道这是聪明的编程者的方式,也是那些不需要浪费时间重建的方式。 我觉得,完美主义的强迫症有时在我心中也很强大。 你希望你的团队现在多花费一点时间,从而节省很多以后的时间。因为每个人都对分给的“其他人所写的糟糕代码(他们到底在想什么?)”步履维艰,这个简写是SCOPWWHWTT,因为我知道你喜欢叫不上名字的缩写。 我也知道,你不希望你的团队代码对他们自己或其他人来说是这样的。 所以,让我们看看能做些什么来引导你的团队走向正确的方向。

如何优化:欢迎来到这门艺术

首先,当我们想到程序优化时,我们通常会立即假定我们在谈论性能。即使已经比它似乎更加模糊(速度?内存使用?等),所以让我们停在那里。 让我们更加模糊!刚开始。 我的大脑喜欢在可能的情况下创造秩序,所以我需要每一盎司的最优主义去思考我想说的是一件好事。 有一个简单的(性能)优化的规则是不要这样做。这听起来很容易遵循,但并不是每个人都同意这一点。我也不完全同意这一点。有些人会比其他人写出更好的代码。期望中,对于任何一个人来说,他们在一个全新的项目中编写的代码质量会随着时间的推移而不断提高。但是我知道,对于许多程序员而言,情况并非如此,因为他们知道的越多,他们将越来越多的尝试过早地优化。

对于许多程序员来说,他们知道的越多,他们将越来越多的尝试过早地优化。

因此,这并不是一门精确的科学,但它只是为了抵消典型的技术人员内心的渴望来解决这个难题。毕竟,这首先是吸引许多程序员的手段。我明白这个。但要求他们保存,以抵制诱惑。如果现在需要一个问题解决的渠道,人们总是可以在星期日的“数独”(Sudoku)中玩耍,或者拿起一本Mensa书,或者用一些人为的问题去 code golfing 。但是请把它放回repo,直到适当的时候。这几乎总是比预优化更聪明的路径。 记住,这种做法已经足够臭名昭著了,人们会问,是否过早的优化是所有邪恶的根源(我不会走那么远,但我同意这种看法。) 我并不是说我们应该在设计的每一个层面上都能想出最愚蠢的方法。当然不是。但是与其挑选最聪明的人,我们可以考虑其他的价值观: [callout class=“info” title=“”]

  • 最简单的解释给你的新员工
  • 最有可能通过最经验丰富的开发人员通过代码审查
  • 最可维护的
  • 最快写的
  • 最容易测试
  • 最便携
  • 等等

[/callout] 但问题的症结就在于此。这不仅仅是为了避免对速度、代码大小、内存占用、灵活性或未来的未来进行优化。它是关于平衡的,关于你所做的事情是否符合你的价值观和目标。它完全是上下文相关的,有时甚至不可能客观地衡量。

这是一门艺术 。(C.f. The Art of Computer Programming.)

为什么这是一件好事?因为生活就是这样的。它是混乱的。我们的面向编程的大脑有时想在混乱中创造秩序,以至于我们最终以讽刺的结果来成倍地增加混乱。这就像试图强迫别人爱你一样的矛盾。如果你认为你已经成功了,那就不再是爱了;与此同时,你又被绑架了,你可能需要比以往更多的爱,这个比喻是我所能选择的最尴尬的。 无论如何,如果你认为你已经找到了一个完美的系统,那么在它持续的时候好好享受它吧,我想。没关系,失败是学习的好机会。 如何避免过早优化的魔咒

牢记UX

让我们来探索一下用户体验是如何在这些潜在的优先级中进行的。毕竟,在某种程度上,即使是想要表现良好的东西,也会是关于UX。 如果您在UI上工作,无论代码使用什么框架或语言,都会有一定数量的样板和重复。从编程人员的时间和代码的清晰度来看,这无疑是很有价值的。为了帮助平衡优先级的艺术,我想和大家分享一些故事。 在一份工作中,我工作的那家公司使用的是一个基于固执己见的技术堆栈的封闭源代码企业系统。事实上,它是如此的固执,将它卖给我们的供应商拒绝进行UI定制,这与栈的观点不相符,因为对他们的开发人员来说,这是非常痛苦的。我从未使用过他们的堆栈,所以我不谴责他们,但事实是这“有利于程序员,不利于用户”的权衡在某些情况下对于我的同事是麻烦的。最终,我编写了一个第三方插件重新实现这个系统用户界面的一部分。(这是一个巨大的生产力促进剂。我的同事喜欢它!十多年后,它仍然为每个人节约时间和时间) 我并不是说,独断主义本身就是一个问题;在我们的案例中,太多的问题成了一个问题。作为一个反例,Ruby on Rails的一大吸引力在于它是固执的,在前端的生态系统中,由于有太多的选择,很容易让人头晕目眩。(给我一些意见,直到我能找出自己的!) 相比之下,你可能会想要在你的项目中使你的每一件事的UX 圆满。这是一个有价值的目标,但让我来讲述我的第二个故事。 在上述项目成功的几年后,我的一位同事来到我这里,要求我通过自动化一个有时出现的混乱的现实场景来优化UX,这样就可以用一次点击就可以解决这个问题了。我开始分析,是否有可能设计出一种算法,它不会有任何错误的正面或负面的结果,因为这个场景的许多和奇怪的边界情况。我和我的同事谈得越多,我就越意识到这些要求根本不可能得到回报。这个场景只会在一个月的时间里出现一次,让我们说,目前只花了一个人几分钟就可以解决了。即使我们能够成功地实现自动化,也没有任何bug,但是需要花费几个世纪的时间来完成需要的开发和维护时间,以节省我的同事所节省的时间。在我看来,取悦别人的人很难拒绝,但我不得不缩短谈话的时间。 所以让电脑尽可能的帮助用户,但只是在一个合理的范围内。你怎么知道这个程度呢?如何避免过早优化的魔咒 我喜欢采用的一种方法是将UX与开发人员的配置文件代码进行比较。从用户那里找出花费最多时间点击或重复输入相同的东西,看看是否可以优化这些交互。您的代码可以对其最有可能输入的内容进行一些有根据的猜测,并将其作为默认值吗?除了某些禁止的上下文(不点击EULA确认?),这对用户的工作效率和幸福感都有很大的影响。如果可以的话做一些可用性测试。有时,你很难解释计算机做这些易于或不易于帮助什么,…但总体来说,这个值可能对您的用户非常重要。

避免过早优化:何时和如何优化

我们对其他情况的探讨,现在我们明确地假设我们正在优化本文其余部分的原始机器性能的某些方面。我的建议方法也适用于其他目标,如灵活性,但每个目标都将有自己的困境; 主要的一点是,任何事情的过早优化可能会失败。 那么,在性能方面,实际上有哪些优化方法呢?我们开始干起来。

这不是基层倡议,是Triple-Eh

TL;DR意思是:从顶部工作。在项目中可以提前进行更高层次的优化,较低层次的优化应该留在后面。这就是所有你需要知道的“过早优化”一词的大部分含义;脱离这种顺序做事有很大的可能性浪费你的团队的时间和起到反效果。毕竟,从一开始就不把整个项目写在机器代码中,对吗?我们的AAA做法是按照这个顺序进行优化: [callout class=“info” title=“”]

  • 架构(Architecture)
  • 算法(Algorithms)
  • 装配(Assembly)

[/callout] 普遍的智慧是,算法和数据结构通常是最有效的优化场所,至少在性能方面。但是,请记住,架构有时会决定哪些算法和数据结构可以被使用。 我曾经发现一个软件做财务报告,通过多次查询SQL数据库进行每个金融交易,然后在客户端进行一个非常基本的计算。使用该软件的小企业只使用了几个月,即使他们相对较少的财务数据,使用全新的桌面和相当强大的服务器,报告生成时间已经达数分钟了,这是他们需要相当频繁地使用一个功能。我最后写了一个简单的SQL语句,其中包含了总结逻辑,通过将工作移动到服务器来避免所有重复和网络往返(甚至几年的数据),我的版本可以在相同的旧硬件上以毫秒为间隔生成相同的报告。 有时,您对项目的架构没有影响,因为在项目中,对于架构变更的可行性来说已经太晚了。有时,你的开发人员可以绕过它,就像我在上面的例子中所做的那样。但是如果您在项目的开始,并且在它的体系结构中有一些发言权,那么现在是优化它的时候了。

架构如何避免过早优化的魔咒

在一个项目中,架构是事后改变的最昂贵的部分,所以这是一开始就可以进行优化的地方。例如,如果你的应用程序是通过ostriches传递数据,您想要将其构造为低频率、高负载的数据包,以避免使一个糟糕的瓶颈变得更糟。在这种情况下,您最好有一个完整的俄罗斯方块的实现来招待您的用户,因为加载微调器不会削减它。(开玩笑的:几年前,我正在安装我的第一个Linux发行版本,Corel Linux 2.0,并且很高兴这个长期运行的安装过程包括了这一点。看到Windows 95安装程序的广告宣传片,我已经记住了很多次,这是当时的一股清新的空气。) 作为昂贵的架构更改的一个例子,前面提到的SQL报告的高度不可伸缩的原因在其历史上是很清楚的。该应用程序随着时间的推移而发展,从MS-DOS和本土化的自定义数据库的根源,甚至原本不是多用户的开始。当供应商最终切换到SQL时,模式和报告代码似乎已经被移植了一个。这让他们在他们的更新中留下了令人印象深刻的1,000%+性能改进,只要他们通过实际使用SQL的优势来完成架构转换。与我当时的雇主一样,我也很喜欢与客户打交道,很明显,在最初的转换过程中,我很想优先考虑编码效率。但在某些情况下,满足客户的需要,就像改锥转动螺丝一样有效。 架构在一定程度上是为了预测您的项目将需要多大程度的规模,以及以何种方式进行架构。由于架构是如此的高水平,所以我们很难在不把我们的注意力集中到特定的技术和领域的情况下将我们的“要和不要”弄清楚。

我不会这么说,但其他人都这么做

值得庆幸的是,互联网上到处都是收集到的关于各种建筑的智慧。当你知道是时候优化你的架构时,研究陷阱基本上可以归结为描述你的辉煌愿景的术语。很可能有人和你一样思考,尝试过,失败了,重复了,并在博客或书中发表了。 通过搜索来完成流行词识别可能是棘手的,因为对于您所称的FLDSMDFR,其他人已经创造了SCOPWWHWTT这个术语,他们描述了你正在解决的同样的问题,但是使用完全不同的词汇。开发人员社区来拯救!用尽可能详尽的描述来访问StackExchange或HashNode,再加上您的构架中不是所有的流行语,因此他们知道您做了充分的初步研究。有人会很乐意启发你。 与此同时,一些一般的建议可能是思考的好食物。

算法和装配

鉴于一个有利的架构,您的团队中的编码人员将会在那里获得最多T-bling的时间。早期优化的基本避免也适用于此,但您的程序员会很好地考虑这一级的一些细节。关于实现细节,我写了一篇专门针对一线和高级程序员的关于代码优化的文章。 但是,一旦您和您的团队实现了一些性能上的不优化,您是否真的将它放在了不再做的日程上呢?你从来没有优化? 你是对的。对于专家来说,下一个规则是,不要做。

时间基准!

您的代码工作。也许它是如此的慢,以至于您已经知道您需要优化,因为它的代码将经常运行。也许你不确定,或者你有一个O(n)算法,并认为它可能很好。无论如何,如果这个算法可能是值得优化的,那么我的建议是相同的:运行一个简单的基准测试。 为什么?不清楚我的O(n³)算法不可能比别的更糟糕吗?那么,有两个原因:

  1. 您可以将测试套件添加到测试套件中,作为您的绩效目标的客观衡量标准,无论它们是否得到满足。
  2. 即使是专家也可能无意中使事情变慢。即使看起来很明显。真的很明显。

不相信我的第二点?

如何从1400美元的硬件中获得更好的效果,而不是7000美元的硬件

StackOverflow的杰夫·阿特伍德(Jeff Atwood)曾经指出,有时候(通常在他看来),购买更好的硬件比花费宝贵的程序员时间优化更具成本效益。好的,所以假设你已经达到了一个合理客观的结论,你的项目将适合这种情况。我们进一步假设您要优化的是编译时间,因为它是您正在开展的大量Swift项目,这已成为一个相当大的开发人员瓶颈。硬件购物时间! 你买什么?很明显,更昂贵的硬件往往比价格更便宜的硬件表现更好。很显然,一个7,000美元的Mac Pro应该比一些中档Mac Mini更快地编译你的软件,对吧? 错误! 事实证明有时更多的内核意味着更有效的编译…在这种特殊情况下,LinkedIn发现了他们的堆栈的相反的方式。 但我看到管理层犯了一个错误:他们在前后都没有做过基准测试,发现硬件升级并没有让他们的软件感觉更快。但是没有办法确切地知道;而且他们仍然不知道瓶颈在哪里,所以他们对性能仍然不满意,耗尽了他们愿意分配给这个问题的时间和金钱。

好的,我已经有了基准。我可以进行优化吗

是的,假设你已经决定了你需要。但是,也许这个决定会等到所有的其他算法都实现了,所以你可以看到这些移动的部件是如何组合在一起的,而这在性能分析中是最重要的。这可能是一个小应用程序的应用级别,也可能只适用于一个子系统。不管怎样,记住,一种特定的算法对于整个应用程序来说似乎很重要,但即使是专家,尤其是专家,也很容易误诊

在你破坏(Disrupt)之前想一想

“我不知道你的人,但…” 如何避免过早优化的魔咒 作为思考的最后一部分,考虑如何将错误优化的想法应用到更广泛的观点:你的项目或公司本身,甚至是经济的一个部门。 我知道,人们很容易认为科技会拯救我们的生活,我们也可以成为英雄,使之成为现实。 另外,如果我们不这样做,别人也会这样做。 但请记住,权力是腐败的,尽管它的意图是最好的。我不会在这里链接到任何特定的文章,但是如果你没有在任何地方徘徊,那就值得去寻找一些关于扰乱经济的更广泛的影响,以及这些有时最终会带来的影响。您可能会对试图通过优化来拯救世界的一些副作用感到惊讶。

后记

你注意到什么了吗,Optimus?我唯一一次称呼你Optimus的时候是在最开始,现在是在最后。在整篇文章中,你并没有被称为Optimus。说实话,我忘了。我写了整篇文章,没有叫你Optimus。最后,当我意识到我应该回去把你的名字写在文章中的时候,我内心的一个小声音说,不要这样做。

了解基础知识

[toggle hide=“yes” title=“什么是过早优化?” color=“”] 尝试在第一次编码时进行优化。性能优化最好从最高级别在任何给定的时刻完成。对于新建项目,在架构阶段。对于遗留项目,通过正确的分析来确定瓶颈,而不是玩昂贵的猜测游戏。 [/toggle] [toggle hide=“yes” title=“为什么过早优化不好?” color=“”] 假设(假定)性能优化的代码实际上是您的第一优先级,高于正确性、清晰性、可测试性等等,这是一个隐藏的陷阱。另一个陷阱是,假设代码中的代码对总体性能有足够的影响,值得优化。过早优化全中。 [/toggle]

预览
Loading comments...
0 条评论

暂无数据

example
预览