2025年2月13日·阅读约1分钟

存储过程与可视化工作流:逻辑应该放在哪里?

存储过程 vs 可视化工作流:实用方法帮你决定哪些业务逻辑该放在数据库、拖放工作流,或自定义代码中。

存储过程与可视化工作流:逻辑应该放在哪里?

这个决策真正意味着什么

业务逻辑是一组规则,用来决定什么被允许、接下来会发生什么,以及当真实的人使用系统时系统应该做什么。它不是数据本身,而是行为:谁可以做什么、在什么条件下以及会有哪些副作用。

因此“存储过程 vs 可视化工作流”的争论实际上是关于这些规则应该放在哪里,以便它们易于修改、不易被破坏,并且对掌管流程的人清晰可见。

大多数团队最终会在三个地方存放逻辑:

  • 数据库中(存储过程、触发器、约束): 规则靠近数据运行。这通常速度快且一致,但非数据库专家修改起来更困难。
  • 可视化工作流中(拖放式流程构建器): 规则以步骤和决策的形式表达,通常更容易阅读、审查并在流程变化时调整。
  • 自定义代码中(服务、应用、脚本): 规则用编程语言编写。灵活性最大,但更改通常需要更多工程纪律和测试。

这个选择影响日常交付速度和长期维护。如果把逻辑放错地方,你会得到慢速交付(每次更改都需找懂数据库的那个人)、更多错误(规则在多个地方重复)、以及痛苦的调试(没人知道记录为何被拒绝)。

大多数系统包含几类常见的业务逻辑:校验(必填字段、允许范围)、审批、定价与折扣、通知,以及访问规则。

一个实用的思路是:数据库擅长保护数据完整性,可视化工作流擅长表达业务流程,而自定义代码适合那些很难或无法干净建模的特殊或复杂规则。像 AppMaster 这样的平台位于中间:你可以建模数据,然后用可读的可视化逻辑实现流程,而不会把规则散落到多个应用中。

判定标准:你在优化什么

这不是品味问题,而是你试图保护什么:数据、改动系统的人,以及变更速度。

最重要的结果

列出项目的首要目标。大多数团队在以下几点之间权衡:

  • 正确性: 规则在任何时候、任何负载下都必须以相同方式执行。
  • 清晰性: 新来的人应该能不用猜测就明白发生了什么。
  • 速度: 在必要时,逻辑必须快速并靠近数据运行。
  • 可审计性: 你需要证明谁什么时候做了更改,以及何时执行。
  • 变更频率: 你预计需求是按周而不是按年变化。

你很少能把这五项全部最大化。把逻辑靠近数据库可以提升正确性和速度,但可能降低不熟悉 SQL 的人的清晰度。

谁会更改逻辑(以及频率)

诚实地判断谁会负责日常更改。一个需要运维每周调整的规则不应该要求 DBA 来部署存储过程。与此同时,影响资金的规则也不应在未经审查的情况下可随意编辑。

用变更摩擦来思考。如果需求经常变化,你需要一个安全、可见且快速上线的位置。可视化工作流工具(例如 AppMaster 的 Business Process Editor)在业务负责人和工程师需要共同协作而不去编辑底层代码时很有效。如果变更罕见且规则很关键,较高的摩擦可以接受。

快速检验所有权的一些问题:

  • 半夜 2 点崩溃时会通知谁?
  • 需要多快修补一个规则?
  • 更改需要审批或纸质记录吗?
  • 多个应用会依赖同一规则吗?
  • 逻辑主要是数据处理,还是业务决策?

尽早考虑约束。有些行业要求严格的访问控制、职务分离或详细日志。还要考虑数据访问限制:如果只有某些服务应看到某些字段,这会影响逻辑能否安全地运行的位置。

何时把逻辑放入存储过程

存储过程是在数据库内部运行的逻辑块。在 PostgreSQL 中,它们用 SQL(有时用 PL/pgSQL 等数据库语言)编写。与其让应用拉出行、循环处理再推回改变,不如让数据库在数据所在之处完成工作。

