如何避免过早优化的诅咒

已发表: 2022-03-11

这几乎是值得保证的,真的。 从新手到专家,从架构到 ASM,以及从机器性能到开发人员性能的任何优化,您和您的团队很有可能会缩短自己的目标。

什么? 我? 我的团队?

这是一个相当严重的指控。 让我解释。

优化不是圣杯,但它可能同样难以获得。 我想与您分享一些简单的技巧(以及一大堆陷阱),以帮助您将团队的体验从一种自我破坏转变为一种和谐、满足、平衡,并最终实现优化。

什么是过早优化?

过早的优化试图优化性能:

  1. 首次编写算法时
  2. 在基准确认之前,您需要
  3. 在分析精确点之前需要优化的地方
  4. 比您的项目当前要求的级别低

现在,我是一个乐观主义者,擎天柱。

至少,在我写这篇文章的时候,我会假装自己是一个乐观主义者。 就你而言,你可以假装你的名字是擎天柱,这样它会更直接地对你说话。

作为技术人员,您有时可能想知道它怎么可能是$year ,然而,尽管我们取得了所有进步,但对于$task来说,如此令人讨厌的耗时却是可以接受的标准。 你想变瘦。 高效的。 惊人的。 像 Rockstar Programmers 这样的人,这些职位都在叫嚣着,但有领导者的印章。 因此,当您的团队编写代码时,您鼓励他们第一次就做对(即使“正确”在这里是一个高度相关的术语)。 他们知道这是 Clever Coder 的方式,也是那些以后不需要浪费时间重构的人的方式。

我觉得。 完美主义的力量有时在我体内也很强大。 您希望您的团队现在花一点时间来节省以后的大量时间,因为每个人都在努力完成他们分享的“其他人写的烂代码(他们到底在想什么?)”。 简称 SCOPWWHWTT,因为我知道你喜欢不发音的首字母缩略词。

我也知道您不希望您的团队的代码为他们自己或其他任何人使用。

因此,让我们看看可以做些什么来引导您的团队朝着正确的方向前进。

优化什么:欢迎来到这是一门艺术

首先,当我们想到程序优化时,我们通常会立即假设我们正在谈论性能。 即使已经比看起来更模糊(速度?内存使用情况?等等)所以让我们停在那里。

让我们让它更加模棱两可! 刚开始。

我的蜘蛛网般的大脑喜欢在可能的情况下创造秩序,所以我需要每一盎司的乐观情绪来考虑我要说的是一件好事

有一个简单的(性能)优化规则,那就是不要这样做。 这听起来很容易严格遵循,但并非所有人都同意。 我也不完全同意。 有些人会简单地写出比其他人更好的代码。 希望对于任何给定的人来说,他们在全新项目中编写的代码质量通常会随着时间的推移而提高。 但我知道,对于许多程序员来说,情况并非如此,因为他们知道的越多,他们就越容易过早地进行优化。

对于许多程序员来说……他们知道的越多,他们就越容易过早地进行优化。

所以这个不要做它不能是一门精确的科学,而只是为了抵消典型的技术人员解决难题的内在冲动。 毕竟,这首先是吸引许多程序员参与这项技术的原因。 我明白了。 但请他们保存它,以抵制诱惑。 如果你现在需要一个解谜的出口,你总是可以涉足周日报纸的数独游戏,或者拿起一本门萨书,或者去打高尔夫球打一些人为的问题。 但是在适当的时间之前将其排除在回购之外。 几乎总是这比预优化更明智。

请记住,这种做法臭名昭著,以至于人们会问过早的优化是否是万恶之源。 (我不会走那么远,但我同意这种观点。)

我并不是说我们应该在每个设计级别选择我们能想到的最脑残的方式。 当然不是。 但是,我们可以考虑其他值,而不是选择看起来最聪明的值:

  1. 最容易向新员工解释
  2. 最有可能通过最有经验的开发人员的代码审查
  3. 最可维护的
  4. 最快的写
  5. 最容易测试
  6. 最便携
  7. 等等。

