文体问题:使用白色空间

时间:2009-06-18 05:21:40

标签: language-agnostic coding-style whitespace

对于我的代码的美学,我有一种特别愚蠢的不安全感......坦率地说,我对白色空间的使用很尴尬。我的代码看起来像个极客;不是很可怕,但很尴尬,你感觉不好盯着,却看不到。

我只是不确定何时应该留空或使用行尾注释而不是上述注释。我更喜欢在我的代码之上发表评论,但有时候打破三个字评论的流程似乎很奇怪。有时在代码块之前和之后抛出一个空行就像在一个平滑的代码段中加速。例如,在嵌套循环中,在中心分隔三或四行代码块几乎使缩进的视觉效果无效(我注意到K& R支撑件比Allman / BSD / GNU样式更不容易出现这个问题)。

我个人的偏好是密集的代码,除了函数/方法/注释块之外几乎没有“减速”。对于棘手的代码部分,我想留下一个大的注释块告诉你我将要做什么以及为什么,然后在该代码部分中添加一些“标记”注释。不幸的是,我发现其他人一般都喜欢慷慨的垂直白色空间。一方面,我可以拥有更高的信息密度,而其他一些人认为流量不是很好,另一方面,我可以以更低的信噪比为代价获得更好的代码库。

我知道这是一个小小的,愚蠢的事情,但这是我真正想要的工作,因为我提高了我的其余技能。

有人愿意提供一些提示吗?你认为什么是流动良好的代码,在哪里适合使用垂直空白?有关两行或三个词的评论结束的任何想法吗?

谢谢!

P.S。 这是我一直在研究的代码库中的方法。不是我最好的,但不是我迄今为止最差的。

/**  
 * TODO Clean this up a bit.  Nothing glaringly wrong, just a little messy.  
 * Packs all of the Options, correctly ordered, in a CommandThread for executing.  
 */  
public CommandThread[] generateCommands() throws Exception
 {  
  OptionConstants[] notRegular = {OptionConstants.bucket, OptionConstants.fileLocation, OptionConstants.test, OptionConstants.executable, OptionConstants.mountLocation};  
  ArrayList<Option> nonRegularOptions = new ArrayList<Option>();  
  CommandLine cLine = new CommandLine(getValue(OptionConstants.executable));  

  for (OptionConstants constant : notRegular)  
   nonRegularOptions.add(getOption(constant));  

  // --test must be first  
  cLine.addOption(getOption(OptionConstants.test));  

  // and the regular options...  
  Option option;  
  for (OptionBox optionBox : optionBoxes.values())  
   {  
    option = optionBox.getOption();  
    if (!nonRegularOptions.contains(option))  
     cLine.addOption(option);  
   }  

  // bucket and fileLocation must be last  
  cLine.addOption(getOption(OptionConstants.bucket));  
  cLine.addOption(getOption(OptionConstants.fileLocation));  

  // Create, setup and deploy the CommandThread  
  GUIInteractiveCommand command = new GUIInteractiveCommand(cLine, console);  
  command.addComponentsToEnable(enableOnConnect);  
  command.addComponentsToDisable(disableOnConnect);  
  if (!getValue(OptionConstants.mountLocation).equals(""))  
   command.addComponentToEnable(mountButton);  

  // Piggy-back a Thread to start a StatReader if the call succeeds.  
  class PiggyBack extends Command  
   {  
    Configuration config = new Configuration("piggyBack");  
    OptionConstants fileLocation  = OptionConstants.fileLocation;  
    OptionConstants statsFilename = OptionConstants.statsFilename;  
    OptionConstants mountLocation = OptionConstants.mountLocation;  

    PiggyBack()  
     {  
      config.put(OptionConstants.fileLocation, getOption(fileLocation));  
      config.put(OptionConstants.statsFilename, getOption(statsFilename));  
     }  

  @Override  
  public void doPostRunWork()  
   {  
    if (retVal == 0)  
     {  
// TODO move this to the s3fronterSet or mounts or something.  Take advantage of PiggyBack's scope.  
      connected = true;  
      statReader = new StatReader(eventHandler, config);  
      if (getValue(mountLocation).equals(""))  
       {  
        OptionBox optBox = getOptionBox(mountLocation);  
        optBox.getOption().setRequired(true);  
        optBox.requestFocusInWindow();  
       }  

      // UGLY HACK... Send a 'ps aux' to grab the parent PID.  
      setNextLink(new PSCommand(getValue(fileLocation), null));  
      fireNextLink();  
     }  
   }  
 }  

PiggyBack piggyBack = new PiggyBack();  
piggyBack.setConsole(console);  
command.setNextLink(piggyBack);  
return new CommandThread[]{command};  
}  

13 个答案:

答案 0 :(得分:11)

