代码整洁之道,邪恶的表明

图片 1要不要写注释,那是四个主题素材

别给倒霉的代码增多注释——重新写吗。

注:正文中的援引是直接援用笔者Bob三伯的话,两条横线中间的段落的是自身要好的视角,别的大概都能够算是笔记了。

若编制程序语言丰富有表明力,可能大家善用用这几个语言来表明意图,就不那么须求注释——大概根本无需。

作者鲍岳父伯在这一节中就注释展开商量,假诺你在此之前早就稳重阅读过部分开源软件的解说,你会发觉好些个本文上校要谈到的坏注释的例证在不菲有名的开源软件的源代码中都辈出过。小编也清晰的声明是投机的立场,正是「这些注释都是邪恶的」。没有错,一种代码写作风格出今后少数闻名的开源软件中,并不表示那么些风格正是好的。

注明的合适用法是弥补大家在用代码表达意图时面前遭逢的败诉。假如您发现自个儿要求写注释,再想想看是或不是有法子通过代码来抒发。

Don't comment bad code — rewrite it.---Brian W. Kernighan and P. J. Plaugher

正文不提倡写太多注释,能用代码表明就不用写注释。

方便的注释对于精晓代码的意图很有帮衬,可是不好的代码却会使得代码变得可怜絮乱不堪,乃至会对代码形成风险。而日常的处境是,大多数的代码注释都卓绝糟糕。

1. 讲授不可能美化倒霉的代码

写注释的普及动机之一是不佳的代码的存在。

包涵少许表明的净化而有表明力的代码,比带有大批量疏解的零碎而复杂的代码像样的多。与其花时间编写解释你搞出的不得了的代码的解说,不及花时间清洁那堆糟糕的代码。

「Clean Code」的小编对注释全部上是持反对意见的,他以为写代码就像写小说(这里的作品日常指的是记叙文),好的代码应该是能清晰地自解释的,所以在好的代码里不该出现注释。来看这段论述:

2. 用代码来论述

神蹟,代码本人不足以解释其行事。幸运的是,非常多时候大家都得以把代码写地能解说自个儿的一言一动。

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_DAY) && 
    (employee.age > 65))

改成这么怎么?

if (employee.isEligibleForFullBenefits())

故而当您开掘本人在某些项指标贰个地点不得不动用注释时,停下来好好牵记,看是或不是还大概有另一种方法去退换前段时间的气象,进而使用代码来分解你要抒发的意趣。

3. 好注释

稍许注释是必需的,也可能有益的。可是要铭记在心,独一真正的好注释是您想方法不去写的笺注。

再三倘诺大家写了一个模块,之后开掘它结构混乱,代码本人令人费解,然后大家对团结说「哦,那自个儿加条注释就好了」。那是非平日的,与其把时间花在写注释上,还不及花点时间把代码修改得越来越好一些。

3.1 法律音讯

本子及小说权证明正是有理由在每一种源文件开端注释处停放的原委

此处列举了一些「好的注明」的例证

3.2 提供消息的批注

// format matched kk:mm:ss EEE, MMM dd, yyyy
Pattern timeMatcher = Pattern.compile("\d*:\d*:\d* \w*, \w* \d*, \d*");

注解表明,该正则宣布式目的在于协作二个经过SimpleDateFormat.format函数利用特定格式字符串格式化的小运和日期。

那类注释不常管用,但更加好的方法是尽恐怕利用函数名称表明音讯。

1. 版权新闻

不常必需求把版权消息以注释的章程写进代码里去。

3.3 对意向的表明

有的时候,注释不仅仅提供了关于完结的有用消息,并且还提供了有些决定背后的用意。

上边包车型大巴例子,你也许不容许程序员给这么些难题提供的化解办法,但最少你知道他想干什么。

public void testConcurrentAddWidgets() throws Exception {
    WidgetBuilder widgetBuilder = 
        new WidgetBuilder(new Class[] {BoldWidget.class});
    String text = "'''bold text'";
    ParentWidget parent = 
        new BoldWidget(new MockWidgetRoot(), text);

    AtomicBoolean failFlag = new AtomicBoolean();
    failFlag.set(false);

    // This is our best attempt to get a race condition 
    // by creating large number of threads
    for (itn  i = 0; i < 25000; i++) {
        WidgetBuilderThread widgetBuilderThread = 
            new WidgetBuilderThread(widgetBuilder, text, parent, failFlag);
        new Thread(widgetBuilderThread).start();
    }

    assertEquals(false, failFlag.get());
}
2. 提供音信的讲明

譬喻代码3-第11中学有个很复杂的正则表明式,那时我们必要丰硕适当的讲授告诉读者那么些表达式相称的现实格式有哪儿。

//代码3-1// format matched kk:mm:ss EEE, MMM dd, yyyy Pattern Pattern timeMatcher = Pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*"); 

