减少代码中的行数有多重要?


85

我是从事J2SE(核心Java)的软件开发人员。
通常在我们的代码审查期间,我们被要求减少代码中的行数。

这并不是删除多余的代码,而是遵循一种专注于用更少的代码行来完成相同事情的样式,而我相信即使要增加行数,代码也要清晰。

您认为正确的做事方式是什么?
如果LOC(代码行)很小,它将如何影响代码?如果LOC是一个较大的数字,它将如何影响代码?

网站上的示例:“ javaranch”-

public static void happyBirthday(int age)
{  
    if ((age == 16) || (age == 21) || ((age > 21) && (((age % 10) == 0) || ((age % 25) == 0))))        
    {
        System.out.println("Super special party, this year!");
    }
    else
    {
        System.out.println("One year older. Again.");
    }
}

VS

public static void happyBirthday(int age)
{

    boolean sweet_sixteen = (age == 16);
    boolean majority = (age == 21);
    boolean adult = (age > 21);
    boolean decade = (age % 10) == 0;
    boolean quarter = (age % 25) == 0;

    if (sweet_sixteen || majority || (adult && (decade || quarter)))
    {
        System.out.println("Super special party, this year!");
    }
    else
    {
        System.out.println("One year older. Again.");
    }
}

63
我可以将任何Java文件转换为一行代码(s/\n/ /g),这并不意味着它甚至可以远程读取
棘手的怪胎

6
您的公司是否使用LOC来衡量生产力,因此他们正试图阻止您使用其编码标准来“操纵系统”吗?
JeffO

29
如果您可以提供每种样式的简短示例(不是摘自),那将真的有帮助,因此每个人都清楚我们在说什么。双向都有极端。答案将高度依赖于您的上下文。
丹尼尔·B

3
曾经打扫过你的房间,然后你的母亲进来说:“那不干净”,并指出了你没有收拾的十件事。基本上,这就是他们在代码审查中告诉您的内容。
Reactgular 2013年

11
您提供的示例几乎是Introduce Explaining Variable重构的教科书版本,通常可以提高可读性和意图(这是一件好事)。有人认为您应该将变量进一步重构为短的单行函数,但这将其推向了极端。我想说您的版本比该评论推荐的短版本更好。
Daniel B

Answers:


75

度量的问题,无论其意图如何,都在于衡量项目的重要性,而必然的结果就是,不衡量项目的行为就变得无关紧要。衡量重要的是绝对重要的,而不衡量不重要的是绝对必要的。

衡量SLOC(实际上是您的评论正在做的事情),使SLOC很重要。...SLOC重要吗?-绝对不会,永远不会(在混淆编程竞赛之外),永远不会在商业组织中。

问自己一个简单的问题-“减少此例程的SLOC”如何使任何人的代码更好。在这种情况下,可能发生的情况是将SLOC用作衡量复杂性的幼稚方法。您必须不惜一切代价避免计算易于计数的bean –客观指标(例如SLOC),而不是计算重要但难以计数的bean –例如可读性,复杂性等。


33
尽管OP对复审的描述听起来有些毫无意义,但我想说代码行通常与您提到的更难的措施有关。长函数通常不那么可读,并且通常也具有较高的圈复杂度。因此,这实际上取决于审查是否实际上建议分解/缩短将从中受益的代码,或者只是建议内联多个合法行。
Daniel B

3
我要说的是,减少代码行数很重要的原因是能够在单个页面上查看更多的功能。在无需滚动的情况下查看方法或类越容易,在上下文中维护上下文就越容易。
CLandry

2
@DanielB长函数通常更难缠头,不是因为它们长。但是,因为他们试图一次做很多事情。例如,它们通常从输入验证开始,然后进行一些处理,然后检查替代处理,再进行另一次检查以查看是否需要更新不相关的内容,然后执行与主操作无关的内联例程(例如检查月份是否超支并进行调整的日期逻辑)等等。到结束时,您已经不记得上课的责任了。
Edwin Buck

