聊聊代码注释

当我们谈起代码注释,估计你有以下反应:

1.老子的代码没别人看,不需要注释;
2.这段代码很简单,不需要注释;
3.这段代码很复杂,我多写些注释;

当你发现一段代码有bug,或者看到一坨很恶心的代码像重构,然而没有一点注释,可能会出现以下心理活动:

1.写这段代码的家伙(有可能是你自己)一点注释都不写,这bug怎么修?
2.这段代码做什么?需求是什么?找找需求文档...
3.参数啥意思?我找找接口文档先...
4.需求文档呢?接口文档呢?(好旧的需求)

当你发现一段代码有bug,还有注释:

1.幸好有注释,我知道它干什么;
2.草,注释说的跟代码不符合呀!

今天咱们聊聊,没写注释和写了注释也会出现的尴尬的问题。


请求api的注释

1.如果你公司有接口文档,你应该写注释;
2.如果你公司没接口文档,你更应该写注释。

举个的例子:


public interface Api {
    @POST("/challenge/createActivity")
    Observable<String> createActivity(@Field("activityStartTime") int activityStartTime, @Field("activityEndTime") int activityEndTime,
                                      @Field("challengePoint") int challengePoint,
                                      @Field("checkInNumRule") int checkInNumRule,
                                      @Field("description") String description,
                                      @Field("distanceRule") int distanceRule,
                                      @Field("speedRule") int speedRule,
                                      @Field("sumDistanceRule") int sumDistanceRule,
                                      @Field("taskType") int taskType);
}

你知道createActivity方法是做什么的吗?直译的话,可以认为这是“创建一个活动”的接口。你知道每个参数含义吗?distanceRule checkInNumRule什么意思?反正没注释笔者是不知道。

这时,有工程师会:

安卓工程师:“找接口文档。”
笔者:“请问接口文档在哪?”
安卓工程师:“公司一般有接口文档管理网站,搜一下就好。”

“搜接口文档”看起来很简单的事,实际上,有那么简单吗?对于新项目,接口文档很好找,如果是老项目,接口文档管理网站可能已经换了,你还得问后端同事,旧网站网址。而且不是每个后端工程师都知道网址,可能得问老员工......

还有,如果每次阅读这段代码,都要查查接口文档,耗费工程师多少时间成本?

以下是笔者认为比较好的注释:


public interface Api {

    /**
     * 创建个人发起的挑战活动  http://doc.thejoyrun.com/api/challenge/createActivityForPersonal
     *
     * @param activityStartTime 挑战开始时间
     * @param activityEndTime   挑战结束时间
     * @param challengePoint    挑战积分
     * @param checkInNumRule    打卡次数, 当taskType=2时,必填
     * @param description       规则说明
     * @param distanceRule      单次打卡距离, 当taskType=2时,必填
     * @param speedRule         配速, 当taskType=1时,必填,整型,如配速 6分30秒,应传390
     * @param sumDistanceRule   累计距离, 当taskType=1时,必填
     * @param taskType          挑战类型, 1是累计距离挑战;2是打卡挑战;必填
     *
     * @return 创建成功返回msg
     */
    @POST("/challenge/createActivity")
    Observable<String> createActivity(@Field("activityStartTime") int activityStartTime, @Field("activityEndTime") int activityEndTime,
                                      @Field("challengePoint") int challengePoint,
                                      @Field("checkInNumRule") int checkInNumRule,
                                      @Field("description") String description,
                                      @Field("distanceRule") int distanceRule,
                                      @Field("speedRule") int speedRule,
                                      @Field("sumDistanceRule") int sumDistanceRule,
                                      @Field("taskType") int taskType);
}

这样是不是清晰多了?方法功能、参数意义、接口文档网址都有了。工程师还能用Quick Documentation快速查看代码注释,节省工程师多少时间。


以下给出接口文档 (假的url):http://doc.thejoyrun.com/api/challenge/createActivityForPersonal

接口名称 创建个人发起的挑战活动-(预设)
请求类型 post
请求Url  /challenge/createActivity
变量名 含义 类型 备注
activityEndTime 挑战结束时间 number 必填
activityStartTime 挑战开始时间 number 必填
challengePoint 挑战积分 number 必填
checkInNumRule 打卡次数 number 当taskType=2时,必填
description 规则说明 string 必填
distanceRule 单次打卡距离 number 当taskType=2时,必填
speedRule 配速 number 当taskType=1时,必填,整型,如配速 6分30秒,应传390
sumDistanceRule 累计距离 number 当taskType=1时,必填
taskType 挑战类型 number 1是累计距离挑战;2是打卡挑战;必填

自动生成代码/注释

