代码精进之路
范学雷
Oracle首席软件工程师,Java SE安全组成员,OpenJDK评审成员
立即订阅
6350 人已学习
课程目录
已完结 47 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 你写的每一行代码,都是你的名片
免费
第一模块:代码“规范”篇 (16讲)
01 | 从条件运算符说起,反思什么是好代码
02 | 把错误关在笼子里的五道关卡
03 | 优秀程序员的六个关键特质
04 | 代码规范的价值:复盘苹果公司的GoToFail漏洞
05 | 经验总结:如何给你的代码起好名字?
06 | 代码整理的关键逻辑和最佳案例
07 | 写好注释,真的是小菜一碟吗?
08 | 写好声明的“八项纪律”
09 | 怎么用好Java注解?
10 | 异常处理都有哪些陷阱?
11 | 组织好代码段,让人对它“一见钟情”
12丨组织好代码文件,要有“用户思维”
13 | 接口规范,是协作的合约
14 | 怎么写好用户指南?
15 | 编写规范代码的检查清单
16丨代码“规范”篇用户答疑
第二模块:代码“经济”篇 (14讲)
17 | 为什么需要经济的代码?
18丨思考框架:什么样的代码才是高效的代码?
19 | 怎么避免过度设计?
20 | 简单和直观,是永恒的解决方案
21 | 怎么设计一个简单又直观的接口?
22丨高效率,从超越线程同步开始!
23 | 怎么减少内存使用,减轻内存管理负担?
24 | 黑白灰,理解延迟分配的两面性
25 | 使用有序的代码,调动异步的事件
26 | 有哪些招惹麻烦的性能陷阱?
27 | 怎么编写可持续发展的代码?
28 | 怎么尽量“不写”代码?
29 | 编写经济代码的检查清单
30丨“代码经济篇”答疑汇总
第三模块:代码“安全”篇 (14讲)
31 | 为什么安全的代码这么重要?
32 | 如何评估代码的安全缺陷?
33 | 整数的运算有哪些安全威胁?
34 | 数组和集合,可变量的安全陷阱
35 | 怎么处理敏感信息?
36 | 继承有什么安全缺陷?
37 | 边界,信任的分水岭
38 | 对象序列化的危害有多大?
39 | 怎么控制好代码的权力?
40 | 规范,代码长治久安的基础
41 | 预案,代码的主动风险管理
42 | 纵深,代码安全的深度防御
43 | 编写安全代码的最佳实践清单
44 | “代码安全篇”答疑汇总
加餐 (1讲)
Q&A加餐丨关于代码质量,你关心的那些事儿
结束语 (1讲)
结束语|如何成为一个编程好手?
代码精进之路
登录|注册

05 | 经验总结:如何给你的代码起好名字?

范学雷 2019-01-14
上一节我们讲了编码规范的重要性,而编码规范,从起一个好名字开始。但起名字,也没有我们想得那么简单。有个流传很广的戏言:“计算机科学只有两件难事,废弃缓存和取名字。”
之所以说是戏言,因为取名字这件事无论如何都不算是高深的学问;之所以广泛流传,因为取名字真的就是一件很难的事情,而且起名字是关乎代码质量的大事。
给小孩取过名字的人都知道,取个好名字有多难,又要合八字,又要算五行,还要避尊者讳。 写程序给代码取名字更难,每天都要想很多名字。给孩子取名字,父母喜欢就行,给代码取名字,还要别人也喜欢。

为什么需要一个好名字?