3.4 阐释

不时参数只怕再次回到值晦涩难懂的时候,用注释来帮衬阐释其意义就能有用。但前提是,你思索一下是或不是有更加好的不二诀要,在小心的丰硕注释。

3. 疏解意图

一时候注释要公布的不只是代码达成(implementation)的音讯,还可能有小编利用这种达成形式(implementation)的意图。

3.5 警示

奇迹,用于警示别的技士会出现某种后果的注释也是立竿见影的。

public static SimpleDateFormat makeStandardHttpDateFormat() {
    // SimpleDateFormat is not thread safe
    // so we need to create each instance independently.
    SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
    df.setTimeZone(TimeZone.getTimeZone("GMT"));
    return df;
}

地点例子也有更加好的化解办法,可是那个注释却是特别有不可缺少的。它能阻碍有些紧迫的工程师以频率之名使用静态起始器。

4. 说明

把某个「自个儿意图的发布」不是很鲜明的代码的「真实用意」表明出来

那条第一是在低档语言中比较适用,在如Java那样的尖端语言的采纳中,大多数的境况都足以通过函数封装、修改命名或其余方法来解除这种注释的现象的。

3.6 TODO注释

TODO是一种技术员认为应当作,但由于某个原因近日还没做的劳作。它或然是要唤醒删除有些不须求的风味,或然要求客人注意某些难题,它也许是央求外人取个好名字等等。

这段时间好些个IDE都提供了稳固TODO注释,定时查看那个注释,删除不再需求的,让代码整洁。

5. 对于严重后果的告诫

举例说有个别函数的功效是删除有个别主要的数额,且无法还原,这种状态增进对于此函数的后果的警告注释是拾壹分要求的。

3.7 放大

讲解能够用来推广某种看起来不创设之物的基本点。

String listItemContent = match.group(3).trim();
// the trim is real important. It removes the starting
// spaces that could cause the item to be recognized 
// as another list
new ListItemWidget(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end()));
6. TODO注释

奇迹要求增加TODO注释来标志对于今后支出工作的陈设性,只怕解释为啥「在此地临时使用了三个不好的贯彻情势」,只怕公布对此某段代码今后的落到实处的期许,如代码3-第22中学所示。

//代码3-2//TODO-MdM these are not needed// We expect this to go away when we do the checkout model protected VersionInfo makeVersion() throws Exception { return null; } 

3.8 公共API中的Javadoc

若是您在编排公共API,就该为它编写优秀的Javadoc。

7. 使某段代码更明显

4. 坏注释

绝大比较多注脚都属此类。经常,坏注释都是不佳代码的帮忙或借口,大概对错误决策的修正,基本上等于技术员自说自话。

8. 公共API的javadoc

大部的评释可以被放入这一类,它们平时都只是坏代码的屏障。

4.1 喃喃自语

写一些独有小编本身清楚意思的注释,正是喃喃自语。

1. 自言自语

那类注释经常独有代码的撰稿人自个儿能真正的通晓其意思,对于别的人来讲则是一点战略也施展不出。

故而一旦你要在某处写注释,必须要发挥清楚此注释的上下文,否则那条注释对于代码阅读者来讲尽管没有趣的。

小编在这里又举了多个FitNesse的例子,这一个事例中的注释其实是对此阅读代码有赞助的,不过表述的大概远远不足清晰,会导致读者的误解,搞不清楚。

//代码3-3public void loadProperties() { try { String propertiesPath = propertiesLocation + "/" + PROPERTIES_FILE; FileInputStream propertiesStream = new FileInputStream(propertiesPath); loadedProperties.load(propertiesStream); } catch (IOException e) { // No properties files means all defaults are loaded // }}

这里的疏解并从未发挥清楚暗中认可值是在哪儿被加载进来的,借使别人照旧小编自身在一段时间后要来修改私下认可值的布局,但她只见到到这段注释,依旧要再进一步去代码里找相应的兑现。

4.2 多余的注释

对待代码本人不能够提供更过的消息便是剩下的注释。比方未有证北齐码的含义,也并未有交给代码的来意或逻辑。读这种注释还不及读代码。

2. 冗余注释

在部分代码中,代码自个儿其实早就写的很好了,可是开垦者依旧会在内部增多大批量的评释,去解释用途或效果与利益,在小编看来,这种注释是冗余的,同一时候它们又从未代码本身能发挥的精确度,无端地扩张了代码的开卷难度。

//代码3-4public abstract class ContainerBase implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable { /** * The processor delay for this component. */ protected int backgroundProcessorDelay = -1; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport;

笔者在此处拿了汤姆cat源码来比喻,只怕过三个人都看过如此的代码,如若大家从Bob三伯的这一条龙的编制程序农学出发,这种注释确实是冗余的。

