以下文章来源于雷达峰 ,作者Faye Chen
作者:陈雅菲——中兴通讯公司资深软件架构师资深敏捷教练。深耕软件领域20余年,拥有丰富的大型软件项目架构、设计与开发经验,在软件设计开发理论与实践上均有独到见解。 长期致力于敏捷技术实践指导与推广,多次获得公司十佳敏捷教练称号。目前研究方向是LLM辅助设计编码。
▼
告警屏蔽:
4.当d告警产生时,屏蔽掉e、f告警。
告警生成:
2.当e告警产生且f告警未产生时,生成h告警。
首先思考系统的输入和输出。根据问题描述,特别是告警生成描述中的第2点,不难想到,系统的输入是告警列表。系统的输出是规则应用结果,包括应用成功、应用失败和未应用。
分析清楚了系统的输入和输出,我们再来思考系统本身。显而易见的是系统里的各种规则。不那么显而易见的是规则之间的关系。
用一句话描述就是:设计实现一个告警规则功能,该系统接受一个告警列表,根据各种规则和规则之间的关系应用规则,输出规则应用结果。
在问题描述中,告警是一个高频出现的概念,与当前特定问题领域的核心需求密切相关。
告警的语义是系统产生的某种告警,例如告警a、告警b。通常系统告警会包含很多属性,但在当前特定问题领域,只需要能把各种告警区分开的属性就行,例如告警名称、告警码等。这里使用告警名称唯一标识某种告警,因此用告警名称作为告警的构造参数。
“告警a”可形式化表达为alarm(a),圆括号里的是构造参数,即告警名称。
在问题描述中,规则是一个非常明显的概念,与告警规则这个问题领域的核心需求密切相关。
规则的语义是系统遵循的某种规则,其输入是告警列表、输出是规则应用结果。规则包括原子规则和组合规则。
规则可形式化表达为rule: alarms -> { succeeded | failed | unapplied },箭头左边是输入、右边是输出,花括号里的内容表示多选一。
在问题描述中,屏蔽告警非常明显,但屏蔽告警规则却不那么明显。
屏蔽告警规则的语义是屏蔽某种告警的规则,例如屏蔽告警b规则、屏蔽告警c规则。被屏蔽的某种告警作为它的构造参数。屏蔽告警规则是一种原子规则。
“屏蔽告警b规则”可形式化表达为mask(alarm(b))。
提炼出屏蔽告警规则后,生成告警规则是类似的。
生成告警规则的语义是生成某种告警的规则,例如生成告警g规则、生成告警h规则。被生成的某种告警作为它的构造参数。生成告警规则是一种原子规则。
“生成告警g规则”可形式化表达为generate(alarm(g))。
在问题描述中,“当...时,...”的句式描述的是一种条件应用规则。
条件应用规则由条件和规则构成。它的语义是:接受一个告警列表,对其进行条件判断,如果满足条件就应用规则,输出规则应用结果;如果不满足条件,就不应用规则,输出规则未应用。条件应用规则是一种组合规则。
条件应用规则可形式化表达为whenThen(condition, rule)。
相比较条件应用规则,顺序应用规则就非常不明显了。在问题描述中,告警屏蔽的1、2、3、4点和告警生成的1、2点其实都是顺序应用规则。
顺序应用规则由子规则列表构成。它的语义是:按照给定的顺序依次应用多条规则,如果某条规则应用失败或未应用,继续应用下一条规则,无论是否有规则应用失败或未应用,最终始终输出规则应用成功。顺序应用规则是一种组合规则。
顺序应用规则可形式化表达为seq(rules)。
条件应用规则包含了条件这一核心概念。
条件的语义是告警列表需要满足的某种条件,其输入是告警列表、输出是boolean,告警列表满足条件时输出true、否则输出false。条件包括原子条件和组合条件。
条件可形式化表达为condition: alarms -> { true | false }。
包含条件也不太明显,以“当a告警产生时”为例,它的实际含义是告警列表是否包含告警a。
包含条件的语义是告警列表是否包含某种告警,被包含的某种告警作为它的构造参数。包含条件是原子条件。
“a告警产生”可形式化表达为contains(alarm(a))。
提炼出包含条件后,否条件看上去就比较明显了。
虽然寻找否条件这个核心概念看上去并不难,但提炼其概念语义并不一定容易。以“f告警未产生”为例,否条件的语义有两种提炼方式:方式一是告警列表是否不包含告警f;方式二是告警列表包含告警f、再取非。哪种方式更好?方式二,因为方式二提炼的概念语义组合性更强、更抽象。否条件需要一个子条件作为它的构造参数。否条件是组合条件。
否条件可形式化表达为not(condition)。“f告警未产生”可形式化表达为not(contains(alarm(f)))。
在问题描述中,或条件非常明显。
或条件的语义可以直接映射到布尔代数的OR。在做设计时,首先考虑是否能将问题领域映射到一个熟悉的同构领域。如果能,就可以借用那个领域的机制来表达问题领域的概念,而不是重新发明。能找到这样一个同构领域应该是一个最好的结果,实在找不到再自己发明。或条件由两个子条件构成,两个以上的子条件只是语法糖衣。或条件是组合条件。
或条件可形式化表达为or(condition1, condition2)。“a或b告警产生”可形式化表达为or(contains(alarm(a)), contains(alarm(b)))。
提炼出或条件后,与条件是类似的。
与条件的语义可以直接映射到布尔代数的AND。与条件由两个子条件构成。与条件是组合条件。
核心概念 | 概念语义 | 原子/组合 | 形式化表达 |
告警 | 系统产生的某种告警,用告警名称唯一标识 | / | alarm(a) |
规则 | 规则的输入是告警列表、输出是规则应用结果,有3种情况:应用成功、应用失败、未应用。 | / | rule: alarms -> { succeeded | failed | unapplied } |
屏蔽告警规则 | 屏蔽某种告警的规则 | 原子规则 | mask(alarm(b)) |
生成告警规则 | 生成某种告警的规则 | 原子规则 | generate(alarm(g)) |
条件应用规则 | 对告警列表进行条件判断,如果满足条件就应用规则,输出规则应用结果;如果不满足条件,就不应用规则,输出规则未应用 | 组合规则 | whenThen(condition, rule) |
顺序应用规则 | 按照给定的顺序依次应用多条规则,如果某条规则应用失败或未应用,继续应用下一条规则,无论是否有规则应用失败或未应用,最终始终输出规则应用成功 | 组合规则 | seq(rules) |
条件 | 条件的输入是告警列表、输出是boolean,告警列表满足条件时输出true、否则输出false | / | condition: alarms -> { true | false } |
包含条件 | 告警列表是否包含某种告警 | 原子条件 | contains(alarm(a)) |
否条件 | 布尔代数的非 | 组合条件 | not(condition) |
或条件 | 布尔代数的或 | 组合条件 | or(condition1, condition2) |
组合条件 | and(condition1, condition2) |
有了语义模型及其形式化表达,可以用DSL实现语义模型的形式化表达,可以用DSL写出针对告警规则这个特定问题领域的规格说明(Specification)。在写规格说明的时候,其实就是在用这套DSL编程。
这里选择用Java语言以面向对象的方式实现设计。也可以用其他编程语言或其他方式,例如函数式编程实现设计。一般来说,通过构建语义模型驱动出的设计与编程语言、编程范式没有必然联系。
这里展示一些关键代码。
Alarm类
RuleResult类
Condition接口及其实现类
Rule接口及其实现类
END 11月24-25日,一场聚焦于AI大语言模型的年度盛会,“AI+软件研发行业数字峰会(AiDD峰会)”即将于深圳举办。助你在人工智能的浪潮中乘风破浪。 双11特惠 好基友同行,第二人半价