在Java/C#/C++中编写简洁的代码有什么原因吗?

6

你是否曾经在Java、C#或C++中编写过精简的代码?

如果是,为什么呢?你认为在使用这些语言的情况下,是否存在可以接受这种做法的情况?


抱歉,我不是母语人士。"terse code" 是什么意思? - Grzenio
@Grzenio:它指的是没有使用大量字母、单词或行的代码。 - Welbog
3
在Java中编写简洁的代码是否可行? - f3lix
1
祝你在Java中写出简洁的代码,好运! :) - cletus
简洁的代码更好。只有愚蠢的情况才能证明相反。编写更短的代码会让你考虑简单的解决方案。 - Banjocat
简洁的代码是可怕的,是时候提出新的让人明确、描述并且有分寸的反驳来回答Banjocat在Stackoverflow上关于Yuval的问题是否编写简洁的代码可以接受(true)。标识符不应表达实现细节或封装上下文。这是我的两分意见。 - Coder Guy
12个回答

23

这取决于你对“简洁”的定义。

如果你指的是“简短明了”,那么它基本符合我对代码的理解。

如果你指的是“神秘难懂的”,那么就有问题了。


晦涩难懂是主观的。如果你在实现某个数学概念时使用与之一致的Unicode符号,那么这是理想的。然而,如果没有始终使用正确的符号,那么对于那些精通该数学概念的人来说,跟踪代码将变得困难。 - Coder Guy

16

代码应该尽可能简洁,但不要过于简短。

开玩笑的话,有几个因素会影响代码是否简洁:

  • 生命周期。

    • 通常比你想象的要长 :)
  • 出错的概率。

    • 这取决于许多因素,但原始编码人员在其中扮演了重要角色。
  • 计算机读取(解析)它。

    • 不仅是编译器,还有智能感知等。
  • 人类阅读它

    • 有时是原始的,有时候需要像diff工具之类的程序来帮忙。
    • 有时并非编写者本人。
  • 所需的性能特征。

所有这些因素都会产生一系列有时相互竞争的力量,这些力量可能会导致更多或更少的冗余。平衡这些力量是有效开发的关键。哪一个更重要完全取决于您的软件试图解决的问题。

首先让我们看看容易的部分:

计算机。

当计算机读取您的代码时,无论冗余程度如何,它们都可以做到。它们可能会慢一些,但这通常很难测量(您不太可能比最小理论可能性多1或2个数量级的冗余)。 值得注意的例外情况是,如果您正在(滥用)预处理器之类的东西来执行大量扩展的元编程,编译时可能需要很长时间。在这种情况下,您必须决定是否值得这种权衡。

人类。

通常,阅读代码的人都具有与您相似的上下文,并且他们将在类似于您编写代码时的情况下阅读源代码。这意味着如果函数在名为Foo的文件/类/模块中,则没有必要在各个地方都加上Foo,从上下文中应该很清楚Foo的方面。这样可以使以后更改此方面更容易。

熟悉您正在使用的编程语言/编程风格的程序员通常能够理解一些非常简洁的构造。例如,循环索引变量称为“i”,这是最简洁的方式,但在循环变得大时通常不会成为问题。
这里你可以看到一个有趣的二分法。简洁度的价值往往与其所在代码块的复杂性成正比。随着这个块变得更加简洁,其中的变量受益于被缩小。通过编写具有有限职责的函数/类来编写代码,可以更容易地保持简洁,因为人类的混淆范围较小。矛盾的是,这可能导致需要更明确的上下文,从而需要更长的方法和类名。

寿命

寿命和错误概率影响着您将必须阅读代码或调试它的频率。许多调试器支持在行上的多个点处设置断点(正确识别其中有两个语句的位置),但某些调试器不支持。因此,如果您打算经常在其中断点,请注意要确保能够最小化投入和控制这些断点。

如果代码出错的概率低但寿命长,则会出现另一种有趣的情况。当您需要更改代码时,代码可理解性的概率要低得多(您将拥有更糟糕的记忆或甚至不在那里)。因此,这段代码比正常情况下略微不太简洁。

性能

有时,为了满足性能目标,您可能必须牺牲某些东西的紧凑但清晰的表示方法,例如,您可能必须进行位打包,这绝不是阅读代码的好事情,但如果必须适应特定的内存量,则无法避免。 希望这样的情况很少发生。

常规概念

有些语言结构可以鼓励编写简洁的代码(例如自动属性、匿名内部类、lambda等等)。在合适的情况下使用这些概念,善加利用它们。其想法是它们可以减少模板代码并暴露“意图”。

