Loading
0

三十年软件开发之路:老码农的自我修养!
被墙跳转TG:@qianhenetwork QQ 851617266

301免备案跳转微信公众号
腾讯云服务器大促销。
华为服务器

黑客攻击 安全 代码 安全漏洞 程序员

声明:本文来自于微信公众号 CSDN(ID:CSDNnews),作者:Julio Biason,授权tag知识库转载发布。

【CSDN编者按】“千帆过尽仍少年”,对于程序员来说,保留技术初心、不断提升实力是夯实自己的不二法则。而本文的作者,作为一名有着三十多年开发经验的“老”程序员,就在本文中详细总结了自己这些年踩过的坑和实践得出的真理,谈到了包括软件开发、团队工作、个人成长等方方面面。相信阅读本文后,会帮助你成为更优秀的程序员。

声明:本文已获作者 Julio Biason 翻译授权。

译者 | 王艳妮,责编 | 郭芮

以下为译文:

这是我 30 年来从事软件开发过程中所学到的一些实际经验,可能有些听起来愤世嫉俗,但都是我的切身经验之谈。

再次强调,有些内容真的是愤世嫉俗,有些则是对不同工作岗位的长期观察。

软件开发

先明确问题,再开始写代码

如果你不知道你想要解决的问题是什么,那你肯定就不知道要写些什么代码。在编写任何代码之前,先明确地把应用程序是如何工作的写下来。

“如果没有需求或设计,编程就是向空文本文件不断增加bug的艺术。”——Louis Srygley

有时,即使只是“电梯演讲”(指短时间内表述结果内容)那么长——用仅仅两个自然段来描述这个应用程序的功能——也足够了。

有时候我看着自己的代码发呆,不知道下一步该怎么做,其实往往是因为下一步本来就还没有被定义出来。一般出现这种情况,就意味着是时候停下来,与同事们讨论一下了——或者重新考虑解决方案。

将步骤写为注释

如果你不知道如何开始,请先用自然语言、英语或你的母语描述应用程序的流程,然后用代码填充注释之间的空白。比这更好的做法是:将每个注释视为一个函数,然后编写出能完全实现其功能的代码。

Gherkin是帮助你了解期望(expectation)的好帮手

Gherkin是一种测试描述格式,它指出“鉴于系统处于特定状态,当发生某些事情时,这是预期的后果”。即使你不使用任何能读取Gherkin的测试工具,它也会让你很好地理解应用程序的预期效果。

单元测试很好,集成测试更好

在我目前的工作中,我们只测试模块和类(例如,我们只为视图层编写测试,然后仅测试控制器层,依此类推)。它能让我们了解到某一部分有没有出错,但缺乏对整体的观察——而集成测试测试了整个系统的行为,在这方面会表现得更好。

测试可以让API更好

我们在不同层次中编码:有一个存储层,应该使我们的数据永久存储;有一个处理层,应该对存储的数据进行一些转换;有一个视图层,它有关于数据必须如何被展示出来的信息......等等。

正如我所提到的,集成测试感觉更好,但是单独测试不同层可以让你更好地了解其API。然后你可以更好地了解如何调用东西:API是否太复杂了?是否需要保留大量数据才能进行一次调用?

做你知道如何在命令行上运行的测试

也不是说命令行对于任何项目都很重要,但是当你知道运行测试的命令时,你就知道如何让测试的执行自动化起来,然后你可以在一个连续的集成工具中使用这些测试。

时刻准备好扔掉你的代码

很多人在刚开始使用TDD(测试驱动开发,Test-Driven Development)时,一旦被告知他们可能不得不重写很多东西,就会变得很生气。

TDD“旨在”扔掉代码:越了解你的问题,那么你就会越明白,无论你写了什么,从长远来看都无法解决问题。

所以你不应该担心这个。你的代码不是一面墙:如果你必须永远抛弃它,那也不是白白浪费了材料。当然这意味着你编写代码的时间一去不复返了,但是你现在对这个问题有了更好的理解。

好的语言生来带有综合测试

可以肯定的是,如果一种语言在其标准库中自带一个测试框架——即使小得不能再小——那么与没有测试框架的语言相比,它周围的生态系统仍将拥有更好的测试,无论该语言的外部测试框架有多好。

未来思路是垃圾思路

当开发人员试图解决问题时,他们有时会试图找到一种方法来一下解决所有问题,包括未来可能出现的问题。

