软件 规则引擎_如何设计软件规则引擎

软件 规则引擎

想象一下这种情况 (Imagine this scenario)

You’re a busy engineer working in a company with too much to build and too few resources to do it. Departments constantly ask for changes only an engineer can make. Marketing continuously asks for email on-boarding changes. Operations wants more and more batch tooling. Sales wants to test new pricing structures every other week. You and your team are overwhelmed with requests.

您是一个忙碌的工程师,在一家公司里工作,要建立的东西太多,而要做的东西却很少。 各个部门不断要求只有工程师才能进行的更改。 市场营销不断要求更改电子邮件注册。 运营需要越来越多的批处理工具。 销售人员希望每两周测试一次新的定价结构。 您和您的团队不知所措。

What are your options?

您有什么选择?

Stop progress on planned work to make these requested changes? A constant stream of interruptions is terrible way to get any real work done, and who knows if these asks are even worth interrupting the real work for.

停止计划中的工作以进行所需的更改吗? 持续不断的打扰是完成任何实际工作的可怕方式,谁知道这些要求是否值得中断真正的工作。

Ignore it? You’ll make progress on your planned work, but you’ll also have a bunch of external stakeholders now suddenly very angry at your department. Besides, isn’t technology supposed to help the business? Is it really helpful to have the business miss out on potentially significant opportunities just because you couldn’t spare an hour or two?

忽略它? 您将在计划的工作上取得进展,但是您现在还会有许多外部利益相关者突然对您的部门感到愤怒。 此外,技术不应该对业务有所帮助吗? 仅仅因为您不能花一两个小时而错过潜在的重要机会,这真的有帮助吗?

Triage the asks around a planned schedule? Planned interruptions are better than unplanned ones, but you’re still potentially limiting the progress of other departments and forcing them to work around your schedule — not quite as collaborative as one could be.

根据计划时间表对问题进行分类? 计划中的中断要比计划中的中断要好,但是您仍然有可能限制其他部门的进度,并迫使他们按自己的时间表工作-协作程度可能不尽人意。

Imagine if there was a way to prevent these requirements from every reaching you, and to give the other departments tools to pursue these opportunities without your involvement. They’d be able to make internal pivots without having to rely on engineering to perform the work.

试想一下,是否有一种方法可以阻止这些要求每一项都达到您的要求,并提供其他部门的工具来在您不参与的情况下抓住这些机会。 他们将能够进行内部枢纽,而不必依赖工程来执行工作。

If such a solution existed, you’d save a lot of time and be able to focus on more important problems.

如果存在这样的解决方案,您将节省大量时间,并能够专注于更重要的问题。

Enter the rules engine.

输入规则引擎。

什么是规则引擎? (What is a rules engine?)

A rules engine is a system that performs a set of actions based on specific conditions which can be configured during runtime. This means that an effectively set up rules engine would not require engineers to change a system’s business logic.

规则引擎是一种系统,它根据可以在运行时配置的特定条件执行一组操作。 这意味着有效设置的规则引擎将不需要工程师更改系统的业务逻辑。

Engineers build rules-based systems all the time, albeit unconsciously. Every time you code an if-else statement, you are effectively creating a hardcoded rule that is followed by the system.

工程师始终在不知不觉中构建基于规则的系统。 每次编写if-else语句时,都在有效地创建系统遵循的硬编码规则。

You can go a step further and make these systems configurable dynamically. When I say dynamic, I mean that the behavior of the system is not determined by flows coded by engineers, but by configuration through data.

您可以更进一步,使这些系统可以动态配置。 当我说动态时,我的意思是系统的行为不是由工程师编码的流程决定的,而是由数据配置决定的。

These so-called “codeless” systems are not new. Software like Zapier, Hubspot, and IFTTT operate off of the same concepts, as do more technical implementations like Boomi or Drools.