如果你重复做同样的事情,并且存在一定数量的代码重复,考虑使用共享函数/类/模块。但要记住,如果必须使共享代码不太清晰(例如在其中一个代码路径中添加if语句或未使用的变量),那么您可能没有净胜利。
类型推断很强大,但请记住,编译器有时比人类更擅长。如果你在说flibble x = new flibble(),那么var x = new flibble()毫不费力(而且随着flibble变得更大,它会变得更好)。相比之下,var flibble = SomeMethodWhoseReturnTypeIsNotClear()则不同。常识在这里有帮助,如果你从不需要使用Intellisense来解决它,那么肯定应该考虑使用它。
以下是其他一些有用且简洁的经验法则:
- 在单行上执行多个操作通常会让人感到困惑。 - 副作用通常会让人感到困惑(++x或x++在概念上并没有任何区别,除非它们是更广泛表达式的一部分)。 - 缩进对于大多数人来说比括号更有助于推断结构。 - 优先级规则通常被人类“内化”,而不是记忆为一组规则。这意味着在惯用语很常见但使用情况不太常见的情况下,无谓的(对编译器来说)加括号可能会影响可读性,但在使用情况不太常见的情况下,加括号可能是有用的。 - 逻辑非通常是一个字符。在if语句中使用它时,请考虑是否可以重新构造以不需要它。这可能不可能(如果结果对变量/方法名称或代码顺序的扭曲超过了去除,则将其保留)。

1
它的长度正好是需要的那么长 :-P - TofuBeer

12

这取决于您所说的“简洁”具体指什么。我确实喜欢编写表达我想要实现的内容的简明扼要的代码。例如,我喜欢LINQ的方式,它让我表达数据管道,而不是以前编写循环来转换或过滤集合、查找最大值等的方式。那只是重复的代码,应该在某个模板方法中。

另一方面,较短的代码并不总是比较长的代码更易读。条件运算符在这方面引起了争议。是:

Foo x = null;
if (condition)
{
    x = y;
}
else
{
    x = z;
}

比起下面的代码,更易读或不易读:

Foo x = condition ? y : z;

如果“condition”、“y”和“z”都相当简单,那么条件运算符就胜出了。如果必须跳过许多环节才能使“y”和“z”成为单个表达式,在执行多个语句更可读的情况下,if/else形式很可能更易读。

简而言之,我会尽可能编写最易读的代码。这通常是简洁的代码,但并非总是如此。


我看看手表... 是喝杯茶的时间了。 - Richard

5

在编写实际的源代码时,尽可能做到强健(不影响性能)。例如:

var result = GetResultFromFoo(GetOtherResult()).DoSomeCalculation(CallAnotherMethod());

可能会很有趣,但是调试起来会很麻烦。没有任何好处,只需要将其简化为以下内容:

var result = GetOthereEsult();
var fooResult = GetResultFromFoo(result);
var anotherMethodResult = CallAnotherMethod();
var finalResult = fooResult.DoSomeCalculation(anotherMethodResult);

更易于调试。

我唯一能想到需要尽可能编写简洁代码的情况是,如果源代码的大小很重要(比如一个每秒被服务数百次的JavaScript文件),或者有意尝试混淆代码,但通常有软件可以为您完成这项工作。因此,总的来说,在我看来,实际上没有什么理由这样做。


4

尽量编写清晰的代码。有时清晰的代码很简洁,但通常不是。

为什么呢?因为在6个月之后,你需要理解自己当初想要实现什么目标。你越快理解清楚,就越好。


2
除了其他问题,更短的代码更好,因为你可以一次看到更多的代码。

2

请记住,代码被阅读的次数比编写的次数多,写作时要考虑读者(甚至可能是你自己)。不要像假定读者愚蠢一样编写代码,也不要编写假定代码越少越好的代码。

像Joel Coehoorn建议的那样,写得“简短明了”。


2

我发现,在长期看来,对于人类来说,易读性是代码中最重要的特征。

易读性包括简洁、准确和清晰。如果你把东西混在一起,会让读者感到困惑。如果你的代码易于阅读,就不需要太多注释。如果你将复杂的事情分解成本地的、命名良好的变量,你将极大地帮助读者,并隐含地记录下你所做的事情。

写得好的代码将流传下去。追求完美吧 :)


1

我非常喜欢可读性强的代码。我曾经看到过一些“简洁”的代码,看起来像这样:

int af = yb; 
while(af<ex){af++;af*=4;}

从编程角度来看,很容易看出正在做什么,但实际上在意义方面正在做什么是模糊的。我更喜欢有可读性的变量名称,而不是试图节省几个字符的代码并使用简洁的名称。好的代码并不总是最短的。好的代码涉及良好的算法、良好的文档和良好的可维护性。如果代码具备所有这些属性,我不在乎代码长度,它就是好的代码。


1

@j_random_hacker(还不能对评论进行评论)

我曾经遇到过这样的情况,就是在6个月后我发现很难解读我写的一段代码。因此,确实,这部分也很重要。


2
"谁写了这个难以阅读的垃圾代码"... (检查源代码控制) "哎呀,是我自己..." - Mario Ortegón
是的,我听说过一个名为“blame”的SVN函数,但直到现在都没有使用过它,它可以做到这一点。 - Adrian Pascalin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接