SAP ECC to S/4HANA: Automating Custom-Code Remediation Analysis

The risk in an SAP ECC-to-S/4HANA move is rarely the database. It is the years of custom Z-code nobody has read since the person who wrote it left, and the fact that most programmes size that remediation far too late to do anything calm about it.

SAP mainstream maintenance for ECC 6 enhancement packages 6 to 8 ends on 31 December 2027. Extended maintenance runs to the end of 2030 at a surcharge of roughly two percentage points on the maintenance rate, and after that you are on customer-specific maintenance, which is a polite name for being on your own. Those dates are fixed; SAP has restated them repeatedly. The board-level decision to move is, by now, mostly made. What is usually not made — and what quietly determines whether the programme lands on time — is an honest, evidence-based estimate of what it will cost to make your custom code run on S/4HANA.

Why the estimate arrives late, and wrong

A typical long-lived ECC estate carries tens of thousands of custom objects: reports, includes, function modules, BAdI implementations, enhancements, and a great deal of code copied, forgotten, and never deleted. Nobody in the building can tell you, from memory, how much of it will break on S/4HANA. So the number gets guessed. It is guessed by a system integrator during a bid, or by an internal lead under pressure to be optimistic, and the guess becomes a line in a business case that the board approves. Remediation is then discovered — not estimated — during realisation, when developers actually try to activate the code against the new data model. That is the most expensive possible moment to find out, because by then the timeline and budget are already committed.

Free · 4 minutes

Do you actually know what you are running — and what it is about to cost you?

Fourteen questions on the systems you depend on, the ones nobody owns, and the support dates that turn a routine upgrade into a forced re-platform. Banded finding on screen, full sheet by email.

The good news is that this is one of the few migration variables you can measure precisely and early. The tooling to do it is included with SAP, it runs against your live ECC system without disrupting it, and it produces object-level output you can turn into a costed backlog. There is no reason to guess.

What the scans actually surface

Three instruments matter, and they answer different questions. SAP Readiness Check is the executive-level scan: run against production, it produces a dashboard covering sizing, add-on and business-function compatibility, recommended follow-on activities, and a custom-code summary. It is where you start, but its custom-code view is a headline count, not a work plan.

The Simplification Item Check tells you where the S/4HANA data model has changed under your feet — the simplification items that describe, for example, the material number extension to 40 characters, or business-partner data model changes — and flags which of those items are relevant to your system. This is the functional side of the risk: it is not that your code has a syntax error, it is that the table or field it depends on no longer behaves the way it did.

The ABAP Test Cockpit (ATC), run with the S4HANA_READINESS check variant, is where the real work list comes from. ATC uses the Simplification Database to check every custom object against the known S/4HANA changes and returns findings by priority: broadly, things that will stop the code compiling or running, things that need functional review, and lower-priority advisories. Run it as a remote analysis — a central checking system reaching into the ECC system by RFC — and you can profile the whole estate without installing anything on production. The output is object by object, message by message. That granularity is the point.

Usage data is the lever that shrinks the number

A raw ATC finding count is almost always an overestimate of the work, because a large share of custom code in an old ECC system is dead. It is never called. Remediating it would be pure waste, and — worse — carrying it forward pollutes the new system with debt on day one.

This is where the ABAP Call Monitor (transaction SCMON, with the older Usage Procedure Logging as an alternative source) earns its place. Switch it on in production and let it run for a representative period — ideally twelve months, so you capture quarter-end, year-end and every seasonal job. It records which custom objects were actually executed. Join that usage data to the ATC findings and the estate splits into three: code that is broken and used, which you must remediate; code that is broken and unused, which you retire rather than fix; and code that is clean, which you carry. The Custom Code Migration process in SAP is built precisely to combine the ATC readiness checks with this usage data so unused objects drop out of scope. In practice this is the single biggest lever on the remediation number, and it is why any estimate produced without usage data should be treated as a ceiling, not a plan.

From findings to a costed backlog

The scans give you exports; what the board needs is a backlog sized in effort. That transformation is mechanical and worth automating, because you will re-run it every time the codebase or the usage window changes. The following joins an ATC export to an SCMON usage export, drops the dead code, and rolls the survivors up into a prioritised backlog with a rough effort estimate by object.

# size_remediation.py — turn ATC + usage exports into a costed backlog
# Inputs: two CSV exports.
#   atc.csv  : object_type,object_name,priority,check_id,message
#   usage.csv: object_type,object_name,exec_count   (from SCMON/UPL)
import csv, collections

# Rough effort in person-days per finding, by ATC priority.
# Calibrate these against your own first remediated objects.
EFFORT = {"1": 1.0, "2": 0.5, "3": 0.1}

def load(path, key_cols):
    with open(path, newline="", encoding="utf-8") as f:
        return list(csv.DictReader(f))

usage = {(r["object_type"], r["object_name"]): int(r["exec_count"])
         for r in load("usage.csv", None)}

backlog = collections.defaultdict(lambda: {"findings": 0, "effort": 0.0,
                                           "used": False, "top": "9"})
retired = 0
for r in load("atc.csv", None):
    key = (r["object_type"], r["object_name"])
    calls = usage.get(key, 0)
    if calls == 0:                 # broken but never executed -> retire, don't fix
        retired += 1
        continue
    b = backlog[key]
    b["used"] = True
    b["findings"] += 1
    b["effort"] += EFFORT.get(r["priority"], 0.1)
    b["top"] = min(b["top"], r["priority"])   # worst (lowest) priority seen

# Highest priority first, then heaviest objects.
rows = sorted(backlog.items(), key=lambda kv: (kv[1]["top"], -kv[1]["effort"]))
total = sum(b["effort"] for _, b in rows)
print(f"objects to remediate: {len(rows)}  retired (unused): {retired}")
print(f"estimated effort: {total:.1f} person-days")
for (otype, oname), b in rows[:20]:
    print(f"P{b['top']}  {otype:8} {oname:30} "
          f"{b['findings']:3} findings  {b['effort']:5.1f} pd")

The effort weights are the honest part of the exercise and the part no tool can hand you. Calibrate them: remediate a first tranche of real objects, record how long each priority band actually took, and feed those durations back into the table. After one iteration the estimate stops being a guess and becomes a projection with a known error bar — which is exactly what a steering committee is entitled to ask for.

Sequence the work while there is still slack

Once you have a costed, usage-filtered backlog, the sequencing follows. Retire the dead code first and formally — deletion is the cheapest remediation there is, and it shrinks everything downstream, including the eventual regression test. Take the priority-one, high-usage objects next, because those are the ones that will otherwise surface as blockers during the technical conversion. Batch the low-priority advisories for a later clean-core pass rather than letting them inflate the critical path. None of this is possible on a guessed number; all of it falls out naturally of an object-level one.

The firms that will struggle in 2027 are not the ones with the most custom code. They are the ones who never measured it, and who therefore priced the hardest part of the migration by intuition. The scans have been sitting in the system the whole time. Run them early, join them to usage, and the Z-code stops being the thing that derails the programme and becomes the thing you costed before you started — which is the whole difference between acting before the clock runs out and being run by it.

Sixteen Pillars is a technology governance consultancy based in Cyprus. Engagements run remote across the EU, UK, and Middle East, with on-site time where the engagement requires it.

Build and rescue work

Hands-on delivery of this kind is handled by Sixteen Pillars Studio.

Looking at an acquisition, supplier, or major project?

The greatest risks are rarely visible in the executive summary. The Sixteen Pillars framework surfaces the technology risks that diligence usually misses.