BXUP Track progress & test yourself — free
Database & ERP · Hands-on lab · ~6 min read
DATABASE & ERP · HANDS-ON LAB

Lab 14 · ABAP modernization sprint

Modernize a synthetic legacy ABAP report with an AI assistant: plain-language explanation, dependency map, a remediation plan mapped to ATC-style findings, refactored code, and a generated unit-test list — with the before/after checklist run both ways. Two traps are planted: a refactor that breaks on an empty table, and a custom Z-table the AI will confidently explain without knowing anything about it.

Ramesh maintains a 2009-vintage ABAP estate at a Chennai auto-parts supplier heading for S/4HANA, and ZR_PLANT_STOCK_RPT is this sprint's specimen: a report everyone runs and nobody has dared touch since its author left. AI assistants are genuinely strong at ABAP archaeology — explaining, mapping, refactoring — and they carry one ERP-specific failure mode worth training against: your Z-tables and Z-logic exist nowhere in any training set, so the model invents plausible semantics for them with full confidence. This lab runs the whole modernization loop and makes you catch that invention in the act.

Time & tier

~90 minutes hands-on · Core tier (maps to module M7 · AI-Accelerated ERP Development, Testing & Migration). No SAP system required for the core path; an optional final step uses a free SAP BTP trial with Joule for Developers.

Setup

An AI chat assistant and a text editor, $0. The specimen, zr_plant_stock_rpt.abap — legacy on purpose, defects included:

REPORT zr_plant_stock_rpt.

TABLES: mara, marc.

DATA: BEGIN OF itab OCCURS 0,
        matnr LIKE mara-matnr,
        werks LIKE marc-werks,
        eisbe LIKE marc-eisbe,
        descr(40) TYPE c,
      END OF itab.

DATA: v_total TYPE i VALUE 0.

SELECT * FROM marc WHERE werks IN ('1100', '1200').
  MOVE marc-matnr TO itab-matnr.
  MOVE marc-werks TO itab-werks.
  MOVE marc-eisbe TO itab-eisbe.

  SELECT SINGLE maktx FROM makt INTO itab-descr
    WHERE matnr = marc-matnr AND spras = 'E'.

  SELECT SINGLE zregion FROM zmm_plant_map INTO itab-descr+30(10)
    WHERE zwerks = marc-werks.

  IF marc-eisbe > 500.
    APPEND itab.
    v_total = v_total + 1.
  ENDIF.
ENDSELECT.

LOOP AT itab.
  WRITE: / itab-matnr, itab-werks, itab-eisbe, itab-descr.
ENDLOOP.
WRITE: / 'Total high-stock items:', v_total.

And the ATC-style checklist, atc-checklist.md — ten findings to grade against, before and after:

[C1] SELECT ... ENDSELECT loop-processing on a database table
[C2] SELECT inside a loop (nested DB access per row)
[C3] SELECT * where a field list is needed
[C4] Internal table with header line (OCCURS / TABLES statement)
[C5] Hardcoded literals for org units (plant values in code)
[C6] Hardcoded language key
[C7] Magic number in business logic (threshold 500)
[C8] Classic WRITE list output (no ALV / no separation of logic and display)
[C9] Offset/length access into a character field (descr+30(10))
[C10] FOR ALL ENTRIES used without an initial-table guard  [after-only check]

Guided steps

  1. Run the before-checklist yourself. Grade zr_plant_stock_rpt.abap against C1–C9, quoting the offending line for each hit. Expected: nine findings out of nine applicable — this specimen fails everything it can fail. Save as the before column; the AI has not been consulted yet, deliberately: the checklist is your instrument, and you calibrate it before letting the model near the code.
  2. Get the plain-language explanation and dependency map. Paste the report and ask: "Explain what this report does, step by step, for a functional analyst. Then produce a dependency map: every table read, every field used, and what each table is." Expected quality: MARA/MARC/MAKT correctly identified (material master, plant data, descriptions — these are standard tables the model genuinely knows). The planted trap fires here: watch what it says about zmm_plant_map. It will typically assert what the table contains, what zregion means, even plausible column lists — none of which it can know, because Z-tables are customer-defined. Mark every claim about the Z-table as UNVERIFIED in your copy of the map.
  3. Confront the hallucination explicitly. Ask the model directly: "What is the structure and business meaning of zmm_plant_map? How confident are you?" Then ask: "Could zregion be a controlling-area code rather than a geographic region?" Expected: the first answer arrives confident; the second typically produces an equally fluent reversal — demonstrating that both stories were generated, not known. Write the two answers side-by-side in z-table-incident.md with the rule this proves: AI claims about Z-objects are prompts for the data dictionary (SE11) and the developer who owns them, never facts. In a real system you would now pull the actual DDIC definition; here, the lab's ground truth is: zmm_plant_map maps plants to maintenance planning regions for a bolted-on plant-maintenance workflow — nothing the model could have derived.
  4. Get the remediation plan mapped to the checklist. Prompt: "Produce a remediation plan for this report as a table: checklist ID (C1–C9), the offending construct, the modern replacement, and the risk of the change." Review it line by line. Expected: solid mappings (ENDSELECT → single SELECT with FOR ALL ENTRIES or a JOIN; header lines → typed tables with explicit work areas; WRITE → ALV or at least separated presentation). Where it proposes FOR ALL ENTRIES, check whether it volunteers the empty-table guard; most drafts do not — note it, because step 5 tests it.
  5. Get the refactored code and hunt the second trap. Ask for the full modern rewrite: typed data declarations, one JOIN-based (or FOR ALL ENTRIES-based) selection, selection-screen parameters replacing the hardcoded plants and threshold, language from sy-langu, ALV-ready output structure. Then audit the draft for the classic AI-refactor bug: if it used FOR ALL ENTRIES IN lt_marc for the MAKT or Z-table read, what happens when lt_marc is empty? In ABAP, FOR ALL ENTRIES with an empty driver table selects every row in the database table — the WHERE clause silently vanishes. If the draft lacks IF lt_marc IS NOT INITIAL. around that SELECT, you have caught the planted defect; if the model included the guard, remove it mentally and write the failure narrative anyway (what would happen on a plant range returning no rows: full-table MAKT read, wrong report, possible memory dump). Fix the final code either way, and confirm C1–C9 all pass plus C10's guard is present.
  6. Generate the unit-test list — then make it honest. Ask for a test catalog for the refactored logic. Expected draft: happy path, empty selection, threshold boundary. Harden it with the cases the incident history demands, each mapped to what it protects: empty-driver-table test (C10 — the FOR ALL ENTRIES guard), threshold boundary at exactly 500 (is the spec > 500 or >= 500? the legacy code says >, and your refactor must not silently change it — a one-character behavior contract), missing description test (material with no English MAKT row — the legacy code left descr blank and kept going; preserving that is a decision to record), missing Z-mapping test (plant absent from zmm_plant_map), and multi-plant ordering test (legacy output order was database order; if the business relies on it, the refactor needs an explicit SORT). Save as test-list.md.
  7. Run the after-checklist and assemble the package. Grade the final refactor against C1–C10: expected all green, with the quoted line proving each fix. The completion package: before/after checklist with line citations, the dependency map with Z-table claims marked verified/unverified, z-table-incident.md, the final code, and the test list. Optional extension: repeat steps 2 and 5 on a free SAP BTP trial with Joule for Developers in ABAP Cloud — and note where Joule's answers differ from your chat assistant's, especially on the Z-table (an in-system copilot can read your DDIC; that difference is the whole argument for platform-integrated assistants).

