Skip to content
advanced Phase 99 · Architecture Principles

Coupling and Cohesion in Magento

Understanding coupling and cohesion including types of coupling, measuring cohesion, and improving both in Magento codebases

45m
0 problems
Topic Progress 0%

Types of Coupling

Coupling Types

Type Description Example
Content Shared internal data Global variables
Common Shared global data Static methods
External Via external data format XML config, database
Control Flag/control flow passed Callback functions
Stamp Shared composite data Passing entire objects
Data Via parameters only Method arguments

Tight Coupling Example

// BAD: Tight coupling
class OrderProcessor
{
    public function process($orderId)
    {
        // Direct dependency on concrete class
        $connection = new \Magento\Framework\DB\Adapter\Pdo\Mysql();
        $order = $connection->fetchRow("SELECT * FROM sales_order WHERE entity_id = {$orderId}");
        
        // Direct dependency on another concrete class
        $emailSender = new \Vendor\Email\Model\Sender();
        $emailSender->send($order['customer_email']);
    }
}

Loose Coupling Example

// GOOD: Loose coupling via interfaces
class OrderProcessor
{
    private OrderRepositoryInterface $orderRepository;
    private EmailServiceInterface $emailService;
    
    public function __construct(
        OrderRepositoryInterface $orderRepository,
        EmailServiceInterface $emailService
    ) {
        $this->orderRepository = $orderRepository;
        $this->emailService = $emailService;
    }
    
    public function process(OrderId $orderId): void
    {
        $order = $this->orderRepository->get($orderId);
        $this->emailService->sendOrderConfirmation($order);
    }
}

Coupling in Magento

// BAD: Tight coupling in Magento
class ProductController
{
    public function execute()
    {
        // Direct model dependency
        $product = Mage::getModel('catalog/product')->load($id);
        
        // Direct helper dependency
        $helper = Mage::helper('catalog');
    }
}

// GOOD: Loose coupling via DI
class ProductController
{
    private ProductRepositoryInterface $productRepository;
    private CatalogHelper $catalogHelper;
    
    public function __construct(
        ProductRepositoryInterface $productRepository,
        CatalogHelper $catalogHelper
    ) {
        $this->productRepository = $productRepository;
        $this->catalogHelper = $catalogHelper;
    }
}

Key Takeaway

Reduce coupling by depending on interfaces, not concrete classes. Use dependency injection instead of direct instantiation. Avoid global state and static methods.

Types of Cohesion

Cohesion Levels (Best to Worst)

Level Description Example
Functional Single purpose Math functions
Sequential Output of one feeds input of next Pipeline
Communicational Operate on same data Same entity operations
Procedural Execute in sequence Workflow steps
Temporal Execute at same time Initialization
Logical Logically related Utilities
Coincidental No meaningful relationship Random functions

High Cohesion Example

// GOOD: High cohesion - all related functionality
class OrderService
{
    public function placeOrder(OrderRequest $request): Order
    {
        $order = $this->createOrder($request);
        $this->processPayment($order);
        $this->sendConfirmation($order);
        return $order;
    }
    
    private function createOrder(OrderRequest $request): Order { /* ... */ }
    private function processPayment(Order $order): void { /* ... */ }
    private function sendConfirmation(Order $order): void { /* ... */ }
}

Low Cohesion Example

// BAD: Low cohesion - unrelated functionality
class Manager
{
    public function processOrder($orderId) { /* ... */ }
    public function generateReport() { /* ... */ }
    public function sendEmail($to, $subject, $body) { /* ... */ }
    public function updateInventory($productId) { /* ... */ }
    public function calculateTax($amount) { /* ... */ }
}

Improving Cohesion

// Before: Low cohesion
class OrderHelper
{
    public function createOrder() { /* ... */ }
    public function validateAddress() { /* ... */ }
    public function calculateShipping() { /* ... */ }
    public function sendNotification() { /* ... */ }
}

// After: High cohesion - split by responsibility
class OrderCreator
{
    public function create(OrderRequest $request): Order { /* ... */ }
}

class AddressValidator
{
    public function validate(Address $address): bool { /* ... */ }
}

class ShippingCalculator
{
    public function calculate(Order $order): Money { /* ... */ }
}

class OrderNotifier
{
    public function sendConfirmation(Order $order): void { /* ... */ }
}

Key Takeaway

High cohesion means related functionality is grouped together. Split classes with unrelated responsibilities. Each class should have a single, well-defined purpose.

Measuring Coupling and Cohesion

Coupling Metrics

// Coupling Between Objects (CBO)
// Count of classes this class depends on

class OrderProcessor
{
    private OrderRepository $orderRepo;      // +1
    private PaymentGateway $payment;         // +1
    private EmailService $email;             // +1
    private InventoryService $inventory;     // +1
    private TaxCalculator $tax;              // +1
    // CBO = 5 (high coupling)
}

Cohesion Metrics

// Lack of Coherence (LCOM)
// Measures how methods share instance variables

class OrderService
{
    private $orderRepo;
    private $paymentGateway;
    
    // Methods using $orderRepo
    public function getOrder() { /* uses $orderRepo */ }
    public function saveOrder() { /* uses $orderRepo */ }
    