但现实就是这样:未来的问题永远不会到来,你最终要么必须维护一堆永远不会被完全使用的庞大代码,要么得整个重新写,因为有一大堆屁用没有的东西......

解决你现在遇到的问题,然后解决下一个,然后再下一个。直到有一天,你会发现这些解决方案中显现出了一种固定的模式,然后你才能真正地“一次性解决所有问题”。

文档是写给未来自己的情书

我们都知道,为函数、类(class)和模块编写该死的文档是一个痛苦的过程。但是以后当你看到文档就能回想起来当时你编写函数时的思路,你就会明白将来文档能在关键时刻救你一命。

功能文档是份合同

当你以编写文档作为自己编程工作的起始点时,你实际上是在签订合同(可能是跟未来的自己):我说了这个函数要做这件事情,那么它就必须做这件事情。如果稍后你发现代码与文档不匹配,那你就是代码出了问题,而不是文档出了问题。

如果一个函数的描述包含“和”,这就是不对的

一个函数应该且仅应该做一件事,真的。当你编写函数文档并发现你写了“和”这个字的时候,这意味着该函数不仅仅是做一件事。那么就需要将该函数分解为两个独立函数并删除“和”。

不要使用布尔型变量作为参数

当你设计一个函数时,你可能会想要添加一个flag——不要这样做。

现在,让我给你举个栗子:假设你有一个消息传递系统,并且有一个函数可以将所有消息返回给用户,称为getUserMessages。但有一种情况是需要返回每条消息的摘要(例如,第一段)或完整消息,因此,你添加一个名为retrieveFullMessage的flag/布尔参数。

再说一次,不要这样做。

因为任何读你代码的人都会看到getUserMessage(userId,true)并想知道这里的true到底是个什么意思。

你可以将函数重命名为getUserMessageSummaries并使用另一个getUserMessagesFull或类似的东西,但每个函数只调用原始的getUserMessage为true或false——但是类/模块外部的接口仍然是清晰的。

但是一定“不要”在函数中添加flags / Boolean作为参数。

注意界面的变化

在上面几点中,我提到了重新命名函数的问题,如果你能控制使用该函数的整个源头,那就不算是问题,只需要搜索和替换即可。

但是,如果该函数实际上是由库公开的,那么你不能随便地更改函数名称。这将打破你无法控制的许多其他应用程序,并惹恼其他人。

你可以通过文档或某些代码功能创建新函数并将当前函数标记为已弃用,然后,经过几次释放后,你终于可以Kill掉原来的函数了。

(你可以做的一个有些混蛋的举动是创建新函数,将当前函数标记为已弃用,并在函数开头添加一个休眠,这样一来使用旧函数的人会被迫更新。)

好的语言自带集成的文档

如果语言有自己的方式来记录函数、类、模块或其他,而且带有一个哪怕最简单的文档生成器,你就可以确切知道所有的函数、类、模块、库、框架都具有良好的文档了(不是说一定特别好,但至少是比较好的)。

大多数情况下,没有集成文档的语言,文档方面做得都不怎么样。

一门语言绝不仅仅是一门语言而已

编程语言就是你写的、而且能做事情的东西,但在特殊关键词以外它还有很多别的东西:它有一个构建系统,它有一个依赖控制系统,它有一种使工具/库/框架互动的方式,它有一个社区,它有一种与人打交道的方式。

不要仅仅因为一种语言容易使用就选择它。永远记住,你可能因为一种语言的语法很简明而支持这种语言,但是与此同时你也是在支持维护人员对待这个社区的方式。

有时候,宁愿让应用程序崩溃也不要什么都不做

虽然这听起来很奇怪,但即使在处理过程中添加了某些错误,也不要默默地捕捉到错误但什么都不做。

Java中一个可悲的常见模式是:

image.png

这看起来跟处理异常没有什么关系——除了重复了一遍,仅此而已。

如果你不知道如何处理它,那就随它去吧,你早晚会知道它会发生什么。

如果你知道如何处理该问题,那么就处理它

与前一点相反:如果你知道什么东西在何时会导致异常/错误/某种结果,并且知道如何处理它,那么就请处理它吧。显示错误信息,尝试将数据保存在其他位置,将日志文件中用户的输入捕获到以便以后处理,但要记得处理它。

类型决定你的数据是个什么东西

内存中只是一串字节序列;字节只是 0 到 255 之间的数字组合;这些数字的真正含义取决于语言的类型系统。

