Sam Newman在他的书“构建微服务
中说服务之间过多耦合的弊端比代码重复引起的问题要糟糕得多
我只是不明白服务之间的共享代码是如何邪恶的。如果需要共享库,那么作者是否意味着服务边界本身的设计很差,或者他是否真的意味着我应该在常见业务逻辑依赖的情况下复制代码?我看不出那解决了什么。
假设我有两个服务共有的实体共享库。两个服务的公共域对象可能有异味,但另一个服务是用于调整这些实体状态的GUI,另一个是用于其他服务的接口,用于为其目的轮询状态。相同的域名,不同的功能。
现在,如果共享知识发生变化,我将不得不重建和部署这两种服务,无论公共代码是外部依赖还是跨服务重复。通常,同样涉及两个服务的所有情况,这取决于业务逻辑的相同文章。在这种情况下,我只看到重复代码的危害,降低了系统的内聚力。
当然,共享知识中的分歧可能会导致共享库出现问题,但即便如此,也可以通过继承,组合和巧妙使用抽象来解决。
那么,Sam的意思是说代码重复比通过共享库的过多耦合更好吗?
答案 0 :(得分:5)
服务之间过多耦合的弊端比代码重复引起的问题要糟糕得多
当他使用通用词“coupling”时,作者非常不具体。我同意某些类型的耦合是严格的禁忌(如共享数据库或使用内部接口)。但是,使用公共库不是其中之一。例如,如果您使用golang开发两个微服务,则您已经拥有共享依赖关系(对于golang的基本库)。这同样适用于您自己开发用于共享目的的库。请注意以下几点:
不要忘记 - 微服务架构风格不是关注代码组织或内部设计模式,而是关注更大的组织和流程相关方面,以允许扩展应用程序架构,组织和部署。有关概述,请参阅this answer。
答案 1 :(得分:3)
短 微服务体系结构的核心概念是微服务具有独立的开发-发布周期。 “共享库”破坏了这一点。
更长
以我自己的经验,保持微服务尽可能隔离和独立非常重要。 隔离基本上是关于释放和部署而与其余程序无关的。像
“共享库” 是那些阻碍您这样做的库。
处理“共享库”如何毒害您的体系结构是“有趣的”:
哦,我们有一个User对象!让我们到处重复使用它吧!
这会导致整个企业“共享库”,并开始破坏 Bounded Contexts (DDD),迫使您依赖一种技术
我们已经有了您需要的带有TDO的共享库,编写方式为 java ...
重复我的自我。这种共享库的新版本将影响所有服务,并使您的部署复杂到非常脆弱的设置。结果是,在某个时刻,没有人相信自己会开发通用共享库的下一个版本,或者每个人都担心会大爆炸。
所有这些仅仅是为了“不要重复自己”吗? -这是不值得的(我的经验证明了这一点)。 Ť 共享受损的“用户”对象很少好于实践中特定微服务中的几个重点用户对象。
但是永远不会有灵丹妙药,而Sam仅根据他的项目为我们提供指导和建议(如果您愿意,可以采用启发式方法)。 我的印象 我可以给你我的经验。不要以有关共享库的推理来启动微服务项目。只是不要一开始就做它们,而是接受服务之间的一些代码重复。将时间花在DDD上,以及域对象和服务边界的质量。
在项目进行期间,一旦您或您的团队获得了足够的内幕,您就可以将某些零件重构到库中。与反向方法相比,这种重构通常非常便宜。
这些库可能应该涵盖一些样板代码,并专注于一项任务-其中有多个,而不是一个{em> common-lib-foreverything 中的一个。在comment above Oswin Noetzelmann中给出了一些如何进行的建议。最大限度地利用他的方法将产生良好且集中的库,而不是有毒的“共享库”
答案 2 :(得分:0)
可以使用共享库定义服务之间的接口/ DTO,这是可以接受复制的紧密耦合的一个很好的例子。特别是使用相同的类/结构对数据进行序列化/反序列化。
假设您有两个服务-A和B-它们都可以接受略有不同但总体上几乎相同的JSON输入。
创建一个描述通用密钥的DTO也是很诱人的,其中还包括服务A和服务B用作共享库的极少数密钥。
一段时间后,系统工作正常。两种服务都将共享库添加为依赖项,并正确构建和运行。
尽管如此,随着时间的流逝,服务A需要一些其他数据,这些数据将改变JSON的结构,与以前相同。结果,您不能使用相同的类/结构同时反序列化两个服务的JSON-服务A需要进行更改,但服务B将无法反序列化数据。
您必须更改共享库,向服务A添加新功能并重建它,然后重建服务B以将其调整为新版本的共享库,即使此处未更改任何逻辑。
现在,您是否会从一开始就在内部为这两种服务分别定义DTO,后来,它们的合同就可以在您可以想象的任何方向独立安全地发展。当然,起初看起来在两种服务中都使用几乎相同的DTO似乎很臭,但是从长远来看,它给您带来了改变的自由。
最终,(微)服务与整体服务的差异不大。关注点分离和隔离至关重要。无法避免某些依赖项(语言,框架等),但是在您自己引入任何其他依赖项之前,请三思而后行。
我宁愿遵循给出的建议-复制DTO并避免共享代码,除非您无法避免。过去一直在咬我。上面的情况是微不足道的,但它可能会产生细微差别并影响更多服务。不幸的是,它只会在一段时间后才会打击您,因此影响可能很大。
答案 3 :(得分:-1)
对此没有绝对的答案。你总能找到一个合理的规则例外的例子。我们应该以此为“指导方针”。
话虽如此,服务之间的耦合是应该避免的,共享库是耦合的警告。
正如其他答案所解释的那样,微服务生命周期应该是独立的。 至于你的例子,我认为这在很大程度上取决于图书馆有什么样的逻辑/职责。
如果是业务逻辑,那就有点奇怪了。也许您需要将库拆分到不同职责的不同库中,如果这种职责是唯一的且无法拆分,那么您应该想知道这两个服务是否应该只有一个。如果该库的业务逻辑在这两个服务上感觉很奇怪,那么该库很可能应该是一个独立的服务。
答案 4 :(得分:-2)
每个微服务都是自治的,因此可执行文件将拥有自己的共享库副本,因此与共享库没有耦合?
Spring Boot,封装语言运行时也在微服务的封装中
即使运行时也不共享任何内容,因此我在微服务中使用库或公共包时没有发现问题
如果共享库在微服务中造成耦合,那么在不同的微服务中使用相同的语言也是一个问题?
我在阅读 Sam Newman 的“构建微服务”时也很困惑