这些所谓的“无代码”系统并不新鲜。 Zapier,Hubspot和IFTTT等软件的运行原理相同,Boomi或Drools等更多技术实现也是如此。

A rules engine is a system that performs a set of actions based on specific conditions which can be configured during runtime.

规则引擎是一种系统,它根据可以在运行时配置的特定条件执行一组操作。

混凝土的脆性 (The fragility of concrete)

Why are rules engines even needed?

为什么甚至需要规则引擎?

By default, most engineers concern themselves on the details of what the rules are of the code they are writing. They were concrete implementations specific to the business use case they are encountering.

默认情况下,大多数工程师关注他们正在编写的代码规则的细节。 它们是特定于他们遇到的业务用例的具体实现。

This makes sense — code does exactly what it says it does, so engineers need to know what needs to be done to write the code properly.

这是有道理的-代码完全按照其声明的方式工作,因此工程师需要知道需要做什么才能正确编写代码。

However, this coupling to the details of the use case makes the code they write churn significantly when the details of the use case changes. While this approach works in many cases, sometimes the rate of change can become overwhelming, especially on smaller teams or more dynamic environments like post-investment startups.

但是,这种与用例细节的耦合使得当用例细节发生变化时,他们编写的代码会明显混乱。 尽管这种方法在很多情况下都可行,但有时变化的速度会变得势不可挡,尤其是在规模较小的团队或更具活力的环境(如投资后的初创企业)中。

It’s easy to see how these things can change. Business logic is implemented to fulfill a requirement in what behavior the software should exhibit. These requirements can come from many sources — business demands, improvements in UX, regulatory needs, technical drivers, etc.

很容易看到这些事情如何发生变化。 实现业务逻辑是为了满足软件应表现出的行为要求。 这些需求可能来自多种来源-业务需求,UX的改进,法规需求,技术驱动因素等。

Examples include:

示例包括:

  • A “welcome” email must be sent 2 hours after a user signs up

    用户注册后2小时必须发送“欢迎”电子邮件
  • If a payment account holds more than $100,000, over 3 consecutive days, the entire amount must be disbursed immediately

    如果付款帐户连续3天持有的金额超过$ 100,000,则必须立即全额支付
  • Employees that are a member of this union should accrue vacation time at double the standard rate for 2019, but not 2021.

    参加工会的员工应以2019年标准费率的两倍加倍休假时间,而不是2021年。

All of these can also vary in levels of stability, or how often the details change.

所有这些都可能在稳定性级别或细节更改频率上有所不同。

For example, a requirement based on data obtained through user analytics may change weekly, whereas a requirement based on a financial regulation may change once every couple of years. A requirement based on a union contract may only change when the contract is renegotiated.

例如,基于通过用户分析获得的数据的需求可能每周更改,而基于财务法规的需求可能每两年更改一次。 基于工会合同的要求只能在重新协商合同后才能更改。

When it does change, the implementation must change alongside of it.

当确实发生更改时,实现必须随之更改。

实现的演变 (The evolution of an implementation)

Let’s examine a hypothetical implementation of the “welcome” email requirement as it evolves over time.

让我们研究一下“欢迎”电子邮件要求随时间变化的假设实现。

A “welcome” email must be sent 2 hours after a user signs up

用户注册后2小时必须发送“欢迎”电子邮件

第一阶段 (The first stage)

Developers can be relied on to do the easiest thing. Most engineers boil business logic down to an if-this-do-that: if this happens, perform this action.

开发人员可以依靠它来做最简单的事情。 大多数工程师将业务逻辑归结为“如果执行此操作”:如果发生这种情况,请执行此操作。

The first (and unfortunately often last) implementation most developers take is the direct approach.

大多数开发人员采用的第一个(不幸的是最后一个)实施方法是直接方法。

It’s so easy — a single line of code can fulfill this requirement:

非常简单-一行代码即可满足此要求:

def on_user_create
WelcomeEmail.send(in: 2.hours)
end

第二阶段 (The second stage)