没关系。

1)开发自己的风格。无论你发现最简单,最舒适,做到这一点。尽量保持一致,但不要成为一致性的奴隶。拍摄约90%。

2)当您修改其他开发人员的代码或处理组项目时,请使用代码库中存在的样式约定或样式指南中已列出的样式约定。不要抱怨它。如果您能够定义样式,请提供您的偏好,但愿意妥协。

如果你按照这两个方法进行操作,那么你将全部完成。可以把它想象成以两种不同的方式讲同一种语言。例如:与朋友谈论你的朋友的方式不同。

答案 1 :(得分:5)

制作漂亮的代码并不是小事。当我写一些我真的很自豪的东西时,我通常可以退后一步,查看整个方法或课程,并一目了然地确实知道它的作用 - 甚至几个月之后。美学在其中发挥了作用,虽然不如优秀设计那么大。另外,意识到你不能总是编写漂亮的代码,(任何人都可以使用无类型的ADO.NET?)但是,如果可以,请做。

不幸的是,至少在这个更高级别,我不确定你是否有任何硬性规则可以始终产生美观的代码。我可以提供的一条建议就是读取代码。很多。在许多不同的框架和语言中。

答案 2 :(得分:4)

我喜欢用空格分解代码的逻辑“短语”。这有助于其他人轻松地可视化方法中的逻辑 - 或者在我回去查看旧代码时提醒我。例如,我更喜欢

reader.MoveToContent();
if( reader.Name != "Limit" )
    return false;

string type = reader.GetAttribute( "type" );
if( type == null )
    throw new SecureLicenseException( "E_MissingXmlAttribute" );

if( String.Compare( type, GetLimitName(), false ) != 0 )
    throw new SecureLicenseException( "E_LimitValueMismatch", type, "type" );

而不是

reader.MoveToContent();
if( reader.Name != "Limit" )
    return false;
string type = reader.GetAttribute( "type" );
if( type == null )
    throw new SecureLicenseException( "E_MissingXmlAttribute" );
if( String.Compare( type, GetLimitName(), false ) != 0 )
    throw new SecureLicenseException( "E_LimitValueMismatch", type, "type" );

使用大括号几乎可以完成相同的中断,但我发现实际上会增加视觉噪音并减少可以同时视觉消耗的代码量。

代码行上的Commens

至于行尾的评论 - 几乎从不。这并不是很糟糕,在扫描代码时很容易错过。而且它们使代码线条变得混乱,使得它更难以阅读。我们的大脑已逐行连接到grok。当评论位于该行的末尾时,我们必须将该行分为两个具体概念 - 代码和注释。我说如果重要的是评论,就把它放在代码上。

话虽如此,我确实发现有关特定值含义的一两行提示评论有时可以。

答案 3 :(得分:3)

我发现很少有空白的代码难以阅读和导航,因为我需要实际读取代码以找到其中的逻辑结构。巧妙地使用空格来分隔函数中的逻辑部分可以增加理解代码的难易程度,不仅对作者而且对其他人也是如此。

请记住,如果您在其他人可能维护代码的环境中工作,他们将花费大部分时间来查看您编写的代码。如果你的风格明显不同于他们以前看到的风格,你的平滑代码可能是他们的减速带

答案 4 :(得分:1)

我最小化空白区域。我将主要注释块放在代码块上方,并在Stuff上添加了行注释,这对另一个开发人员来说可能并不明显。我认为你已经这样做了

答案 5 :(得分:1)

对于大多数开发人员来说,我首选的风格可能是一种诅咒,但我会偶尔添加一些空白行来分隔代码中恰当的“段落”。它适用于我,没有人在代码审查期间抱怨(但是!),但我可以想象它对其他人来说似乎是武断的。如果其他人不喜欢它,我可能会停止。

答案 6 :(得分:1)

最重要的是要记住,当你加入现有的代码库时(你几乎总是在你的职业生涯中),你需要遵守项目规定的代码风格指南。

许多开发人员在重新启动项目时,选择使用基于Linux内核编码风格文档的样式。可以在http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/CodingStyle;h=8bb37237ebd25b19759cc47874c63155406ea28f;hb=HEAD查看该文档的最新版本。

同样,许多维护者坚持要求您在提交版本控制更改之前使用Checkpatch。您可以在我在上面链接到的相同树中看到Linux内核附带的最新版本:scripts / checkpatch.pl(我会链接到它但我是新的,每个答案只能发布一个超链接)。

虽然Checkpatch与您关于空格使用的问题没有特别的关系,但它肯定会帮助您消除尾随空格,标签前的空格等。

答案 7 :(得分:1)

我使用与你相同数量的空格:)方法之前的空白,在注释块之前。在C,C ++中,括号还提供了一些“伪空格”,因为在某些行上只有一个打开/关闭括号,因此这也有助于打破代码密度。

