10 Practical Rules to Build High Quality Magento 2 Module

A while ago I have been working on custom module for Magento 2. One of the task was to create custom attribute for customer address entity in Magento 2. Once attribute is added as part of address it should be rendered during checkout process for shipping and billing forms. Afterwards, value should be stored as part of an order.

My first thought about this was like “Hah, this is a simple task, I will do this super quickly”. But in reality it appeared to be kind of complex once you start doing it.

Magento 2 Enterprise Edition provides customer attribute management functionality where admin user can simple go to Magento Admin and manage custom attributes directly from admin. No hustle is required.

Magento 2 Community Edition however, requires additional development and adjustments to maintain custom attributes.

I’ve prepared list of rules together with Magento Community which may help you to plan and build custom module for Magento 2.

Rule #1: Consider unknown complexity

Well, I did say it is fast to add custom attribute in Magento 2, however I was not aware about complexity of the development involved into it. Unless you have implemented custom attribute in the past on some project it is most likely estimation won’t be accurate.

As for me, I was surprised to figure out that I have to create 7 Observers, 3 Plugins, 4 Models/Resources, Checkout Layout Processor and 7 configuration files…

Spend some time investigating and planning development tasks to provide precise estimation.

Rule #2: Estimate, estimate after prototyping

Let’s say you work with a client where every hour is billable and it is highly expected by your client to provide estimates in advance for the work. In case of custom attribute module I would miss estimates.

With just 10–15 minutes looking into code base, especially when we talk about Magento 2 we can have a solid understanding and couple of great ideas how to implement custom module. So in case your estimate is 10 hours, in reality it might be 50 hours or full work week plus weekend.

Use pencil and paper to draw custom module architecture, even high level diagram would give you a better idea and good bread to think what needs to be implemented.

Use pencil and paper to draw custom module architecture

Check Magento 2 code base for extension points like Interfaces and APIs when building custom functionality.

Rule #3: Follow Versioning Policy

Follow versioning policy in your custom Magento 2 module. It will allow a module to be more stable and less fragile when Magento releases new version. Composer package manager allows to specify and maintain up to date dependencies on other packages and Magento 2 modules.

The composer.json example with Magento 2 module dependencies

Important part plays dependencies on other Magento 2 modules. If, let’s say, composer.json from custom module has 100.1.* version dependency on magento/module-catalog module it means that all PATCH updates are compatible with custom module.

In practice there are more modules which do not have clear API or full API coverage and you will end up having 100.1.3 dependency. Such modules most likely use Inheritance rather than Composition.

David Manners recommends to check semver.org and keepachangelog.com resources for clear explanation on how to follow versions in a module or package and right way of having human-readable CHANGELOG.md file.

Rule #4: Don’t blindly follow Magento 2 core

I hear a lot from Magento developers saying that “It is same approach as in Magento 2 core and I followed (read copy-pasted) same approaches and it should be right”. Theoretically I would agree with this statement to follow Magento 2 core implementations. In practice there are still big chunks of code which are planned for refactoring and reimplementation by the Magento Team.

Let’s say you find similar implementation in Magento\Payment module to build custom payment implementation. As part of the module you will find AbstractMethod class and examples of it’s implementation in payment modules which come together with Magento 2 Community Edition. What I see for last 2 years since Magento 2.0 release is that the approach of implementing payment integrations is following exactly same as Magento 1, which is deprecated.

Most important is that AbstractMethod is marked as @deprecated and shouldn’t be used. There is a Payment Gateway API where all parts or components can be implemented separately from each other. The only thing you have to ensure is to configure these payment components properly via di.xml configuration file.

Magento Documentation or DevDocs is a good starting point if you aren’t aware about architecture or best practices for Magento 2 development.

Rule #5: Provide Localisation Support

Before you decide that module is ready to be shipped to Magento Marketplace or GitHub for community make sure you have localisation support included.

All texts located in custom module should be wrapped with __(‘My Text’) function. It should be used everywhere, classes, templates, JavaScript components, email templates etc.

