重构以更高的LOC结束是否有意义?[关闭]


25

在某些情况下,比起更简洁的代码,更冗长的代码(如更逻辑的语句)更干净吗?



18
当然可以。即使消除重复,定义新提取函数的代码也会占用自己的空间。编写新函数可能需要四行,而只保存两行,但这仍然是值得做的事情。
凯莉安·佛斯

5
“更简洁的代码”?我真的很讨厌这样一种误解,即行数越少意味着代码越“好”。没有。实际上,通常是相反的。有一点很重要-到达的速度非常快-在越来越少的空间中塞满越来越多的含义使代码难以理解。实际上,有一场完整的竞赛-国际混淆C代码竞赛 -许多优胜者依靠人类理解的那些极限来编写难以理解的代码。
安德鲁·亨利

1
您的问题的标题和问题本身就是在问不同的问题。例如,可以将if语句更改为逻辑上相同但只有1行的三元表达式。
曼队长

1
-1 ***更详细的代码(如更多的逻辑语句)***冗长和逻辑语句的数量是两个不相关的事物。更改定义是不好的形式。
Pieter B

Answers:


71

为了回答这个问题,让我们以发生在我身上的真实世界为例。在我维护的C#库中,我有以下代码:

TResult IConsFuncMatcher<T, TResult>.Result() =>
    TryCons(_enumerator) is var simpleMatchData && !simpleMatchData.head.HasValue
        ? _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
        : _recursiveConsTests.Any() 
            ? CalculateRecursiveResult() 
            : CalculateSimpleResult(simpleMatchData);

与同龄人讨论时,一致的结论是,嵌套的三元表达式以及对的“巧妙”使用会is var导致简洁但难以阅读的代码。

因此,我将其重构为:

TResult IConsFuncMatcher<T, TResult>.Result()
{
    var simpleMatchData = TryCons(_enumerator);

    if (!simpleMatchData.head.HasValue)
    {
        return _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
    }

    return _recursiveConsTests.Any() 
        ? CalculateRecursiveResult() 
        : CalculateSimpleResult(simpleMatchData);
}

原始版本仅包含一个带有隐式的复合表达式return。现在,新版本包含一个显式变量声明,一个if语句和两个explicit returns。它包含更多的语句和更多的代码行。但是我咨询过的每个人都认为它更易于阅读和推理,这是“干净代码”的关键方面。

因此,您的问题的答案是一个明确的“是”,比简洁的代码更冗长的代码更简洁,因此是有效的重构。


34
在当今时代,开发人员的大脑比磁盘,CPU,RAM或网络带宽稀缺。那些其他事情很重要,在某些应用程序中它们可能是您的限制因素,但是在大多数情况下,您希望针对开发人员首先理解代码的能力进行优化,然后再优化其他事情。
anaximander

2
@anaximander,绝对同意。编写代码,供其他人首先阅读,其次是编译器。这就是为什么我觉得让其他同伴查看我的代码(即使我是唯一开发它的人)很有用的原因。
David Arno

4
如果我正在对此进行审查,则建议反转return语句的顺序并!从条件中删除。我也建议将第二个收益放在else。但是即使如此,它还是一个巨大的进步。
Martin Bonner

2
@DavidArno我看到了这种逻辑,如果if (!foo.HasValue)在您的代码中是一个惯用语,则更是如此。但是,这if并不是真正的提前退出-它是“取决于”。
Martin Bonner

2
@fabric布尔值的比较是危险的。我会尽量避免。
Martin Bonner

30

1. LOC与代码质量之间缺乏相关性。

重构的目的是提高一段代码的质量。

LOC是一个非常基本的指标,有时与一段代码的质量相关:例如,具有数千个LOC的方法可能会出现质量问题。但是,应该指出,LOC并不是唯一的度量标准,并且在许多情况下缺乏与质量的相关性。例如,4 LOC方法不一定比6 LOC方法更具可读性或可维护性。

2.一些重构技术包括添加LOC。

如果您列举了一系列重构技术,则可以轻松地发现那些有意添加 LOC的技术。例子:

两者都是非常有用的重构技术,并且在考虑是否使用它们时,它们对LOC的影响是完全无关的。

避免使用LOC。

LOC是一个危险的指标。它非常容易测量,并且很难正确解释。

在您熟悉代码质量测量技术之前,请首先考虑避免测量LOC。大多数情况下,您不会获得任何相关信息,并且在某些情况下,它会误导您降低代码质量。


您重构了答案,并通过添加更多拍品(文字行)来提高质量:p
grinch

12

如果您想查看仅使源代码的字节数或LoC数最小化的最终结果,请查看提交给Stack Exchange Code Golf网站的提交。

如果以这种方式减少源代码,您很快就会陷入混乱。即使您是编写此类代码的人,并且当时对它完全了解,但六个月后返回时,您的效率如何?没有证据表明这样的最少代码实际上可以更快地执行。

代码的编写方式应使您团队中的任何成员都可以查看它,并立即了解它在做什么。


也许是多余的,但只是说明一下;如果您重构高尔夫代码以提高可读性,那么您总是会得到更多的LoC
JollyJoker

1

是的,重构肯定会导致更多的代码行。

IMO最常见的情况是,当您使用非通用代码并使之更加通用/灵活时。轻松地生成代码会使代码行显着增加(有时增加两倍或更多)。

如果您希望新通用代码被其他人(而不是作为内部软件组件)用作库,那么通常您最终会添加单元测试代码和代码内文档标记,这将再次增加代码行。

例如,这是每个软件开发人员都会遇到的非常常见的情况:

  • 您的产品需要在两周内提供紧急的高优先级新功能或错误修复或增强功能(或在您认为项目大小/公司规模/等重要的任何时间范围内)
  • 您会努力工作并按时交付XYZ,它就可以正常工作。恭喜你!做得好!
  • 在开发XYZ时,您现有的代码设计/实现并不真正支持XYZ,但是您可以将XYZ填充到代码库中
  • 问题是,填充程序很丑陋,并且具有可怕的代码气味,因为您做了一些棘手的/聪明的/丑陋的/不好的做法,但有点工作
  • 当您以后找到时间时,可以重构代码,这可能会更改许多类或添加新的类层,并且您的新解决方案“正确”,并且不再具有不良的代码气味...但是, “正确的方式”现在占用更多的代码行。

我想到了一些具体的例子:

  • 对于命令行界面,您可以有5000行if / else-if代码,也可以使用回调...每个回调都小得多,并且更易于阅读/测试/验证/调试/等,但是如果您计算编写丑陋的5000行if / else-if代码可能会更小
  • 对于支持N种处理方法的处理代码段,您可以再次使用看起来最丑陋的if / else语句。
    • 或者您可以切换到更好/更好的回调,但是回调需要更多的代码行(尽管仍然是编译时)
    • 或者您可以进一步抽象并制作可以在运行时更改的插件。插件很好,因为您不必为每个新插件或对现有插件进行修改而重新编译主产品。并且您可以发布API,以便其他人可以扩展产品。但是,插件方法再次使用了更多的代码行。
  • 为GUI创建一个很棒的新窗口小部件
    • 您或同事注意到,新的小部件非常适合XYZ和ABC,但现在该小部件已紧密集成,仅适用于XYZ
    • 您重构了窗口小部件以使其同时适用,但是现在总代码行增加了
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.