实用代码重构,第4部分-效率

tech2023-11-04  99

In part three of this series we dealt with refactoring code for extensibility and discussed logical extensibility, modular design, decoupling, and encapsulation. In this final part of the series, we discuss what the main concerns of efficiency are for your web application and how to refactor for better efficiency.

在本系列的第三部分中 ,我们讨论了用于可扩展性的重构代码,并讨论了逻辑可扩展性,模块化设计,解耦和封装。 在本系列的最后一部分中,我们将讨论对Web应用程序效率的主要关注点以及如何重构以提高效率。

Most web applications are light by nature, so efficiency usually revolves around keeping bottlenecks to a minimum (none in a perfect world), whether they be memory consumption, processor availability, and network traffic. We all want our applications’ timing and rendering of content to be “reasonably fast”.

大多数Web应用程序本质上都是轻量级的,因此效率通常围绕着将瓶颈降到最低(在理想环境中没有瓶颈)而论,无论它们是内存消耗,处理器可用性和网络流量。 我们都希望我们的应用程序的时间安排和内容呈现“合理快速”。

Before I mention some sources of inefficiency though and how to deal with them, you should know that you have two “best friends” when it comes to efficiency: buffering and caching. Buffering allows efficient utilization of memory and network resources, and caching allows efficient utilization of memory and processor. These are two important concepts which you can always use for more performant web apps.

在我提到一些效率低下的原因以及如何处理它们之前,您应该知道在效率方面您有两个“最好的朋友”:缓冲和缓存。 缓冲可以有效利用内存和网络资源,而缓存可以有效利用内存和处理器。 这是两个重要概念,您始终可以将它们用于性能更高的Web应用程序。

You may use these ideas to refactor your code at a fine-grained level, not just as a big solution for a big problem. A good example of granular caching is an image gallery with thumbnails; instead of generating thumbnails dynamically each time you load the gallery, generate them once and cache them. They can be loaded from cache, and the cache can be updated whenever a new image is uploaded to the server. An example for fine grained buffering is reading a big file from the disk or network in chunks (into a buffer). Otherwise, you might not know how long it will take to read the entire file and it can block your application’s response.

您可能会使用这些想法在细粒度的级别上重构代码,而不仅仅是解决一个大问题。 粒度缓存的一个很好的例子是带有缩略图的图库。 而不是每次加载图库时都动态生成缩略图,而是一次生成并缓存它们。 可以从缓存中加载它们,并且每当将新映像上载到服务器时就可以更新缓存。 细粒度缓冲的一个示例是从磁盘或网络中分块读取大文件(放入缓冲区)。 否则,您可能不知道读取整个文件将花费多长时间,并且它会阻止应用程序的响应。

Along with common problems and their refactoring strategies, keep in mind that since we are talking about efficiency, not only bare refactoring is engaged but also some optimization.

除了常见问题及其重构策略外,请记住,由于我们在谈论效率,因此不仅要进行裸重构,还要进行一些优化。

网络带宽效率低下 (Network Bandwidth Inefficiencies)

1. Are resource requests from the server kept to a minimum?

1.来自服务器的资源请求是否保持最少?

A web app is some business logic (written in PHP for example) that generates HTML, CSS, and JavaScript to be downloaded by a client (usually a browser). Keep in mind that you always have someone “waiting” for your page to load, and he’s not willing to wait for very long. Generally speaking, your page should load in around 2.5 seconds on 512Kb connection. For heavy pages, this shouldn’t be more than 5-10 seconds or the user will start to feel impatient. To be able to achieve this, you need to cut down on the number of resources you request from the server. Instead of having many CSS files load, merge them in a single file. The same goes for JavaScript. Then, optimize these aggregate files further.

