5

我在 StackOverflow 上看到(并搜索过)很多关于过早优化的问题——大街上的一句话是,它是万恶之源。:PI承认我经常为此感到内疚;我并没有真正以代码易读性为代价来优化速度,但我将使用似乎更适合该任务的数据类型和方法以逻辑方式重写我的代码(例如,在 Actionscript 3 中,使用类型化向量而不是非类型化数组用于迭代),如果我可以让我的代码更优雅,我会这样做。这通常有助于我理解我的代码,并且我通常知道我为什么要进行这些更改。

无论如何,我今天在想——在 OOP 中,我们提倡封装,试图隐藏实现并促进接口,从而使类松散耦合。这个想法是在不必知道内部发生了什么的情况下制作一些可以工作的东西——黑匣子的想法。

因此,这是我的问题——尝试在类级别对代码进行深度优化是否明智,因为 OOP 促进了模块化?或者这是否属于过早优化的范畴?我在想,如果您使用一种易于支持单元测试的语言,您可以测试、基准测试和优化该类,因为它本身就是一个接受输入并生成输出的模块。但是,作为一个编写代码的人,我不知道等到项目完全完成后再开始优化是否更明智。

供参考:我以前从未在团队中工作过,所以对于有这种经验的开发人员来说显而易见的事情对我来说可能是陌生的。

希望这个问题适合 StackOverflow - 我没有找到另一个直接回答我的查询的问题。

谢谢!

编辑:考虑到这个问题,我意识到“分析”可能是正确的术语,而不是“单元测试”;单元测试检查模块是否正常工作,而分析检查性能。此外,我之前应该问的部分问题 - 在创建单个模块之后对它们进行分析不会减少应用程序完成后的时间分析吗?

我的问题源于我正在尝试做的游戏开发 - 我必须创建应该以最佳方式执行的模块,例如图形引擎(它们是否会是一个不同的故事:D)。在性能不太重要的应用程序中,我可能不会担心这一点。

4

5 回答 5

2

我并没有真正以代码易读性为代价来优化速度,但我会使用看起来更适合任务的数据类型和方法以逻辑方式重写我的代码[...],如果我能让我的代码更优雅,我会这样做的。这通常可以帮助我理解我的代码

这并不是真正的优化,而是为了更简洁的代码和更好的设计而重构*。因此,它是一件好事,它确实应该不断地练习,小幅度地练习。Bob Martin 叔叔(在他的《清洁代码》一书中)推广了适用于软件开发的童子军规则:让代码比你找到的更干净

因此,要回答您改写的标题问题,是的,重构代码以使其可单元测试是一种很好的做法。其中一个“极端”是测试驱动开发,首先编写测试,然后添加使测试通过的代码。这样,代码从一开始就被创建为可单元测试的。

*不要吹毛求疵,只是澄清常用术语并确保我们以相同的含义使用相同的术语是有用的。

于 2011-03-31T21:27:59.053 回答
1

我坚信你永远不应该因为性能优化而降低代码的可读性和良好的设计。

如果您正在编写性能至关重要的代码,那么降低代码的风格和清晰度可能是可以的,但这对于普通的企业应用程序并不适用。硬件发展迅速,而且每天都在变得更便宜。最后,您编写的代码将被其他开发人员阅读,所以您最好把它做好!

阅读精心设计的代码总是很美妙,其中每条路径都有一个测试,可以帮助您了解应该如何使用它。我真的不在乎它是否比做很多疯狂事情的​​意大利面条替代品慢 50 毫秒。

于 2011-03-31T21:29:20.613 回答
1

诚然,我认为优化应该作为最后的任务(尽管在编写初稿时了解您可能需要返回并优化的地方是件好事)。这并不是说您不应该迭代地重构事物以保持代码中的秩序和清洁度。也就是说,如果某项当前服务于目的并且没有破坏应用程序的需求,那么应首先解决需求,因为最终它们是您负责交付的(除非需求包括关于最大请求时间的细节或类似的东西)。我也同意 Korin 的方法,如果时间允许,请先构建功能以优化您的内心内容(或理论限制,以先到者为准)。

于 2011-03-31T21:24:36.960 回答
1

过早优化是一件坏事的原因是:它可能会花费大量时间,而且您事先不知道在哪里可以最好地利用您的时间。

例如,您可能花费大量时间优化一个类,却发现应用程序中的瓶颈是网络延迟或类似因素,这在执行时间方面要昂贵得多。因为一开始你没有一个完整的画面,过早的优化会导致你的时间没有得到最佳利用。在这种情况下,您可能更愿意修复延迟问题而不是优化类代码。

于 2011-03-31T21:24:38.687 回答
1

是的,您应该跳过单元测试的优化。需要时进行优化通常会使代码更加复杂。以简单为目标。如果您针对单元测试进行优化,您实际上可能会针对生产进行优化。

如果单元测试中的性能真的很差,您可能需要查看您的设计。在优化之前在应用程序中测试以查看性能是否同样糟糕。

编辑:当处理的数据大小不同时,可能会发生反优化。处理数据集的类最有可能发生这种情况。响应可能是线性的,但最初较慢,与几何和最初的快速相比。如果单元测试使用一小组数据,则可以选择几何解进行单元测试。当生产以大量数据性能坦克达到一流水平时。

排序算法是这种行为和由此产生的反优化的典型案例。许多其他算法具有相似的特征。

EDIT2:我最成功的优化是报告的排序例程,其中数据存储在磁盘上的内存映射文件中。排序时间是合理的,数据大小适中,不需要磁盘访问。对于更大的数据集,处理数据可能需要数天时间。报告的初始时间显示;数据选择3分钟,数据整理3天,报告3分钟。对该排序的研究表明,它是一个完全未优化的冒泡排序(对于大小为 n 的数据集,n-1 次完全通过),在大 O 表示法中大致为 n 平方。更改排序算法将此报告的排序时间减少到 3 分钟。我没想到单元测试会涵盖这种情况,并且原始代码与小型集合一样简单(快速)。对于非常小的集合,替换要复杂得多,速度也要慢得多,但是使用更线性的曲线更快地处理大型集合,n log n 在大 O 表示法中。(注意:在我们有指标之前没有尝试优化。)

在实践中,我的目标是将至少占用模块运行时间的 50% 的例程改进十倍。使用 55% 的运行时间为例程实现这一级别的优化将节省 50% 的总运行时间。

于 2011-03-31T21:32:06.940 回答