是否有可能在没有任何评论的情况下编写好的和可理解的代码?

时间:2009-04-24 02:00:00

标签: comments

任何人都可以建议在没有一行评论的情况下编写可以理解的优秀代码的最佳方法是什么?

20 个答案:

答案 0 :(得分:15)

阅读Code Complete, 2nd Edition封面以涵盖。也许两次。

提供一些细节:

  • 使代码可读
  • 消除代码重复
  • 在编写代码之前进行设计/架构

答案 1 :(得分:14)

我在大学时曾经有一位教授告诉我,任何优秀的代码都不需要任何评论。

她的方法是将非常精确的逻辑组合成具有非常描述性的方法/属性/变量名称的小函数。事实上,她提出的大部分内容都非常易读,没有任何评论。我试着对我写的所有内容做同样的事情......

答案 2 :(得分:7)

我喜欢'人性化'代码,所以代替:

if (starColour.red > 200 && starColour.blue > 200 && starColour.green > 200){
   doSomething();
}

我会这样做:

bool starIsBright;
starIsBright = (starColour.red > 200 && starColour.blue > 200 && starColour.green > 200);

if(starIsBright){
   doSomething();
}

答案 3 :(得分:6)

在某些情况下 - 是的,但在许多情况下没有。 部分已经被其他人回答了 - 保持简单,写得很好,给它可读的名字等等。当您在代码中解决问题时,部分就会出现根本不是代码问题,而是域特定问题或业务逻辑问题。即使它没有评论,我也没有问题阅读糟糕的代码。这很烦人,但可行。但是,如果不理解为什么它会像这样以及它试图解决什么,那么几乎不可能阅读一些代码。所以像:

if (starColour.red > 200 && starColour.blue > 200 && starColour.green > 200){
   doSomething();
}

看起来不错,但在程序实际执行的环境中可能毫无意义。我宁愿这样:

// we do this according to the requirement #xxxx blah-blah..
if (starColour.red > 200 && starColour.blue > 200 && starColour.green > 200){
   doSomething();
}

答案 4 :(得分:6)

编写良好的代码可能会消除评论的必要性,以解释您正在做什么,但您仍然需要评论来解释原因。

答案 5 :(得分:3)

如果你真的想要那么你需要在你的变量名和方法名中非常详细。

但在我看来,没有好办法做到这一点。注释在编码中起着严肃的作用,即使您是唯一一个编码,有时仍需要提醒您正在查看的代码部分。

答案 6 :(得分:3)

是的,您可以编写不需要注释的代码来描述它的作用,但这可能还不够。

仅仅因为一个函数在解释它的作用时非常清楚,它本身并不会告诉你为什么它正在做它的作用。

和所有事情一样,适度是一个好主意。编写解释性的代码,并写出解释其原因或做出假设的注释。

答案 7 :(得分:2)

我认为Fluent Interfaces的概念确实是一个很好的例子。

var bob = DB.GetCustomers()。FromCountry(“USA”)。WithName(“Bob”)

答案 8 :(得分:2)

Robert C. Martin的

Clean Code包含编写干净,易懂的代码所需的一切。

答案 9 :(得分:1)

使用描述性变量名称和描述性方法名称。使用空格。

让您的代码像普通会话一样阅读。

对比Junit中Matchers的使用:

assertThat(x, is(3));
assertThat(x, is(not(4)));
assertThat(responseString, either(containsString("color")).or(containsString("colour")));
assertThat(myList, hasItem("3"));

使用传统的assertEquals样式:

assertEquals(3, x);

当我查看assertEquals语句时,不清楚哪个参数是“预期的”,哪个是“实际的”。

当我看assertThat(x, is(3))时,我可以用英语读作“断言x是3”,这对我来说非常清楚。

编写自我记录代码的另一个关键是用明确的名称包装方法调用中不清楚的任何逻辑。

if( (x < 3 || x > 17) && (y < 8 || y > 15) )

成为

if( xAndYAreValid( x, y ) )  // or similar...

答案 10 :(得分:1)

我认为评论应该表达为什么,也许是什么,但代码应该尽可能地定义如何(行为)。

有人应该能够从代码中读取代码并理解它的作用(如何)。可能不明显的是为什么你会想要这样的行为以及这种行为对整体要求的贡献。

评论的需要应该让你停下来。也许你是怎么做的太复杂了,写评论的必要性表明了这一点。

记录代码的第三种方法是记录。一个充满了日志记录语句的方法可以做很多事情来解释原因,可以触及什么,并且可能会给你一个比命名良好的方法和行为变量更有用的工件。

答案 11 :(得分:1)

您通常可以将评论转换为函数名称,如:

