首页 » 网站建设 » php整洁之道代码技巧_代码整洁之道读书笔记

php整洁之道代码技巧_代码整洁之道读书笔记

访客 2024-12-07 0

扫一扫用手机浏览

文章目录 [+]

想看此书却还没开始的人也可以从这篇条记出发,对条记中列出的规则有疑问再翻书找答案,相信会比直接啃书来的快一些。

ps: 未必要严格遵照书中的规则,代码不是八股文。

php整洁之道代码技巧_代码整洁之道读书笔记

命名1.避免误导

php整洁之道代码技巧_代码整洁之道读书笔记
(图片来自网络侵删)

\"大众一组账号\"大众别用accountList表示,List对程序员有分外含义,可以用accountGroup、bunchOfAccounts、乃至是accounts

不该用差异较小的名称,ZYXControllerForEfficientHandlingOfStrings和ZYXControllerForEfficientStorageOfStrings难以辨别

不该用小写l、大写O作变量名,看起来像常量1、0

2.做故意义的区分

不以数字系列命名(a1、a2、a3),按照真实含义命名

Product/ProductInfo/ProductData意思无差异,只统一用一个

别写冗余的名字,变量名别带variable、表名别带table

3.利用可搜索的名称

单字母名称和数字常量很难在高下文中找出。
名称是非应与其浸染域大小相对应,越是频繁涌现的变量名称得越随意马虎搜索(越长)

4.命名时避免利用编码

把类型和浸染域编码进名称里增加理解码包袱。
意味着新人除了理解代码逻辑之外,还须要学习这种编码措辞。

别利用匈牙利语标记法(格式:[Prefix]-BaseTag-Name个中BaseTag是数据类型的缩写,Name是变量名字),纯属多余

不必用\"大众m_\"大众前缀来表明成员变量

接口和实现别在名称中编码。
接口名IShapeFactory的前导\"大众I\公众是废话。
如果接口和实现必须选一个编码,宁肯选实现,ShapeFactoryImp都比对接口名称编码来的好

5.类名、方法名

类名应该是名词或名词短语,方法名应该是动词或动词短语

6.每个观点用一个词

fetch、retrieve、get约定一个一贯用即可

7.别用双关语

add方法一样平常语义是:根据两个值得到一个新的值。
如果要把单个值加入到某个凑集,用insert或append命名更好,这里用add便是双关语了。

8.添加故意义的语境

很少有名称能自我解释,须要用良好命名的类、函数、或者命名空间来放置名称,给读者供应语境,如果做不到的话,给名称添加前缀便是末了一招了。

函数1.越短小越好

if/else/while语句的代码块该当只有一行,该行该当是一个函数调用语句。

函数的缩进层级不应该多于一层或两层。

2.只做一件事

如果函数只是做了该函数名下同一抽象层上的步骤,则函数只做了一件事。

要判断函数是否不止做了一件事,便是要看是否能再拆出一个函数。

3.每个函数一个抽象层级4.switch语句

把switch埋在较低的抽象层级,一样平常可以放在抽象工厂底下,用于创建多态工具。

5.利用描述性的名称

函数越短小、功能越集中,就越便于取个好名字。

别害怕长名称,长而具有描述性的名称,要比短而令人费解的名称好,要比描述性的长注释好。

别害怕花韶光取名字。

6.函数参数

参数越少越好,0参数最好,只管即便避免用三个以上参数

参数越多,编写组合参数的测试用例就越困难

别用标识参数,向函数传入bool值是不好的,这意味着函数不止做一件事。
可以将此函数拆成两个。

如果函数须要两个、三个或者三个以上参数,就解释个中一些参数该当封装成类了。

将参数的顺序编码进函数名,减轻影象参数顺序的包袱,例如,assertExpectedEqualsActual(expected, actual)

7.副浸染(函数在正常事情任务之外对外部环境所施加的影响)

检讨密码并且初始化session的方法 命名为checkPasswordAndInitializeSession而非checkPassword,纵然违反单一职责原则也不要有副浸染

避免利用\"大众输出参数\"大众,如果函数必须修正某种状态,就修正所属工具的状态吧

8.设置(写)和查询(读)分离