名字要准确地代表它背后的东西,并且还能让代码干净漂亮。不然,我们的思路就会受到干扰,影响我们的思考和心情。
比如说,对于答案只有是与非两个选择的时候,我们通常使用布尔类型(boolean)。所以,取名字的时候,我们通常需要一个表达疑问的前缀,比如是不是“is”。
public boolean isEmpty(); // String.isEmpty()
但如果我们把这样的疑问前缀,使用到一个非布尔类型上,会有什么效果?
public byte[] isEmpty();
你是不是觉得如鲠在喉,对于代码要干什么百思不得其解? 反正,我写这个例子的时候,感觉像是吃了五百只苍蝇!
名字就是沟通的方式,错误的命名很难让我们清楚地理解代码真实的意图。所以,混淆的命名很难让我们阅读和理解代码。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《代码精进之路》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(28)

  • pyhhou 置顶
    思考题:
        1. 第四行:class Solution -> class TwoSumSolution
        2. 第九行:public int[] twoSum(int[] nums, int target) { ->
                       public int[] twoSumSolve(int[] numbers, int targetNumber) {
        3. 第十行:map -> targetNumbersRemain
        4. 第十二行:complement -> remain

    望老师指点,感觉命名确实可以让程序变规范、写代码变高效、读起来更直观、管理起来更方便,谢谢老师

    作者回复: 改得漂亮! 我真没有想到使用remain,语义会更清晰些。👍 类似的,参数名也不是很清晰,也可以改改。

    2019-01-15
    9
  • richey
    范老师,一直有个疑问,有时候为了方法名或类名更好的表意,会把名字起的比较长,但名字太长也感觉不太优雅,这方面有什么好的经验吗?

    作者回复: 如果名字没有超过20个字符,长一点也没关系。如果是代码内部使用标识符,要是使用它的代码还能保持在80个字符以内,再长一点也可以。毕竟,容易理解是最重要的。

    确实有不方便的时候,可以使用首字母缩略词,比如把server name indication缩略成sni,使用类似于sniServerName这样的命名。 缩略语离开语境,就很难理解了,我们可以通过注释或者接口规范弥补这个缺陷,解释清楚缩略语代表什么意思,以及缩写的名字具体的含义。 比如说,

    @param sniServerName the server name of a Server Name Indication (SNI)

    2019-01-14
    11
  • J
    推荐FindBugs插件,不规范命名可以识别出来

    作者回复: 是的,工具可以帮助我们查一查。

    顺便的,FindBugs停止更新了,后继者是SpotBugs。前面的留言区有小伙伴提到过。

    2019-01-14
    9
  • 雷小鸿
    简单说下我们dao层命名。一般我们dao层都是和数据库交互的。一个dao类对应一个数据库表。可以用数据库表名+dao这样。具体名字严格按照类命名规范。一个表映射一个实体dao类。这个dao类里面的方法只操作对应的表。如果你不是这样的dao。可以相同的业务放在一个dao里面。根据相同的业务命名。只是给那位同学提供参考不一定完全正确。

    作者回复: 谢谢!

    2019-01-15
    5
  • 🍃Spring🍃
    抛开编程,其实我们的工作是一种表达,或者沟通,不同的是我们在于两个截然不同的两个主体表达,第一个计算机,它有他的规范,只要满足就能实现。第二个就是人,我们自己,有章有法的表达就是最好的沟通。

    作者回复: 👏此处有掌声👏

    2019-01-14
    4
  • MOV AX,0
    编写这段代码时,有两个书写问题,也是我一直所困惑的:
    1.参数中存在多种类型,是否有根据参数类型来在参数声明中,排列参数的规范呢?比如例子中的
    (int[] numbers, int targetNumber),我希望参数列表呈现出一种递减/增的趋势,由集合到数值,再到布尔类型,或者反过来。例如:Map<String, Object> idNameMap, List<CustomerDto> customers,
    long minBalance, boolean isMember。每个参数所包含元素的复杂度递增/递减,让我觉得有一种美感。
    不知老师怎么看?
    2.类似1中的问题,在方法体内,初始化参数时,我希望参数的初始化顺序是由简至繁。虽然表述有歧义,
    请看我之前贴的代码:
            int testTargetNumber = 7;
            int[] testNumbers = new int[]{1, 2, 3, 4, 5};
    我希望在保证所有初始化的参数,尽量贴近它的首次调用点的前提下,做到简单类型先初始化,每行代码的长度从上至下由短到长。
           可能这些问题,看起来都很无聊没有太多可讨论的地方。但我认为编码就是艺术,艺术在于精进,再简单的东西也要尽量做的赏心悦目。起初这门课程上线时,我也有看大纲,很多已经从sonar刻到骨子里了,想着没有太大必要再买。但一位好友近期要转java开发,我也一时想不到什么特别好的书给他参考。某天点开极客时间,又看到这门课,买下来看了下,确实深有感触。如果自己都没确认好不好,不敢误人子弟。趁着这个机会推荐给他,我自己也再学一遍,也算与他共同学习吧,不知他有没机会看到这段话。也希望老师对我的代码给一点建议,感激不尽!

    作者回复: 第一个问题是个好问题。我还没有看到过这方面的书面规范。一般情况下,我使用的方法是按照参数的关联度,或者参数的逻辑关系。

    比如,String.valueOf(char[] data, int offset, int count),最重要的是data,所以放在第一位。然后是从什么地方开始,使用多少个字符。

    我们如果阅读这个方法的规范,它写的是“Returns the string representation of a specific subarray of the char array argument.” 首先提到的就是data这个参数,然后再说明data的附加条件。

    我觉得可以试试,如何用语言把这个方法描述出来。参数出现的描述中顺序大致就可以是参数在方法中的出现顺序。

    第二种初始化的顺序,也是我常用的顺序。

    可能会有人觉得规范无聊,但是掌握了它的人都知道,好的规范,赏心悦目的代码,可以理清思路,提高效率,减少错误,减轻疲劳。只是大家不知道为什么好,就不知道为什么要规范。所以我也选择了一个不太讨好市场的方式,说了很多为什么好的道理。这确实不性感,不带劲!

    我非常感谢你能给朋友推荐这个专栏。我希望这个专栏的打开方式是从这里看看为什么和一些小例子,找一个详尽的规范看看详细的怎么办,比如阿里巴巴的规范,Google的规范,Java自己的规范等等。然后,使用练手题练习一下,然后把学到的、认可的规范用到自己实际的代码里去。

    写好代码,是一个长期的修行。我自己也在不停地琢磨怎么可以做的更好。共勉!

    2019-01-30
    3
  • ownraul
    一个好名字的确定,也是建立在业务模型稳定的基础之上,如果开发前不能把最终的业务名称用词确定下来,那是很难一下在代码层面把名字定完善的
    2019-01-18
    3
  • allean
    认真规范自己写的代码,感觉很开心了

    作者回复: 代码写的好看,真的心情好的。

    2019-01-14
    2
  • hshayq
    每次代码写到后面,都会词穷,不知道怎么命名
    2019-07-08
    1
  • 人脑逆向工程师
    对国内程序员来说提升英语水平会比较明显有助于改善变量命名

    作者回复: 😂坚持使用良好的变量命名,反过来也促进英文水平。

    2019-03-18
    1
  • MOV AX,0
    非常感谢您的细心回复!实际工作中,确实会返回空集合,这也是我一直的习惯。因为在例子中返回异常,所以还是按异常来写了。main方法是写给其他初学者看的,刚开始工作时JUnit都不会,只会main来测... 有不少同学提到了阿里的代码规范插件,配合SonarLint更佳!我们公司对异常的处理,是使用了一个ApiResult的类封装返回结果,假设Facade接口内捕获了报错,会使用:
    LOGGER.error("error msg in logger", e);
    return result.error("error msg to invoker");
    这样调用方,可以通过静态方法ApiResult.isSuccess(result)/ApiResult.isFail(result)来判断接口调用是否成功,通过result.getMsg()即可获取错误信息。
    对外接口是绝对不可以抛出异常的,内部调用的服务XxxxService是可以抛出异常的,DAL层不做参数校检且不对外提供服务,参数的校检和异常捕获也应在Service层完成。关于结果返回封装类,网上有很多实现可以参考。

    作者回复: 这种ApiResult的处理方式让我想起了C语言时代的错误处理方式。

    2019-01-31
    1
  • 加载中……
    我觉得dao层的方法,也应该根据不同的业务隔离,不提倡公用(复用)。复用既耦合,大部分业务复杂的CRUD系统,随着后续的维护工作的开展,dao复用带来的弊,比复用带来的利要大的多。
    2019-01-15
    1
  • 草原上的奔跑
    这节课给的命名规则很实用,既见树木,又见森林,范老师不仅告诉我们为什么要用命名编码规范,还说了不同语言业公认命名编码规范,自己不同的命名方法,驼峰,匈牙利,蛇形,串行。命名效果要信达雅。继续跟着范老师精进!
    2019-01-15
    1
  • dao层,与数据库交换层,一般写sql语句,是不是用sql的功能来命名? 比如getStudentinfo之类的

    作者回复: 谢谢。我对数据库比较陌生了,小伙伴们能不能帮着回答下这个问题?

    > 如果多个(至少5个)方法调用同一个dao,这个dao要怎么命名好点?还是,以业务功能划分,把这个dao分开?
    以前我做数据库代码的时候,数据库的设计一般按照业务逻辑来的。数据存取接口虽然不涉及具体的业务逻辑,但是由于数据库的设计是按照业务数据来做的,数据存取接口也是按照业务逻辑设计的。这样,接口的命名体现的也是业务数据处理的细分功能。命名的时候,也是使用业务的逻辑表达方式。

    现代的数据库模型是什么样子的,我就不懂了。希望看留言区的小伙伴可以帮帮我。

    2019-01-14
    1
  • 老师您好,如果多个(至少5个)方法调用同一个dao,这个dao要怎么命名好点?还是,以业务功能划分,把这个dao分开?

    作者回复: 不好意思,dao是什么意思?

    2019-01-14
    1
  • Being
    学习完后,抬头看自己的代码,嗯,又挑出刺儿来了,好好优化吧,争取做到“雅”🤔

    作者回复: 嗯,又好了一点儿😄

    2019-01-14
    1
  • 虢国技匠
    打卡
    2019-01-14
    1
  • Sisyphus235
    代码的命名规范没有共识,但可读性和效率却是大家都在追求的。
    在实践命名的过程中,总是能感觉到代码内部命名和 REST 规则有某种联系。
    package, module, class 都是资源,尽可能用名词,而 function 就像是 API,用动词/动词短语获取资源。

    作者回复: 👍

    2019-05-21
  • 小文
    老项目驼峰命名方法和匈牙利命名方法混着用,我是应该用哪种呢?求解 😄

    作者回复: 建议你使用驼峰命名方法。匈牙利命名方法是历史遗留产物了。

    2019-02-14
  • MOV AX,0
    一直以来有两个疑惑:
    1.参数列表中参数的排序规则.
      惯于将类型复杂度由高到低(或相反),排列函数参数,如:
        (Map<String, Object> idNameMap, List<CustomerDto> customers, long minBalance, boolean isMember)

    2.方法中声明/初始化参数的顺序.
      以尽量将参数声明/初始化贴近首次调用位置,为前提下。
      惯于将类型复杂度由低到高,对各个参数声明/初始化,如:
        boolean isMember = true;
        long minBalance = 20000;
        List<CustomerDto> customers = customerService.getByParams(params);
        Map<String, Object> idNameMap = customerWeixinService.getIdNameMapByParams(params);
    个人觉得看起来比较有美感,但还未见有提过这方面的规范。
    最早上线这门课程时,看了下大纲,感觉sonar里基本都提过了,就没有购买。
    直到某天想起编码规范的事,想给朋友推荐一本书来参考,发现没有什么特别深入的书。
    基本都是讲讲命名法之类的就没了,还不如sonar插件。本着推荐人一定要自己先验证的原则,
    买来看了几篇,深有体会。公司很多旧代码,包括现有的一些工作已久的同事,注释都不好好写。
    这个问题也不好提,比较尴尬,因为我也才工作一年多。也不知道我的朋友会不会看到这段话,
    希望他通过这门课程,能够受益终生,我也将与他共同学习。同时也希望老师对我的代码给一些
    宝贵的建议,谢谢!

    作者回复: 问题在另外一个留言里回复过了,你找找看看。

    我也理解编码不规范的程序员,他们还没有养成习惯。很多问题,形成氛围就好了。我的同事们一般都比较直爽,有的时候会说,这段代码我看的比较费劲,你加一段注释;这段代码通常不这么处理,你为什么这么干,加一段注释;这个参数无效这么办,规范里写清楚。我自己非常享受这样的氛围。

    这样的氛围形成之前,先把自己的代码弄好,然后看看能不能影响你觉得可以影响的人。

    2019-01-30
收起评论
28
返回
顶部