【问题标题】:Should code be short/concise? [closed]代码应该简短/简洁吗? [关闭]
【发布时间】:2010-10-31 10:23:17
【问题描述】:

编写数学证明时,一个目标是继续压缩证明。证明变得更加优雅,但不一定更具可读性。压缩转化为更好的理解,因为您消除了不必要的字符和冗长。

我经常听到开发人员说您应该使代码占用空间尽可能小。这会很快产生不可读的代码。在数学中,这不是一个问题,因为该练习纯粹是学术性的。然而,在时间就是金钱的生产代码中,让人们试图弄清楚一些非常简洁的代码在做什么似乎没有多大意义。对于更冗长的代码,您可以获得可读性和节省。

什么时候停止压缩软件代码?

【问题讨论】:

  • “尽可能简单,但绝不简单。”转述爱因斯坦。
  • 我从来都不喜欢将编程与数学或诗歌进行直接比较。是的,一些相同的想法也适用,但您必须小心避免类比过分。
  • @Nosredna:+1,就像一位朋友常说的“不好的比喻就像可乐罐......”

标签: proof math


【解决方案1】:

干燥:不要重复自己。这将为您提供既简洁又安全的代码。多次编写相同的代码是使其难以维护的好方法。

现在这并不意味着您应该为任何看起来很相似的代码块创建一个函数。

一个非常常见的错误(恐怖?)例如,分解代码执行几乎相同的事情,并通过向函数 API 添加标志来处理出现之间的差异。起初这可能看起来无害,但生成的代码流难以理解且容易出错,甚至更难重构。

如果您遵循常见的重构规则(查看代码异味),您的代码将变得越来越简洁,因为许多代码异味都与检测冗余有关。

另一方面,如果您不遵循任何有意义的准则而尝试使代码尽可能短,那么在某些时候您将不得不停下来,因为您再也看不到如何减少代码了。

试想一下,如果第一步是删除所有无用的空格......在大多数编程语言中的该步骤代码将变得如此难以阅读之后,您将没有太多机会找到任何其他可能的增强功能。

上面的例子很讽刺,但与你在不遵循任何明智的指导方针的情况下尝试优化大小时得到的结果相差无几。

【讨论】:

  • 我完全理解你的意思,代码看似简洁而简短,但实际上隐藏了神奇的抽屉,这些抽屉展开后会给你带来奇怪的实现和冗余(它只是隐藏它)。例如使用宏 =)
【解决方案2】:

就对象名称而言,随着新编程语言的引入,对此的思考已经发生了演变。

如果您采用“花括号”语言,从 C 开始,简洁被认为是智慧的灵魂。因此,例如,您将有一个变量来保存名为“lv”的贷款值。当时的想法是您要输入大量代码,因此请尽量减少击键次数。

随后出现了 Microsoft 认可的“匈牙利表示法”,其中变量名称的第一个字母表示其基础类型。有人可能会使用“fLV”或类似的词来表示贷款价值是由一个浮点变量表示的。

随着 Java,然后是 C#,范式变得清晰。贷款价值变量的好名字是“loanValue”。我相信部分原因是大多数现代编辑器中的命令完成功能。由于不再需要输入完整的名称,因此您可以使用尽可能多的字符来进行描述。

这是一个很好的趋势。代码需要易于理解。评论通常是事后才添加的,如果有的话。它们也不会随着代码的更新而更新,因此它们已经过时了。描述性的、精心挑选的变量名是让其他人知道您的编码内容的首选、最佳和最简单的方法。

我有一位计算机科学教授说:“作为工程师,我们不断创造出以前从未存在过的事物类型。我们给它们起的名字会一直存在,所以我们应该小心命名事物有意义的。”