一个简单规则是:当主要工作是保护数据并进行批量数据操作,而不是协调人员或系统时,就把逻辑放在数据库。

存储过程的强项

存储过程适用于必须在所有应用或集成触达时始终为真的规则。把它们想象成阻止错误数据进入系统的护栏。

它们也擅长基于集合的更新——一条语句可以安全快速地更新成千上万行。纯粹关于数据的简单计算,比如汇总或应用固定折扣公式,也可以放在这里,这样能减少往返并保持结果一致。

例子:当订单标记为 paid 时,一个过程可以原子性地更新订单状态、减少库存并写一条审计记录。如果任何步骤失败,整个更改回滚。

存储过程变得危险的情况

存储过程比应用代码更难测试和版本化,尤其是在团队不把数据库变更当作正式发布时。逻辑也可能变成对应用来说“隐藏”的,直到后来才发现耦合问题。

调试也更难。错误可能以数据库消息的形式出现,缺少关于用户操作的上下文。新成员可能难以上手,因为规则分散在应用和数据库之间,数据库逻辑在入职时容易被忽略。

如果你使用可视化工具处理大部分逻辑,建议把存储过程保留给那些小且稳定、必须靠近数据运行的核心逻辑。把其他东西放在更容易阅读、追踪和修改的地方。

何时把逻辑放在可视化工作流中

可视化工作流是按步骤的流程逻辑,可以像清单一样阅读:当发生某事时,按顺序执行这些动作,并在明显的决策点分岔。它们更少涉及大量计算,而是关注工作如何在人、系统和时间之间流转。

当你在意共享理解时,它们非常有效。如果产品、运维、支持与工程都需要就一个流程达成一致,可视化工作流能让规则变得可见。可见性常常是“系统坏了”与“流程上周变了”之间的区别。

它们通常适合审批与审核、路由、通知与提醒、定时步骤(等待 2 天然后升级)以及集成(调用 Stripe、发送消息、更新 CRM)。

例子:客户申请退款。工作流检查订单时间,若超过阈值则路由给经理,批准后通知财务并向客户发送更新。每一步都容易指认并用普通语言讨论,这帮助相关方签署并让新成员理解“为什么”这样做。

像 AppMaster 的 Business Process Editor 这样的工具专为此类逻辑设计:你可以看到路径、条件和副作用(消息、API 调用、状态更改),而无需深入数据库脚本。

为了防止工作流变成一团乱麻,保持它们简短并可读。每个工作流只给出一个结果,给步骤和分支清晰命名,限制深度嵌套的决策,并记录关键选择以便日后回答“为什么会这样?”

当工作流开始进行复杂的数据计算或涉及多表时,通常是信号,表明应把部分逻辑移动到别处。可视化工作流最适合作为指挥者,而非整个乐团。

何时自定义代码是正确的工具

减少 SQL 变更摩擦
把易变的规则从存储过程移出,放到团队可以审阅的地方。
开始构建

自定义代码是你以软件形式编写和维护的逻辑:函数、服务或小型库,作为应用的一部分运行。这是最灵活的选项,因此应有目的地使用,而非默认选择。

当逻辑很难用数据库过程或拖放式工作流安全地表达时,自定义代码就派上用场。如果你发现自己在强行用工具适配问题,代码通常更清晰也更容易保持正确。

明显应选择代码的信号:

  • 问题是算法型的(定价规则、路线规划、评分、匹配、欺诈检测),有许多边界情况。
  • 需要不寻常的集成(对方 API 验证异常、复杂重试、严格的幂等性规则)。
  • 性能敏感(高吞吐量处理、重计算、精细缓存)且你需要精确控制。
  • 必须在多个地方共享同一逻辑(Web、移动、批处理)而不复制。
  • 需要围绕逻辑做强自动化测试,因为错误代价高。

代码也能让所有权更清晰。一个团队可以负责审查更改、保持测试通过并记录行为。这总比“它存在于三个工作流里,没人确定哪一个先运行”要好。

