Slide 1

Slide 1 text

Designing for Change: Extensibility points in practice SymfonyCon Vienna 2024

Slide 2

Slide 2 text

$ whoami Adam Wójs • Director of Engineering @ Ibexa • > 14 years of experience • Working with PHP ecosystem /adamwojs /adamwojs /adamwojs

Slide 3

Slide 3 text

Who is Ibexa ?

Slide 4

Slide 4 text

What is Ibexa DXP ? • CMS + PIM & Commerce + Personalization • Based on Symfony • Highly customizable • 90+ composer packages • 350+ REST endpoints • 1,6+ mln lines of codes (*.php)

Slide 5

Slide 5 text

Agenda Extension Points Events Decorators Strategies

Slide 6

Slide 6 text

Extension points

Slide 7

Slide 7 text

What is an Extension Point? Extension Point is a code designed and introduced to enable customization of a functionality without altering the original codebase.

Slide 8

Slide 8 text

What is an Extension Point? Extension Point is a code designed and introduced to enable customization of a functionality without altering the original codebase.

Slide 9

Slide 9 text

What is an Extension Point? Extension Point is a code designed and introduced to enable customization of a functionality without altering the original codebase.

Slide 10

Slide 10 text

How to provide extensibility points ?

Slide 11

Slide 11 text

Events

Slide 12

Slide 12 text

Events Use case 1. Customize default logic 2. Notifications Infrastructure code ★★☆ (provided by symfony/event-dispatcher component) Steps to introduce 1. Create event class 2. Dispatch event 3. Process result (if applicable) Comments Can be used inside of the core logic and works with multiple clients by default

Slide 13

Slide 13 text

Example: kernel.controller event Description • Dispatched while processing request, after the controller has been resolved but before executing it • Used to initialize things or change the controller just before the controller is executed Example usage Collecting profiler data about routing (see Symfony\Component\HttpKernel\DataCollector\RequestDataCollector) Source symfony/http-kernel package

Slide 14

Slide 14 text

Example: ControllerEvent class

Slide 15

Slide 15 text

Example: ControllerEvent class Extends Symfony\Contracts\EventDispatcher\Event

Slide 16

Slide 16 text

Example: ControllerEvent class Setter for a new controller that is used in the processing of the request

Slide 17

Slide 17 text

Events: dispatching kernel.controller event

Slide 18

Slide 18 text

Events: dispatching kernel.controller event An extension point is triggered during the process of controller resolution

Slide 19

Slide 19 text

Events: dispatching kernel.controller event Processing results

Slide 20

Slide 20 text

Events: best practices • Provide documentation on when a given event is dispatched and how to change its outcome (if applicable) • Group related events by introducing base class or marker interface. For example. For example: 1. Symfony\Component\Form\FormEvent 2. Symfony\Component\HttpKernel\Event\KernelEvent 3. Symfony\Component\Workflow\Event\Event

Slide 21

Slide 21 text

Decorators

Slide 22

Slide 22 text

Decorators Use case Add new behaviors on top of existing objects Infrastructure code ★☆☆ (provided by symfony/dependency-injection component) Steps to introduce 1. Extract an interface 2. Register the service using interface FQCN introduced in a previous point as an alias to concreate implementation. 3. Provide abstract decorator (optional) Comments N/A

Slide 23

Slide 23 text

Abstract decorators • An abstract decorator is an abstract class that implements a decorated interface and delegates execution to the decorated instance. • Eliminates boilerplate code in client implementations when decorating complex interfaces. • Must-have for complex interfaces

Slide 24

Slide 24 text

Example: EntityManagerDecorator Description • The EntityManager is the central access point to ORM functionality. • Doctrine\ORM\EntityManagerInterface declares 27 methods + 8 inherited methods • Doctrine ORM provides abstract decorator for EntityManagerInterface: Doctrine\ORM\Decorator\EntityManagerDecorator Source: doctrine/orm package

Slide 25

Slide 25 text