答案 8 :(得分:1)

由史蒂夫麦康奈尔(在通常的位置提供)的代码完成是我对这类事物的圣经。它有一整个关于布局和风格的章节,非常出色。整本书充满了有用和实用的建议。

答案 9 :(得分:1)

您的代码很好,只需按照您(以及您可能使用的其他人)的要求做到这一点。

我对一些(没有经验的)程序员关于空格的唯一看法是他们可能害怕使用它,这在这种情况下是不正确的。

但我注意到您在示例代码中没有使用多个连续的空行,在某些情况下,您应该使用。

答案 10 :(得分:1)

以下是重构该方法的方法。事情当然可以改进,我还没有重构PiggyBack类(我只是把它移到了上层)。

通过使用Composed Method pattern,代码变得更容易阅读,因为它分为多个方法,每个方法都做一件事并且在单一抽象级别上工作。也需要更少的评论。回答问题“什么”are code smells的评论(即代码应该重构为更具可读性)。有用的注释回答了“为什么”这个问题,即使这样,最好还是改进代码,以便原因显而易见(有时可以通过让测试失败而没有不明显的代码来完成)。

public CommandThread[] buildCommandsForExecution() {
    CommandLine cLine = buildCommandLine();
    CommandThread command = buildCommandThread(cLine);
    initPiggyBack(command);
    return new CommandThread[]{command};
}

private CommandLine buildCommandLine() {
    CommandLine cLine = new CommandLine(getValue(OptionConstants.EXECUTABLE));
    // "--test" must be first, and bucket and file location must be last,
    // because [TODO: enter the reason]
    cLine.addOption(getOption(OptionConstants.TEST));
    for (Option regularOption : getRegularOptions()) {
        cLine.addOption(regularOption);
    }
    cLine.addOption(getOption(OptionConstants.BUCKET));
    cLine.addOption(getOption(OptionConstants.FILE_LOCATION));
    return cLine;
}

private List<Option> getRegularOptions() {
    List<Option> options = getAllOptions();
    options.removeAll(getNonRegularOptions());
    return options;
}

private List<Option> getAllOptions() {
    List<Option> options = new ArrayList<Option>();
    for (OptionBox optionBox : optionBoxes.values()) {
        options.add(optionBox.getOption());
    }
    return options;
}

private List<Option> getNonRegularOptions() {
    OptionConstants[] nonRegular = {
            OptionConstants.BUCKET,
            OptionConstants.FILE_LOCATION,
            OptionConstants.TEST,
            OptionConstants.EXECUTABLE,
            OptionConstants.MOUNT_LOCATION
    };
    List<Option> options = new ArrayList<Option>();
    for (OptionConstants c : nonRegular) {
        options.add(getOption(c));
    }
    return options;
}

private CommandThread buildCommandThread(CommandLine cLine) {
    GUIInteractiveCommand command = new GUIInteractiveCommand(cLine, console);
    command.addComponentsToEnable(enableOnConnect);
    command.addComponentsToDisable(disableOnConnect);
    if (isMountLocationSet()) {
        command.addComponentToEnable(mountButton);
    }
    return command;
}

private boolean isMountLocationSet() {
    String mountLocation = getValue(OptionConstants.MOUNT_LOCATION);
    return !mountLocation.equals("");
}

private void initPiggyBack(CommandThread command) {
    PiggyBack piggyBack = new PiggyBack();
    piggyBack.setConsole(console);
    command.setNextLink(piggyBack);
}

答案 11 :(得分:1)

对于C#,我说“if”只是一个单词,而“if(”是代码 - “if”,“for”,“try”等之后的空格根本无法提供可读性,所以我如果没有这个空间,那就更好了。

另外:Visual Studio&gt;工具&gt;选项&gt;文本编辑器&gt;所有语言&gt;制表符与GT;保持标签!

如果你是一个坚持使用标签所属空格的软件开发人员,我会坚持认为你是一个懒汉 - 但无论如何 - 最后,它都是编译的。另一方面,如果你是一个Web开发人员,在你的HTML / CSS / JavaScript中有一堆连续的空格和其他多余的空格,那么你要么对客户端代码一无所知,要么就是你不给一个废话。客户端代码未编译(并且未使用IIS默认设置进行压缩) - 客户端脚本中无意义的空白就像在服务器端代码中添加无意义的Thread.Sleep()调用一样。

答案 12 :(得分:0)

我喜欢最大化窗口中可以看到的代码量,所以我只在函数之间使用一个空行,而且很少使用。希望你的功能不会太久。看看你的例子,我不喜欢开放式支撑的空白行,但我会有一个结束。压痕和着色应足以显示结构。