代码整洁之道总结

命名

  • 类名:名词或名词短语;避免使用Manager、Processor、Data、Info之类的类名
  • 方法名:动词或动词短语
  • 使用解决方案领域名称,比如:AccountVisitor(访问者模式)
  • 使用所涉问题领域名称
  • 富有语境的名称,比如state单独拎出来不知道是什么意思,而AddrState就代表了地址的状态
  • 不要添加无用的语境,比如一个固定的前缀或者后缀

函数

  • 短小

  • 只做一件事

  • 每个函数一个抽象层次

  • 自顶向下,让每个函数后面都跟着下一抽象层次的函数

  • UML时序图能很好体现抽象层次,按照先后顺序,从上到下层层组装

  • 单一职责原则:函数只能做一件事情,那么这个函数就不能再拆分出此函数层次上的新函数

  • 单一抽象层次原则:函数中的语句应该是同一个抽象层次上的步骤组合,也就符合单一职责原则

  • http://lanlingzi.cn/post/technical/2019/0531_layer/

  • switch语句

  • 违反单一职责原则:根据值来做不同的事情

  • 违反开闭原则:当新增一个类型时,必须修改原有函数

  • 解决方案:放在抽象工厂方法下面,用多态解决。这样,这个函数就是只做了一件事情:根据类型创建对象,符合单一职责原则;并且新增一个类型不同改动到原来的类的方法,新增一个子类即可

  • 使用描述性的名称

  • 能较好的描述函数做的事情

  • 使用与模块名一脉相承的短语、动词和名称给函数命名

  • 函数参数

  • 最理想的参数数量为0,其次是1,再次是2,应尽量避免3

  • 参数和函数名不在同一个抽象层次上,不容易理解

  • 参数越多,测试越难

  • 输出参数比输入参数更难理解:不要传入一个参数,然后去改变这个参数的值,通过返回值去输出

  • 一元函数:一种较好的方式是函数里面输入一个事件,那这个函数要做什么事情就一目了然

  • 标识参数:True/False,明显违反了单一职责原则

  • 参数对象:当参数大于等于3个时,就应该封装为对象

  • 动词与关键词:函数和参数应该形成良好的名称/动词对形式,比如set(name) 、setField(name),就能很清晰的说明给name属性设置值

  • 无副作用:大部分函数都达不到

  • 分隔指令和查询:要么修改对象的状态,要么查询对象信息(CQRS也是分隔指令和查询,但目的应该不大一样)

  • 使用异常代替错误码:错误处理代码能从主路径中分离出来

  • 抽离try/catch:错误处理就是一件事

  • 别重复自己

  • 如何写出这样的函数:画时序图

注释

  • 需要解释的才需要注释,从语境、名称及抽象层次能一眼看懂的,就不需要
  • 函数名如果高中生看不懂,就需要注释下了

格式

  • 团队统一一个代码格式:比如谷歌代码格式

对象和数据结构

  • 数据抽象:接口呈现了数据结构,并且固定了一套存取策略

  • 数据、对象的反对称性

  • 数据结构:暴露其数据,没有提供有意义的函数

  • 过程式编码:便于在不改动数据结构的情况下新增新函数;但是一旦数据结构有变动,所有的函数都得改变

  • 对象:将对象隐藏于抽象之后,暴露操作数据的函数

  • 面向对象编号:便于在不改动既有函数的情况下添加新类;同样不利于添加新函数,因为必须改动所有类

  • 得墨忒耳律:只跟朋友谈话,不跟陌生人讲话

  • 类C的方法f只应该调用以下对象的方法:

  • C

  • 由f创建的对象

  • 作为参数传递给f的对象

  • C的实体变量持有的对象

  • 火车失事:ctx.options.strachDir.absolutePath(与陌生人进行了对话)

  • 混杂:一半是对象,一半是数据结构

  • 隐藏结构:ctx.createScratchFileStream(classFileName)

  • 数据传输对象:只有数据,没有函数。如果需要函数,应该再创建一个实体类

错误处理

  • 使用异常而非返回码;算法和错误处理被隔离,错误处理在catch中得到解决
  • 使用不可控异常
  • 给出异常发生的环境说明
  • 定义异常类
  • 定义常规流程:特例模式,创建一个类和配置一个对象来处理特例
  • 别返回null,返回空对象,比如空字符串、空列表
  • 别传递null值

边界

  • 使用第三方代码:避免直接使用(比如map),应该封装Map的使用,把它保留在类中(场景极少,无需如此)

  • 浏览和学习边界:不要在生产代码中试验新东西

  • log4j

  • 学习性测试的好处,不只是免费:编写第三方包的测试代码,帮助增进对api的理解

  • 使用尚不存在的代码:比如要对接第三方通信系统,但是接口未给出,我们可以自己先定义自己的Adapter

  • 整洁的边界

  • 通过代码中少数引用第三方边界接口的位置来管理第三方边界

  • 如map般包装他们,或者用Adapter模式将我们的接口转换为第三方接口

  • 边界内部一致