Example: EntityManagerDecorator You should never attempt to inherit from the EntityManager: Inheritance is not a valid extension point for the EntityManager. Instead you should take look at the \Doctrine\ORM\Decorator\EntityManagerDecorator and wrap your entity manager in a decorator. Source: https://github.com/doctrine/orm/blob/3.3.x/src/EntityManager.php#L53-L56

Slide 26

Slide 26 text

Example: EntityManagerDecorator

Slide 27

Slide 27 text

Example: EntityManagerDecorator Injecting decorated instance

Slide 28

Slide 28 text

Example: EntityManagerDecorator Delegate execution to decorated instance

Slide 29

Slide 29 text

Decorators: best practices • Provide interface for a services which are indented to be decorated. Expose them as a contract. • Create abstract decorator in case of the complex interfaces • Avoid decoration for a combination of main interfaces and optional feature interfaces

Slide 30

Slide 30 text

Strategy

Slide 31

Slide 31 text

Strategy Use case Define a family of interchangeable algorithms Infrastructure code ★★☆ (provided by symfony/dependency-injection component) Steps to introduce 1. Introduce strategy interface 2. Implement out-of-the-box implementations (optional) 3. Register service with tag of your choice 4. Use the right strategy Comments N/A

Slide 32

Slide 32 text

Example: Placeholder Provider Description Generating placeholders if image is missing or unavailable Example usage • Ibexa\Bundle\Core\Imagine\PlaceholderProvider\GenericProvider • Ibexa\Bundle\Core\Imagine\PlaceholderProvider\RemoteProvider Source ibexa/core package

Slide 33

Slide 33 text

Example: Placeholder Provider Generic provider Remote provider (with placekitten.com) vs

Slide 34

Slide 34 text

Example: Placeholder Provider configuration

Slide 35

Slide 35 text

Example: Placeholder Provider

Slide 36

Slide 36 text

Example: Placeholder Provider Strategy interface

Slide 37

Slide 37 text

Example: Placeholder Provider

Slide 38

Slide 38 text

Example: Placeholder Provider Service tag used to mark service as one of the available strategies

Slide 39

Slide 39 text

Example: Placeholder Provider Strategy identifier

Slide 40

Slide 40 text

Example: Placeholder Provider Extension point is triggered by method call

Slide 41

Slide 41 text

Strategy registry Use case • Listing available strategies • Selecting strategy based on configuration • Adding & removing strategies in runtime Infrastructure code ★★★ (custom code) Steps to introduce 1. Introduce registry class along side with corresponding interface Comments N/A

Slide 42

Slide 42 text

Example: Payment method type registry Description Access to all available strategies Example usage • Ibexa\Bundle\Payment\Form\Type\PaymentMethodTypeChoiceType Source ibexa/payment package

Slide 43

Slide 43 text

Example: Strategy registry

Slide 44

Slide 44 text

Example: Strategy registry Allows to iterate over available strategies

Slide 45

Slide 45 text

Example: Strategy registry Accessors for a strategy

Slide 46

Slide 46 text

Strategy: best practices • Strategy interface alongside with the corresponding service tag should be considered as a contract • Introduce registry if you want to give a client access to manage available strategies from runtime

Slide 47

Slide 47 text

Extension points

Slide 48

Slide 48 text

Extension points are easy to introduce, but…

Slide 49

Slide 49 text

Cost of extension point Code Complexity Extension points requires additional abstractions. Testing Complexity You need to account for various customization scenarios during testing. Maintenance Effort Once an extension point is established, removing or modifying it can break existing customizations. Extension point requires extensive documentation. … but they come with a cost:

Slide 50

Slide 50 text

Summary • Extension points is a code introduced to enable customization without altering the original codebase • Design patterns are foundation of extensibility. Both symfony/event- dispatcher & symfony/dependency-injection components provides necessary infrastructure code for extension points in most cases • Extension points are easy to introduce, but they come with a cost of increased code & testing complexity as well as extra maintenance effort

Slide 51

Slide 51 text

PLAY NOW! Win a pair of headphones with Ibexa Developing the digital experience

Slide 52

Slide 52 text

Q&A

Slide 53

Slide 53 text

Thank you!