例子:一个退款决策引擎会考虑订单历史、欺诈信号、运输状态和时间窗口。你可以把审批步骤保留在可视化工作流中,但决策本身通常更适合以代码实现,配备单元测试和版本控制。

成本是真实存在的。自定义代码需要工程时间、评审和持续维护。更改可能比编辑工作流花更长时间,而且需要发布流程。AppMaster 可以通过用可视化逻辑和模块覆盖常见部分来减少你需要编写的代码,同时仍允许团队在必要时导出源代码并扩展。

一个可重复使用的逐步框架

把流程变成工作流
将审批、路由和提醒构建为可读的可视化业务流程。
创建工作流

团队常常跳过最有用的部分:先把规则写清楚,然后选择一个与规则行为相匹配的归属位置。

每当出现新逻辑时使用此框架:

  • 把规则写成一句话,然后打标签。 如果它关乎有效数据(约束、唯一性、必须匹配的总计),就是数据规则。如果它关乎步骤和交接(审批、等待、通知),就是流程规则。如果它是大量数学或复杂转换,就是计算规则。
  • 问谁会编辑它以及频率。 如果非技术人员必须每周更改它,就不要把它埋在 SQL 或代码发布中。如果它很少改动且必须每次都被强制执行,数据库是更强的候选地。
  • 检查失败影响和你需要的审计轨迹。 如果错误会造成金钱损失、合规问题或难以修复的数据,优先选择具备清晰日志和严格控制的地方。
  • 选择位置并定义边界。 明确输入、输出与错误。例如:“给定 order_id,返回 allowed_refund_amount 或一个明确的原因代码。” 这个边界防止逻辑无处不在地泄漏。
  • 挑一个层保持精简。 决定哪个层应主要“保持哑化”,以免重复规则。常见选择:保持数据库精简(仅数据完整性)、保持工作流精简(仅编排)、或保持代码精简(仅胶水逻辑)。

经验法则:把数据规则放得最靠近数据,把流程规则放在工作流工具里,把计算规则放在最容易测试和版本化的地方。

如果你使用像 AppMaster 这样的平台,可以把数据库作为护栏(表、关系、基础约束),用可视化 Business Process Editor 处理“谁接下来做什么”的部分,同时把自定义代码留给极少数真正需要的场景。

导致系统混乱的常见错误

混乱的系统很少源于一次糟糕选择。它们发生在逻辑被分散、隐藏或复制,直到没人确切知道系统实际上做了什么。

重复是经典问题:同一规则存在于两个地方,但随时间漂移。例如:数据库拒绝超过 $500 的退款,除非有审批记录,但工作流仍然按另一个限额把退款请求发给支付系统。两者“都能工作”,直到遇到第一个真实边界情况,支持就会面对神秘的错误。

隐藏规则也是问题。触发器、存储过程和数据库中的临时修复对构建 UI 或工作流的人可能是不可见的。如果规则没有在依赖它的工作流或 API 附近记录,更改就变成猜测,测试变成试错。

过度臃肿的工作流则是另一类问题。一个包含数十个分支的长链拖放流程会变得脆弱且无人愿意修改。在像 AppMaster 这样的工具中,快速添加模块很容易,但今天的速度可能会在没有明确边界的情况下变成未来的困惑。

两种相反的“过度”错误会带来长期痛苦:

  • 数据库里太多: 每次策略变更都变成迁移项目,小的产品调整要等数据库发布。
  • 应用代码里太多: 基本数据规则(必填、允许的状态、唯一约束)被忘记,坏数据通过导入、管理员工具或未来的集成进入系统。

一个简单习惯能防止大多数问题:把每条规则放在一个主要归属地,并写明它在哪里及原因。如果你无法在 10 秒钟内回答“这是在哪里强制的?”,你已经在为混乱付费。

快速检查:两分钟内决定

构建运维就绪应用
围绕清晰的工作流和受保护的数据规则构建面向运维的应用和管理面板。
创建工具

你在选择一个能让规则保持正确、可见且易变更的位置。

