mcpField
C
clean-abap

clean-abap

github.com/likweitan测试与质量7257 次安装2 周前更新
代码仓库

关于 clean-abap

clean-abap 是一项按 Clean ABAP 原则检查 ABAP 代码的技能。它按主题整理问题、标注影响级别,并提供带代码示例的改进建议。

主要功能

  1. 01检查 15 类 Clean ABAP 规范
  2. 02按主题归类问题
  3. 03按影响程度确定优先级
  4. 04提供代码示例和修正建议
  5. 05参考附带的风格指南

适用场景

  1. 01检查 ABAP 代码风格问题
  2. 02发现过时的 ABAP 语言模式
  3. 03改进命名与方法设计
  4. 04评估可测试性和错误处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/likweitan/abap-skills --skill clean-abap

安装后在 Claude Code 中输入/clean-abap确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
checklist.md
CleanABAP.md
quick-reference.md

详细介绍

Clean ABAP

此技能依据 Clean ABAP 风格指南,对照其中的原则全面检查 ABAP 代码。该指南将 Robert C. Martin 的 Clean Code 原则应用于 ABAP。

如何使用此技能

检查 ABAP 代码是否符合 Clean ABAP 规范时:

  1. 阅读用户提供的代码
  2. 按 Clean ABAP 章节对问题进行分类(名称、语言、常量、变量、表、字符串、布尔值、条件、IF 语句、类、方法、错误处理、注释、格式、测试)
  3. 在条件允许时,指出违规之处并提供具体行号
  4. 提供可执行的改进建议,并通过代码示例展示问题和整洁的解决方案
  5. 按影响程度对问题进行优先级排序(严重、主要、次要)

检查类别

1. 名称

核心原则:

  • 使用能表达内容和含义的描述性名称
  • 优先使用解决方案领域和问题领域中的术语
  • 使用易于发音的名称
  • 始终使用 snake_case
  • 除非必要,否则避免缩写
  • 类使用名词,方法使用动词
  • 避免在名称中使用 "data"、"info"、"object" 等无意义词语
  • 为每个概念选用一个词
  • 避免编码式命名(匈牙利命名法,以及 iv*、rv*、lt_ 等前缀)
  • 避免使用容易与内置函数混淆的名称

检查以下问题:

  • 变量、方法或类的名称缺乏描述性(例如,data1、temp、x)
  • 代码中缩写使用不一致
  • 命名风格混用(未采用 snake_case)
  • 名称中包含无意义词语
  • 使用匈牙利命名法或不必要的前缀(iv*、ev*、rv*、lt*、ls_)
  • 方法名称容易与 ABAP 内置函数混淆
2. 语言

核心原则:

  • 面向对象编程优于过程式编程
  • 函数式语言结构优于过程式语言结构
  • 避免使用过时的语言元素
  • 合理使用设计模式

检查以下问题:

  • 使用过时语句(如 SELECT 中未转义的宿主变量等)
  • 本应采用面向对象方式实现的过程式代码
  • 使用旧式 MOVE,而非赋值
  • 使用 TRANSLATE,而非 to_upper()/to_lower()
  • 使用 CREATE OBJECT,而非 NEW
  • 使用旧式 READ TABLE,而非表表达式
3. 常量

核心原则:

  • 使用常量代替魔法数字
  • 常量应使用描述性名称
  • 优先使用 ENUM,而非常量接口
  • 将相关常量归组

检查以下问题:

  • 代码中出现魔法数字或字符串字面量
  • 常量名称缺乏描述性(c_01、c_x 等)
  • 未归组的常量本应放在 BEGIN OF/END OF 块中
4. 变量

核心原则:

  • 优先使用内联声明,而非预先声明
  • 不要在声明块之外使用变量
  • 不要链式预先声明
  • 现代 ABAP 中不要使用字段符号动态访问数据
  • 选择合适的循环目标(字段符号、引用或值)

检查以下问题:

  • 使用预先 DATA 声明,而内联声明会更清晰
  • 在声明块作用域之外使用变量
  • 链式 DATA 声明
  • 使用 ASSIGN 时存在不必要的字段符号
5. 表

核心原则:

  • 使用合适的表类型(STANDARD、SORTED、HASHED)
  • 避免使用 DEFAULT KEY
  • 优先使用 INSERT INTO TABLE,而非 APPEND TO
  • 优先使用 LINE_EXISTS,而非 READ TABLE 或 LOOP AT
  • 优先使用 READ TABLE,而非 LOOP AT
  • 优先使用 LOOP AT WHERE,而非嵌套 IF
  • 避免不必要的表读取

检查以下问题:

  • 表使用 DEFAULT KEY
  • 在 INSERT INTO TABLE 更合适时使用 APPEND TO
  • 使用 READ TABLE ... TRANSPORTING NO FIELDS,而 LINE_EXISTS 会更清晰
  • 使用 LOOP AT ... EXIT,而实际意图是 READ TABLE
  • LOOP AT 内嵌套 IF,而 WHERE 子句即可实现
  • 重复读取(先检查是否存在,随后再次读取)
6. 字符串

