工程实践:给函数取一个"好"的名字

工程实践:给函数取一个"好"的名字

  早在2013年,国外有个程序员作了一个有意思的投票统计(原始连接请见:《程序员:你认为最难作的事情是什么?》),该投票是让程序员从如下几个选项中选出平时在工做中本身认为最难作的事情:html

  • 作项目方案设计
  • 编写测试用例
  • 撰写设计文档
  • 向别人解释咱们在作什么事情
  • 实现你不认同的feature
  • 在别人写的代码基础上作改造
  • 与人沟通
  • 给函数、变量命名
  • 进行工做量估时

  也许在你们的印象中,撰写设计文档在别人写的代码基础上作改造应该是最难的事情。可是最终的投票结果确让你们意想不到,此次投票一块儿有4522名程序员参与了投票,排在第一位的是给函数、变量命名:java

  大概一半的人投票给了给函数、变量命名,从此次投票结果咱们足能够看出:给函数、变量命名虽然是一件再普通不过的事情,可是要想把这件事作好绝非易事。那么今天,咱们就来聊一聊如何给函数取一个好的名字。如下是本文大纲目录:程序员

  一.常见的函数命名风格缓存

  二.函数命名的最高境界微信

  三.函数命名最佳实践session

  如有不正之处请多多谅解,并欢迎批评指正。app

  请尊重做者劳动成果,转载请标明原文连接:函数

     https://www.cnblogs.com/dolphin0520/p/10567879.html测试

  

一.常见函数命名风格

  目前来讲,最多见的函数命名主要有两种风格:驼峰命名和帕斯卡命名。fetch

  • 驼峰命名:多个单词组成一个名称时,第一个单词所有小写,后面单词首字母大写;如:
public void setUserName(String userName);
  • 帕斯卡命名:多个单词组成一个名称时,每一个单词的首字母大写;
public void SetUserName(String userName);

  两种命名风格都是ok的,但要保证一点,对于一个团队或者一个项目,须要根据语言自己的推荐命名方式作好约定。好比java通常都采起驼峰命名,C#采起帕斯卡命名。

二. 函数命名最高境界

  咱们一般说:天下武功,惟快不破。那么对于函数命名来讲最高境界是什么呢?我认为是:见字如面,顾名思义,就是看到函数的名字就知道这个函数具体作了哪些事情。

  好比上面的函数:

public void setUserName(String userName);

  可是下面这个函数命名就不是一个好的命名:

public String addCharacter(String originString, char ch);

  这个函数,一咋看,还不错,从函数字面意思看是给某个字符串添加一个字符。可是究竟是在原有字符串首部添加,仍是在原有字符串末尾追加呢?亦或是在某个固定位置插入呢?从函数名字彻底看不出来这个函数的真正意图,只能继续往下读这个函数的具体实现才知道。

  而下面这几个名字就比上面要好得多:

public String appendCharacter(String originString, char ch);     // 追加到末尾
public String insertCharacter(String originString, char ch, int insertPosition); // 插入指定位置

三. 函数命名最佳实践

1)要领1:动词选取要精准

  一般来讲,动词决定了一个函数要采起什么"动做"。动词取的好,一个函数名字已经成功了80%。

  经常使用动词表:

类别 单词
添加/插入/建立/初始化/加载 add、append、insert、create、initialize、load
删除/销毁 delete、remove、destroy、drop
打开/开始/启动 open、start
关闭/中止 close、stop
获取/读取/查找/查询 get、fetch、acquire、read、search、find、query
设置/重置/放入/写入/释放/刷新 set、reset、put、write、release、refresh
发送/推送 send、push
接收/拉取 receive、pull
提交/撤销/取消 submit、cancel
收集/采集/选取/选择 collect、pick、select
提取/解析 sub、extract、parse
编码/解码 encode、decode
填充/打包/压缩 fill、pack、compress
清空/拆包/解压 flush、clear、unpack、decompress
增长/减小 increase、decrease、reduce
分隔/拼接 split、join、concat
过滤/校验/检测 filter、valid、check


  动词决定了函数的具体动做,而名词决定了函数具体的操做对象,对于名词,尽可能使用领域词汇,不要使用生僻或者你们不多使用的词语。