As time passes, the business often demands changes to details that seemed concrete and set in stone in the past.

随着时间的流逝,企业经常要求对过去似乎是具体的,固定的细节进行更改。

Change is a constant, and software is SOFTware for a reason — it has to be malleable to fit the situation and circumstances.

变化是一个常数,而软件是软件是有原因的-它必须具有适应性,以适应具体情况。

What if we discover that 2 hours is too long, and we want to change it to 15 minutes? If we do, an engineer needs to go and change it.

如果我们发现2小时太长,而又想将其更改为15分钟怎么办? 如果这样做,工程师需要去进行更改。

def after_user_create
WelcomeEmail.send(in: 15.minutes)
end

Change is a constant, and software is SOFTware for a reason — it has to be malleable to fit the situation and circumstances.

变化是一个常数,而软件是软件是有原因的-它必须具有适应性,以适应具体情况。

第三阶段 (The third stage)

If the business is performing experiments to see what kind of on-boarding leads to the best retention and conversion rates, it’s likely this value will change a lot.

如果企业正在进行实验,以了解哪种入职方式可带来最佳的保留率和转化率,则该价值可能会发生很大变化。

If this happens enough times, the developer will hopefully get smart and move this detail out of the code so it can be configured during runtime.

如果发生这种情况的次数足够多,开发人员将有望变得聪明,并将此细节移出代码,以便可以在运行时对其进行配置。

def after_user_create
WelcomeEmail.send(in: Configuration.get('welcome_email_wait'))
end

Configuration.get could access the database, read a configuration file, look at an environment variable, or perhaps even randomly decide. The important factor is that it is now determined at runtime instead of hard-coded.

Configuration.get可以访问数据库,读取配置文件,查看环境变量,甚至可以随机决定。 重要的因素是,它现在是在运行时确定的,而不是硬编码的。

第四阶段 (The fourth stage)

Each individual requirement taken in isolation often ends at the third stage.

孤立地满足的每个单独要求通常在第三阶段结束。

However, if there is a collection of related requirements, patterns can start to emerge which the intuitive engineer can pick up on.

但是,如果有一系列相关需求,则可能会出现一些直观的工程师可以借鉴的模式。

Let’s say the business also wants to send a tips and tricks email. An engineer is likely to code the following implementation, being consistent with prior work:

假设该企业还希望发送提示和技巧电子邮件。 与先前的工作一致,工程师可能会编码以下实现:

def after_user_create
WelcomeEmail.send(in: Configuration.get('welcome_email_wait'))
TipsEmail.send(in: Configuration.get('tips_email_wait'))
end

Once again, however, it requires a engineer to add support for the new kind of email.

但是,这再次要求工程师增加对新型电子邮件的支持。

检查演变 (Examining the evolution)

As we’ve seen above — each change is easy and small, but it adds up over time, quite insidiously. It’s easy to see how it can quickly grow out of control in a system where hundreds or thousands of requirements may be implemented in parallel, often under high delivery pressure.

正如我们在上面看到的那样,每个更改都很容易,而且很小,但是随着时间的推移,它会变得非常隐蔽。 很容易看到它如何Swift脱离控制,而该系统通常会在高交付压力下并行执行成百上千的需求。

Even in this simple circumstance, time has caused unrelated emails to be tightly coupled to record lifecycle, which makes systems more complicated.

即使在这种简单的情况下,时间也导致无关的电子邮件与记录的生命周期紧密相关,这使系统更加复杂。

In the above scenario, the developer made the judgement to couple the mechanism to the use case. This means the developer tied together what was being done to how something should be done to why something was being done. They coupled the business domain to the technical domain — the mechanism became tied to the use case.

在上述情况下,开发人员做出了将机制耦合到用例的判断。 这意味着开发商绑在一起正在采取什么东西应该怎么做, 为什么事情正在做。 他们将业务领域与技术领域相结合-机制与用例联系在一起。