核心原则:

  • 使用 `(反引号)定义字符串字面量
  • 使用 |(管道符)拼接文本

检查以下问题:

  • 使用单引号表示字符串字面量
  • 使用 && 拼接字符串,而非字符串模板
7. 布尔值

关键原则:

  • 布尔类型使用 ABAP_BOOL
  • 比较时使用 ABAP_TRUE 和 ABAP_FALSE
  • 使用 XSDBOOL 设置布尔变量
  • 考虑布尔值是否合适(与枚举相比)

检查项:

  • 使用 CHAR1 或其他类型代替 ABAP_BOOL
  • 使用 'X' 和 ' ' 比较,而不是 ABAP_TRUE/ABAP_FALSE
  • 使用 IF-THEN-ELSE 设置布尔值,而不是 XSDBOOL
  • 应拆分为多个方法的布尔参数
8. 条件

关键原则:

  • 尽量使用肯定条件
  • 优先使用 IS NOT,而不是 NOT IS
  • 对于返回布尔值的方法,考虑使用谓词式调用
  • 考虑分解/提取复杂条件

检查项:

  • 可以改为肯定条件的否定条件
  • 使用 NOT IS,而不是 IS NOT
  • 应当分解的复杂嵌套条件
  • 应当提取到方法中的冗长条件
9. If 语句

关键原则:

  • 不要有空的 IF 分支
  • 有多个选项时,优先使用 CASE,而不是 ELSE IF
  • 尽量减少嵌套层级

检查项:

  • 仅在 ELSE 中包含逻辑的空 IF
  • 应改为 CASE 的多个 ELSE IF
  • 嵌套过深的 IF 语句(>3 层)
10. 类

关键原则:

  • 优先使用对象,而不是静态类
  • 优先使用组合,而不是继承
  • 不要在同一个类中混用有状态和无状态逻辑
  • 默认使用全局类,仅在合适时使用本地类
  • 如果类并非为继承而设计,则使用 FINAL
  • 成员默认设为 PRIVATE,仅在需要时使用 PROTECTED
  • 考虑使用不可变数据代替 getter

检查项:

  • 应基于实例而非静态的类
  • 过深的继承层次结构
  • 混用有状态和无状态方法
  • 并非为继承而设计但未设为 FINAL 的类
  • 应设为 PRIVATE/PROTECTED 的 PUBLIC 成员
  • 获取不可变数据的不必要 getter 方法
11. 方法

关键原则:

  • 优先使用实例方法,而不是静态方法
  • 公有实例方法应实现接口
  • 尽量减少 IMPORTING 参数(<3 个)
  • 拆分方法,而不是使用 OPTIONAL 参数
  • 恰好使用一个 RETURN、EXPORT 或 CHANGE 参数
  • 优先使用 RETURNING,而不是 EXPORTING
  • 只做一件事,并把它做好
  • 保持方法简短(理想情况下为 3-5 条语句)
  • 尽早失败
  • 尽可能省略 RECEIVING、EXPORTING 关键字
  • 调用实例成员时省略自引用 ME

检查项:

  • 应改为实例方法的静态方法
  • 不属于接口的公有方法
  • IMPORTING 参数超过 3 个的方法
  • 多个 OPTIONAL 参数(应拆分方法)
  • 多个输出参数
  • 使用 EXPORTING,而不是 RETURNING
  • 过长的方法(>20 行)
  • 执行多项任务的方法
  • 不必要的 RECEIVING、EXPORTING 关键字
  • 显式 ME-> 调用
12. 错误处理

关键原则:

  • 优先使用异常,而不是返回码
  • 使用基于类的异常
  • 可处理的异常抛出 CX_STATIC_CHECK
  • 不可恢复的情况抛出 CX_NO_CHECK
  • 优先使用 RAISE EXCEPTION NEW,而不是 RAISE EXCEPTION TYPE
  • 包装外部异常

检查项:

  • 使用返回码,而不是异常
  • 使用消息类处理错误
  • 使用旧式的 RAISE EXCEPTION TYPE
  • 未包装的外部异常
  • 捕获通用的 CX_ROOT
13. 注释

关键原则:

  • 用代码表达意图,而不是注释
  • 不要用注释为糟糕的命名开脱
  • 写注释解释原因,而不是内容
  • 注释使用 ",而不是 *
  • 删除代码,而不是将其注释掉
  • 使用 FIXME、TODO、XXX 时附上你的 ID
  • ABAP Doc 仅用于公有 API

检查项:

  • 解释代码作用的显而易见的注释
  • 用注释弥补糟糕的命名
  • 被注释掉的代码
  • 使用 - 注释,而不是 "
  • 不带 TODO/FIXME 标签的注释
  • 注释中的手动版本管理
  • 注释中重复的消息文本
14. 格式

核心原则:

  • 激活前使用 ABAP Formatter
  • 每行最多一条语句
  • 行长适中(120 个字符)
  • 用单个空行分隔(不多于一个)
  • 在行尾闭合括号
  • 单参数调用保持在一行内
  • 缩进并对齐到制表符

检查以下内容:

  • 每行包含多条语句
  • 行长超过 120 个字符
  • 存在多个连续空行
  • 缩进不一致
  • 链式赋值
15. 测试

核心原则:

  • 编写可测试的代码
  • 测试公有部分,而非私有内部实现
  • 使用 given-when-then 结构
  • 断言数量少且聚焦
  • 使用恰当的断言类型

检查以下内容:

  • 代码不可测试(耦合紧密、未使用依赖注入)
  • 测试缺少清晰的 given-when-then 结构
  • 存在多个无关的断言
  • 公有方法缺少测试类

输出格式

按以下结构组织分析:

# Clean ABAP Check Results

## Summary
- Total Issues: [count]
- Critical: [count]
- Major: [count]
- Minor: [count]

## Critical Issues

### [Category] - [Issue Title]
**Location:** Line [X] / Method [name]
**Problem:** [Description of what violates Clean ABAP]
**Recommendation:** [How to fix it]

**Anti-pattern:**
```abap
[problematic code]