Web应用程序是一些业务逻辑(例如,用PHP编写),可生成HTML,CSS和JavaScript,供客户端(通常是浏览器)下载。 请记住,您总会有人“等待”页面加载,而他不愿意等待很长时间。 一般来说,在512Kb连接上,您的页面应会在2.5秒内加载。 对于较厚的页面,此时间不应超过5-10秒,否则用户将开始感到不耐烦。 为了实现此目的,您需要减少从服务器请求的资源数量。 与其加载许多CSS文件,不如将它们合并到一个文件中。 JavaScript也是如此。 然后,进一步优化这些聚合文件。

You can easily cut the filesize of CSS and JavaScript files down by at least 30% if you use JavaScript compressors/minimizers such as YUI JS Compressor and CSSO. Some might argue that these are considered optimizations and not code refactoring, but at this point there is some overlap since you minimizing your code to minimize filesize.

如果使用YUI JS Compressor和CSSO之类JavaScript压缩器/最小化器,则可以轻松地将CSS和JavaScript文件的文件大小减少至少30%。 有人可能会认为这些被认为是优化而不是代码重构,但是由于要最小化代码以最小化文件大小,因此这时存在一些重叠。

For images you should use CSS sprites, a technique by which you can group images together in a single file to minimize bandwidth. It’s more network efficient to download a single larger file than a large number of smaller images. You can learn more about creating sprites here.

对于图像,您应该使用CSS Sprites,通过这种技术,您可以将图像分组到一个文件中,以最小化带宽。 下载单个较大的文件比大量较小的图像更有效地利用网络。 您可以在此处了解有关创建精灵的更多信息。

2. Do you use server callbacks wisely?

2.您是否明智地使用服务器回调?

Most modern web-based applications are Ajax-based and call the server in the background naturally. This is fine so long as your server callbacks don’t have much latency. Don’t overuse Ajax for simple tasks that doesn’t require the server. Only use it when you REALLY need to fetch something from the server, and not for true real-time data. If you require real-time data, consider using techniques for data-push such as Comet and WebSockets.

大多数现代的基于Web的应用程序都是基于Ajax的,并且自然在后台调用服务器。 只要您的服务器回调没有太多延迟,就可以了。 不要将Ajax用于不需要服务器的简单任务。 仅在确实需要从服务器中获取某些信息时才使用它,而不是真正的实时数据。 如果需要实时数据,请考虑使用诸如Comet和WebSockets的数据推送技术。

内存效率低下 (Memory Inefficiencies)

1. Are you using recursion?

1.您正在使用递归吗?

Recursion is a powerful programming feature that can save you a lot of hassle when solving some complex problems, like tree traversal and searching. But recursion comes at a price: in languages like PHP it can consume all of your your memory if you don’t know what you are doing. Most problems which are solved with recursion can be solved with iteration, so keep recursion for those which specifically deserve it.

递归是一项强大的编程功能,可以在解决一些复杂的问题(例如遍历和搜索树)时为您节省很多麻烦。 但是递归是有代价的:在PHP之类的语言中,如果您不知道自己在做什么,它可能会占用您的所有内存。 用递归解决的大多数问题都可以通过迭代解决,因此请保留那些特别值得递归的递归。

2. Do you iterate too much?

2.你迭代太多了吗?

Using iteration instead of recursion doesn’t give you the green-light to do whatever you like; each technique has its limits, and when it comes to efficiency, using nested loops is totally inefficient. Use nested loops only for matrix-like problems, those which require 2 or more dimensional iterations and which can’t be solved by other means.

使用迭代而不是递归不会给您开绿灯的机会。 每种技术都有其局限性,并且在效率方面,使用嵌套循环是完全无效的。 仅对类似矩阵的问题使用嵌套循环,这些问题需要二维或二维以上的迭代,而其他方法无法解决。

As well, you should always have some near breaking condition for most of your loops to avoid page load latency. For example, you may want to iterate over the latest 20 news feeds, but why not only the latest 5 and then provide a nice “more” link? Think in that manner and you can increase your page speed.

同样,对于大多数循环,您应该始终处于接近中断的状态,以避免页面加载延迟。 例如,您可能要遍历最新的20个新闻提要,但是为什么不仅要选择最新的5个,然后又提供一个不错的“更多”链接? 以这种方式思考,可以提高页面速度。

