您的干净代码可能是别人的技术债务

news/2025/1/31 8:45:01/文章来源:https://www.cnblogs.com/jellyai/p/18695628

您的干净代码可能是别人的技术债务

为什么软件模式必须适应团队规模,以及如何正确操作。

大卫·罗德纳斯 博士

由作者生成

在软件开发中,我们面临着一个奇怪的悖论:对于一个团队来说,使代码更干净、更易维护、更优雅的架构决策,可能会让另一个团队觉得更复杂、更僵化、更麻烦。随着组织的扩展,我们依赖的那些让代码保持干净的原则,可能开始对我们不利。

这不仅仅是关于代码模式或最佳实践,而是关于团队边界如何改变干净代码的本质——以及为什么我们需要重新思考在成长中的组织中如何进行软件设计和架构。

人性化的因素

当我们思考如何组织和设计代码时,通常会从技术的角度入手:有哪些元素,它们如何相互交互,以及哪种模型最能代表功能。所有这些都是从技术完美的角度出发,但技术并不是一切。代码并不存在于真空中;它存在于团队之中,代码不仅需要适应技术需求,还需要适应团队的需求。

这并不是什么新鲜事。整个“干净代码”运动的核心正是如此:代码不仅要服务于技术目的,还必须适应你的团队,以及我们未来如何理解和维护它。

正是在代码的人性维度中,我们也必须考虑团队规模的维度:与代码交互的团队规模不再仅仅是一个团队,而是大型组织和大型项目,多个团队协作完成一个代码库,或者多个代码库协同实现一个目标。

在这一点上,当有不止一个团队在处理同一份代码时,规则改变了,团队的人性化因素对代码的影响也更大了。一些对小团队有效的东西,对大型组织来说可能成为巨大的麻烦。

随着团队的增长,复杂性从代码本身转移到了团队之间的交互上。

一个简单的共享库示例

开发中的一个前提是引入库来帮助解决小问题,并避免花费大量时间编写和维护代码。这些库可能是提高生产力的救星。

对于一个小团队来说,如果需要使用一个新库,没问题——你看看有哪些可用的选项,然后选择一个最适合的。简单直接。比如你需要进行日期计算,查看三四个选项,选择一个合适的就行了。

但当涉及到组织时情况就变了,而这样的决定会影响多个团队。如果我们沿用小团队的做法,首先我们需要选择一个解决问题的库。你需要选择一个库,这意味着需要评估每个团队的需求,并选择一个最能满足所有需求的库。但这永远不可能完美,每个团队都必须以某种方式进行适应。

而这仅仅是第一步。相较于小团队,这一步可能已经需要十几次会议,并且影响多个团队,带来变更和额外成本。

接下来要决定谁来负责管理这个库。因为库是会演化的:它会添加新功能、修复漏洞、解决bug,甚至可能被弃用,需要用另一个库来替代。而所有这些都可能变成持续的额外成本、延迟和麻烦。

即使是一个团队需要升级版本,因为一个对他们来说至关重要的新功能刚刚发布,这也会触发一连串的变更,从而导致其他团队需要进行更新以保持一致性,带来延迟和额外成本。

于是,我们把一个技术决策变成了一个政治问题。

不仅仅是第三方库,也包括我们自己的代码

单个库会遇到的问题,也会发生在项目本身写的代码中。

那些让干净代码在小型代码库中有效的方法,在大型组织中可能变成了弱点。

这就是问题所在。大多数开发人员都学会了如何为小规模编写干净代码,而不是为大规模编写。适应小团队,适应小范围的工作。

架构师、代码设计者以及高级开发人员也一样。他们提出的解决方案在小团队中非常有效。但当团队规模扩大时,游戏规则改变了,他们的知识和经验必须适应新的情况。然而,他们的每一次经验和直觉都引导他们走向已经知道并曾经奏效的解决方案。

最大的麻烦在于,我们经常接受这些低效的、不适合大规模的工作方式带来的额外成本。我们接受它们是开发的一部分。我们接受它们是大团队的代价。我们接受它们是大型代码库的开销。

而这些东西被接受之后,就不会被纠正。从中也学不到任何东西。

甚至SOLID原则也会崩塌

SOLID是一组由罗伯特·C·马丁(“干净代码”一书的作者)提出的原则,用于提升代码质量。SOLID本身是五项原则的首字母缩写:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则旨在帮助编写更好、更易维护的软件。

然而,当在同一组织中有多个团队协作时,即使是这些SOLID原则本身也会被破坏。