先问一个问题:这条规则是关于数据正确性吗,必须不能被绕过?如果是,把它尽量靠近数据库。若是关于步骤、审批或通知,把它放在工作流层。

一个快速清单:

  • 它是在强制数据正确性吗(防止负库存、阻止重复的“active”记录)?倾向数据库。
  • 它涉及多张表且需要基于集合的更新吗?倾向数据库。
  • 你需要谁在什么时候批准了什么的明文可读审计轨迹吗?倾向工作流。
  • 非工程人员需要每周或每月更改它吗?倾向工作流。
  • 它会调用外部服务(支付、消息、AI)吗?倾向应用或工作流,而不是数据库。

现在考虑失败。一条会失败的规则应以人类可恢复的方式失败。

如果你需要安全重试和清晰的错误信息,倾向于使用可以跟踪状态并逐步处理异常的编排层。可视化工作流通常使这更容易,因为每一步都是显式的并且可以记录。

一个实用的决胜法则:

  • 如果系统必须在未来有人写新应用时仍保持正确,在数据库强制执行。
  • 如果流程需要被运维团队阅读和审查,放在可视化工作流。
  • 如果涉及复杂集成、重计算或特殊库,使用自定义代码。

例子:“退款金额不能超过原支付”是正确性问题,应在数据附近强制。“超过 $500 的退款需要经理审批然后发送 Telegram 消息”是工作流。在 AppMaster 中,这个审批链自然适合 Business Process Editor,而严格约束保留在数据模型中。

示例场景:带审批的退款

选择你的部署方式
部署到 AppMaster Cloud 或你的 AWS、Azure、Google Cloud。
立即部署

一个常见的真实案例是:退款金额超过某值需要经理审批,并且要有通知与清晰的审计记录。

首先定义单一事实来源:一个 Refund 记录,包含金额和清晰的状态字段(例如:requestedneeds_approvalapprovedrejectedprocessingpaidfailed)。系统的每个部分都应读写这些相同字段,而不是在不同地方维护并行状态。

什么属于数据库

把保护资金和数据一致性的规则放得最靠近数据。

使用约束(有时结合存储过程)来确保不能退款超过已捕获的支付金额、不能对已全额退款的订单再退款、不能为同一订单创建两个活动退款请求、或在退款批准后更改关键金额。

同时把原子更新放在这里:当创建退款请求时,在一个事务中写 Refund 行并更新 Order 总额。如果任一写入失败,则不应有部分更新。

什么最适合放在可视化工作流

审批步骤是流程,不是数据保护。可视化工作流是路由请求到合适经理、等待决策、更新状态、发送提醒并通知申请人的好归属地。

一个简单流程可能是:创建请求 -> 如果金额超限,设状态为 needs_approval -> 通知经理 -> 如果批准,设为 approved -> 通知申请人 -> 若 24 小时无回应,发送提醒。

在像 AppMaster 这样的工具里,这可以映射为一个对状态变更做出反应并触发邮件、短信或 Telegram 消息的业务流程。

什么应放在自定义代码中

支付提供商有不规则的边界情形,不总能整齐地放进规则或拖放步骤。把供应商特定逻辑放在自定义代码中,比如含费用的部分退款或多次捕获支付、Webhook 对账(提供商说“paid”但你的应用显示“processing”)以及在提供商超时情况下的幂等与重试处理。

关键是自定义代码不应发明自己的状态。它读取 Refund 记录,执行支付提供商操作,然后写回下一个状态和确认的金额,这样数据库仍然是所有人信任的账本。

接下来的步骤:让决策长期有效

好的决策只有在六个月后仍然有效才有价值。目标是让关于“逻辑应该放在哪里”的选择易于查看、易于测试并且难以被意外绕过。

创建一个简单的逻辑地图:列出关键规则和你为每条规则选择的归属地。保持简短并在规则变更时更新。包括规则名、它在哪里(数据库、工作流、自定义代码)、为什么(一句话)、它读写什么,以及谁批准更改。