3. Are your queries planned?

3.您的查询有计划吗?

Database latency is very common as a bottleneck in PHP applications and so you should always plan your queries. How many of us have written something like this?

数据库延迟是PHP应用程序中的常见瓶颈,因此您应始终计划查询。 我们有多少人写过这样的东西?

select * from users;

The problem becomes relevant when the table grows over 10,000 users and has many columns. You’re selecting all columns of all rows in a single query! This is a typical unplanned query.

当表增长到10,000个用户以上并且有许多列时,该问题就变得很重要。 您在一个查询中选择所有行的所有列! 这是典型的计划外查询。

If you’re not using a ORM, you should dedicate some time to planning the querys you need. Decided exactly what data you need to retrieve, or else you’ll have easily rendered your web-app useless after your first 1K users.

如果您不使用ORM,则应花一些时间来计划所需的查询。 准确确定您需要检索的数据,否则您的前1000名用户将很容易使Web应用变得无用。

Some records can grow exponentially, and so you should account for this in advance. Don’t take the tables for granted. Always select particular columns and rows, and if you’re not sure, use a limit clause to limit the generated result set.

一些记录可以成倍增长,因此您应该提前考虑这一点。 不要把桌子当成理所当然。 始终选择特定的列和行,如果不确定,请使用limit子句限制生成的结果集。

处理效率低下 (Processing Inefficiencies)

1. Do you need dynamic language features?

1.您需要动态语言功能吗?

PHP has a lot of dynamic features, like overloading getters and setters, dynamic instantiation and method/function calling, even the most dangerous eval() method. Use all that wisely. These may be magical elements to some creative solutions to non-standard problems, but generally speaking you don’t need them in standard web app, in which using any extensively is unnecessary added complexity.

PHP具有许多动态功能,例如重载getter和setter,动态实例化和方法/函数调用,甚至是最危险的eval()方法。 明智地使用所有这些。 对于某些非标准问题的创造性解决方案,这些元素可能是不可思议的元素,但总的来说,您不需要在标准Web应用程序中使用它们,因为在Web应用程序中大量使用这些不必要的复杂性。

2. Do you use employ good coding habits?

2.您使用良好的编码习惯吗?

If you need to loop based on the count of an array, count it outside the loop so it’s counted only once. This applies for any function calls too you need to make for comparisons.

如果您需要基于数组的计数进行循环,请在循环之外对其进行计数,因此仅计数一次。 这也适用于所有函数调用,您也需要进行比较。

摘要 (Summary)

The efficiency of your application is a factor of several things. The guidelines suggested here are not a replacement for post-coding optimizations which require you to measure for inefficiencies using profiling tools. They are pre-refactor steps you can take to help reduce bottlenecks before they start. Refactoring code is meant to be an incremental process; do it in simple small steps a bit at a time.

应用程序的效率是多方面因素的一部分。 此处建议的准则不能代替后期编码优化,后者要求您使用性能分析工具来评估效率低下的问题。 它们是重构前的步骤,您可以采取这些步骤来帮助减少瓶颈。 重构代码是一个增量过程。 一次只用简单的小步骤就可以完成。

Refactoring is an important technique in software development that ensures your code health. Throughout this series I’ve introduced a set of practical lists you can use when refactoring. I’ve talked about good code, and how you can achieve good code in terms of Readability, Extensibility, and Efficiency. I hope you enjoy reading the series as I enjoyed writing it! :)

重构是确保代码健康的软件开发中的一项重要技术。 在整个系列中,我介绍了一组在重构时可以使用的实用列表。 我已经讨论了好的代码,以及如何在可读性,可扩展性和效率方面获得好的代码。 希望您喜欢我喜欢写的系列! :)

Image via Fotolia

图片来自Fotolia

翻译自: https://www.sitepoint.com/practical-code-refactoring-4/

相关资源:jdk-8u281-windows-x64.exe
最新回复(0)