{"name":"软件设计","id":"软件工程-软件设计-软件设计","content":"# 软件设计：从复杂性到稳定性\n\n> 软件设计的本质，是在变化的世界中建立可理解、可演化的秩序。\n> 它连接需求与解决方案，用模型对抗混乱，用结构控制复杂性。\n\n## 设计的本质与目标\n\n软件设计的核心工作，就是**构建模型**，用模型连接\"问题空间（需求）\"与\"解空间（实现）\"，\n并通过**规范**去约束实现，以在变化中保持系统的可控与稳定。\n\n* **战术编程**：赶紧实现功能，能跑就行。\n* **战略编程**：预先构建结构，控制复杂性。\n\n**软件设计就是战略编程的体现**——它不只是写代码，而是构建\"可长期生存的系统\"。\n\n设计原则是指导设计的经验总结，设计模式是问题导向的一系列方案或者设计思路，编码规范是实现可读性的约束手段。通过设计原则的指导，使用设计模式，经过编码规范约束并配合重构，保证代码的可读性、扩展性、可复用性，最终实现高内聚、低耦合的模块或系统\n\n## 复杂性：设计要对抗的敌人\n\n> 复杂性不是敌人本身，而是失控的结构。\n> 设计的意义，在于让复杂性有序地分布。\n\n### 复杂性的表现\n\n复杂性的表现可以从四个维度感知：\n\n**结构维度**——系统内部耦合的外显\n\n* **变更放大**：看似简单的修改，却需要动很多地方。\n* **脆弱性**：修改 A，意外破坏 B。与变更放大不同——放大是范围问题，脆弱是意外性问题。\n* **不可测试性**：代码无法被独立验证，必须依赖复杂环境才能运行，是耦合过深的直接暴露。\n\n**认知维度**——理解成本的外显\n\n* **认知负荷**：开发者要理解多少知识才能改动一行代码。\n* **未知的未知**：不知道改哪里能实现目标。\n* **调试困难**：无法追踪因果链，难以复现问题——是认知负荷在运行时的体现。\n\n**时间维度**——系统随时间退化的外显\n\n* **腐化加速**：越改越乱，每次修改都让下一次更难，技术债产生利息效应。\n* **行为难以预测**：相同输入在不同时序或状态下产生不同结果，无法建立稳定心智模型。\n* **文档与代码背离**：注释描述的是曾经的行为，已无法信任任何说明。\n\n**协作维度**——团队效能的外显\n\n* **并行开发冲突**：多人无法独立工作，频繁相互阻塞，合并冲突频发。\n* **知识孤岛**：只有少数人真正理解某个模块，形成\"巴士因子\"风险。\n\n### 复杂性的根源\n\n理解复杂性的来源，首先需要区分两类性质不同的复杂性：\n\n* **本质复杂性**：问题域本身固有的复杂，无法消除。业务规则的内在复杂、分布式系统的物理约束，都属于此类。\n* **偶然复杂性**：由工具选择、实现方式、设计决策引入的复杂，可通过良好的设计减少但难以完全消除。\n\n设计的核心目标，是消除偶然复杂性，接受本质复杂性。偶然复杂性的主要来源：\n\n* **依赖过多**：难以管理的依赖关系，牵一发动全身。\n* **语义模糊**：实体意义不明，职责混乱，读者无法建立准确心智模型。\n* **关注点交织**：将不同性质的逻辑缠绕在一起，如状态与业务逻辑混合、时序与功能耦合。\n* **可变状态扩散**：共享的可变状态在系统各处隐式流动，行为随时间变得难以推理。\n* **组织结构映射**：团队的沟通边界会直接映射为系统的架构耦合（Conway 定律），人的协作方式本身制造了技术复杂性。\n\n### 降低复杂性的思路\n\n复杂性无法被彻底消除，它只能被**转移**——从调用方转移到模块内部，从接口转移到实现，从不可控的位置转移到可控的位置。设计的本质，是让复杂性在最合适的地方被承担。\n\n**深模块原则**：最理想的模块，是接口简单、实现丰富的\"深模块\"——对外暴露简单的契约，对内隐藏大量复杂决策。浅模块则相反，接口与实现一样复杂，调用方获得的抽象收益极低。\n\n```\n深模块：简单接口 ＋ 复杂实现  →  复杂性被封装在内部\n浅模块：复杂接口 ＋ 简单实现  →  复杂性泄露给调用方\n```\n\n不同粒度下，降低复杂性的思路各有侧重：\n\n* **函数/类层面**：单一职责、命名清晰、减少参数、缩短函数体\n* **模块层面**：信息隐藏、接口抽象、深模块设计\n* **系统层面**：分层架构、组件化、显式依赖图\n\n这些思路并非独立策略，而是同一个核心原则在不同粒度上的体现：**让边界内的决策对边界外不可见**。\n\n## 对抗复杂性的核心手段\n\n> 一切优秀的软件设计，都是在不断回答两个问题：\n> \"这部分应该知道什么？\"、\"这部分不该知道什么？\"\n\n不同的复杂性来源，需要不同的手段来对抗。没有万能的单一策略，而是一套相互配合的工具集。\n\n### 关注点分离\n\n通过分解问题，让每个模块只关心自己的责任。这是一切结构性设计的起点，直接对抗**依赖过多**与**关注点交织**。\n\n实现方式：模块化与封装、单一职责、分层架构、清晰边界定义。\n\n### 信息隐藏\n\n每个模块应封装部分知识与决策，让这些细节只存在于内部实现中，而不出现在外部接口。模块间依赖的是**抽象**，而非**细节**，从而减少耦合、增强稳定性。\n\n信息隐藏是关注点分离的实施机制——分离回答\"边界在哪里\"，隐藏回答\"边界内藏什么\"。\n\n### 抽象\n\n抽象是信息隐藏的表达形式，是一种隔离机制。越抽象的接口代表模块越\"深\"，能隐藏更多复杂性，让模块变得\"可替换、可演化、可理解\"。\n\n三者的层次关系：\n\n```\n关注点分离  →  确定边界（分什么）\n信息隐藏    →  封装决策（藏什么）\n抽象        →  暴露接口（露什么）\n```\n\n### 不变性\n\n不变性直接对抗**可变状态扩散**。当数据不可变时，行为不再依赖时序，推理负担从\"运行时状态\"退化为\"静态结构\"。函数式编程以此为核心原则，其本质是用约束换取可预测性。\n\n### 显式化\n\n将隐式假设、隐式依赖、隐式状态变为显式。直接对抗**语义模糊**与**未知的未知**。\n\n* 隐式依赖 → 显式声明依赖\n* 隐式约定 → 显式接口契约\n* 隐式状态 → 显式状态机\n\n### 一致性\n\n相似的问题用相同的方式解决。一致性本身不减少代码量，但通过建立**可迁移的心智模型**，大幅降低认知负荷——读者在一处学会的模式，可以直接复用到其他地方。\n\n### 删减\n\n最彻底的手段：不存在的代码没有复杂性。删减直接对抗**偶然复杂性**，是 YAGNI 原则的本质——不要为假设中的未来需求，在今天引入真实的复杂度。\n\n## 设计原则：代码层的秩序\n\n> 设计原则是从无序到有序的经验总结，是控制局部复杂性的策略。\n\n### 结构性设计原则\n\n| 原则              | 含义           | 核心思想    |\n| --------------- | ------------ | ------- |\n| **SRP 单一职责**    | 每个模块只对一个行为负责 | 控制变更范围  |\n| **OCP 开闭原则**    | 对扩展开放，对修改关闭  | 以抽象隔离变化 |\n| **LSP 里氏替换**    | 子类可替代父类      | 保持行为一致性 |\n| **ISP 接口隔离**    | 不依赖无关接口      | 控制依赖扩散  |\n| **DIP 依赖反转**    | 依赖抽象而非实现     | 控制依赖方向  |\n| **LoD 迪米特法则**   | 只与直接协作者交流    | 封装传播半径  |\n\n> 这些原则共同形成一个目标：**以抽象对抗变化，以接口维持秩序。**\n\n#### SRP：单一职责原则\n\n任何一个软件模块都应只对某一类行为负责，修改一个类的原因应该只有一个。\n\n主要讨论函数与类的关系。当一个类承担过多职责时，不相关的函数会聚集在一起，此时应将这个类分解，让每个子类专注于单一职责。\n\n#### OCP：开闭原则\n\n设计良好的软件应该容易扩展，同时禁止修改已有代码。\n\n目标是将旧代码的修改量降至最小，限制变化的范围。在繁杂的业务代码中，应编写可适应未来情况、能以软编码方式变更业务逻辑的代码。实现方式是通过接口反转组件间的依赖关系，使高层组件不会因低层组件被修改而受到影响，并通过中间层隔离高层组件对低层细节的直接依赖。\n\n#### LSP：里氏替换原则\n\n一个软件实体如果使用的是某个基类，那么它一定也可以使用其子类，且无法察觉出基类对象与子类对象的区别。\n\n```java\nanimal.run(); → cat.run();\n```\n\n若不满足此原则，各子类的行为差异会增大继承体系的复杂度。LSP 是指导接口与其实现方式的核心设计原则。\n\n#### ISP：接口隔离原则\n\n对模块来说，与它无关的接口发生变更时不应该影响到该模块；不应该强迫客户依赖它们不用的方法。\n\n使用多个专门的接口比单一的总接口更合理。软件设计如果依赖了它并不需要的东西，会引入不必要的耦合，带来麻烦。\n\n#### DIP：依赖反转原则\n\n高层模块不应该依赖于低层模块，二者都应该依赖于抽象；抽象不应该依赖于细节，细节应该依赖于抽象。\n\n想要设计一个灵活的系统，应多引用抽象类型而非具体实现——接口相比实现更为稳定。该原则主要关注系统中那些经常变动的部分，通过依赖抽象隔离变化的传播。\n\n#### LoD：迪米特法则\n\n一个模块只应与它的直接协作者交流，不应深入了解协作者的内部结构。典型的违反形式是链式调用 `a.getB().getC().doSomething()`——调用者不仅依赖了 B，还隐式依赖了 B 的内部结构 C，任何一层的变动都会沿链向外传播。LoD 的本质是封装传播半径：让变化在模块边界处自然消失，而不是蔓延到无关的地方。\n\n#### SOLID 的协同体系\n\n五个原则不是孤立的规则，而是相互依存的系统，共同指向同一个目标：\n\n- **SRP 是基础**：职责单一，变更边界才清晰，其余原则才有施展的空间。\n- **OCP 是目标**：系统能在不修改已有代码的前提下扩展——这是整个体系的核心诉求。\n- **DIP 是 OCP 的实现机制**：只有依赖抽象而非具体实现，才能真正做到对修改关闭。\n- **LSP 是继承场景下 OCP 的前提**：子类必须可以替换基类，抽象才有意义，才能被安全复用。\n- **ISP 是 DIP 的精度约束**：接口粒度过大，依赖抽象反而引入无关耦合，ISP 确保接口足够精准可依赖。\n\n### 平衡性原则 —— 从理性到节制\n\n* **DRY（不要重复）**：重复是复杂性的温床，相同逻辑应有唯一的权威来源。\n* **YAGNI（你不会需要它）**：不要为未来的假设增加当下的负担，只实现现在真正需要的。\n* **Rule of Three（三次原则）**：在重复中发现抽象，但抽象须经三次印证，避免过早提炼。\n* **KISS（保持简单）**：设计的美感来自直觉一致与易于理解，简单优于聪明。\n* **POLA（最小惊奇原则）**：让系统行为符合常识，减少认知摩擦，降低出错概率。\n* **节制地使用原则本身**：原则若被机械套用同样会适得其反——过度 SRP 导致类爆炸，过度 DIP 导致接口层叠，过度 OCP 导致过早抽象。原则的价值在于指导判断，而非替代判断。\n\n这些原则塑造了微观层面的\"理性结构\"，是代码世界的行为准则。\n\n## 模块与层次：结构化复杂性的方式\n\n模块化与分层，是人类应对认知边界的本能策略。\n当一个系统复杂到无法整体理解时，唯一的出路是：建立边界，让局部可以被独立理解。\n\n### 模块：认知的边界\n\n模块的本质不是代码单元，而是**认知边界**。一个好的模块，让人在完全不理解其内部的情况下，仍然能对它的外部行为做出正确推理。\n\n模块的价值不在于\"拆分了代码\"，而在于\"减少了理解一件事所需要知道的其他事\"。模块边界越清晰，局部可理解性越强，系统的整体认知负荷就越低。\n\n### 层次：抽象的跃迁\n\n分层的本质是**抽象的跃迁**。每一层都应该提供一种新的语言——让上层能用更少的概念表达更多的意图，而无需感知下层的细节。\n\n层次失败的信号，往往不是\"层数不够\"，而是\"抽象没有发生\"：上下层之间只是换了个名字，而非换了一个思考维度。真正的层次，意味着跨层后理解问题所用的词汇发生了质的变化。\n\n### 分与合：有意识的张力\n\n分离与合并，是模块化设计中永恒的张力：分离降低了局部复杂性，却引入了协调成本；合并减少了协调，却扩大了理解范围。\n\n这个张力没有正确答案，只有**有意识的选择**。判断边界位置的依据，不是代码量、不是技术归属，而是**变化率**：把变化率相同的事物放在一起，把变化率不同的事物隔开。边界的正确位置，就是变化不再跨越的地方。\n\n## 组件设计：系统层的秩序\n\n> 当软件规模扩大到无法在一个脑中完全装下时，设计的重心从函数与类上升为**组件与依赖图**。\n\n模块解决\"如何理解局部\"，组件解决\"如何演化整体\"。组件是可独立部署与演化的最小单元——既是技术边界，也是组织边界。\n\n### 聚合：什么应该在一起\n\n组件内部的聚合，本质仍是变化率问题，只是升维到了发布与复用的粒度。\n\n- **CCP（共同闭包原则）** 回答变化的维度：总是因同一理由变化的事物，应放在同一组件中——这是 SRP 在组件粒度上的投影。\n- **CRP（共同复用原则）** 回答复用的维度：总是被一起使用的事物，应放在同一组件中；不该强迫使用者依赖他们不需要的东西——这是 ISP 在组件粒度上的投影。\n- **REP（复用/发布等同原则）** 则约束结果：组件内的内容应有统一的主题，复用与发布的边界应当一致。\n\n三者相互制衡——没有哪一个可以单独最大化，聚合的决策始终是在变化隔离与复用便利之间寻找平衡。\n\n### 依赖：稳定性的方向\n\n组件之间的依赖不是对称的。**SDP（稳定依赖原则）** 要求依赖应从不稳定流向稳定——一旦逆转，稳定的部分就会被不稳定的变化所拖累。\n\n稳定性与抽象程度天然协同，这正是 **SAP（稳定抽象原则）** 的核心：抽象不依赖实现，因此抽象的组件更稳定；具体实现随需求变化，因此具体的组件更不稳定。依赖的方向，也是抽象程度递增的方向。\n\n### 依赖图：稳定结构的投影\n\n组件的依赖关系构成一张有向图，这张图是系统稳定结构的投影。**ADP（无依赖环原则）** 要求这张图必须无环：有环意味着变化无法被边界拦截，会扩散到整个环；无环意味着稳定性可以沿依赖方向单向传递，变化有边界可守。\n\n## 设计的兼容性与演化性\n\n> 稳定性不是不变，而是**在变中保持秩序**。\n\n### 兼容性：守护已有的契约\n\n兼容性的本质，是对\"已有依赖方\"做出的承诺。系统对外建立的契约存在于三个层次：\n\n* **协议契约**：消息格式与版本的约定——破坏它，旧的通信方无法解码\n* **接口契约**：API 签名与语义的约定——破坏它，已有调用方无法正常运行\n* **数据契约**：存储结构与字段含义的约定——破坏它，历史数据无法被正确读取\n\n维护兼容性，就是在演化时不单方面撤销这些承诺。技术手段（版本号、接口保留、数据迁移）都只是承诺的实现方式，根本在于**有意识地管理契约边界**。\n\n### 演化性：让变化有地方发生\n\n演化性是系统吸收变化而不腐化的能力。系统腐化的本质不是\"代码变旧\"，而是**变化的压力找不到合适的出口**——每一次修改都不得不触碰不该触碰的地方，技术债就在这种摩擦中持续累积。\n\n演化弹性来自设计时预留的\"变化通道\"：边界清晰的模块可以被替换而不影响外部；稳定的接口允许实现在背后悄然更迭；依赖抽象而非具体，让方向性的变化不必波及全局。\n\n演化性不是一次性注入的属性，而是在持续反馈与重构中维护的结果。优秀的架构师不追求\"设计不需要改变的系统\"，而追求\"系统在需要改变时知道往哪里改\"。\n\n## 设计的未来：从模式到模型\n\n软件设计正在经历一次重心的转移：从**记住正确答案**到**建立正确的推理方式**。\n\n模式与规则在问题稳定时有效；当技术环境快速变化、问题的边界持续漂移时，模式会失效，而第一性原理的推理能力不会。设计的未来，不是积累更多模式，而是建立更准确的心智模型。\n\n### 意图驱动：表达层的上移\n\n框架与 DSL 的本质，是将设计的表达层从\"如何实现\"上移到\"想要什么\"。约定优于配置、声明式优于命令式——这不只是编程风格的演进，而是设计语言本身的抽象跃迁。当实现细节被框架吸收，设计者得以在更高维度思考系统的边界与意图。\n\n### 反馈驱动：设计是持续的过程\n\n测试不只是验证，更是设计的反馈机制——可测性暴露耦合，测试的痛苦往往是设计问题的信号。但\"可测\"不等于\"设计良好\"：测试可以确认边界是否清晰，却无法告诉你边界是否在正确的位置。\n\n重构是设计在时间维度上的延续——不是修正错误，而是用更深的理解更新已有的决策。\n\n### 比较推理：设计是选择，不是发现\n\n好的设计决策来自多方案的对比，而非对单一方案的深度优化。比较不同的结构，才能真正理解某个选择的代价与收益。多次设计的价值，不在于找到\"最优解\"，而在于揭示不同选择之间的本质权衡。\n\n### AI 时代的设计：判断力的边界前移\n\nAI 可以生成代码，但生成的是实现，不是设计。当实现的成本趋近于零时，**判断力成为稀缺资源**：什么边界是正确的？什么依赖是危险的？什么抽象是稳定的？这些问题 AI 无法代劳，因为它们没有唯一答案，只有对复杂性、演化方向、组织协作的综合判断。\n\nAI 辅助设计带来的不是设计者的消亡，而是设计者角色的前移——从写代码的人，转变为**定义问题边界、评估方案取舍、维护系统认知模型**的人。设计能力的核心，正在从\"知道怎么做\"转向\"知道为什么这样做、以及什么时候应该做不同的选择\"。\n\n## 结语：设计的哲学\n\n软件设计这门学科，始于一个古老的张力：**人类的认知能力是有限的，系统的复杂性却可以无限增长**。设计，是人类在这个张力中寻求秩序的方式。\n\n这篇文档走过的路，是同一种思维方式在不同粒度上的展开：在代码层，通过原则控制局部的混乱；在模块层，通过边界让局部可以被独立理解；在组件层，通过稳定性的方向让整体可以持续演化；在时间维度，通过兼容性与演化弹性让系统在变化中存活。\n\n这些不是独立的策略，而是同一个核心洞察的投影：**把复杂性从不可控的位置，转移到可控的位置**。\n\n设计不追求消除复杂性——本质复杂性是问题本身的一部分，无法被设计掉。设计追求的，是让复杂性在正确的地方、以正确的形式被承担：在深模块的内部，在稳定的依赖方向里，在清晰的边界之内。\n\n在 AI 时代，这一判断力变得尤为关键。当实现的代价趋近于零，\"如何做\"不再稀缺，\"**为什么这样划分边界、为什么这样安排依赖**\"成为不可替代的能力。软件设计的核心——在不确定中做出有意识的选择——正在成为人类在工程中最后的、也是最根本的贡献。\n\n> 好的设计，让每一个边界都有理由存在，\n> 让每一次变化都知道往哪里发生，\n> 让系统在时间的侵蚀中，仍然保持可以被理解的形态。\n\n## 关联内容（自动生成）\n\n- [/软件工程/理论/结构化设计方法.md](/软件工程/理论/结构化设计方法.md) 结构化设计方法与软件设计在模块化、信息隐藏和关注点分离方面有密切联系\n- [/软件工程/软件设计/代码质量/代码质量.md](/软件工程/软件设计/代码质量/代码质量.md) 代码质量是软件设计的重要目标，两者共同关注高内聚、低耦合的模块设计\n- [/软件工程/软件设计/代码质量/整洁代码.md](/软件工程/软件设计/代码质量/整洁代码.md) 整洁代码体现了软件设计原则的具体实践，特别是SOLID原则的落地\n- [/软件工程/软件设计/代码质量/代码重构.md](/软件工程/软件设计/代码质量/代码重构.md) 代码重构是软件设计原则在代码层面的落地实践，有助于实现高内聚低耦合的模块设计\n- [/软件工程/架构/系统设计/架构设计.md](/软件工程/架构/系统设计/架构设计.md) 架构设计是软件设计在更高层次上的体现，关注系统整体结构和组件间关系\n- [/软件工程/设计模式/设计模式.md](/软件工程/设计模式/设计模式.md) 设计模式是软件设计原则的具体实现方式，提供了常见问题的解决方案\n- [/软件工程/理论/软件需求.md](/软件工程/理论/软件需求.md) 软件设计承接需求分析的结果，将需求转化为具体的系统设计方案\n- [/软件工程/领域驱动设计.md](/软件工程/领域驱动设计.md) 领域驱动设计提供了复杂业务系统的设计方法，与软件设计中的模块化和边界定义密切相关\n- [/软件工程/微服务/微服务.md](/软件工程/微服务/微服务.md) 微服务架构体现了软件设计中模块化和低耦合高内聚的思想\n- [/编程语言/编程范式/面向对象.md](/编程语言/编程范式/面向对象.md) 面向对象编程范式是软件设计的重要基础，其原则如SOLID与软件设计紧密相关\n- [/软件工程/软件设计/软件开发本质.md](/软件工程/软件设计/软件开发本质.md) 探讨软件开发的认知本质与协作哲学，是理解软件设计出发点的基础文档\n- [/软件工程/架构/演进式架构.md](/软件工程/架构/演进式架构.md) 阐述架构如何在不确定中持续演进，直接对应兼容性与演化性章节的核心命题\n- [/软件工程/架构/架构思维.md](/软件工程/架构/架构思维.md) 讲述多视角分解与系统整合的思维方式，与模块/层次的结构化思路高度一致\n- [/软件工程/架构模式/分层架构.md](/软件工程/架构模式/分层架构.md) 分层架构是\"层次：抽象跃迁\"原则的典型落地，阐释依赖倒置与稳定性梯度\n- [/编程语言/编程范式/函数式编程.md](/编程语言/编程范式/函数式编程.md) 函数式编程以不变性为核心对抗可变状态带来的复杂性，对应文档中不变性章节\n- [/编程语言/编程范式/编程范式.md](/编程语言/编程范式/编程范式.md) 编程范式决定了设计的表达方式与约束边界，对应意图驱动与设计语言的抽象跃迁\n","metadata":"tags: ['软件工程', '架构设计', '编程语言']","hasMoreCommit":true,"totalCommits":21,"commitList":[{"date":"2026-03-24T16:39:13+08:00","author":"MY","message":"docs(software-design): 更新偶然复杂性的描述","hash":"36d407892ac5cd44f8253c4645073a8adacfaf7d"},{"date":"2026-03-11T18:14:29+08:00","author":"MY","message":"docs(software-design): 修复软件设计文档中的格式问题","hash":"63d5838c23ba066df5f7a57c1458f05e61f1c09a"},{"date":"2026-03-11T14:13:43+08:00","author":"MY","message":"docs(software-design): 完善软件设计文档内容并优化章节结构","hash":"c5243e222c46a5f3eb8938cbb0b0b0b9b561797a"},{"date":"2026-03-10T18:21:40+08:00","author":"MY","message":"docs(software-design): 更新软件设计原则文档内容","hash":"b2c6bf5997c408580278052ce1fb1cf236a22b0b"},{"date":"2026-03-10T16:36:34+08:00","author":"MY","message":"docs(software-design): 完善软件设计文档中的复杂性理论","hash":"9d576d3b117359b2fc46a6234b642cd261698e9e"},{"date":"2026-03-10T11:07:27+08:00","author":"MY","message":"docs(software-design): 移除文档中的冗余分隔线并优化格式","hash":"ba5614fdcf58cea63276e82bcf4489879d94adfe"},{"date":"2026-02-12T14:07:03+08:00","author":"MY","message":"doc: 整理标签","hash":"290b3e8ad18f48832ac282290238d020fc030a88"},{"date":"2026-01-20T14:39:32+08:00","author":"MY","message":"docs(software-design): 更新软件设计文档的标签和关联内容","hash":"40348a452e9fb3b50c2100e30724ef4be3338650"},{"date":"2025-11-16T21:30:56+08:00","author":"MY","message":"docs: 统一并精简文档标签","hash":"21362e9d7aeb62e05364cd5e7f3a3c24d7e293c7"},{"date":"2025-10-14T15:40:50+08:00","author":"MY","message":"docs(软件工程): 重构软件设计文档结构与内容","hash":"abf1e2fd59654108b515d7ac05c83feebbc3cc15"}],"createTime":"2021-08-03T19:01:36+08:00"}