把边界写成不可妥协的条目,以在以后有人添加功能时保护系统。一个有用的格式是:“数据库保证 X”和“工作流强制执行 Y。”例如,数据库保证退款记录不能在没有订单的情况下存在,而工作流强制执行超过 $500 的退款需要经理审批。

在更改任何东西之前计划测试。你不需要一个庞大的测试计划,只需在规则更改时每次重跑的几个用例:

  • 正常路径(预期输入、预期结果)
  • 失败路径(缺失数据、无效状态、重复请求)
  • 并发(两个人同时触发相同行为)
  • 安全(用户试图跳过步骤或直接调用端点)

也要设定所有权和评审规则。决定谁可以编辑存储过程、谁可以编辑工作流,以及什么需要同伴评审。许多系统要么因此保持健康,要么因此滑向“没人知道它为何能工作”的状态。

如果你想要拖放式工作流而不放弃真实的后端结构,像 AppMaster(appmaster.io) 这样的平台注册为实用的折中方案:建模你的数据,在 Business Process Editor 中表达业务流程,并在需求变化时重新生成与部署。

选择一条高影响的规则,映射它,添加边界,并写三个测试用例。这个简单习惯可以防止大多数逻辑蔓延问题。

常见问题

What’s the simplest way to decide where business logic should live?

把规则放在能始终正确、可见并且易于变更的地方。将数据完整性规则靠近数据库保留,将逐步的业务流程放在工作流里,当规则过于复杂或需要严格测试时使用代码。

When should I put logic in stored procedures?

将存储过程用于数据保护和批量数据处理:在所有应用和集成触达之前强制不变量、执行基于集合的更新,以及运行必须始终一致的原子事务。保持它们小且稳定,避免成为隐藏的“惊喜逻辑”。

When are visual workflows the better choice?

可视化工作流最适合流程规则:审批、路由、通知、提醒、等待步骤以及按人可读顺序执行的集成。它们适合让非工程人员或跨职能团队审阅和调整工作如何流转。

What are the signs that a rule should be custom code?

算法性或不寻常的逻辑选择自定义代码:复杂定价、欺诈判断、匹配/评分、高级重试与幂等性,或需要特殊库和精细错误处理的集成。代码也适合当你需要强自动化测试来防止代价高昂的错误时。

How do I handle rules that affect money, like refunds or discounts?

把不可妥协的资金与一致性规则放在数据库里,审批与沟通步骤放在工作流里。如果混在一起,要么每次策略变更都变成迁移发布,要么有人绕过 UI 导致坏数据进入系统。

How do I avoid duplicating rules across the database, workflows, and code?

把每条规则放在一个主要归属位置,其他层调用它而不是重新实现。重复实现会导致“UI 能通过但数据库 拒绝”的错误,当限制、状态或验证逐步偏离时问题就出现了。

How do I stop visual workflows from turning into spaghetti?

保持工作流小而专注:一个明确结果、简单分支、可读的步骤名称。当工作流开始做大量数据计算或操作多张表时,把计算拆到代码或把完整性相关部分移到数据库。

Why do stored procedures feel hard to debug and maintain?

把数据库逻辑当作真正的软件变更:版本化、评审、测试,并记录在哪儿强制执行。同时确保错误在工作流或 API 层返回可操作的信息,让人能理解失败原因并采取补救。

How should compliance or audit requirements change the decision?

在数据层强制访问和完整性约束,然后在工作流层保留决策轨迹(谁在什么时候批准了什么)。这种分离让审计更容易,你既能证明数据规则被执行,也能证明决策过程被记录。

How does AppMaster fit into the stored procedures vs workflow decision?

AppMaster 是在结构化数据和可读流程逻辑之间的实用折中。你可以建模 PostgreSQL 支持的数据,并在可视化 Business Process Editor 中表达业务流程,同时为核心保留存储过程,为特殊情况保留代码扩展。

容易上手
创造一些 惊人的东西

使用免费计划试用 AppMaster。
准备就绪后,您可以选择合适的订阅。

开始吧