单元测试

  • TDD三定律:限定大概在30秒的循环内,生产代码和测试代码一起编写

  • 在编写不能通过的单元测试前,不能编写生产代码

  • 只可编写刚好无法通过的单元测试,不能编译也算不过

  • 只可编写刚好足以通过当前失败测试的代码

  • 保持测试整洁:请重视生产代码一样,重视测试代码

  • 整洁测试三要素:可读性、可读性、可读性

  • 明确、简洁,有足够表达力

  • 构造-操作-检验

  • 每个测试一个断言

  • 每个测试只测试一个概念;不要超长的测试函数,测试完这个再测试那个

  • F.I.R.S.T

  • 快速:测试够快,且应该尽快运行

  • 独立:测试相互独立

  • 可重复:可以再任何环境中重复通过

  • 自足验证:测试应该有布尔值输出

  • 及时:测试应及时编写

  • 类的组织

  • 遵守Java约定

  • 从一组变量列表先开始

  • 从上到下:公共静态常量->私有静态变量->私有实体变量

  • 很少会有公共变量(就不应该有,如果有则应该定义在Contants类中)

  • 封装

  • 尽量保持变量和函数的私有性

  • 如果测试需要调用到,测试说了算

  • 类应该短小

  • 类的代码行数不能过多

  • 无法给某个类以精准的命名,那么这个类就应该太长了

  • 单一权职原则

  • 类和模块应有且只有一条加以修改的理由

  • 系统应该由许多短小的类组成,而不是少量巨大的类

  • 内聚

  • 类应该只有少量实体变量;类中的每个方法都应该操作一个或多个这种变量

  • 方法操作的变量越多,越内聚

  • 内聚高,意味着类中的方法和变量互相依赖,形成一个逻辑整体

  • 保持内聚性,就会得到许多短小的类

  • 为了修改而组织

  • 在写代码的时候,就应该考虑到代码会修改,这时候应该为了符合开闭原则而组织代码

  • 我们系统通过扩展系统而非修改现有代码来添加新特性

  • 隔离代码(解耦,符合依赖倒置原则)

  • 抽象类呈现概念,具体类包含细节。如果依赖具体类,当细节改变时,就会有风险(构造器、具体算法、实现逻辑改变)

系统

  • 如何建造一个城市

  • 系统层面保持整洁

  • 抽象等级和模块

  • 将系统的构造和使用分开(依赖注入)

  • 延迟初始化与之相反:比如方法中调用new ServiceImp()来实例化对象

  • 扩容

  • 因需求而导致系统递增式的增长

  • 持续的将关注点切分

  • 横贯式关注面

  • 事务、持久化、安全等

  • 用AOP处理,也可以用模块、封装处理

  • 测试驱动系统架构

  • 语意不详,后续阅读测试驱动开发、有效的单元测试

  • 优化决策

  • 模块化和关注点切分->分散化管理和决策

  • 模块化是将关注点集中管理,感觉微服务和DDD中的领域(核心域、支撑域等)是在模块化的基础上对业务的进一步分离关注

  • 系统需要领域特定语言(DSL)

  • 填平了问题域和实现域的壕沟

迭进

  • 简单设计4条规则

  • 运行所有测试:反向驱动设计

  • 驱动:类短小且单一职责

  • 驱动:遵循依赖倒置原则

  • 促进:低耦合、高内聚

  • 不可重复

  • 表达了程序员的意图

  • 尽可能减少类和方法的数量

  • 抵制教条:比如字段和行为切分到数据类和行为

并发编程

  • 并发防御原则

  • 单一权职原则

  • 并发代码有自己的开发、修改和生命周期

  • 建议:分离并发相关代码和其他代码

  • 限制数据作用域

  • 锁:synchronized,Lock

  • 并发更新共享数据的地方越多,越容易出错

  • 使用数据副本

  • 从多线程中收集所有副本的结果,单线程中合并这些结果

  • 线程尽可能独立

  • 不与其他线程共享数据;每个线程处理客户端的一个请求,从不共享的源头接纳请求数据,存储为本地变量(个人理解是数据作为入参传递给run方法)

  • 尝试将数据分解到可被独立线程操作的独立子集

  • JDK

  • java.util.conurrent

  • executor

  • 尽可能使用非锁解决方案

  • 了解执行模型(不部分并发问题都在一下三种模型中的一个)

  • 生产者-消费者模型

  • 生产者线程某些创建工作,并置于缓存或队列中;消费者线程从缓存或队列中获取数据并完成工作

  • 读者-作者模型

  • 存在一个主要为读者线程提供信息源,偶尔被作者线程更新的共享资源

  • 作者线程的更新操作,会锁住很多读者线程(共享资源被作者线程独占)

  • 读写锁专门解决这个问题

  • 宴席哲学家

  • 信号量可以协调共享资源(每个共享资源的许可数量不一样,就能去协调资源)

  • 警惕同步方法之间的依赖

  • 建议:避免使用一个共享对象的多个方法

  • 如果必须使用一个对象的多个方法

  • 基于客户端锁定:客户端代码再调用第一个方法前锁定服务端

  • 基于服务段锁定:在服务端内创建锁定服务端的方法

  • 适配服务端:创建执行锁定的中间层

  • 保持同步区域微小

  • 很难编写正确的关闭代码

  • 比如父线程等待所有子线程执行结束,然后释放资源并关闭;但是如果子线程死锁,资源就无法被释放

  • 建议:尽早考虑关闭情况

  • 测试线程代码

  • 将伪失败看做是线程问题(伪失败=偶现问题)

  • 先使非线程代码可工作

  • 建议:不同同时追踪线程问题和非线程问题

  • 编写可插拔的线程代码

  • 用运行快速、缓慢和有变动的测试替身执行

  • 将测试配置为能运行一定数量的迭代

  • 编写可调整的线程代码

  • 要允许线程数量可调节

  • 运行多于处理器数量的线程

  • 在不同平台运行

  • 装置试错代码(增加对wait、sleep、yield、priority等方法的调用,改变代码执行顺序)

  • 硬编码:手工向代码中插入sleep、wait、yield、prioty的调用

  • 自动化:使用CGLIB、ASM等来装置代码

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

推荐阅读更多精彩内容