1
@CLandry:通过使其适合一页来维护上下文是减少SLOC的非常不好的原因。当然,如果代码布置合理并且易于阅读,则更容易维护上下文。-什么是2500或1000像素的“页面”?我有2 * 30英寸的纵向监视器,但有时会在笔记本电脑上进行开发
。– mattnz

4
显示(ref a)LOC === Bug的研究一毛钱。这是众所周知的事实。(据我所知)尚未显示(参考b)“减少代码库中的LOC ===减少该代码库中的错误”。用外推(参考a)​​声明(参考b)是不科学的。发表证明或反对这种关系的论文将是。
mattnz

84

我同意您的代码审阅者的意见,但带有星号。您在代码中编写的每个语句都是技术责任–这是潜在的失败点。如果您用10条语句编写一种方法,而您的同事用5条语句编写实现相同功能的方法,则按问题可能性衡量,他的方法可能会“更好”(错误代码过多的地方是错误的两倍)复杂或有问题的)。

不过,这是星号。这与想法中的实际代码行数无关,因为您可以通过以下方式减少行数:

void someMethod() {   
 someobject.doSomething(someSingleton.getInstance().with().a().lot().of().law().of().demeter().violations()).and().if().that().werent().enough().theres().more();
}

这是一行代码,但是在这里可能发生很多错误。因此,我想说的是专注于以最少的语句完成最多的工作-根据需要编写尽可能多的代码,而无需完成更多工作。至少,我认为这就是您的代码审阅者所追求的目标。

就个人而言,我认为有一个平衡点。就像我说过的那样,您编写的每条语句都是一种责任,但是如果提取具有描述性名称的局部变量会使您的方法更清晰,更易读,那么也有理由这样做。我认为您可以轻松进入人们对相对较小的美学差异感到困惑的情况,但总的来说,我认为您的审稿人有正确的想法-希望将可能出错的事情减少到最少。


4
同意-将语句的数量减少到一定程度可能是有用的,但是,如果代码审查想要减少语句的数量,他们不是会说“较少的语句数量”而不是“较少的行数”吗?码”。
mattnz

1
@mattnz仅用于确定他们是否正在做书。
Dan Neely

2
以我的经验,可以用更少的语句编写相同算法的人会:a)使用不太常见或不太了解的东西,以及b)引入更多需要单元测试的边缘情况,并可能引入错误。当然,这假设两个程序员的能力大致相同。
Daniel AA Pelsmaeker

13
+1(幽默长的函数调用链)和后面的狡猾双括号violations()
Joe Z.

5
100%+1,所以很多人不了解他们添加到代码库中的每一额外代码的后果,这是人们真正需要知道的事情。
吉米·霍法

32

接受评论者的建议从字面上看是没有用的,因为显而易见的直接结果是促进了简洁的单线(尽管行长受到限制)。我相信,这里要学习的教训是使您的代码减少工作量

换句话说,这是对简单性的要求。相当普遍的说法是代码是一种责任,而不是资产,因此在保留功能的同时减少其数量是一项艰巨的努力。这可以通过直接,更扎实的方法来实现,该方法可以直接解决问题,并希望使用简洁的解决方案。

就像肯·汤普森(Ken Thompson)曾经说过的那样:我最富有成效的一天之一是扔掉了1000行代码


21

我倾向于同意“即使在代码增加的情况下也要保持代码清晰”的立场。

我已经看到了太多简洁的单线纸,但是现在还不清楚它们在做什么。可读性为王,因为其他开发人员必须维护您的代码。

我认为,针对的更好的方法是简短的方法。为了几行代码而不是简短,而是因为它们只做一件事情就简短。


12

我目前在一家大型公司担任高级应用程序开发人员和项目业务分析师,而我的开发工作从未成为关注的中心。但是,我相信代码越简洁,BUT就越好,但它不会以快速分析和纠正(或添加)为代价。对我来说,当您负责关键业务应用程序时,必须具有广泛的可伸缩性,并且能够在不间断的不断变化的环境中进行即时更改,简洁,易于阅读的代码是开发中最重要的元素之一。归功于Erik Dietrich的回复,这是:

