Originally posted on Medium.com

Whether you write custom modules for individual clients or sell
extensions on the Magento Marketplace—Magento 2 (M2)
extension development is a big change from M1.

I started writing Fooman’s M2 extensions almost two years ago, and
have clocked up countless hours of wins, fails (sometimes
painful), trial and error earning my M2 developer stripes. Many
nights were spent coding until the wee hours of the morning,
and I’d fall into bed only to be woken by my newborn baby.

Learning the ins and outs of M2 has been a labour of love. But
these hours have taught me a lot that I want to share with the
#realmagento community. New M2 features have added a couple of
shortcuts to writing smart code, but this does require a shift
in thinking from Magento 1.

Triggered by the above tweet I started writing down what I had
learned so far. Here are my six take-aways of how you can write
better Magento 2 extensions.

1. Work with the framework

While Magento 1 and 2 share a number of similarities, a lot has
moved on with Magento 2. Familiarise yourself with the new
platform and its capabilities. The system architecture has been
overhauled and it’s now easier than ever to use current design
patterns and tools with Magento.

Early on I looked closely at how things are implemented in the
Magento_Customer module. This module has generally been
mentioned by Magento as reflecting the new way of doing things
in M2. However, don’t be surprised if other Magento modules
look different — Magento hasn’t had a chance to refactor all
modules yet and things are still changing.

One example I learned from the Customer module is to prefer
Repository classes (their interfaces to be exact) for
retrieving entities. While you can still use Collections like
in M1, I expect their use to be discouraged over time.

When working with the M2 framework, keep track of the
individual Magento Core modules that you use in your
extension’s composer.json require section. Add them to the
module.xml’s sequence node to make sure your extension’s config
files are loaded after the core module.

Doing this will allow you to use Composer — something that will
make your life much easier when dealing with future Magento
upgrades.

2. Use service contracts

Magento has put a lot of effort into creating service contracts
(implemented via php interfaces) for their code. The service
contract approach brings flexibility to the system (you can
replace implementations with your own) while also defining
boundaries (the new implementations need to follow the same
expectations as the original implementation, enforced via the
interface). Use Magento’s existing service contracts as often
as you can. For example, use
MagentoSalesApiDataOrderInterface in your code, rather than
MagentoSalesModelOrder.

You can create service contracts for your own code too. Simply
create an interface (by convention in the Api folder of your
extension) then instruct M2 to use your actual implementation
of the interface via a preference in your di.xml file.

I created service contracts for the supply of a pdf ready to be
attached to an email in our free Fooman Email Attachments M2
extension. If the free Fooman Print Order Pdf M2 extension is
also installed (since many people install these together), it
will then supply the actual implementation for the order pdf to
be sent attached to the email:

<virtualType name="fooman_emailattachments_order_pdf_renderer" type="FoomanEmailAttachmentsModelPdfRenderer">
   <arguments>
       <argument name="pdfRenderer" xsi:type="object">FoomanPrintOrderPdfModelPdfOrder</argument>
   </arguments>
</virtualType>
<type name="FoomanEmailAttachmentsObserverAbstractSendOrderObserver">
   <arguments>
       <argument name="pdfRenderer" xsi:type="object">fooman_emailattachments_order_pdf_renderer</argument>
   </arguments>
</type>

Fooman Pdf Customiser on M2 uses the same mechanism to swap out
the default pdfs with our customised pdfs instead.

Why did I do this? Email Attachments does not know of the
existence of either the Print Order Pdf or Pdf Customiser
extensions. Keeping the responsibility decoupled like this
increases the maintainability of the code.

Generally, you want to aim for your constructor to only be
using service contracts from any module (including your own) or
classes from your own namespace. At the current stage of M2
this isn’t always possible—but it’s where things are heading.
Don’t be afraid to let Magento know where there are gaps that
are currently not covered by service contracts like Vinai did
here.

3. Use plugins

Wherever possible, use plugins (preferably on methods that have
an @api annotation) to implement your functionality. This will
reduce the scope for possible conflicts with other extensions,
and lessen support issues later down the track (something we
can all appreciate).

M2 plugins are a lot more targeted than what we have in M1,
which only had the crude method of overwriting complete
classes. M2 plugins allow you to target
changing/adding/removing functionality on the method level.

I decided to use the plugin approach to replace the output of
one core method that we need to change in our free Google
Analytics + extension.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
   <type name="MagentoGoogleAnalyticsBlockGa">
       <plugin name="fooman_googleanalytics_plus_ga" type="FoomanGoogleAnalyticsPlusPluginGa"/>
   </type>
</config>

