模型驱动的开发和测试
扫描二维码
随时随地手机看文章
凭借数十年的经验,我喜欢为公司构建企业应用程序。每个解决方案都需要一组模型:SQL 数据库、API(应用程序编程接口)、声明性规则、声明性安全性(基于角色的访问控制)、测试驱动的场景、工作流和用户界面。 “元”设计方法需要考虑每个组件如何与其他组件交互。我们还需要了解项目范围的变化如何影响每个元组件。虽然我使用过许多不同的语言(APL、Revelation/PICK、BASIC、Smalltalk、Object/1、Java、JavaScript、Node.js、Python))这些模型始终是影响最终综合解决方案的基础。模型是元抽象,描述对象的形状、内容和能力在运行环境中的行为方式,而与语言、平台或操作系统 (OS) 无关。
模型优先方法
从现有的 SQL 架构和良好的 ORM 开始,可以抽象数据库并生成 API。我一直在使用ApiLogicServer(一个由 GenAI 驱动的 Python 开源平台),它有一个命令行界面来连接主要的 SQL 数据库并创建 SQLAlchemy ORM(对象关系模型)。从这个模型中,创建了一个用于 JSON API 的开放 API(又名 Swagger),并且一个 YAML 文件(模型)驱动了一个 react-admin 运行时。 YAML 文件还用于构建 Ontimize ( Angular ) 用户界面。请注意,ApiLogicServer 的 GenAI 部分允许我使用提示驱动的方法,仅使用几个关键字即可获取整个运行堆栈。
命令行工具
CLI(命令行界面)用于创建新的 ApiLogicServer (ALS) Python 项目,连接到 SQL 数据库,使用 KeyCloak 进行单点登录身份验证,如果数据库发生更改,则重建 SQLAlchemy ORM,从API 等等。构建 API 的大部分工作都是由 CLI 完成的,映射表和列,处理数据类型、默认值、列别名、带引号的标识符以及父/子表之间的关系。这个工具的真正威力在于你看不到的东西。
构建 Northwind 演示的命令行:
Markdown
als create --project-name=demo --db-url=nw+
开发者视角
作为一名开发人员/顾问,我需要多个框架和一组工具来构建和交付完整的微服务解决方案。 ApiLogicServer 是一个与开发人员合作的框架,通过低代码和 DSL(领域特定语言)服务来增强和扩展这些不同的模型。
· 带有调试器的 VSCode 是绝对必要的。
· 用于代码完成和代码生成的 Copilot
· Python (3.12) 开源框架和库
· Kafka集成(生产者和消费者)
· 用于单点登录的 KeyCloak 框架
· LogicBank 声明式规则引擎与 ORM 模型和所有 CRUD 操作集成
· 用于源代码管理的 GitHub 集成(VSCode 扩展)
· SQLAlchemy ORM/Flask 和 JSON API 开源库
· 基于角色的访问控制的声明式安全性
· 使用 YAML 模型支持 React-Admin 和 Angular UI
· 用于构建和部署容器的 Docker 工具
· 行为测试驱动工具
· 所有 API 端点上的乐观锁定(可选)
· 开源(无许可证问题)组件
· 访问 Python 库以实现可扩展性
API 模型生命周期
数据库优先
随着利益相关者和最终用户与系统交互,每个应用程序都会发生变化。反馈越早,就越容易修改和测试结果。第一个源模型是 SQL 模式:缺少属性、外键查找、数据类型更改、默认值和约束需要重建 ORM。 ApiLogicServer 使用命令行功能“从数据库重建”来重建 SQLAlchemy ORM 模型和各种 UI 工具使用的 YAML 文件。此方法需要 SQL 知识来定义表、列、键、约束和插入数据。 GenAI 功能将允许采用迭代和增量方法来构建数据库,但最终需要真正的数据库开发人员来完成这项工作。
模型优先(GenAI)
SQLAlchemy 的一个有趣功能是能够修改 ORM 和重建SQL 数据库。如果它是一个没有现有数据的新应用程序,这可能很有用。这就是 GenAI 开箱即用的工作方式:它将要求 ChatGPT 构建 SQLALchemy ORM 模型,然后从该模型构建数据库。这对于原型和快速解决方案似乎非常有效。 GenAI 可以创建模型并填充小型 SQLite 数据库。如果系统已有数据,则添加列或新表进行聚合需要更多的努力和 SQL 知识。
虚拟列和关系
有许多用例阻止开发人员“接触”数据库。 这要求框架能够声明虚拟列(如check_sum乐观锁定)和虚拟关系来定义实体之间的一对多和多对一关系。 SQLAlchemy 和 ALS 支持这两个功能。
自定义API定义
有许多用例需要不直接映射到 SQLAlchemy 模型的 API 端点。 ApiLogicServer 提供了一个可扩展框架来定义和实现新的 API 端点。此外,有些用例需要以适合消费者的方式格式化 JSON 响应(例如,嵌套文档)或对简单 JSON API 无法支持的结果进行转换。这可能是 ALS 的最佳功能之一:自定义用户端点的可扩展性。
LogicBank:声明性逻辑
规则以易于理解的 DSL 编写,以支持派生 ( formula、sums、counts、parent copy)、约束 ( reject when) 和事件。规则可以使用 Python 函数进行扩展(例如,调用 Kafka 生产者的提交事件)。可以在不知道操作顺序的情况下添加或更改规则(如电子表格);规则对依赖实体和字段的状态更改起作用。这些 LogicBank 规则可以使用 Copilot 部分生成,用于公式、求和、计数和约束。有时,引入总和和计数需要添加父表和关系来存储列聚合。
Python
Rule.formula(derive=LineItem.Total, as_expression=lambda row: row.UnitPrice * row.Quantity)
Rule.copy(derive=LineItm.UnitPrice, from_parent=Product.UnitPrice)
活动
这是开发人员可以将业务和 API 事务与外部系统集成的点。事件应用于实体(early、row、commit或flush),并且与 Kafka 代理的现有集成演示了如何使用触发事件来生成消息。这也可以用于与工作流程系统连接。例如,如果commit在 上使用该事件Order,则当所有规则和约束完成(并且成功)时,将调用提交事件并使用 Python 函数发送邮件、生成 Kafka 消息或调用另一个微服务 API 来船order。
Python
def send_order_to_shipping(row: models.Order, old_row: models.Order, logic_row: LogicRow):
""" #als: Send Kafka message formatted by OrderShipping RowDictMapper
Format row per shipping requirements, and send (e.g., a message)
NB: the after_flush event makes Order.Id available.
Args:
row (models.Order): inserted Order
old_row (models.Order): n/a
logic_row (LogicRow): bundles curr/old row, with ins/upd/dlt logic
"""
if (logic_row.is_inserted() and row.Ready == True) or \
(logic_row.is_updated() and row.Ready == True and old_row.Ready == False):
kafka_producer.send_kafka_message(logic_row=logic_row,
row_dict_mapper=OrderShipping,
kafka_topic="order_shipping",
kafka_key=str(row.Id),
msg="Sending Order to Shipping")
Rule.after_flush_row_event(on_class=models.Order, calling=send_order_to_shipping)
声明式安全模型
使用像 KeyCloak 这样的单点登录将返回身份验证,但可以根据用户定义的角色声明授权。每个角色都可以拥有读取、插入、更新或删除权限,并且角色可以将角色的特定权限授予特定实体 (API),甚至应用行级筛选权限。这种细粒度的方法可以在开发生命周期中随时添加和测试。
Python
DefaultRolePermission(to_role = Roles.public, can_read=True, ... can_delete=False)
DefaultRolePermission(to_role = Roles.Customer, can_read=True, ... can_delete=True)
# customers can only see their own account
Grant( on_entity = models.Customer,
to_role = Roles.customer,
filter = lambda : models.Customer.Id == Security.current_user().id)
总结
ApiLogicServer (ALS) 和 GenAI 支持的开发改变了微服务应用程序的部署。 ALS 具有适合大多数开发人员的特性和功能,并且基于开源组件。 LogicBank 需要以不同的方式思考数据,但投资是减少编写代码的时间。 ALS 非常适合需要 API 并能够构建自定义前端用户界面的数据库事务系统。 模型驱动开发是实现 GenAI 支持的应用程序的方式,ALS 是开发人员/顾问提供这些解决方案的平台。