所有这些要点都可以应用于移动开发、Web 前端和后端。我从不同的团队以及过去 6 年中遇到的问题中收集了这些实践。当您从头开始构建项目时,这些实践尤其有用。其中一些可能非常适合您,而另一些则可能不适合。如果您有自己的方法和不同的经验,如果您在这里分享它们,我会很高兴。顺便说一句,如果您是寻求晋升的中级或初级开发人员,那么在您的团队中实施这些做法确实会有所帮助。我们走吧!
在标准的软件开发流程中,当业务提出新功能请求时,它会分布在几个团队中:前端、后端和移动应用程序开发。
然后,每个团队进行计划和任务分解。但是,如果后端团队需要更多时间来开发他们的部分怎么办?如果他们每周只能交付一次端点怎么办?
后端成为瓶颈。
移动和前端开发团队最后是这样工作的:“哦,后端已经实现了这个,让我来接这个任务。”然后,他们休息一下,将上下文切换到另一个功能,然后循环继续。这会导致疲劳、速度下降和质量下降。
解决方案:与后端团队达成合同并模拟所有请求。
1. 与后端团队就端点和实体进行协调。
2A.使用存根响应实现后端 API。 Faker 库可以帮助生成示例数据。
2B。或者在前端实现存根。这可以是直接在代码中包含数据的对象。例如,在 Node.js 中,您可以使用动态导入有效地实现这一点并避免增加包大小:
getUser() { return import('../../assets/mocks/users') .then(data => data.userById) .then(deserializeUser); };
这也可以是一个模拟 HTTP 服务,它从资产中获取 JSON 文件而不是发出真正的请求。
隐藏功能标志后面的功能。
当后端准备就绪时,如果您使用前端存根方法,请切换到实际 API,并验证一切是否按预期工作。并开启这个功能。
现在,您可能已经注意到,在上一节中,我提到了功能标志。简而言之,功能标志又名功能切换允许开发人员在实时环境中打开或关闭功能。在某些情况下它们也很有用:逐步推出新功能、执行 A/B 测试、启用 Beta 功能以及实施修补程序。
我们使用 Gitlab 来存储功能标志。它是后端和前端项目都使用的专用存储库。好消息是它有一个用户友好的用户界面,因此产品经理可以自己管理功能。以前,我们曾经分别为每个项目存储库使用功能标志。然而,这种方法并没有提供一次性禁用整个产品功能的能力。因此,我们将所有内容移至单一存储库。
在代码中,它看起来很简单:
if features.YOUR_FEATURE
放在需要隐藏的代码中。
当我们的产品从 MVP 阶段过渡到生产应用程序时,我们担心用户会遇到我们无法重现甚至可能没有意识到的错误。在研究了错误跟踪工具之后,我们选择了 Sentry。经验是积极的。现在,让我们来看看一些重要的细微差别。
在引擎盖下,将跟踪任何未捕获的异常。随着应用程序和用户数量的增长,错误的数量会越来越多,以至于几乎不可能注意到任何真正重要的事情。如果你不过滤掉不需要的东西,Sentry 会变成垃圾箱。例如,取消请求、连接错误和连接脚本错误等事件是完全无用的,只会向您的工作电子邮件发送垃圾邮件通知。作为解决方案,您可以将过滤器添加到配置中。为此,只需定义一个beforeSend
回调并将其放入您的sentryPackage.init
中。在此回调中,您可以分析每个捕获的错误,如果它无用则将其丢弃(通过返回 null)。下面是一个排除不必要错误的过滤器示例:
function beforeSend(event, hint) { const error = hint.originalException; const externalScripts = [ 'gtm.js', // Google Tag Manager 'watch.js', // X Analytics ].join('|'); const errorsToIgnore = [ AxiosError.ERR_NETWORK, AxiosError.ECONNABORTED, AxiosError.ETIMEDOUT ]; if (axios.isCancel(error) || errorsToIgnore.includes(error.code) || error.stack?.match(externalScripts)) { return null; } return event; }
默认情况下,哨兵可能不会在错误报告中包含请求和响应的内容。没有这些信息,就不可能进行正确的调试。幸运的是,在beforeSend
处理程序中,我们可以包含此信息。
function beforeSend(event, hint) { const error = hint.originalException; if (error.isAxiosError) { const url = error.request?.responseURL; const response = error.response?.data; const request = error.config?.data; event.extra = { ...(event.extra || {}), url, response, request }; } return event; }
错误内容中不应包含密码、电子邮件地址和密钥等数据。 Sentry 具有隐藏此类信息的内置机制。您可以在安全设置中配置它。此外,您还可以在beforeSend
中删除事件对象中的内容
如果您的业务性质禁止将此类数据存储在其他地方的服务器上,Sentry 提供在您自己的服务器上使用它的能力。
想象这样一种情况,你在 Sentry 中成功捕捉到一个错误,但是描述中的信息不充分。您转向日志,但如何在每秒数千个请求和更多日志行中识别具体错误?您如何区分正确的请求、构建请求链并查明确切的错误,尤其是当您的业务有多个团队并与其他服务集成时?这就是跟踪发挥作用的地方。
在我们的具体实现中,我们使用了Jaeger ,它基于 OpenTracing API。
简而言之,每个请求及其所有方法调用都带有唯一标签。每个标签都有对其父标签和一些元数据的引用。这个数字的结构取决于实现,但对于 OpenTracing,您可以在官方存储库页面上阅读它的工作原理并熟悉跨度、引用、子项、父项等术语。在现实生活中,tracing luckily 是很少用到的。但是,在这些罕见的事故中,它可以节省您的时间。
当我们实施金融科技应用程序的 MVP 时,我们有一个非常复杂的形式。那时,我还年轻,经验不足。最终,我们意识到我们的项目正在放缓。我们不得不花费额外的时间来找出原因。我们有很多不必要的重新渲染,因为我们忽略了 React 中与 props 相关的基本规则。我想尽一切可能避免将来出现这种情况。
因此,我向项目中添加了这样的 linters 和 package.json 的额外起始配置以运行why-did-you-render 。简而言之,如果某些东西被不必要地重新渲染,这个插件会发出警告,并建议如何避免它。此外,我们还包括以无头模式运行 Lighthouse 。有人说过早的优化不好,但对我来说,这是一个原则:从一开始就做对。
您可能听说过破窗理论。如果建筑物中有一个破窗而没有人更换它,最终该建筑物中将不会留下一个完整的窗户。
项目中的规则和控制越少,编写低质量代码或以完全不同的风格编写代码的诱惑就越大。不一致的代码增加了理解它所需的时间,而清晰、熟悉和简洁的代码允许快速阅读。在我们的一个团队中,我们在一个地方描述了编码风格。作为一个很好的起点,您可以采用Prettier或Airbnb 代码风格。
已经有大量文献介绍了不同类型的测试、方法以及如何正确编写它们。这里唯一值得一提的是,没有回归测试,任何生产应用程序都无法生存。这就是为什么我们将所有精力都集中在创建一个全面的端到端测试框架上,并在此基础上编写了与 BDD 场景和用户故事相关联的测试。我们使用页面对象模式来组织代码,并使用 Playwright 框架与浏览器进行交互。要跨不同浏览器(包括 Safari)进行测试,您可以使用名为Moon的解决方案。它可以部署在您的其中一台服务器上。
感谢您花时间阅读本文!总之,本文重点介绍了可增强开发过程和代码质量的关键软件工程实践。通过采用后端响应模拟、功能标志、错误监控、性能优化、代码风格标准、回归测试和跟踪等技术,您可以创建更高效、更可靠的软件。让我们继续改进我们的软件并保持联系! :)