Skip to content

Commit

Permalink
更新文档
Browse files Browse the repository at this point in the history
  • Loading branch information
entropy-cloud committed Jul 23, 2023
1 parent f293456 commit 5488d7d
Showing 1 changed file with 38 additions and 11 deletions.
49 changes: 38 additions & 11 deletions docs/theory/pros-and-cons-of-framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,13 @@ Nop平台中所有的模型对象都可以自动的转换为对应的DSL模型

在Excel的数据模型中我们可以指定部分显示相关的属性,它经由ORM层的扩展属性传递给Meta,然后再传递到前端页面模型中。

### 五. 框架的设计完备性如何?

从科学的角度上说,一个科学的解决方案绝不会是一个孤立的设计,而必然是包含从简单到复杂的一组可以渐进演化的策略集合,针对不同的复杂性我们都需要拟定对应的解决策略。因此,一个立足于适应各种使用场景的底层框架一定要在某种程度上保证自己的设计完备性,而且这种完备性往往无法用穷举法来实现。

### 五. 框架的设计完整性如何?

从科学的角度上说,一个科学的解决方案绝不会是一个孤立的设计,而必然是包含从简单到复杂的一组可以渐进演化的策略集合,针对不同的复杂性我们都需要拟定对应的解决策略。因此,一个立足于适应各种使用场景的底层框架一定要在某种程度上保证自己的设计完整性,而且这种完整性往往无法用穷举法来实现。



### 分层设计
### 函数抽象和模板化

举一个简单的例子。假设我们现在要编写一个流程设计器,流程节点需要显示图标和文字,最简单的设计如下:

Expand All @@ -223,24 +221,53 @@ type Node{
}
```

如果我们需要控制文字的显示位置,则还需要加入labelPosition这样的描述字段。如果要求根据流程状态的不同改变背景颜色或者显示额外的一个状态标识,则我们需要继续为节点增加statusIconMapping等属性。显然我们是无法通过穷举法来响应所有需求的。一个合适的解决方案是在节点级别提供一个渲染函数抽象,它负责实现节点的自定义渲染。
如果我们需要控制文字的显示位置,则还需要加入labelPosition这样的描述字段。如果要求根据流程状态的不同改变背景颜色或者显示额外的一个状态标识,则我们需要继续为节点增加statusIconMapping等属性。显然我们无法通过属性枚举来穷尽所有可能的需求,为了保证设计的完备性,我们必须要引入函数抽象,例如在节点级别提供一个渲染函数render,它负责实现节点的自定义渲染。

一旦建立函数抽象,进一步的问题就是如何去实现这个函数的问题。一个有趣的解决方案是模板化。
```xml
<template>
<span v-if="prop.label">{{prop.label}}</span>
<span :class="'status-'+prop.status" />
</template>
```
render(data){
...
}

**借助于一种图灵完备的模板语言,我们可以用描述式的方式实现对函数的分解,甚至可以提供一种可视化的设计器来支持客户自行设计函数内容**

Nop平台系统化的利用Xpl模板语言来实现对函数的细粒度分解。比如在报表引擎中我们需要连接外部的数据源来获取数据
```xml
<beforeExecute>
<report:UseSplDataSet src="/report.splx" var="ds1" xpl:lib="/report.xlib" />
</beforeExecute>
```

一般的报表引擎总是内置大量的数据源种类,试图穷尽所有外部数据源的连接方式。如果一种数据源没有内置在报表工具中,我们就需要等待报表工具厂商支持或者需要自行编写一个插件。在NopReport引擎中,数据源的概念并不是内置在引擎深处的一个概念,引擎只是在输出报表时调用一个beforeExecute函数来准备数据。具体如何获取数据我们是在beforeExecute模板函数中自行决定的。Nop平台提供了所谓的Xpl模板语言,它是一种采用XML语法格式、图灵完备的程序语言,除了手工编写之外,我们也可以通过可视化设计器来设计Xpl模板。

> Xpl模板语言集成了NopIoC依赖注入容器,借助于IoC容器的对象发现能力(可以按照名称、前缀、注解、类型等多种方式动态查找所有满足条件的bean,并实现自动注入),可以起到类似插件机制的作用,而且调用形式更加简单、直观。
### 分层次、分阶段设计

一个完备的解决方案必然是高度结构化的,在不同颗粒度的结构层次我们都应该提供**仅需要使用该层次信息的处理机制**。以NopORM框架为例

1. IOrmTypeHandler:负责处理单个字段层面的结构问题。比如说字段加密、字段类型适配等。

2. IOrmComponent: 负责处理多个字段层面的结构问题。比如将多个字段组织成一个可复用的Address类型等。

3. IOrmEntity: 负责处理单个实体对象层面的结构问题。比如增加实体扩展属性、跟踪实体属性修改等。

4. IOrmInterceptor:拦截所有实体的关键操作,具有全局性的知识。例如录制整个请求过程中所有读取和修改的数据,输出到数据文件中作为自动化单元测试的初始化数据和结果验证数据。

除了组合关系之外,结构之间还可以存在着丰富的变换关系。我们需要仔细的对结构层次进行梳理,确定哪些是最基本的概念,哪些可以成为衍生概念。而不是所有的特性都堆砌在一起,形成一种平铺式的设计。

比如在NopORM框架中,多对多关联并不是一个内置的概念,底层的关系数据库存储机制只处理一对多和多对一关联。在Java实体层面,通过代码生成机制生成一些辅助函数,将多对多关联分解为两个一对多关联。类似的处理还有NopWorkflow中对于会签功能的实现:工作流的运行时引擎并不需要内置会签节点,通过`x:gen-extends`这种嵌入式代码生成器,在工作流模型加载的过程中可以动态生成DSL代码,将一个会签节点展开成为一个普通步骤节点和一个Join汇聚步骤节点。

Nop平台基于可逆计算原理,提供了一种系统化的多阶段编译机制。类似的处理机制可以应用于所有的自定义DSL语言。参见 [XDSL:通用的领域特定语言设计](https://zhuanlan.zhihu.com/p/612512300)

### 异步处理

同步处理和异步处理看似只是技术层面的一种选择,但本质上它们对应着不同的世界观。一个没有考虑异步处理的框架设计是不完整的。

在目前的程序实践中,如果事前没有考虑支持异步处理,则往往后期很难将整体框架转换为支持异步处理。为了系统化的支持异步处理,我们需要考虑如何将一个上下文对象在各个线程间进行传递的问题,同时也需要考虑各种并发场景下如何避免锁冲突等复杂的技术问题。



## 六. 框架提供了哪些差量化机制?

所有的框架都要考虑可扩展性的问题。在软件开发中,所谓的可扩展性指的是在不需要修改原始代码的情况下,通过添加额外的代码或差异信息,可以满足新的需求或实现新的功能。如果在完全抽象的数学层面去理解软件开发中的扩展机制,我们可以认为它对应于如下公式:
Expand Down

0 comments on commit 5488d7d

Please sign in to comment.