2)要领2:名词使用领域词汇

  举个例子:集合的容量一般用capacity、集合实际元素个数用size、字符串长度用length,这种就遵循你们的使用习惯,不要用size去形如字符串的长度。

  再好比,假如使用到建造者模式,那么一般会用build做为函数名字,这个时候就不要另辟蹊径,用create来做为函数名字,使用你们约定俗成的命名习惯更容易让你的代码被别人读懂。

  经常使用名词表:

类别 单词
容量/大小/长度 capacity、size、length
实例/上下文 instance、context
配置 config、settings
头部/前面/前一个/第一个 header、front、previous、first
尾部/后面/后一个/最后一个 tail、back、next、last
区间/区域/某一部分/范围/规模 range、interval、region、area、section、scope、scale
缓存/缓冲/会话 cache、buffer、session
本地/局部/全局 local、global
成员/元素 member、element
菜单/列表 menu、list
源/目标 source、destination、target

3)要领3:函数取名最忌讳"名存实亡"

  函数取名最忌讳的是"名存实亡",举个例子,假若有个Cache类,里面有个函数判断key是否过时:

public boolean isExpired(String key) {
        // 当前时间戳
        long curTimestamp = DateUtils.nowUnixTime();
        // 获取key的存入时间戳
        long storeTimestamp = getStoreTimestamp(key);
       
        if (curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {
            // 注意这个地方的delete是个隐藏逻辑
            delete(key);
            return true;
        }
        return false;
 }

  上面这个函数从函数字面意思看是判断key是否过时,可是!!它竟然在函数里面隐藏了一段特殊逻辑:若是过时则删除掉key。这个就是典型的"名存实亡",这个是最忌讳的,会给后续的开发人员留下"巨坑"。

  有两种方式去优化这段代码:

  • 方式一:将隐藏逻辑去掉
public boolean isExpired(String key) {
        // 当前时间戳
        long curTimestamp = DateUtils.nowUnixTime();
        // 获取key的存入时间戳
        long storeTimestamp = getStoreTimestamp(key);
       
        if (curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {
            return true;
        }
        return false;
 }
  • 方式二:改变函数名字
public int deleteIfExpired(String key) {
        // 当前时间戳
        long curTimestamp = DateUtils.nowUnixTime();
        // 获取key的存入时间戳
        long storeTimestamp = getStoreTimestamp(key);
       
        if (curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {
            return delete(key);
        }
        return 0;
 }

4)要领4:多查询条件的函数名字谨慎使用介词by

  咱们平时在写查询接口时,假若有多个查询参数怎么办?每一个经过by一块儿链接依赖?No!这绝对不是明智的方式。假如一开始产品的需求是经过学生姓名查询学生信息,写出来的多是这样的函数:

public List<Student> getByName(String name);

  而后忽然又有一天产品提出了新的需求,但愿同时能够经过姓名和电话号码来查询学生信息,那么函数可能变成这样了:

public List<Student> getByNameAndMobile(String name, String mobile);

  接着,没过多久,产品又但愿根据学生年龄来查询学生信息,那么函数可能变成这样了:

public List<Student> getByNameAndMobileAndAge(String name, String mobile, int age);

  若是这样来给函数命名,那么你的噩梦大门即将打开。

  一般比较好的作法是:

  • 若是是经过主键id来查询,那么能够经过by来链接查询信息,好比:

public Student getByStudentId(long studentId);
  • 若是是经过其余属性来查询,而且将来会存在多个组合查询的可能性,建议进行封装,好比:

public List<Student> getStudents(StudentSearchParam searchParam);

  

  最后,建议你们平时在写代码过程当中,不要怕在函数命名上耗费时间,一个好的函数命名在后期会大大减小你代码重构的成本,争取对函数命名作到"见字如面"~

 

  推荐下海子刚开通的微信公众号,欢迎你们扫码关注:

  

相关文章
相关标签/搜索