
命名1.避免误导“一组账号”别用那种表示方式, List对于程序员而言有着特殊的含义, 它可以用这个、那个、甚至采用另外一种方式来进行表达。不使用区别较小的名称gs和s难以辨别不使用小写l、大写O作变量名看起来像常量1、02.做有意义的区分不以数字系列命名(a1、a2、a3)按照真实含义命名// 意思无区别只统一用一个别写冗余的名字变量名别带、表名别带table3.使用可搜索的名称难以在上下文中找出单字母名称以及数字常量。名称长短应当跟其作用域大小相对应, 变量名称越是频繁出现, 那么越容易搜索越长。4.命名时避免使用编码把类型编码进名称里, 增加了解码负担, 把作用域编码进名称里, 也增加了解码负担, 这意味着新人除了要了解代码逻辑之外, 还得学习这种编码语言。别采用匈牙利语标记法, 那种样子是这样的格式: --数据类型的缩写 变量名字, 完全是多余的没意义的东西 , 毫无必要。不必用m_前缀来表明成员变量在名称里别对接口以及实现进行编码, 接口名前面的那个“I”是没意义的, 要是非得在接口与实现之中选一个来编码的话, 宁愿选择对实现编码也比对接口名称进行 要好。5.类名、方法名类名应当是名词或名词短语方法名应当是动词或动词短语6.每个概念用一个词fetch、、get约定一个一直用即可7.别用双关语add方法通常的语义是, 依据两个值来获取一个全新的值。要是将单个值添加到某个集合之中, 使用或命名会更为合适, 在此处使用add属于双关语。8.添加有意义的语境仅有极少的名称能够自行表明其意, 需借助具备良好命名的类、函数或者命名空间, 来安置那些名称, 从而给读者予以语境, 倘若难以达成做到这一点的话, 那么给名称增添前缀便成为了最后的办法一招了。函数1.越短小越好用于if语句, 或者else语句, 以及while语句是的代码块, 应当仅仅只有一行, 而这一行所容纳的恰恰应该得是一个, 用于发起对函数进行调用命令的语句。函数的缩进层级不应该多于一层或两层。2.只做一件事要是函数所进行的仅仅是处于该函数名下同一抽象层级上面存在着的各项步骤, 那么此种函数就仅仅是实施了一桩事情。对于一个函数而言, 若要判别它是不是并非仅仅做了一件事情, 那就要去查看它能不能再次拆编出另外一个函数, 这样才行。3.每个函数一个抽象层级4.语句把它埋在较低的那些抽象层级当中, 往常一般能够放置在抽象工厂的底部位置, 其作用主要是用于创建呈现出多态特性的对象。5.使用描述性的名称函数越短小、功能越集中就越便于取个好名字。别惧怕长名称, 长且具备描述性的名称, 相较于短而让人费解的名称而言更好, 相较于描述性的长注释而言也是更好的。别害怕花时间取名字。6.函数参数参数越少越好0参数最好尽量避免用三个以上参数参数越多编写组合参数的测试用例就越困难勿引用标识参数, 朝着函数传递bool值是欠佳的, 这表明函数并非仅执行一项事务。能够把此函数拆解成为两个。要是函数所需参数为两个、是三个, 要不就是三个以上哟那般情况的话, 那就意味着呀其中某些参数得给封装成为类才行。让函数名把参数的顺序给编码进去, 以此来减轻记忆参数先后顺序的那种负担嘞, 举例来说, (, )。7.副作用(函数在正常工作任务之外对外部环境所施加的影响)对密码展开检查, 同时进行初始化的那种方式方法, 将其认定为而非, 就算违背了单一职责原则, 但是也不要产生副作用。防止运用“输出参数”, 要是函数非得更改某种状态, 那就去更改所属对象的状态罢。8.设置(写)和查询(读)分离如果设置“”, “”成立, 那么{……}所表达的意思不清晰明确无法判断, 应当变更为:if ((“”)) {(“”, “”);9.使用异常代替返回错误码出现返回错误码的情况时便会要求调用者马上对错误进行处理, 进而引发深层次的嵌套结构。if ((page) E_OK) {if (xxx() E_OK) {if (yyy() E_OK) {log();} else {log();} else {log();} else {log();使用异常机制:try {();xxx();yyy();} catch ( e) {log(e-());try/catch代码块, 其模样极为难看, 因而嘛, 尽可能去把try部分与catch代码块的主体给抽取出来, 独立地形成为一个函数了。try {do();} catch ( e) {();函数所做之事仅为一件, 有关错误处理亦属这一件事。于此函数其内, 若关键字try有存续, 那么它理应充当函数起始之首个单词。并且, 于catch代码块之后, 不应存有任何别的内容句号。有这样一种情况, 当定义错误码的class要添加新的错误码时, 所有用到该错误码class的其他class都必须重新进行编译继而部署。然而呢, 如果使用的是异常而非错误码, 那么新异常能够从异常class派生出来, 并不需要重新编译以及部署。这同样也是开放闭合原则针对扩展开放, 对于修改封闭的一个范例。10.不要写重复代码重复是软件中一切邪恶的根源。当算法改变时需要修改多处地方11.结构化编程只要函数维持短小, 偶尔出现的、break、语句并无坏处, 甚至相较于单入单出原则更具表达力。goto唯有在大函数当中才有其合理性, 应当尽可能避免运用。12.如何写出这样的函数并不会一开始就依据这些规则去编写函数, 没人能够做到, 去想什么便写什么, 接着再对这些代码进行打磨, 依照这些规则来组装函数。注释若编程语言足够有表现力我们就不需要注释。注释总是一种失败。代码在演化注释却不总是随之变动。不准确的注释比没注释坏的多。1.用代码来阐述创建一个与注释所言同一事物的函数即可若.标志与并且.年龄大于65。应替换为if (.efits())2.好注释法律信息提供基本信息如解释某个抽象方法的返回值对意图的解释反应了作者某个决定后面的意图作出阐释, 将某些晦涩难懂的参数致使出来的意义, 或者返回值所具备的意义翻译成能够被阅读的样子。采取更好的办法是, 让那些意义自身变得足够清晰明了, 然而类似标准库的这样的代码, 我们是没有办法去进行修改的。if ((a) 1) //b a请注意, 这可能存在一定风险, 需加以警惕, 不要奔跑, 你还有一些时间可以消磨, 要明白这一点 , 需谨慎行事。TODO注释放大 一些看似不合理之物 的重要性3.坏注释自言自语那些多余的注释, 将逻辑在里面再写一遍, 并不会比由代码所提供的信息更多, 去读它并不比读代码来得简单, 一目了然的成员变量就别添加注释了, 这样做显得极为多余。误导性注释遵守规矩的注解, 给每个函数添加注解, 给每个变量添加注解, 这是愚笨傻气的。代码版本控制工具出现后, 日志式注释中, 原本需在文件开头维护的修改时间、修改人这类注释就无需再进行维护了。能用函数或者变量表示就别用注释:// does the from the list// on the we are part of?if (.().(.())可以改为 .(); .();if (.())位置标记。标记多了会被我们忽略掉:你提供的内容重复且无实际意义句子, 请提供有意义的句子以便我进行改写。右括号注释try {while () {if () {} // if} // while} // try如果你想标记右括号其实应该做的是缩短函数这个源代码控制工具会记住署名 /* add by rick */ 的你, 然而署名注释却难以跟上代码持续不断的演变。注释掉的代码。会导致看到这段代码其他人不敢删除信息过多。别在注释中添加有趣的历史话题或者无关的细节注释, 并非解释清楚的那种, 其作用在于解释代码, 代码是未能自行解释的, 要是注释自身还需要解释, 那就太让人遗憾了。短函数的函数头注释。为短函数选个好名字比函数头注释要好。非公共API函数的/注释。代码格式1.垂直格式相较于长文件而言, 短文件更易于被理解。单个文件平均仅200行 , 最多也不会超过500行 , 凭借这样的文件能够构建出出色的系统。区隔情况是这样的, 在封包声明以及导入声明之间, 要用空白行分隔开, 而且每个函数之间, 同样也要用空白行分隔开, 并且这些空白行下面, 标识着新的独立概念。贴近: 紧密关联的代码应当彼此贴近, 举例而言, 一个类之中的属性之间不要借助空白行予以分隔, 标点符号。变量声明, 应当尽可能地靠近其使用的位置, 循环之中, 控制变量应该始终在循环语句里声明。成员变量应该放在类的顶部声明不要四处放置要是有某个函数调用了别的一个, 那就应当将它们放置到一块儿。我们期望底层的细节在最后呈现出来, 不要沉迷在细节里, 故而调用者尽量放置在被调用者的上方。执行同一基础任务的几个函数应该放在一起。2.水平格式一行代码, 并非必须固守80字符的上限, 偶然达到100 字符, 只要不超过120字符便没事了可以啦呀。区分与贴近: 空格着重突出左右两侧的划分, 给赋值运算符两边加入空格, 函数名跟左圆括号之间不添加空格, 乘法运算符在和加减法运算符组合之际无需添加空格, 比如a*b - c。不一定非得呈现出水平方向精准对齐的状态。就如同在进行一堆成员变量声明这个行为的时候, 每一行不必要做到让每一个单词都处于对齐的情况。哪怕是简短的if情形, 或者while情况, 乃至函数之中, 最好统统都不要违背缩进的规则哟, 总之別搞成这个样子:if (xx yy) z 1;对象和数据结构对象:暴露行为(接口),隐藏数据(私有变量)数据结构, 不存在显著的行为接口, 将数据予以暴露, 比如DTO数据。1.对象与数据结构的反对称性(参考书中代码清单6-5)运用数据结构带来便利, 能在于不变更现在的数据结构的情形下增添新函数借助对象具备便利之处, 可使其在不改动既有函数的状况下添加新类。使用数据结构时, 添加新数据结构存在困难, 原因在于需要对所有函数进行修改使用对象时, 添加新函数存在困难, 原因在于需要对所有类进行修改。在某些时候, 我们会于简单数据结构之上开展一些过程式的操作然而万物皆对象仅仅是个传说。2.定律(最少知识原则)模块不应该了解它所操作对象的内部情形class C的方法f只应该调用以下对象的方法:在方法f里创建的对象作为参数传递给方法f的对象C持有的对象方法不应该去调用, 由任意函数返回的对象所具有的方法。下面给出的代码, 违背了定律:final ctxt.().().();就比如说, 存在这样一个简单的例子, 人能够去命令一条狗进行行走这个动作, 也就是“walk”, 然而呢, 人并不应当直接地去指挥狗的腿做出行走的举动, 而是应当让狗自身去指挥并且控制它自己的腿到底要怎样去行走。异常处理异常处理具备相当的重要性, 然而要是异常处理在代码中间呈现出四处分散的状况, 进而致使逻辑展现出模糊不清的特征, 那么它无疑就是错误的。1.使用异常而不是返回错误码要是运用错误码, 调用者就得在函数返回之际马上处理错误, 然而这件事极易会让我们给忘掉。错误码通常会导致嵌套if else2.先写try-catch语句在着手编写那种存在可能会抛出异常情况的代码之际, 要先把try - catch给妥善撰写好, 而后才往其中堆砌各类逻辑。3.使用 (java独有)4.在捕捉异常的区域那里, 要尽可能地去将错误的相关信息给记录下来, 要记下去致使出现失败情况的操作事宜, 还要记下去失败所呈现出来的类型情况。5.根据调用者的需要 定义不同的异常处理类在同一个try当中, catch多个不同的情况, 然而catch所处理的事情, 像是打日志之类的, 是一致的, 这种情况下, 可以考虑运用函数将这个异常处理进行打包, 对于不同的异常, 仅仅需要throw成同一个异常, 而不做任何处理, 在外层进行catch的时候统一处理, 也就是打日志等操作。要是仅仅想要捕获一部分异常, 而放过其他异常那就使用不同的函数来打包这个异常处理。6.特例模式: 创建一个类来处理特例。try { .(.getID()); .();// 如果消耗了餐食计入总额} catch ( e) { ();// 如果没消耗将员工补贴计入总额出现异常致使业务逻辑被打断了。并非在()当中抛出异常, 而是于并未消耗餐食之际返回一个特别的对象 (), 对()方法进行复写。 .(.getID()); .();publc class {int () {// xxx; //返回员工补贴7.别返回null值返回null值只要一处没检查null应用程序就会失败处在想要返归null值的情形之时, 能够尝试去抛出异常, 或者返回呈现特例模式的对象。8.别传递null值在方法中传递null值是一种糟糕的做法应该尽量避免。于方法里采用if对null值参数做过滤, 然而依旧会萌生出运行阶段的失误, 不存在妥善之法去应对调用者不经意传入的null值, 适宜的举措便是不准许传入null值。边界将第三方代码干净利落地整合进自己的代码中1.防止公共API返回界限接口, 或者把界限接口当作参数传递给API。把界限留存于近亲类内。2.避免于生产代码里尝试新鲜事物, 应去编写测试以此来领会第三方代码。3.避免我们的代码过多地了解第三方代码中的特定信息。单元测试1.TDD(Test- )三定律第三条法则: 不应编写超出通过测试所需的更多代码。这一法则强调有效编码, , 避免过度编写代码, , 以确保代码的质量和效率。2.保持测试整洁脏测试等同于没测试测试代码越脏 生产代码越难修改。测试代码和生产代码一样重要。最应具备于整洁的测试代码之中的要素是整洁性, 测试代码里不要存在大量的重复代码调用且不要有大量重复代码的调用。3.每个测试一个断言每个测试函数有且仅有一个断言语句。每个测试函数中只测试一个概念。4.整洁的测试依赖于FIRST规则快地: 用于测试的代码理应能够在速度方面迅速地运行起来, 鉴于我们有着经常而频繁地去运行它这样的需求。测试应当彼此相互独立, 某一个测试不应当去依赖前一个测试所产生的结果, 测试能够按照任意一种顺序来予以进行。: 测试应可以在任何环境中通过自我方面: 测试需要有布尔值输出的情况, 不应该借助查看日志方式来确认测试的结果, 不应该依靠手工逐个对比看两个文本文件具体情况来确认测试的结果。需及时去编写测试代码, 单元测试是应当在生产代码之前就进行写作编写的, 要不然的话生产代码将会致使变得难以去进行测试的情况发生。1.类的结构组织(顺序):公共静态常量私有静态变量私有实体变量公共函数私有工具函数2.类应该短小拿函数来讲, 我们借助计算代码行数去衡量其大小, 针对类而言, 我们运用权责来进行衡量。类的名分应当表述其权责义务, 类的取名乃是判定类长短的首个方式, 倘若没法给某个界定准确的名号, 那这个范畴长度就过长了。类的名号涵盖含糊的词汇, 像、、Super, 这般的状况就意味着存在不恰当的*权责集中情形。单一权责原则: 类, 并且模块, 应当存在一个权责, 此权责为只有一条修改的理由。系统应该由许多短小的类而不是少量巨大的类组成。类应当仅有少量的实体变量, 要是一个类里每个实体变量都被每个方法所运用, 那就表明该类具备最大的内聚性。构建最大化的内聚类不太切实可行, 不过应当将高内聚当作目标。内聚性越高意味着类中的方法和变量相互依赖、相互结合从而形成一个逻辑整体。维持内聚性便会得着诸多短小的类, 要是你打算将一个大函数之中的某一小部分裁剪成就单个的函数, 裁剪出来的函数运用了大函数里的4个变量, 用不着把4个变量当作参数传送到新函数里面, 只需把这4个变量提升成为大函数所在类的实体变量, 然而如此做却因实体变量的增多而失去了类的内聚性, 更佳的做法是让这4个变量拆分出来, 拥有其独有的类, 把大函数拆分成为小函数往往是将类拆分成小类的契机。3.为修改而组织(参考书中代码清单10-9、10-10)类应当对扩展开放对修改封闭(开放闭合原则)我们在理想系统里, 是借助扩展系统的方式, 而非采用修改现有代码的做法, 以此来添加新特性。系统1.将系统的构造与使用分开把整个构造历程迁挪至main, 或者是那个被称作main的模块里头, 当关联到系统的其他部分之际, 假定所有对象都已然被正确构造了。存在这样的情况, 应用程序有时是需要承担起确定何时去创建对象的责任的, 我们能够运用抽象工厂模式, 使得应用自身来把控何时创建对象, 然而构造方面的能力却是在工厂实现类当中的, 它与应用使用的部分是相互分开的。有一种强大机制, 它叫依赖注入(DI), 还有一种与之相关的, 叫控制反转(IoC), 它们是用于分离构造与使用的手段。四条规矩帮助你创建优良的设计1.运行所有测试密耦合的代码编写测试存在难度, 测试投入得越多, 便越会依照类似依赖注入的规则, 从而让代码降低耦合度。测试消除了对清理代码就会破坏代码的恐惧。2.消除重复采用两种方式, 将共同特性提取至新的方法当中, 新的方法被分解至另外一类里边, 依此来提高它的可视性。模板方法模式是消除重复的通用技巧// 原始逻辑class () {void tion() {//do x;//do US y;//do z;void tion() {//do x;//do EU y;//do z;// 模板方法模式重构之后class {void () {x();y();z();void x() {//do x;void y() {} private void z() { //do z; }class {void y() {//do US y;class {void y() {//do EU y;3.表达意图作者把代码写的越清晰其他人理解代码就越快。很多时候, 我们深陷于亟待解决的问题里, 在写出能够运行的代码后, 便转向下一个问题去了, 却没投入足够精力使代码调整得让后来者更易读懂。稍微尊重一下我们的技艺, 在每个函数和类上花费些许时间。4.尽可能少的类和方法为了保持类和函数的短小我们可能会早出太多细小的类和方法。类和方法数量太多有时是由毫无意义的教条主义导致的。5.以上4条规则, 其优先级是按照依次递减的顺序排列的。关键在于进行测试, 还要消除重复的部分, 并且清晰地表达意图。并发编程1.防御并发代码问题的原则与技巧遵循单一职责原则。分离并发代码与非并发代码限制临界区数量、限制对共享数据的访问。避免使用共享数据使用对象的副本。线程尽可能地独立不与其他线程共享数据。