本地落地 ABAP Cloud:不买 BTP 也能实现 Clean Core 实战指南
最近不少朋友问我同一个问题不买 SAP BTP还能不能在本地 SAP 系统里搞 ABAP Cloud走向 Clean Core我理解他们背后的焦虑——云战略喊得响但预算、合规、存量系统迁移成本都摆在那里直接上云不现实。我自己的答案是可以而且本地落地 ABAP Cloud 不是权宜之计是一条独立的技术路线。这篇就把我实际踩过的坑、验证过的策略以及那些 SAP 官方文档里不会写清楚的细节掰开揉碎讲一遍。先说清楚什么叫 Clean Core。它不是云专属概念核心思想很简单让标准系统保持“干净”把客户定制代码从内核里剥离出来放到清晰的扩展层里这样升级时不会冲突创新时不用翻旧账。过去我们习惯直接在标准表上加字段、在标准函数里改逻辑系统越用越“脏”升级一次痛一次。Clean Core 要求我们用官方扩展点、用 RAP 开发模型、用合适的伙伴对象来写扩展而不是碰标准代码。这些约束在本地 S/4HANA 里同样能做到甚至某些方面比云端更灵活。这篇文章面向的读者是那些暂时没有 BTP 预算或者因为数据驻留、网络隔离、系统架构原因必须维持在本地环境的开发者和架构师。如果你正准备新启动一个 S/4HANA 项目或者正在为老系统做升级评估这篇内容可以帮你省掉大量试错时间。1. 为什么要在本地系统谈 Clean Core1.1 Clean Core 不是云专属SAP 官方把 ABAP Cloud 定义为一种开发模型强调三件事第一开发对象必须支持云就绪也就是能在 Steampunk 技术栈上运行第二必须使用标准的扩展点不能修改 SAP 交付的代码第三通过 RAP 统一开发业务逻辑和接口。这套模型最早和 BTP 绑定给人感觉好像只有上云才能用。但实际上ABAP Cloud 的开发规范和 Clean Core 原则可以完全在你的本地 S/4HANA 系统里落地只要你的系统版本满足条件。我见过很多企业误以为“不上云就谈不上 Clean Core”结果继续在标准系统里乱改等到要升级到新版本时才发现一堆增强点和隐式增强因为代码冲突无法激活。实际上SAP 从 S/4HANA 2020 左右开始就在本地系统里提供了足够的工具和框架来支持云开发模式包括 RAP 标准的业务对象模型、基于 CDS 的数据建模、以及通过“业务添加-自定义字段”等功能实现扩展。这些能力不依赖任何 BTP 订阅只需要你愿意改变开发习惯。所以本地落地 Clean Core 的第一步是从思想上把“云”和“ABAP Cloud”解耦。ABAP Cloud 是一种开发范式BTP 只是一个可选的运行环境。就像跑步机是运动工具户外跑步也能达到健身效果关键是你跑不跑。1.2 本地落地的实际驱动为什么非要本地搞我遇到的主要有几种情况。第一种是成本控制。BTP 按用量计费尤其是云平台的标准订阅、消息流量、数据库存储长期下来是一笔不小的支出。很多企业的 SAP 系统使用率已经固定为了几个扩展功能每年付云平台费用财务上过不去。更容易出的方案是把开发模型本地化保留未来迁移云端的可能性但当下不付费。第二种是数据合规与网络隔离。有些企业因为行业监管要求核心业务数据必须留在自有数据中心或者整个网络环境不允许外部连接。BTP 作为公有云服务很难满足这类要求。本地系统反而能完全掌控数据流该隔离的隔离该日志审计的日志审计。第三种是现有架构整合。很多传统企业已经在本地部署了一整套 SAP 生态包括各个模块、中间件和周边系统。如果为了 ABAP Cloud 强行引入 BTP等于又多了一个需要集成、监控、运维的平台。在本地系统里统一开发标准反而是最平滑的整合方式。明确驱动之后你需要判断自己的系统版本和升级路径。如果当前还在 ECC 6.0建议先把基础版本升级到 S/4HANA 2021 及以上否则很多云开发功能不可用。如果已经在 S/4HANA 2020 以上可以直接开始改造。2. 本地 ABAP Cloud 的架构基础与选型2.1 ABAP Cloud 开发模型的三个支柱在动手前需要把 ABAP Cloud 开发模型的底层逻辑理解透。它有三个支柱CDS 数据模型、RAP 行为模型、以及在 Fiori 层上的服务暴露。CDSCore Data Services用于定义数据模型。它和传统 ABAP 数据字典最大的区别在于它直接在数据库层做建模通过注解实现语义补充生成的 SQL 更高效还能自动暴露 OData 服务。CDS 是 ABAP Cloud 的数据基础几乎所有新开发都应该从 CDS 开始而不是先建透明表。RAPABAP RESTful Application Programming Model定义了基于 CDS 的实体、行为、服务如何组合。它把 CRUDQ 操作、校验、权限、事件等统一到行为定义里。在本地系统里你可以用 RAP 创建一个完整的 Fiori 应用也可以发布一个服务给外部系统调用。RAP 最大的好处是强制你在业务逻辑和服务接口之间做清晰分层不会像传统报表那样把所有代码堆在一个 ABAP 程序里。第三个支柱是服务暴露。RAP 定义的服务模型可以绑定到 OData 协议上前端 Fiori、SAP 集成套件、第三方系统都能消费。本地系统里可以通过事务代码 SEGW 或直接在 RAP 里发布不需要额外中间件。2.2 在本地复现 BTP 能力的替代路径BTP 上常见的服务包括身份认证、工作流、业务规则、日志分析等。本地落地 ABAP Cloud 时这些能力可以由 ABAP 环境自身或配套组件替代关键是别指望功能完全对等。身份认证BTP 的 IAS/IPS 可以由本地 S/4HANA 自带的 Fiori 框架和网关认证机制替代。如果你有 SSO 需求直接配 Kerberos 或 SAML 到企业自己的 IdP效果可能更好因为完全内网可控。工作流BTP 的工作流服务实例化程度高但 S/4HANA 本身还有经典工作流ArchiveLink Workflow以及新的“可维护工作流”功能。后者是基于云就绪模型可以在测试环境里建模。如果流程复杂度不高用本地工作流引擎足够。业务规则BTP 的规则服务可以拆到 S/4HANA 的 BRFplus 中。BRFplus 从旧版本就有一直维护到现在的 S/4HANA可以定义决策表、表达式和规则集且能在 RAP 行为逻辑里直接调用。日志和监控BTP 上的 SaaS 应用日志可以用本地系统的事务代码 SLG1 和 ST05 替代甚至更熟悉。重点是别为了“云原生”去托管一个没有实际收益的额外平台。我的建议是先列出在 BTP 上计划使用的所有组件再到本地 S/4HANA 上找对应的替代品做一次能力映射。如果映射后发现某些服务确实无法替代再考虑是否要让该模块保持本地空转或者用轻量中间件调用外部服务。2.3 适合本地落地的目标系统形态并不是所有本地系统都适合直接做 ABAP Cloud 开发。我根据项目经验建议按以下优先级排序最理想的是全新的 S/4HANA 私有云或本地部署系统从项目第一天就用 Clean Core 原则建立代码治理框架。这样没有任何历史包袱扩展开发全部走 RAP测试传输从开始就规范。事实上SAP 官方的“Clean Core”参考架构就是针对这种绿色地带的。第二档是已有的 S/4HANA 系统但还没有被严重改脏。系统里可能有一些自定义表和增强但核心流程仍可用标准功能。这类系统适合用“逐步侵蚀”策略先把新需求全部用 RAP 开发再慢慢把旧的自定义代码迁移到扩展层。第三档是遗留 ECC 或自定义非常多且混乱的 S/4HANA。这种情况不考虑直接做本地 Clean Core 大改造而是先建立标准和限制清单只允许新增对象不允许修改标准对象。然后用接口或迁移方式逐渐把核心业务往标准功能上靠。你需要意识到这种情况下“本地 ABAP Cloud”是长远目标不是短期冲刺。我自己更推荐从“新增开发全用 ABAP Cloud”开始因为存量改造的复杂性远超预期。先保证新代码不脏再逐步消化存量。3. 存量改造与新增开发的分层策略3.1 先态后势划分代码边界本地系统的代码构成通常三类SAP 标准代码、合作伙伴代码、客户自有代码。我们要做的就是让后两者不侵入第一类。这里最核心的实践是“划分代码边界”。我具体做法是用软件包Package强制分层。比如设计一个客户扩展根包ZALL ZALL_CORE - 所有 CDS/RAP 业务对象 ZALL_DT - 所有数据字典扩展 ZALL_IF - 服务接口 ZALL_UI - Fiori 相关配置 ZALL_UTILS - 工具类然后给每个包设置“仅允许创建”的访问控制关键字。这样从物理上阻止开发人员在标准包里创建对象。除了包结构还可以用 Transport Layer 区分开发对象。点击软件包属性里的“传输层”将客户扩展包绑定到自定义传输层上和 SAP 标准传输层分离。这样升级时传输请求不会交叉也能清晰看到哪些是客户包。在代码边界上我还建议启用“增强点”和“隐式增强”的管控。SAP 在标准代码里提供了大量显式增强点指标准程序里预留给客户的扩展按钮。开发规范里强制优先使用显式增强点实在没有才允许用隐式增强而且隐式增强必须单独建立增强项目并登记。本地系统里可以使用事务代码 SEOG 管理增强实施。维护得当的话升级时这些增强都能自动识别。3.2 用 RAP 替代经典对话事务本地系统里大量现有事务比如报表、维护界面都是基于经典 ABAP 屏幕的。这些程序不是不行但很难满足 Clean Core 的“云就绪”要求。新开发我不建议再用 Module Pool而是直接以 RAP 为核心。一个具体场景客户要求做一个“销售人员维护客户价格清单”的新功能。传统做法是建表、写屏幕、写 PBO/PAI 逻辑。RAP 做法是第一步定义 CDS 视图作为数据根。AccessControl.authorizationCheck: #CHECK EndUserText.label: 客户价格 Metadata.ignorePropagatedAnnotations: true define root view entity ZI_CustomerPriceList as select from ztc_price as p association [1..1] to I_Customer as _Customer on _Customer.Customer p.Customer { key p.Customer as Customer, key p.Product as Product, p.Price as Price, p.ValidFrom as ValidFrom, p.ValidTo as ValidTo, _Customer.CustomerName as CustomerName }第二步在这个 CDS 上定义行为实现类通过FOR UPDATE、FOR CREATE等标注来控制权限和验证。这些行为定义在 ABAP 开发环境里是标准的不依赖任何外部服务。第三步把 business object 暴露为服务绑定到 OData 协议。前端可以配 Fiori Elements或者用第三方工具通过 OData 直接读写。这样整个应用的业务逻辑都放在后端行为类里结构清晰测试性好也符合 RAP 的规范。RAP 不是只能做简单 CRUD。行为定义里可以写确定、验证、动作、函数甚至触发后续事件。比如价格修改后写审计日志可以在 RAP 的Save阶段做而不需要动标准表。值得花时间学习它的行为交互模型这会让你的代码质量比传统方式高一个等级。3.3 扩展字段与自定义逻辑的官方通道本地系统里最常见的“脏”就是在标准表上乱加字段。比如给材料主数据表加一个“物流组”很多人直接在表上追加 includes或直接改表结构。正确的做法是利用自定义字段框架。S/4HANA 里事务代码SFW5开启相关业务功能后通过扩展字段Customer Fields功能添加字段。这个框架会自动在相关的 CDS 视图和 UI 模型上同步字段保证后续升级时合并冲突最小。它不是直接改标准表而是建立一个扩展字段表并在运行时按逻辑关联SAP 官方会维护这个机制兼容性最好。如果需要在标准功能上增加自定义业务逻辑优先使用 BAdI业务插件实现。SAP 标准流程几乎都预留了 BAdI 接口比如物料主数据的保存、销售订单的创建、凭证校验等等。找到合适的 BAdI在里面挂钩子比直接增强方法更安全。举个例子我们曾有一个需求创建销售订单时必须根据自定义汇率表重新计算价格。直接在标准函数里改代码必挂。后来用了销售订单创建主流程的 BAdI 之一在完成创建后、保存前调用我们的 ABAP Cloud 类逻辑通过自定义日志记录。整个改造没有触碰标准代码升级时一挂即过。这个过程中需要维护一个“扩展清单”列出所有的自定义字段、BAdI 实施、隐式增强。后续升级前可以用这个清单做影响分析提前发现不兼容变更而不是等到激活报错才哭。4. 实操落地关键步骤与工具链4.1 项目启动前的基线评估在开始写任何代码之前先给系统做一次全面的“健康检查”。这个项目能不能顺利推进完全取决于你对现状的理解有多清楚。首先梳理当前系统的 S 版本补丁级别。使用事务代码SAP_BASIS_INFO或SUIM查看系统版本。注意 ABAP Cloud 模型的完整支持依赖于较新的内核版本尤其是 RAP 相关功能。如果系统还在 2020 以下建议先升级内核和组件至少到 SP 02 以上。其次运行事务代码SE08查询系统代码目录搜索所有对标准表中的直接修改。用SLIN或代码分析器检查 ABAP 对象质量重点看是否使用了MODIFY、INSERT对 SAP 数据字典对象的直接操作是否存在自定义函数覆盖标准函数。这些是“脏”的集中地。建议把结果输出到一个电子表格中为每个问题对象标注“建议方案”迁移到 RAP、用 BAdI 替代、删除废弃代码、保留并隔离。这会形成项目改造的完整 backlog。最后检查一下传输请求系统。如果原来客户对象混在标准传输层里需要尽早分离。你可以创建一个自定义传输层把所有客户开发对象调整到这个层里。这个动作越早做越好因为一旦业务代码变多调整传输层会影响导入顺序。4.2 开发对象的迁移与创建前面提到新开发全部走 RAP。但已经存在的 ABAP 报表、函数模块和类怎么处理我的经验是不需要一次全部迁移。你可以先确立一个“RAP 优先”原则然后在每个业务需求迭代中把相关的旧对象逻辑替换掉。具体操作时首先为每个旧功能创建一个新的 RAP 对象例如用 CDS 视图替代旧的 SQL 查询用行为类替代旧函数模块中的写入逻辑。然后在新的 UI 层暴露 OData 服务并把旧程序的入口隐藏或废弃。整个过程可以并行运行直到旧程序无人使用后删除。迁移时注意一点不要在 RAP 的 CDS 里使用旧的自定义表结构。如果表结构本身很乱先把它规范化。规范的规则包括主键明确、时间戳字段使用ABP_LAST_CHANGED_AT、所有字段都加描述标签、全部使用 CamelCase 命名。这些细节决定后续维护时是否清晰。为了快速创建 RAP 对象你可以在 ADTABAP Development Tools里使用项目模板。选择Fiori项目模板可以生成 CDS、行为定义、服务定义和工程基本结构。我习惯在本地先写 CDS再生成行为再在 Eclipse 里调服务整个链路比 SE80 舒服许多。4.3 构建、测试与传输ABAP Cloud 项目非常依赖自动化测试。本地系统没有 BTP 的 CI/CD 服务但你可以自建或者用系统自带的工具。在构建环节使用GCTSGit 版 CTS可以把传输请求和 Git 仓库绑定这样每一次开发提交都会留 Git 记录。如果你没有 Git 服务器也可以在本地用 ADT 的Check功能做静态检查。更重要的是把 ATCABAP Test Cockpit检查嵌入开发流程。ATC 可以按 Clean Core 规则检查某个对象是否符合云就绪标准比如是否使用不推荐语句、是否有安全问题。每次开发完成后运行事务代码ATC选择相关对象集查看检查结果。如果你在开发过程中不断解决 ATC 提示项目推进到后期会非常顺畅。否则到了验证阶段再拉着一堆 RED 状态的问题去逐条解释那是灾难。传输环节依然走 CTS。建议每个 RAP 对象都打成一个独立的传输请求并且请求说明里写明关联的业务场景。这样出问题时可以通过请求号快速定位影响范围。同时在SE01里维护传输层的依赖关系确保传入测试系统时按正确的顺序导入。5. 常见的坑与避坑清单5.1 命名空间和软件包管理的坑很多团队在刚做 ABAP Cloud 时对命名空间不重视开发对象全都放在默认的$TMP或标准包Z下随意建对象。这导致后期清理时根本分不清哪些是正式对象哪些是测试残留。我建议从一开始就定义清晰的命名规则所有开发对象必须以Z或Y开头且最好包含业务模块缩写。例如销售客户对象以ZSD开始财务以ZFI开始主数据以ZMD开始。在包结构里为每个模块建一个主包下面建子包子包再按“DT、BO、UI”划分。这样给你的后续维护带来极大便利。还有个大坑是包类型和传输层的匹配。如果你不小心把客户对象建到了标准包SAP下传输请求会混入标准请求升级时会冲突。发现这类情况需要用事务代码SE03把对象从标准包里转出。这个操作本身容易出问题所以最稳妥的办法是新开发前先建立好完整包结构并给团队做一次强制培训。5.2 版本升级与兼容性的坑本地系统最大的优势是完全可控但升级依然是不可避免的。Clean Core 的最终目的就是在升级时不出冲突。实际过程中最常遇到的坑是 CDS 视图与数据库表的版本兼容。S/4HANA 的 CDS 视图基于数据库表的动态字段列表。如果标准 CDS 视图在升级中增加了新字段而你的自定义扩展视图没有同步调整会导致激活失败。这个问题的典型解法是不要创建“扩展视图”去复制标准视图内容而是使用extend view的能力通过扩展视图添加自己的字段和关联。本地系统里这种扩展方式兼容性好升级时通常能自动合并。另一个兼容性坑是隐式增强。隐式增强在旧版本里允许你给标准方法添加任意代码但新版本内核在每次升级后都会检查这些增强是否仍然兼容。如果增强引用了标准方法签名中已经被改过的参数升级时就报错。解决方法是尽量少用隐式增强尤其不要在关键接口上用。非要使用也得把增强代码的粒度做小逻辑集中在自定义类里不要直接在增强里写复杂业务。5.3 团队技能与流程的坑很多项目在技术上走对了但团队还停留在旧开发模式导致代码风格混乱、质量参差。比如有人仍然用WRITE输出报表、在 ABAP 里写 HTML、用旧 BDC 方式批量处理。这些代码虽然能跑但在 CDS 和 RAP 环境里就是“脏”。团队技能需要在项目开始时同步补课。我建议给团队统一安排 RAP 和 ADT 培训并建立“代码评审委员会”。每次传输请求入测试系统前必须由另一名熟悉 ABAP Cloud 的开发者做评审。你可以在 ADT 里配置“对象检查字号”将 ATC 检查设为强制执行只有检查结果无省略项才能释放请求。还有流程上的坑不要把所有扩展都堆在开发系统里而不做定期的“清扫”。每个迭代结束后把废弃请求和未选择的对象清理掉保持开发系统干净。否则到了升级测试阶段你会发现开发环境本身就乱得无法进行变更。5.4 性能与运行稳定性本地系统里使用 RAP 后代码结构更清晰但如果不注意性能依然会慢。CDS 视图的关联不能滥用。每个关联都会生成额外的 JOIN 或子查询如果关联层级过深性能会急剧下降。建议使用OData.publish: true的属性时只发布必要的服务避免把所有视图都暴露给 OData。RAP 行为类中的读写操作必须使用 EMLEntity Manipulation Language的现代语法而不要用MODIFY直接改表。EML 会自动处理锁和校验但你必须理解事务边界。我见过有同事在FOR MODIFY里对每个子记录单独写操作结果引起锁冲突。正确做法是先把数据收集到一个表再一次性调用 EML 批量处理。运行时稳定性方面要给本地系统开启 ABAP 日志和监控。使用事务代码SLGL打开 ABAP 运行日志记录 RFC 调用、更新任务和数据库操作。结合自定义的错误处理机制把每个 RAP 行为类的业务异常都抛给统一错误类处理。这样即使用户操作出现问题也能在日志里快速定位而不是随机报错后无从下口。6. 本地 Clean Core 的长期维护与演进6.1 持续合规的代码扫描本地系统需要建立周期性的代码扫描制度。我通常每个季度运行一次 ATC针对所有客户开发对象做一次云就绪检查输出不符合项然后制定整改计划。要让这个过程自动化可以用 ABAP 计划任务定期触发 ATC 检查并把结果发送到邮件列表。扫描的重点包括是否使用了不推荐的 ABAP 语句、是否有安全漏洞、是否引用了不存在的字段、是否违反了命名规范。通过定期扫描团队能时刻知道自己离 Clean Core 有多远。除了 ATC还要关注权限检查。RAP 的行为定义中要显式使用访问控制不要图方便让所有用户都能 OData 访问。你可以用 DCL数据控制语言为 CDS 视图定义权限逻辑这样在前端 Fiori 里会自动生效也不会因为误配置造成数据泄露。6.2 与未来云迁移的衔接最后聊一下本地 ABAP Cloud 和未来云迁移的关系。很多人担心本地做好了以后上云是否还得重做。我的回答是不会反而会轻松很多。因为 ABAP Cloud 的开发规范本质上是云兼容的。如果你的本地代码严格遵循 RAP、CDS、云开发检查规则并且所有扩展都使用标准通道那么未来迁移到 S/4HANA 公有云或私有云时这些对象都能原样运行或做非常少的调整。真正麻烦的是那些仍停留在旧开发模式的程序那才是迁移时的最大阻力。所以本地落地 ABAP Cloud 的意义不仅是解决眼前升级痛更是为未来云迁移保留了选择权。你现在做的每一步都在降低未来的技术债。我个人在实际操作中最深的体会是Clean Core 不是一次性完成的“项目”而是一个需要持续维护的规范。你可以把它当成一个长期习惯来培养最开始可能处处受限但坚持下来会发现系统的可维护性、交付速度、升级平滑度都会显著提升。如果你刚起步我建议先从一个小模块的 RAP 扩展开始走通全流程再逐步铺开。路虽然长但每一步都值得。