代码整洁之道 - 读书笔记

代码整洁之道 - 读书笔记

0 前言

永远没必要说这本书看的太晚了,只是能再早一点也许会更好。

这里只是一部分笔记和随笔。并非是划重点。原著才是根本。

1 整洁代码

  • 记住一句话:让营地比你来时更干净

2 有意义的命名

  • 起一个好名字,会给接下来的事情带来效率。

  • 单字母和数字常量的问题:难以搜索。

    但是,一个很长的常量同样不利于阅读。

    书上的例子,MAX_CLASSES_PER_STUDENT,个人来说差不多快到极限了。

  • 成员前缀殊无必要

    m_lpszName纯属历史遗留。

    之前写C#的时候,有时还喜欢用m_ 或者 g_ ,但并不是标准,也不指的提倡。

    现代的IDE已经不需要这些额外信息了

  • 前导字母I也是滥用

    • 好听点是干扰,难听点根本就是废话的程度。
    • 用户需要知道是个接口吗?不需要
    • C#中枪……
  • 方法名应该是动词或动词短语

    • postPayment, deletePage, save, 这些都是好名字
  • 语境

    • 要有意义,以及,包装为更大的概念更好

      例如, addrName, addrZipCode还可以

      但其实不如address.name, address.zipCode

    • 不要添加额外的语境,比如给每个变量加上gsd前缀这种。

3 函数

  • 函数应该做一件事。做好这件事。只做这件事。

  • 应该少用switch函数,应以多态替换之。

  • 函数参数:越少越好

    • 最理想的是没有参数(0参数)
    • 一个次之。
    • 两个再次
    • 三个以上就应当尽量避免。
  • 函数应当没有副作用(亦即没有非名称中的作用)

    举例而言

    public void checkSession(session){
    
      if(session.notValid()){
    
          session.initialize();
          }
    }

    上面的函数含有了失败则初始化,这是名称所没有的副作用。

    所有名称看不出的作用,都是有害的,是给将来挖的坑。

  • 输出参数

    输出参数是有害的。

    尤其是在java里面。

    在C#里面还算能容忍,因为有明确的out参数:

    public int func(int a, out obj b);

    在C++里面属于相当讨厌的东西:

    public void func(obj* p);

    如果不进入函数内部,不知道是不是会改。而在C++里面传递指针又超级普遍。

    再说一遍,java中不应当使用输出参数

    也许go那种多返回值才是最终答案。

  • 依赖磁铁

    例如一个错误枚举类就是依赖磁铁。其修改会导致大范围重新编译。应当尽量避免。

  • 没人能按照这些规则来写函数

    所以,正当的流程是:

    1st=>operation: 实现
    2nd=>operation: 重构
    3rd=>operation: 再重构
    
    1st->2nd->3rd
    

4 注释

  • 真实只在代码里存在

  • 用代码来阐述

    if (empolyee.isEligibleForFullBenefits())
    • 这个函数足够描述功能,无需再去写注释。
    • 英文对于国内非英文母语者是个挑战(对我也是)
    • 如果相信这个函数名,就无需再去看内部
  • 若你想标记右括号,其实应该做的是缩短函数

      }//while
    }//for(...)
    • 如果一屏之内能看完,何必用这个来标记?
    • 还有现代的IDE折叠功能
  • 注释就是注释,不要带有html等格式化内容

5 格式

  • 垂直距离

    关系密切的概念应该互相靠近,也不应分布在不同的文件中。

  • 水平对齐

    可以考虑拿掉了。
    虽然我自己有些时候还是习惯于这样做,特别是常量定义的时候。

6 对象和数据结构

  • 得墨忒定律(The Law of Demeter)

    模块不应了解他所操作对象的内部情形

    亦即下面的代码:

    final String s = ctxt.getOptions().getScratchDir();

    调用ctxt的模块没有道理知道getOptions()函数返回的对象有什么操作。

7 错误处理

  • 别返回null
  • 别传入null

以上两条说起来容易,真正做起来难啊。

8 边界

9 单元测试

测试的FIRST规则

  • Fast(快速)
  • Independent(独立)
  • Repeatable(可重复)
  • Self-Validating(自足验证)
  • Timely(及时)

10 类

11 系统

  • “一开始就做对系统”纯属神话。反之,我们应当只去实现今天的用户故事,然后重构,明天在扩展系统,实现新的用户故事。

12 迭进

  • 重复是拥有良好设计系统的大敌

13 并发编程

14 逐步改进

  • 必须要吐槽一下,本章所说的Args适用的语法,居然没有给出。

    依据对于代码的推测,我推算语法规则如下:
    • 命令 -参数 值 -参数2 值2...
    • 值通过前缀(#, *)等来区别其格式
    • 允许参数合并,如ls -lh这种
    • 只有单字母参数
  • 渐进

    毁坏程序最好的办法就是以改进之名,大动其结构。有些程序将永远无法从这种所谓的“改进”之中恢复过来。

15 JUnit内幕

16 重构SerialDate

  • Javadoc的HTML格式化工作让我畏惧。注释里面带有太多的语言。注释应当和最终输出没什么关系
  • 纯文本注释输出可以保证格式的统一

17 味道与启发

  • 前后一致

    例如,如果某个函数用rsp来命名HttpServletResponse对象,那么其他的函数也应当这么做。

    如果用的是response,那么大家也都用

    重要的不是用什么而是一致

  • 别用算子参数(selector参数)

    例如这种函数:func(true,false,true) 完全是噩梦。

  • 图书推荐:Implementation Patterns(实现模式)

  • 封装条件

    如果没有上下文,布尔逻辑就难以理解。

    应该把解释了条件意图的函数抽离出来。

    例如:

    if(shouldBeDelete(timer))

    要好于

    if(timer.hasExpired() && timer.isRecurrent())
  • 否定式难以理解。尽量用肯定式

    亦即尽量少用 if(!xxx()) 这种

附录A 并发编程II

  • 应当尽量选择基于服务端的锁定

猜你喜欢

转载自www.cnblogs.com/banruoake/p/11483940.html