例如,在C中,值为 65 的char型变量可能是字母“A”,值为 65 的int型变量是数字65——处理数据时请不要忘记这一点。这也是为什么大多数人在用布尔型变量做加法以查看True的数量时经常出错。

现在,让我展示一下我最近看到的一个JavaScript里的例子:

image.png

如果你的数据具有模式(schema),请使用结构(structure)来保留它

你可能会想要使用列表(或元组,如果你用的语言允许的话)来保存数据,如果它很简单——比如说,只有 2 个字段。

但是如果你的数据有一个模式(schema),有一个固定的格式——你应该每次都使用一些结构来保存它,不管是用struct还是class。

理解并保持cargo cult的方式

“Cargo cult”是一种理念,如果其他人那样做了,那么我们也可以。大多数情况下,cargo cult只是对一个问题的偷懒的解决方法:

“如果X这样做了,我们为什么要考虑如何正确存储我们的用户数据?”

“如果有某巨头公司是这样存储数据的,那么我们也可以”。

“如果有某巨头公司支持这种做法,那就说明这种方法很好。”

......

不要管所谓的“合适的生产力工具”,你只需要尽力去push进程

“合适的生产力工具”其实意味着:对于某件事情,有一个正确的工具和一个错误的工具——例如,应该使用另外的某种语言/框架而不是当前的语言/框架。但每当我听到有人提到这个词时,他们都是在试图推销他们喜欢的语言/框架,而不是合适的语言/框架。

“正确的工具”比你想象的更明显

也许你当前的项目需要处理一些文本,也许你很想说“让我们用Perl吧!”,因为你知道Perl在处理文本时非常强大。

但你漏掉了哪一点呢?你在一个C的团队工作,每个人会C,而不是Perl。

当然,如果它是一个小的、“放在角落”的不起眼的项目,那么用Perl就可以了——但如果它对公司很重要,那么最好还是用C。

PS:你的英雄项目(本文稍后将详细介绍)可能因此而失败。

不要跟你项目之外的事情纠缠

有时人们会试图改变外部库/框架,而不是使用适当的扩展工具——例如,直接对WordPress或Django进行更改。

这样很容易让你的项目秒瘫痪,变得无法维护。一旦发布了新版本,你就必须与主项目保持同步,并且很快就会发现改动不再适用,你将把外部项目留在一个旧版本中,且充满了安全漏洞。

数据流动比模式更重要

(再次说明,这仅仅是个人意见)当你了解数据如何在代码中流动时,你的代码质量就会更上一层楼,这比无脑应用一堆设计设计模式(design pattern)好多了。

设计模式是用来描述解决方案的,但它不能找到解决方案

(同样,个人观点)大多数时候我看到设计模式被应用的时候,它们被用作寻找解决方案的一种方式,所以你最终会扭曲一个解决方案——有时候,甚至是扭曲问题本身——来适应某个设计模式。

首先,解决你的问题,找到一个好的解决方案,然后你可以检查模式,以提供如何命名该解决方案的思路。

我经常看到这种情况发生:我们有这个问题;一个设计模式接近正确的解决方案;让我们使用这个设计模式吧;现在我们需要在适当的解决方案基础上添加很多东西以适应这个设计模式......

学习函数式编程的基础知识

你不需要彻底搞懂“什么是一个单子(monad)?”和“这是一个函子(functor)?”等问题,但要知道不能一直改变数据——使用新值创建一个新元素(将数据视为不可变),并尽可能使函数/类不保留某些内部状态(纯函数/类)。

认知成本是可读性的杀手

“认知失调”是一种高大上的说法,但其实意思就是“我需要同时记住两个(或更多)不同的东西才能理解这一点。”把这些不同的东西保留在你的头脑中会产生成本,并且事物之间关联性越小,这种成本就越会不断积累(因为你必须把所有这些都记在脑子里)。

例如,将布尔值相加以计算True的数量就是一种轻微的认知不协调;如果你正在阅读一段代码并看到一个sum()函数,你知道它是列表中所有数字的总和,你就预料到列表由数字组成,但我看到过人们使用sum函数计算布尔值列表中的True的数量,这也太特么容易让人糊涂了吧。

Magical Number 7 ,正负二(7+- 2 的范围内)

“magical number”是一篇心理学文章中提到的概念,意思指人们可以在同一时间记住的事物的数量。如果你有一个函数,它调用一个调用函数的函数,该函数又调用一个调用函数的函数……再往下说下去你可能要疯。