Using a plugin here allows us to surgically replace the output
of only one method. All other core functionality is retained
and means fewer chances things will break on future Magento
upgrades.

4. Write tests

Compared to Magento 1, M2 makes automated testing a whole lot
easier. Out of the box, M2 comes with unit tests, integration
and functional tests—plus frameworks to use them. Aim to use
all types for your own code.

Tests will not only help you to write better code, but they’ll
save you time when testing compatibility with new versions of
Magento later down the track. If you’re planning to sell your
extension to multiple end users, tests will also assist people
in evaluating the quality of your code. If you do need to
compromise on what tests to write, I’m a firm believer in
prioritising functional tests. This is for the simple reason
that functional tests are aligned with what the end customer
uses, i.e. using the site via a browser. A functional test
provides you with more certainty than a unit test that your
code (as experienced by the end user) does what it is designed
to do.

When I started M2 development at Fooman, I knew that Magento’s
code base would continuously change. At the time of writing,
there have been ten 2.0.x releases and three 2.1.x releases so
far. Investing time upfront in automated installs and running
the various testing frameworks (unit tests, integration tests
and functional tests) is already allowing us to move faster.
I’m confident that all those hours we invested setting this is
up already starting to pay off.

5. Use modular code

Consider creating separate modules or extensions with highly
targeted functionality, rather than bundling together loosely
related features which are not relevant to the majority of your
users. Pick the specific features which will be most helpful to
your target customer, then spend your energy making those
features outstanding.

Splitting code into logical units of functionality is a great
way to increase code reusability. Start by extracting framework
independent code into your own libraries. Magento 2 supports
modularisation by using composer for dependency management
which allows you to join packages easily. You can always decide
later to create a metapackage that brings together your
targeted modules to form a broader product.

Keeping modules smaller allows more fine-tuned control to
install only the features which are needed by the store,
without burdening the performance of the store with features
that aren’t required. It also makes the extension itself easier
to maintain in the future, as less code is involved.

For M2, I decided to de-bundle one of the most popular features
of our Email Attachments extension and keep it free. Fooman
Print Order Pdf was born—it’s a simple module which lets you
print an Order Confirmation pdf document for single or multiple
orders. This extension has literally one feature—but this
feature is powerful and in demand.

Even if it wasn’t free, I can see that this single-feature
extension would fill a basic need for a lot of people who don’t
need the advanced features provided by a specific pdf
customisation/creation tool.

6. Seek customer feedback to improve your code

This one’s not a specific M2 tip but is as relevant as ever. I
always advocate taking a lean approach when developing
extensions. It makes sense to show your work early on to
confirm that you’re on the right track, before investing
precious resources in developing a 100% complete version and
later realising there just wasn’t demand for it.

Seek feedback as early as possible from the target user—whether
this is your client or early adopters of a community extension.
Is the basic functionality going to solve their problem? Are
any logical core features missing? Was anything confusing to
set up or use? This could save hours of wasted time developing
features people aren’t interested in, and make your product
stronger. Plus, if you’re selling extensions, seeking early
feedback can also help to create a good first impression for
those all-important first reviews.

Development priorities at Fooman have always been influenced by
customer requests. Moving to M2, all extensions had to be
rewritten from the ground up, and every single M1 file was
changed. To show we’re serious about Magento 2 it was essential
to release our popular products early. Fooman Pdf Customiser
for M2 was released with core pdf customisation functionality,
but fewer features than our bestselling M1 version. Since then,
we’ve added plenty of new features based on customer feedback.
If we’d waited to develop our full list of features before
releasing the extension, we would have missed out on those
customer insights which led to those features being prioritised
over others.

Look for trends in feedback and be open-minded—early feedback
could lead you to your best code or product tweaks. But also
trust your instinct and don’t allow yourself to get distracted
from the core extension purpose and target customer.

In Summary

Writing code which takes advantage of new M2 tools will
initially take longer as you learn the new platform—there’s no
getting around this. But once you’ve worked with M2 for a
while, going back to developing with M1 will feel like a step
back in time. Hopefully these tips will give you a few
shortcuts to take advantage of the new framework when writing
M2 extensions.

Kristof
Ringleff

Kristof is the extension guy behind Fooman. He’s been coding with
Magento since 2007 and has spent the last 1.5 years writing
time-saving extensions for Magento 2. A huge fan of the Magento
community, Kristof is glued to Twitter and Magento StackExchange
as well as running the local
meet up group in New Zealand
. He founded the Magento Extension Developers Network to
give a stronger voice to extension developers committed to
quality coding, customer experience, and a strong Magento
ecosystem. Kristof is a very big fan of coffee.