例如,在单一职责原则的案例中,在一个小团队中,这很简单。很容易知道我们想为代码分配的单一职责是什么。但当涉及多个团队一起协作时,这些界限就会模糊。例如,有五个团队需要五个看似相同但略有不同的功能。这时,各团队即使没有意识到,也必须开始做出妥协,为了统一目标而放弃各自的偏好。现在你会看到,团队之间会争论谁拥有代码的所有权以及实现的最佳方式,或者干脆盲目服从被强加的规则。

我们可以继续谈下去。比如在开闭原则的情况下,我们会看到每个团队对如何扩展组件有不同的理解,导致微妙的断裂点和维护难题。对于里氏替换原则,每个团队都会以自己的方式使用这些构件,使得它们无法扩展到超出团队需求的范围。接口隔离原则可能会演变成“接口汤”,而依赖倒置原则可能会让任何团队的计划偏离轨道。

一切最初帮助我们产生更好代码的东西,在规模发生变化时,开始失效,甚至会造成额外的开销成本。

在API中的SOLID原则

问题的根源不在于代码本身无法工作,而在于我们强迫团队之间超出必要地协作。

我们需要改变这一点。因为这种强制协作增加了会议、交互、干扰点和依赖关系的数量。这增加了团队协调所需的时间,远远超过了我们能够从中获得的收益。

而在这里,我们需要划定边界。

团队之间需要一个边界,以便他们可以彼此协作。这些边界的切入点和退出点可以是API、REST API、代码API……任何需要的形式。总之,团队之间必须有清晰的合同(contract),允许他们在不泄露实现细节的情况下互动。这种方式可以让每个团队在代码上保持自治,并根据具体情况做出最适合自己的决定,而无需与其他团队协调。

我们可以将这些SOLID原则应用于这些API中。这些原则,正如罗伯特·C·马丁在《Clean Architecture》(《架构整洁之道》)一书中定义的,不仅仅适用于代码,也适用于模块及其交互。

例如,单一职责原则表明,每个模块、每个API的一部分,仅响应一个参与者,仅响应一个操作方式。这样我们不再依赖其他人,除非我们明确定义了这种依赖。开闭原则——“软件构件应该对扩展开放,但对修改关闭”——清楚地表明,我们可以添加新功能而不移除旧功能。里氏替换原则表明,即使我们进行了更改,我们也必须保持兼容性,以免破坏现有代码。接口隔离原则不仅要求我们根据用途隔离接口,还要求我们不强迫使用不必要的内容。这迫使我们创建更简单、更易用的API。

因为良好的设计和良好的架构更多地是考虑其他团队如何与你的API交互,而不是如何解决具体的代码细节。

焦点从代码转向了开发者的体验。

准备好迎接WET吧

关于DRY(Don’t Repeat Yourself,不要重复自己)的一个神话将被打破。

当我们停止在跨团队共享的代码中使用SOLID时,我们将开始看到重复的代码。

这或许听起来很糟糕,甚至我们也会觉得这是反模式。但在每个设计和架构决策中都有利有弊。在这种情况下,如果所有人都必须共享相同的代码,所有人就会依赖相同的代码,而这段代码必须变得复杂以满足所有的小变体。如果代码本身不能做到这一点,那么与之交互的代码就会变得复杂。

但通过放弃这种DRY模式,接受WET(Write Everything Twice,所有内容写两遍),团队将变得独立。每个团队都可以按照自己的节奏前进,每个团队都可以根据自己的需求定制代码,无需妥协。我们甚至会看到,那些起初看似相同的代码,最终会因为满足了不同的需求而分化。

嗯,仔细想想,DRY的意思是不要重复你自己,对吧?如果每个团队是不同的团队,即使我们在同一个项目中复制了代码,它仍然符合DRY的精神,对吧?

挑战规模问题

我们不能接受额外的开销成本是正常的,也不能接受使用无法扩展的解决方案,更不能接受代码变得比我们期望的更复杂。所有这些仅仅因为代码库的规模在增长,团队的数量在增加。

我们需要挑战这些问题,并寻找可以改变和改进的地方。

因为,归根结底,所有这些原则、模式和规则的存在是有原因的。我们必须忘掉那些在特定情况下不起作用的小细节,而追求它们创建的真正原因。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/877233.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读算法简史:从美索不达米亚到人工智能时代02古老的算法

苏美尔文字起源于湿黏土陶筹,楔形文字记录了苏美尔语,促进社会发展。阿卡德、巴比伦帝国相继统治,文字变迁。19世纪欧洲考古学家破译文字。美索不达米亚算法复杂,包括六十进制和毕达哥拉斯定理。埃及数学留存少,欧几里得算法著名。1. 苏美尔 1.1. 位于苏美尔地区的乌鲁克,…