void someMethod() {   
someobject.doSomething(someSingleton.getInstance().with().a().lot().of().law().of().demeter().violations()).and().if().that().werent().enough().theres().more();
}

对我来说是完全不可接受的,但是,我发现更改了以下公司的所有现有代码:

if (boolean == true){
value.prop = option1;
}
else{
value.prop = option2;
}

至:

value.prop =  boolean ? option1 : option2;

是一个出色的代码压缩选择,并且不会牺牲可读性。

至于它如何影响代码?我从来没有注意到性能提高或降低(例如100行代码)。一个简单的事实是,到达最终产品所用的流程比到达最终产品所需的生产线数更多。我看到一些编写的过程非常紧凑,但是效率很低,与较长的代码和具有更好的代码流的性能不同。


您的意思是value.prop = boolean ? option1 : option2;
ChristofferHammarström,2013年

我做!...还是在“压缩代码”上。
Joshua Volearix

2
您的第二个示例特别好,因为它不仅更简单,而且还使您更加清楚,这是两个选项之一的赋值,没有副作用。在if-then-else掩盖这一点; 例如,在的每个分支中分配一个不同的变量太容易了if(这可能会也可能不是一个错误,但是很难发现)。
Andres F.

我遇到了明确禁止使用三元运算符的环境。通常,它们是从PL / SQL过渡到类似于Java的环境,人们担心它们太笨拙了。关于您声明编写更多的代码不会对性能产生影响,可能取决于代码是什么。例如,如果用方法调用替换运算符,肯定会产生影响(并且可能会产生严重影响)。
jwenting

9

IMO,通过琐碎的LOC计数来衡量代码有效性是一个坏主意。正确设计有效代码的要素还有很多。

以我的经验,有效的代码:

  • 不会违反任何SOLID原则
  • 可读性强,不言自明
  • 通过了爱因斯坦(Albert Einstein)的简单性测试:“一切都应尽可能简单,但不要简单。”

1
爱因斯坦报价为+1。
Justsalt

6

这里有很多答案可以解决降低LOC的技术利弊,以及它是否是有意义的高质量软件指标。这不是这个问题的意思。它的目的是如何应对那些坚持天真的教条主义遵守特定经验法则的管理。

令人遗憾的是,当人们在适当的上下文中使用并务实地应用好建议时,将其束之高阁,将它们从该上下文中移出,并在教条化地应用它们,而首先却没有意识到建议所要解决的问题。

关于降低LOC的建议的目的是避免创建试图一劳永逸的方法,并阻止创建“神类”,因为“神类”对设计的某些方面了解太多直接责任以及系统中所有其他类别所依赖的。较短的代码的另一个优点是它更具可读性,尽管正如您所指出的那样,您可以将其过度使用,以至于实际上开始损害可读性。

低LOC计数具有明显的优势(小方法比大方法更容易适应您的需要,代码中更少的内容意味着更少的出错地方,等等),但是它也受制于收益递减法则。将150行方法重构为20行方法比将10行方法重构为7行方法要大得多。

当这种重构以良好软件设计的其他方面(例如可读性)为代价时,您就可以证明不这样做是合理的。删除赋予代码含义的上下文变量,然后将其替换为没有含义的文字,这是非常非常糟糕的事情。好的代码几乎没有文字。但是,这些变量(和命名的常量)是不直接对程序起作用的代码行,因此,如果LOC被视为某种神灵而被崇拜,则此类澄清行将面临极大的危险,因此无法获得快速的成功。管理层的一些误导性表扬。

我相信您足够聪明,可以意识到这一点,实际上,这几乎就是您最初提出的问题的重点。问题不是您了解什么时候代码缩减是好的,什么时候不好,问题在于教条主义在不加选择地应用通常是合理的做法。