整洁代码:

[improved code]

重大问题

[与“严重问题”格式相同]

次要问题

[与“严重问题”格式相同]

优点观察

  • [符合 Clean ABAP 的良好做法]

总体评估

[简要总结代码质量和主要改进领域]


## Priority Levels

**Critical:** Issues that significantly impact maintainability, testability, or could cause bugs
- Magic numbers without constants
- Deep nesting (>3 levels)
- Methods with >5 parameters
- Empty IF branches
- Static classes without interfaces
- Return codes instead of exceptions

**Major:** Issues that reduce code clarity and violate Clean ABAP principles
- Non-descriptive names
- Hungarian notation/prefixes
- Long methods (>20 lines)
- DEFAULT KEY usage
- Commented-out code
- Multiple output parameters

**Minor:** Issues that are stylistic improvements
- Missing inline declarations
- String quotes instead of backticks
- Unnecessary ME-> references
- Formatting inconsistencies

## References

When you need detailed explanations or examples for specific Clean ABAP rules, consult these reference files:

1. **Complete Guidelines**: Read `references/CleanABAP.md` - the full Clean ABAP style guide with in-depth explanations, rationale, and code examples for all principles
2. **Quick Patterns**: Read `references/quick-reference.md` - condensed good/bad code examples for common patterns
3. **Review Checklist**: Read `references/checklist.md` - a checklist format for systematic code reviews

**When to consult references:**
- To provide accurate citations when explaining violations
- To show users the official reasoning behind recommendations
- To find specific code examples to illustrate points
- To answer follow-up questions about Clean ABAP principles
- When encountering edge cases not covered in the summary above

## Examples

### Example 1: Checking a Simple Method

**Input:**
```abap
METHOD calculate.
  DATA: lv_result TYPE i,
        lv_temp TYPE i.

  lv_temp = iv_value1 + iv_value2.
  IF lv_temp > 100.
    lv_result = lv_temp * 2.
  ELSE.
    lv_result = lv_temp.
  ENDIF.

  ev_result = lv_result.
ENDMETHOD.

输出:

# Clean ABAP Check Results

## Summary
- Total Issues: 4
- Critical: 0
- Major: 2
- Minor: 2

## Major Issues

### Names - Hungarian Notation Used
**Location:** Method calculate
**Problem:** Variables use Hungarian notation prefixes (lv_, iv_, ev_) which adds no value and violates Clean ABAP naming guidelines.
**Recommendation:** Remove prefixes and use descriptive names.

**Anti-pattern:**
```abap
DATA: lv_result TYPE i,
      lv_temp TYPE i.

整洁代码:

DATA(result) = value1 + value2.
IF result > 100.
  result = result * 2.
ENDIF.
方法——使用 EXPORTING 而非 RETURNING

位置: 方法签名 问题: 方法使用 EXPORTING 参数而非 RETURNING,无法采用函数式调用风格。 建议: 对单个输出值使用 RETURNING 参数。

反模式:

METHOD calculate
  IMPORTING iv_value1 TYPE i
            iv_value2 TYPE i
  EXPORTING ev_result TYPE i.

整洁代码:

METHOD calculate
  IMPORTING value1 TYPE i
            value2 TYPE i
  RETURNING VALUE(result) TYPE i.

次要问题

变量——提前声明

位置: 第 2-3 行 问题: 变量提前声明,导致声明与使用之间间隔较远。 建议: 使用 DATA( ) 进行内联声明。

语言——过程式风格

位置: 第 5-9 行 问题: 可以使用 COND 进行条件赋值,而非 IF-ELSE。 建议: 使用函数式结构。

整洁代码:

METHOD calculate
  IMPORTING value1 TYPE i
            value2 TYPE i
  RETURNING VALUE(result) TYPE i.

  DATA(sum) = value1 + value2.
  result = COND #( WHEN sum > 100 THEN sum * 2 ELSE sum ).
ENDMETHOD.

总体评估

代码可以正常运行,但使用了过时的 ABAP 模式。主要改进方向:移除匈牙利命名法,使用 RETURNING 代替 EXPORTING,优先采用内联声明,并使用函数式语言结构。完成这些更改后,代码将更加整洁且易于维护。

评论

支持 Markdown