一份标准的文档,是有固定格式,笔者公司用RAP文档管理。笔者写了个用java代码根据文档生产代码+注释的小工具,繁琐、重复的工作,交给脚本生成就好。


Java Bean注释

1.当成员变量英文名或意义比较复杂,必写注释;
2.当成员变量数值有范围,或多个值且有特定意义,必写注释。

请看请求接口和返回列表

public interface Api {
    /**
     * 我的挑战列表   http://doc.thejoyrun.com/api/challenge/myChallenges
     */
    @GET("/challenge/myChallenges")
    Observable<List<Challenge>> getChallengeList();
}
/**
 * 挑战
*/
public class Challenge {
    int    challengeId;    
    String title;
    String imageCover;

    int activityEndTime;
    int activityStartTime;
    int activityStatus;
    int joinTime;
    int timeLeft;
    int userJoinStatus;
}

Challenge是挑战列表的元素。直译,猜到activityStatususerJoinStatus是两种状态,但这两种状态分别有什么数值呢?什么数值代表什么意思?

当你看到如下代码:

Challenge challenge = new Challenge();

switch (challenge.getActivityStatus()){
     case 0:
          // do something A
          break;
     case 1:
          // do something B
          break;
    ......
}

假如,测试工程师跟你说 活动进行中有bug,而你又不知道activityStatus哪种情况会执行AB,那你就必须debug,或者查接口文档activityStatus哪个数值是 活动进行中

还有,timeLeft直译“剩下的时间” ,是到哪个时间节点剩下的时间?

这些工作都会大量耗费工程师时间。如果我们把注释写好一点:

public class Challenge {
    /** 挑战活动ID */
    int    challengeId;
    /** 标题 */
    String title;
    /** 封面地址 */
    String imageCover;

    /** 挑战结束时间 */
    int activityEndTime;
    /** 挑战开始时间 */
    int activityStartTime;
    /**
     * 挑战活动状态 0-未开始 1-进行中 2-已结束
     */
    int activityStatus;
    /** 用户报名挑战时间 */
    int joinTime;
    /** 挑战未开始的时候为距离开始的剩余时间;当挑战进行中的时候表示还剩余多少时间结束 */
    int timeLeft;
    /**
     * 参与状态 -1失败 0-未参加 1-挑战中 2-挑战成功
     */
    int userJoinStatus;
}

这样就清晰多了,直接Quick Documentation就可以查看activityStatus注释。你可以明确activityStatus==1时,才出现bug,直接定位到case 1出bug代码块。

还有,timeLeft在不同状态下,意义不同。1.挑战未开始,为距离开始的剩余时间;2.挑战进行中,表示还剩余多少时间结束。如果不写注释,谁知道这些啊?


Activity注释

如果给你一个Activity,完全没有注释:

@RouterActivity("page_x")
public class ActivityX extends AppCompatActivity {
        ......
}

Activity注解@RouterActivity表示外部可以通过page_x路由跳进来。

请问,这个Activity是从哪个界面跳进来的?

好运的话,Find Usages会找到startActivity(new Intent(context, ActivityX.class)),或者找到路由跳转page_x的位置。

给你个场景:ActivityXA界面条进来,而A界面必须满足一定条件,才出现跳转page_x按钮。例如,A界面请求服务器,返回某个字段status=1满足条件。

再复杂一点,跳转路径:

C -> B -> A -> X

继续复杂点,page_x是后端返回的跳转路径,app不写死。在代码层面根本找不到入口。

你能一眼看出ActivityX是干什么的吗?

对于复杂的跳转路径,及满足条件才能跳转,我们非常难知道ActivityX的功能是什么。

如果我们在头部写上备注:

/**
 * 参与过的活动详情。<br>
 * 入口:我的活动,右上角“历史” -> 参与过的活动列表,点击item进入
 */
@RouterActivity("page_x")
public class ActivityX extends AppCompatActivity {
        ......
}

这样是不是清晰明了?


结语

本篇笔者就重点说了请求接口注释、java bean注释。读者应该举一反三:

1.java的方法要写注释,表明用途;
2.方法参数写注释,表明意义;
3.成员变量写注释,表明意义,数值范围,每个值的意义等.

每次笔者要修bug,当代码不是笔者写,而且又没有任何备注,恐怕会立即脱口而出“卧槽”!
写好注释不能让你从中级变高级工程师,但其他工程师阅读你的代码,知道你是一个做事谨慎细心的人,也让阅读的人赏心悦目。

不写注释有个笑话:

我写这段代码时,知道它在做什么的,只有老天和我;
但是现在,只有老天知道这段代码在做什么。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,941评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,397评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,345评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,851评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,868评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,688评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,414评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,319评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,775评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,945评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,096评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,789评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,437评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,993评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,107评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,308评论 3 372
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,037评论 2 355