架构模式
此页面为架构问题提供全面的模式指导,包括功能单元、问题分离、状态管理、API 管理和消息传递。这些模式通过对服务边界、数据访问模式和组件责任的审慎设计决策来塑造长期的解决方案成功。
模式
| 何处查看 | 好样的 |
|---|---|
| Apex 类 | ✅ 服务类遵循单一责任原则,名称明确表示目的(AccountService、OrderProcessor、InventoryManager)。每个服务类关注一个域或业务功能。服务类中的方法在 20 行下具有单一、集中的责任。 |
| 触发器 | ✅ 触发器委派给处理程序类,而不是直接包含业务逻辑。触发器处理程序模式与上下文中明确的方法名称一致使用 (handleBeforeInsert、 handleAfterUpdate)。处理器类按触发事件组织逻辑,每个方法具有一个责任。 |
| Lightning Web组件 | ✅ 组件遵循单一责任原则,配置界面清晰。每个 LWC 关注一个 UI 问题(数据显示、用户输入、导航)。为组合设计的组件,而不是单片实施。 |
| 服务层 | ✅ 服务类封装了独立于入口点的业务逻辑(触发器、API、流、批次)。同一个服务类处理多个调用上下文,没有重复。服务层将业务规则与演示和数据访问问题分开。 |
| 可重用组件 | ✅ 设计用于跨多个项目和团队重复使用的组件。使用自定义元数据类型的配置驱动的行为支持无需代码部署的行为更改。可调用操作将 Apex 逻辑公开为可用于流和外部编排的声明性构建块。 |
反模式
| 何处查看 | 什么不好的样子 |
|---|---|
| 上帝类 | 避免在一个类中累积过多的责任。将大类(>500 行)拆分为具有单一责任的重点类。当类处理多个不相关的问题时,重新组织它们(OrderProcessor 不应该也处理电子邮件发送和报告)。 |
| 混合关注 | 避免在单个类中混合触发器逻辑、业务规则和数据访问。在控制器中将演示逻辑与业务逻辑分开。将集成问题与核心域逻辑分开。 |
| 触发器中的触发器逻辑 | 避免直接在触发器文件中嵌入业务逻辑。请勿将 300 多行触发器与嵌套条件一起使用。始终通过触发器上下文委派给具有明确方法组织的处理程序类。 |
模式
| 何处查看 | 好样的 |
|---|---|
| 业务逻辑 | ✅ 业务规则集中在服务类中,而不是分散在触发器、控制器和批处理类中。无论记录如何进入系统,域类都一致地封装了记录级行为(验证、默认值、派生值)。逻辑通过服务层重复使用,而不是在入口点之间重复。 |
| 数据访问 | ✅ 在存储库或选择器模式类后抽象的数据访问。SOQL 查询集中在选择器类(AccountSelector、OpportunitySelector)中,确保字段列表和 WHERE 子句的一致性。存储库模式支持使用模拟数据源进行测试,而无需更改业务逻辑。 |
| 界面合同 | ✅ 组件通过显式接口进行通信,而不是实施细节。Apex 接口定义了图层之间的合同。自定义元数据配置定义了行为边界。平台事件提供生产者和消费者之间的消息传递合同。 |
| 模块边界 | ✅ 边界上下文为数据模型和业务规则定义了明确的所有权边界。每个模块都有自己的数据、自动化和业务逻辑。模块通过定义的 API 进行交互,而不是直接共享数据库对象。文档清楚地标识了哪个团队拥有哪些对象和服务。 |
| 依赖流 | ✅ 依赖性单向流动(演示 → 业务 → 数据)。核心业务逻辑不依赖于任何外部因素,从而实现独立演进。基础设施问题(日志、缓存、外部 API)取决于通过接口的业务逻辑,而不是相反。 |
反模式
| 何处查看 | 什么不好的样子 |
|---|---|
| 逻辑复制 | 避免在触发器、API 端点和批处理类之间重复业务逻辑。集中到服务层,并在入口点之间重复使用。每当相同业务规则出现在多个类中时,提取到共享服务。 |
| 分散的数据访问 | 避免 SOQL 查询分散在字段列表和 WHERE 子句不一致的触发器、控制器和批处理类中。在选择器类中集中查询,确保模式一致,并在一个位置启用 LDV 优化。 |
| 触发器中的业务逻辑 | 避免验证规则、字段计算和工作流编排直接嵌入触发器代码。移动到服务类或域类。保持触发器精简,仅关注委派给适当的处理程序。 |
| 控制器中的业务逻辑 | 避免 Aura/LWC 控制器方法中的复杂计算、验证或数据操纵。控制器应编排对服务层的调用,而不是直接实施业务规则。 |
| 循环依赖性 | 避免带有循环依赖性的软件包或类,其中 A 依赖于 B,B 依赖于 A。通过将共享的关注提取到单独的模块中,颠倒依赖方向,或使用事件驱动的通信来打破耦合来解决。 |
模式
| 何处查看 | 好样的 |
|---|---|
| 平台缓存(组织分区) | ✅ 组织分区中缓存的频繁访问参考数据,包括自定义元数据查找、选项列表值、配置设置和昂贵操作的计算结果。根据数据波动性配置的默认 TTL(每月更改参考数据的小时数,频繁更新配置的分钟数)。缓存密钥策略可防止不同数据类型之间的冲突。 |
| 平台缓存(会话分区) | ✅ 存储在会话缓存中的用户特定首选项、计算个性化数据和会话范围状态。会话缓存不用于应在用户之间共享的数据。缓存无效策略会适当处理用户首选项更新。 |
| Lightning数据服务 | ✅ LDS 为 Lightning Web 组件提供自动客户端记录缓存。标准 CRUD 操作使用 LDS,而不是自定义 Apex 控制器。LDS 消除了冗余的服务器往返,并提供乐观的 UI 更新。组件利用跨页面的共享 LDS 缓存。 |
| 自定义元数据类型 | ✅ 配置和行为规则存储在自定义元数据类型中,而不是硬编码在类中。可通过更改集或源驱动的开发跨环境部署的自定义元数据。对自定义元数据的更改不需要完整的部署周期。在平台缓存中缓存自定义元数据查询以提高性能。 |
反模式
| 何处查看 | 什么不好的样子 |
|---|---|
| 循环中的查询 | 避免在迭代循环中执行 SOQL。在循环外部的单个 SOQL 语句中查询所有需要的记录。按父级 ID 将结果组织到地图中,以便在迭代期间查找。这是最常见的 Salesforce 反模式。 |
| 重复查询 | 避免每次事务多次查询相同的自定义元数据、自定义设置或引用数据。查询一次,缓存在平台缓存或事务静态变量中,跨事务重复使用。 |
| 缺少缓存策略 | 避免在没有缓存的情况下重复查询频繁访问的参考数据。为自定义元数据、配置和计算结果实施平台缓存。根据数据波动性定义适当的 TTL。 |
| 无无效缓存 | 避免缓存数据而不考虑无效策略。定义适合更新频率的缓存 TTL。如果仅使用 TTL 是不够的,则在源数据更改时实施手动缓存清除。 |
| 非受管会话状态 | 避免在没有验证的情况下假设会话状态在页面导航中持续存在。Lightning 组件应处理页面加载时的状态刷新。使用 Lightning 数据服务进行自动状态同步。 |
模式
| 何处查看 | 好样的 |
|---|---|
| 解决方案架构规划 | ✅ 在重大构建投资之前进行架构规划,包括需求分析(功能和非功能)、预期数据量的调控器限制分析、适合需求的模式选择以及定义主要组件和界面的组件设计。 |
| 设计模式选择 | ✅ 经验证的 Salesforce 设计模式始终适用:用于业务逻辑重用的服务层模式、用于数据访问抽象的存储库/选择器模式、用于可交换算法的策略模式、用于记录级行为的域模式、用于一致触发器组织的触发器处理程序模式。 |
| 架构决策记录 | ✅ 版本控制中存储的 ADR 记录了重要的架构决策。ADR 捕获上下文(业务驱动因素、技术约束)、决策(选择的内容)、考虑的替代方案(为什么其他人拒绝)和后果(权衡、技术债务、重新访问触发器)。 |
| 构建与购买评估 | ✅ AppExchange 评估在自定义开发决策之前使用总拥有成本分析。评估标准包括战略价值(竞争优势与商品)、TCO 比较(构建工作量、维护、升级成本)、集成复杂性和退出成本(如果解决方案被证明是不够的)。 |
| 州长限制分析 | ✅ 架构规划确定了给定预期数据量和事务模式时,哪个调控器限制最约束设计。在峰值条件下,设计为消耗小于任何单个调控器限制的 80% 的事务。为增长、未来功能和意外使用模式构建的利润。 |
| 风险评估 | ✅ 为推进平台边界的架构方法识别的技术风险。为每个重大风险定义的缓解策略。原型或概念验证工作会在完全构建承诺之前验证高风险技术方法的假设。 |
反模式
| 何处查看 | 什么不好的样子 |
|---|---|
| 无计划 | 避免在没有分析数据量、调控器限制影响或模式选择的情况下开始构建。架构规划研讨会应确定关键约束,选择模式,并在构建开始前根据调控器限制进行验证。 |
| 未记录的决定 | 避免在会议中做出架构决策,而不抓住上下文、理由、替代方案和后果。使用存储在版本控制中的架构决策记录为未来的团队成员保留决策上下文。 |
| 无构建与购买分析 | 避免在没有 AppExchange 评估的情况下构建自定义解决方案。在自定义开发前,评估前 3-5 个相关软件包。比较 TCO,包括实施工作量、维护、升级成本和退出成本。 |
| 工程不足 | 避免仅为当前数据量设计,而不考虑增长预测。预测 2-3 年内的数据增长。设计针对 5-10 倍当前卷进行选择性验证的查询模式。为增长构建架构利润。 |
模式
| 何处查看 | 好样的 |
|---|---|
| 第二代受管软件包 (2GP) | ✅ 2GP,用于需要命名空间隔离、AppExchange 分发和 IP 保护的新受管软件包。带有模块化应用程序开发的源驱动的开发工作流。明确管理的软件包依赖性。使用语义版本发布的版本。 |
| 解锁的软件包 | ✅ 解锁软件包,用于需要模块化且没有命名空间约束的内部企业应用程序。没有依赖于组织的工件的软件包的独立部署。为正确部署顺序跟踪软件包依赖性。为内部软件包定义的版本策略。 |
| 模块边界 | ✅ 为每个软件包定义明确的所有权边界。每个软件包都有自己的数据模型、业务规则和自动化。软件包通过定义的界面进行交互,而不是直接的对象访问。文档标识软件包所有权和软件包间合同。 |