ThoughtWorks刘尚奇:架构耦合是毒性,不谈计量是耍流氓

一君_ 发布于 06/01 16:26
阅读 5K+
收藏 20

开源软件供应链点亮计划,等你来!>>>

软件耦合一定是件糟糕的事吗?

数人对这个问题的回答都是“是”。任何一个软件中都会涉及不同程度的耦合,混乱或是错误的耦合会给软件的理解、维护、修改带来许多麻烦,低耦合常常能降低一些错误对软件架构的伤害。因此“高内聚低耦合”是软件开发领域为数不多的“银弹”之一。

不过,全球软件及咨询公司 ThoughtWorks 区块链业务负责人刘尚奇近日提出新的看法:在合适的上下文里,软件耦合是可以存在的。5 月 15 日,ThoughtWorks 举办“2021年技术雷达峰会”上,刘尚奇围绕耦合设计发表演讲。在不久前 ThoughtWorks 发布的第24期技术雷达报告中,“识别架构耦合上下文”也是主题之一。

那么,究竟什么是耦合上下文?我们该如何理解耦合在架构设计中的作用?本次峰会结束之后,我们采访了刘尚奇,聊了聊耦合,以及 ThoughtWorks 在提供技术决策咨询时的一些理念。

受访人物简介:
刘尚奇是活跃在技术前线的咨询师,ThouhgtWorks 区块链业务负责⼈,主要关注在区块链、分布式计算、微服务架构、领域建模、遗留系统重构等技术⽅向,致⼒于去中⼼化⼀切。刘尚奇曾先后为国内外医疗、⾦融、通信、汽⻋等⾏业的客户提供软件咨询和交付服务,主导和参与了多个系统架构设计、技术评估、⼤型遗留系统重构规划和实施、微服务架构转型。并作为技术负责⼈带领团队交付软件,技术攻关和构建⼯程能⼒。刘尚奇还是ThoughtWorks全球技术顾问委员会成员,帮助制定技术雷达。

理解耦合、耦合上下文

Q:首先可以用最通俗的话解释一下耦合、耦合上下文这两个概念吗?

刘尚奇:

可以用中国传统建筑工艺榫卯解释耦合。

耦合就是两个组件如何连接在一起。中国古代传统建筑用的最原始的技艺是把两个木头用非常精巧的结构镶嵌到一起,它其实可以形象反映耦合的本质。

很多时候我们用现代建筑做隐喻,形容软件开发,但其实并不是那么精准,因为现代建筑用了大量混凝土、其他材料,从结构和构造的角度跟软件开发并不相似。我觉得中国古代劳动人民通过一些构的镶嵌,更加反映软件模块跟软件模块间是怎样紧密连接到一起的,这是关于耦合的概念。

关于耦合上下文,通俗讲就是“不谈计量谈毒性,就是耍流氓”。因为在软件开发领域,高内聚、低耦合是一个绝对的立场正确。所有的软件开发人员、架构师为自己的架构决策做辩护,去挑战别人的架构决策的时候,其实都会说“你做的这个耦合太高,我做的这个设计其实可以降低耦合”。

但是降低耦合不是没有成本的,有可能会带来一些额外的调用开销、开发工作的不便利性,以及可能带来数据一致性的降低。

在这个基础上,如何在成本和灵活度之间取得平衡?我们认为应该为耦合去找到一个合适的边界跟上下文。在边界以内的,我们认为耦合的毒性没有那么大,可以接受;超出这个边界,我们认为应该尽可能清晰地定义耦合边界,去将软件的不同部分隔离开来。

Q:所以“高内聚低耦合”不是银弹?

刘尚奇:

是的,我觉得没有最佳实践。

很多我们行业同仁们爱去讲最佳实践,但是他们往往忽略了最佳实践一定是在特定的上下文中才工作的,这个上下文是他所在的业务、所在的团队结构、所具备的技术能力,以及他所在团队对这个事情的共识,脱开这个去谈最佳实践,其实没有任何意义。

Q:有种观点认为,耦合是衡量软件架构好坏最重要的标准之一,您认可这种观点吗?

刘尚奇:

我觉得不是,耦合肯定是一个立场正确的选项。衡量软件架构有很多因素,最基础的是一个可以运行的、可以产生业务和用户价值的系统,这是最重要的。

当然耦合方面,是否需要做一个高内聚、低耦合的应用也很重要。我们看到在不同场景下,比如服务于某次营销活动的一个小程序,这种日抛型的应用,没必要做充分解耦的设计,可能把代码堆到一起也可以工作。

如果我想做一个维护周期比较长的系统,希望这个系统可以持续演进,灵活应对变化。这时我们还是鼓励用这种软件工程的角度去看,希望设计一个高内聚低耦合的系统。

Q:可以举个例子说明耦合设计对软件架构的影响有多大吗?

刘尚奇:

有很多,比如为什么我们现在去 IOE 这么困难因为美国进出口管制,很多美国技术服务提供商和软件提供商,没有办法继续对我们中国的企业提供服务。按理说他们提供的数据库服务,我们只是在上层做商业应用开发,如果架构耦合不严重,我们本应该很容易地把这些数据库替换掉。

但因为绝大多数企业系统其实并没有做到应用层和数据层的解耦,整个软件高度依赖数据库实现,持久化存储没有做抽象直接依赖专有API,甚至很多业务逻辑以存储过程的方式直接写在数据库里面。这样就很难替换底层的数据库存储。

当有一天发现必须要做出替换数据库的决策时,必须要把 oracle、IBM 提供专有数据存储换掉,你就会发现你做不了,业务没办法继续开展。

所以我觉得现在贸易战、科技战的背景其实更加提醒我们去做软件设计的时候,应该尽可能识别依赖选项,降低耦合风

Q:这相当于高耦合的风险,低耦合的风险呢?

刘尚奇:低耦合没有什么风险,毕竟你在前期设计和后期实施投入了更多成本。

Q:微服务、API 网关、集中中心,这些都会遇到耦合的设计,在不同场景下,耦合级别会有什么样的差别?

刘尚奇:

可以举两个例子,一个是服务注册发现,一个是 API 网关。

服务注册发现只是将服务名称和物理IP地址强绑定通过建立一层抽象映射解耦开来。这是我们认为比较合理的方式。

而 API 网关,理想的情况下,我们应该只是做一些横切层的处理,比如说是做一些 API 认证、授权、限流这样的功能

但是在现实生活中,人们往往会往 API 网关中添加太多职责其中的动往往是一些厂商为了去卖自己的 API 网关产品,往往把 API 网关的功能做的很强大,甚至包含了智能路由业务逻辑编排等。这可能会引诱开发团队,把更多的业务逻辑代码放到 API 网关里实现形成对API网关产品的锁定。

这个时候就形成了我们说的一个反模式,叫做 Over ambitious API Gateway,它其实反而会增加复杂度带来不必要的耦合。

Q:那在微服务中呢?另外微服务概念现在很,这种声音有没有虚高?

刘尚奇:

还好,我的观点是每个时代都有每个时代默认的架构风格,而微服务是我们这个云原生时代的默认架构风格

ThoughtWorks 虽然是最早提出微服务概念的公司之一,我们的很多项目也在非常早期就采用了微服务架构和 Netflix 技术栈。但是直到今天,我们仍然认为,一些企业的成熟度不太适合用微服务,可能用模块化单体的架构就足以应对业务需求。

但是我们也看到在云时代新成长起来的一批开发者和社区,这对他们来说是默认架构方式,一开始就用 SpringBoot 去写服务。对他们来说,反而是把所有系统放到一个代码库一个进程里是一件很别扭的事情。

上世纪90年代这个世纪初,当我们谈论企业软件开发,我们谈论的是面向对象设计,设计模式和类结构之间的继承组合多态……今天我们去谈软件开发,我们在谈论是服务跟服务之间怎么做拆分和解耦,跨进程调用和高可用设计。

也许在每一个时代会有每一个时代的默认架构风格,而微服务是顺应了云计算的趋势,顺应了数字化业务需要快速迭代的需求,它成为了现在我们做企业开发的时候一个默认的架构风格。

Q:这一期的技术雷达中提到一句“通过耦合设计为客户端生成代码是不好的事情”,为什么这么说?

刘尚奇:

在分布式领域,我们曾经试图用 RMI, rpc 模型简化跨系统调用表面上使用起来像本地的方法调用一样,背后发生在网络两端两个不同的进程之间。但事实并不是这样的,本地的调用是非常快速,而且进程内调用不太可能出错,但是跨网络调用有很多网络开销,包括时延、乱序、丢包,所以是不稳定的。

使用客户端生成代码的实践,是试图把分布式调用去伪装成一个本地的调用,从客户端角度来说,去远程调用和本地调用,好像没有任何区别,都是做一些方法调用,但其实屏蔽和忽略了很多网络调用中的复杂度和错误处理。

另外这种实践也会在 API 发布者和消费者之间的系统引入静态耦合如果 API 发布方接口发生了变化,往往需要重新发布客户端 SDK而消费方不得不重新编译、部署和升级。因为这是一个非常强的程序静态编译层面的耦合

我们完全可以采取更加动态松耦合的集成方式,不要过于依赖 IDL 提供的虚幻的类型安全。如果发布者 API 发生了变化,只要消费端宽容读者的模式(tolerant reader pattern)可以对 API schema 变化有比较高的适配,不需要重新做部署升级。我们仍然可以使用消费者驱动契约测试(Consumer Driven Contract Test)等方式保证 API 的变化是安全的。

从使用技术到判断技术

Q:到具体制定某个技术解决方案时,你们怎么做到比这个开源软件的开发者,或者是技术产品公司的工程师们更了解他们的产品,然后再去提供技术发展的决策建议?

