Ambitious e-commerce projects require flexibility. This article will introduce you to the architecture behind the Shopsys Framework from the viewpoint of packages (in contrast to application layers) and give you an idea of what the actual development of an online store based on the Shopsys Framework looks like.
An ideal e-commerce framework should be easily customizable, while at the same time allowing for installable functionality and upgradability. And these attributes contradict each other in terms of architecture.
For developer teams working on big projects, customizability is often the most important characteristic in the long run, so our goal is a fully customizable, open-box core that incorporates isolated, separately upgradable components and installable plugins, giving you the best of both worlds.
Currently the Shopsys Framework is a fully working lean online store with monolithic architecture, and we’ve started with the separation into components and the plugin interfaces design.
Requirements of an Ideal E-commerce Framework
Back in 2003, when the Shopsys Company was established, e-commerce sites were relatively simple in comparison to today’s online platforms, and often included only the most basic elements like product listings and details, checkout, and elementary administration control panels. Back then there were few online sellers and little competition, but as more and more customers have turned to online options to purchase their goods, we’ve seen a gradual shift in the number of merchants who have also adopted e-commerce solutions to run their businesses. In today’s extremely saturated competitive market, online sellers are required to deliver not only products but also an engaging and unique experience that helps set them apart — they need to be both innovative and effective.
But nobody really knows which innovations or ideas will work in the end, and which are doomed to fail. The key is in being able to ascertain the potential of each of them quickly, on a daily or a weekly basis, and focus on those strategies which make the most sense from a business perspective. E-commerce software itself has become the main pillar of ambitious projects. As the market has changed, the more successful and savvy e-commerce companies, both B2B or B2C, have simultaneously transitioned into tech companies in order to stay ahead of the curve.
A successful e-commerce project is an ever-changing piece of software. New features must be delivered as fast as possible, and existing features require constant tweaking without sacrificing the quality of code or easy maintainability in the future.
As an online store grows, so does the customer base, and performance can become a serious issue. By it’s nature, performance is not something that can be designed perfectly in advance — it always comes down to what your application is about and how exactly it is used. Therefore, the code has to be flexible enough to allow for substantial alterations, depending on each scenario. Being restricted by pre-designed options can prevent you from creating truly unique solutions that satisfy your exact needs.
Some types of features are common across a variety of different online stores. A typical example of this is an integration with payment gateways. There is not much room for innovation, not much room for customization — you just expect it to work.
Having implementations of all payment methods already included in this case would only be a burden, as typical online stores choose to support only 2 or 3 types of payments. It is best to install only the extensions you want, whether they are payment methods, product XML feeds, or analytics integrations. Otherwise, there will be a lot of unused code that would bloat your codebase.
At the same time, these extensions must be reliable, safe to use, easy to install, and allow the option of removing it without consequences, in case you want to try it out and then decide not to keep it.
Upgradability of the System
Ask any developer, and they’ll tell you they never want to work on an obsolete application. This is where upgrades come into play, and can provide you with new features, bug fixes, and compatibility with new versions of third party software or services.
In the best case scenario, you should be able to upgrade each part of an application independently as you see fit, but because upgrading always puts your application at risk, it should be done only when there is a good reason for it.
Upgrading should be as easy as possible, ideally without requiring any modification of your code. This goal is very hard to achieve while both providing unlimited customizability and innovating the framework itself, as the project’s every customization has to work well with every new release.
Just as perfection is a fool’s errand, trying to achieve the ideal e-commerce framework is practically impossible. There are two principal forms of extensibility in open-source packages and each satisfies a different subset of the requirements described earlier.
The first one is called open-box extensibility and enables you to directly change the source code and as a result permits unrestricted customizability. This approach, however, makes it harder to upgrade the system because you have to merge all the changes done by the package maintainers with your customizations manually.
The second approach, glass-box extensibility, does not allow for modification of the original package code and therefore creates a clear separation between your code and the code maintained by somebody else (Composer places this code in the vendor directory). The result is that the fixed common interface between your code and the package makes it possible to easily upgrade the package without the need of modifying your code. The same interface, however, will restrict the possibilities of customization.
Developer teams focused on a single project, whether they are an in-house team or a part of an agency offering a long-term allocation of developer time, tend to prioritize customizability. Typically they modify the codebase directly (open-box extensibility). This frees their hands from restrictions and allows them to change any feature of the project.
Developers that switch between projects routinely, which is often a necessity in software agencies maintaining a lot of different projects, tend to favor a solution that is upgradable, can reuse a lot of common components, and individual differences are easily visible. This allows for customization without modifying the original code itself, only extending it from the outside (glass-box extensibility).
The Shopsys Framework is focused on developer teams with a full and long-term focus on the project. Therefore, the core is an open-box. To address the issue of upgradability there will be components with isolated responsibilities, and to offer developers ready-to-use functionality, there will be plugins which will be easily installable into the Shopsys Framework.
Fully Customizable Core
To develop an e-commerce project based on Shopsys Framework, the basic premise is to fork the original core repository and modify it to reflect the needs of your business. This repository contains the business logic of a basic online store that you can build on, along with minimalistic responsive design templates you can use as a scaffold for your custom front-end.
For the core, we chose open-box extensibility (modifying the code directly) in contrast to glass-box extensibility of the components and plugins (where the code is not to be modified directly but it is extensible via configuration or inheritance instead). The open-box extensibility of the core guarantees unlimited customizability of your application. Every single feature is flexible and can be manipulated according to your own preferences, meaning you won’t have to rely on an existing extension point (eg. an event being triggered) or a supplied interface.
We believe that lean codebase that is easily modifiable is a better place to start building your project than a feature-rich platform with a lot of configurable options. This is because every unused feature bloats the code and makes successive changes harder and harder to implement. An additional advantage is a great support in IDE because of a lower amount of indirection, and better understandability even for more junior developers.
Because the core is the very heart of your application you should be the owner of its code. We firmly believe you should have maximum control over it and have the last word about all the features.
Components That Can Be Separately Upgraded
In every project, there is a lot of code dedicated to functionality which is not related to the core of your business, but you still need it there. And although they’re necessary, it can be a long wearisome job building them from the ground up. Instead, you may be better off using code maintained by other developers who have already put in the ‘leg work’.
For example, management of data grids in the administration can be extracted into a separate package. When extracted it can be developed independently of the core and released using Semantic Versioning. This would mean you can easily upgrade this specific package to get access to a new feature or to fix a known bug. That is what we call a component.
Here are some examples of what a component could be:
Images and thumbnails management
Spam protection of forms
Convenient file upload
HTTP smoke testing
Components can be highly abstract so they can be used in other Symfony applications (or even outside Symfony) or they can be more tightly bound to the Shopsys Framework inner workings. Either way, as long as it is in a separately versioned package it can be independently upgraded when a new version is released.
Even though there will be options to customize the behavior of the components to better fulfill your needs, you may require a completely different way of handling the particular task. In such cases, you can always stop using the specific component and implement the required behavior in your open-box core repository. This is made fairly easy due to the fact that components are isolated from each other — replacing one of them does not require modifying the others.
Plugins with Interfaces in Isolated Packages
To satisfy the need for an installable functionality, Shopsys Framework will provide a plugin system. You can install a plugin just by requiring its package via Composer and registering it in your application.
Here are some ideas for features implementable by plugins:
Product XML feeds
Payment method gateways
Package shipping integrations
Analytic service integrations
Registration and login via social networks
VAT calculation for different regions
The benefit of plugins is that they can provide out-of-the-box functionality when the functionality itself has been standardized. For example, when talking about payment systems, relying on a shared interface across systems assures that implementations of the functionality (such as Paypal), will have a lot if in common.
Compatibility with your forked version of the core will be granted by a separate package of interfaces used by a certain type of a plugin. A plugin repository will depend only on the interfaces while your core will depend on the interfaces as well as all the plugins you want to use.
In the near future we’re also hoping to present a marketplace site where you can find useful plugins for your application along with end-to-end customization guides, advanced tools, etc.
Clear Information About Changes
When working with code maintained by someone else for a long time it is very important to know about any changes, found issues, and upcoming features. When an important change is made we will announce it via our blog and/or in the CHANGELOG.md. Bug fixes, as well as security fixes, will be announced in the same way.
The original open-box core repository will be maintained and further developed in cooperation with the community. You can merge or cherry-pick important changes into your fork as you see fit. An importance source of information and assistance in this regard will be a clear Git history that we maintain along with descriptive commit messages. To ease the process of keeping up with any refactoring work we make in the original repository, such as renaming a method, there will also be automatic tools to help supplement the tedious work of manually doing it yourself.
In the event there is bug inside of a component or a plugin, a simple update via Composer will be enough. Thanks to Semantic Versioning you will always know whether the update just fixes issues, adds new features, or incorporates incompatible API changes.
Where Are We Now and Where Are We Heading
Currently, the architecture of the Shopsys Framework is monolithic. This means that all the code is stored in one repository with a high amount of classes tightly coupled together. The low amount of indirection helps to understand and maintain the code easily.
The repository contains a fully functional online store along with demonstrational data, tools for easier development with coding standard checks, and an automatic test suite.
Up to this point, we have focused on customizability and stability of the application so an individualized e-commerce project can be successfully built from it and maintained afterward. We have already verified this by developing a few online stores on it. Now we want to widen our focus on all three requirements mentioned above — customizability, extensibility, and upgradability.
Separation into Packages
We have separated the first component from the core (and we will release an article focused on it soon) and we are about to extract more to allow independent improvement of these features and their upgradability in your projects.
We’re also working on designing the interfaces used by plugins so a required functionality can be installed directly into a given project and be ready to use.
As we enter this phase of our work, we would love to receive feedback on this process. Please let us know in the comments below what types of features you would like to see as components and plugins.
More Details About Our Plan
At the moment we are putting together a roadmap that will provide some important milestones and describe the plan in more detail. We will release the roadmap at the end of this month, stay tuned.