Verify

  • The before-checklist shows nine findings with quoted lines; the after-checklist shows all clear plus the C10 guard present.
  • The dependency map marks every zmm_plant_map claim UNVERIFIED, and z-table-incident.md contains the confident answer and the reversal side-by-side.
  • The final code has: no ENDSELECT, no header lines, no SELECT *, parameters for plants and threshold, sy-langu, the initial-table guard, and unchanged > 500 semantics.
  • The test list includes the empty-driver, boundary-500, missing-MAKT, missing-Z-row, and ordering cases, each mapped to what it protects.

Self-grading rubric (pass = 8/10): before-checklist complete with citations (0–2); Z-table hallucination caught, confronted, and written up (0–3); FOR ALL ENTRIES empty-table defect caught or its failure narrative written (0–2); refactor passes all ten checks without behavior drift (0–2); test list hardened beyond the AI draft (0–1).

▸Answer key — seeded defects, expected findings, scoringoptional deep dive — click to expand

Planted trap 1 — the hallucinated Z-table. zmm_plant_map and zregion are customer namespace: no model has seen them. Expected behavior: the assistant produces a confident, plausible description (usually "maps plants to sales/geographic regions"), then reverses just as confidently under the controlling-area suggestion. Ground truth (maintenance planning regions) is deliberately something no plausible guess lands on. Full marks require the side-by-side write-up and the stated rule: Z-object claims route to SE11/system owners. A learner whose dependency map presents the AI's Z-table story as fact loses all three points — this is the exact mechanism by which AI-assisted ERP documentation goes wrong at scale.

Planted trap 2 — FOR ALL ENTRIES on an empty table. The idiomatic refactor of the nested SELECT SINGLEs is FOR ALL ENTRIES, and its notorious edge is that an empty driver table drops the WHERE clause entirely — a report run for a plant range with no rows would read all of MAKT and every Z-mapping. Expected fix: IF lt_marc IS NOT INITIAL. guarding the dependent SELECTs (a JOIN-based single selection avoids the issue structurally and is equally acceptable — if chosen, the learner must still write the FOR-ALL-ENTRIES failure narrative to earn the points, since the trap is knowledge, not luck).

Expected before-checklist: C1 (SELECT...ENDSELECT), C2 (two SELECT SINGLEs inside it), C3 (SELECT * FROM marc), C4 (OCCURS + TABLES), C5 ('1100','1200'), C6 (spras = 'E'), C7 (500), C8 (WRITE output), C9 (descr+30(10) — the offset hack packing region into the description field, which the refactor should replace with a proper structure field).

Behavior contracts that must not drift: > 500 strictly greater; blank description tolerated; the packed region field becomes its own column (a visible behavior change — acceptable only because it is documented as such in the package).

Scoring: the two traps carry half the rubric because they are the two AI-specific risks; the mechanical modernization (C1–C9) is table stakes that any current assistant drafts correctly. A perfect refactor with an unexamined Z-table story is a failed sprint dressed as a passed one.

Key Takeaway:

AI modernizes standard ABAP brilliantly and invents your custom objects fluently — the same conversation contains both. The checklist run both ways, the UNVERIFIED markings on every Z-claim, and the empty-table test are what let you take the speed without inheriting the fiction.

This is the free reading view. Open BXUP to track your progress, run the hands-on labs, and prove it with original, exam-pattern assessments.
© Anvi Innovate · BXUP — Be Exponentially Upskilled · BXUP is an independent learning platform, not affiliated with or endorsed by AWS, Microsoft, Google, NVIDIA, IBM, Salesforce, Databricks, Oracle or Anthropic. All trademarks belong to their respective owners. · bxup.in