They coupled the business domain to the technical domain — the mechanism became tied to the use case.

他们将业务领域与技术领域相结合-机制与用例联系在一起。

When we introduced the tips and tricks email, we essentially had to repeat the implementation. The implementation relied on specific details — namely when something was being done, how long to wait, and what was actually being sent. These details then changed, forcing changes to the implementation (aka. extra work for engineers).

当我们介绍提示和技巧电子邮件时,我们实际上必须重复执行。 该实现依赖于特定的细节,即何时完成某件事,等待多长时间以及实际发送了什么。 然后更改了这些详细信息,迫使更改实现(又称工程师的额外工作)。

细节没关系 (The details don’t matter)

The truth is that these details don’t matter.

事实是,这些细节无关紧要。

From a technical perspective, it shouldn’t matter whether a welcome email is sent 2 hours after the user signs up or 15 minutes after. Nor should it matter that it was a welcome email or a tips and trick email.

从技术角度来看,在用户注册2小时后还是15分钟后发送欢迎电子邮件都没有关系。 不管是欢迎电子邮件还是提示和技巧电子邮件,都没有关系。

That’s the realm of the business — these are merely use cases for the base technology.

那就是业务的境界-这些仅仅是基础技术的用例。

The implementation itself should remain the same — as far as the system should be concerned, it sent a Foobar notification upon creation of a Whatsittoya record, and can use (mostly) the same exact code to send a Fizzbuzz notifcation upon the deletion of a Whatchamacallit record.

实现本身应该保持不变-就系统而言,它在创建Whatsittoya记录时发送了Foobar通知,并且可以使用(大部分)相同的代码在删除Whatchamacallit时发送Fizzbuzz通知记录。

When it is sent or what is being sent are details that just aren’t as concrete. These are the details that should be abstracted away because these are the details that are the most likely to change over time.

何时发送或正在发送的内容并不十分具体。 这些细节应该被抽象掉,因为这些细节最有可能随着时间而改变。

You don’t want to have to engineer something every time a requirement changes. You want to give that power to the business, barring some contractual, security[1], or regulatory requirement.

您不需要每次需求变化时都必须进行工程设计。 您希望将业务授权给业务,除非有合同,安全性[1]或法规要求。

[1] Security also includes job security.

[1]安全性还包括工作安全性。

建立规则引擎 (Building a rules engine)

So, now that we’ve examined the context in which a rules engine would be useful, how do you actually build one?

因此,既然我们已经研究了规则引擎有用的上下文,那么您如何实际构建一个呢?

There’s a lot of ways, but conceptually a minimal rules engine includes the following components:

有很多方法,但是从概念上讲,最小规则引擎包括以下组件:

规则 (Rule)

A rule is a business policy. Within the technical domain of the rules engine, it is a collection of a set of triggers, conditions, and effects that are applied by the rules engine.

规则是一种业务策略。 在规则引擎的技术领域内,它是规则引擎所应用的一组触发器,条件和效果的集合。

触发 (Trigger)

The trigger is the thing that determines whether the engine should attempt to run through a rule or not. In most cases, it is contextual.

触发器是确定引擎是否应该尝试通过规则运行的事物。 在大多数情况下,它是上下文相关的。

In simple systems, it could be a simple string check or even hard-coded, such as a string on a Rule with the value on_create and PaymentAccount to indicate that the rule should only be executed when a record of type PaymentAccount is created.

在简单的系统中,它可以是简单的字符串检查,甚至可以是硬编码的,例如规则上的字符串,其值为on_createPaymentAccount以指示仅当创建PaymentAccount类型的记录时才应执行该规则。

In more complex systems, it could be a full context check that looks at things like whether the user is logged in or the kind of record being worked on.

在更复杂的系统中,它可能是一个完整的上下文检查,它检查诸如用户是否已登录或正在处理的记录类型之类的事情。

健康)状况 (Condition)

