4006-998-758
新闻动态

语义模型驱动设计——软件复杂性应对之法(实战篇

2023-11-03

中智凯灵 2023年11月02日 09:03 

以下文章来源于雷达峰 ,作者Faye Chen

语义模型驱动设计——软件复杂性应对之法(实战篇(图1)雷达峰.

工程师探索与思考的基地

语义模型驱动设计——软件复杂性应对之法(实战篇(图2)

作者:陈雅菲——中兴通讯公司资深软件架构师资深敏捷教练。深耕软件领域20余年,拥有丰富的大型软件项目架构、设计与开发经验,在软件设计开发理论与实践上均有独到见解。 长期致力于敏捷技术实践指导与推广,多次获得公司十佳敏捷教练称号。目前研究方向是LLM辅助设计编码。

语义模型驱动设计——软件复杂性应对之法(实战篇(图3)
开发维护大型软件系统面临的主要挑战是降低软件复杂性。语义模型驱动设计(Semantic Model Driven Design,SMDD)是一种好的设计方法,合理使用此方法可以做出好的设计,以降低软件复杂性。语义模型驱动设计的核心思想是通过构建语义模型驱动出好的设计。在使用该设计方法时需要遵循两条原则:语义模型的语义与问题领域的核心需求相匹配、语义模型提供的框架具备可组合性。使用语义模型构建三步法可针对特定问题领域构建特定语义模型,再基于语义模型提供一套DSL(Domain-Specific Language,领域特定语言)。语义模型是核心、DSL只是附属品。要做到这些,需要与之相匹配的人员能力。


实战案例

-问题-

请实现一个告警规则功能原型,需根据下述规则进行告警屏蔽和告警生成:

告警屏蔽:

1.当a告警产生时,屏蔽掉b、c、d、e、f告警;
2.当b告警产生时,屏蔽掉d、e、f告警;
3.当c告警产生时,屏蔽掉d、e、f告警;

4.当d告警产生时,屏蔽掉e、f告警。

告警生成:

1.当a、b、c或d任一告警产生时,生成g告警;

2.当e告警产生且f告警未产生时,生成h告警。


-分析-

该告警规则功能尚不知如何实现,暂时是个黑盒,以下称之为系统。

首先思考系统的输入和输出。根据问题描述,特别是告警生成描述中的第2点,不难想到,系统的输入是告警列表。系统的输出是规则应用结果,包括应用成功、应用失败和未应用。

分析清楚了系统的输入和输出,我们再来思考系统本身。显而易见的是系统里的各种规则。不那么显而易见的是规则之间的关系。

用一句话描述就是:设计实现一个告警规则功能,该系统接受一个告警列表,根据各种规则和规则之间的关系应用规则,输出规则应用结果。


-设计-

一、语义模型构建三步法

下面使用语义模型构建三步法,针对告警规则这个特定问题领域构建特定语义模型。 
语义模型驱动设计——软件复杂性应对之法(实战篇(图4)

1. 告警

1)寻找核心概念

在问题描述中,告警是一个高频出现的概念,与当前特定问题领域的核心需求密切相关。

2)提炼概念语义

告警的语义是系统产生的某种告警,例如告警a、告警b。通常系统告警会包含很多属性,但在当前特定问题领域,只需要能把各种告警区分开的属性就行,例如告警名称、告警码等。这里使用告警名称唯一标识某种告警,因此用告警名称作为告警的构造参数。

3)形式化表达

“告警a”可形式化表达为alarm(a),圆括号里的是构造参数,即告警名称。

2. 规则

1)寻找核心概念

在问题描述中,规则是一个非常明显的概念,与告警规则这个问题领域的核心需求密切相关。

2)提炼概念语义

规则的语义是系统遵循的某种规则,其输入是告警列表、输出是规则应用结果。规则包括原子规则和组合规则。

3)形式化表达

规则可形式化表达为rule: alarms -> { succeeded | failed | unapplied },箭头左边是输入、右边是输出,花括号里的内容表示多选一。

3. 屏蔽告警规则

1)寻找核心概念

在问题描述中,屏蔽告警非常明显,但屏蔽告警规则却不那么明显。

2)提炼概念语义

屏蔽告警规则的语义是屏蔽某种告警的规则,例如屏蔽告警b规则、屏蔽告警c规则。被屏蔽的某种告警作为它的构造参数。屏蔽告警规则是一种原子规则。

3)形式化表达

“屏蔽告警b规则”可形式化表达为mask(alarm(b))。

4. 生成告警规则

1)寻找核心概念

提炼出屏蔽告警规则后,生成告警规则是类似的。

2)提炼概念语义

生成告警规则的语义是生成某种告警的规则,例如生成告警g规则、生成告警h规则。被生成的某种告警作为它的构造参数。生成告警规则是一种原子规则。

3)形式化表达

“生成告警g规则”可形式化表达为generate(alarm(g))。

5. 条件应用规则

1)寻找核心概念

在问题描述中,“当...时,...”的句式描述的是一种条件应用规则。

2)提炼概念语义

条件应用规则由条件和规则构成。它的语义是:接受一个告警列表,对其进行条件判断,如果满足条件就应用规则,输出规则应用结果;如果不满足条件,就不应用规则,输出规则未应用。条件应用规则是一种组合规则。

3)形式化表达

条件应用规则可形式化表达为whenThen(condition, rule)。

