模型驅(qū)動(dòng)的開發(fā)和測(cè)試
憑借數(shù)十年的經(jīng)驗(yàn),我喜歡為公司構(gòu)建企業(yè)應(yīng)用程序。每個(gè)解決方案都需要一組模型:SQL 數(shù)據(jù)庫、API(應(yīng)用程序編程接口)、聲明性規(guī)則、聲明性安全性(基于角色的訪問控制)、測(cè)試驅(qū)動(dòng)的場景、工作流和用戶界面。 “元”設(shè)計(jì)方法需要考慮每個(gè)組件如何與其他組件交互。我們還需要了解項(xiàng)目范圍的變化如何影響每個(gè)元組件。雖然我使用過許多不同的語言(APL、Revelation/PICK、BASIC、Smalltalk、Object/1、Java、JavaScript、Node.js、Python))這些模型始終是影響最終綜合解決方案的基礎(chǔ)。模型是元抽象,描述對(duì)象的形狀、內(nèi)容和能力在運(yùn)行環(huán)境中的行為方式,而與語言、平臺(tái)或操作系統(tǒng) (OS) 無關(guān)。
模型優(yōu)先方法
從現(xiàn)有的 SQL 架構(gòu)和良好的 ORM 開始,可以抽象數(shù)據(jù)庫并生成 API。我一直在使用ApiLogicServer(一個(gè)由 GenAI 驅(qū)動(dòng)的 Python 開源平臺(tái)),它有一個(gè)命令行界面來連接主要的 SQL 數(shù)據(jù)庫并創(chuàng)建 SQLAlchemy ORM(對(duì)象關(guān)系模型)。從這個(gè)模型中,創(chuàng)建了一個(gè)用于 JSON API 的開放 API(又名 Swagger),并且一個(gè) YAML 文件(模型)驅(qū)動(dòng)了一個(gè) react-admin 運(yùn)行時(shí)。 YAML 文件還用于構(gòu)建 Ontimize ( Angular ) 用戶界面。請(qǐng)注意,ApiLogicServer 的 GenAI 部分允許我使用提示驅(qū)動(dòng)的方法,僅使用幾個(gè)關(guān)鍵字即可獲取整個(gè)運(yùn)行堆棧。
命令行工具
CLI(命令行界面)用于創(chuàng)建新的 ApiLogicServer (ALS) Python 項(xiàng)目,連接到 SQL 數(shù)據(jù)庫,使用 KeyCloak 進(jìn)行單點(diǎn)登錄身份驗(yàn)證,如果數(shù)據(jù)庫發(fā)生更改,則重建 SQLAlchemy ORM,從API 等等。構(gòu)建 API 的大部分工作都是由 CLI 完成的,映射表和列,處理數(shù)據(jù)類型、默認(rèn)值、列別名、帶引號(hào)的標(biāo)識(shí)符以及父/子表之間的關(guān)系。這個(gè)工具的真正威力在于你看不到的東西。
構(gòu)建 Northwind 演示的命令行:
Markdown
als create --project-name=demo --db-url=nw+
開發(fā)者視角
作為一名開發(fā)人員/顧問,我需要多個(gè)框架和一組工具來構(gòu)建和交付完整的微服務(wù)解決方案。 ApiLogicServer 是一個(gè)與開發(fā)人員合作的框架,通過低代碼和 DSL(領(lǐng)域特定語言)服務(wù)來增強(qiáng)和擴(kuò)展這些不同的模型。
· 帶有調(diào)試器的 VSCode 是絕對(duì)必要的。
· 用于代碼完成和代碼生成的 Copilot
· Python (3.12) 開源框架和庫
· Kafka集成(生產(chǎn)者和消費(fèi)者)
· 用于單點(diǎn)登錄的 KeyCloak 框架
· LogicBank 聲明式規(guī)則引擎與 ORM 模型和所有 CRUD 操作集成
· 用于源代碼管理的 GitHub 集成(VSCode 擴(kuò)展)
· SQLAlchemy ORM/Flask 和 JSON API 開源庫
· 基于角色的訪問控制的聲明式安全性
· 使用 YAML 模型支持 React-Admin 和 Angular UI
· 用于構(gòu)建和部署容器的 Docker 工具
· 行為測(cè)試驅(qū)動(dòng)工具
· 所有 API 端點(diǎn)上的樂觀鎖定(可選)
· 開源(無許可證問題)組件
· 訪問 Python 庫以實(shí)現(xiàn)可擴(kuò)展性
API 模型生命周期
數(shù)據(jù)庫優(yōu)先
隨著利益相關(guān)者和最終用戶與系統(tǒng)交互,每個(gè)應(yīng)用程序都會(huì)發(fā)生變化。反饋越早,就越容易修改和測(cè)試結(jié)果。第一個(gè)源模型是 SQL 模式:缺少屬性、外鍵查找、數(shù)據(jù)類型更改、默認(rèn)值和約束需要重建 ORM。 ApiLogicServer 使用命令行功能“從數(shù)據(jù)庫重建”來重建 SQLAlchemy ORM 模型和各種 UI 工具使用的 YAML 文件。此方法需要 SQL 知識(shí)來定義表、列、鍵、約束和插入數(shù)據(jù)。 GenAI 功能將允許采用迭代和增量方法來構(gòu)建數(shù)據(jù)庫,但最終需要真正的數(shù)據(jù)庫開發(fā)人員來完成這項(xiàng)工作。
模型優(yōu)先(GenAI)
SQLAlchemy 的一個(gè)有趣功能是能夠修改 ORM 和重建SQL 數(shù)據(jù)庫。如果它是一個(gè)沒有現(xiàn)有數(shù)據(jù)的新應(yīng)用程序,這可能很有用。這就是 GenAI 開箱即用的工作方式:它將要求 ChatGPT 構(gòu)建 SQLALchemy ORM 模型,然后從該模型構(gòu)建數(shù)據(jù)庫。這對(duì)于原型和快速解決方案似乎非常有效。 GenAI 可以創(chuàng)建模型并填充小型 SQLite 數(shù)據(jù)庫。如果系統(tǒng)已有數(shù)據(jù),則添加列或新表進(jìn)行聚合需要更多的努力和 SQL 知識(shí)。
虛擬列和關(guān)系
有許多用例阻止開發(fā)人員“接觸”數(shù)據(jù)庫。 這要求框架能夠聲明虛擬列(如check_sum樂觀鎖定)和虛擬關(guān)系來定義實(shí)體之間的一對(duì)多和多對(duì)一關(guān)系。 SQLAlchemy 和 ALS 支持這兩個(gè)功能。
自定義API定義
有許多用例需要不直接映射到 SQLAlchemy 模型的 API 端點(diǎn)。 ApiLogicServer 提供了一個(gè)可擴(kuò)展框架來定義和實(shí)現(xiàn)新的 API 端點(diǎn)。此外,有些用例需要以適合消費(fèi)者的方式格式化 JSON 響應(yīng)(例如,嵌套文檔)或?qū)唵?JSON API 無法支持的結(jié)果進(jìn)行轉(zhuǎn)換。這可能是 ALS 的最佳功能之一:自定義用戶端點(diǎn)的可擴(kuò)展性。
LogicBank:聲明性邏輯
規(guī)則以易于理解的 DSL 編寫,以支持派生 ( formula、sums、counts、parent copy)、約束 ( reject when) 和事件。規(guī)則可以使用 Python 函數(shù)進(jìn)行擴(kuò)展(例如,調(diào)用 Kafka 生產(chǎn)者的提交事件)??梢栽诓恢啦僮黜樞虻那闆r下添加或更改規(guī)則(如電子表格);規(guī)則對(duì)依賴實(shí)體和字段的狀態(tài)更改起作用。這些 LogicBank 規(guī)則可以使用 Copilot 部分生成,用于公式、求和、計(jì)數(shù)和約束。有時(shí),引入總和和計(jì)數(shù)需要添加父表和關(guān)系來存儲(chǔ)列聚合。
Python
Rule.formula(derive=LineItem.Total, as_expression=lambda row: row.UnitPrice * row.Quantity)
Rule.copy(derive=LineItm.UnitPrice, from_parent=Product.UnitPrice)
活動(dòng)
這是開發(fā)人員可以將業(yè)務(wù)和 API 事務(wù)與外部系統(tǒng)集成的點(diǎn)。事件應(yīng)用于實(shí)體(early、row、commit或flush),并且與 Kafka 代理的現(xiàn)有集成演示了如何使用觸發(fā)事件來生成消息。這也可以用于與工作流程系統(tǒng)連接。例如,如果commit在 上使用該事件Order,則當(dāng)所有規(guī)則和約束完成(并且成功)時(shí),將調(diào)用提交事件并使用 Python 函數(shù)發(fā)送郵件、生成 Kafka 消息或調(diào)用另一個(gè)微服務(wù) 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 這樣的單點(diǎn)登錄將返回身份驗(yàn)證,但可以根據(jù)用戶定義的角色聲明授權(quán)。每個(gè)角色都可以擁有讀取、插入、更新或刪除權(quán)限,并且角色可以將角色的特定權(quán)限授予特定實(shí)體 (API),甚至應(yīng)用行級(jí)篩選權(quán)限。這種細(xì)粒度的方法可以在開發(fā)生命周期中隨時(shí)添加和測(cè)試。
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)
總結(jié)
ApiLogicServer (ALS) 和 GenAI 支持的開發(fā)改變了微服務(wù)應(yīng)用程序的部署。 ALS 具有適合大多數(shù)開發(fā)人員的特性和功能,并且基于開源組件。 LogicBank 需要以不同的方式思考數(shù)據(jù),但投資是減少編寫代碼的時(shí)間。 ALS 非常適合需要 API 并能夠構(gòu)建自定義前端用戶界面的數(shù)據(jù)庫事務(wù)系統(tǒng)。 模型驅(qū)動(dòng)開發(fā)是實(shí)現(xiàn) GenAI 支持的應(yīng)用程序的方式,ALS 是開發(fā)人員/顧問提供這些解決方案的平臺(tái)。