我建议您花些时间与您的管理层聊天,解释您的职位以及为什么您觉得被要求执行的操作会损害代码而不是帮助代码。尽量避免对抗,但在讨论中要保持理性和镇定。管理层必须了解编程是一项务实的活动,并且最佳实践建议仅在以务实的方式加以应用时才有用,这一点很重要。最佳实践写在书上,而不是刻在石头上,当发生冲突(短代码与可读代码)时,程序员应自行决定遵循哪种最佳实践。希望他们是喜欢这种输入的有理智的人。

您还需要有一点勇气,因为如果您被迫在您认为没有必要或不适当的地方降低LOC的压力,那么您自然会为了安静的生活而进行更改,这是很自然的。您需要拒绝这样做,并且您必须“拥有”该决定。在管理层合理的情况下,您不必完全遵循他们的准则,但是您应能够辩解任何不合理的情况。

令人遗憾的是,人们可能会变得不理智,尤其是当人们在啄食顺序较低的人群中质疑自己的决定和对您施加的规则时。他们可能选择不合理。您也需要为此做好准备。如果您可以证明LOC最佳做法与其他最佳做法直接冲突以及为什么这会损害产品的情况,并且可以在他们很少或根本没有个人参与的部分代码库中这样做(如果这样做,则不会)似乎不是对其工作或受其监督的工作的人身攻击),那么这可能有助于加强您的论点。同样,您必须准备以一种冷静,理性的方式为自己辩护,并能够“拥有”您所做的论据。

如果您的管理人员是合理的人,那么他们必须感谢您所说的是有道理的,如果您能提供证据支持您的主张。


2

我认为您确实应该努力使具有少量SLOC的功能。

如果LOC(代码行)是一个小数字,它将如何影响代码;如果LOC是一个较大的数字,将如何影响代码?

理想情况下,一眼就能理解8行代码比一眼理解30行代码要容易。

这并不意味着在8行中压缩30 LOC更容易理解。

您认为正确的做事方式。

通常在函数中,我尝试按抽象级别(“此处输入IO代码”,“此处验证”,“此处计算”等)将其分组。

然后,我将其分成块,并用空白行分隔。如果代码多于十行,则将每个块提取到一个不同的函数中(无论如何,对于出现多次的代码,我都会这样做)。我曾听到过有关以这种方式破坏性能的争论(不必要的函数调用),但实际上,我从未遇到过由此引起的性能瓶颈。

就是说,我已经完成了提取的功能,此后该功能的长度约为40行(C代码)。如果代码尽可能地分组,那么较长的函数不会出现问题。


2

我认为,专注于干净,自动记录的代码比LOC更重要。不过,我真的不喜欢您的示例,因为它解释了代码在做什么,而没有说明原因。例如,这:

boolean sweet_sixteenteen =(年龄== 16);

是非常多余的。任何阅读“年龄== 16”的人都知道这一点。我宁愿这样写代码:

public static boolean companyShouldThrowABigParty(int age) {
    return (age == 16) || (age == 21) || ((age > 21) && (((age % 10) == 0) || ((age % 25) == 0))); 
}

public static void happyBirthday(int age)
{  
    System.out.println(companyShouldThrowABigParty(age) ? "Super special party, this year!" : "One year older. Again.");
}

决定何时举行聚会的逻辑与System.out分开,可以进行测试,并且很容易理解。但是,更重要的是,阅读代码的人可以理解以这种方式编写代码的原因(“公司希望为某些人举办盛大的聚会”)。


2
甜蜜的十六岁(和21岁)的意义是特定于文化的。短语“十六岁”比“年龄== 16”更容易搜索。对于那个原因,给人的名字一定布尔值可能是有用的。不过,我同意您的一般观点:不要浪费时间解释不言自明的代码。
JonasKölker2013年

1

我认为更少的代码行=更具可读性的代码

但是,当然,当您开始缩小/模糊代码以减少行数时,存在一些限制。

/** Pad a number with 0 on the left */
function zeroPad(number, digits) {
    var num = number+"";
    while(num.length < digits){
        num='0'+num;
    }
    return num;
}

这是最小化,逻辑保持不变,只是可读性较低。这不应该由人类来完成,这种缩小是由机器来完成,然后由机器读取。