6. 顺序应用规则

1)寻找核心概念

相比较条件应用规则,顺序应用规则就非常不明显了。在问题描述中,告警屏蔽的1、2、3、4点和告警生成的1、2点其实都是顺序应用规则。

2)提炼概念语义

顺序应用规则由子规则列表构成。它的语义是:按照给定的顺序依次应用多条规则,如果某条规则应用失败或未应用,继续应用下一条规则,无论是否有规则应用失败或未应用,最终始终输出规则应用成功。顺序应用规则是一种组合规则。

3)形式化表达

顺序应用规则可形式化表达为seq(rules)。

7. 条件

1)寻找核心概念

条件应用规则包含了条件这一核心概念。

2)提炼概念语义

条件的语义是告警列表需要满足的某种条件,其输入是告警列表、输出是boolean,告警列表满足条件时输出true、否则输出false。条件包括原子条件和组合条件。

3)形式化表达

条件可形式化表达为condition: alarms -> { true | false }。

8. 包含条件

1)寻找核心概念

包含条件也不太明显,以“当a告警产生时”为例,它的实际含义是告警列表是否包含告警a。

2)提炼概念语义

包含条件的语义是告警列表是否包含某种告警,被包含的某种告警作为它的构造参数。包含条件是原子条件。

3)形式化表达

“a告警产生”可形式化表达为contains(alarm(a))。

9. 否条件

1)寻找核心概念

提炼出包含条件后,否条件看上去就比较明显了。

2)提炼概念语义

虽然寻找否条件这个核心概念看上去并不难,但提炼其概念语义并不一定容易。以“f告警未产生”为例,否条件的语义有两种提炼方式:方式一是告警列表是否不包含告警f;方式二是告警列表包含告警f、再取非。哪种方式更好?方式二,因为方式二提炼的概念语义组合性更强、更抽象。否条件需要一个子条件作为它的构造参数。否条件是组合条件。

3)形式化表达

否条件可形式化表达为not(condition)。“f告警未产生”可形式化表达为not(contains(alarm(f)))。

10. 或条件

1)寻找核心概念

在问题描述中,或条件非常明显。

2)提炼概念语义

或条件的语义可以直接映射到布尔代数的OR。在做设计时,首先考虑是否能将问题领域映射到一个熟悉的同构领域。如果能,就可以借用那个领域的机制来表达问题领域的概念,而不是重新发明。能找到这样一个同构领域应该是一个最好的结果,实在找不到再自己发明。或条件由两个子条件构成,两个以上的子条件只是语法糖衣。或条件是组合条件。

3)形式化表达

或条件可形式化表达为or(condition1, condition2)。“a或b告警产生”可形式化表达为or(contains(alarm(a)), contains(alarm(b)))。

11. 与条件

1)寻找核心概念

提炼出或条件后,与条件是类似的。

2)提炼概念语义

与条件的语义可以直接映射到布尔代数的AND。与条件由两个子条件构成。与条件是组合条件。

3)形式化表达
与条件可形式化表达为and(condition1, condition2)。“e告警产生且f告警未产生”可形式化表达为and(contains(alarm(e)), not(contains(alarm(f))))。

二、语义模型

至此,使用语义模型构建三步法建立了针对告警规则这个特定问题领域的语义模型,如下表所示:

核心概念

概念语义

原子/组合

形式化表达

告警

系统产生的某种告警,用告警名称唯一标识

/

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编程。

语义模型驱动设计——软件复杂性应对之法(实战篇(图5)


-实现-

这里选择用Java语言以面向对象的方式实现设计。也可以用其他编程语言或其他方式,例如函数式编程实现设计。一般来说,通过构建语义模型驱动出的设计与编程语言、编程范式没有必然联系。

这里展示一些关键代码。

Alarm类 语义模型驱动设计——软件复杂性应对之法(实战篇(图6)

RuleResult类

语义模型驱动设计——软件复杂性应对之法(实战篇(图7)

Condition接口及其实现类 语义模型驱动设计——软件复杂性应对之法(实战篇(图8)

语义模型驱动设计——软件复杂性应对之法(实战篇(图9)
语义模型驱动设计——软件复杂性应对之法(实战篇(图10)

 Rule接口及其实现类 语义模型驱动设计——软件复杂性应对之法(实战篇(图11)

语义模型驱动设计——软件复杂性应对之法(实战篇(图12)

语义模型驱动设计——软件复杂性应对之法(实战篇(图13)




END



11月24-25日,一场聚焦于AI大语言模型的年度盛会,“AI+软件研发行业数字峰会(AiDD峰会)”即将于深圳举办。助你在人工智能的浪潮中乘风破浪。

语义模型驱动设计——软件复杂性应对之法(实战篇(图14)语义模型驱动设计——软件复杂性应对之法(实战篇(图15)语义模型驱动设计——软件复杂性应对之法(实战篇(图16)双11特惠语义模型驱动设计——软件复杂性应对之法(实战篇(图17)语义模型驱动设计——软件复杂性应对之法(实战篇(图18)语义模型驱动设计——软件复杂性应对之法(实战篇(图19)

好基友同行,第二人半价

名额有限赶快抢购吧!语义模型驱动设计——软件复杂性应对之法(实战篇(图20)
语义模型驱动设计——软件复杂性应对之法(实战篇(图21)



返回列表