目录
有意义的命名
- 名副其实 : 变量命名
- 避免误导 : 0和O,相似的长单词
- 有意义的区分
- 使用读得出的名称
- 使用可搜索的名称
- 使用涉及领域的名称
- 类名/对象名 用名词
- 方法名 用动词
- 避免思维映射,理解偏差
函数
- 短小
- 只做一件事
- 语句放在同一层级,自顶向下
- switch if复杂且很难避开,扔在工厂下面不让任何人看到
- 使用描述性名称, 函数越短小越便于起名
- 参数越少越好
- 无副作用
- 指令(做什么) 与 询问(回答什么) 分隔开
- 使用异常代替返回错误码(抽离try/catch)
- 不用重复自己
- 结构化编程
注释
- 注释并不能美化代码
- 尽可能用代码来阐述其行为
- 好注释 : 对意图的解释, 阐释难懂的参数, 警示, TODO
- 坏注释 : 喃喃自语, 多余, 误导, 循规式,日志式, 位置标记, 括号后的注释, 署名, 注释代码
错误处理
错误处理不能影响到代码逻辑!
- 使用异常代替返回错误码
- 先写try-catch-finally语句
- 使用不可控异常
- 给出异常发生环境说明
- 别返回/传递 null 值
边界
使用第三方代码时, 保持软件边界整洁
类
- 类顺序 变量(公共静态变量>私有静态变量>私有实体变量)>公共函数>私有工具函数
- 封装,保持私有性,但不执著于此
- 短小
- 单一权责原则 (类应该有且仅有一个权责——只有一个能修改的理由, 一个类只做一件事)
- 内聚 (类的实体变量尽量少, 最好是每个变量能被每个方法使用)
- 保持内聚就会得到短小的类
- 为了修改而组织 (系统后续会持续的修改, 所以要对类加以组织 降低日后修改的风险)
系统
- 代码整洁不仅在较低层的细节, 在较高层级的系统上也要保持整洁
- 系统的构造与使用分开 (启动代码 与 运行逻辑 分离处理)
- 实现构造与使用分离的方法: 1.构造过程搬迁到main模块中 2.依赖注入
- 扩容: 不可能一开始就做对之后的系统, 所以应该实现今天的需求,然后重构,扩展系统,实现新的需求。
- 软件系统短生命周期使得 架构可以递增,可以切分关注切面
- java代理
- 延迟决策 能够基于更多的信息作出选择
- 入侵性架构会湮灭领域逻辑,冲击敏捷能力
4条迭进设计规则
- 1.运行所有的测试(全面持续通过所有测试)
- 2 重构-消除重复代码
- 3重构-保证表达力 (标准命名)
- 4-重构-减少类和方法数量 (优先级低于前三条)
并发编程
- 并发是解耦策略, 把目的与时机分解开,改进程序的吞吐量和结构
- 并发算法有可能与影响单线程系统的结构
- 正确的并发是复杂的, 并发会增加一些开销, 可能引起偶发bug, 而且经常需要对系统结构设计根本性的修改
- 了解java库, 使用java库提供的线程安全类
- 了解并发模型(生产者-消费者,读者-作者,宴席)
- 方法互相依赖可能破坏同步代码 (避免使用同一个共享对象的多个方法)
- 如果必须使用共享对象可以(1.客户端调用方法前锁定,调用完解锁。2.服务端自己锁定调用完解锁。3.创建锁定的中间层,适配服务端)
- 尽可能少设计同步区域, synchronized是昂贵的
- 多考虑线程的关闭问题 (子线程死锁,父线程怎么关闭? )
并发编程原则:
- 单一权责 (分离并发代码与其他代码)
- 限制数据作用域 (共享数据死锁问题,严格限制共享数据访问权限)
- 使用数据复本 (避免共享数据)
- 线程尽可能独立 (每个线程处理一个请求.不与其他线程共享数据,从不共享的源数据接纳请求,这样每个线程就是唯一的)
并发编程的测试: (如何测试偶发bug)
- 线程代码可能导致"不可能失败的代码"失败!!! 不要归于偶发事件
- 先使非线程代码工作, 然后编写可拔插,可调整的线程代码
- 使线程数>处理器数, 任务交换频繁就有可能找到死锁代码
- 增加wait() sleep() yield() priority()方法调用改变执行顺序, 增加侦测缺陷的可能. 使用CGLIB,ASM等工具自动化测试
逐步改进
想要整洁代码, 必须先写肮脏代码能工作就行, 然后马上立刻清理它!!!
代码能工作还不够, 经常会严重崩溃,带来深远和长期的损害. 进度、需求都可以重订, 代码只会一直腐败发酵, 必须一直保持代码整洁
优秀的软件设计 大都关乎分隔, 对关注面的分隔使得代码易于理解和维护