想一想:我会得到这个函数的结果,然后将它传递给第二个函数,得到它的结果,然后传递给第三个函数。但是:

  • 当今,心理学家更多地谈论Magical Number 4,而不是7。

  • 把函数当成写作文(如“我将调用该函数,然后该函数,然后该函数......”),而不是函数作为主体(如“该函数将调用该函数,将调用该函数......”) 。

走捷径挺nice的,但只是在短期内如此

许多语言、库、框架都有缩短工作时间的方法,减少了需要你打字输入的内容。但是,稍后,这些东西会让你栽跟头,你将不得不弃用这些捷径并懂得人间正道是沧桑的道理。

因此,在使用之前,先了解那些捷径是如何做事情的。

你不需要先用难的方式写东西然后再用捷径的方式清理:你只需要走捷径在后台做事情,所以你至少知道使用它可能出错的地方在哪里,以及如何用非捷径方式替换它。

抵制“轻松”的诱惑

当然IDE会帮助你完成大量的自动填充并让你轻松构建你的项目,但是你明白发生了什么吗?你了解你的构建系统是如何工作的吗?如果你必须在没有IDE的情况下运行你的程序,你知道该怎么做吗?如果没有自动填充你能记住你的函数名吗?是不是有办法打破/重命名一些东西让它们更容易被理解?......

要对窗帘后面的东西保持好奇。

总是在你的日期中使用时区

处理日期时请始终添加时区。你的计算机时区和生产服务器时区(或其中一个实例时区)将始终存在问题,你将花大量时间来调试为什么界面总是显示错误的时间。

总是使用UTF-8

在日期上出现的问题,也将出现在对字符的编码上。所以时刻记得将你的字符串转换为UTF8,将它们作为UTF8 保存在数据库中,在你的API上返回UTF8。

你可以转换为任何其他编码方式,但UTF8 赢得了编码战争,因此更容易保持这种方式。

从笨办法开始

远离IDE的一种方法是“从笨办法开始”:只需获取编译器并获得一个带有代码突出显示的编辑器(任何编辑器),做你该做的事情:写代码,构建它,运行它。

不,这并不容易。但是当你跳进某个IDE时,你看到某个按钮只会简单地想,“是的,它会运行它”(顺便说一下,这正是IDE所做的)。

日志用于事件,而不是用户界面

很长一段时间,我使用日志向用户显示正在发生的事情——因为,你知道的,使用单个东西会更容易一些。

使用标准输出通知用户发生了什么事件,使用标准错误通知用户有关错误的信息,但使用日志来捕捉可以在日后轻松处理的东西。

将日志想成是你必须解析以便在那时从中提取一些信息的东西,而不是用户界面,它不一定要是让人看得懂的明文。

Debugger们被高估了

我常常听到很多人抱怨,不能Debug的编辑器有多糟糕。

但是当你的代码投入生产时,你无法运行你喜欢的Debugger;哎呀,你甚至不能运行自己喜欢的IDE;但是logging......logging随处都可以运行......你可能在崩溃时没有所需的信息(例如,不同的日志记录级别),但你可以启用日志记录以便稍后找出某些内容。

不是说Debugger们很糟糕,只是它们没有大多数人想象的那么有用。

始终使用版本控制系统

“这只是个随便写的破程序,我只想学点东西”——这不是一个不使用版本控制系统的好借口。如果你从一开始就使用版本控制系统,那么当你做了一些傻事时,撤销会更容易。

每次提交一个更改

我见过人们编写提交消息,如“修复了问题#1,# 2 和#3”。除非所有这些问题都是重复的——那么其中两个应该已经不存在——它们应该分三次提交,而不是一次。

尝试在每次提交中只进行一项更改(并且这里的更改并不是“一个文件更改”; 如果一个更改需要更改三个文件,你应该将这三个文件一起提交。想想“如果我还原这一步,那是什么消失了?“)

当你过度交换时,“git add -p”是你的朋友

(仅限Git的主题)Git允许使用“-p”部分合并文件,这允许你仅选择相关更改并不管其他更改——可能是为了新的一项提交。

按数据/类型组织项目,而不是功能

大多数项目的组织如下:

image.png

换句话说,它们使数据按功能分类组织(所有传入的模型都在同一目录/包中,所有过滤器都在同一个目录/包中,依此类推)。