Rule #6: Use Composer File

Importance of composer.json file might be underestimated. Every single Magento 2 module, package, theme and localization should include composer.json file with all dependencies listed. I saw a lot of Magento 2 modules where only 1 dependency listed which is “magento/framework”. This is incorrect assumption to have dependency only for Framework if your module uses Magento\Catalog\Api interfaces from “magento/module-catalog” package for example.

Rule #6.1: No God classes a.k.a Helpers

Magento 1 approach was to create special class where all utility functions/methods were located. Sometimes these methods have relation between each other, however in majority of situations such special class was holding way too many responsibilities. This class is also known as Helper.

First of all, avoid using Helpers as a term and as a definition to God Give Me All class in Magento 2. It is always better to create 5 smaller classes with clear naming and purpose than just Helper.php.

For example if you have Attribute Helper class with 2 responsibilities a) Merging attribute values; b) Mapping attribute values; consider having 2 independent classes with it’s own responsibility:

  1. AttributeMerger
  2. AttributeMapper

Rule #7: Main Menu Usage

Every time you I install Magento 2 module with Magento Admin capabilities I see that new Menu Icon is added to the left main menu.

There is some misleading assumption that if merchant install “my” module it is a main and most used functionality and should be listed under main menu.

In 99% of cases custom module requires configuration settings and for this Magento provides special page under Magento Admin -> Stores -> Configuration menu. So if your module helps merchant to increase conversion most likely “Marketing” is a good name of configuration section. In case custom module adjusts existing functionality, it should be part of existing configuration section.

Rule #8: Test Module with Different Deployment Modes

It is very good practice to switch between production and development application modes to ensure custom module does not break any existing functionality. According to latest report by Magento Marketplace team 70% of modules can’t compile with production mode.

Take some time and plan testing with production mode before releasing Magento 2 module to Magento Marketplace or anywhere else. Magento Ecosystem requires healthy and stable modules.

Rule #9: Testing is as import as code

Consider adding different types of tests while building custom module for Magento 2. As for now you can find different types included into Magento 2 including Unit Tests, Integration Tests, Functional Tests, etc.

For sure initial estimation of effort will be increased for building tests, costs for maintenance however, would be lower. New features can be added much faster with good level of confidence for existing functionality to be working as expected.

Rule #10: Code Review

Whether you work in a team or solo developer find a way to show your code to other developer and ask to provide code review. It doesn’t matter whether you are Senior Developer who knows absolutely everything or Junior Developer who just started the importance of code review can’t be underestimated.

One small TYPO in code can lead to website down time and huge revenue drop for store owner. Peer review could give a better and cleaner version of code.

Rule #11: Granularity Matters

It is a good practice to build functionality in a way that package or module is responsible for small complete part of a functionality. It will help to have very minimum amount of external dependencies on other Magento 2 modules.

Here is what Igor Minyaylo says about dependencies:

There shouldn’t be a lot of external dependencies. And if you need to introduce dependency on another optional (read switchable module) , this functional dependency better to put into dedicated module (like Magento\ConfigurableInventory — module which provides functionality for inventory calculation of Configurable products) . Doing so, both of optional modules can potentially be switchable without affecting other module’s functionality which dependent on it.

Before The End

Big THANKS to all my Magento Friends Marius Strajeru, David Manners, Fabian Schmengler, Sergii Shymko, Igor Minyaylo (apologises if I missed someone) who contributed into this post by sharing thoughts and tips on how to build better code for Magento 2.

The End

If you like to learn more about development with Magento 2 you can check my Magento DevChannel on YouTube where I share tutorials about custom development.

Also, I write tips and tutorials and send it via email every week. Check The Devletter email and subscribe if you want to get more interesting content.

Do you have thoughts or your practices on building custom functionality in Magento 2? Leave a comment below.


Connect with me.

Twitter @max_pronko. Instagram @maxpronko. GitHub @mcspronko. Commerce Hero @maxpronko.

Thanks for reading,

Max

Show your support

Clapping shows how much you appreciated Max Pronko’s story.