How Simpler Architectures Made Me a Better Senior Developer
设计更简单且有效的架构的技巧
我过去认为图中的框框越多,设计就越好。在多年参与大型企业系统开发后,我学到了相反的教训;
大多数系统不是因为工具不足而失败,而是因为它们拥有太多工具而失败

以下是五种重塑了我对系统设计思考方式的架构实践。
仅在必要时拆分系统
我们曾从一开始就使用微服务构建了一个支付系统。想法是构建一个从一开始就具有可扩展性的系统

即使流量较低,每个支付请求也会触发多个网络调用。任何服务的故障都会导致整个支付失败。
除此之外,调试是个头疼的问题。它需要跨日志搜索和团队间协调。
此外,即使是简单的更改也需要在依赖的服务中进行部署。
让我们简化这个架构:

通过去除物理分隔同时保持逻辑边界,我们显著减少了故障模式。部署现在更简单了。调试现在更快了。
当扩展需求出现时,我们可以将使用最频繁的一个服务提取出来,变成它自己的微服务。
避免过度抽象
我们继承了一个难以维护的订单管理系统。我们的第一反应是通过添加抽象层来清理它;引入了通用服务、共享存储库和基类来"标准化"行为。结果比以前更糟了。

理解订单流程需要跨越界面和基类。业务规则分散在各个层级,使得即使是简单的修改也变得昂贵;抽象消除了重复,但也消除了意义。我们改变了方法。

我们不再使用通用层,而是将工作流明确化。订单创建、定价和履行都存在于具体的代码中。仍然存在一些重复,但这是有意为之且显而易见的。改动变得局部化,失败也更容易追踪。
简单的系统会明确地崩溃。复杂的系统会神秘地崩溃。
宁选简单而非花哨的架构
在结账系统中,我们为整个流程采用了事件驱动架构。每一步都发出并消费事件。在白板上看起来很优雅。在生产环境中却痛苦不堪。

稍作停顿。你在这套架构中看到任何明显的问题吗?
大多数讨论都围绕事件排序、重试和消费者延迟展开。没有哪个服务明确拥有订单的最终结果。失败导致订单处于部分状态,需要人工干预。
该架构以牺牲清晰度为代价,优化了灵活性。
我们将完全事件驱动的流程替换为简单、同步的结账服务。

一个服务负责整个结账生命周期。它验证购物车、处理支付,并返回最终的成或败。事件仍然被使用,但仅用于分析、通知等副作用。核心业务流程保持线性且易于理解。
失败现在变得即时且可见。一个订单要么完成,要么明显失败,绝不会处于模糊的状态
你不需要它(YAGNI)
产品范围很窄,用户提交了反馈。管理员审核了它。但架构比这复杂得多。

在纸面上,设计预期能够增长。实际上,它优化了一个从未到来的未来。这也造成了诸多复杂性:
- 一个服务内的多个架构层
- 反馈提交的事件驱动流程
- 反馈、状态和审计日志的分离表
- 保护未完成或未使用功能的特性标志
所有这些复杂性都存在于一个服务中。它并没有解决一个真正的问题。它只是反映了关于未来的假设。
简化的架构看起来大致是这样的:

通过移除未使用的抽象、表格和基础设施,系统变得一目了然。
过多的配置并不总是好的
个内部系统将灵活性推向了极端。几乎每种行为都由配置驱动;
特性标志、环境变量和多个配置文件影响了核心逻辑。大多数生产事故并非由代码缺陷引起,而是由错误的配置导致。

理论上,这看起来很灵活,但它有许多隐藏的复杂性:
- 运行时加载了多个配置源
- 控制关键执行路径的功能标志
- 跨代码库的特定环境行为
要了解系统如何运行,你首先必须了解它是如何部署的。
现在,让我们看看简化的架构:

- 直接在代码中定义清晰的默认值
- 特性标志仅用于临时发布
- 配置仅限于真实环境差异
随着可移动部分的减少,部署变得更安全。系统行为变得可预测。代码解释了自身。
简洁的架构并不意味着设计薄弱。它意味着去除不必要的复杂性,以便系统在发展过程中保持可理解性。
强大的系统始于简单。它们随着时间的推移逐渐获得复杂性。
本文到此结束,感谢阅读。
原文地址:How Simpler Architectures Made Me a Better Senior Developer