第四阶段:软件设计与架构哲学
阶段定位:从“会用框架”到“会做设计”,从“理解实现”到“创造实现”。本阶段是前三阶段技术知识的认知升华——用设计视角重新审视已经掌握的所有技术,形成可迁移的架构决策能力。
系列间依赖关系
flowchart TB
subgraph 根基[" 根基层 "]
D1["④ 软件设计原则与哲学<br/>(8篇)"]
end
subgraph 方法论[" 方法论层 "]
D2["① 设计模式深度<br/>(10篇)"]
D3["② 领域驱动设计 DDD<br/>(15篇)"]
D4["③ 架构风格与模式<br/>(10篇)"]
end
subgraph 实践[" 实践层 "]
D5["⑤ 工程化与交付设计<br/>(9篇)"]
end
D1 --> D2
D1 --> D3
D1 --> D4
D2 --> D3
D2 --> D4
D3 --> D4
D2 --> D5
D3 --> D5
D4 --> D5
style D1 fill:#fce4ec,stroke:#880e4f
style D2 fill:#e8f5e9,stroke:#2e7d32
style D3 fill:#e8f5e9,stroke:#2e7d32
style D4 fill:#e8f5e9,stroke:#2e7d32
style D5 fill:#e3f2fd,stroke:#1565c0
| 系列 | 层级 | 核心问题 |
|---|---|---|
| ④ 软件设计原则与哲学 | 根基层 | 什么样的设计是“好”的?SOLID 如何落地?复杂度如何管理? |
| ① 设计模式深度 | 方法论层 | GoF 23 种模式如何在框架中应用?何时该用、何时不该用? |
| ② 领域驱动设计 DDD | 方法论层 | 如何把业务复杂性驯服在代码结构中? |
| ③ 架构风格与模式 | 方法论层 | 微服务/事件驱动/云原生等架构风格如何选型与组合? |
| ⑤ 工程化与交付设计 | 实践层 | 设计如何落地为可测试、可交付、可追溯的工程体系? |
依赖摘要:
- ④ → ①:SOLID 原则是设计模式的哲学根基。开闭原则(OCP)是策略模式、模板方法模式的理论来源;依赖倒置原则(DIP)是工厂模式、适配器模式的理论来源;单一职责原则(SRP)是装饰器模式的理论来源。
- ④ → ②:限界上下文的划分依据是单一职责原则和高内聚低耦合;聚合的设计依据是迪米特法则(最小知识原则);领域事件的设计依据是开闭原则(对扩展开放,对修改封闭)。
- ④ → ③:架构风格的选型本质上是质量属性(性能/可用性/安全性/可维护性/可测试性)之间的权衡——这正是 ATAM 权衡分析法的应用场景。
- ② → ①:DDD 的聚合根、资源库、领域服务等战术模式,本质上是对 GoF 模式(工厂、策略、观察者)在业务层的重新诠释。
- ② → ③:限界上下文是微服务拆分的边界;领域事件是事件驱动架构的驱动力;CQRS 是读写分离架构在业务层的实现。
- ①/②/③ → ⑤:设计模式决定了测试策略(策略模式便于 Mock,责任链便于分段测试);DDD 的限界上下文决定 API 契约的边界;架构风格决定 Git 仓库拆分和 CI/CD 流水线设计。
系列 ① 设计模式深度(10 篇)
定位:以 GoF 23 种经典设计模式的定义与结构为骨架,以 JDK / Spring / Netty / Kafka 源码中的实现为血肉,最后以模式选型决策树收尾。
| 序号 | 文章标题 | 稳定性 | 知识点 |
|---|---|---|---|
| 1 | 创建型模式:单例、工厂、建造者与原型 | 🟢 | 单例模式:定义、结构(私有构造器 + 静态实例 + 静态获取方法)。JDK Runtime.getRuntime()(饿汉式)、枚举单例(防反射防序列化破坏)。Spring @Scope("singleton") 与 GoF 单例的区别(per-IoC vs per-JVM)。工厂方法模式:定义、结构( Creator + factoryMethod() + ConcreteCreator)。JDK Iterable.iterator()。Spring FactoryBean.getObject()。抽象工厂模式:定义、结构( AbstractFactory + ConcreteFactory + AbstractProduct + ConcreteProduct)。Spring BeanFactory 层次结构。建造者模式:定义、结构( Director + Builder + ConcreteBuilder + Product)。JDK StringBuilder、Stream.builder()。Spring HttpSecurity DSL 链式配置。原型模式:定义、结构( Prototype + clone())。JDK Cloneable + Object.clone()(浅拷贝)。Spring @Scope("prototype")。 |
| 2 | 结构型模式(上):适配器、桥接与装饰器 | 🟢 | 适配器模式:定义、结构(Target + Adapter + Adaptee)。类适配器(继承)vs 对象适配器(组合)。JDK Arrays.asList()、InputStreamReader。Spring HandlerAdapter(将 HttpRequestHandler/Controller 统一适配为 ModelAndView handle())。桥接模式:定义、结构( Abstraction + RefinedAbstraction + Implementor + ConcreteImplementor)。JDK java.sql.Driver 与 Connection。Spring PlatformTransactionManager 与 DataSourceTransactionManager/JtaTransactionManager。装饰器模式:定义、结构( Component + ConcreteComponent + Decorator + ConcreteDecorator)。JDK BufferedInputStream、Collections.synchronizedList()。Netty ChannelPipeline(每个 ChannelHandler 装饰处理逻辑)。Spring BeanDefinitionDecorator。 |
| 3 | 结构型模式(下):代理、外观、组合与享元 | 🟢 | 代理模式:定义、结构(Subject + RealSubject + Proxy)。JDK 动态代理(InvocationHandler)vs CGLIB(MethodInterceptor)。Spring AOP(JdkDynamicAopProxy vs CglibAopProxy)、@Lazy 延迟注入代理。外观模式:定义、结构( Facade + 子系统类群)。JDK Class 类。Spring JdbcTemplate(封装 DataSource → Connection → Statement → ResultSet)。组合模式:定义、结构( Component + Leaf + Composite)。Spring CompositePropertySource。享元模式:定义、结构( FlyweightFactory + Flyweight + ConcreteFlyweight + 非共享外部状态)。JDK Integer.valueOf(-128~127) 缓存池、String 常量池。Spring 三级缓存 singletonObjects。 |
| 4 | 行为型模式(上):策略、模板方法与观察者 | 🟢 | 策略模式:定义、结构(Context + Strategy + ConcreteStrategy)。JDK Comparator、ThreadPoolExecutor.RejectedExecutionHandler。Spring ResourcePatternResolver、InstantiationStrategy。Kafka Partitioner 接口。模板方法模式:定义、结构( AbstractClass + templateMethod() + primitiveOperation())。JDK AbstractList.addAll() 调用子类 add()、AQS.acquire() 调用子类 tryAcquire()。Spring AbstractApplicationContext.refresh()(13 步模板 + 钩子)。观察者模式:定义、结构( Subject + Observer)。推送模型 vs 拉取模型。JDK Observer/Observable(JDK 9 废弃)、PropertyChangeListener。Spring ApplicationEvent + @EventListener(进化:同步/异步/事务绑定)。Kafka ConsumerRebalanceListener。 |
| 5 | 行为型模式(中):责任链、命令、迭代器与中介者 | 🟢 | 责任链模式:定义、结构(Handler + ConcreteHandler + successor)。纯链(处理或传递)vs 不纯链(处理后可继续传递)。Spring FilterChain、HandlerInterceptor 链。Netty ChannelPipeline(Inbound/Outbound 双向链)。命令模式:定义、结构( Invoker + Command + ConcreteCommand + Receiver)。JDK Runnable、Callable。Kafka ProducerRecord 本质是命令对象。迭代器模式:定义、结构( Iterator + ConcreteIterator + Aggregate + ConcreteAggregate)。JDK Iterator + fail-fast(modCount)。Spring CompositeIterator。中介者模式:定义、结构( Mediator + ConcreteMediator + Colleague)。JDK java.util.Timer。Spring DispatcherServlet 作为前端控制器协调各组件。 |
| 6 | 行为型模式(下):状态、备忘录、访问者与解释器 | 🟢 | 状态模式:定义、结构(Context + State + ConcreteState)。JDK Thread 状态机。Seata AT 事务状态机(Begin→Committing→Committed/Rollbacking→Rollbacked)。备忘录模式:定义、结构( Originator + Memento + Caretaker)。JDK Serializable。Seata AT undo_log 表(beforeImage + afterImage 行级快照)。访问者模式:定义、结构( Visitor + ConcreteVisitor + Element + accept())。JDK java.nio.file.FileVisitor。Spring BeanDefinitionVisitor。解释器模式:定义、结构( AbstractExpression + TerminalExpression + NonterminalExpression + Context)。Spring SpEL(ExpressionParser → Expression → EvaluationContext → getValue())。 |
| 7 | 模式组合与变体:框架中的多模式协作 | 🟢 | Spring AOP:代理(创建代理对象)+ 责任链(MethodInterceptor 链式调用)+ 策略(JDK 代理 vs CGLIB)+ 适配器(AdvisorAdapter 将 Advice 适配为 Interceptor)。Spring IoC:工厂( BeanFactory 层次)+ 单例(singleton 作用域)+ 模板方法(refresh() 流程)+ 策略(不同 InstantiationStrategy)+ 观察者(事件机制)。Netty 管道:责任链( ChannelPipeline)+ 装饰器(每个 ChannelHandler 增加处理能力)+ 策略(EventExecutorChooser)+ 适配器(ChannelInboundHandlerAdapter)。Kafka 生产者:策略( Partitioner)+ 命令(ProducerRecord)+ 模板方法(Sender.run())+ 观察者(Callback)。反模式:模式堆砌——不是所有场景都需要多模式协作,过度抽象导致代码膨胀。 |
| 8 | 设计原则:SOLID、正交性与迪米特法则 | 🟢 | SRP 单一职责:一个类应该只有一个引起变化的原因。OrderService 不应同时处理订单逻辑和发送邮件。OCP 开闭原则:对扩展开放,对修改封闭。 BeanPostProcessor 扩展点,无需修改 Spring 核心代码。LSP 里氏替换:子类应能替换父类而不引起错误。 InputStream 的子类都能替换 InputStream 使用。ISP 接口隔离:不应强迫客户端依赖不使用的方法。 CharSequence 将公共接口隔离出来。DIP 依赖倒置:高层不应依赖低层,两者都依赖抽象。 JdbcTemplate 依赖 DataSource 接口而非 HikariDataSource。正交性:不同变化维度相互独立。 HandlerMapping(路由)与 HandlerAdapter(执行)的正交分离。迪米特法则:只与直接朋友通信。 a.getB().getC().doX() 的反模式。微服务中通过 API 网关通信。 |
| 9 | 设计反模式与过度设计的识别 | 🟢 | 单例误用:全局状态 → 隐藏耦合、测试困难。静态工具类优于单例。 工厂误用:3 个以下实现类时,直接 new 比工厂更简单。 观察者误用:没有明确解耦需求时,同步调用优于事件通知。 责任链误用:链过长(Spring Security 默认 15 个 Filter)→ 调试困难。 装饰器误用:装饰层过多 → 类型层次复杂。 过度设计特征:为不确定需求预留扩展点、每个接口只有一个实现类、代码量增长远超业务复杂度。 KISS 原则:能用 if-else 不用策略模式,能用单机不用分布式。 YAGNI 原则:在真正需要变化时才重构引入模式。 |
| 10 | 模式选型决策树与实战演练 | 🟢 | 决策树: 对象创建复杂?→ Builder/Factory Method/Abstract Factory。 接口不兼容?→ Adapter。需要动态增强?→ Decorator。需要控制访问?→ Proxy。 算法需灵活切换?→ Strategy。固定流程有钩子?→ Template Method。状态决定行为?→ State。 多处理者可能响应?→ Chain of Responsibility。一对多通知?→ Observer。 实战推演 4 场景:支付系统多支付方式(Strategy)、Spring Boot 多配置源加载(Composite + Facade)、订单状态流转(State)、网关鉴权→限流→日志→转发(Chain of Responsibility)。 自检清单:是否引入了不必要的抽象?是否真的存在变化?现在不用的模式三年后会不会成为技术债? |
系列 ② 领域驱动设计 DDD(15 篇)
定位:从战略设计到战术设计再到工程落地,形成完整的 DDD 方法论。贯穿案例:电商交易系统。
| 序号 | 文章标题 | 稳定性 | 知识点 |
|---|---|---|---|
| 1 | DDD 战略设计:限界上下文、实体与值对象 | 🟢 | 统一语言:与业务专家协同建立术语表,在代码中映射为类名、方法名、模块名。 事件风暴:识别领域事件( OrderPlaced、InventoryDeducted)、命令(PlaceOrder)、聚合(Order、Inventory)→ 聚类为限界上下文。限界上下文:语义边界,决定微服务拆分粒度;验证四大启发式规则(业务能力、组织边界、数据一致性、变化频率)。 上下文映射:共享内核、客户-供应商、防腐层、开放主机服务、发布语言。 AI 辅助事件风暴:将业务需求描述输入 LLM,自动提取候选领域事件、命令、聚合,人工复核后形成初步限界上下文。 |
| 2 | 战术 DDD 与 Spring 实现:聚合、资源库与领域服务 | 🟢 | 聚合与聚合根:一致性边界,小聚合优先,通过 ID 引用其他聚合,一次事务只修改一个聚合。 值对象: @Embeddable 实现 Address、Money,equals/hashCode 基于值比较。资源库: interface OrderRepository extends JpaRepository<Order, Long>,只定义聚合根的资源库。领域服务:跨聚合的业务逻辑(如 PricingService 计算订单总额),区别于应用服务(编排)。领域事件: AbstractAggregateRoot.registerEvent() 发布,@TransactionalEventListener 异步处理。 |
| 3 | Spring Modulith 与 DDD 融合:模块化单体的领域边界 | 🟡 | 核心组件:@ApplicationModuleListener(异步事件通信)、@ApplicationModuleTest(模块级集成测试,Scenario API)。模块验证: ModuleTest.verify() 检测模块间非法依赖。ArchUnit 约束: ArchRule 禁止领域层依赖基础设施层。与微服务拆分衔接:Modulith 作为微服务的前置过渡,限界上下文清晰后可独立拆分为微服务。 |
| 4 | 事件驱动架构与 CQRS 的 Spring 落地 | 🟡 | CQRS 命令/查询分离:写端 @Entity + JPA,读端 @Document (ES) 或 Redis;写操作发布 OrderPlaced 事件,读端消费更新物化视图。Spring 实现:写端 ApplicationEventPublisher.publishEvent(),读端 @TransactionalEventListener(phase = AFTER_COMMIT) 异步消费。查询优化:读端直接查询 ES/Redis,不经过写模型。 事件存储: outbox 表 + Debezium CDC 保证事件可靠发布。 |
| 5 | 领域事件设计原则与 Spring 实现:Event 建模、存储与分发 | 🟢 | 事件设计:命名过去式(OrderPlaced),包含聚合 ID、关键字段、时间戳;避免携带过多数据。事件存储与发布: outbox 模式在业务事务中写入 event_store 表,Debezium 或 PollingPublisher 读取并发送到 Kafka。消费者幂等:通过 eventId 唯一键 INSERT ON DUPLICATE KEY UPDATE 去重。与集成事件的区分:领域事件关注业务含义,集成事件关注技术同步。 |
| 6 | CQRS 与 Event Sourcing 深度:Axon Framework 实战 | 🟡 | Axon 核心源码:@Aggregate 标识聚合根,@CommandHandler 处理命令并发布事件,@EventSourcingHandler 根据事件重建状态。AggregateLifecycle.apply(event):事件先经过 EventBus 发布到 EventStore,再由 TrackingEventProcessor 分发。Saga 编排: @Saga + @StartSaga + @SagaEventHandler + @EndSaga 实现分布式长事务(补偿逻辑),对比 Seata AT/TCC。DeadlineManager:处理超时业务(如 30 分钟未支付自动取消),基于 Quartz 或 JobRunr 调度。 |
| 7 | 防腐层与接口适配:集成多个限界上下文的策略 | 🟢 | 防腐层代码实现:@Component 封装 FeignClient,将上游模型 ExternalOrderDTO 翻译为内部领域对象 Order。适配器模式: InventoryAdapter implements InventoryPort,内部调用 RPC 或 HTTP,领域层仅依赖 InventoryPort 接口。集成多个 Bounded Context:每个下游对应一个 Adapter + Translator,隔离外部模型变化。 测试防腐层: WireMock 模拟下游 API,验证 Translator 翻译正确性。 |
| 8 | 聚合设计指南:大小、边界与事务一致性 | 🟢 | 设计原则:小聚合(减少并发冲突),通过 ID 引用其他聚合(不直接持有对象引用),最终一致性处理跨聚合操作。 事务边界:一次事务只修改一个聚合实例;跨聚合操作通过领域事件异步完成。 不变量保护:聚合根检查业务规则(如 Order 的 confirm() 校验状态为 PENDING 且库存充足),校验在聚合内部而非外部 Service。反模式:聚合过大(包含过多实体→慢 SQL、大对象图)、聚合过小(导致事务边界不完整)。 |
| 9 | DDD + Kubernetes:领域服务到微服务的部署映射 | 🟡 | 限界上下文 → K8s Deployment:每个上下文独立 Deployment、Service、ConfigMap。聚合 → Pod 伸缩单元:热点聚合(如秒杀商品)独立部署与扩缩容。 领域事件 → Istio/Eventing:事件驱动通过 Kafka 或 Knative Eventing 触发。CI/CD:每个上下文独立代码仓库、独立流水线,与 GitOps 结合。 |
| 10 | 微服务划分原则:从业务能力到限界上下文的映射 | 🟢 | 康威定律:团队组织与限界上下文对齐,每个跨职能团队负责一个上下文。 拆分决策:业务能力独立性、数据独立性、变更频率差异、可伸缩性需求四维度评估。 不应拆分:强事务耦合、数据量低、团队规模小→先用 Modulith 单体。 |
| 11 | 复杂业务系统的模型演进与重构策略 | 🟢 | 遗留系统改造:Strangler Fig 模式——新功能在微服务中实现,旧单体功能逐步替换。 聚合拆分:大聚合拆分为多个小聚合,通过领域事件保持最终一致。 数据迁移: pt-archiver 分批迁移,Debezium 双向同步,双写过渡期。 |
| 12 | 业务中台化设计思想:能力复用与标准化 | 🟢 | 中台与限界上下文映射:中台能力(用户中心、订单中心、商品中心)对应共享内核或开放主机服务。 能力标准化模板:能力名称、输入输出、SLA、API 契约(OpenAPI 3.0)、错误码体系。 中台与微服务的边界:中台提供通用能力(如 UserService),前台提供差异化业务(如 VipOrderService)。 |
| 13 | 从代码到架构:编写表达业务意图的陈述式代码 | 🟢 | DSL 模式:订单状态转换使用状态机 DSL。 Builder 模式: Order.builder() 链式调用,内部校验必填字段。Specification 模式: Specification<Order> 封装查询条件,在 Repository 中直接使用。表达式语言: @PreAuthorize("hasRole('ADMIN')") 结合 SpEL 表达业务权限。 |
| 14 | 企业级项目实战:电商交易系统的 DDD 完整案例 | 🟢 | 贯穿案例:从需求出发(用户下单、支付、库存扣减、通知)。 事件风暴:识别 OrderPlaced、PaymentConfirmed、InventoryDeducted、NotificationSent 事件。限界上下文:订单上下文、库存上下文、支付上下文、通知上下文。 聚合设计: Order 聚合(OrderId、OrderItems、Status),Inventory 聚合(ProductId、Quantity)。战术落地:Spring Data JPA 实现 Repository, @Transactional 保护聚合一致性,领域事件发布。CQRS:订单查询走 ES,订单写入走 JPA。 防腐层: PaymentAdapter 封装支付网关 API。 |
| 15 | 反模式与排查宝典 | 🟢 | 12+ 反模式:贫血模型(@Entity 只有 getter/setter,逻辑全在 Service)、聚合过大、资源库滥用、领域事件循环、跨界上下文直调、没有统一语言、值对象错当实体、事件未幂等、CQRS 过度设计、未遵循小聚合、AI 生成的模型未经过人工验证。六步排查法:错误示例→现象描述→排查思路( jstack/arthas、SQL 日志)→根因分析→修正方案→最佳实践。AI 辅助代码审查:通过 LLM 扫描代码,检测贫血模型、聚合过大、缺少防腐层等反模式,输出评审报告。 |
系列 ③ 架构风格与模式(10 篇)
定位:跳出单一框架,理解分布式系统背后的架构模式。与第三阶段总纲呼应——总纲讲“是什么”,这里讲“为什么这样设计”和“如何选型”。
| 序号 | 文章标题 | 稳定性 | 知识点 |
|---|---|---|---|
| 1 | 分层架构与六边形架构 | 🟢 | 经典三层:表现层→业务逻辑层→数据访问层,依赖自上而下。 DDD 四层:接口层→应用层→领域层→基础设施层,依赖倒置(领域层是核心,不依赖任何外部)。 六边形架构(端口-适配器):领域模型在中心,端口(Port)定义接口,适配器(Adapter)实现端口连接外部。输入适配器(HTTP/RPC)和输出适配器(DB/MQ)地位对等。 与 Spring 的关系: @RestController 是输入适配器,JpaRepository 是输出适配器,@Service 是应用层。 |
| 2 | 微服务架构的拆分方法论 | 🟢 | 拆分策略:按业务能力拆分、按 DDD 限界上下文拆分、按康威定律(团队结构)拆分。 拆分粒度决策框架:内聚性、耦合度、团队规模、变更频率、数据一致性要求五维度量化。 何时不拆:业务紧密耦合、数据量与 TPS 不高、团队规模小。 通信选型:同步 RPC(核心链路,强一致)vs 异步消息(非核心链路,最终一致)。 数据策略:每服务独立数据库,去中心化数据管理,CQRS 读写分离。 |
| 3 | 事件驱动架构设计 | 🟢 | 核心概念:事件生产者、事件消费者、事件总线(Message Broker)。 发布-订阅模式:Topic/Queue 解耦生产者与消费者。 事件溯源:所有状态变更存储为事件序列,当前状态 = 事件重放。 CQRS:写模型(Command)与读模型(Query)分离,事件驱动同步。 流处理:Kafka Streams / Flink 实时处理事件流,窗口聚合。 幂等保证:消费者通过唯一键去重,生产者通过幂等发送。 |
| 4 | 数据密集型架构模式 | 🟢 | 数据分区:水平分片(ShardingSphere/Mycat),分片键 = 核心查询条件。 读写分离:一主多从,ProxySQL/ShardingSphere 延迟感知路由。 多级缓存:Caffeine L1(极热)→ Redis L2(热)→ DB L3(温冷)。 冷热分离:ES ILM Hot-Warm-Cold-Delete 四阶段,MySQL pt-archiver 归档。数据中台:Trino 联邦查询 + PG FDW + API 网关统一入口。 一致性边界:强一致(核心交易)vs 最终一致(缓存/搜索同步),CDC 异步收敛。 |
| 5 | 云原生架构模式 | 🟡 | 容器化:Docker 分层构建,Dockerfile 最佳实践。服务网格:Istio Sidecar 透明注入,流量管理(VirtualService + DestinationRule)、安全(mTLS + AuthorizationPolicy)、可观测(Telemetry)。 声明式运维:YAML 定义期望状态,Controller 调谐至期望状态。 弹性伸缩:HPA 基于 CPU/内存/QPS 自动扩缩容,CA 扩 Node。 GitOps:Git 作为声明式配置唯一来源,ArgoCD/Flux 自动同步。 |
| 6 | 响应式架构与流处理 | 🟢 | 响应式宣言:即时响应、韧性、弹性、消息驱动。 Reactor 编程模型:Mono 0-1,Flux 0-N,背压控制(request(n) 信号)。 WebFlux:非阻塞 HTTP 处理,Netty EventLoop 线程模型。 R2DBC:响应式数据库驱动,非阻塞 SQL 执行。 Kafka Streams:有状态流处理拓扑,KStream/KTable/GlobalKTable。 背压传播:从消费者到生产者,全链路非阻塞反压。 |
| 7 | 架构演进策略 | 🟢 | Strangler Fig 模式:新功能在微服务中实现,旧单体功能逐步替换,最终绞杀单体。 模块化过渡:Spring Modulith 作为微服务前置,限界上下文清晰后拆分。 可逆决策:技术选型保留回退路径,如先混合部署再逐步迁移。 技术债务管理:每季度评审超时参数、每半年压测验证容量、每年评审架构模式。 演进路径:单体 → 垂直拆分(SOA)→ 微服务 → 云原生(容器化+K8s+服务网格)。 |
| 8 | 架构评审与检查清单 | 🟢 | 四维评审:通信(调用链闭环?超时遵循传递链?重试保证幂等?)、协作(分布式锁有 fencing token?事务方案匹配一致性要求?)、存储(分片键是所有核心查询条件?缓存 TTL 随机化?)、治理(熔断降级覆盖所有外部依赖?探针考虑 GC 停顿?)。 通信检查清单:超时传递链校验、重试幂等校验、MQ 死信队列监控、连接池 maxActive < DB max_connections × 0.5。 协作检查清单:锁 fencing token 校验、事务超时 > GC + 业务 + 网络、Raft 集群奇数节点。 存储检查清单:分片键区分度 > 分片数 × 10、缓存 TTL = base + random(0,300)。 治理检查清单:所有外部依赖有熔断、探针 liveness > GC × 2 + 启动、告警 P0 电话 + P1 企微 + P2 邮件。 |
| 9 | 架构权衡分析法(ATAM) | 🟢 | 质量属性场景:用场景描述性能(10000 QPS 下 P99 < 100ms)、可用性(单 AZ 故障下服务 60s 内恢复)、安全性(SQL 注入检测 < 1ms)、可维护性(新人 1 周可提交首个 PR)、可测试性(单元测试覆盖率 > 80%)。 敏感点与权衡点:敏感点(影响单一质量属性的设计决策)、权衡点(同时影响多个质量属性且存在冲突的决策)。 效用树:质量属性 → 场景 → 优先级(H/M/L)→ 难度(H/M/L)。 风险与非风险:风险(可能对质量属性产生负面影响的决策),非风险(经过验证的安全决策)。 ATAM 流程:阶段 0 准备 → 阶段 1 评估 → 阶段 2 评审 → 阶段 3 报告。 |
| 10 | 架构风格选型决策树与实战 | 🟢 | 决策树: 业务复杂且团队大 → 微服务。简单且团队小 → 模块化单体。 实时性要求高 → 同步 RPC。吞吐量优先 → 异步消息。 数据量大且查询多样 → CQRS + ES。数据量小且查询简单 → 单库。 需要长期存储历史事件 → Event Sourcing。 需要多平台统一查询入口 → 数据中台(联邦查询)。 实战推演:电商平台架构选型——微服务拆分(订单/库存/支付/通知)+ 同步 RPC(核心)+ 异步消息(非核心)+ AT 分布式事务(订单-库存)+ CDC 缓存刷新(MySQL → Kafka → Redis)+ ES 搜索 + K8s + Istio。 架构决策记录(ADR):记录决策上下文、备选方案、最终选择与理由、后果。 |
系列 ④ 软件设计原则与哲学(8 篇)
定位:提炼跨越语言和框架的设计智慧。SOLID 在设计模式系列已讲,本系列聚焦更高阶的设计哲学。
| 序号 | 文章标题 | 稳定性 | 知识点 |
|---|---|---|---|
| 1 | 高内聚低耦合的量化与实现 | 🟢 | 内聚度量:LCOM(Lack of Cohesion of Methods),方法共享字段越少内聚越低。巧合内聚→逻辑内聚→时间内聚→过程内聚→通信内聚→顺序内聚→功能内聚,七级内聚。 耦合度量:Afferent Coupling(传入耦合,被依赖数)vs Efferent Coupling(传出耦合,依赖别人数)。不稳定性 = Efferent / (Afferent + Efferent),0=最稳定,1=最不稳定。 代码层面实现:接口隔离(ISP)、依赖倒置(DIP)、包设计原则(REP/CCP/CRP)。 微服务中的体现:限界上下文内高内聚,上下文间低耦合,通过 API/事件异步通信。 |
| 2 | 正交性与关注点分离 | 🟢 | 正交性定义:不同变化维度相互独立,修改一个维度不影响其他。 正交设计四原则:分离关注点、缩小抽象范围、一次且仅一次、限制变化传播。 AOP 与横切关注点:日志/事务/安全是横切关注点,AOP 将其与业务逻辑正交分离。 中间件管道模式:Netty ChannelPipeline、Spring FilterChain,每个处理器关注独立维度。配置 vs 代码:环境相关配置与业务逻辑正交,配置中心(Nacos/Apollo)实现配置与代码的分离。 |
| 3 | 约定优于配置 | 🟢 | 起源:Rails 的核心理念,Spring Boot 将其发扬光大。 Spring Boot 的体现: @SpringBootApplication 自动组件扫描、@EnableAutoConfiguration 条件装配、application.yml 默认属性、Starter 依赖传递。约定的层级:框架默认约定 → 团队规范约定 → 项目特殊约定。约定越靠前优先级越低。 合理约定 vs 过度魔法:约定让 80% 场景零配置,但允许覆盖约定(显式配置 > 约定)。 反模式:不理解约定原理盲目排除( exclude 滥用)、约定与团队习惯冲突时不协商直接覆盖。 |
| 4 | 最小知识原则与迪米特法则 | 🟢 | 迪米特法则定义:一个对象应对其他对象保持最少的了解,只与直接朋友通信。 “火车残骸”反模式: a.getB().getC().doX()——a 穿越了 B 去认识 C。修复手段:在 B 中增加委托方法 B.dox() 内部调用 C.doX(),或使用 Optional.map() 链式调用。微服务中的体现:服务间不直接依赖其他服务的内部模型,通过 API 网关或防腐层隔离。 与 Law of Demeter 的权衡:过度委托会导致中间类膨胀(Wrapper Hell),需在简洁性与隔离性间平衡。 |
| 5 | 简单性与复杂性管理 | 🟢 | 复杂性来源:本质复杂性(业务问题本身)vs 偶然复杂性(技术选型引入)。 KISS 原则:Keep It Simple, Stupid——先用最简单的方案,真正需要时再演进。 YAGNI 原则:You Ain't Gonna Need It——不要为不确定的未来需求预留扩展点。 技术选型的复杂度代价:引入 Kafka 带来运维成本,引入 CQRS 带来代码量翻倍,引入微服务带来分布式复杂性。 复杂度预算:每个系统有可承受的复杂度上限,超出后团队无法维护。新增任何技术都必须从预算中扣除。 简单性检查清单:这个方案能否用更简单的技术实现?移除它后系统还能工作吗?团队新人需要多久理解它? |
| 6 | 软件设计的哲学本质 | 🟢 | 设计是发现而非发明:好的设计不是凭空创造,而是从问题域中自然涌现。限界上下文不是设计的,是从业务中发现的。 抽象的艺术:什么是好的抽象?——隐藏实现细节,暴露意图。 List 接口抽象了数组和链表,DataSource 抽象了连接来源。分层的哲学:每一层只解决本层的问题,下层为上层提供能力,上层为下层赋予意义。OSI 七层 → TCP/IP 四层 → 架构分层,层层递进的抽象思想。 模式的本质:模式是对重复出现的问题的通用解决方案,但不是模板——每个模式都需要根据上下文调整。 权衡的必然性:软件设计没有银弹,任何选择都伴随代价。理解代价比做出选择更重要。 |
| 7 | 设计中的认知偏差与决策陷阱 | 🟢 | 权威偏差:盲目追随“最佳实践”而不评估是否适合当前场景。 幸存者偏差:只看到成功案例(如“Netflix 用微服务成功了”),忽视失败案例。 沉没成本:已经投入大量时间在某个方案上,明知不合适仍不愿放弃。 新奇偏差:追逐新技术而忽视成熟方案的稳定性。 确认偏差:只收集支持自己预设立场的信息,忽略反面证据。 决策改进:ADR(架构决策记录)强制写下决策理由;预注册反驳意见(Devil's Advocate);延迟决策(在信息更充分时决定)。 |
| 8 | 从技术到架构:工程师的思维跃迁 | 🟢 | 技术思维 vs 架构思维:技术思维关注“怎么实现”(How),架构思维关注“为什么这样”(Why)和“还能怎样”(What if)。 全局视角:单个组件的性能最优 ≠ 系统整体最优。局部缓存的 TTL 调整可能引发数据库雪崩。 时间视角:今天的选择对未来 3 年的影响是什么?如果 QPS 增长 10 倍,这个设计还能工作吗? 业务视角:技术选型最终服务于业务目标。降低 10ms 延迟能提升多少转化率?多机房容灾的 RPO/RTO 是否匹配业务 SLA? 组织视角:康威定律——系统设计最终会镜像组织沟通结构。跨团队协作的接口设计比单团队内部接口需要更稳定的契约。 思维跃迁路径:编码(实现功能)→ 设计(构建模块)→ 架构(构建系统)→ 哲学(构建可进化的体系)。 |
系列 ⑤ 工程化与交付设计(9 篇)
定位:设计不只是代码结构,还包含测试策略、版本管理、CI/CD、API 设计和架构决策记录。
| 序号 | 文章标题 | 稳定性 | 知识点 |
|---|---|---|---|
| 1 | 测试策略与测试金字塔 | 🟢 | 测试金字塔:单元测试(70%)→集成测试(20%)→契约测试(8%)→E2E 测试(2%)。 单元测试:Mockito + AssertJ,Mock 外部依赖,测试业务逻辑。 集成测试:Testcontainers 启动真实 MySQL/Redis/Kafka 容器, @DynamicPropertySource 动态注入。契约测试:Spring Cloud Contract,消费者定义契约(Groovy DSL)→ 生成 Stub JAR → 生产者验证。 E2E 测试:核心业务链路端到端验证,数量少但覆盖关键路径。 测试反模式:测试污染(共享状态未清理)、慢测试(未使用 Testcontainers 复用容器)、冰激凌甜筒反金字塔(大量 E2E 少量单元)。 |
| 2 | API 设计与演化 | 🟢 | RESTful API 设计规范:资源命名(名词复数 /orders)、HTTP 方法语义(GET/POST/PUT/DELETE)、状态码精确使用。版本管理:URL 版本( /v1/orders)、Header 版本(Accept: application/vnd.api+json;version=1)、Query 版本(?version=1)。向后兼容规则:新增字段兼容、新增接口兼容、新增错误码兼容。不兼容变更:删除字段、修改字段类型、修改接口语义。 OpenAPI 3.0:Swagger/Swagger UI 自动生成文档, springdoc-openapi 集成。gRPC 接口演进:Protobuf 字段编号不可变,新增字段用新编号,保留废弃字段( reserved)。GraphQL Schema 演进: @deprecated 标记废弃字段,新字段直接添加不影响现有查询。 |
| 3 | Git 工作流与分支策略 | 🟢 | Git Flow:main + develop + feature/* + release/* + hotfix/*,适合有固定发布周期的项目。GitHub Flow: main + feature/*,PR 合并即部署,适合持续部署项目。Trunk-Based Development:所有开发者在 main 分支上小批量频繁提交,Feature Flag 控制未完成功能。分支策略选型:发布频率(周/月 → Git Flow,日/时 → GitHub Flow/TBD)。 Commit 规范:Conventional Commits( feat:/fix:/docs:/refactor:),关联 Issue 编号。Code Review:Review 检查项(设计是否合理/测试是否覆盖/安全是否有风险/性能是否有隐患)。 |
| 4 | CI/CD 流水线设计 | 🟢 | 持续集成(CI):提交触发 → 编译 → 单元测试 → 代码扫描(SonarQube)→ 镜像构建 → 推送镜像仓库。 持续交付(CD):部署到测试环境 → 集成测试 → 部署到预发布环境 → 人工审批 → 部署到生产。 GitOps 部署:ArgoCD 监听 Git 仓库 → 自动同步 K8s 集群状态 → 自动回滚。 金丝雀发布:Istio VirtualService weight: 80/20 → 验证新版本 → 全量切换。蓝绿部署:两套完整环境, Service Selector 一键切换。自动化回滚: Deployment revisionHistoryLimit + rollout undo。 |
| 5 | 容器化与镜像构建最佳实践 | 🟡 | Dockerfile 优化:多阶段构建(maven:3.8 构建 + openjdk:8 运行)、COPY --chown 非 root 运行、.dockerignore 排除无用文件。镜像分层:将变化频率低的依赖层( COPY pom.xml + RUN mvn dependency:resolve)放在变化频率高的源码层(COPY src)之前。Jib:无需 Dockerfile,Maven/Gradle 插件直接构建镜像,自动分层。 镜像安全: docker scan 扫描漏洞、使用 Distroless 基础镜像、不在镜像中存密钥。JVM 容器感知: -XX:+UseContainerSupport、-XX:MaxRAMPercentage=75.0。 |
| 6 | 技术文档与架构决策记录(ADR) | 🟢 | ADR 模板:标题(ADR-001: 选择 Kafka 作为消息队列)、状态(提议/已采纳/已废弃/已取代)、上下文(为什么需要做决策)、决策(选择了什么)、后果(正面/负面/中性)。 ADR 的价值:让架构决策可追溯、可复审、可传承。新人可以通过 ADR 理解系统为什么这样设计。 文档即代码:Markdown 存于 Git,PR 评审,与代码同步版本。 C4 模型:Context(系统上下文图)→ Container(容器图)→ Component(组件图)→ Code(类图),逐级放大。 Arc42:架构文档模板,覆盖需求/约束/上下文/解决方案/运行时/部署/横切概念/风险。 |
| 7 | 特性开关(Feature Flag)与渐进交付 | 🟡 | Feature Toggle 类型:发布开关(控制未完成功能是否可见)、实验开关(A/B 测试)、运维开关(紧急关闭高负载功能)、权限开关(按用户级别开放功能)。 实现方式:配置中心(Nacos/Apollo)动态开关 + @ConditionalOnProperty 条件装配。Trunk-Based Development 支撑:代码合入 main 但功能不启用,通过 Flag 控制发布。 技术债管理:Flag 有生命周期,功能稳定后及时清除 Flag 代码。 开源方案:FF4J、Unleash、LaunchDarkly。 |
| 8 | 可观测性设计:从代码到生产的全链路可追踪 | 🟡 | 日志规范:MDC 注入 TraceId,统一日志格式(时间 + 级别 + TraceId + 类名 + 消息),logback-spring.xml 配置。指标规范:Micrometer 统一指标门面, Timer(耗时)、Counter(计数)、Gauge(瞬时值)。业务指标命名规范:business.orders.created。链路追踪规范:TraceId 全链路传播(Gateway Filter → Feign Interceptor → MQ Header → ThreadPool TaskDecorator)。 SLO 定义:99.9% 请求 < 200ms,Error Budget = (1 - SLO) × 总请求数。 告警分级:P0(立即响应,Error Budget 燃烧 > 10%/h)、P1(紧急处理,> 2%/h)、P2(关注,延迟趋势上升)。 |
| 9 | 软件交付的工程化成熟度模型 | 🟢 | 成熟度等级: L1 初始级:手动构建、手动部署、无自动化测试。 L2 可重复级:自动化构建、手动部署、单元测试。 L3 已定义级:CI/CD 流水线、集成测试、代码审查。 L4 已管理级:GitOps 部署、金丝雀发布、自动化回滚、SLI/SLO 监控。 L5 优化级:混沌工程验证、AI 辅助代码审查、自愈系统。 评估维度:构建自动化、测试自动化、部署自动化、监控自动化、安全自动化。 提升路径:识别当前等级 → 制定下一等级目标 → 选择最关键的一个维度提升 → 度量 → 复盘。 |
| 10 | 技术债管理与持续重构 | 🟢 | 技术债四象限分类(有意/无意×鲁莽/谨慎)、六大识别方法(SonarQube技术债比率、JaCoCo覆盖率缺口、ADR过期复审、特性开关过期审计、Trivy/Dependabot依赖库漏洞与过期、契约测试/ArchUnit文档滞后度)、偿还策略(季度评审制度、Sprint投入15%-25%、童子军规则、Branch by Abstraction渐进重构、Strangler Fig绞杀者模式)、制度化预防(ADR记录有意债务、PR模板检查项、开关创建强制过期、Dependabot/Renovate自动更新)。 |