Magento 2 Plug-in (AOD) architecture is harmful

Yegor Shytikov
7 min readFeb 16, 2021

Magento Developers who uses Plugin/AOD/Interceptor pattern in Adobe Commerce usually don’t even understand that there is something wrong with transfer of control from anywhere to anywhere.

Magento 2 interception approach changes the behavior of a class function, but it does not change the class itself.

When the before and around plugin sequence is finished, Magento calls the first plugin after method in the sequence loop, and not the after the method of the current plugin that was being executed by the around method.

Magento uses a lot of plugins, even at its core, it increases request time by ~30%. This is especially noticeable in places where a lot of non-cached PHP logic is going on (for example, admin panel/cart/checkout/Ajax is noticeably slow). The plugins interceptors generate GOTO code that is called on nearly every public method to check if modules have some injected code.

Magento 2 AOD/Spaghetti Architecture

Any modern software doesn’t use this harmful software development bad practices.

Magento 2 Plug-in Aspect-Oriented Programming (AOP) is a paradigm that tries to increase the modularity of code.

<!-- Preference !-->
<preference for="Magento\Catalog\Plugin\Block\Topmenu" type="Diode\CategoryStore\Plugin\Block\Topmenu"

Aspect-Oriented Programming (AOP) breaks Object-Oriented Programming (OOP) rules by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the plug-in ad-hok (Latin phrase meaning literally ‘to this’) solution. Plug-in enables the modularization of concerns such as log management that cut across multiple types and objects. (Such concerns are often termed crosscutting concerns in AOP literature.)

However, AOP is a risky solution: It is a very generic mechanism for solving some very specific concerns and has been likened to a kind of “GOTO” (“hook into”) statement for OOP. Like GOTO, it can cause more harm than good.”

To overcome the limitations of the PHP programming languages, aspect-oriented programming has been proposed. Unfortunately, language elements used by many AO languages are in a way similar to the Go To statement.

Code containing aspects is certainly not native PHP code, because the aspect XML annotations or, worse, invisible string-name-based pointcuts change the behavior of the code they’re on, breaking the normal rules of the language. You’ll see “impossible” behavior at runtime: call a method and the call stack jumps to a completely different method. A method throws an exception that’s thrown nowhere in its body. If you want to say that Magento Plug-in is designed in its own right, then it’s an architectural decision that breaks all the rules of good software design best practices: it essentially contains GO To as a core language feature. Whereas monad implementations are (generally) plain old code that follows the normal rules of the language.

Aspect-Oriented Programming (AOP) approach has been introduced to provide an implementation-level programming framework for separately developing basic functionalities and non-functionalities of a software application.

So AOP/APD principles was not designed to change behavior of the original app logic. But add additional non app layer like:

  • Error Handling
  • Security
  • Logging
  • Notifications
  • Sync

However Magento uses it as an approach write the application code and cachange the behavior instead of OOP. So Adobe break everything!

AOD is also applicable for refactoring legacy application where nobody caress about code quality and requires only some quick dirty workarounds. So, by applying AOD/Plugins Adobe considering Magento 2 core as a legacy impossible to maintain and fix in other way without dirty patching by plug-ins.

Magento 2 hooks/plugins should be used as little as possible especially for the 1-st party customizations when you are creating final solutions for the merchants. You can even move some plugins/hooks to the performance class for better performance and code structure. Unfortunately, 3-d party Magento extensions and Magento core are abused by wrong plaguing and creates really bad examples of creating Plugin for Plugin:

On this code profiling image, you can see Magento core framework Plugin functionality overhead. For a single product Page, it adds 160ms overhead. Moder e-commerce platform can return the results in 150ms when Magento spends this time in useless plugin code. How to fix it? We need just move plugin functionality to the code using best software development practices using event emitters and inheritance.

Let's see what code Plugin/Interceptor functionality has :

File: vendor/magento/framework/Interception/PluginList/PluginList.php

/**
* Retrieve next plugins in chain
*
* @param string $type
* @param string $method
* @param string $code
* @return array
*/
public function getNext($type, $method, $code = '__self')
{
$this->_loadScopedData();
if (!isset($this->_inherited[$type]) && !array_key_exists($type, $this->_inherited)) {
$this->_inheritPlugins($type);
}
$key = $type . '_' . lcfirst($method) . '_' . $code;
return $this->_processed[$key] ?? null;
}

Interceptor auto-generated Class Example:

File: generated/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute/Interceptor.php

public function isScopeStore()
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'isScopeStore');
if (!$pluginInfo) {
return parent::isScopeStore();
} else {
return $this->___callPlugins('isScopeStore', func_get_args(), $pluginInfo);
}
}

This code is just garbage…

So, for each method with “Plunging” Magento runs a lot of useless code. And this function execution happens 67527 times. For the customized store this overhead will be much bigger.

Instead of caring about architecture and application design now you can hook into and break everything just using a plugin.

Jut let’s write Magento-less micro-services using a relatively lightweight, straightforward, and explicit web framework (NodeJS, GO, Rust, Larval, which is more of a library than a framework), modern language features, and not a Magento plugin obfuscated code.

Magento Plug-ins have some of the problems associated with the Go To the statement, namely that it does not allow to provide a sound mapping from variables to values based only on a coordinate system of non-program values.

Comparing Magento Plugins constructions to dynamic dispatch in OOP, but argued that for OOP inheritance rules lighten the problem. For Plugins, similar rules are still missing and they are considerably more dangerous.

However, the situation of Plug-ins differs in two ways from OOP. First, as AOP is orthogonal to the OOP paradigm (but can add AOP features to OOP) the problem cannot be dismissed by claiming that OOP is problematic but nonetheless successful. So Magento 2 with AOP language constructs with OOP is no option.

Second, to counter the effect of the uncertain method call target the OOP community has developed a set of rules on how to use method overriding and how not to. Magentos Plug-ins just a meh. Informally an overriding method should only expect less and provide more, by maintaining all invariants, so each overriding method ideally has (more or less) the same semantics. As a consequence, the programmer can reason about the semantics of a method call even if the actually called method is statically unknown. This is still missing for AOP.

Dijkstra in his letter observed: “ … that the quality of programmers is indirectly proportional to the amount of Go To statements they use in their programs.”. As currently, most AOP research is not about methodology but about more dynamicity in the future this might be rephrased to “ … indirectly proportional to the number of plugins they use in their programs.

Let’s compare:

public function execute() {. $x = 2;. echo magentoResult(x); // actually it is hidden GO TO.}public function magentoResult($x) {. return $x}public function aroundMagentoResult($x){. return $x * $x;}

“aroundMagentoResult” is equal to GO TO but in a more obfuscated and slow Magento way.

If you want to have good website performance and a maintainable code base use silly Magento 2 Plugins as little as possible.

Conclusion

Magento 2 Plug-in is still far from being a well-established paradigm since its history only spans almost a decade. There are some issues that need to be addressed and problems to be solved. There are few best practices about using. in bigger projects. Furthermore, modeling software applications that use AOP elements also introduce difficulties that cannot be properly overcome by using current notation. There are many research papers published that describe AOD issues. It is really sad that Magento 2 instead of doing grate modern eCommerce platform using best software development practices. M2 creates its own bad practices, software principles that break maintainability and code quality, produces more bugs. Adobe as a software development company must understand what was sold to them and rewrite it from scratch using best practices.

--

--

Yegor Shytikov

True Stories about Magento 2. Melting down metal server infrastructure into cloud solutions.