本文概述
真的, 这几乎值得保证。从新手到专家, 从体系结构到ASM, 再到从机器性能到开发人员性能的所有优化, 你和你的团队都有可能缩短自己的目标。
什么?我?我的团队?
这是一个相当大的指控。让我解释。
优化并不是圣杯, 但它可能很难获得。我想与你分享一些简单的技巧(以及很多陷阱), 以帮助你将团队的经验从自我破坏转变为和谐, 实现, 平衡以及最终优化。
什么是过早优化?
过早的优化正在尝试优化性能:
- 首次编码算法时
- 在基准确认你需要之前
- 在进行概要分析之前, 先找出需要进行优化的地方
- 低于你的项目当前要求的水平
现在, 我是一个乐观主义者, 擎天柱。
至少, 在撰写本文时, 我会假装自己是一个乐观主义者。就你而言, 你可以假装自己的名字叫擎天柱, 这样可以更直接地对你说话。
作为技术人员, 你有时可能会想知道这可能是一年的费用, 但是尽管我们取得了长足的进步, 但以某种方式来说, 这是一个可接受的标准, 因为$任务如此耗时。你想瘦。高效。太棒了像Rockstar程序员这样的人, 这些职位很吸引他们, 但领导排骨。因此, 当你的团队编写代码时, 你鼓励他们第一次正确执行代码(即使此处”正确”是一个高度相关的术语)。他们知道, 这就是聪明编码器的方式, 也是那些以后不需要浪费时间重构的人的方式。
我觉得。完美主义的力量有时在我内部也很强大。你希望你的团队现在花一点时间来节省很多时间, 因为每个人都在抱怨”别人写的烂代码(他们在想什么?”)。简称SCOPWWHWTT, 因为我知道你喜欢不易发音的首字母缩写词。
我也知道你不希望你的团队的代码是自己或其他任何人的代码。
因此, 让我们看看可以采取什么措施来指导你的团队朝着正确的方向发展。
优化的内容:欢迎来到这门艺术
首先, 当我们想到程序优化时, 通常会立即假设我们在谈论性能。即使那已经比看起来还模糊(速度?内存使用率?等等), 所以让我们就此停下来。
让我们变得更加含糊!刚开始。
我的蜘蛛网大脑喜欢在可能的情况下创造秩序, 因此对我来说, 要想成为一件好事要使我感到万分乐观。
那里有一个简单的规则, 那就是”性能优化”。严格遵循这听起来很容易, 但并非所有人都同意。我也不完全同意。有些人会比其他人简单地编写更好的代码。希望对于任何给定的人来说, 他们在一个全新项目中编写的代码的质量通常会随着时间的推移而提高。但是我知道, 对于许多程序员而言, 情况并非如此, 因为他们了解的越多, 就会倾向于尝试过更多的方式进行过早的优化。
对于许多程序员来说, 他们了解的越多, 就会倾向于尝试更多的方式进行过早的优化。
因此, “不这样做”不可能是一门精确的科学, 而仅仅是为了抵消典型技术人员解决难题的内在冲动。毕竟, 这首先吸引了许多程序员。我明白了。但是请他们保存它, 抵制诱惑。如果现在需要解谜的出路, 则可以随时涉猎周日报纸的数独游戏, 或者拿起Mensa的书, 或者去打高尔夫, 解决一些人为的问题。但是将其保留在回购协议中, 直到适当的时候为止。几乎总是比预优化更明智的途径。
请记住, 这种做法臭名昭著, 以至于人们问过早的优化是否是万恶之源。 (我不会走那么远, 但我同意这种观点。)
我并不是说我们应该选择在每个设计级别都可以想到的最脑筋急转弯的方式。当然不是。但是我们可以选择其他值, 而不是选择外观最聪明的值:
- 最容易向新员工解释
- 最有经验的开发人员最有可能通过代码审查
- 最易维护
- 最快写
- 最容易测试
- 最便携
- 等等
但是, 在这里问题很难解决。这不仅仅是避免针对速度, 代码大小, 内存占用, 灵活性或面向未来的优化。这是关于平衡以及你所做的工作是否实际上符合你的价值观和目标的。它完全是上下文相关的, 有时甚至无法客观地衡量。
这是一门艺术。 (参见计算机编程艺术。)
为什么这是一件好事?因为生活就是这样。太乱了我们面向程序的大脑有时会非常想在混乱中创造秩序, 以至于最终讽刺地使混乱倍增。这就像试图强迫某人爱你的悖论。如果你认为自己成功了, 那就不再是爱情;同时, 你被劫持为人质, 你可能比以往任何时候都需要更多的爱, 这个隐喻一定是我所能挑选的最尴尬的事物之一。
无论如何, 如果你认为自己已经找到了完美的系统, 那么……我想, 请尽情享受幻觉。没关系, 失败是学习的绝佳机会。
保持用户体验
让我们探讨用户体验如何适应这些潜在的优先事项。毕竟, 从某种程度上来说, 甚至希望某件事表现良好也是关于UX的。
如果你使用的是UI, 无论代码使用哪种框架或语言, 都会有一定数量的样板和重复。尽量减少程序员的时间和代码清晰度, 这绝对是有价值的。为了帮助平衡优先次序的艺术, 我想分享一些故事。
在一份工作中, 我所工作的公司使用了一种基于自以为是的技术堆栈的闭源企业系统。实际上, 它是如此自以为是, 将其出售给我们的供应商拒绝进行不符合堆栈意见的UI自定义, 因为这对他们的开发人员来说是很痛苦的。我从来没有使用过它们的堆栈, 因此我不为此谴责它们, 但事实是, 这种”对程序员有利, 对用户不利”的折衷对我的同事来说在某些情况下非常麻烦, 以至于我结束了编写第三方插件来重新实现系统UI的这一部分。 (这极大地提高了生产力。我的同事们都喜欢它!十多年后, 它仍然节省了所有人的时间和沮丧感。)
我并不是说观点本身就是问题;就我们而言, 太多的问题就成了问题。作为反例, Ruby on Rails的一大吸引人之处在于它被认为是在前端生态系统中, 人们可以通过过多的选择轻松获得眩晕感。 (给我一些意见, 直到我能弄清楚自己的意见!)
相比之下, 你可能会想在项目中将UX授予万物之王。一个值得的目标, 但让我讲述我的第二个故事。
在上述项目成功完成几年后, 我的一位同事来找我, 要求我通过自动化有时会出现的某些混乱的真实场景来优化UX, 以便单击即可解决。我开始分析由于该场景有很多奇怪的情况, 是否甚至有可能设计出不会出现误报或漏报的算法。我与同事谈论的越多, 我越意识到要求根本无法实现。该方案仅偶尔出现一次(例如, 每月一次), 目前只需要一个人几分钟即可解决。即使我们能够成功实现自动化, 而没有任何错误, 但要花上几个世纪的时间才能根据我的同事节省的时间来偿还所需的开发和维护时间。我内的讨好人说”不”很困难, 但我不得不缩短对话时间。
因此, 让计算机尽其所能来帮助用户, 但只能做到理智。但是你怎么知道这是什么程度呢?
我喜欢采取的一种方法是像开发人员配置他们的代码一样配置UX。从你的用户那里找出他们花费最多时间反复单击或键入相同内容的地方, 然后查看是否可以优化这些交互。你的代码能否对它们最有可能输入的内容进行一些有根据的猜测, 并将其设为无输入默认值?除了某些禁止使用的内容(无EULA确认?)之外, 这确实可以改善用户的工作效率和满意度。如果可以, 请进行一些走廊可用性测试。有时, 你可能很难解释什么对计算机而言容易解决, 而哪些则不可行……但是总的来说, 此值对用户而言非常重要。
避免过早的优化:何时以及如何进行优化
尽管我们在其他环境下进行了探索, 但现在让我们明确地假设我们在本文的其余部分中正在优化原始机器性能的某些方面。我建议的方法也适用于其他目标, 例如灵活性, 但是每个目标都有自己的陷阱。要点是过早优化任何内容都可能会失败。
那么, 就性能而言, 实际上要遵循哪些优化方法?让我们深入。
这不是基层计划, 而是Triple-Eh
TL; DR是:从顶部向下进行。较高级别的优化可以在项目的早期进行, 而较低级别的优化则应留待以后使用。这就是获取”过早优化”一词的大部分含义所需要的;不按顺序进行工作很可能浪费团队的时间并产生反效果。毕竟, 你不是从一开始就用机器代码编写整个项目的, 对吗?因此, 我们的AAA方式操作按以下顺序进行优化:
- 建筑
- 演算法
- 部件
普遍的看法是, 至少在性能方面, 算法和数据结构通常是最有效的优化场所。但是请记住, 该体系结构有时会确定完全可以使用哪些算法和数据结构。
我曾经发现一种软件, 可以通过对每个财务交易多次查询一个SQL数据库, 然后在客户端进行非常基本的计算来制作财务报告。小型企业只用了几个月就使用了该软件, 即使他们的财务数据相对较少, 这意味着, 借助全新的台式机和相当强大的服务器, 报表生成时间已经长达数分钟, 这是他们需要经常使用的一种。我最终写了一条简单的SQL语句, 其中包含求和逻辑-通过将工作移至服务器以避免所有重复和网络往返来破坏它们的体系结构-甚至是数年后的价值数据, 我的版本也可以生成在相同的旧硬件上, 仅几毫秒内的相同报告。
有时, 你对项目的架构没有影响力, 因为为时过晚, 无法进行架构更改。有时你的开发人员可以像上面的示例中那样绕过它。但是, 如果你是项目的开始, 并且在其架构中有发言权, 那么现在是时候对其进行优化。
建筑
在项目中, 架构是事后更改的最昂贵的部分, 因此在这里, 一开始就可以进行优化。例如, 如果你的应用是通过鸵鸟来传递数据, 则你希望将其构造为低频率, 高负载的数据包, 以免造成严重的瓶颈。在这种情况下, 最好使用完整的Tetris来娱乐用户, 因为加载微调器不会削减它。 (开玩笑:几年前, 我正在安装我的第一个Linux发行版Corel Linux 2.0, 并且很高兴长期运行的安装过程包括其中。看到Windows 95安装程序的信息电视屏幕如此之多, 以至于我记住了它们, 当时呼吸着新鲜空气。)
作为体系结构更改代价昂贵的一个示例, 上述SQL报告首先具有如此高的不可扩展性的原因已从其历史中显而易见。该应用程序从其MS-DOS的根源到一个本来不是多用户的, 自定义的自定义数据库, 随着时间的流逝而发展。当供应商最终转用SQL时, 架构和报告代码似乎已经一对一地移植了。每当他们通过实际利用给定报告的SQL优势来完成体系结构转换时, 这便使他们多年有价值的性能提升达到了1, 000%以上, 可用于整个更新。非常适合像我的前雇主这样的锁定客户的公司, 并且显然在初始过渡期间尝试优先考虑编码效率。但是, 在某些情况下, 满足客户的需求与用锤子拧螺丝一样有效。
架构部分是关于预期项目将需要扩展到什么程度以及以何种方式进行扩展。由于架构是如此高级, 因此很难在不将我们的关注范围缩小到特定技术和领域的情况下, 具体说明我们的”做与不做”。
我不会这样说, 但其他人都会这样
值得庆幸的是, 互联网上充斥着关于梦想中的大多数每种架构的智慧。当你知道该优化架构的时候了, 研究隐患可以归结为找出描述你的出色愿景的流行语。有人可能会按照与你相同的思路进行思考, 尝试, 失败, 反复使用并在博客或书籍中发布。
仅仅通过搜索就可以轻松地识别流行词, 因为对于你所说的FLDSMDFR, 已经有人创造了SCOPWWHWTT这个术语, 它们描述的是你要解决的相同问题, 但所用词汇却与你完全不同。开发者社区来解救!尽可能详尽地描述StackExchange或HashNode, 以及你的体系结构所没有的所有流行词汇, 因此他们知道你已经进行了充分的初步研究。有人很高兴能启发你。
同时, 一些一般性建议可能是值得深思的。
算法与汇编
给定有益的体系结构, 在这里, 你团队中的编码人员将在他们的时间内获得最多的T-bling。避免过早优化的基本原则也适用于此, 但是你的程序员最好考虑一下此级别的某些细节。关于实现细节, 有太多需要考虑的地方, 我写了另一篇关于代码优化的文章, 专门针对前线和高级编码人员。
但是, 一旦你和你的团队实施了一些性能未优化的方案, 你是否真的将其留在”不做”呢?你从来没有优化?
你是对的。下一条规则是, 仅对于专家, 不要这样做。
是时候进行基准测试了!
你的代码有效。也许它是如此之慢, 以至于你已经知道需要进行优化, 因为它的代码经常运行。也许你不确定, 或者你有O(n)算法, 但认为可能很好。无论如何, 如果此算法可能值得优化, 那么我在这一点上的建议是相同的:运行一个简单的基准测试。
为什么?难道我的O(n³)算法不可能比其他任何算法都差吗?好吧, 有两个原因:
- 你可以将基准添加到测试套件中, 作为衡量性能目标的客观指标, 而不管当前是否达到了目标。
- 即使是专家也可能会无意中使事情变慢。即使看起来很明显。真的很明显。
在第二点上不相信我?
如何从1400美元的硬件中获得比7, 000美元的硬件更好的结果
StackOverflow知名度的Jeff Atwood曾指出, 有时(通常, 他认为), 购买更好的硬件有时可能比花费宝贵的程序员时间进行优化更具成本效益。好的, 假设你已得出一个合理客观的结论, 即你的项目将适合这种情况。让我们进一步假设你要优化的是编译时间, 因为这是你正在处理的一个庞大的Swift项目, 并且这已经成为开发人员的一个很大的瓶颈。硬件购物时间!
你应该买什么?好吧, 显然, 用日元换日元, 较昂贵的硬件往往比较便宜的硬件性能更好。因此, 显然, 售价7, 000美元的Mac Pro应该比某些中档Mac Mini更快地编译软件, 对吗?
错误!
事实证明, 有时更多的内核意味着更有效的编译……在这种情况下, LinkedIn发现了一种困难的方法, 即对它们的堆栈而言, 情况恰恰相反。
但是我看到管理层进一步犯了一个错误:他们之前和之后甚至都没有进行基准测试, 发现硬件升级并没有使他们的软件”感觉”更快。但是没有办法确定。而且, 他们仍然不知道瓶颈在哪里, 因此他们对性能仍然不满意, 因为他们已经花了时间和金钱来解决问题。
好的, 我已经设定了基准。我真的可以优化吗?
是的, 假设你已决定需要。但是也许这个决定将等到更多/所有其他算法都实现后再进行, 因此你可以查看运动部件如何组合在一起, 以及通过剖析最重要的部分。对于小型应用程序, 这可能是在应用程序级别, 或者可能仅适用于一个子系统。请记住, 无论哪种方式, 特定的算法对于整个应用程序似乎都很重要, 但是即使是专家(尤其是专家)也容易误诊。
三思而后行
“我不认识你们, 但是……”
作为最后的思考结果, 请考虑如何将错误优化的思想应用到更广阔的视野:你的项目或公司本身, 甚至是经济部门。
我知道, 很容易想到技术会挽救一天, 而我们可以成为实现这一目标的英雄。
另外, 如果我们不这样做, 其他人也会这样做。
但是请记住, 尽管有最好的意图, 但权力还是会腐败。我不会在这里链接到任何特定的文章, 但是, 如果你没有在任何文章上徘徊, 那么值得一提的是, 了解破坏经济的更广泛影响, 以及最终为谁服务。你可能会对通过优化来拯救世界的一些副作用感到惊讶。
后记
你注意到了吗, 擎天柱?我唯一一次给你打电话给擎天柱是在开始时, 现在是结束时。在整篇文章中, 你都没有称呼擎天柱。老实说, 我忘了。我写了整篇文章时都没有称呼你擎天柱。最后, 当我意识到我应该回头在整个文本中撒上你的名字时, 我内心有点声音说, 不要这样做。
评论前必须登录!
注册