计量经济学——空间计量概述(十八)

img { display: block; margin-left: auto; margin-right: auto } table { margin-left: auto; margin-right: auto } 空间计量经济学(Spatial Econometrics)创新性地解决了经典计量方法在空间数据分析中的局限性,研究地理观测值之间的相互关系。近年来,在人文社会科学的“…

经济经济学——空间计量概述(十八)

img { display: block; margin-left: auto; margin-right: auto } table { margin-left: auto; margin-right: auto } 空间计量经济学(Spatial Econometrics)创新性地解决了经典计量方法在空间数据分析中的局限性,研究地理观测值之间的相互关系。近年来,在人文社会科学的“…

Cisco NX-OS System Software - ACI 16.1(2g)F - 适用于 ACI 模式下的 Nexus 9000 系列交换机系统软件

Cisco NX-OS System Software - ACI 16.1(2g)F - 适用于 ACI 模式下的 Nexus 9000 系列交换机系统软件Cisco NX-OS System Software - ACI 16.1(2g)F 适用于 ACI 模式下的 Cisco Nexus 9000 系列交换机系统软件 请访问原文链接:https://sysin.org/blog/cisco-aci-16/ 查看最新…

Cisco APIC 6.1(2g)F - 应用策略基础设施控制器

Cisco APIC 6.1(2g)F - 应用策略基础设施控制器Cisco APIC 6.1(2g)F - 应用策略基础设施控制器 Application Policy Infrastructure Controller (APIC) 请访问原文链接:https://sysin.org/blog/cisco-apic-6/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org思科…

Python多线程爬取亚马逊商品数据

前言 新年快乐 1.环境准备 使用miniconda为亚马逊创建一个新环境,防止feapder和其他包冲突(比如scrapy)。 # 创建一个新的 Conda 环境: conda create -n python_feapder python=3.12# 查看已创建的环境 conda info --envs# 激活环境 conda activate python_feapder# 安装所…

Debug: debugger失效排查

MarkTime: 2024-11-24 19:25:17 LogTime: 2024-11-24 19:25:17记一次 debugger 断点失效原因的排查版本说明Chrome: 131.0.6778.86 Vue: 3.2.27结论检查 是否启用了 谷歌浏览器 的 自定义排除规则, 并把 node_modules 给排除了 检查 前端项目配置文件eslint 是否有覆盖规则, 使…

Debug: 前端发送请求参数传递null, 后端转换实体类对应变量自动注入默认值

MarkTime: 2024-11-18 16:19:47 LogTime: 2024-11-25 01:26:05实体类属性未正确定义原因导致: ​ 基础数据类型未被初始化, 会对对应变量赋予默认值(int: 0; boolean: false;...) ​ 包装类型允许存储null, 不会进行默认值赋予, 实体类中如果需要设置默认值需要自行指定(privat…

Vue: 项目映射到外网后, 前端打包配置调整

Mark Time: 2024-11-15 15:55:34 Log Time: 2024-11-24 16:00:00小项目, 记录下前端打包的debug过程(配置文件有做部分删减, 看个结构就好)说明 版本说明项目前后端分离axios: 0.24.0node: 14.18.0npm: 6.14.15vue: 3.2.27webpack: 4.46.0webpack-bundle-analyzer: 4.8.0背景说…

Pyton多线程爬取亚马逊商品数据

前言 新年快乐 1.环境准备 使用miniconda为亚马逊创建一个新环境,防止feapder和其他包冲突(比如scrapy)。 # 创建一个新的 Conda 环境: conda create -n python_feapder python=3.12# 查看已创建的环境 conda info --envs# 激活环境 conda activate python_feapder# 安装所…

独立开发经验谈:如何通过 Docker 让潜在客户快速体验你的系统

如果你的产品是和我的在线客服系统一样,100% 允许用户私有化部署的,那你一定要使用 Docker 技术,让用户能够快速体验到你的系统,以及能够在生产环境中非常轻松的把你的产品用起来。我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统。陆陆续续开发了几年,从…

AP Physics C Mechanics Chapter 7 Rotation 1

RTVocabularyRigid body 刚体 Angular displacement 角位移 \(\Delta \theta\) Angular velocity 角速度 \(\omega\) Angular acceleration 角加速度 \(\alpha\) Rotational kinetic energy 旋转动能 \(KE_{\text{rotational}}\) Rotational inertia 转动惯量 \(I\) Torque 扭矩…