38

我正在研究可以帮助我编写更小但更复杂的代码的算法。与其编写 150 行 if-else 语句,我可以设计一个算法,用 20 行来完成。问题是很多这些算法可能很复杂,需要大量的数学才能理解它们。我也是这里唯一了解他们的人。

为了代码的可维护性,像其他人一样编写代码会更好,还是使用算法更好?

4

28 回答 28

55

正如爱因斯坦所说:

让一切尽可能简单,但不要更简单。

它适用于代码和物理。

使用您的判断 - 它会变得更容易维护吗?通常通过将大的 if/else 混乱减少到更小的东西,您可以删除不需要存在的极端情况,从而防止将来可能出现的错误。当然,通过将一组明确的条件简化为一个模糊的布尔逻辑扭曲,这种逻辑只会碰巧起作用,当某些事情发生变化时,您可能会使事情变得更加难以维护。

编辑:
对于您引用的案例,如果该公式可行,那么它可能是更好的选择-您甚至可以引用源代码发表评论。不过,完全有可能该公式以前存在,但被删除以允许解决特定情况。这是版本控制存储库中的注释应该提供帮助的那种事情。

由于还没有人发布链接,这里是他所指的 PID 算法的描述。

于 2009-01-16T21:28:18.137 回答
28

代码写一次,读十次。因此,您应该尽量使其易于理解。

此外,调试比编写代码要困难得多。那么,当您已经将所有的脑力都用于编写复杂的代码时,您怎么能调试您的代码呢?

试着遵循软件开发的三定律

  1. 开发人员必须编写能够创造价值的代码。
  2. 开发人员必须使他们的代码易于维护,除非此类支出与第一定律相冲突。
  3. 开发人员必须将他们的代码减少到可能的最小大小,只要这种减少不与前两条定律相冲突。
于 2009-01-16T21:35:13.117 回答
25

Robert C. Martin 用这部漫画作为他的书Clean Code的介绍:

代码质量的唯一有效度量:WTFs/minute
(来源:osnews.com

于 2009-01-16T21:25:48.237 回答
13

请记住,代码应该主要由人类理解......编译器负责让计算机理解。

于 2009-01-16T21:22:28.073 回答
11

“复杂”的程度在这里可能有点冒险,但只要算法不需要数学博士来解决,

我会说继续使用算法。确保提供有关算法名称的适当级别的文档,并且可能是对其工作原理的简短描述或对有关它的文档的引用。

它将减少代码量,有望为应用程序提供一些额外的性能,并有望鼓励您周围的一些程序员学习一些新东西以添加到他们的曲目中。另外,知道这些事情的程序员总是有可能以后不会进来。

于 2009-01-16T21:25:00.873 回答
9

好旧的报价....

任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码

  • 马丁·福勒
于 2009-01-16T21:38:02.657 回答
8

我无法相信有人会认为 150 行的任何东西都比 20 行的东西简单。

使用 20 条线,并按以下方式保护您的同事:

  • 记录每个数据结构不变量和每个非平凡循环不变量。记录这些不是在注释中,而是在检查不变量的实际代码中。可以在生产过程中关闭检查。

  • 如果您在代码中使用数学公式或在代码中派生,请在注释(或静态字符串)中包含引用。理想情况下包括两份参考资料:一份可能会在几秒钟内获得的网络参考资料和一份可能会长期印刷并在大学图书馆中找到的广受好评的教科书。

如果理解你的代码需要特殊的专业知识(理解偏微分方程、物理学学位、伽罗瓦理论,等等),那么为了保护自己,你可能希望去找你的管理人员说“我有这种特殊的专业知识,这使它我可以编写更小的代码(因此更快、更可靠、更易于维护),但是当您必须替换我时,您将不得不雇用具有类似专业知识的人。您希望我做什么? " 如果你能告诉你的管理层是多么容易获得这样的专业知识,那将会很有帮助。例如,很多拥有工程学位的人可以学习偏微分方程,但伽罗瓦理论家却相当薄弱。

PS这是一个爱好项目的示例评论,以便我以后可以调试自己的代码:

/* 
 * Compute the position of a point partially along the geodesic from 
 * pt1.lat,pt1.lon to pt2.lat,pt2.lon
 * 
 * Ref: http://mathworld.wolfram.com/RotationFormula.html
 */
于 2009-01-17T00:54:28.033 回答
6

这实际上取决于复杂的含义。如果你的“简单”算法是 150 行几乎相同的代码,我的眼睛会发呆,我将无法理解它。如果您将这些条件放在矩阵或其他东西中,那么您的代码就是一个读取矩阵并做出决策的循环,即使循环可能不如一堆 if/else 语句“简单”,我也会更好地理解它。

如果基本上你谈论的是一个 Perl 程序,你在一行中做所有事情,大量使用默认变量 $_ 我会说坚持使用更长更详细的版本。

如果有一个公认的公式来做某事,那么您可以使用公认的公式。如果有一个需要 3 或 4 行的简单代数公式,并且有一个需要 1 行的复杂微分方程,则应该使用简单代数公式。在评论中提到的情况下,我认为 PID 算法比 150 行 if/else 代码“简单”。我不认为你使用算法来掩盖任何东西,而是你在问题领域使用标准技术。只要确保很好地评论它,甚至可能包括一个指向描述公式的网页的链接。

于 2009-01-16T23:06:02.107 回答
6

尽可能复杂,仅此而已。

于 2009-01-16T21:24:42.170 回答
5

找到通过 100 行 if/else 语句的方法通常(在我看来)比花同样时间理解更好的算法(应该在评论中解释或链接)并最终验证20 行的实现确实执行了那个。它还具有工作教育的好处,这使得它变得更加有趣(从积极的意义上说),并且通常还有更好的执行概况(更少的资源使用)。

您应该避免的聪明之处在于滥用语言而没有实际好处的“聪明的黑客”形式。您应该接受的聪明之处在于始终使用最好的算法来完成这项工作。

编辑:关于 PID 示例:我发现很难想象 PID 的功能可以被一堆 if-else 语句合理地替代。if-else 解决方案总是会工作得更糟(不太平滑的过渡),很难维护,也很难调整(调整 PID 部分对于获得所需的行为非常重要)。我想补充一点,理解 PID 并不难,即使你不知道数学,也可以很容易地查到。

于 2009-01-16T23:29:25.193 回答
4

Python之很好地解决了这个问题:

...

简单胜于复杂。

复杂胜于复杂。

...

如果实现很难解释,那就是个坏主意

...

换句话说(正如其他人所说),在强加的约束(时间、内存等)下完成工作的最简单算法是最好的算法。显然,一个无法完成工作的更简单的算法还不够好。如果你的代码因为使用了复杂的想法而变得更短,那么它就是复杂的。如果没有其他人能够理解您的代码,那么它就很复杂,而且如果您很难向他们解释它(即使他们拥有数学博士学位也能理解),这是一个坏主意

...

特殊情况不足以打破规则。

虽然实用胜过纯洁。

...

通常有很多特殊情况代码在其生命周期内潜入最初的“纯”代码。您应该与这种建筑复杂性作斗争,但在必要时接受它。

于 2009-01-16T21:43:26.237 回答
4

越简单通常越好。请记住,其他人可能有一天必须维护它。

于 2009-01-16T21:22:03.877 回答
4

以对编写代码的普通程序员来说最容易维护和理解的方式编写代码。

于 2009-01-16T21:22:12.347 回答
4

有趣的是,代码复杂度最常见的衡量标准之一是嵌套深度。您的“If-then-else”解决方案很可能被自动代码分析器归类为比您的公式化解决方案更复杂。

然而,我已经看够了“WTF?” 您描述的编码我通常会采用 if-then-else 方法。但是考虑一下;是否可以使用您更复杂、更公式化的方法,但将特别困难的组件分解为命名良好的方法?如果您可以这样做(甚至可能进行重构以消除冗余),您可能能够避免算法中最糟糕的方面,同时也可以避免多级 if-then-else 结构。

于 2009-01-16T21:37:16.747 回答
3

不必要的复杂性总是不好的。是的,编写一个完成 200 行功能的出色的单行器可能会很有趣。但请记住,您应该维护代码。简短的复杂代码很难维护。

于 2009-01-16T21:25:07.787 回答
2

我见过非常优化的代码运行得很慢,而未优化的代码运行得很快,这是因为编译器知道计算机想要如何工作,而编译器编写者首先关注的是易于优化的代码。

可能是您的 150 行算法在运行时编译成比您的 20 行版本快得多的东西。您的 20 行算法最终可能会变慢,因为编译器不知道如何优化它。

我还建议您可能希望将 if-else 版本放在 20 行算法版本上方的注释块中(反之亦然),以便维护人员可以了解您的复杂版本正在尝试做什么。将它们都包含在代码中也可以轻松地对两者进行性能测试(一旦您将它们都输入,就没有理由删除另一个)。这也将允许轻松迁移到其他语言/平台/编译器。您可能没有预料到,但如果代码有效,它可能会存在数十年并看到许多不同的编译器和平台。

于 2009-01-16T23:41:33.283 回答
2

尝试在您编写完“更复杂”的版本几周后,让其他人对其进行审核。判断您阅读并向他人解释它的难度以及他们对代码的反应的复杂性。

于 2009-01-16T23:44:14.540 回答
2

使代码更简单的另一个风险是你会陷入一堆普通的编码人员中。您要查找的行是可读/不可读的代码。如果您可以在一周内回来并且仍然可以轻松阅读代码,那么我会说它已经足够简单了。

于 2009-01-16T21:36:06.717 回答
1

如果你能在 20 行上做到这一点,然后正确地评论那些行,我会说去吧。您不仅通过减少需要维护的代码使维护变得更容易,而且还有助于使您的程序员同事变得更聪明。

预优化和巧妙的破解是一回事,但智能算法一直是公平的游戏。

但是让这些算法在它们自己的函数中隔离,并记住解释输入和输出变量!

强制性报价:

“控制复杂性是计算机编程的本质。” (布赖恩·克尼根)

于 2009-01-16T23:38:09.890 回答
1

我认为将领域复杂性与底层技术复杂性分开是很重要的。

您希望使用计算机实现的某些特定领域的功能本质上是复杂的,而有些则不然。例如,会计问题充满了奇怪的规则,但大多数计算都相当简单。另一方面,根据类型评估金融证券,可能包括非常复杂的数学公式和大量的模拟。大多数计算机系统实际上只是在收集大量数据,但其中许多系统都有一些底层的复杂算法。

另一方面,技术往往会带来其自身的复杂性。用 C++ 为 PC 编写一个大程序可能是一个挑战。为 Internet 编写基于 Web 的应用程序可能会更糟。试图确保容错性、性能或安全性通常会导致大量增加的复杂性。每种不同的技术都会帮助或阻碍系统。

我们真正想做的,是以最接近其固有领域或技术规范的最简单的形式表达代码。如果您正在编写操作系统,那么 C 是一种更易于使用的语言。如果您正在计算保险的复杂风险概率,那么像 APL 这样的面向矩阵的语言可能更合适。如果您只是创建大量报告,那么最好选择具有面向报告的简单语法的东西。

因此,如果你的 150 行 if/else 内容“匹配”了问题的表达方式,远远好于 20 行巧妙的代码,那么它就是一段更易于维护和消耗的代码。如果您从长远的角度来看,编写运行代码很容易,保持这种方式才是真正的挑战......

保罗。

于 2009-01-28T19:50:10.217 回答
1

让它变得复杂的风险是没有其他人会理解它。在这种情况下,请清楚地评论它并引用一些有助于其他人学习和理解的资源。

把它简单化的风险是有人不想理解它,因为它很长。

于 2009-01-16T21:29:09.510 回答
1

我认为问题是 - 复杂的代码更好吗?它更快、更可靠吗?目标是编写最好的程序,如果复杂的代码是最好的解决方案,那么您只需要编写更好的注释,以便您的继任者将来可以管理代码。原则上,代码在任何给定情况下都应该尽可能简单。

于 2009-01-16T21:32:32.700 回答
0

对我来说,复杂并不一定意味着更多或更少的代码行。

完美的系统从来都不是第一次构建的。 你所能做的就是尽量不要做出太多复杂的决定,让你以一种方式做事。

出于这个原因,我喜欢在任何项目的初始版本中保持较低的复杂性。您构建某些东西的原因(新的灵活性)受到了严重影响。如果你让它尽可能复杂,那么一开始就会有更少的人理解它。这可能是好事也可能是坏事。

如果你让它太简单(并且代码增加 50% 到 70%),它可能会出现性能问题。

随着系统的老化和成熟,复杂性似乎是通过重构来实现的。到那时,您可能会达到某些代码可能永远不会再被触及的地步,如果您曾经这样做,由于触摸它的频率较低,了解复杂性的成本将会降低。

我喜欢用简单的步骤解决复杂的问题。在不可能的情况下,复杂性会相应增加。关于知道何时“足够好”的另一个问题有一点。有时,更多的代码(5-20​​%)可以显着抵消复杂性,这可能会让某人重新学习或理解成本更高。

需要一个更好的算法通常是一个好问题,因为这意味着你的东西正在被使用并且有新的需求需要处理。

对我来说,这与适用于数据库抽象的复杂性相同,您必须知道何时使其更灵活,何时保持简单,最好通过构建它来学习,并在编写之前大量废弃它任何东西的单行。

于 2009-01-16T23:33:03.987 回答
0

只有在实际需要速度或空间提升时,复杂的算法才是好的。不要费心编写一个在 O(1) 中运行的花哨的阶乘算法,因为基本上不会使用大约 25 的阶乘。但是,如果代码在最内层循环中,并且此代码中 25% 的加速将使整个应用程序提高 20%,那么就去做吧。

于 2009-01-16T23:40:16.390 回答
0

好吧,如果代码足够大(参见大多数 Java 代码),代码可能会因为数量庞大而变得非常难以理解和维护。如果所有其他(性能等)都相同,并且简单算法和复杂算法之间的长度差异非常大,那么我总是会选择复杂但简洁而优雅的算法,而不是简单但冗长的算法。假设这两种算法都被证明是正确的,那么 if 语句较少且整体代码较少的算法不太可能出现细微的实现错误,因此不太可能需要维护。如果我是一名维护者,我宁愿花时间学习一种新算法,也不愿学习某人如何实现一些可笑的冗长但无聊的算法。

于 2009-01-16T21:38:32.563 回答
0

要看。我不想维护 150 行 if-then-else 语句组成一个函数,尤其是在决策树很密集的情况下。20 行复杂的数学可能会更好,也可能不会更好。理解可能需要时间,但更长的解决方案可能需要更长的时间来验证。

理想情况下,您会找到一种方法,用更少和更简单的行来完成它,但并非所有功能都以这种方式工作。

如果您确实使用了 20 行,请使用保存在注释中的 130 行中的一些来解释您正在使用什么算法。如果你不能很好地解释它,请使用 150 行的解决方案。

于 2009-01-16T21:55:04.870 回答
0

我承认自己了解并喜欢数学和算法,但对我来说,150 行 if/else 的混乱比任何可以用 20 行清晰表达的东西都要复杂和难以维护。正确记录代码并引用论文、书籍或维基百科。

于 2009-01-23T10:14:46.367 回答
0

它需要尽可能复杂。不能是复杂的,大不同的。

于 2009-01-16T21:26:27.440 回答