Estimating an SAP Commerce Upgrade: The Hands-On Assessment Method
How to turn "how big is this upgrade?" into an evidence-based estimate in days: the git overlay technique for isolating customizations, the five analysis phases from build to smoke test, and the organizational practices that keep the next upgrade small.
Every upgrade project starts with the same question from whoever owns the budget: how big is it? The honest answer cannot come from a spreadsheet of extension counts or a gut feeling about code quality; it comes from actually attempting the upgrade, in miniature, and cataloguing what breaks. That is the upgrade assessment: a time-boxed, method-driven dry run whose deliverable is an issue list with an estimate attached, not upgraded code. This guide covers the method, updated for the 2211 world, plus the organizational practices that determine whether your upgrades are routine or traumatic.
One framing note for 2026: within 2211, "upgrading" means adopting update releases continuously, and the assessment below is overkill for a monthly update. It earns its keep in two situations that are both very much alive: legacy installations (6.x, 1905, 2005, 2011) making the jump to 2211, and the 2211 JDK 17 to JDK 21 / Spring 6 framework migration, which behaves like a classic upgrade in every way that matters. A readiness checklist for the 2211 move specifically lives in a companion guide; this one is about producing the estimate.
When to Skip the Assessment#
If the upgrade is a foregone conclusion (mandated, funded, scheduled), do not run a separate assessment; fold the discovery into the execution project's first phase. The assessment exists to answer a genuinely open question (scope, budget, feasibility, vendor selection) with evidence. Know which situation you are in before spending two weeks producing a report nobody needed.
Step 1: Isolate Your Customizations#
The single technique that makes the whole method work: reconstruct, in git, the exact boundary between what SAP shipped and what your project changed. Without it, every diff is noise.
- Create a fresh repository. Generate your project's template exactly as it was originally generated (same accelerator recipe, same
modulegenparameters) using your current platform version, and commit that pristine state tomaster. - Add your actual customizations on top and commit. Now
git diffshows precisely what your project did to the template, which is the surface the upgrade has to carry forward. - Branch, and swap the platform underneath:
export NEW_ARCHIVE="<target_version_zip>"
export NEW_VERSION_FOLDER="<unzip_target>"
export PROJECT_HOME="<project_path>"
cd ${PROJECT_HOME}/hybris/
# remove the shipped platform, keep custom code and config
rm -rf bin/platform bin/ext-* bin/modules
rm -rf data/ log/ tmp/
unzip -d "${NEW_VERSION_FOLDER}" -qo ${NEW_ARCHIVE} 'hybris/*'
# overlay the new platform; -p preserves timestamps or the build
# will misjudge dependency freshness and break
cp -prf ${NEW_VERSION_FOLDER}/hybris/bin/* ${PROJECT_HOME}/hybris/bin/
- Commit the overlay untouched. From here, every fix is its own commit, which turns the git log into the assessment's raw data:
git format-patch master --stdout > Upgrade.patchat the end produces both the findings record and a patch that can bootstrap the real upgrade project later.
Optional but valuable for big version jumps: regenerate the storefront template with the target version's modulegen and diff against your generated code, which sizes the template drift separately from your deliberate customizations. (The Spartacus/composable question is deliberately out of scope here; if the upgrade includes leaving the accelerator, that is its own workstream with its own guide.)
Step 2: Analyze, in Five Phases#
Work the phases in order; each one gates the next, and the issue counts per phase are the skeleton of the estimate. The discipline throughout: fix or mock each issue just enough to proceed, commit it separately, and log it (an epic per functional area with a task per issue works well; the tracker is part of the deliverable).
Build#
cd ${PROJECT_HOME}/hybris/bin/platform
ant clean && ant all && ant initialize -Dtenant=master
Expect compilation failures from changed APIs (IDE find/replace handles signature changes in bulk), missing deployments on types that previous versions tolerated, and property drift (compare your config against the new version's reference properties). Console warnings during compilation are findings too; they are the deprecations that become errors next time.
Launch#
Start the platform. This phase belongs almost entirely to Spring: version jumps in the framework itself (the 2211-jdk21 track brings Spring 6, which removed @Required and a raft of deprecated classes), beans that no longer exist, Jalo code touching beans before the context is ready, and changed converter wiring. It is slow, serial work because Spring reports one context failure at a time: fix, commit, relaunch, repeat. Budget accordingly; this phase's duration surprises everyone. Success means HAC and Backoffice both open.
Update#
Run a system update so the type system regenerates, and expect it to fail informatively. The catalogue of causes is long and worth having at hand while triaging: deployments added, removed, or renamed; typecodes changed; table or properties-table names changed; composed-type parents changed (which alters the inheritance path and super-type PKs); Jalo class or extension assignments moved. Each finding here is potential data migration work in the real project, which estimates very differently from code fixes; tag them.
Data and ImpEx scripts#
Every data adjustment the previous phases forced (fix-up ImpEx, SQL, Groovy) gets committed with the code. In the real upgrade these become the migration runbook; in the assessment they size it. Note where volume matters: a script that alters one column of five million orders may need to run as direct SQL rather than through the type system, and that decision (with its interceptor-bypass implications) should be flagged now, not discovered during the production window.
Smoke test#
Time-boxed and last, because the earlier phases may eat the budget: run a cronjob, add to cart, place an order, open the cockpits, exercise whatever the team flagged as fragile. The goal is not coverage; it is discovering the category of runtime breakage that compiles cleanly, which adjusts the estimate's risk factor.
Step 3: Report#
The deliverable is two artifacts:
The analysis sheet: the extension inventory (name, custom versus template versus platform, dependency hierarchy) and the issue list from the tracker, each issue tagged by phase, functional area, and fix type (mechanical, refactor, data migration, unknown).
The report: effort estimation built up from the issues, with the multipliers made explicit: Spring security customization depth (large upgrades routinely spend serious time re-basing security config; compare spring-security-config.xml across versions and read the framework's release notes before estimating), circular dependencies in custom Spring config (the platform refactors beans between versions, and untangling your cycles against their refactors is the classic estimate-buster), cockpit customizations (deprecated technology; the honest line item is "port to Backoffice", not "fix"), and whether initialization actually builds a testable system or the project has always hand-loaded data (if so, add the effort to script realistic test data, because the upgrade project cannot test without it).
An assessment that produces "six weeks, here are the 47 issues and the patch file" changes the conversation. One that produces "medium complexity" wasted two weeks.
The Practices That Shrink the Next One#
The assessment measures the gap between your version and the target; these habits keep the gap small:
- Stay current as a habit. On 2211, adopt update releases on a fixed cadence (quarterly at minimum) rather than accumulating a multi-year jump. The team that upgrades often gets good at upgrading, and its customization style evolves to survive upgrades, which is a compounding return.
- Always be on the latest patch of whatever you run. Patches are monthly and carry security and performance fixes; they also keep the eventual big jump smaller.
- Separate bug populations. During an upgrade project, every bug found gets triaged against a reference environment running the untouched source version: pre-existing bugs go to the normal backlog, only upgrade-caused bugs block the upgrade. Projects that skip this quietly convert the upgrade into a general remediation program and blow the timeline.
- Converge on vanilla. At every upgrade, ask which customizations the target version has made redundant (the web-services layer you built in 5.x, the custom feature the platform now ships) and delete rather than port. Tailoring requirements toward the platform's current capabilities is the cheapest upgrade work there is.
- Baseline with Sonar before starting and watch the trend during execution (the coding standards guide covers the setup); an upgrade should not degrade code quality under schedule pressure, and the dashboard is what makes that visible.
- Split data migration from code upgrade as parallel workstreams with different skills, and use every lower-environment deployment as a timed dry run of the production procedure.
- Keep everything. The notes, error logs, SQL, ImpEx, and screenshots from this upgrade are the accelerant for the next one. Teams that archive their upgrade artifacts estimate the next assessment in hours instead of days.
The pattern under all of it: upgrades are only expensive in proportion to how long they were deferred and how invisible the customization surface was allowed to become. The assessment method makes the surface visible; the cadence habit keeps it small; and together they turn the budget question from a negotiation into a lookup.