function zP(e,t){var n=e+"";while(n.length<t){n="0"+n}return n}

如果您可以删除一些代码,并且算法仍在执行应做的工作,那么请继续。只是不要减少您的代码,有更好的工具可以做到这一点。


1

我认为更少的代码行==更具可读性的代码。但是,与理论有很大不同的现实是,编写大量行的代码通常没有经过适当的设计。因此,对更少行的要求可能会迫使某些程序员在有能力的情况下提出更好的设计。不同之处在于,许多程序员都不是,那么要求并没有太大帮助。


1

在正常情况下,我认为行数不是问题,但是它可以指出问题。如果有人向您展示了一个包含1000行代码的类,则该类的完成或设计方式一定存在问题。

您的示例确实指出了一种情况,其中需要使用更多行代码。但这就是那个例子。每天我都会看到示例,其中行数与计划不足有关


0

我认为,LOC是项目开始时比实际实施中更有用的指标。了解每个功能点LOC,您可以估算项目的工作量,并据此估算项目所需的时间以及最佳的开发人员数量。

它还可能影响设计和语言选择:减少功能点或切换到LOC / FP较低的语言应减少项目工作量,而其他所有方面都是相同的。


0

代码行本身不是很重要。一种查看方式是将其与散文进行比较。第一个认识是代码和散文的重要属性(假定正确性)是可读性。可读性(和可理解性)有助于其他属性,例如可维护性和正确性。

能够在少量的行中拟合函数具有优势。但是,文本不带段落会降低其可读性。使用困难的概念,困难(稀有)的单词和复杂的表达方式通常会减少表达一个想法所需的单词数量,但同时将文本的阅读级别从中学级别提升到专业学者(在散文)。

通常,在您的代码中添加抽象并使用助手等会很有帮助。但是同样,这些抽象可能会变得太多。还可能发生的是将复杂性转移到代码的另一部分。有时,例如当您作为专家来设计供初级程序员(或学生)使用的框架/库时,这样做是个好主意。但是不要指望初级人员能够理解您的代码是如何工作的,只是让他们很难正确地使用它。

编写代码时,尤其不要回避在代码中添加空行。它们用作段落,可以帮助您将函数的不同部分分开(即使它们不应该被放入助手中)。


-1

每一种形式化代码评估方法的最大问题是,它肯定会在某些代码上失败。这是因为编程是一种艺术,因此,不存在明确的评估标准。当然,还有不同种类的艺术-绘画的大量生产也存在,也许在这个行业中,在一张绘画上花费多少油漆很重要。:)


-1

老实说,我对LOC的测量不抱有任何疑问。当然,函数或过程尽可能短是一件很不错的事情,但是我会在一天中的任何时候都将可读代码放在较短的位置。


-2

我同意始终要求降低LOC会导致代码难以阅读。

但是,也许您的编码风格过于冗长,而您的审阅者认为更简洁的方法更好。例如,由于清楚选择了变量名,仅能解释一个显而易见的语句的注释是没有用的。


5
据我所知,评论不属于LOC。
mhr

1
根据您使用的定义,它不计数或计数。
MatthieuW,2013年

1
评论是评论。他们不是代码。因此,它们不适用于LOC计数。尽管自记录代码比注释良好的代码更好,但是从不那么明显的代码中删除注释对任何人都没有帮助。
GordonM

-2

代码行只衡量一件事,那就是您拥有的代码行数。其他一切都是热空气,投机和偏见。

其他答案中有很多很好的例子,更少的代码行会如何使事情变得更糟,而不是变得更好,但是似乎遗漏了一个核心要点,那就是:您实际上需要多少行才能完成这项工作?

如果完成您的任务需要10行代码,那么就分10行执行。如果完成它需要10,000行,那么同样地,您也需要10,000行。如果您使用1,000或2,000或其他代码,“更少的代码行”的崇拜将不会使后面的示例更好。这项工作需要 10,000行,而这10,000行可能包含验证,错误检查,安全性等层,如果您减少工作量,则会丢失这些层。

编辑