if (starColourIsGreaterThanThreshold(){
    doSomething(); 
}

....

private boolean starColourIsGreaterThanThreshold() { 
    return starColour.red > THRESHOLD && 
           starColour.blue > THRESHOLD && 
           starColour.green > THRESHOLD
} 

答案 12 :(得分:1)

我不确定编写具有如此富有表现力的代码,以至于您不需要评论必然是一个很好的目标。在我看来,就像另一种形式的过度优化。如果我在你的团队中,我会很高兴看到清晰,简洁的代码,只有足够的评论。

答案 13 :(得分:1)

在大多数情况下,是的,您可以编写足够清晰的代码,使评论成为不必要的噪音。

评论的最大问题是无法检查其准确性。我倾向于在他的书第4章清洁代码中与鲍勃·马丁叔叔达成一致:

  

正确使用评论是为了弥补我们未能表达自己的意见   码。请注意,我使用了失败这个词。我的意思是。评论总是失败。我们必须   拥有它们是因为我们不能总是弄清楚如何在没有它们的情况下表达自己,   但他们的使用并不值得庆祝。

     

因此,当您发现自己处于需要撰写评论的位置时,请考虑一下   通过,看看是否有一些方法可以扭转局面并表达自己   码。每当你用代码表达自己时,你应该拍拍自己。一切   你写评论的时间,你应该做鬼脸并感受到你的能力的失败   表达

大多数评论要么是不必要的冗余,要么是彻头彻尾的谬误,要么用来解释写得不好的代码。我说,因为在某些情况下,语言缺乏表达性而不是程序员。

例如,通常在源文件的开头找到版权和许可证信息。据我所知,在任何流行语言中都没有已知的构造。由于简单的一行或两行注释就足够了,因此不太可能添加这样的构造。

大多数评论的最初需求已经被更好的技术或实践取代。使用变更日志或注释掉代码已被源控制系统所取代。只需编写较短的函数,就可以减轻长函数中的解释性注释。等

答案 14 :(得分:0)

我认为代码可以在很大程度上自我记录,我认为它至关重要,但阅读编写良好的代码就像用显微镜观察人体细胞一样。有时需要评论才能真正解释系统各部分如何组合在一起的大局,特别是如果它解决了一个非常复杂和困难的问题。

考虑特殊的数据结构。如果所有计算机科学家发表过关于数据结构的都是编写良好的代码,那么很少有人真正理解一个数据结构相对于另一个数据结构的相对优势 - 因为任何给定操作的Big-O运行时有时在读取代码时并不明显。这是文章中提出的数学和摊销分析的结果。

答案 15 :(得分:0)

我相信这是可能的,如果你考虑的事实不是每个人都喜欢相同的风格。因此,为了尽量减少评论,了解“读者”是最重要的事情。

在“信息系统”类软件中,尝试使用陈述句,尝试将代码行近似为英文行,并避免“数学编程”(使用i,j和k作为索引,以及 - 不惜一切代价去做 - 很多)。

答案 16 :(得分:0)

这可能不是评论,但是,为了帮助别人更好地理解它的作用,你可能需要一些解释程序应该如何工作的图表,因为如果一个人知道全局,那么理解代码会更容易。 / p>

但是,如果你正在做一些复杂的事情,那么你可能需要一些评论,例如,在一个非常数学密集的程序中。

我发现评论有用且重要的另一个地方是确保某人不会用看起来应该有效的东西替换代码,但不会。在这种情况下,我将坏代码留下并将其注释掉,并解释为什么不应该使用它。

因此,可以编写没有注释的代码,但前提是您在编写什么类型的应用程序时受到限制,除非您可以在某处解释为什么做出决定,而不是将其称为注释。

例如,随机生成器可以用很多方式编写。如果你选择一个特定的实现,可能有必要解释你选择那个特定发生器的原因,因为这段时间对于当前的要求可能足够长,但是后来的要求可能会改变,你的发电机可能还不够。

答案 17 :(得分:0)

在大多数情况下,我并不认为评论是个好主意。编译器不会检查注释,因此随着代码的变化,它们经常会产生误导或错误。相反,我更喜欢自我记录,简洁的方法,不需要评论。它可以做到,我多年来一直这样做。

编写没有注释的代码需要练习和训练,但我发现随着代码的发展,学科会得到回报。

答案 18 :(得分:0)

描述性名称是你明显的第一个赌注。

其次要确保每个方法只做一件事而且只做一件事。如果你有一个需要做很多事情的公共方法,可以将它拆分成几个私有方法,并以一种使逻辑明显的方式从public方法中调用它们。

前段时间我不得不创建一个计算两个时间序列相关性的方法。

要计算相关性,您还需要平均值和标准差。所以我有两个私有方法(实际上,在这种情况下,它们是公开的,因为它们可以用于其他目的(但假设它们不能,那么它们将是私有的))用于计算A)平均值,B)标准偏差。

这种将函数分解为有意义的最小部分可能是使代码可读的最重要的事情。

您如何决定分解方法的位置。我的方式是,如果名称很明显,例如getAddressFromPage它是正确的大小。如果你有几个竞争者,你可能想要做太多,如果你不能想到一个有意义的名字,你的方法可能不会“做”足够 - 虽然后者的可能性要小得多。

答案 19 :(得分:0)

如果你想完全没有注释编码并且仍然可以使用你的代码,那么你将不得不编写更多的更短的方法。方法必须具有描述性名称。变量也必须具有描述性名称。这样做的一种常见方法是为变量赋予名词的名称,并为方法提供口头短语的名称。例如:

account.updateBalance();
child.givePacifier();
int count = question.getAnswerCount();

大量使用enum。使用enum,您可以替换大多数boolean和积分常量。例如:

public void dumpStackPretty(boolean allThreads) {
    ....
}

public void someMethod() {
    dumpStackPretty(true);
}

VS

public enum WhichThreads { All, NonDaemon, None; }
public void dumpStackPretty(WhichThreads whichThreads) {
    ....
}

public void someMethod() {
    dumpStackPretty(WhichThreads.All);
}