The Condition determines if the Rule should be applied in that particular circumstance and on that particular record.

条件确定是否应在该特定情况下以及该特定记录上应用该规则。

It has some minor overlap conceptually with a trigger, but also enough differences to warrant a separate discussion.

从概念上讲,它与触发器有一些细微的重叠,但也有足够的差异,值得单独讨论。

A trigger is more of a generalized determination of whether a rule’s conditions should even be checked, whereas condition is more of an instance-specific check. Smaller systems can potentially fold the trigger in to a a condition, but more complex systems will likely benefit from separating the two.

触发条件更多地是确定是否应检查规则条件的一般确定,而条件更多地是特定于实例的检查。 较小的系统可能会将触发器折叠成一个状态,但是更复杂的系统可能会受益于将两者分开。

The Condition itself will likely have some sort of reference to actual code that performs the check itself, with some parameters to pass in to the function.

Condition本身可能会对执行检查本身的实际代码进行某种形式的引用,并将某些参数传递给函数。

For example, you could store a Condition record in the database that stores the name of the condition class as well as some accompanying parameters. The code could then dynamically initialize the condition class it identifies, passing in the parameters and the record to check against.

例如,您可以在数据库中存储一个条件记录,该记录存储条件类的名称以及一些附带的参数。 然后,代码可以动态初始化它标识的条件类,并传入参数和要检查的记录。

影响 (Effect)

The Effect is what happens once a Rule is triggered and its Conditions pass. It is typically a function or execution of a function. It may be something as simple as setting a field or something as complex as kicking off an entire workflow.

效果是触发规则并通过条件后发生的情况。 它通常是一个函数或函数的执行。 它可能像设置字段一样简单,也可能像启动整个工作流程一样复杂。

Like the Condition, it will likely have some sort of reference to actual code that applies the Effect itself.

像条件一样,它可能会对应用效果本身的实际代码有某种引用。

发动机 (Engine)

Finally, you have the engine itself. This is the thing that will actually perform the bulk of the work. It’ll accept records, load a list of rules, check whether those rules should be applied based on specific triggers and conditions, and then apply the effects of the rules.

最后,您拥有引擎本身。 这实际上将完成大部分工作。 它将接受记录,加载规则列表,检查是否应基于特定的触发器和条件应用这些规则,然后应用规则的效果。

其他一些令人关注的领域 (Some other areas of concern)

In addition to the above components, you’ll also likely encounter secondary areas of concern when building the rules engine. Things like auditing changes to rules, tracking the history of rules being applied, enabling the configuration of rules to specific people, event-based effects, rule DSLs, etc. are all related subsystems, but also outside the scope of the core of the rules engine.

除了上述组件之外,在构建规则引擎时,您还可能会遇到其他需要关注的方面。 诸如审核规则更改,跟踪所应用规则的历史记录,为特定人员启用规则配置,基于事件的效果,规则DSL等之类的东西都是相关子系统,但也超出了规则核心的范围。发动机。

规则引擎的流程 (The flow of a rules engine)

How would this rules engine actually work?

该规则引擎实际上将如何工作?

  • Step 1: Trigger the engine

    步骤1:触发引擎
  • Step 2: Get the Rules

    步骤2:取得规则
  • Step 3: Check the Conditions

    步骤3:检查条件
  • Step 4: Apply the Effects

    步骤4:套用效果

步骤1:触发引擎 (Step 1: Trigger the Engine)

The first step that occurs is the engine gets triggered. The entry point could be a function Engine#run. This function is passed a record and its associated context (eg. if the record is newly created, or the engine is being called in an update, etc.)

发生的第一步是触发引擎。 入口点可以是Engine#run函数。 向该函数传递一条记录及其关联的上下文(例如,如果是新创建的记录,或者正在更新中调用引擎等)

步骤2:取得规则 (Step 2: Get the Rules)