这很好,很有效。但是当你按照数据进行组织时,将项目拆分到较小的项目中会更容易——因为在某些时候,可能你想要做的与你现在正在做的几乎一样,只是有些许小的差异。

image.png

现在,你可以创建一个仅处理Data1 的模块,另一个仅适用于Data2 的模块,依此类推,然后你就可以将它们分解为独立的模块了。然后当你有另一个项目也有Data1 但也处理Data3 时,你可以重新用上Data1 模块中的大部分内容。

创建库

我已经见过很多项目要么创建一个包含不同项目的大型存储库,要么保留不同的分支,这些分支不被用作以后加入主要开发区域的临时环境,而作为一个小而不同的东西延续下去了(从上文讲到的模块化角度来说,请想象一下,我没有构建一个重用Data1 类型的新项目,而是拥有一个具有完全不同的主函数和Data3 类型的分支)。

为什么不将公共部分拆分出来加到库里并在不同的项目中应用它呢?

原因在于,大多数情况下,“因为人们要么是不知道如何创建库,要么是他们担心如何将这些库‘发布’到依赖源中而不致泄露(因此也许你也应该了解你的项目管理工具如何检索依赖项,以便你可以创建自己的依赖项存储库)。”

学会监控

从前,为了理解系统的行为方式,我添加了大量的指标:输入速度、输出速度、中间滞留数量、已处理的数量......这样可以很好地了解系统的行为方式:速度在下降吗?如果是的,那我可以检查正在输入系统的内容以了解原因。在某些时候下降是否正常?......

事实上,在此之后,试图查明一个没有任何监控的系统有多健康就变得很奇怪,仅使用“是否应答请求”来检查系统运行状况不再适用。

尽早添加监控将有助于你了解系统的行为方式。

config文件是个好东西

想象一下,你编写了一个函数,你必须为它传入一个初始值才能开始运行(例如,一个推特用户帐户ID)。但是后来你又必须用两个值来做,所以你就直接用另一个值再次调用了该函数。

使用配置文件更有道理,只需使用两个不同的config文件运行应用程序两次。

命令行选项很奇怪,但很有帮助

如果你将某样东西移动到config文件,你还可以通过添加选项来选择配置文件并公开它来帮助用户。

现在对每种语言的命令行选项都有一些库可以处理,这将有助于你构建一个良好的命令行,并为你的用户提供一个标准的接口。

不仅仅是功能组成,还有应用程序组成

Unix自带“应用程序只做一件事,并且把它做好”的理念。

如今,我说你可以使用一个带有两个配置文件的应用程序,但是如果你需要两个应用程序的结果呢?那时你可以编写一个应用程序,用两个配置文件读取第一个的结果并转换为单个结果。

即使是做APP,也要从原始的东西开始

APP的开发可能会涉及微服务——这很好——但微服务需要一些关于应用程序如何通过线路(协议等)在彼此之间“对话”的想法。你不需要从那开始,应用程序都可以从文件中写入和读取,这样容易多了。

当你了解了网络是如何工作后,再通过电话进行交谈时可能会担心的吧。

优化是面向编译器的

假设你需要更高的性能,你可能很想看看你的代码和“可以在这里挤出更多性能的东西”或“如何在这里删除几个循环来获得更多速度”。

好吧,猜猜怎么着?编译器知道如何做到这一点。智能化的编译器甚至可以删除你的部分代码,因为它始终会生成相同的结果。你需要做的是为代码考虑更好的设计,而不是如何改进当前代码。

代码是为了让人类阅读的、优化面向编译器的,因此,找到一种智能的方法来解释你在尝试做的是什么(在代码中)而不是使用更少的话语来表述。

通过懒惰(评估)

Lisp很久以前就这么做了,而现在大多数语言都是这样做的。

例如,Python有yield语句,它将停止当前函数的执行并立即返回值,只有在再次调用该函数时才会产生新值。如果你将使用yield的函数链接起来,则不需要像保留返回列表的函数那样多的内存。

在团队/工作上

code review并不是为了彰显风格

花点时间进行code review,指出架构或设计问题,而不是代码样式(风格)问题。没有人真正喜欢那些在code review中写“你在这一行中留下空白了”或“括号前缺少空格”的人。

现在,如果你确实发现了架构或设计问题,那么你可以顺便说一下代码风格问题。

代码格式化工具还可以,但它们也不是无往不胜的

团队可能想要避免在code review中讨论样式,因而可能会考虑使用代码格式化工具在提交之前自动格式化代码。