Bob二叔的那条法规其实某些代码洁癖的痛感。在某种程度上,他说的都以科学的,可是在平日的编制程序场景中,又很难完全制止对于代码增添冗余的代码,因为大家连年不可能确认保障team中各样人还或然有前几日说不定维护或选择这段代码的人都富有这种优良的阅读代码的习于旧贯。

4.3 误导性注释

讲授远远不足标准,和代码自个儿表明的意义不均等,轻便误导技士。

3. 令人误解的疏解

有一点注释会说明的情致和函数的本心是见仁见智的,就能够招致代码的阅读者对于代码发生误解。

4.4 循规式注释

所谓每一个函数都要有Javadoc或各个变量都要有注释的老老实实全然是脑痨可笑的。这类注释猝然让代码变得一塌糊涂,满口人言啧啧,让人狐疑。

/**
 * @param title The title of the CD
 * @param author The author of the CD
 * @param tracks The number of tracks on the CD
 * @param durationInMinutes The duration of the CD in minutes
 */
public void addCD(String title, String author, int tracks, int durationInMinutes) {
    CD cd = new CD();
    cd.title = title;
    cd.author = author;
    cd.tracks = tracks;
    cd.duration = durationInMinutes;
    cdList.add(cd);
}
4. 强制性注释

作者认为强制的对于每个函数都添参与代码3-5中所示的javadoc是一件鲁钝的作业,

代码3-5/** * * @param title The title of the CD * @param author The author of the CD * @param tracks The number of tracks on the CD * @param durationInMinutes The duration of the CD in minutes */public void addCD(String title, String author,int tracks, int durationInMinutes) { CD cd = new CD(); cd.title = title; cd.author = author; cd.tracks = tracks; cd.duration = duration; cdList.add;}

4.5 日志式注释

有人会在历次编辑代码时,在模块开首处添加一条注释。那类注释就如一种记录每便修改的日志。

比较久从前,在模块起首处创设并保险这么些记录还算有道理。那时候,我们还未曾源代码调节种类可用。近来,这种冗长的记录只会让模块变得凌乱不堪,应当全体删减。

5. 日记性质的注明

稍许人会有这种习贯:每便去编辑有些模块然后,都会在模块的最起初投入一段类似日志性质的笺注,在版本调节如此推广的后天,这种注释是完全没须要的。

4.6 废话注释

对鲜明之事喋喋不休,毫无新意。

/** 
 * Default constructor
 */
protected AnnualDateRule() {

}

/** The day of the month. */
private int dayOfMonth;

/**
 * Returns the day of the month
 * @return the day of the month
 */
public int getDayOfMonth() {
    return dayOfMonth;
}
6. 噪声注释

这种注释会让我们读起代码来十三分苦恼,你去留心地读书它们啊,它们表明的意思在代码中都以一览无余的;你不去阅读它们啊,又怕会一知半解什么细节。所以这种注释在写代码时应有是用尽全力制止的。

4.7 可怕的废话

Javadoc也说不定是废话。下列Javadoc(摘自某老牌开源库)的指标是怎样? 答案:无。

/** The name. */
private String name;

/** The version */
private String version;

/** The licenseName */
private String licenseName;

/** The version. */
private String info;

再细致读读这个注释。你是还是不是察觉了细分-粘贴错误? 倘使我在写(粘贴)注释的时候都没花心思,怎么能指望读者从中受益呢?

7. 可怕的噪音

主干同上条

4.8 能用函数或变量时就别用注释

寻访以下代码概要:

// does the module from the global list <mod> depend on the 
// subsystem we are part of ?
if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem()))

能够改成以下未有注释的本子:

ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))
8. 只要得以选拔一个函数大概变量,就不要使用注释。

有一些注释是为了让读者能更加好地知道代码要发布的意义,那么这种气象就应该运用合适的函数名和变量名来代表这种意思,并非写二个晦涩难懂的函数,然后再写一解说释去解释你的用意。

4.9 地点标识

不时,程序猿喜欢在源代码中标识有个别极度职责。举例:

// Actions //////////////////////////////////////////

把特定函数放在这种标志上边,大多时候便是无理。鸡零狗碎,理当删除——非常是尾部那一长串无用的斜杠。

那样说吗,假如标志栏非常的少,就能够显明。尽量少用那中标志栏。要是滥用,代码就能够沉没在背景噪音中,被忽视掉。

9. 标记地方的讲解

小编以为那类的注释假如正好的使用,是能给代码带来益处的,可是很轻松被滥用。

4.10 括号后的注释

一时候,程序猿会在括号前边停放特殊的讲解,即使那对于富含深度嵌套结构的长函数或者有意义,但只会给我们更乐于编写的短小、封装的函数带来混乱。要是你开掘本人想标识右括号,其实应当作的是抽水函数。

