client/media/skills/clean-abap/SKILL.md
Clean ABAP coding standards and best practices. Use when writing ABAP code, reviewing ABAP code, or refactoring ABAP code to ensure it follows SAP's official Clean ABAP style guide. Covers naming conventions, modern language constructs, class/method design, error handling, formatting, comments, and unit testing patterns.
npx skillsauth add marcellourbani/vscode_abap_remote_fs clean-abapInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Distilled from the SAP Clean ABAP Style Guide. Licensed under Creative Commons BY 3.0. © SAP SE. Attribution preserved per license terms.
Apply ALL rules below when writing or reviewing ABAP code. Every rule is mandatory unless explicitly marked "consider".
customizing_entries not ce_tab.materials not material_tab.detection_object_types not dobjt.snake_case. When hitting length limits, abbreviate the least important words.
DATA max_response_time_in_millisec TYPE i.
is_ or has_.
CLASS /clean/account.
METHODS read_entries.
IF is_empty( table ).
account not account_data; user_preferences not user_info.read_*, never mix read_this with retrieve_that.iv_, rv_, lt_, etc.
" good
result = a + b.
" bad
rv_result = iv_a + iv_b.
condense, lines, strlen, etc.) with method names.FUNCTION check_business_partner [...].
DATA(validator) = NEW /clean/biz_partner_validator( ).
result = validator->validate( business_partners ).
ENDFUNCTION.
DATA(variable) = 'A'. " not MOVE
DATA(uppercase) = to_upper( str ). " not TRANSLATE
index += 1. " not ADD 1 TO
DATA(obj) = NEW /clean/cls( ). " not CREATE OBJECT
DATA(line) = value_pairs[ name = 'A' ].
@-escaped host variables in SQL:
SELECT * FROM spfli WHERE carrid = @carrid INTO TABLE @itab.
IF abap_type = cl_abap_typedescr=>typekind_date. " not 'D'
CONSTANTS status_inactive TYPE mmsta VALUE '90'. " not c_01
ENUM (7.51+) over constants interfaces:
TYPES: BEGIN OF ENUM type, warning, error, END OF ENUM type.
BEGIN OF ... END OF:
CONSTANTS:
BEGIN OF message_severity,
warning TYPE symsgty VALUE 'W',
error TYPE symsgty VALUE 'E',
END OF message_severity.
DATA(name) = 'something'.
DATA per variable — no chaining:
DATA name TYPE seoclsname.
DATA reader TYPE REF TO reader.
dref->* directly.ASSIGNING FIELD-SYMBOL(<line>) — read/modify in place (fastest).REFERENCE INTO DATA(line) — when references needed outside loop.INTO DATA(line) — when you need a copy.HASHED — large, filled once, read often by unique key.SORTED — large, filled incrementally, read by full/partial key.STANDARD — small tables, arrays, or mixed access.DEFAULT KEY. Use explicit keys or EMPTY KEY:
DATA itab TYPE STANDARD TABLE OF row_type WITH EMPTY KEY.
INSERT INTO TABLE over APPEND TO.line_exists( ) for existence checks:
IF line_exists( my_table[ key = 'A' ] ).
READ TABLE over LOOP AT ... EXIT for single-row retrieval.LOOP AT ... WHERE over nested IF inside LOOP.TRY.
DATA(row) = my_table[ key = input ].
CATCH cx_sy_itab_line_not_found.
RAISE EXCEPTION NEW /clean/not_found( ).
ENDTRY.
DATA(s) = `ABC`. Not single quotes.| | to assemble text:
DATA(msg) = |HTTP { status_code }: { text }|.
abap_bool as the type. Use abap_true/abap_false for comparisons — never 'X', ' ', or IS INITIAL.
DATA has_entries TYPE abap_bool.
IF has_entries = abap_false.
xsdbool( ) to set Booleans:
DATA(has_entries) = xsdbool( line IS NOT INITIAL ).
IS NOT over NOT IS, <> over NOT =.IF condition_is_fulfilled( ). " not = abap_true
CASE over ELSE IF chains.AND.FINAL unless designed for inheritance.PRIVATE by default. PROTECTED only for intentional subclass override.READ-ONLY attributes over getters:
DATA name TYPE string READ-ONLY.
NEW to CREATE OBJECT. Use CREATE OBJECT only for dynamic types.CREATE PRIVATE, keep CONSTRUCTOR in PUBLIC SECTION.CLASS-METHODS new_from_template IMPORTING template TYPE REF TO zcl_tmpl
RETURNING VALUE(result) TYPE REF TO zcl_doc.
CLASS-METHODS new_from_name IMPORTING name TYPE string
RETURNING VALUE(result) TYPE REF TO zcl_doc.
cl_my_class=>static_method( ). " not lo_instance->static_method( )
CALL METHOD only for dynamic dispatch.RECEIVING — capture return value directly.EXPORTING keyword.me-> unless resolving a scope conflict.PREFERRED PARAMETER sparingly.RETURNING over EXPORTING — enables functional style.RETURNING large tables is okay — don't prematurely switch to EXPORTING.RETURNING with EXPORTING/CHANGING.CHANGING sparingly — only for in-place updates.update_without_saving( ). " not update( do_save = abap_true )
update_and_save( ).
RESULT:
METHODS get_name RETURNING VALUE(result) TYPE string.
IF ... RETURN over CHECK. Use CHECK only at method start.CHECK inside loops — use IF + CONTINUE.MESSAGE e001(ad) INTO DATA(message). for where-used traceability.TRY/CATCH), not legacy EXCEPTIONS.CX_STATIC_CHECK for manageable expected exceptions.CX_NO_CHECK for usually unrecoverable situations.CX_DYNAMIC_CHECK only when caller controls whether it can occur.RAISE EXCEPTION NEW to RAISE EXCEPTION TYPE:
RAISE EXCEPTION NEW cx_gen_error( previous = exception ).
CATCH cx_amdp_failure INTO DATA(ex).
RAISE EXCEPTION NEW cx_generation_failure( previous = ex ).
", not *.FIXME, TODO, XXX with your user ID.##NEEDED) to pseudo comments ("#EC NEEDED).structure-type = 'A'.
structure-id = '4711'.
ltc_reads_entry, not ltc_test.FOR TESTING ABSTRACT global class.lth_* classes.cut (default) or meaningful name.cl_abap_testdouble over hand-written doubles:
DATA(mock) = CAST if_reader( cl_abap_testdouble=>create( 'if_reader' ) ).
cl_abap_testdouble=>configure_call( mock )->returning( value ).
LOCAL FRIENDS only for CREATE PRIVATE constructor access.reads_existing_entry, throws_on_invalid_key.'42', '?=/"&'.assert_equals, assert_false — not assert_true( xsdbool(...) ).fail( ) after CUT call for expected exceptions:
TRY.
cut->do_something( '' ).
cl_abap_unit_assert=>fail( ).
CATCH /clean/some_exception.
ENDTRY.
RAISING on the test method.development
Create SAP Data Workbooks (.sapwb) for SAP data analysis. Use when the user asks to analyze SAP data, create data quality checks, build reports, compare tables, profile data, or any multi-step SAP data exploration. Workbooks have ABAP SQL cells (queries against SAP) and JavaScript cells (process results). They save as files and can be re-run.
tools
Investigate SAP ADT REST API endpoints. Use when the user asks about ADT API endpoints, request/response XML formats, content types, or how a specific ADT feature works under the hood. Teaches how to trace from discovery documents → RES_APP classes → handler classes → Simple Transformations → XML schemas. Requires the adt_discovery_export tool output files and standard ABAP tools (get_abap_object_lines, search_abap_objects, search_abap_object_lines).
development
Generate a comprehensive SAP System Personality Report. Analyzes custom code landscape, functional footprint, development activity, health metrics, and package breakdown. Use when a user asks to characterize a system, understand a system, get a system overview, system report, system personality, or "what does this system do?" Collects data via SQL queries and presents results in a structured webview.
data-ai
Navigate and understand SAP Customizing (SPRO/IMG). Use when the user asks about customizing settings, SPRO activities, configuration tables, maintenance views, view clusters, or needs to read/understand any customizing data. This skill teaches how to systematically trace from an SPRO activity to the actual tables where config data is stored, and how to find the SPRO menu path for any activity. Load this skill whenever customizing, SPRO, IMG, configuration, or settings maintenance is involved.