但这就是问题本身很困难的地方。 这不仅仅是避免优化速度、代码大小、内存占用、灵活性或面向未来的能力。 这是关于平衡以及你所做的是否真的符合你的价值观和目标。 它完全是上下文相关的,有时甚至无法客观地衡量。

这是一门艺术。 (参见计算机编程艺术。)

为什么这是一件好事? 因为生活就是这样。 很乱。 我们面向编程的大脑有时非常想在混乱中创造秩序,以至于我们最终讽刺地加剧了混乱。 这就像试图强迫某人爱你的悖论。 如果你认为你已经成功了,那就不再是爱; 与此同时,你被指控劫持人质,你可能比以往任何时候都需要更多的爱,而这个比喻一定是我能选择的最尴尬的比喻之一。

不管怎样,如果你认为你已经为某事找到了完美的系统,那么……我想,在它持续的时候享受幻觉吧。 没关系,失败是学习的绝佳机会。

过早的优化通常会使您的产品变得不必要且徒劳地复杂化。

牢记用户体验

让我们探讨一下用户体验如何融入这些潜在的优先事项。 毕竟,在某种程度上,甚至想要表现良好的东西也是关于 UX 的。

如果您正在处理 UI,无论代码使用什么框架或语言,都会有一定数量的样板和重复。 尝试减少这种情况在程序员时间和代码清晰度方面绝对是有价值的。 为了帮助平衡优先级的艺术,我想分享几个故事。

在一份工作中,我工作的公司使用了一个基于自以为是的技术堆栈的闭源企业系统。 事实上,卖给我们的供应商如此固执己见,拒绝进行不符合堆栈意见的 UI 定制,因为这对他们的开发人员来说太痛苦了。 我从未使用过他们的堆栈,所以我不会因此而谴责他们,但事实是这种“对程序员有利,对用户不利”的权衡在某些情况下对我的同事来说麻烦了,以至于我结束了编写第三方插件来重新实现系统 UI 的这一部分。 (这是一个巨大的生产力助推器。我的同事喜欢它!十多年后,它仍然为每个人节省了时间和挫败感。)

我并不是说意见本身就是一个问题。 在我们的案例中,太多的问题成为了问题。 举个反例,Ruby on Rails 的一大吸引力恰恰在于它固执己见的,在前端生态系统中,人们很容易因为有太多选择而感到眩晕。 (给我一些有意见的东西,直到我弄清楚我自己的!)

相反,您可能会想在您的项目中将 UX 冠以一切之王。 一个有价值的目标,但让我讲述我的第二个故事。

上述项目成功几年后,我的一位同事来找我,要求我通过自动化有时出现的某些混乱的现实生活场景来优化用户体验,以便只需单击一下即可解决。 我开始分析是否有可能设计一个不会有任何误报或误报的算法,因为该场景有许多奇怪的边缘情况。 我与同事谈论得越多,我就越意识到这些要求根本不会得到回报。 这种情况只是偶尔出现一次——比如说每月一次——目前需要一个人几分钟来解决。 即使我们能够成功地实现自动化,并且没有任何错误,所需的开发和维护时间也需要几个世纪才能得到回报,因为我的同事节省了时间。 我内心的讨人喜欢的人很难说“不”,但我不得不缩短谈话时间。

因此,让计算机尽其所能帮助用户,但仅限于理智的范围内。 你怎么知道那是什么程度呢?

对计算机来说,什么是容易的,什么是困难的

我喜欢采用的一种方法是像开发人员分析他们的代码一样分析用户体验。 从您的用户那里找出他们花费最多时间点击或一遍又一遍地输入相同内容的地方,看看您是否可以优化这些交互。 您的代码能否对他们最有可能输入的内容做出一些有根据的猜测,并将其设为无输入默认值? 除了某些禁止的上下文(无点击 EULA 确认?)之外,这确实会影响用户的工作效率和幸福感。 如果可以的话,做一些走廊可用性测试。 有时,您可能难以解释计算机可以轻松提供哪些帮助,哪些不方便……但总体而言,此值可能对您的用户非常重要。

避免过早优化:何时以及如何优化

