适应性胜过聪明:代码真正优秀的因素
Source: Dev.to
系统之所以能够存活,并不是因为它们从一开始就完美无缺,而是因为它们在需求变化、技术演进、团队发现之前未曾预料到的问题时,能够弯而不折。为变化而构建要比一次又一次追求过早的完美更有效。
你永远不可能第一次就做对。这并不是失败,而是软件开发的常态。需求会在构建过程中逐渐清晰,边缘情况会在使用中显现,性能问题会在真实负载下暴露。把第一次尝试当作圣经的团队会花数月时间去打磨错误的问题的解决方案。
相反,要构建能够演进的系统。给自己留出交付、学习和适应的空间,让现实来决定哪些是重要的,哪些不是。
可适应代码的原则
单一职责原则
让每个组件专注于一件事,无论是拥有有界上下文的微服务,还是处理单一关注点的类。当需求变化时,只需修改负责该关注点的那一块,而不必在整个系统中进行连锁编辑。
清晰的接口与关注点分离
服务通过契约而不是实现细节进行通信。业务逻辑不需要了解 HTTP;数据库层也不做授权决策。恰当粒度的抽象让你在理解演进时能够切换实现,而无需重写上游的所有代码。
将变化外部化
让可变行为可配置。环境特定的设置使相同代码能够部署到开发、预发布和生产环境。可调的超时、批量大小和重试策略让运维在不参与工程的情况下调整系统行为。
快速且明确地失败
立即暴露问题。沉默的失败会在远离根源的地方演变成难以追踪的 bug。系统边界的显式校验、关键路径的防御性断言以及结构化日志能够在出错时提供清晰信号。
完备的测试
能够让你放心重构的测试。
- 单元测试 验证组件行为。
- 集成测试 捕捉接口不匹配。
- 端到端测试 确认关键工作流仍然可用。
一致的命名与结构
降低认知负荷。当模式重复时,开发者能够更快理解代码库。服务遵循相同的生命周期。仓库提供相同的 CRUD 操作。一致性让陌生感变得熟悉。
适度的灵活性
目标不是最大化灵活性,而是恰当的灵活性。基于领域知识和过去经验,对你能够合理预见的变化进行优化。支付系统需要支持新的支付提供商,而内部管理工具大概率不需要插件化架构。
结论
为昨日需求编写的完美代码在现实转变时会失效。过度设计的代码会在自身重量下崩溃。可适应的代码找到了平衡点:在可能变化的地方保持灵活,在不太可能变化的地方保持简洁。