【讨论】:

    【解决方案3】:

    只要您对代码进行注释,您就可以使代码尽可能简短或紧凑。这样你的代码可以优化但仍然有意义。如果还不清楚,我倾向于在描述性变量和方法的中间位置停留。

    【讨论】:

    • 评论腐烂得很快。我花了太多时间阅读可能描述代码如何工作的 cmets。清晰的代码不会腐烂。
    • 它是双向的。我通读了几页代码,却发现它不再被使用,只是在收集灰尘,因为它们只是害怕去除。代码只能告诉你这么多,cmets应该像代码一样更新。
    • 负面评价的答案是如何被选为答案的? 4thSpace,社区显然不同意你的观点……Scott 的回答并不是你问题的最佳答案……
    • 这种方法会导致各种不可读的代码。您应该努力编写根本不需要 cmets 的代码,而不是用 cmets 来混淆视听。
    【解决方案4】:

    是的。总是。

    【讨论】:

    • 对于那些缺少幽默基因的人 - 这是一个笑话!这就是我将其设为 Wiki 的原因。
    【解决方案5】:

    相对于冗长/漫无边际?当然!

    但它太短太简洁以至于难以理解,那么你就走得太远了。

    【讨论】:

    • "...那你走得太远了。"真正了解是主观的。
    • 整个问题都是主观的,不是吗?如果您正在寻找经验法则,我不确定我是否可以给您,但是您是否可以在编写代码一段时间后理解自己的代码,或者您的同事是否可以理解,这很好嗅探测试,看看你是否压缩太多。我猜这完全取决于你想弄清楚你写了什么。
    【解决方案6】:

    这是 Steve McConnell 的一篇好文章 - 最佳实践http://www.stevemcconnell.com/ieeesoftware/bp06.htm

    我认为简短/简洁是编写良好代码的两个结果。编写好的代码有很多方面,写得好的代码有很多结果,意识到两者是不同的。你不打算为一个小的足迹,你计划一个简洁的功能,并且做得非常好 - 这应该导致一个小的足迹(但可能不会)。以下是我在编写代码时会关注的简短列表:

    • 单一专注的功能 - 一个功能应该只做一件事,一个简单的交付,多功能的功能是错误的,不容易重复使用
    • 松散耦合 - 不要从一个函数内部接触到全局数据,也不要严重依赖其他函数
    • 精确命名 - 使用有意义的精确变量名,隐晦的名称就是这样
    • 保持代码简单而不复杂 - 不要过度使用特定于语言的技术哇,有利于给他人留下深刻印象,难以理解和维护 - 如果您确实添加了一些“特别”的评论,那么至少人们可以欣赏它在骂你之前
    • 均匀评论 - 对许多 cmets 将被忽略和过时,对少数没有意义
    • 格式化 - 以代码的外观为荣,正确缩进的代码有帮助
    • 以代码维护人员的头脑工作 - 想想维护您正在编写的代码会是什么样子
    • 不要害怕或懒于重构 - 第一次没有什么是完美的,清理你自己的烂摊子

    【讨论】:

    • 这些是很好的指导方针。然而,当你遇到有人因为它很酷而使用某个东西并要求他们重写以使代码更具可读性时,你就处于一场无休止的战斗中。
    • 请他们发表评论 - 这样他们就可以向其他人展示他们有多聪明
    • +1 我认为这是最好的答案。谢谢。
    【解决方案7】:

    简洁的代码和性能之间不一定存在相关性。这是一个神话。在像 C/C++ 这样的成熟语言中,编译器能够非常有效地优化代码。在这些语言中,有必要假设代码越简洁,性能就越好。像 Ruby 等较新的、性能优化较少的语言缺乏 C/C++ 编译器的编译器优化功能,但仍然没有理由相信简洁的代码性能更好。现实情况是,在代码投入生产并进行分析之前,我们永远不知道代码在生产中的性能如何。如果从代码中的足够多的位置调用简单、无害的函数,可能会成为巨大的性能瓶颈。在高并发系统中,最大的瓶颈通常是由糟糕的并发算法或过度锁定引起的。这些问题很少通过编写“简洁”的代码来解决。

    底线是:一旦性能分析确定它是瓶颈,性能不佳的代码总是可以重构。只有易于理解的代码才能有效地重构。写得“简洁”或“聪明”的代码通常更难重构和维护。

    编写代码以提高可读性,然后在必要时重构以提高性能。

    我的两分钱...

    【讨论】:

      【解决方案8】:

      代码优化与编码风格几乎没有关系。文件包含的 x 空格或新行少于开头的事实并不能使它更好或更快,至少在执行阶段是这样 - 您使用编译器通常忽略的白色字符格式化代码。它甚至使代码变得更糟,因为它变得无法让其他程序员和您自己阅读。

      更重要的是代码的逻辑结构要简洁明了,例如测试条件、控制流、假设、错误处理或整体编程接口。当然,我也会在此处包含智能且有用的 cmets + 文档。

      【讨论】:

        【解决方案9】:

        找到平衡的一种方法是寻求可读性,而不是简洁。程序员不断地以视觉方式扫描代码以查看正在执行的操作,因此代码应尽可能流畅。

        如果程序员在扫描代码时碰到了难以理解的部分,或者费了些力气在视觉上解析和理解,那是一件坏事。使用常见且易于理解的结构很重要,除非必要,否则不要使用模糊且不经常使用的结构。

        人类不是编译器。编译器可以吃掉这些东西并继续前进。晦涩的代码不会像清晰理解的代码那样迅速地被人类在精神上消耗掉。

        有时很难用复杂的算法生成可读的代码,但在大多数情况下,我们应该寻找的是人类可读性,而不是聪明。我也不认为代码的长度真的是衡量清晰程度的标准,因为有时更冗长的方法比简洁的方法更具可读性,有时更简洁的方法比长的方法更具可读性。

        另外,cmets 应该只是补充,而不应该描述你的代码,你的代码应该描述它自己。如果你必须评论一行,因为它不明显做了什么,那很糟糕。大多数有经验的程序员阅读英文解释比阅读代码本身需要更长的时间。我认为 Code Complete 这本书很适合这一点。

        【讨论】:

          【解决方案10】:

          努力重构,直到代码本身阅读良好。你会在这个过程中发现自己的错误,代码会更容易被“下一个人”理解,并且你不会因为在 cmets 中维护(后来忘记更改)你已经表达过的东西而感到负担代码。

          如果失败...当然,请给我留言。

          不要在评论中告诉我“什么”(这就是代码的用途),告诉我“为什么”。

          【讨论】:

            【解决方案11】:

            代码应该简短、具体、集中。 cmets 中你总是可以用很多词来解释你的想法。

            【讨论】:

            • 我也完全不同意你的观点。让代码自己解释。你并没有你想的那么聪明。
            • 你怎么知道我有多聪明?关于最佳编码实践有很多意见。我的建议不会使编译器过载并利用各自语言的功能。毕竟,imo,编码就像写数学公式。你可以在你的 cmets 中尽可能地冗长,毕竟编译器会忽略它们。
            • @Kensai:我完全同意 4thspace,没人知道你有多聪明,但显然你没有你想象的那么聪明。您只是忘记了您主要是为其他程序员编写代码,而不是为编译器编写代码。程序员将同时阅读 cmets 和代码,并且总是让两者都说完全相同的事情并不容易。有时您甚至可以编写 cmets 来说明您真诚地相信您的代码在做什么,而仅仅一个拼写错误会使代码执行完全不同的事情。最安全的解决方案是根本不输入 cmets,而是让代码足够清晰,不需要它们
            • 你们显然喜欢冗长的方法。我不。就这样。我喜欢优雅的代码。丰富简洁的cmets总能给同道的程序员讲解。
            【解决方案12】:

            我的规则是说出你的意思。我看到人们出错的一种常见方式是“降低力量”。基本上,他们用似乎跳过步骤的东西代替了他们正在考虑的概念。不幸的是,他们在代码中遗漏了概念,使其更难阅读。

            例如,改变

            for (int i = 0; i < n; i++)
                foo[i] = ...
            

            int * p = foo, q = foo+n;
            while ( *p++ = ... < q );
            

            是一个似乎可以节省步骤的强度降低示例,但它忽略了 foo 是一个数组这一事实,从而使其更难阅读。

            另一个常见的方法是使用 bool 而不是枚举。

            enum {
                MouseDown,
                MouseUp
            };
            

            就这样

            bool IsMouseDown;
            

            忽略了这是一个状态机这一事实,使代码更难维护。

            所以我的经验法则是,在你的实现中,不要深入到比你试图表达的概念更低的层次。

            【讨论】:

            • 我认为这是一个很好的答案,这些都是很好的例子。
            【解决方案13】:

            我认为有几点决定何时停止优化:

            • 值得花时间进行优化。如果有人花费数周时间却一无所获,是否可以更好地利用这些资源?

            • 优化优先级的顺序是什么。当涉及到代码时,人们可能会关心几个不同的因素:执行时间、执行空间(运行和编译的代码)、可扩展性、稳定性、实现了多少功能等。其中一部分是交易脱离时间和空间,但它也可能是一些代码的去向,例如中间件可以执行即席 SQL 命令还是应该通过存储过程路由以提高性能?

            我认为主要的一点是大多数好的解决方案都会有一个适度

            【讨论】:

              【解决方案14】:

              一般来说,我让事情变得显而易见且易于使用。如果简洁/简短在这方面对我有用,那就更好了。简短的答案通常是最清楚的,所以简短是显而易见的副产品。

              【讨论】:

              • 对不起,我完全不同意,正如 OP 中所讨论的那样。简洁的代码“可以”更容易理解,但通常更难。
              • “简洁”意味着删除所有多余的东西。所以,对我来说,简洁意味着清晰,因为唯一可以消除的就是分散注意力。
              • 我的目标是显而易见。通常,显而易见的代码是简明扼要的。
              【解决方案15】:

              对小代码足迹的需求是汇编语言和第一个稍微高级的语言时代的倒退……小代码足迹是真正迫切需要的地方。但是,这些天来,它并不是必需品。

              也就是说,我讨厌冗长的代码。在我工作的地方,我们编写的代码尽可能像自然语言一样阅读,没有任何额外的语法或单词。我们不会缩写任何东西,除非它是一个非常常见的缩写。

              Company.get_by_name("ABC") 
              makeHeaderTable()
              

              和我们一样简洁。

              【讨论】:

                【解决方案16】:

                需要在简短的源代码和性能之间取得平衡。如果它是不错的源并且运行速度最快,那么很好,但对于不错的源,它像狗一样运行,那就糟糕了。

                【讨论】:

                  【解决方案17】:

                  没有明确的界限可以区分 glib 的代码和华丽的代码。用你最好的判断。让其他人查看您的代码,看看他们理解它的难易程度。但请记住,正确性是第一目标。

                  【讨论】:

                    【解决方案18】:

                    您可以通过查看冗余并将其消除或通过聪明来使代码更小。做前者而不是后者。

                    【讨论】:

                      【解决方案19】:

                      我试图达到某种程度的冗长,使我的程序语句读起来像任何程序员都能理解的句子。这确实意味着要对我的代码进行大量重构,使其成为故事的一小部分,因此每个动作都将在单独的方法中进行描述(更进一步的层次可能是另一个类)。

                      意思是我不会仅仅因为可以用更少的字符来减少我的字符数。这就是代码高尔夫比赛的目的。

                      【讨论】:

                      • +1:代码有意义。软件是知识获取。软件是一种组合,就像证明依赖于引理和公理一样。
                      • 调试也有话要说。较短的代码可以消除您想要放置断点的区域,这是一个缺点。
                      • 如果您不构建 API,请不要担心长函数名。拥有带有长描述性名称的短(代码行)函数,您会惊讶于您的代码是如何“自我记录”的。 (如果你正在构建一个 API,或者任何不是“工作函数”的东西,你还需要尊重那些必须输入你的函数名称的人)
                      • @4thSpace:非常真实!我最喜欢的函数是DoNothing(),它在空的else 语句中充当调试断点持有者。
                      猜你喜欢
                      • 2011-06-17
                      • 1970-01-01
                      • 2013-10-29
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-04-25
                      • 1970-01-01
                      相关资源
                      最近更新 更多