美文网首页
聊聊代码注释

聊聊代码注释

作者: 键盘男 | 来源:发表于2019-05-12 22:22 被阅读0次

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

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

    不写注释有个笑话:

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

    相关文章

      网友评论

          本文标题:聊聊代码注释

          本文链接:https://www.haomeiwen.com/subject/kdjfaqtx.html