Code Architecture Guidance and Tool

Edit on GitHub

This document outlines Spryker recommendations for the code architecture.

Architecture and layer separation

  • Storage/Search modules should not make RPC calls to ZED and should focus on fetching data from the key-value storage.
  • Maintain separation between layers, sticking to the following rules:
    • Avoid calling Facade functions in the Persistence layer.
    • Database queries must exclusively occur within the Persistence layer.
    • Ensure the Client layer is not dependent on Yves or Zed Communication layers.
    • Prevent the Service layer from relying on the Business layer of another module.
    • Encourage the Business layer to depend on the Persistence layer, for example, a Repository, but not on ORM directly.
    • Avoid cross-module Business layer dependencies. Use injected Facades instead.
  • To identify all violations, you can run docker/sdk cli vendor/bin/deptrac analyse on the ./src directory.

Dependency handling and business logic

  • Singleton instances should be provided from Dependency Provider classes, and avoid using getInstance() method outside the Dependency Provider.
  • Ensure there is no business logic within Non-Business layers. Plugins should focus on using business classes and making simple, one-line calls.
  • There is no need to follow the Bridge design pattern on the project level. Refrain from creating or extending bridges from the core.
  • Business Factory classes can resolve Repository, Entity Manager, and Config classes without needing initialization inside the Factory class.

Code quality

  • If a method has multiple tasks, it violates the Single Responsibility Principle. The ideal approach is for a method to perform one task that aligns with its name.
  • Handle exceptions in your code base to provide meaningful error messages to customers at runtime.
  • Separate reader and mapper responsibilities for optimal implementation; mappers convert data types, and readers retrieve data from sources.
  • Avoid using deprecated classes or functions.
  • Eliminate commented code blocks and unused classes or methods. Remove them instead of keeping them as comments.
  • Exclusively utilize constants within the configuration classes.
  • Utilize constants exclusively within configuration classes.
  • For the sake of the improved management, enhanced readability, and clearer code intent, avoid hard-coded strings and IDs with variables or constants.
  • Avoid unnecessary duplications from the core; consider using “parent” when applicable or exploring alternative development strategies such as plug-and-play.
  • Avoid suppressing PHPStan checks. These checks are there to improve the quality of the code base.

Code testability and cleanup

  • Avoid mocking a service outside a test environment.
  • Use of global variables will reduce the testability of the code base.
  • Remove example modules such as ExampleProductSalePage, ExampleStateMachine, etc.
  • Rather than relying on comments to ensure that code remains unchanged, we recommend creating a unit test that fails if the requirements are not met.

Tools

We use our Architecture Sniffer Tool to assert a certain quality of Spryker architecture for both core and project.

Running the tool

The sniffer can find a lot of violations and report them:

$ vendor/bin/console code:sniff:architecture

// Sniff a specific subfolder of your project - with verbose output
$ vendor/bin/console code:sniff:architecture src/Pyz/Zed -v

// Sniff a specific module
$ vendor/bin/console code:sniff:architecture -m Customer

Tip: c:s:a can be used as a shortcut.

Additional options:

  • -p: Priority [1 (highest), 2 (medium), 3 (experimental)] (defaults to 2)
  • -s: Strict (to also report those nodes with a @SuppressWarnings annotation)
  • -d: Dry-run, only output the command to be run

Run –help or -h to get help about usage of all options available.

See the architecture sniffer documentation for details and information on how to set it up for your CI system as a checking tool for each PR.