一、整洁代码的定义
- 整洁的代码只做一件事情
- 逻辑不清楚,性能不好的代码,会让别人非常想改它,然后改的更乱了。
二、命名
-
不能提供更多额外信息的词汇不要用。 比如一个 Product 类,还有一个 ProductInfo 和 ProductData,其中 Info 和 data 并不能提供更多的信息。Info和 data 就像是 a\an\the 这种词都是冗余。
-
避免误导,就是程序名和变量名要名符其实。比如 OrderList 就应该是一个 list,而不应该是一个对象。函数的名称要和函数所做的动作一致。假如发现无法有很好的函数名称形容这个函数,那说明这个函数做的事情太多了,需要进行拆分。
-
名称宁愿长点,也不要缩写成别人无法理解的单词。
-
不要前缀! 因为代码读的越多,眼中就慢慢会自动忽略前缀。
-
类名和对象名应该是名词或者名词短语。例如:Customer、WikiPage、AddressParser。类名不应该是动词。避免:Manager,Processor 这种类名,因为他是比较笼统的概念。
-
方法名应该是动词或者动词短语。如 PostPayment, Delete 。初始化一个类时
Complex fulcrumPoint = new Complex(20, 30) //这种方式会更好 Complex fulcrumPoint = Complex.FromRealNumber(20,30)
可以考虑将对应的构造器设为 priate,强制使用各种方式
-
每个概念对应一个单词。给每个抽象出来的对象或者操作规定一个名称。比如fetch、retrieve、get他们都是获取的意思时,要给出对应的场景单词。注意区分insert、append并替代add使用。尽可能使用email代替emailAddress,因为后者几乎没有提供比前者更多的信息。
-
对于词义比较广泛的,需要进行限制,比如 get、add、manage 等。
get
是获取对象属性fetch
从远程获取数据load
从文件或者存储中获取数据query
从数据库里获取数据calculate
计算出来的数值find
从数组中查找数据create
、parse
、build
从数据生成数据
常用单词:
add/remove increment/decrement open/close begin/end insert/delete show/hide create/destory lock/unlock source/target first/last min/max start/stop get/put next/previous up/down get/set old/new 新增: add, new, create, make, build, generate 更新: update, set, transform, 获得:get, load, fetch, calculate, find, search, filter, query 删除:remove, delete, clear, 接口:Ajax
-
很少有名称是可以自我说明的,比如 name, 所以需要有上下文环境,上下文环境可以是名称前缀,当然抽象成类更好。
三、函数
- 函数的第一规则是短小,第二规则还是短小!
- 函数只做一件事情。做好这件事情,只做这一件事情
- 函数的抽象层级要统一,就是函数内操作的颗粒度要统一。比如一个函数要渲染页面, render(View) 是高层次抽象,然后 printString(String) 这里就是底层的实现,他们应该要进行分层。就像我们设置里面,先进入控制面板,然后找到所属的模块,然后细节的操作。
- 函数参数,最理想的参数数量是0,应该避免三个参数以上的函数,有足够特殊的里有才能用三个以上的参数。参数太多可以用责任链设计模式。
- 禁止标识参数,就是 Flag 或者 Switch,不准像函数传入布尔值。这标明了函数没有做一件事情,假如为 true 会这么做,假如为 false 会这么做。
- 如果函数参数看来需要两个或者三个以上,那说明其中一些参数应该被封装成类了。
- 函数要么做什么事,要么回答一些事。但二者不可兼得。把动作查询分开。当然有时候动作的结果就是我们查询的对象,这时候直接返回。但是不要既做动作,又对结果进行额外的查询。
- try...catch...中的代码块,应该抽离成函数
- 不要重复!重复是复杂度的根源之一。很多原则和实践规则都是为了避免重复
四、注释
- 注释不能美化糟糕的代码!
- 注释只应该出现在理解困难或者容易出错的地方,能不用就不要用。
- 不准保留注释掉的代码,统统删干净
五、格式
- 统一的缩进格式
- 代码行应该尽可能短小,最好不要超过120字
- 代码格式要团队进行统一,使用编辑器工具进行限制
- 类的组织,首先应该是常量, 然后是属性,然后是公共函数,对应的私有函数要放在调用者附近。公共函数应该在变量之后
六、对象和数据结构
- 类并不是用取值和赋值将私有变量对外使用。二是要暴露抽象接口,让用户无需了解数据结构就可以使用。
- 对象把数据隐藏于抽象之后,暴露操作数据的函数。 数据结构暴露起数据结构,没有提供有意义的函数。
- 过程式代码(使用数据结构的代码),难以修改数据结构,因为会影响函数,但是容易修改函数。
- 对象式代码,难以添加新函数,因为会影响很多类。
- 模块不应该了解对象内部的数据结构,对象不应该通过存取器暴露内部结构。
- 数据对象,只有公共变量,没有函数的类。被称为数据传送对象。作用就是将原始数据转化为类的操作,比如 ActiveRecord
七、错误处理
- 使用异常而不是返回码。 意思是主函数调用子函数时,子函数不应该返回 true 或者 false 等返回码,这样主函数还需要进行判断,而应该直接抛异常。由统一的错误处理进行处理。
- 不要返回 null 值!不要传递 null 值
八、范围
- 一个类要有其对应的范围。不能啥都干。比如 StoreHandler 只应该做返回值是Store 的操作,获取 Store 的 Price 应该放到 PriceHandler
- 使用接口类限制边界
九、类
- 类的单一权责。系统应该由很多短小的类而不是少量巨大的类构成。
- Controller 过于臃肿,而且 controller 里面的方法不便于其他 controller 进行调用。所以将 controller 逻辑提取出来,根据函数所获得的结果进行汇总,然后控制逻辑层,防止逻辑层大爆炸。为了防止逻辑层大爆炸,就要求逻辑层有比较想尽的文档,在编写之前可以先查阅文档是否已经存在有类似的函数。对与逻辑层的起名不要包含业务层信息。仅描述对资源的获取,包含三个部分,请求的资源,请求的条件,请求返回的格式。