您当前的位置:首页 >> 资讯 >  >> 
全球快讯:『代码效率重构与可扩展性思路』----“PHP与MySQL的应用开发”阅读笔记
来源: 哔哩哔哩      时间:2023-07-04 01:03:51

这是一篇我在阅读《PHP与MySQL的应用开发》时,2020年9月29日发表于某平台的学习随记,现转载至B站。 


(资料图)

关于如何在编写PHP及其他代码时优化代码提高扩展性,本篇文章内容大多摘自书本《PHP与MySQL的应用开发》。

代码重构实践

代码重构是一门实践性极强的艺术,并不是“高大上”、要束之高阁的科学,我们要了解更多隐藏在代码后面的内容,并非写完程序就万事大吉,那只是懒惰的程序员所为,优秀的开发者要承担代码的所有责任。

什么是不良代码

在一些情况下,身担上线重任的我们要完成开发任务,代码逻辑没有仔细考虑,常常会出现代码冗余,有的甚至是从其他文件中复制过来的。如果复制的代码也存在错误,这样会让代码越来越混乱,导致错误更大蔓延。

这些“坏味道”的代码主要表现在如下方面:

代码逻辑难以被读懂理解

代码中要增加很多单行注释

代码逻辑存在低级的Bug

存在冗余的代码

过多面向过程的代码

在开发任务中,如果代码过多冗余,对于公司的运营、项目的管理和后续的开发调试都会增加困难。

什么是好代码

我们通过三个准则来判断代码是不是好代码,分别是:

可读性

可扩展性

效率

1. 可读性

我们在项目中按照一些标准的语法、风格来开发软件,如果在解释代码逻辑时很容易讲清楚、讲明白,初步判断就是一篇可读性较好的代码。

我们通常遵循一个通用标准,或者自己定义一个风格。但无论你选择哪种,当同事接替你的工作,按照你的代码、风格以及文档、注释等就能顺利工作,而无须太多解释,这也是干净的好代码。

在讲究严谨的研发团队中,成员都遵守通用的编码标准,当有新人加入团队,可以有效缩短学习曲线和有效减少开发成本。

2. 可扩展性

可读性和可扩展性有助于代码的可维护性,使得在项目规划的时间内快速迭代。

使用设计模式,它有助于可读性和可扩展性。

软件开发中遵循一些可重复使用的、逻辑的、已知的设计模式,它是定义的标准设计模式或正常的逻辑流程,因此代码具备更大的可扩展性。

一般的,除非有特殊情况,尽量不去使用while和for这样的循环语句,在遍历数组时通常会用foreach语句,以避免不必要的混乱,造成可维护性不佳。

可扩展性的主要体现是去除耦合封装。去除耦合意味着代码(主要是函数/方法和类)不相互依赖或相互重叠,而应该是“纯粹”的功能实现,任何重叠的功能和其他非关联性实体都应该删除。

我们正在写的函数逻辑应该与它的命名相符,不应该“挂羊头卖狗肉”,即不在函数内做额外的东西。

在编写代码时使用“工具箱”的方式——众多函数库共同打造大的复杂系统。

封装也是去除耦合的重要部分。姚封装组件,就要从项目的范围抽取逻辑,并分离其内部相互作用缩小在接口级别,这是一个通用模块化的方法,这样使得它更容易在以后删除或更新系统的任何功能,使代码更清晰。

3. 效率

在开发过程中,我们应在头脑中时刻牢记“效率”,效率是系统的瓶颈问题。

因为在任何项目的代码中都有使用一些不合理的结构:例如嵌套循环和递归。以及一些不正常的处理逻辑,例如哦不使用缓存和发送/接收数据时没有恰当的使用缓存。

互联网产品中,可读性和可扩展性不好导致的结果就是运行效率降低,大多数情况下,效率和这两个规则成正比。

如何增加代码可读性

1. 代码文件是否遵循相同编码风格

应该使用代码标准,最好是一个通用的标准,如PSR-1/2.

如果要自定义编码标准,你可以以自己的代码为范本,为自己和自己的团队写一个简短的说明。

2. 开发使用的是标准语法结构,不使用怪语法

由于PHP的灵活性,可能有多个样式来编写程序结构。一般的,我们只在一个项目需坚持一种风格。

3. 每个文件有一个标题,注释、记录其在项目中的角色

作为一项基本要求,你应该在每个程序文件中包括一个头与下面的注释:

