SAP云应用编程模型(CAP)是一个用于构建企业级应用的编程框架。它引导开发人员沿着经过验证的最佳实践的“黄金路径”以及丰富的开箱即用解决方案来构建应用。
与过度专注于技术细节相反,基于CAP的项目主要通过关注快速的业务实现而实现价值。
CAP框架采用一系列经过验证且广泛采用的开源和SAP技术,如下图所示。
在开源技术基础上,CAP主要增加了以下内容:
将代码与技术栈解耦 → 保护投资
今天的技术发展太快,新的技术可能很快就会过时,如何与这样的时代保持同步是一个重大挑战。CAP通过更high level的概念和API来避免了和特定技术的锁定,这些概念和API在很大程度上抽象了底层功能和协议。特别是在以下方面:
这些抽象使我们能够在不影响应用程序代码的前提下迅速适应新技术,从而保护投资。
CAP是开放的 → 无绑定
这听起来可能矛盾,但并非如此:虽然CAP在不牺牲开放性和灵活性的情况下提供最佳实践,但您仍然可以自由选择技术栈,或者选择以下的技术架构。
抽象,避免和底层锁定的高级概念和API :所有抽象都遵循玻璃箱模式,允许访问底层事物
开箱即用的最佳实践,为许多重复任务提供通用解决方案:您始终可以使用 custom handlers 来用自己的方式处理事务,例如决定是否采用读写分离或事件溯源开发框架,CAP做的只是减少您的工作量。
对SAP Fiori和SAP HANA的开箱即用支持:您也可以选择其他数据库和其他前端技术,如Vue.js等。
在SAP Business Application Studio、Visual Studio Code或Eclipse中提供的专用工具支持:CAP不依赖于这些工具。在CAP中可以使用@sap/cds-dk CLI脚手架和任何。
关键概念和范式
以下部分突出了CAP的关键概念,这些概念基于两个主要范式:
CAP专注于业务知识和意图,而非代码本身 — 意味着关注“什么”,而不是“如何” — 从而促进:
下图说明了常见的CDS数据模型(在左侧),这些模型为CAP服务运行时或数据库提供动力。
核心数据服务(CDS) :
CDS是我们的通用建模语言,以概念上、简洁且可理解的方式来描述静态和动态属性,它是CAP的支柱。
CDS中的Model:
entity Books : cuid {
title : localized String;
author : Association to Authors;
}
entity Orders : cuid, managed {
descr : String;
Items : Composition of many {
book : Association to Books;
quantity : Integer;
}
}
Domain Models描述静态属性方面,类似实体关系ER模型。
Associations 描述关系。Compositions 扩展了Association,帮助我们轻松建模文档结构。
Annotations 允许使用额外的元数据来丰富模型,例如用于UI、验证、输入验证或授权的元数据。
CDS Aspects
extend Books with @restrict: [ { grant:'WRITE', to:'admin' } ];
extend Books with { ISBN : String };
extend Orders with { customer_specific : String };
Aspects 允许灵活扩展模型。此外还能分离标准内容和自定义内容。
Node.js和Java中的CAP运行时从SAP应用程序中提炼并提供了许多通用的实现,加速开发,减少样板代码,提高代码质量。
以下是通用功能的摘录:
自动提供请求
处理重复任务
企业最佳实践
CAP中所有数据访问都是动态的,基于实时数据的方法与对象关系映射ORM形成鲜明对比
核心查询语言(CQL)
CQL是CDS的高级查询语言。它使用元素轻松查询深度嵌套的对象图和文档结构。例如,这是CQL中的一个查询:
sql SELECT ID, addresses.country.name from Employees
相同语义的纯SQL:
sql SELECT Employees.ID, Countries.name FROM Employees
LEFT JOIN Addresses ON Addresses.emp_ID=Employees.ID
LEFT JOIN Countries AS Countries ON Addresses.country_ID = Countries.ID
Queries(CQN)
orders = await SELECT.from (Orders, o=>{
o.ID, o.descr, o.Items (oi=>{
oi.book.title, oi.quantity
})
})
// 通过Odata
GET .../Orders?$select=ID,descr
$expand=Items(
$select=book/title,quantity
)
Queries可以使用CQN作为纯对象符号直接发送给本地服务,通过诸如OData或GraphQL的协议发送给远程服务,或者发送给将其转换为本机数据库查询以进行优化执行的数据库服务。
设计态的Projection
// CDS中的Projection
service OrdersService {
define entity OrderDetails
as select from Orders {
ID, descr, Items
}
}
我们还在CDS中使用CQL声明底层模型的非规范化视图,例如在定制服务API中。
CAP中的所有行为都是基于服务和事件的概念,就像此清单中表达的:
所有活动的事物都是服务 — 本地的、远程的,以及数据库
服务在CDS中声明 — 反映并在通用服务提供者中使用
服务提供统一的API — 被其他服务或前端使用
服务对事件作出响应 — 包括同步和异步API
服务消费其他服务 — 在事件处理程序实现中
所有数据都是被动的 — 即没有自己的行为,遵循REST
CAP中的服务都是无状态且具有最小功能范围的,这使您可以将解决方案模块化为微服务或函数即服务。
CAP的六边形架构
CDS中的服务定义
// CDS中的服务定义
service OrdersService
{ entity Orders as projection on my.Orders;
action cancelOrder (ID:Orders.ID);
event orderCanceled : { ID:Orders.ID }
}
服务在CDS模型中声明,用于自动提供能力。它们以entities、actions和events的形式来描述模型的行为。
统一消费
// JavaScript中的服务消费
let srv = cds.connect.to('OrdersService')
let { Orders } = srv.entities
order = await SELECT.one.from (Orders).where({ ID:4711 })
srv.cancelOrder (order.ID)
// 通过REST API进行消费
GET /orders/Orders/4711
POST /orders/cancelOrder/4711
CAP中的所有动态的事务都是服务,包括本地服务或远程服务 — 即使数据库也是服务的一部分。
所有服务都为编程式消费提供统一的API。因此代码和底层协议完成了解耦。
普遍事件
// 服务实现
cds.service.impl (function(){
this.on ('UPDATE','Orders', (req)=>{})
this.on ('cancelOrder', (req)=>{})
})
// 发送事件
// 例如,在this.on ('cancelOrder', ...) 中
let { ID } = req.data
this.emit ('orderCancelled', {ID})
// 订阅事件
let srv = cds.connect.to('OrdersService')
srv.on ('orderCancelled', (msg)=>{})
在CAP中,一切都是对事件的响应。CAP具有普遍的事件概念,表示通过同步API进入的请求以及异步事件消息。
我们在event handlers中添加自定义逻辑,用于实现服务操作。同样,我们可以订阅由其他服务发出的异步事件。
如果对CAP有更多兴趣,可以尝试完成CAP入门练习,基于nodejs和sqlite来快速开发一个书店应用
关于本文内容有任何问题或见解,欢迎在评论区留下你的想法,如果时间紧迫,也可以直接联系到我 [email protected],感谢你的时间