发布于 2026-01-06 0 阅读
0

不要像编写单体应用那样编写微服务,保持其可维护性,避免过度设计。

不要像编写单体应用那样编写微服务,保持其可维护性,避免过度设计。

你会用枪打死一只苍蝇吗?答案是不会。同样的道理也适用于编写一个代码量不超过 1 万行的微服务应用程序。不要过度设计。

好吧,你一直在编写和维护大型代码库。有些代码库可能超过 10 万行,但你需要改变旧习惯,换个思路。这篇文章将帮助你揭开编写小型且易于维护的微服务的奥秘。文中提出的建议带有个人观点,但这些建议在价值百万美元的企业中都得到了验证。

不要像编写单体应用那样编写微服务,保持其可维护性,避免过度设计。

TLDR;

微服务是小型软件系统。你可以放心地放弃 MVC 架构。拒绝 ORM,也不要把设计模式的包袱带到微服务中。专注于代码性能、可读性和可维护性,而不是那些陈旧的规则和模式。那些模式是在人们还没有开始使用微服务的时候制定的。

为什么要编写微服务?

在我看来,微服务架构是将一个或多个单体应用拆分成多个更小的系统。这些系统更易于维护,可以基于业务功能独立开发和部署。这些更小的(或许应该称之为“微”)系统应该专注于一个业务功能并将其做到极致。关键在于“微”这个概念,理想情况下,这些系统的代码量应该控制在 1 万行以内。

由于它们是独立的,这有助于企业更快地发布功能。

发货团队并不依赖于结账团队。部署在发货应用程序中的任何内容都不会影响结账功能。

它变得高度解耦。每次变更的影响范围都可控。这就是微服务快速普及的原因。

现在让我们来看看你过去习惯的做事方式,以及为什么这些方式在微服务时代不太适用。

你需要MVC架构吗?

我大概在2007年或者更早的时候接触到了模型-视图-控制器(MVC)架构。当时我认为它是解决所有软件架构问题的灵丹妙药。现在我不再这么认为了。

是的,你以前用Java或PHP,而其他框架都是基于MVC的。现在,你不需要再那么严格地遵循MVC模式了。

专注于明确目标并把事情做好。

如果愿意并且仍然合理,可以使用控制器。想象一下,我的应用程序接收到一个 HTTP 请求,并且需要返回一个 HTTP 响应。要考虑后端 API 和前端对它的调用。看看下面的代码,它肯定不是 MVC 架构:

async function get(params) {
  const today = new Date().toISOString().split('T')[0];
  const {fromCurrency='AUD', toCurrency='USD', onDate=today} = params;

  let exchangeRates = await db.query(
    `SELECT rate, created_at FROM exchange_rates WHERE from_currency = ? AND to_currency = ? AND on_date = ?`, 
    [fromCurrency, toCurrency, onDate]
  );

  if (exchangeRates.length) {
    const rate = Number(exchangeRates[0].rate);
    console.log(`Found exchange rate of ${rate} for ${fromCurrency} to ${toCurrency} of ${onDate} in the db`);
    return {fromCurrency, toCurrency, onDate, rate};
  }

  return getExternal(fromCurrency, toCurrency, onDate);
}

module.exports = {
  get
}
Enter fullscreen mode Exit fullscreen mode

您可以在这里查看完整的应用程序。请确认其结构,它不是 MVC 架构 :)

所以,与其费尽心思去编写精确的 MVC 代码、测试、实现持续集成,不如给应用添加一些日志和监控功能。让代码易于维护,尽可能保持简洁高效。

不要承担 ORM 的额外开销。

对象关系映射(ORM)——当我第一次看到ORM的实际应用时,我心想这简直是程序员们用过的最棒的东西之一。然而,十多年过去了,我现在会非常谨慎地向任何软件工程师推荐ORM。

去年我将一个完整的 ORM 实现重构为原始 SQL 查询方式,这使得应用程序的这部分性能提高了 20%。

此外,数据库事务清晰可见,代码更易读,因此也更易于维护。

数据映射器和Active Record都有各自的实现方式和逻辑,而且它们还会增加额外的复杂性。这不仅会导致性能问题,还会降低代码的可读性。想想Doctrine的pre-post钩子和事件监听器,它们就像魔法一样运作,而魔法总是难以理解的。

不要像编写单体应用那样编写微服务,保持其可维护性,避免过度设计。

不妨试试,向一个初级软件工程师解释一下 ORM 相关的插入代码是如何工作的,以及一个简单直接的 SQL 插入查询是如何工作的。你很快就会后悔使用 ORM 了。尤其是在微服务架构中,ORM 明显会增加系统开销。微服务的代码量预计最多只有 1 万行,影响的表也不超过 10 个,所以干脆别用 ORM,就这么简单。

设计模式可能是一种包袱

我并不是说你不需要学习软件设计模式。你应该了解SOLID原则、迪米特法则、工厂模式、策略模式、单例模式、适配器模式等等。

如果你进行面向对象编程,那么这些大部分都很有道理,对吧?但如果你用Node.js编写一个微服务,它有1000行代码,分布在大约7个文件中呢?

它只负责业务功能的一小部分。到了那个阶段,所有这些模式都只是锦上添花而已。重新思考一下,所有这些模式和规则都是在微服务广泛应用之前,针对大型代码库设计的。

设计模式适用于已经庞大且在未来 6-12 个月内还会继续增长的代码库,也就是我们通常所说的单体架构。但对于目前只有几百行代码,未来 6-12 个月内会增长到几千行的服务来说,设计模式反而会成为“额外的负担”。我们通常不会预期它会进一步增长,因为要实现更大的规模,我们会使用另一个微服务。所以,请保持微服务代码简洁高效,并进行充分的测试。

不要像编写单体应用那样编写微服务,保持其可维护性,避免过度设计。

结论

如果你仍然想用之前开发单体应用的方式来编写微服务,那可能就真的有问题了。想想看,如果只是短途一日游,你不会像计划两周假期那样打包行李。要考虑代码的性能和可维护性,让数据说话,打破常规。祝你软件工程愉快!


原文发表于geshan.com.np

文章来源:https://dev.to/geshan/dont-code-your-microservice-like-a-monolith-keep-it-maintainable-not-over-engineered-12pc