是的,这部分解决了这个问题,但是还有一个小问题:我们人类不像计算机那样能灵活地阅读代码,计算机可读的内容可能无法被人阅读。当然,有人试图在有利于人类阅读的方面创造一些启发式方法,但这并不意味着这些方法正确。

如果你使用代码格式化工具,请使用它来找出最能更改代码的位置。你可能需要简化这一部分的代码,以避免它出现混乱。

代码风格:遵循它就是了

如果你的项目具有已被定义的代码样式,则必须遵循它。有时可能不清楚(“这个结构/类应该是单数还是复数”?),但请尽力遵循它。

...除非代码样式是Google Code样式

(完全个人观点,你不同意也没关系)每次谷歌发布自己的编码风格,都是一场垃圾焚烧。社区之前采用了更好的风格方式,谷歌带来一个与此很不相同的的风格,只是为了能使其在自己名下。

C / C ++只有一种编码风格:K&R

(再次,完全个人意见)其他所有编码风格都是错误的。(笑)

Python只有一种编码风格:PEP8

社区(大部分)使用PEP8 风格,遵循它,那么你的代码可以顺利地与生态系统中的其他部分集成。

显式优于隐式

你知道什么是有史以来最糟糕的函数名称之一吗?sleep()。

睡了多久?是几秒还是几毫秒?

对你使用的东西要表达地明确一些,sleepForSecs和sleepForMs并不完美,但比一个单纯的sleep更好。

(当你编写应用程序命令行界面或其配置文件时,请考虑这一点。)

(我可以在这里抛出整个“Python之禅”,但我正在努力专注于讲个人的,直接的体验。)

公司想要专才,但全才在公司待的时间更长

如果你对单一语言了解很多,那么它可能会让你更容易找到一份工作,但从长远来看,一门语言的使用可能会消失,你就需要再学一门别的语言了。适当了解许多门其他语言有助于长远发展,更不用说这可能有助于你想出更好的解决方案了。

“一种不能影响你对编程的思考方式的语言,不值得了解。”——Alan Perlis

很长一段时间,我遵循着一个简单的编程规则:我在家里用来玩的语言不应该是我在工作中使用的语言。这使我能够接触到后来我在工作代码库中应用的新内容。

我通过编写Rust代码了解了泛型如何在Java中工作;我理解了Spring如何完成依赖注入因为我之前有学过如何在C++中实现。

心中有用户

想一想你将如何使用你从用户那里收集的数据——这在当今“隐私”变为一种奢侈的时代更为普遍。

如果你捕获任何使用数据,请记住保护它免遭未经授权的使用。

处理用户数据的最佳安全方法是压根不捕获它

你可以确定,在某些时候,数据会因某些安全漏洞或人为干扰而泄漏。如果你没有捕获任何用户数据——或以匿名方式存储——你将不会遇到任何问题。

记下来那些“让我花了一个多小时才解决的愚蠢失误”

我尝试过,但从未真正建成过一个列表来记录那些需要花一个多小时才能修正的失误,这种失误仅仅是“忘了添加依赖”或“添加注释”一类,可我不止一次与这些愚蠢的失误作斗争了。

但你应该尝试保留一个列表来记录那些让你花了一个多小时才解决的愚蠢失误,因为有了它以后你解决起这类失误来要更快一些。

如果它无法在你的计算机上运行,那么你就有麻烦了

我看过很多系统永远无法在孤立的计算机上运行,比如开发人员工具,因为系统需要在专门的环境中运行。

这真的会扼杀生产力。

如果你的系统将在一个专门的环境中运行——包括“云”——那就去找可以抽象你所用之物的东西。例如,如果你使用的是AWS SQS(队列),请找到一个可以抽象队列工作方式的库,这样你也可以使用RabbitMQ了,就可以在你自己的计算机上轻松运行了。

如果你使用的是非常专门化的东西,你可能必须自己编写抽象逻辑了,将其与主系统隔离,这样你就可以安心开发主要产品。

301免备案跳转微信公众号
华为服务器
腾讯云服务器大促销。

声明:站长码字很辛苦啊,转载时请保留本声明及附带文章链接:https://www.zfcdn.xyz/showinfo-36-35619-0.html
亲爱的:被墙域名跳转TG:@qianhenetwork QQ:851617266,可否收藏+评论+分享呢?
上一篇:移动网页速度慢怎么解决?
下一篇:网站被攻击 该怎样查找漏洞并进行修复