· 6 min read
5 reasons to like Spryker as a developer
Sharing my own 6+ years experience

I have been developing in PHP for over 15 years, and for the past 6 years, I have been working on Spryker projects. Right from the beginning, it was a breath of fresh air, and I am really happy that our paths crossed.
The goal of this article is not to convince you to use Spryker or compare it with other platforms. I have never worked with other e-commerce platforms. However, I will try to give you some highlights about working with Spryker as a developer.
Code Quality
Alright, let’s get this straight: in the PHP world, most applications have low code quality. It’s really easy to start with PHP; it’s not very strict about many things, which gave the language a good boost in the past, but also became a reason for its bad reputation. If you’ve ever tried to write a plugin for WordPress, you know what I’m talking about.
Luckily, there are modern PHP applications that prioritize code quality, and Spryker is one of them. While there is no perfect code, Spryker sets the bar pretty high.
Without diving deep into architecture, let’s take the checkout implementation as an example. The checkout process in e-commerce usually consists of a few steps, such as choosing an address, delivery method, payment method, etc.
In Spryker, each step is represented by a class with this interface:
interface StepInterface
{
public function preCondition(AbstractTransfer $quoteTransfer): bool;
public function requireInput(AbstractTransfer $quoteTransfer): bool;
public function execute(Request $request, AbstractTransfer $quoteTransfer);
public function postCondition(AbstractTransfer $quoteTransfer): bool;
/*...*/
}Source: Github
Method names clearly indicate what to do: defining pre- and post-conditions for each step and implementing an execute logic, which contains the main business logic for the step.
Setting requireInput to false allows you to create “hidden” steps that don’t require user interaction.
All the steps are collected together in the StepEngine class, which contains elegant yet powerful code that manages the entire process:
$currentStep = $this->stepCollection->getCurrentStep($request, $quoteTransfer);
if (!$currentStep->preCondition($quoteTransfer)) {
return $this->createRedirectResponse($this->stepCollection->getEscapeUrl($currentStep));
}
if (!$this->stepCollection->canAccessStep($currentStep, $request, $quoteTransfer)) {
return $this->createRedirectResponse($this->stepCollection->getCurrentUrl($currentStep));
}
if (!$currentStep->requireInput($quoteTransfer)) {
$quoteTransfer = $this->executeWithoutInput($currentStep, $request, $quoteTransfer);
return $this->createRedirectResponse($this->stepCollection->getNextUrl($currentStep, $quoteTransfer));
}
if (!$this->isRequestedStep($request, $currentStep)) {
return $this->createRedirectResponse($this->stepCollection->getCurrentUrl($currentStep));
}
/*....*/Source: Github
Even if you see this code for the first time, I’m pretty sure you can understand what is going on here. The best code is the code that is easy to read without any documentation.
It’s worth mentioning that the Spryker codebase is covered by numerous sniffers and checkers, such as PHPCodeSniffer, PHPStan, PHPMD, and others.
Extensibility
A lot of e-commerce shops are pretty “standard” and don’t require too much customization. I’m pretty sure that Shopify and other similar platforms work quite well for them. But in the case of complicated enterprise projects, extensibility is key. What does Spryker have to offer here?
Almost every part of Spryker’s core functionality can be extended without copy-pasting the entire module or feature. Let’s take the checkout engine from the previous chapter as an example.
You can easily configure the sequence of steps by just overriding one method:
public function getSteps(): array
{
return [
$this->createEntryStep(),
$this->createCustomerStep(),
$this->createAddressStep(),
/// ... other steps
];
}Source: Github
You can also replace each step completely with just overriding the entire class like CustomerStep or AddressStep.
You can also extend any of the steps using object inheritance. Almost all methods in Spryker core are either public or protected, so the logic can be easily overwritten.
class CustomerStep extends SprykerCustomerStep
{
public function requireInput(AbstractTransfer $quoteTransfer)
{
return false;
}
}You can also create a new class, based on the original one (which would be the preferred way, but we will discuss it in a separate article).
class CustomerStep
{
private CustomerStep $sprykerCustomerStep
// .... overriding logic and reusing some of original
}Thanks to the modular structure and well-defined API between them, you can replace entire modules or groups of modules. For instance, if you don’t want customers to be handled inside of Spryker, you can have a separate service for them. Check the CustomerClientInterface and build a 3rd party following that interface - now you’re ready to replace it!
Architecture
In any complex project, architecture is one of the keys to overall success. Spryker defines many concepts out of the box and helps to build really powerful solutions.
Spryker is divided into several applications, with each application further divided into several modules, and finally each module introduces several levels. All this to promote SOLID principles and provide flexibility and extensibility. It might be overwhelming at first, but after gaining some experience with the platform, it starts to make a lot of sense.
Another architectural pillar worth mentioning is that relational databases (MySQL or PostgreSQL) are not used directly in the frontend applications. Instead, all data is fetched from Redis or Elasticsearch, which makes the frontend very performant and capable of handling high traffic easily.

Source: Spryker Documentation
Guidelines
When you’re building a project on top of Symfony or Laravel, you need to think about the application architecture yourself. How to organize modules, which patterns to use, and which dependencies to include? Such decisions are not easy and require a lot of time and expertise. If you’re working in a team, there will also be a lot of different opinions about any topic.
Spryker already provides guidelines for most use cases. Some decisions are good, some might not be, but they have already been made. It saves a lot of time! Additionally, there is the benefit of easy switching from one Spryker project to another, as many things will look the same.
One good example of guidelines is this article: Best practices for effective testing
Tooling
Developing for Spryker is not easy, but there are a lot of tools that are supposed to help you.
Docker SDK is an app that helps set up docker containers on your local machine or deploy them into the cloud. You have probably worked with docker-compose.yml before, so docker/sdk allows you to do much more and provides a lot of nice shortcuts to control the apps. For instance, docker/sdk jobs stop will stop all the Jenkins background jobs, and docker/sdk console -x data:import merchant will run a data import of merchants in debug mode.
Spryk is a code generator. Everyone admits that Spryker has a lot of boilerplate and repetitive code, so Spryks were created to simplify developers’ lives. They are installed as a composer package and provide a console command that can be used during development.
Few PHPStorm extensions from the community are also available to install and make the creation of new classes much easier. Let’s see what AI can offer here in the future ;)
Summary
In this article, I was happy to share with you what I like the most about Spryker. If you’re looking for other arguments, feel free to check this video and Github repo.
Stay tuned for the next articles!
