Adobe Commerce Developer Expert study materials
Adobe Commerce Developer Expert study resources

Adobe Commerce Developer Expert common mistakes

Adobe Commerce Developer Expert · Understand the traps and how to avoid them.

Mistake 1

Treating plugin sort order as a global sequence, so they assume a plugin with sortOrder 10 on a method always runs before one with sortOrder 20 regardless of which class declares it.

Candidates carry over a mental model from event observer ordering or from single-class experience, and forget that plugin ordering is resolved per intercepted method across the merged di.xml files of all modules, with ordering only comparable within the same scope of interception.

What to do instead

Study how the interceptor list is built by merging all di.xml plugin declarations that target the same class/method, then reason about before/around/after phases separately; when a scenario asks which plugin wins, enumerate every module's declaration and sort by sortOrder within that merged list.

Mistake 2

Assuming an around plugin can change the return value of a method that returns void or can prevent original execution while still needing the original result, and writing around plugins where a before or after plugin is correct.

The around plugin's callable signature and the requirement to invoke the proceed callable are easy to misremember under time pressure, and candidates conflate 'around can do everything' with 'around is always appropriate'.

What to do instead

Memorize the three signatures: before receives the original arguments and returns an array of arguments (or null to leave them unchanged); around receives the subject, arguments, and a proceed callable and must call proceed to run the original; after receives the subject, arguments, and the original return value. Choose around only when you must conditionally skip the original.

Mistake 3

Editing a vendor module's PHP or di.xml directly to add a customization, then describing that as the correct extension approach.

It is the fastest way to make a local test pass, so candidates under exam pressure pick the path of least resistance instead of the architecturally correct one.

What to do instead

Always answer with non-invasive extension points: plugins for behavior around public methods, preferences only for replacing an implementation behind an interface, observers for events, and a new module's di.xml for configuration. State explicitly that vendor code is never modified and that upgrades must not overwrite customizations.

Mistake 4

Using a preference to override a concrete class that other code instantiates directly, or declaring a preference for a class that is instantiated with 'new' rather than through the object manager.

Preferences feel like a universal override, but they only apply where the object manager resolves the type; candidates forget that direct instantiation and already-instantiated shared objects bypass the preference.

What to do instead

Before choosing a preference, check how the target is obtained: if it is injected and resolved by the object manager, a preference works; if it is created with new or is a final class, use a plugin on the calling method or refactor via a virtual type or a new interface implementation wired through di.xml.

Mistake 5

Writing a raw SQL query or a direct resource connection to read product data instead of going through repositories and collections, and presenting that as acceptable for storefront or extension code.

SQL is familiar and appears simpler than the repository and search-criteria API, and candidates underestimate how much the exam weights service contracts and API stability.

What to do instead

Default to service contracts (repositories, getList with SearchCriteria) for reads and writes of entities; reserve direct SQL for cases with no service contract, and then use the resource connection with table-name resolution rather than hardcoded prefixes. Explain that repositories preserve API compatibility and honor plugins and caching.

Mistake 6

Hardcoding table names with a prefix (for example catalog_product_entity) in custom SQL or setup scripts, and treating the EAV attribute tables as if the prefix were fixed.

Local installations often use no prefix or a default one, so the hardcoded name works during development and the portability problem stays invisible until the exam scenario introduces a custom prefix.

What to do instead

Use the resource connection's getTableName() for physical table names and the metadata pool or EAV config for attribute tables. In setup scripts use the schema and EAV setup objects rather than literal SQL identifiers, and verify behavior under a non-default table prefix.

Mistake 7

Adding a new product attribute by writing directly to eav_attribute and catalog_eav_attribute with SQL, or by creating the column by hand, instead of using the EAV setup API in an install or upgrade script.

The underlying tables look straightforward, and candidates who have inspected the schema assume inserting rows is equivalent to the supported attribute-creation path.

What to do instead

Create attributes with EavSetup::addAttribute (or the module's data patch using EavSetupFactory), specifying the correct entity type, backend and frontend models, source model, and the catalog-specific settings. This keeps the attribute consistent across all EAV tables and upgrade-safe.

Mistake 8

Assuming a full-page cache entry is invalidated whenever any product changes, or conversely that changing a product never affects cached category and CMS pages.

The identity and invalidation model is subtle: cache entries carry identities (tags), and invalidation happens only when a matching identity is cleaned; candidates flatten this into 'any product save clears the cache'.

What to do instead

Learn that pages declare cache identities (for example product and category tags) and that saving an entity triggers invalidation of the matching tags, which clears only the affected entries. When designing a custom block, declare the correct identities so targeted invalidation works instead of forcing a global flush.

Mistake 9

Diagnosing a configuration change that 'did not take effect' by flushing the cache, when the real cause is that the value lives in a scope (website or store view) that overrides the default, or that the config was written to the wrong scope.

Cache flushing is the reflex fix for stale-looking behavior, and candidates skip the scope-resolution step that explains why a default value is being masked.

What to do instead

Trace configuration through the scope hierarchy: check the effective scope of the request, query the config with the correct scope code, and confirm where the value was saved. Use the scope config reader with explicit scope arguments when debugging, and only then consider cache as a cause.

Mistake 10

Deploying code changes and expecting them to appear without running the required build steps, or running the wrong mode's commands (for example treating production as if static content and DI compilation were optional).

Developer mode hides these steps by generating files on demand, so candidates who work mostly in developer mode forget that production mode requires an explicit build and deploy sequence.

What to do instead

Memorize the production deployment sequence: set the mode, run dependency injection compilation, deploy static content for the relevant locales and themes, then clear or flush the appropriate caches. Know that generated code and static files are build artifacts, not source, and that developer mode masks missing steps.