10. 大括号末尾的注释

稍稍人习惯在八个大括号的尾声(往往是函数大概if while等代码块的末段)增添一些批注,来便于自身异常快稳定函数或代码块的末梢。不过这种境况,往往是你的函数恐怕代码块设计的不创立,应该经过重构写出越来越小、更加精简的函数。

4.11 归属于署名

/* Added by Rick */

版本调节系统万分专长记住是何人在曾几何时增添了怎么。没须求用不大的签字搞脏代码。

11. 签定注释

稍微人心爱在成就某二个功能时增加一些解说来表示「何人在怎样时候为何修改了好几事物」,这种专业依然交给版本调节系统来成功吗。

4.12 注释掉的代码

直接把代码注释掉是讨厌的做法。别那样干!

InputStreamResponse response = new InputStreamResponse();
resonpse.setBody(formatter.getResultStream(), formatter.getByteCount());
// InputStream resultsStream = formatter.getResultStream();
// StreamReader reader = new StreamReader(resultStream);
// response.setContent(reader.read(formatter.getByteCount()));

其余人不敢删除注释掉的代码。他们会想,代码依然位居那儿,一定有其缘由,况且这段代码相当重大,无法去除。注释掉的代码堆叠在一齐,如同破旧瓶子底部的废品常常。

曾经有一段时间,注释掉代码大概有用。但我们早已具有地利人和的源代码调控种类,这一个系统可认为大家铭记不要的代码。大家不须要再用注释来标识,删掉就能够,它们丢不了。作者保管。

12. 对此代码的批注
//代码3-6InputStreamResponse response = new InputStreamResponse();response.setBody(formatter.getResultStream(), formatter.getByteCount;// InputStream resultsStream = formatter.getResultStream();// StreamReader reader = new StreamReader(resultsStream);// response.setContent(reader.read(formatter.getByteCount;

在有版本调整软件的明日,这种对于代码的解说是一心不必要的,而且对于阅读代码带来了极大的搅动。

4.13 HTML注释

源码中隐含HTML注释令人痛恨到极点,难以阅读。

13. HTML注释

在讲授中应用HTML标签是令人厌倦的,应该完全防止的行为。

4.14 非当地新闻

假如你早晚要写注释,请保管它汇报了离它近年来的代码。别在本地注释的上下文情状中带有出系统级的音信。
上边包车型地铁事例,除了可怕的冗余之外,还隐含了系统级的暗中同意端口消息。然则这么些函数完全没决定特别所谓的默许值。尽管那么些值更换了,不可能保障那一个注释也会跟着修改。

/**
 * port on which fitnesse would run. Default to <b>8082</b>
 * @param fitnessePort
 */
public void setFitnessePort(int fitnessPort) {
    this.fitnessePort = fitnessePort;
}
14. 非本土的消息

要确认保障大家的评释只对于就近代码的讲解。

4.15 音信过多

别在批注中增加有意思的历史性话题或然无关的细节描述。

15. 宣布消息量太大的笺注

稍稍注释会写的相当长很长,把一些历史商讨和不相干的内幕都呈报下来,这种注释是非常不便利对于代码的读书的。

4.16 不引人瞩指标关系

申明及其描述的代码之间的联络应当是明显。假如你乐此不疲要写注释,最少让读者能看着注释和代码,并且知道注释所谈何物。

来讲自Apache公共库的这段注释为例

/**
 * start with an array that is big enough to hold all the pixels
 * (plus filter bytes), and an extra 200 bytes for header info
 */
this.pngBytes = new byte[((this.width + 1) * this.height * 3) + 200];

过滤字节是何许鬼? 与那多少个+1有涉嫌吗?或与*3有关系? 依然与双方都有关系? 注释的功用是演讲不能够自行解释的代码。假若注释本人还亟需解释,就太缺憾了。

16. 宣布不明晰的评释

稍微注释本人就很难精晓,特别不相符拿来当注释。

4.17 函数头

短函数无需太多描述。为只做一件事的短函数取个好名字,平常要比写函数头注释要好。

17. 函数头

短函数没有须求写任何的描述消息。假如您写的有所函数都极短,并且他们的名字起的都拾壹分美貌(像第三个笔记中讲的这样),那么完全不必要在这种函数的底部增多注释。

4.18 非公共代码中的Javadoc

Javadoc对于公共API非常有用,但对于不图谋做公共用途的代码就让人恨恶了。为系统中的类和函数生成Javadoc页并非总有用,而Javadoc注释额外的款型要求大致大同小异八股小说。

18. 非公共API的代码中插足javadoc

这种气象此前商讨过,无需。

自己的博客

本文由365bet体育在线官网发布于网络编程,转载请注明出处:代码整洁之道,邪恶的表明

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。