什么是好代码
- 文学化编程,想清楚,整明白,胸有成竹,下手千行
- 测试驱动,不做额外的无用功,不追求覆盖率,为的是增强自信心
- 度量驱动,代码上线怎么办,如何度量和调优
- 为未来设计有限的灵活性,无需多改容易扩展
- 足够的健壮,不易出错,不怕出错
1. 好代码必须是看起来很舒服,很干净
象一篇好文章,不罗嗦,容易懂,有头有尾
各个层次,模块及函数分工明确,各司其职, 望文知义
接口即契约,要足够简单,易懂易用, 窄接口好过宽接口
其实只要符合代码规范,命名简单易懂,代码就没那么丑
看看重构那本书中的臭味介绍, 可以提高品味
2. 好代码要符合基本的编码原则
首先我们先谈谈几个软件开发的普适原则
KISS
KISS: Keep It Simple and Straight 保持简单和直接, 适当隐藏复杂性
或者
KISS: Keep It Simple and Stupid 保持简单, 象傻瓜一样, 不要让别人多加思考
软件接口或 API 的设计要让人一看就明白, 一看就知道作者的意图和想法, 如何使用它, 有什么结果和可能的异常及副作用. 看过很多代码, 踩过许多坑, 大多是作者或者我自己使用了出乎意料的实现, 不做好必要的抽象和封装, 复杂的判断和算法到处都是
DRY – Don't Repeat Yourself
别重复你自己, 如有重复代码, 请抽象或重用
SRP - Single Responsibility Principle
单一职责原则: 就一类而言, 应该仅有一个引起它变化的原因
也有一个别称 DOTADIW - Do One Thing and Do It Well 就做一件事并做好它
OCP - Open Close Principle
开放封闭原则: 软件实体(类,模块,函数等)应该是可以扩展的, 但是不可修改
LSP
LSP替换基类原则: 子类型应该可以替换掉它们的基类型
DIP
DIP依赖倒置原则: 抽象不应该依赖于细节, 细节应该依赖于抽象
ISP
ISP接口隔离原则: 不应该强迫客户依赖于它们不用的方法, 接口属于客户, 不属于它所在的类层次结构
REP
REP重用发布等价原则: 重用的粒度就是发布的粒度
CCP
CCP共同封闭原则: 包中的所有类对于同一类性质的变化应该是共同封闭的. 一个变化若对一个包产生影响, 则将对包中所有的类产生影响, 而对于其他的包不造成任何影响
CRP
CRP共同重用原则: 一个包中的所有类应该是共同重用的. 如果重用了包中的一个类, 那么就要重用包中的所有类
ADP
ADP无环依赖原则: 在包的依赖关系图不允许存在环
SDP
SDP稳定依赖原则: 朝着稳定的方向进行依赖.
SAP
SAP稳定抽象原则: 包的抽象程度应该和其稳定程度一致
设计模式和面向对象设计中讲了很多,不再赘述
3. 好代码要易于理解,测试和修改
封装好复杂性,区分开经常变化与基本不变的代码, 适当抽取易变参数作为配置
还是书里那句话,高内聚,低耦合,依赖倒置
例如最常用的 MVC 模式,为什么我们要分成模型,视图和控制器三块,原因之一就在于分开易变的与不易变的,分开不会在一起变化的部分,减小每次修改的范围。
如果某个方面的功能需要修改,最好是改个配置, 其次是加几行代码或传个不同参数,最差的就是改多个地方,加多个判断, 作霰弹式修改
4. 好代码要考虑周到
各种逻辑流程和意外情况的处理要面面俱到, 单元和模块测试要覆盖异常逻辑和边界
对于服务质量 SLA 要考虑周全, 简单说起来就是满足用户的以下基本需求
- 功能性
- 稳定性
- 可靠性
- 性能
- 可维护性
- 可移植性
- 灵活性
5. 好代码要与时俱进,自我蜕变
人会变老,代码也会,新业务,新技术,新架构,新框架层出不穷,要大胆试验,小心引入,逐步演进,不必抱残守缺,也不要盲目冲动
一般来说,要封装好业务逻辑,核心业务不会大变,即使推到重写也要理解和参照老系统的业务流程
最后,引述一下,Python 之禅
Python 之禅
虽然说的是Python, 其实适用于多数编程语言
英文 | 中文 |
---|---|
Beautiful is better than ugly. | 美比丑好 |
Explicit is better than implicit. | 明显比隐晦好 |
Simple is better than complex. | 简单比复杂好 |
Complex is better than complicated. | 复杂比难懂好 |
Flat is better than nested. | 扁平比嵌套好 |
Sparse is better than dense. | 稀疏比稠密好 |
Readability counts. | 可读性很重要 |
Special cases aren't special enough to break the rules. | 特例也不要打破这个原则 |
Although practicality beats purity. | 尽管实践会破坏纯洁性 |
Errors should never pass silently. | 错误还是不能让其悄然滑过 |
Unless explicitly silenced. | 除非你明确声明不用理会它 |
In the face of ambiguity, refuse the temptation to guess. | 别让人来猜测不确定的可能性 |
There should be one-- and preferably only one --obvious way to do it. | 应该有一个且只有一个比较好的明显的方法来做事 |
Although that way may not be obvious at first unless you're Dutch. | 尽管那个方法可能并非一开始就显而易见 |
Now is better than never. | 现在就做比永远不做好 |
Although never is often better than right now. | 尽管永远不做经常比马上就动手做好 |
If the implementation is hard to explain, it's a bad idea. | 如果实现很难解释清楚, 那它不是一个好主意 |
If the implementation is easy to explain, it may be a good idea. | 如果实现很容易说清楚, 那它是个好主意 |
Namespaces are one honking great idea – let's do more of those! | 命名空间是个绝妙点子, 让我们那样做得更多 |
参考
- Agile Software Development, Principles, Patterns, and Practices by Robert C. Martin
- Clean code by Robert C. Martin
- Refactoring: Improving the Design of Existing Code Martin Fowler