刘尚奇:这是一个很好的点,我们实际上是产品的用户。

Q:用户,怎么理解?

刘尚奇:因为当我们在做一个技术产品的时候,我们处其中,是没有办法很好地评判的自己的产品的。

首先我们并不客观。其次,在不挑战客观性的前提下,我们陷入了知识的诅咒,一旦知道了解了这个产品,就不了解这个产品还可以怎样去设计、为什么不好用

ThoughtWorks 作为一个全球软件咨询公司,我们在很多工具框架和平台的使用上,扮演了解技术 Know how 的用户角色

我们会使用很多工具和框架而且这种使用并不是停留在 IT 采购的层面,而是真正要用它的 API 写代码做集成上生产。这其实给了我们最直接的反馈——这技术在我的项目里是不是工作的,它给我带来的开发体验是什么样的这是我们跟其他的分析公司最大的区别。

其他的咨询分析公司,往往是基于市场宣传、产品特性列表,性能压测基线来去对技术做评估判断。他们并不是这些技术真正的使用者。而 ThoughtWorks 做技术雷达,我们所有评估一定基于我们一线项目开发者最直接的体验和反馈

Q:平时评估的一些技术或产品中,会涉及开源软件吗?

刘尚奇:

以开源软件为主。

因为在 IT 市场,很多企业做产品解决方案要有很多的市场卖点。我觉得技术雷达最大的意义之一在于客观的评估技术产品质量是否符合开发者体验。比如两款产品,一款产品是商业支持的,获得了非常多的市场宣传经费的支持;另一款是从社区诞生的开源软件,可能产品质量做得非常棒,但是没有预算做宣传推广。而技术雷达会比较客观地做评估,我们并不是凭借市场宣传、市场占有率和普及度来评估技术。

结果往往有很多开源软件胜出

Q:您最近在关注什么软件?

刘尚奇:我个人主要关注在区块链领域,因为区块链领域大部分是以开源软件形式存在的,比如一些公有链、Defi 项目,都是以开源的形式存在的。

企业级的软件,过去我关注比较大的趋势是容器化。前段时间Kubernetes 放弃支持Docker也成为了行业里的一个大新闻。

至于容器和编排领域会往什么样的方向发展,我们看到 Kubernetes 已经成为明显的行业事实标准,它和 CNCF基金会孵化出非常多成功的项目。

Q:对 Docker 未来的发展有预测吗?

刘尚奇:

没有预测。但我觉得 Docker 可以当做开源软件生态发展历程的一个很好的注脚。

Docker 是这一波容器浪潮的掀起者,带领整个行业向容器化前进。但是它在商业策略上的失误,与社区方向渐行渐远,最终失去了市场份额。

我们不否认 Docker 在容器化开源运动的贡献,但 Docker 的商业策略并不算很成功也为其他想要参与到开源生态中的的商业组织提供了一个参考

加载中
4
d
dwcz

人们要的不是耦不耦合,要的是快速代码合成。如果,能快速形成有用代码。谁会关心是否耦合。谈耦合,说白了,就是不能快速形成有用代码时,扯扯哲学。

1
今天的吉祥
今天的吉祥
这我不太赞同,耦合在软件架构方面从来都是贬义词,木匠那个例子不加耦合,或者说那个耦合和软件架构中的讴歌,代表完全不同的意义,耦合的软件它就是不行的。
xiaokek
xiaokek
你是不是疯了,0耦合的系统是不存在的。 耦合也可分为七级,从低至高为:非直接耦合(Nondirect coupling)、数据耦合(Data coupling)、标记耦合(Stamp coupling)、控制耦合(Control coupling)、外部耦合(External coupling)、公共耦合(Common coupling)、内容耦合(Content coupling)。
1
昨夜忆星辰
昨夜忆星辰

文章里两个观点挺认同的:1、低耦合架构是有代价和成本的。2、如果长期维护一个系统,并且想要不断演进、灵活应对变化,还是要低耦合高内聚

0
狂野利爪
狂野利爪

大量快节奏小项目,谁关心是否耦合?一周内弄出来上线交付就完了

0
5
594zzb

我能评论了?

0
10进制宇宙
10进制宇宙

所有的在查数据库的时候用到 left join 的代码, 都是高耦合的, 因为第一,数据库一旦拆分了,left join的左右表如果位于不同的数据库,那就执行不了了,第二,某一天如果换成No SQL方案了,所有的left join都用不了了。

 

如果不能耦合,那大多数的代码都不能写,包括left join也不能写。

_snake_
_snake_
该评论暂时无法显示,详情咨询 QQ 群:912889742
-1
z
z13515

请问各位大神,内聚与耦合的区别是什么?

xiaokek
xiaokek
内聚和耦合是一个意思, 当你把一件事物当成一个整体,你就可以说,它是高内聚的。 当你不认为一件事物是一个整体,但他强凑到一起的时候,你就可以说,它是高耦合的。
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部