由于这引起了一些反对,我想我需要在这里说的更具体。任何人都应该做的第一件事就是读这篇文章 -我要你摆脱的一点是,您编写的高级代码可能与实际执行的机器代码几乎没有相似之处。这一点的相关性是误导了对高级代码的关注,而不了解其下实际发生的情况。

现在考虑以下几点:

  • 仅用一行就可以编写非常糟糕的慢速代码-请注意在我提供的链接末尾有关三元运算符的注释。

  • 如果一行代码进行API调用(或对外部库的其他调用),那么按照定义,您几乎无法直接控制执行的内容或执行的效率。

  • 错误检查,清理等都增加了额外的代码行,而且我敢肯定,即使是最热衷于更少代码行的人也不会反对这些代码。

所以-代码行是一个坏指标。更少的代码行不能保证额外的性能-API或库调用是一行,并且可能超出您的控制范围。更少的代码行并不能保证额外的鲁棒性-错误检查和清除总是需要额外的行。更少的代码行甚至不能保证额外的可读性或可维护性-您只需要查看IOCCC即可知道这一点。

那么,更少的代码行能保证什么呢?更少的代码行,仅此而已。

专注于完成2,000行而不是10,000行的相同工作是非常错误的。相反,应将重点放在有效的,健壮的,在可接受的公差范围内执行并且易于阅读和维护的代码上。 有时这意味着您可以在较低的LoC计数中进行操作,有时这意味着您必须在较高的LoC计数中进行操作,但是LoC计数在这里并不重要。


1
根据定义,如果一项任务绝对需要N行代码才能完成(一开始很难确定),那么它就不能少于N行。因此,您的10,000行任务无法在2,000个周期内完成。我猜想OP谈论的是存在一些回旋余地的情况,即“无论哪种方式都可以完全满足要求,那么哪个更好?”
Andres F.

-3

减少代码中的行数有多重要?在大多数情况下,根本没有。实际上,在大多数情况下,通过将复杂的操作分成更易读的步骤,并注释每个步骤以及总体上添加注释,以使代码更易于阅读和扩展,从而增加代码行数更为重要。追随您的开发人员。


1
为什么所有的反对票?
Marko

是的,为什么一个完全明智的答案被否决了?为什么还有其他完全明智的答案,所有这些都挑战了减少代码行本身就是目的的想法,也被否决了?
Maximus

1
@ mh01我猜是因为这其中的大部分是错误的?具体来说,in most cases, it is more important to increase the number of lines of code by breaking out complex operations into more readable steps完全不是我的经验。通过使复杂的代码更小,更简单,通常可以使它更易读和更容易出错,因为对于那些刚接触该语言/不熟悉该问题/不确定自己在做什么的人来说,编写复杂代码会变得很复杂。
Izkata

-5

在较早的时期中,假设loc的代码行数较大,则该代码有效,并且可以完成它用来完成的所有任务,但是一段时间后才意识到,loc越少,它就越多。由于系统执行代码所花费的成本非常少,因此具有较低的效率。因此,为了使系统loc更好,应减少它的数量。从那时起,假定loc应当更少。应该考虑在内。

  1. 制作问题流程图
  2. 尽量减少循环次数
  3. 函数调用不应该太多
  4. 在使用堆栈或队列存储相关信息的情况下,应使用新的数据结构(如TRIE)。
  5. 并尝试用一种现实的方法而不是一种想象的方法来解决问题,在这种方法中,您将大量数字存储在一个非常大的数组中,然后尝试通过该数组访问它。
  6. 使用尽可能多的宏此外,使用的方法还取决于问题。如果确实很复杂,则有时使用简单的方法也等同于复杂的方法。

5
-1:哇!我认为您需要减少答案中的LOC!阅读它使我的眼睛受伤!
Jim G.

1
@JimG .:我同意答案会伤害我的眼睛,但认为最好通过增加LOC(例如,对每个编号的项目使用单独的一行)来解决。
布赖恩

这是自动格式化程序的错,在列表解决情况之前插入了一个空白行
Balog Pal
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.