应用程序的名称、版本和简要说明

文件到其他文件和包/组的从属关系

4. 通用的代码保持在最低限度

在项目中为加快开发速度和引用方便,我们会使用公共脚本,然后使用include包含语法引入当前PHP脚本。

如果是一个复杂的Web应用程序,使用公用脚本也会成为头痛的问题,如果在文件中使用过多的include和require,多人同步开发工作中他们未必会完全理解,所以要最大限度地减少使用。

如果通用的代码包含其他模块函数和类定义,特别控制结构,需要重构函数或类。作为基本经验法则,控制结构不应该包括在公共的代码中。

命名方式

类、变量等命名,遵循标准模式和代码风格

命名有意义且无歧义

命名是否过长或过短

变量名和常量的长度平均在8-12个字符,特殊的可以达到25个字符,但更重要的是不要命名成为不可读的、繁琐的名字。

方法/函数的名称应平均控制在15~25个字符长度,例外的可以达到30个字符。

类的命名应该控制在10~15个字符。

表达式

表达式遵循标准格式与风格

表达式理解复杂还是容易

代码段

1. 代码段遵循标准模式/风格

保持自己的开发标准,比如在合适的地方加括号、空格等,你的眼睛舒服地看到规律代码结构时,在读代码时会更增进理解。

2. 代码段大于25行时需要重构

如果代码块超过25行,建议至少重构一次,如果愿意多次重构代码,可以达到最佳效果。

有时代码块会有些特殊,可能会达到50行甚至更多。这种情况还是少数,应尽量避免。长代码的可读性不够好,越小块代码的可读性和可维护性越大。

3. 有对功能说明的注释

一般的,在长于平均水平(超过20行)的代码块,或执行复杂的任务或逻辑处加入注释。

可扩展性与效率重构

模块化的代码往往是高度可扩展的,而过程化的代码往往可扩展性低,过程化代码会更有效率。因此一些常用的做法是,以模块化的方式开发和部署在一个过程代码的方式,可以做到两全其美。

关于可扩展的代码的主要方面是:

(正常的逻辑流程和设计模式)逻辑的可扩展性

模块化设计

去除耦合与封装

1. 大部分的代码块,按照正常的逻辑流程

我们正在处理的小的逻辑问题,请使用的是正确的结构,即应该使用最合乎逻辑的语言功能。例如,通过简单的数组循环用foreach,而使用for循环则是不合理的。

2. 复杂问题的解决方案遵循标准设计模式

大型项目中使用设计模式时必须的,因为它们通常容易理解,并能够考虑到将来开发的扩展性。

一般的,使用一个标准软件模式来解决一些复杂的额外难题,要先编写实现的基类。比如什么时候使用factory模式,什么时候使用proxy模式。

模块化设计

1. 代码结构模块化设计

模块化设计的意义就是将产品按照业务不同划分为不同的模块。由小的应用程序组合成一个大的应用程序,这样更容易开发和易于扩展、维护。

其中每个模块都有自己的特性和功能,可以担当独立的功能和应用。

模块核心功能和应用程序的入口点,我们可以在将来方便地添加新的模块以扩展功能,这就是为什么现在大多数产品都设计为插件模块来进行开发。

因此开发者在应用程序结构设计时,需要有模块/插件的安装和卸载功能,需要开发的核心模块,对插件的基本结构进行定义。

一个代码中的一些模块作为单一的实体和比较少的参数,若不是这样就需要把它分解成一个新的模块。当我有一个功能,在一个单独的类中做了越来越多的 副作用任务时,就需要毫不犹豫地把这些迁移到一个新的模块。

一个精心设计的应用设计模块化后,可以有效地防止只为一个任务而写的孤儿代码。当我们写有一些孤儿代码时,我就将它迁移到一个实用模块中,用于处理通用功能和完成小任务,该模块就是通用的函数库

当这些任务足够大、需剥离逻辑,我会再尝试将它们移动到自己的独立的模块中,这种重构是一种持续的过程。

2. 模块依赖性最低

模块自身提供尽可能多的功能,且天然地和其他模块有良好的依赖关系,比如电子商务中库存模块依赖于财务模块。

事实上有许多硬的依赖关系是不好的,它们使调试和部署变得比较困难。为了保证模块间的依赖关系,我们需要遍历当前每一个模式,然后在代码库中看是否有任何模块之间存在硬的依赖关系后清除它们

