Sam Newman在他的“建立微服务”一书中说
服务之间过多耦合的弊端比代码重复引起的问题要糟糕得多
我只是不明白服务之间的共享代码是如何邪恶的。如果出现对共享库的需求,作者是否意味着服务边界本身的设计很差,或者他是否真的意味着我应该在常见业务逻辑依赖的情况下复制代码?我看不出那解决了什么。
假设我有两个服务共有的实体共享库。两个服务的公共域对象可能有异味,但另一个服务是用于调整这些实体状态的GUI,另一个是用于其他服务的接口,用于为其目的轮询状态。相同的域名,不同的功能。
现在,如果共享知识发生变化,我将不得不重建和部署这两种服务,无论公共代码是外部依赖还是跨服务重复。通常,同样涉及两个服务的所有情况,这取决于业务逻辑的相同文章。在这种情况下,我只看到重复代码的危害,降低了系统的内聚力。
当然,在共享库的情况下偏离共享知识可能会引起头痛,但即使这样也可以通过继承,组合和巧妙地使用抽象来解决。
那么,Sam的意思是说代码重复比通过共享库的过多耦合更好吗?
服务之间过多耦合的弊端比代码重复引起的问题要糟糕得多
当作者使用通用词“coupling”时,作者非常不具体。我同意某些类型的耦合是严格的禁忌(如共享数据库或使用内部接口)。但是,使用公共库不是其中之一。例如,如果您使用golang开发两个微服务,则您已经拥有共享依赖关系(对于golang的基本库)。这同样适用于您自己开发用于共享目的的库。请注意以下几点:
不要忘记 - 微服务架构风格不是关注代码组织或内部设计模式,而是关注更大的组织和流程相关方面,以允许扩展应用程序架构,组织和部署。有关概述,请参阅this answer。
可以接受重复的紧耦合的良好示例可以是定义服务之间的接口/ DTO的共享库。特别是使用相同的类/结构来序列化/反序列化数据。
假设您有两个服务--A和B - 它们可能会接受略有不同但总体看起来几乎相同的JSON输入。
将一个DTO描述为公共密钥是很诱人的,还包括服务A和服务B用作共享库的极少数。
一段时间以来系统工作正常。两种服务都将共享库添加为依赖项,构建并正确运行。
但是,随着时间的推移,服务A需要一些额外的数据来改变JSON的结构。因此,您无法使用相同的类/结构同时反序列化两个服务的JSON - 服务A需要进行更改,但服务B将无法反序列化数据。
您必须更改共享库,向服务A添加新功能并重建它,然后重建服务B以将其调整为新版本的共享库,即使没有更改逻辑。
现在,您是否可以从一开始就在内部为两种服务单独定义DTO,之后,他们的合同可以在您可以想象的任何方向上单独和安全地发展。当然,起初可能看起来很臭,在两种服务中保持几乎相同的DTO,但从长远来看,它给你一个改变的自由。
在一天结束时,(微)服务与巨石的差别不大。关注和隔离的分离至关重要。某些依赖项无法避免(语言,框架等),但在您自己引入任何其他依赖项之前,请先考虑未来的含义。
我宁愿遵循给定的建议 - 复制DTO并避免共享代码,除非你无法避免。它过去一直困扰着我。上面的场景是微不足道的,但它可能会更加微妙,并影响更多的服务。不幸的是,它只会在一段时间后打击你,所以影响可能很大。