Skip to main content
Developer Docs

Anti-Patterns

Common mistakes developers make when working with the Magento_Customer module, why they're problematic, and correct implementations.

Best Practices 6 Categories

Table of Contents

Data Access Anti-Patterns

❌ Anti-Pattern 1: Direct Model Usage Instead of Repository

Why It's Bad

  • → Bypasses Service Contracts: Extensions won't intercept this operation
  • → Skips Plugins: Plugins on CustomerRepositoryInterface won't execute
  • → No Event Dispatch: customer_save_after_data_object event not fired
  • → Breaks API Compatibility: Third-party code expecting repository pattern won't work
Bad Code Example Bad
<?php
namespace Vendor\Module\Model;

use Magento\Customer\Model\CustomerFactory;

class CustomerService
{
    private CustomerFactory $customerFactory;

    public function updateCustomerName(int $customerId, string $firstname, string $lastname): void
    {
        // WRONG: Direct model manipulation
        $customer = $this->customerFactory->create();
        $customer->load($customerId);
        $customer->setFirstname($firstname);
        $customer->setLastname($lastname);
        $customer->save();
    }
}
Good Code Example Good
<?php
declare(strict_types=1);

namespace Vendor\Module\Model;

use Magento\Customer\Api\CustomerRepositoryInterface;

class CustomerService
{
    private CustomerRepositoryInterface $customerRepository;

    public function updateCustomerName(int $customerId, string $firstname, string $lastname): void
    {
        // CORRECT: Use repository service contract
        $customer = $this->customerRepository->getById($customerId);
        $customer->setFirstname($firstname);
        $customer->setLastname($lastname);
        $this->customerRepository->save($customer);
    }
}

Why It's Better

  • ✓ Service Contract Compliance: Follows Magento's service contract pattern
  • ✓ Plugin Support: All plugins execute correctly
  • ✓ Transaction Safety: Ensures atomic save operations
  • ✓ Event Dispatch: Proper event chain fires

❌ Anti-Pattern 2: Loading Full Customer When Only ID Needed

Why It's Bad

  • → Performance Waste: Loads all EAV attributes (10+ SQL queries) when only 1 field needed
  • → Memory Overhead: Loads entire customer object into memory
  • → Slow Response: 100-500ms customer load vs. 5-10ms direct query

Correct Approach: Direct SQL Query

Performance Gain: 10-50x faster

Use ResourceConnection for single-field lookups instead of loading full customer entity.

❌ Anti-Pattern 3: Excessive Custom EAV Attributes

Why It's Bad

  • → Query Complexity: Each EAV attribute = 1 LEFT JOIN (50 attributes = 50 JOINs)
  • → Slow Customer Load: 2000ms+ load time with 50+ custom attributes
  • → Database Stress: Complex execution plans, potential table locks

Correct Approach: Extension Attributes + Custom Table

Performance Gain: 10-100x faster

  • ✓ Single JOIN: Only 1 JOIN to extended data table
  • ✓ Fast Queries: 20-50ms vs. 2000ms
  • ✓ Lazy Loading: Extended data only loaded when needed

Cache Anti-Patterns

❌ Anti-Pattern 4: Ignoring Customer Group Cache After Group Change

Why It's Bad

  • → Stale Prices: Full Page Cache serves old pricing based on previous customer group
  • → Wrong Promotions: Catalog rules don't apply immediately
  • → Customer Confusion: "Why are prices still the same?"
  • → Revenue Impact: Potential overcharging or undercharging

Why It's Better

  • ✓ Fresh Pricing: FPC cleared, next page load shows correct prices
  • ✓ Correct Business Logic: Group-based rules apply immediately
  • ✓ Data Integrity: Cache state matches database state

Observer Anti-Patterns

❌ Anti-Pattern 6: Synchronous External API Calls in Observers

Why It's Bad

  • → Slow Saves: Customer save operations take 200-1000ms longer
  • → Failure Coupling: External API failure causes customer save to fail
  • → Poor UX: Admin users wait for external API during customer edits

Performance Gain

10x faster: 51ms (with queue) vs. 500ms (synchronous API call)

Use async queue pattern for external API calls instead of blocking observer execution.

❌ Anti-Pattern 7: Bulk Operations Not Disabling Observers

Why It's Bad

  • → Extremely Slow: 10,000 saves × 50ms = 500 seconds (8+ minutes)
  • → Unnecessary Work: Email sync, audit logs not needed for bulk operations
  • → Timeout Risk: Script may hit max_execution_time

Performance Gain

1000x faster: 0.5 seconds vs. 500 seconds for 10,000 customers

Use direct SQL UPDATE for bulk operations instead of looping through repository saves.

Quick Reference Summary

Anti-Pattern Impact Correct Approach
Direct model usage Bypasses plugins, events Use repository interface
Loading full customer for one field 10-50x slower Direct SQL query for field
Excessive EAV attributes 2000ms+ load time Extension attributes + custom table
Sync external API in observer 10-100x slower saves Async queue pattern
Bulk ops with observers 25x slower Disable observers or direct SQL