    // Methods using $paymentGateway
    public function processPayment() { /* uses $paymentGateway */ }
    public function refundPayment() { /* uses $paymentGateway */ }
    
    // LCOM is low (good cohesion)
    // Two groups, each using shared state
}

Static Analysis Tools

# PHPStan coupling analysis
vendor/bin/phpstan analyse --level=6 app/code/Vendor/

# PHPMD cohesion metrics
vendor/bin/phpmd app/code/Vendor/ text codesize,cleancode

# Exakat coupling analysis
vendor/bin/exakat report --project app/code/Vendor/ --format coupling

Refactoring for Better Metrics

// Before: High coupling, low cohesion
class OrderManager
{
    private $db;
    private $cache;
    private $email;
    private $payment;
    
    public function process($data) { /* uses all 4 */ }
    public function save($data) { /* uses $db */ }
    public function cache($key, $val) { /* uses $cache */ }
}

// After: Lower coupling, higher cohesion
class OrderProcessor
{
    private OrderRepository $repo;
    private PaymentService $payment;
    
    public function process(Order $order) { /* uses $repo, $payment */ }
}

class CacheManager
{
    private CacheInterface $cache;
    
    public function save($key, $val) { /* uses $cache */ }
}

Key Takeaway

Measure coupling (CBO) and cohesion (LCOM) with static analysis tools. Refactor to reduce dependencies and group related functionality.

Reducing Coupling in Magento

Dependency Injection

<!-- Use interfaces in DI -->
<type name="Vendor\Module\Model\OrderProcessor">
    <arguments>
        <argument name="orderRepository" xsi:type="object">
            Magento\Sales\Api\OrderRepositoryInterface
        </argument>
        <argument name="paymentService" xsi:type="object">
            Vendor\Payment\Api\PaymentServiceInterface
        </argument>
    </arguments>
</type>

Event System

// Decouple via events
class OrderService
{
    private EventDispatcher $eventDispatcher;
    
    public function placeOrder(Order $order): void
    {
        // Process order
        $this->orderRepository->save($order);
        
        // Dispatch event instead of direct dependency
        $this->eventDispatcher->dispatch('order_placed', [
            'order' => $order
        ]);
    }
}

// Observer handles side effects
class SendOrderConfirmation
{
    public function execute(EventObserver $observer)
    {
        $order = $observer->getEvent()->getOrder();
        $this->emailService->sendConfirmation($order);
    }
}

Plugin System

// Extend behavior without modifying
class OrderPlugin
{
    public function aroundPlace(
        Order $subject,
        callable $proceed,
        OrderInterface $order
    ): OrderInterface {
        // Add behavior without modifying Order class
        $this->validate($order);
        $result = $proceed($order);
        $this->log($result);
        return $result;
    }
}

Service Contracts

// Depend on interfaces (ports)
interface OrderRepositoryInterface
{
    public function save(OrderInterface $order): OrderInterface;
    public function get(int $orderId): OrderInterface;
}

// Implementation is swappable (adapters)
class MysqlOrderRepository implements OrderRepositoryInterface { /* ... */ }
class ElasticOrderRepository implements OrderRepositoryInterface { /* ... */ }

Configuration Over Code

<!-- Use XML configuration instead of code -->
<config>
    <vendor>
        <payment>
            <gateway>Stripe</gateway>
            <timeout>30</timeout>
        </payment>
    </vendor>
</config>

Key Takeaway

Reduce coupling with DI, events, plugins, service contracts, and configuration. Depend on interfaces, not implementations.

Quiz

1. What is tight coupling?

Question 1 options

2. What is high cohesion?

Question 2 options

3. How to reduce coupling in Magento?

Question 3 options

4. What is CBO (Coupling Between Objects)?

Question 4 options

5. What Magento feature reduces coupling?

Question 5 options

Flashcards

Question

What is tight coupling?

Answer

Direct dependency on concrete implementations, making changes difficult

Question

What is high cohesion?

Answer

Related functionality grouped together with clear purpose

Question

How to reduce coupling?

Answer

DI with interfaces, events, plugins, service contracts

Question

What is CBO?

Answer

Coupling Between Objects - count of dependencies

Question

What is LCOM?

Answer

Lack of Coherence - measures how methods share instance variables

Question

How do events reduce coupling?

Answer

Allow modules to communicate without direct dependencies

Revision Notes

Key Takeaways

  • 1. Reduce coupling by depending on interfaces, not implementations
  • 2. High cohesion groups related functionality together
  • 3. Measure coupling (CBO) and cohesion (LCOM) with tools
  • 4. Use DI, events, plugins to reduce coupling in Magento
  • 5. Split low-cohesion classes into focused classes

Interview Tips

  • Explain types of coupling and how to reduce them
  • Discuss cohesion and how to improve it
  • Describe metrics for measuring coupling/cohesion
  • Explain how Magento features reduce coupling

Cheat Sheet

Coupling & Cohesion

Coupling (lower is better):
Depend on interfaces
Use dependency injection
Avoid global state

Cohesion (higher is better):
Group related functionality
Single responsibility
Split unrelated concerns

Magento Tools:
DI: interfaces in di.xml
Events: observer pattern
Plugins: around/after/before
Service Contracts: Api interfaces

Metrics:
CBO: Coupling Between Objects
LCOM: Lack of Coherence