尽管我们对其他环境进行了探索,但现在让我们明确假设我们正在为本文的其余部分优化原始机器性能的某些方面。 我建议的方法也适用于其他目标,比如灵活性,但每个目标都有自己的陷阱; 要点是过早地优化任何东西都可能会失败。

那么,在性能方面,究竟有哪些优化方法可以遵循呢? 让我们深入挖掘。

这不是草根倡议,这是三重

TL;DR 是:从顶部向下工作。 更高级别的优化可以在项目的早期进行,较低级别的应该留到以后。 这就是获得“过早优化”这一短语的大部分含义所需的全部内容; 不按此顺序做事很可能会浪费团队的时间并适得其反。 毕竟,您不会从一开始就用机器代码编写整个项目,对吗? 所以我们的AAA作案手法是按这个顺序优化:

  1. 建筑学
  2. 算法
  3. 集会

普遍的看法是,算法和数据结构通常是优化最有效的地方,至少在性能方面是这样。 但请记住,架构有时会决定可以使用哪些算法和数据结构。

我曾经发现一个做财务报告的软件,它通过为每笔金融交易多次查询 SQL 数据库,然后在客户端进行非常基本的计算。 使用该软件的小企业只用了几个月,就连他们相对较少的财务数据也意味着,有了全新的台式机和相当强大的服务器,报告生成时间已经达到了几分钟,这是他们需要经常使用的一种。 最后我写了一个简单的 SQL 语句,其中包含求和逻辑——通过将工作转移到服务器来避免所有重复和网络往返——甚至几年后的数据,我的版本可以生成在相同的旧硬件上只需几毫秒即可获得相同的报告。

有时您对项目的架构没有影响力,因为在项目中为时已晚,架构更改不可行。 有时您的开发人员可以像我在上面的示例中那样绕过它。 但是,如果您刚开始一个项目并对其架构有一定的发言权,那么现在是优化它的时候了。

建筑学

“如果建设者按照程序员编写程序的方式建造建筑物,那么出现的第一只啄木鸟就会摧毁文明。” ——温伯格定律

在一个项目中,架构是事后更改成本最高的部分,所以这是一个可以在开始时进行优化的地方。 例如,如果您的应用程序要通过鸵鸟传递数据,您将希望将其构建为低频、高负载数据包,以避免使瓶颈变得更糟。 在这种情况下,您最好拥有俄罗斯方块的完整实现来娱乐您的用户,因为加载微调器不会削减它。 (开个玩笑:几年前,我正在安装我的第一个 Linux 发行版 Corel Linux 2.0,我很高兴长时间运行的安装过程包括了这一点。看过 Windows 95 安装程序的电视广告屏幕很多次,我已经记住了它们,这当时是呼吸新鲜空气。)

作为架构更改成本高昂的一个示例,上述 SQL 报告首先如此高度不可扩展的原因从其历史中可以清楚地看出。 该应用程序随着时间的推移而发展,从其起源于 MS-DOS 和一个甚至最初不是多用户的本土定制数据库。 当供应商最终切换到 SQL 时,模式和报告代码似乎已经一对一地移植了。 每当他们通过实际利用 SQL 对给定报告的优势来完成架构切换时,这让他们在整个更新过程中获得了令人印象深刻的 1,000% 以上的性能改进。 适合像我当时的雇主这样的锁定客户的业务,并且显然试图在初始过渡期间优先考虑编码效率。 但在某些情况下,满足客户的需求就像锤子拧螺丝一样有效。

架构部分是关于预测您的项目需要能够扩展的程度以及以何种方式扩展。 因为架构是如此高级,如果不将我们的关注点缩小到特定的技术和领域,就很难将我们的“注意事项”具体化。

我不会这样称呼它,但其他人都会这样做

值得庆幸的是,互联网上充斥着关于大多数曾经梦想过的建筑的集合智慧。 当您知道是时候优化您的架构时,研究陷阱几乎可以归结为找出描述您出色愿景的流行语。 很有可能有人和你有同样的想法,尝试过,失败过,迭代过,并在博客或书中发表过。