如果不能,应该将这两个模块合并到一个模块,并命名为通用的名称。

封装与解耦

1. 函数、方法和类低耦合,高内聚概念

常见的例子,我们在程序中添加分页功能,从数据库中取得结果显示,这是一个很常见的任务。在早期新手开发中,会在进行分页的程序里写一些代码取数据库的结果来分页,构成非常具体的功能。

在后来发现,分页很多功能的代码是共通的,也就是能够复制的逻辑或代码,因此可以将这些共通的代码抽象出来形成一个分页函数或类。诸如此类,你也会发现需要对自己代码解耦,以提高代码的可重用性和可扩展性。

2. 单一职责:模块和组件相对解耦

代码保持最低限度的依赖,这是解耦的正确途径。比如一个类只做一件事,并把这件事做好,且只有一个引起它变化的原因。

单一职责原则可以看作低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。职责过多,可能引起它变化的原因越来越多,这将导致职责依赖,相互之间就产生影响,从而极大地损伤其内聚性和耦合度。单一职责,通常意味着单一的功能,因此不要为一个模块实现过多的功能点,以保证实体只有一个引起它变化的原因。

降低依赖关系重要的指标是可用性和可扩展等复杂度没有增加。

代码效率

大多数Web应用都要实现快速响应,所以效率通常依赖网站开发者,让系统“瓶颈”保持在最低限度,无论是内存消耗,还是CPU占用率、可用性和节省网络流量。我们都希望应用程序的响应速度和HTML渲染是“相当快”。

内存缓冲与网络资源缓存,可有效地利用高速缓存高效地利用内存和处理器,让Web应用具备高性能。

比如读取一个大文件时,可将文件从磁盘拆分读取输出到网络缓冲区。否则需要读取整个大文件,客户可能不知道要过多久才能下载,并可能中断应用程序的响应。

除了常见的问题和重构策略外,牢记我们谈论的效率不仅仅是重构了事,也要有优化的兼顾。

网络带宽的效率

1. 从服务器请求资源是否在较低限度

一个Web应用程序是一些业务逻辑,例如用PHP编写的脚本,输出HTML、CSS和JavaScript到客户端浏览器。

实际情况上,总有一个用户会为你的页面加载而等待,,无论他是愿意等待得再久一点,还是发现加载很慢,而关闭窗口跑掉。一般来说,页面在512KB的连接速率上,唱过5秒还没有显示完成,用户将开始感到不耐烦。Amazon有一个统计数字:如果页面在3秒内未加载完成,将流失57%的用户,结果是PV减少,用户率降低。每延长1秒,会损失16亿美金。

为了能够快速加载,你需要减少从服务器请求资源的数量。比如分离CSS文件,而不是将它们合并在一个文件中。另外js也和css一样,也需要进一步来优化。

我们还可以压缩CSS和js文件的尺寸,使用js压缩工具,如YUIJS压缩机和CSSO。对图片可以使用CSS sprites的技术,这种技术可以将一组图片合并在一起成为一个单一的文件,可以有效减少带宽占用。

2. 使用Ajax

现代化的Web应用基于Ajax的异步调用功能越来越多,这没有任何问题,只要你的服务器回调时没有太大延迟即可。

但需要注意的是,不要过度使用Ajax来执行非常简单的任务。没有必要尽量不去调用服务器,如果真的需要,再去取,而不是持续的实时数据。如果需要像股票类的实时数据,可以考虑使用数据push技术,如Comet和WebSocket。

内存效率低

1. 是否使用了递归

在PHP中,使用递归是有负面代价的:它会比较占用内存空间

2. 重复太多了吗

使用递归迭代的局限性已了解,另外涉及代码效率,比如嵌套循环,可以用其他解决方案来解决。

比如我们的页面要显示20条新闻文章,可以先显示最新的5条,再加一个更多的链接。

3. 检查数据库查询

这个查询很简单,但问题是当用户表超过10000个时,查询有很多列,这个SQL在一个查询数据库的所有行,效率大大降低。

这是一个典型的无计划的查询。如果你没有使用FROM子句,应该花费一些时间来规划需要的SQ L查询,需要决定什么样的条件的数据需要查询。

另外随着记录成倍的增长,我们应该提前考虑到这一点,不要讲*号看作是理所当然的。要限制特定的字段和行数,如果实在不了解的话,也要使用LIMIT子句限制生成的记录集。

标签:

X 关闭

X 关闭