知行札记
专题程序与软件系统软件设计与架构

软件设计与架构

围绕职责、状态、接口和变化组织软件,并以可对应的视图保存结构、行为和决策。

设计先回答谁负责什么

假设一个系统接收订单、收款并通知用户。订单规则判断商品、金额和状态;支付接入与外部机构交换请求;通知过程把已确认结果交给用户。职责分开后,仍需明确它们怎样联系,以及谁保存各项事实。

模块是承载一组职责并提供接口的组织单元。接口向使用方暴露可依赖的操作、输入、结果和失败条件;实现保存达到结果所需的细节。源码文件、包、进程和服务都能成为组织边界,但它们的运行、部署和失败性质各不相同。

沿变化决定边界

一种分解按执行步骤切开:读输入、计算、写结果。另一种分解按需要隐藏的设计决策切开:输入格式、定价规则、保存方式。第二种分解使一种决策变化时,使用方可以继续依赖稳定接口。Parnas 的经典研究用两种 KWIC 分解讨论这一判据;“信息隐藏”同时涉及预计会变的决策和对外规格。Parnas,On the Criteria To Be Used in Decomposing Systems into Modules

变化预测需要具体依据。支付机构更换影响接入实现,金额规则变化影响领域逻辑,两者是否需要同步演进取决于实际契约。过早把偶然相同的代码合成一个抽象,可能使后来不同的需求共享一堆条件分支。保留短期重复、明确各自责任,再根据真实共同规则提炼,是一种可解释的选择。

判断模块是否合适,要看完成一次变化需要理解和修改哪些地方,接口是否泄露实现假设,错误和状态是否有稳定意义。函数行数、文件数量或某个架构名称可以提供线索,单独不能给出结论。

状态和错误也是架构对象

订单的事实需要有主要所有者。多个模块各存一份付款状态,会引出同步和冲突;只存主要事实、派生显示信息,可以减少维护位置。跨边界复制时,说明它是权威事实、缓存、快照还是事件记录,以及何时允许暂时不同。

错误表明某项职责的保证未能成立。业务拒绝、外部暂时不可用、调用方输入错误和内部不变量破坏,应有调用者可以使用的不同含义。模块对外返回稳定错误类别,对内保留诊断;外部依赖的原始报错不宜直接成为长期业务契约。

选择组织方式时说明代价

分层组织把交互、业务和基础设施分开;垂直切片把完成一个业务能力需要的代码集中;端口与适配器将领域角色和外部实现分开。它们可以组合,选择要依据变化方式、共享规则、团队边界和测试需要。

独立服务增加独立部署和故障隔离的可能,也增加网络失败、契约、观测和数据一致性的工作。单进程减少这些运行边界,内部职责仍需要设计。仓库数量也不能直接决定耦合:依赖图、公开接口、所有权和构建约束才说明哪些变化会一起发生。

归档代码组织研究中的架构偏好、团队相关性、微基准和机构案例,具有不同证据性质。本专题保留其问题和条件,不把风格分布当成可维护性效果,不从一个迁移案例推导所有系统的方案。

让结构、运行和实现对应

架构说明需要辨认软件职责、源码位置、运行实例和工作阶段。订单服务是一种软件对象,生产实例是它在环境中的运行对象,orders/ 是源码位置,构建是工作动作。同名或相近名称要能跨视图追踪。

结构视图说明组成与关系,运行视图解释一次具体操作,部署视图说明实例、节点和网络条件,源码定位说明职责怎样进入实现。关系也需分别命名:包含、调用、依赖、生成和部署提供不同信息。

架构视图与跨视图对应完整展开 C4、arc42、ADR、多视图方法和本站历史案例;代码组织与长期演进讨论抽象、范式、仓库边界和迁移;设计判断与证据边界保留经典论点、研究分歧及十一类设计问题的依据。必要背景在各页就地说明,来源负责追溯。

演进保留行为和理由

重构调整内部结构,同时保持声明范围内可观察的行为;业务变更则有意改变行为。两者混在同一大改中,会增加判断失败来源的负担。渐进替换可以先增加新接口,让消费者迁移,再删除旧入口;整个过渡需要兼容契约、观察和退出条件。

当前架构说明保存这个版本怎样工作;决策记录保存当时的约束、替代、选择和后果。选择获接受、实现完成和效果达到,分别需要依据。维护沿对象、关系、条件和结果的变化检查受影响视图,避免只因为文件移动就重画全部架构。

最后更新于

本页目录