仅通过搜索来识别流行词可能会很棘手,因为对于您所谓的 FLDSMDFR,其他人已经创造了 SCOPWWHWTT 一词,他们描述了您正在解决的相同问题,但使用的词汇与您完全不同。 开发者社区来救援! 尽可能详细地描述 StackExchange 或 HashNode,加上所有你的架构不是的流行语,这样他们就知道你做了足够的初步研究。 有人会很乐意开导你。

同时,一些一般性的建议可能是值得深思的。

算法和组装

给定一个有利的架构,这里是您团队中的编码人员将在他们的时间里获得最多 T-bling 的地方。 过早优化的基本避免也适用于此,但您的程序员最好考虑此级别的一些细节。 当涉及到实现细节时,需要考虑的事情太多了,以至于我写了一篇关于代码优化的单独文章,专门针对一线和高级编码人员。

但是,一旦您和您的团队实施了一些未优化的性能方面的事情,您是否真的将其保留为Don't do it ? 你从不优化?

你说得对。 下一条规则是,仅限专家,要这样做

是时候进行基准测试了!

您的代码有效。 也许它太慢了,以至于您已经知道需要优化,因为它是经常运行的代码。 也许你不确定,或者你有一个 O(n) 算法并且认为它可能没问题。 不管是什么情况,如果这个算法值得优化,我现在的建议是一样的:运行一个简单的基准测试。

为什么? 不是很清楚我的 O(n³) 算法不可能比其他任何东西都差吗? 嗯,有两个原因:

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

不相信我的第二点?

如何从 1,400 美元的硬件中获得比 7,000 美元的硬件更好的结果

StackOverflow 名声的 Jeff Atwood 曾指出,有时(在他看来,通常情况下)购买更好的硬件比将宝贵的程序员时间花在优化上更划算。 好的,所以假设您已经得出了一个相当客观的结论,即您的项目适合这种情况。 让我们进一步假设您要优化的是编译时间,因为这是您正在处理的一个庞大的 Swift 项目,这已成为一个相当大的开发人员瓶颈。 硬件购物时间!

你应该买什么? 嗯,显然,日元对日元,更昂贵的硬件往往比更便宜的硬件表现更好。 很明显,一台 7,000 美元的 Mac Pro 编译软件的速度应该比一些中档 Mac Mini 快,对吧?

错误的!

事实证明,有时更多的内核意味着更高效的编译……在这种特殊情况下,LinkedIn 发现他们的堆栈情况正好相反。

但我看到管理层犯了一个更大的错误:他们甚至没有在前后进行基准测试,并且发现硬件升级并没有让他们的软件“感觉”更快。 但是没有办法确定; 此外,他们仍然不知道瓶颈在哪里,所以他们对性能仍然不满意,因为他们已经用完了他们愿意分配给问题的时间和金钱。

好的,我已经进行了基准测试。 我真的可以优化

是的,假设您已经决定需要这样做。 但也许该决定将等到更多/所有其他算法也被实施,因此您可以通过分析查看移动部件如何组合在一起以及哪些最重要。 这可能是针对小型应用程序的应用程序级别,也可能仅适用于一个子系统。 无论哪种方式,请记住,一个特定的算法对整个应用程序来说似乎很重要,但即使是专家——尤其是专家——也容易误诊。

三思而后行

“我不知道你们这些人,但是……”

来自硅谷的 Gavin Belson 说:“我不想生活在一个别人让世界变得更美好……比我们更好的世界里。”

作为最后的思考点,请考虑如何将错误优化的想法应用于更广泛的观点:您的项目或公司本身,甚至是经济部门。

我知道,人们很容易认为技术将拯救这一天,我们可以成为实现这一目标的英雄。

另外,如果我们不这样做,其他人就会这样做。

但请记住,尽管有最好的意图,权力也会腐败。 我不会在这里链接到任何特定的文章,但如果你没有浏览过任何文章,那么值得寻找一些关于扰乱经济的更广泛影响,以及这有时最终会为谁服务。 您可能会对尝试通过优化来拯救世界的一些副作用感到惊讶。

后记

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