1. 为什么我建议你把 Analyzing the Findings 当主战场,而不是 SCI 结果
1.1 自定义代码分析和 Code Inspector 的定位完全不同
很多 ABAP 顾问第一次听说"自定义代码分析"时,第一反应是"这不就是运行一遍 Code Inspector(事务代码 SCI)看一眼错误列表吗"。真不是。SCI 关注的是代码质量:性能、命名规范、语法、安全漏洞,属于"你写得好不好"的问题。而 S/4HANA 迁移背景下的自定义代码分析,关注的是"你写的东西在新的业务标准下还能不能用"。它在检查清单里装的不是普通语法检查,而是"用法类(usage)"检查:哪些自定义代码还在读一个字段已经变短的表、还在调用一个已经被删除的事务代码、还在使用一个接口签名已经变化的 BAPI。
这个区别决定了结果的处理方式完全不同。SCI 的报错,你改掉就好了;自定义代码分析的每一条 finding,往往需要你去翻简化清单(Simplification Item)、找对应的 OSS Note、确认这个用法在新环境里到底会报错还是只是行为变化,然后决定是改代码、加豁免、还是原封不动保留。我见过不少团队把这两件事混在一起,拿处理 SCI 结果的心态去扫自定义代码分析结果,最后要么改了一堆其实不用改的代码,要么漏掉了真正会挡上线的问题。
1.2 一条 finding 里到底藏了哪些信息
打开 Analyzing the Findings 页面,列表里每一行你看到的字段,都比表面上看起来的信息量多得多。一条典型的 finding 至少包含这几位"主角":
- 检查名称(Check):比如"Usage of changed database tables",它决定了你要去哪一类 Note 里找答案。
- 对象信息(Object):程序名、类名、函数组名,以及代码所在行号。
- 使用类型(Usage Type):是访问了表、调用了函数模块、使用了事务代码,还是继承了某个类。
- 消息文本(Message):这里是最容易被忽略的。很多人只看对象名和行号就跳到代码里去了,其实消息文本里通常会直接告诉你"这个表在新的数据结构中不再包含字段 X"或者"这个函数模块的接口参数 Y 已被删除"。
- 风险等级:有的工具按"非常关键/关键/一般/提示"分,有的按"必须调整/建议调整/可忽略"分。
我自己的习惯是先把列表的表头全部展开看一遍,再根据消息文本做第一次分类,而不是一上来就按行号钻代码。2019 年我第一次正式在迁移预分析里面对两千多条 findings 时,就是吃了"看到哪条点哪条"的亏,半小时过去还在前十行打转,后来才总结出这套先看字段、再读文本、最后定位代码的顺序。
2. 图表先读大局:数量、分布、严重度,三件事别只盯着一样
2.1 打开页面先看图表按检查类型的分布
Analyzing the Findings 的图表区通常会用饼图或条形图展示 findings 按检查类型、按风险等级或按组件的分布。大部分人的操作是:看一眼"总数 3126 条",然后掏手机拍照发群里。正确的读法应该是先问自己三个问题:哪些检查类型最多?这些检查类型对应的业务区域是哪里?每条 finding 是"一批代码里的重复出现"还是"某个孤立的致命用法"?
举个真实的例子。我参与过一个项目,图表里"Usage of changed database tables"占了全部 findings 的 63%,看起来非常吓人。但点进去之后发现,其中接近八成都是同一个物料凭证相关的数据读取逻辑,被一个全厂通用的 Z 函数反复调用。也就是说,真正需要处理的根因只有一个函数模块,其余全是它的调用点。如果你只看那张饼图的外圈标题,很容易启动一场"大会战",把十几个顾问派下去逐条改,结果改了半天发现全是对同一个函数的机械改动。
2.2 风险等级分布图的读法,关键是类型叠加
风险等级分布图我不建议只看红色块的大小。红色块大,可能只是检查阈值定得宽松导致的"泛红",比如很多工具把"访问了发生结构变化的表"一律标为关键,但其中有些表在兼容视图下依然能正常工作;红色块小也不代表没事,一条"调用已删除函数模块"的 finding 一旦命中,可能就是生产环境一个主流程直接起不来。
所以我把风险等级和"使用类型"放在一起看。使用类型里,我最警惕的是这三类:
| 使用类型 | 典型风险表现 | 建议处理顺序 |
|---|---|---|
| 删除的事物代码(Deleted Transaction) | 用户点击后直接无反应或报 Tcode not found | 最高优先级,逐条核查 |
| 接口参数被删除的 BAPI / 函数模块(Changed Interface) | 编译可能通过,但运行时传入参数失效或行为变化 | 高优先级,对照简化清单 |
| 字段被移除的读写逻辑(Deleted / Changed Field) | 返回空值、报字段不存在,或者数据被系统忽略 | 高优先级,需确认替代字段 |
这个习惯帮我在两个项目里避过大坑,一次是批次确定相关 BAPI,一次是清账相关 BAPI,它们在图表上都是毫不起眼的小色块,但最后恰恰是需要最多人天处理的点。
2.3 图表和列表是联动的,点一下比反复输入过滤条件快
以图表做"粗筛",再通过点击某个色块让列表联动收敛,要比你反复手工输入过滤条件高效得多。先点风险等级里的红色块,看完整列表按消息文本去重;再点检查类型里的某一项,看这个类型下的明细是不是都指向同一个对象。这个动作熟练之后,一份三千条的 findings 列表,我大概十五分钟就能在心里排出处理顺序:先动哪几个对象、哪些可以批量处理、哪些需要发邮件给功能顾问确认。
图表的价值不在于"截个图发周报",而在于帮你在第一分钟建立全局认知。反复点击的过程不是浪费时间,它是在不知不觉地训练你对"哪些问题成片出现、哪些问题孤立存在"的敏感度。
3. 过滤器才是提升效率的主战场
3.1 我最常用的几组过滤维度
过滤器用得好不好,直接决定你是"逐条看三千条"还是"只看该看的八十条"。以下是我在每个项目里都会用到的维度,按优先级排列:
- 对象类型:先看 finding 落在程序、类、函数组、包含段里的分布。包含段(Include)的 finding 需要单独小心,因为一个 include 会被很多主程序引用。
- 包 / 软件组件:按包名把结果分给你团队里的不同模块负责人,这几乎是必做的第一步。
- 检查名称:按"检查"过滤,可以把同一类问题的全部出现位置集中到一起。
- 风险等级 / 适应性相关性:第一轮只处理最高风险。
- 消息文本关键字:比如搜"field"、"deleted"、"no longer",快速找到真正要改的。
- 分配人(Responsible)与会签状态:如果你们用了团队任务分配的话。
3.2 一组实战过滤组合:把上千条筛到几十条
我实际用的过滤组合大致是这样:先把"风险等级"设为最高一档;再把包范围限定为自定义包,排除掉外购的、标准化的软件组件;然后按检查名称把数量最大的一类收进去,在消息文本里搜索"no longer"或"deleted"这类关键词。这一套下来,我印象里最典型的一次是从 2400 多条直接收敛到 46 条,剩下这 46 条才是我认为真正需要逐条打开代码看的。
这里有个经验:过滤条件之间要尽量用"收敛型"逻辑,而不是"排除型"逻辑。排除型过滤容易把一些你不熟悉的第三方包一起排除掉,但你根本不知道那些包里会不会有你自己写过并被打包进去的代码。收敛型的过滤是从"只看自己团队维护的包"开始的,风险可控得多。等第一轮处理完,再回过来单独审视那些被排除的第三方包,逐个确认它们是否来自外部供应商、是否需要联系厂商。
3.3 保存视图和导出给团队
大多数分析页面支持把当前过滤条件保存成视图。我建议按角色保存几套固定视图:"我的包-最高风险"、"全部-待评估"、"第三方包-仅查看"这几个。起名字要有信息量,不要叫"视图1""视图2",否则下次你自己都不记得哪个是哪个。视图的作用是让团队所有人用同一套口径看问题,避免两个人因为过滤条件不同而争论"为什么你那边显示 46 条、我这边显示 800 条"。
另外,列表一定要导出到本地表格再分发。代码修改的工作不能全部在页面里完成,你总需要给几个 ABAP 顾问一人一份带行号、带对象名、带风险等级的工作清单。导出之后,建议保留两列:一列是"责任人与状态",另一列是"备注/决定"。这两列很快会变成你们后续周会上的核对依据。到了项目后期,你会发现这份表格本身就是很好的审计底稿。
4. 从一条 Finding 到一行代码:钻取、分析、闭环
4.1 学会读消息文本里的"根因提示"
一条 finding 的消息文本,相当于检查器手写给你的诊断依据。比如它会写类似这样的内容:
Form ZXXX_F01 uses transaction code MB1A which is not supported in the target release.
The database table MSEG does not contain field BWTAR in the expected structure; your code reads the field directly.
看懂这句话,你面对代码时就知道要找什么了。不懂这句诊断时,我一般会做三件事:第一,打开对应的 OSS Note 或简化清单条目,看它建议的替代对象;第二,去标准代码里搜一下替代对象在哪些地方被调用,学习标准用法;第三,在隔离测试环境里用新数据直接跑一遍这个程序,看错误信息是不是和 Note 描述一致。这三件事做完,一条 finding 的"要不要改、怎么改"基本就有结论了。
不要跳步。我见过有人不看消息文本就直接打开代码,结果对着一个完全正常的取数逻辑研究了半天,最后才发现消息文本里说的是"这个函数模块在新的总账里已经废弃"。消息文本本来就是给你节省时间的,别自己把它浪费掉。
4.2 钻取到代码时两条容易卡住的情况
钻取本身很简单,点一下 finding 就能在编辑器里看到对应行被高亮。但实际项目里有两类情况特别容易卡住:
第一种是 finding 落在包含段(Include)里。你看到的对象名可能不是一个程序,而是某个 include,行号高亮的代码也在 include 里。这时候你需要的是"谁在用这个 include",而不是"这个 include 是哪一行写错了"。用一个 where-used 列表把引用 include 的主程序全查出来,再判断哪些属于你的业务范围。如果这个 include 被二十个程序使用,你修一处等于修二十处,但一旦修错影响面也是二十倍,所以改完要安排集成的回归测试。
第二种是函数组的 finding。函数组里往往没有独立的"主程序",它的 top include 和各个功能模块的 include 会被前后台调用。如果 finding 落在函数组里,先定位到具体的函数模块,再看这个函数模块被哪些程序调用,避免你改了代码却影响了一大片原本正常的功能。
提示:遇到这两类情况,先把"调用链"画清楚再动手。画调用链可以用标准工具,不依赖额外的插件。
4.3 处理归类:改代码、加豁免、还是转给功能顾问
一条 finding 看完代码之后,我通常归到四类:
- 真的需要改:接口变了、表结构变了、字段退役了,只能换成新 API。
- 可以豁免:兼容模式下还能用,或者这次升级没有激活某个功能导致检查规则误报,记录理由后豁免。
- 转功能顾问:涉及业务判断,典型的就是"这个报表在 S/4 里应该用哪个标准报表替代""批次确定策略要不要改"这类问题。
- 重复/合并:同一根因在多处重复出现,处理一处即可。
归类不是拍脑袋。我建议每一条都留痕,尤其是在豁免理由上。你能说清楚"为什么豁免"和"为什么在这里豁免",项目审计和上线后复查时都会感激你。相反,如果只是随手点一下"忽略"而不写理由,三个月后没有任何人能解释这条当初为什么被忽略,出了问题只能重新排查。
5. 几个典型场景:结合大家平时搜得多的 SAP 话题
5.1 MD04、MD07 相关自定义报表:别急着改表读逻辑
这两年大家在群里搜"md04怎么看""md07"的频率一直很高。在自定义代码分析结果里,和 MD04、MD07 相关的 finding 通常长这样:你的自定义报表直接读了库存/需求汇总相关数据,或者调用了老的库存需求列表接口。新版本里这部分数据逻辑变动很大,老读法在新环境里很容易出现行为差异,尤其是把库存、需求、批次、序列号混在一起查的自定义报表,分析结果通常会给出一堆相关表访问的 finding。
我处理过的一个案例,是一个按物料显示可用数量的 Z 报表,分析结果里挂着几十条对相关数据源的访问 finding。很多人第一反应是"把表名改掉"。正确的做法是先去核实简化清单建议的替代对象,再想清楚你这个报表的输入输出在新的库存需求体系里对应的是哪个标准流程。改错了表名,程序照样会蹑手蹑脚跑下去,但数字会不对,比编译失败更难发现,而且容易在月末对账时才爆雷。
5.2 序列号状态、报工倒冲和批次确定:最容易"只改成功一半"的地方
序列号状态(比如 EDEL 这类交货状态)的更新逻辑、报工倒冲自动指定批次,这两个话题也是 ABAP 群里高频搜索词。它们在自定义代码分析里的典型形态,是 BAPI 或函数模块接口变化导致的 finding,比如调用生产订单确认类 BAPI 但没有传批次确定所需参数,或者序列号状态更新的标准函数已经换了。
这种 finding 最坑的地方在于:大概率编译是通的,运行也不报错,但结果不对。比如报工倒冲时没有指定批次,系统可能给你随机选一个批次,或者干脆不生成批次凭证。处理这类 finding,我强烈建议让对应的 PP 顾问一起坐下来看,不要只靠 ABAP 侧改代码。你改了调用参数,但业务上到底期望哪个批次确定策略,不是代码能替你回答的。在一个汽车零部件项目里,我们就是因为只改了 BAPI 调用、没跟 PP 顾问对齐批次规则,导致上线后的第一周倒冲批次大面积错乱。
5.3 采购、接口、清账与凭证相关:多留意字段退役和生成代码
采购订单含税价格、清账凭证冲销、MOM 与 SAP 接口这类话题,背后其实都是同一个主题:新版本里一大批字段和接口对象退役或变了行为。自定义代码分析里遇到"字段不存在"或"接口对象被删除"的 finding,多半就落在这些模块。
接口类(比如 SAP CPI、MOM 集成)的 finding 有一点特别值得注意:如果分析结果指向的是系统自动生成的代理类(SPROXY 生成的代码),千万不要手动改生成代码。正确做法是根据接口编号找到对应的代理对象,用标准机制重新生成。你手动在生成代码里打补丁,下一次重新生成时会全部覆盖,等于白改。判断是不是生成代码很简单:看对象的创建者是不是标准的代理生成器,或者看代码头部的生成标记。
清账、冲销这类凭证操作,老 BAPI 在新环境里可能还能调用,但行为有细微变化。我只提醒一点:处理这类 finding 之前,去核对一下相关 OSS Note 里列出的替代 BAPI 和新增参数,尤其注意有没有新增的过账相关字段。很多项目在这里栽跟头,不是没改代码,而是只改了百分之九十,漏掉的百分之十依然会把对账干掉。
6. 我在真实项目里总结的"结果解读套路"
6.1 两轮扫法:先按风险大扫一遍,再按包和检查精扫
第一轮我只看最高风险等级,并且只看消息文本中出现"deleted""no longer exists""does not contain"这类词的。这一轮目的是找硬伤——有没有流程直接跑不了。第二轮再回到图表区,把数量最大的检查类型展开,按包分配给模块负责人,做逐条代码审查。两轮不是并行的,第一轮的结果会直接影响第二轮的处理优先级。比如第一轮发现某个生产确认相关 BAPI 已经彻底失效,我会第一时间通知 PP 和 MES 接口团队,而不是等他们按部就班排到下周四。
6.2 多次分析之间做对比,图表会告诉你有没有在变好
自定义代码分析不是做一次就完。通常团队会先跑一次全量分析,改完一批代码后再跑一次复查。复查的图表如果形态几乎不变,说明你改的地方和 findings 的重灾区没有对到点上;如果某个色块明显缩小,说明改动生效。这个对比过程比任何周报都有说服力。
做对比的时候记得固定过滤条件,比如都用同一个分析范围、同一个系统、同一套包,否则两张图根本没法比。我习惯在每次跑批前把导出的列表文件名带上日期和分析编号,格式就是"CCA_YYYYMMDD_rev01.xlsx"这种,时间久了你能看到一条清晰的收敛曲线。
6.3 误判、重复和"看起来要改但其实不用改"的坑
静态分析工具天然有误判,这是所有做代码分析的人的共识。自定义代码分析同样如此。常见误判包括:代码路径里其实已经做了新老判断、表的兼容视图仍然保留、调用的是标准替代对象但检查器没识别出来。所以永远不要在没看代码前就把一条 finding 标记为"已处理"。
处理误判的正确姿势是加豁免而不是改代码。我在项目里看到过最危险的操作,是有人为了"清零 findings"而把标准取数逻辑改成自定义逻辑,结果造成了更大的兼容性问题。记住,分析结果的最终目标不是让数字归零,而是让所有剩余 findings 都有明确理由和结论。数字归零的项目也可能成为一颗定时炸弹,因为有些问题不是靠改代码能解决的,而是要靠业务决策。
6.4 最后一个习惯:把图表截图、视图名、导出版本一起放进项目文档
每次分析跑完,我会在项目共享目录里保留三样东西:图表区的整体截图、保存的过滤视图清单、导出的原始列表。这三样东西是后续做简化清单核对、上线前复核、审计准备的底稿。很多项目事后发现漏改了一个冷门程序,回头查的时候发现当时的"分析结果"早就不知道丢到哪个文件夹里去了,只能重新跑一遍分析,白白浪费一两天。
我个人在实际操作中的体会是:Analyzing the Findings 这个页面真正考验的不是你懂多少技术,而是你能不能从一堆机器生成的条目里快速判断哪些是人话。图表给你全局,过滤器给你视角,钻取给你证据,最终拍板的是你结合业务场景的判断力。把上面这套流程固定下来,任何一次新跑批你都能在半天内给出让项目组信服的结论。