The engine will get the list of rules that apply for that specific context. Perhaps it will load it in real-time from the database. Maybe it pre-loaded it from a configuration file when the system booted.

引擎将获取适用于该特定上下文的规则列表。 也许它将从数据库中实时加载它。 可能是系统启动时从配置文件中预加载了它。

Either way, these Rules will have associations to Conditions and Effects, which is what the important part is for the next couple of steps.

无论哪种方式,这些规则都将与条件和影响相关联,这是接下来的几个步骤中重要的部分。

步骤3:检查条件 (Step 3: Check the Conditions)

The Condition would be a boolean check that determines whether the Rule’s Effects should be applied or not. If a Rule has multiple Conditions, further boolean logic should be performed to determine how the Conditions are evaluated to determine whether the Rule applies or not (eg. all or nothing, any, quorum).

条件将是布尔检查,确定是否应应用规则的效果。 如果一个规则具有多个条件,则应执行进一步的布尔逻辑以确定如何评估条件以确定该规则是否适用(例如,全部或全部,全部,法定人数)。

步骤4:套用效果 (Step 4: Apply the Effects)

If the Rule’s Conditions pass, it is time to apply the Effects. The Effect itself is arbitrary. You‘ll want to determine how to handle cases in which the application of an Effect failed.

如果规则的条件通过,则是时候应用效果了。 效果本身是任意的。 您将要确定如何处理效果应用程序失败的情况。

Once this happens, the Rule has been applied. You’ve done it!

一旦发生这种情况,便会应用规则。 你完成了!

一个具体的例子 (A concrete example)

Suppose you had to set up a user account to be marked as a “Popular” member once a certain number of views for the profile has been reached. You could theoretically hard-code this, but it would require an engineer to change in the future. Good engineering minimizes the cost and impact of likely future changes.

假设您必须设置一个用户帐户,以便在达到个人资料的特定数量的视图后将其标记为“受欢迎”成员。 从理论上讲,您可以对此进行硬编码,但是将来需要工程师进行更改。 良好的工程设计可将成本和未来可能发生的变化的影响降至最低。

If you had a rule engine that you could use to configure this instead, engineers would not be required.

如果您有可用于配置它的规则引擎,则不需要工程师。

A Rule could be created that:

可以创建一个规则:

  • had the Trigger of view

    有触发的view

  • had a Condition of view_count being greater than 100

    view_count条件大于100

  • had an Effect of setting a field of the user to popular

    具有将用户领域设置为popular

The record would then run automatically through the rules engine, and could also be changed in the future.

然后,该记录将通过规则引擎自动运行,并且将来也可以更改。

样例代码 (Sample code)

Having a hard time conceptualizing this? Not to fear — I’ve created a small Github repository to illustrate some of the concepts here.

很难将其概念化吗? 不用担心-我创建了一个小的Github存储库来说明这里的一些概念。

Note that this isn’t intended to be a production-grade system, but rather a simplified illustration of the above concepts. Actual rules engines have many more moving parts and take into consideration a whole host of other cases.

请注意,这并不是要成为生产级系统,而只是上述概念的简化说明。 实际的规则引擎具有更多的活动部分,并考虑了许多其他情况。

As a final disclaimer: improperly implemented rules engines or rules engines applied outside of the appropriate context can also make your system incredibly complicated and lead to a loss of organizational agility, so be judicious in their usage.

作为最后的免责声明:不正确实施的规则引擎或在适当上下文之外应用的规则引擎也会使您的系统异常复杂,并导致组织敏捷性丧失,因此请谨慎使用它们。

Rules engines are highly useful tools — in the right context. If implemented properly, they can significantly ease development burden and improve the agility of other departments within your organization.

在正确的上下文中,规则引擎是非常有用的工具。 如果实施得当,它们可以大大减轻开发负担并提高组织内其他部门的敏捷性。

翻译自: https://medium.com/swlh/how-to-design-software-rules-engines-adbb098b2d73

软件 规则引擎

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值