if(set(\"大众username\公众, \公众unclebob\"大众)) { ... }的含义模糊不清。
该当改为:

if (attributeExists(\"大众username\"大众)) {setAttribute(\"大众username\"大众, \公众unclebob\公众);...}

9.利用非常代替返回缺点码

返回缺点码会哀求调用者急速处理缺点,从而引起深层次的嵌套构造:

if (deletePate(page) == E_OK) {if (xxx == E_OK) {if (yyy == E_OK) {log;} else {log;}} else {log;}} else {log;}

利用非常机制:

try {deletePage;xxx;yyy;} catch (Exception e) {log(e->getMessage);}

try/catch代码块丑陋不堪,以是最好把try和catch代码块的主体抽离出来,单独形成函数

try {do;} catch (Exception e) {handle;}

函数只做一件事,缺点处理便是一件事。
如果关键字try在某个函数中存在,它就该是函数的第一个单词,而且catch代码块后面也不该有其他内容。

定义缺点码的class须要添加新的缺点码时,所有用到缺点码class的其他class都得重新编译和支配。
但如果利用非常而非缺点码,新非常可以从非常class派生出来,无需重新编译或支配。
这也是开放闭合原则(对扩展开放,对修正封闭)的范例。

10.不要写重复代码

重复是软件中统统邪恶的根源。
当算法改变时须要修正多处地方

11.构造化编程

只要函数保持短小,偶尔涌现的return、break、continue语句没有坏处,乃至还比单入单出原则更具有表达力。
goto只有在大函数里才有道理,该当只管即便避免利用。

12.如何写出这样的函数

并不须要一开始就按照这些规则写函数,没人做得到。
想些什么就写什么,然后再打磨这些代码,按照这些规则组装函数。

注释

若编程措辞足够有表现力,我们就不须要注释。

注释总是一种失落败。

代码在蜕变,注释却不总是随之变动。

不准确的注释比没注释坏的多。

1.用代码来阐述

创建一个与注释所言同一事物的函数即可

// check to see if the employee is eligible for full benefitsif ((employee.falgs & HOURLY_FLAG) && (employee.age > 65))

应更换为

if (employee.isEligibleForFullBenefits)

2.好注释

法律信息

供应基本信息,如阐明某个抽象方法的返回值

对意图的阐明,反应了作者某个决定后面的意图

阐释。
把某些晦涩的参数或者返回值的意义翻译成可读的形式(更好的方法是让它们自身变得足够清晰,但是类似标准库的代码我们无法修正):

if (b.compareTo(a) == 1) //b > a

警示。
// don't run unless you have some time to kill

TODO注释

放大 一些看似不合理之物 的主要性

3.坏注释

自言自语

多余的注释。
把逻辑在注释里写一遍不能比代码供应更多信息,读它不比读代码大略。
一览无余的成员变量别加注释,显得很多余。

误导性注释

遵照规矩的注释。
每个函数都加注释、每个变量都加注释是屈曲的。

日志式注释。
有了代码版本掌握工具,不必在文件开头掩护修正韶光、修君子这类日志式的注释

能用函数或者变量表示就别用注释:

// does the module from the global list <mod>// depend on the subsystem we are part of?if (smodule.getDependSubsystems.contains(subSysMod.getSubSystem)

可以改为

ArrayList moduleDependees = smodule.getDependSubsystems;String ourSubSystem = subSysMod.getSubSystem;if (moduleDependees.contains(ourSubSystem))

位置标记。
标记多了会被我们忽略掉:

///////////////////// Actions //////////////////////////

右括号注释

try {while {if {...} // if...} // while...} // try

如果你想标记右括号,实在该当做的是缩短函数

署名 / add by rick /源代码掌握工具会记住你,署名注释跟不上代码的演化。

注释掉的代码。
会导致看到这段代码其他人不敢删除

信息过多。
别在注释中添加有趣的历史话题或者无关的细节

没阐明清楚的注释。
注释的浸染是阐明未能自行阐明的代码,如果注释本身还须要阐明就太遗憾了。

短函数的函数头注释。
为短函数选个好名字比函数头注释要好。

非公共API函数的javadoc/phpdoc注释。

代码格式1.垂直格式

短文件比长文件更易于理解。
均匀200行,最多不超过500行的单个文件可以布局出色的系统

区隔: 封包声明、导入声明、每个函数之间,都用空缺行分别隔,空缺行下面标识着新的独立观点

靠近: 紧密干系的代码该当相互靠近,例如一个类里的属性之间别用空缺行隔开

变量声明应尽可能靠近其利用位置:循环中的掌握变量该当总是在循环语句中声明。

成员变量该当放在类的顶部声明,不要四处放置

如果某个函数调用了其余一个,就该当把它们放在一起。
我们希望底层细节末了展现出来,不用沉溺于细节,以是调用者尽可能放在被调用者之上。

实行同一根本任务的几个函数该当放在一起。

2.水平格式

一行代码不必去世守80字符的上限,偶尔到达100字符不超过120字符即可。

区隔与靠近: 空格强调旁边两边的分割。
赋值运算符两边加空格,函数名与左圆括号之间不加空格,乘法运算符在与加减法运算符组合时不用加空格(ab - c)

不必水平对齐。
例如声明一堆成员变量时,各行不用每一个单词都对齐。

短小的if、while、函数里最好也不要违反缩进规则,不要这样:

if (xx == yy) z = 1;

工具和数据构造

工具:暴露行为(接口),隐蔽数据(私有变量)数据构造:没有明显的行为(接口),暴露数据。
如DTO(Data Transfer Objects)、Entity

1.工具与数据构造的反对称性(参考书中代码清单6-5)

利用数据构造便于在不改动现在数据构造的条件下添加新函数;利用工具便于在不改动既有函数的条件下添加新类。

利用数据构造难以添加新数据构造,由于必须修正所有函数;利用工具难以添加新函数,由于必须修正所有类。

万物皆工具只是个传说,有时候我们也会在大略数据构造上做一些过程式的操作。

2.Demeter定律(最少知识原则)

模块不应该理解它所操为难刁难象的内部环境

class C的方法f只该当调用以下工具的方法:

C

在方法f里创建的工具

作为参数通报给方法f的工具

C持有的工具

方法不应调用 由任何函数返回的工具的方法。
下面的代码违反了demeter定律:

final String outputDir = ctxt.getOptions.getScratchDir.getAbsolutePath;

一个大略例子是,人可以命令一条狗行走(walk),但是不应该直接指挥狗的腿行走,该当由狗去指挥掌握它的腿如何行走。

非常处理

非常处理很主要,但如果非常处理四处罚散在代码中 导致逻辑模糊不清,它便是错的。

1.利用非常而不是返回缺点码

如果利用缺点码,调用者必须在函数返回时急速处理缺点,但这很随意马虎被我们忘却。

缺点码常日会导致嵌套if else

2.先写try-catch语句

当编写可能会抛非常的代码时,先写好try-catch再往里堆逻辑

3.利用unchecked exception(java独占)4.在catch里尽可能的记录缺点信息,记录失落败的操作以及失落败的类型。
5.根据调用者的须要 定义不同的非常处理类

同一个try里catch多个不同exception,但是catch处理的事(打日志等)是同等的,可以考虑用函数打包一下这个非常处理,针对不同非常仅需throw成同一个非常而不做任何处理,在外层catch时统一处理(打日志等)。
如果仅想捕获一部分非常而放过其他非常,就利用不同的函数打包这个非常处理。

6.特例模式: 创建一个类来处理特例。

try {MealExpendses expenses = expenseRepotDAO.getMeals(employee.getID);m_total += expenses.getTotal;// 如果花费了餐食,计入总额} catch (MealExpensesNotFound e) {m_total += getMealPeDiem;// 如果没花费,将员工补贴计入总额}

非常打断了业务逻辑。
可以在getMeals里不抛非常,而是在没花费餐食的时候返回一个分外的MealExpense工具(PerdiemMealExpense),复写getTotal方法。

MealExpendses expenses = expenseRepotDAO.getMeals(employee.getID);m_total += expenses.getTotal;publc class PerDiemMealExpenses implements MealExpenses {public int getTotal {//return xxx; //返回员工补贴}}

7.别返回值

返回值只要一处没检讨,运用程序就会失落败

当想返回值的时候,可以试试抛出非常,或者返回特例模式的工具。

8.外传递值

在方法中通报值是一种糟糕的做法,该当只管即便避免。

在方法里用if或assert过滤值参数,但是还是会涌现运行时缺点,没有良好的办法对付调动者意外传入的值,恰当的做法便是禁止传入值。

边界

将第三方代码干净利落地整合进自己的代码中

1.避免公共API返回边界接口,或者将边界接口作为参数通报给API。
将边界保留在近亲类中。
2.不要在生产代码中试验新东西,而是编写测试来理解第三方代码。
3.避免我们的代码过多地理解第三方代码中的特定信息。
单元测试1.TDD(Test-driven development)三定律

First Law: You may not write production code until you have written a failing unit test.

Second Law: You may not write more of a unit test than is sufficient to fail, and not compiling is failing.

Third Law: You may not write more production code than is sufficient to pass the currently failing test.

2.保持测试整洁

脏测试等同于没测试,测试代码越脏 生产代码越难修正。

测试代码和生产代码一样主要。

整洁的测试代码最应具有的要素是:整洁性。
测试代码中不要有大量重复代码的调用。

3.每个测试一个断言

每个测试函数有且仅有一个断言语句。

每个测试函数中只测试一个观点。

4.整洁的测试依赖于FIRST规则

fast: 测试代码该当能够快速运行,由于我们须要频繁运行它。

independent: 测试该当相互独立,某个测试不应该依赖上一个测试的结果,测试可以以任何顺序进行。

repeatable: 测试应可以在任何环境中通过

self-validating: 测试该当有bool值输出,不应通过查看日志来确认测试结果,不应手工比拟两个文本文件确认测试结果。

timely: 及时编写测试代码。
单元测试该当在生产代码之前编写,否则生产代码会变得难以测试。

类1.类的构造组织(顺序):

公共静态常量

私有静态变量

私有实体变量

公共函数

私有工具函数

2.类该当短小

对付函数我们打算代码行数衡量大小,对付类我们利用权责来衡量。

类的名称应该描述其权责。
类的命名是判断类长度的第一个手段,如果无法为某个类命以准确的名称,这个类就太长了。
类名包含模糊的词汇,如Processor、Manager、Super,这种征象就解释有不恰当的权责聚拢情形。

单一权责原则: 类或者模块该当有一个权责——只有一条修正的情由(A class should have only one reason to change.)。

系统该当由许多短小的类而不是少量巨大的类组成。

类该当只有少量的实体变量,如果一个类中每个实体变量都被每个方法所利用,则解释该类具有最大的内聚性。
创建最大化的内聚类不太现实,但是该当以高内聚为目标,内聚性越高解释类中的方法和变量相互依赖、相互结合形成一个逻辑整体。

保持内聚性就会得到许多短小的类。
如果你想把一个大函数的某一小部分拆解成单独的函数,拆解出的函数利用了大函数中的4个变量,不必将4个变量作为参数通报到新函数里,仅需将这4个变量提升为大函数所在类的实体变量,但是这么做却由于实体变量的增多而损失了类的内聚性,更好多做法是让这4个变量拆出来,拥有自己的类。
将大函数拆解成小函数每每是将类拆分为小类的机遇。

3.为修正而组织(参考书中代码清单10-9、10-10)

类应该对扩展开放,对修正封闭(开放闭合原则)

在空想系统中,我们通过扩展系统而非修正现有代码来添加新特性。

系统1.将系统的布局与利用分开

将全部布局过程迁居到main或者被称之为main的模块中,涉及系统别的部分时,假设所有工具都已经精确布局。

有时运用程序也须要卖力确定何时创建工具,我们可以利用抽象工厂模式让运用自行掌握何时创建工具,但布局能力在工厂实现类里,与利用部分分开。

依赖注入(DI),掌握反转(IoC)是分离布局与利用的强大机制。

emergent design

四条规矩帮助你创建优秀的设计

1.运行所有测试

紧耦合的代码难以编写测试,测试写的越多,就越会遵照依赖注入之类的规则,使代码加减少耦合。

测试肃清了对清理代码就会毁坏代码的恐怖。

2.肃清重复

两个方法提取共性到新方法中,新方法分解到其余的类里,从而提升其可见性。

模板方法模式是肃清重复的通用技巧

// 原始逻辑public class VacationPolicy {public void accrueUSDivisionVacation {//do x;//do US y;//do z;}public void accrueEUDivisionVacation {//do x;//do EU y;//do z;}}// 模板方法模式重构之后abstract public class VacationPolicy {public void accrueVacation {x;y;z;}private void x {//do x;}abstract protected void y {}private void z {//do z;}}public class USVacationPolicy extends VacationPolicy {protected void y {//do US y;}}public class EUVacationPolicy extends VacationPolicy {protected void y {//do EU y;}}

3.表达意图

作者把代码写的越清晰,其他人理解代码就越快。

太多时候我们深入于要办理的问题中,写出能事情的代码之后,就转移到下一个问题上,没有下足功夫调度代码让后来者易于阅读。
多少尊重一下我们的手艺,花一点点韶光在每个函数和类上。

4.尽可能少的类和方法

为了保持类和函数的短小,我们可能会早出太多眇小的类和方法。

类和方法数量太多,有时是由毫无意义的教条主义导致的。

5.以上4条规则优先级依次递减。
主要的是测试、肃清重复、表达意图。
并发编程1.防御并发代码问题的原则与技巧

遵照单一职责原则。
分离并发代码与非并发代码

限定临界区数量、限定对共享数据的访问。

避免利用共享数据,利用工具的副本。

线程尽可能地独立,不与其他线程共享数据。

标签:

相关文章