<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SparkFabrik</title>
    <description>The latest articles on DEV Community by SparkFabrik (@sparkfabrik).</description>
    <link>https://dev.to/sparkfabrik</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7395%2F42eb7906-d3bf-4dbc-b417-55a45ece44a0.png</url>
      <title>DEV Community: SparkFabrik</title>
      <link>https://dev.to/sparkfabrik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sparkfabrik"/>
    <language>en</language>
    <item>
      <title>Drupal service container deep dive (Part 2): aliases, autowiring, and named arguments</title>
      <dc:creator>Lusso Luca</dc:creator>
      <pubDate>Wed, 10 Dec 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/drupal-service-container-deep-dive-part-2-aliases-autowiring-and-named-arguments-4oh8</link>
      <guid>https://dev.to/sparkfabrik/drupal-service-container-deep-dive-part-2-aliases-autowiring-and-named-arguments-4oh8</guid>
      <description>&lt;p&gt;In this second part of our deep dive into the Drupal service container, we explore the concepts of aliases, autowiring, and named arguments.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19s9nft3mfd421lbwzlt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19s9nft3mfd421lbwzlt.png" alt="Drupal Service Container deep dive, part 2" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://www.google.com/search?q=/en/blog/drupal-service-container-deep-dive-part-1" rel="noopener noreferrer"&gt;first part&lt;/a&gt; of this series, we explored the basics of the Drupal service container, including how services are defined and how dependencies are injected. We discussed concepts such as &lt;strong&gt;tags&lt;/strong&gt;, &lt;strong&gt;compiler passes&lt;/strong&gt;, &lt;strong&gt;service providers&lt;/strong&gt;, and &lt;strong&gt;autoconfiguration&lt;/strong&gt;. In this second part, we will delve deeper into more advanced concepts such as &lt;strong&gt;aliases&lt;/strong&gt;, &lt;strong&gt;autowiring&lt;/strong&gt;, and &lt;strong&gt;named arguments&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aliases
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;alias&lt;/strong&gt; in the Drupal service container is a way to create an alternative name for an existing service. This is particularly useful when you want to refer to a service by a different name without changing the original service definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;request_stack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Symfony\Component\HttpFoundation\RequestStack&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;persist&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;Symfony\Component\HttpFoundation\RequestStack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@request_stack'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we define a service &lt;code&gt;request_stack&lt;/code&gt; and then create an alias &lt;code&gt;Symfony\Component\HttpFoundation\RequestStack&lt;/code&gt; that points to the same service. This allows us to refer to the &lt;code&gt;RequestStack&lt;/code&gt; service using either name interchangeably. This specific example works because a service name is just a string, and we can use anything that is a valid string as a service name, including class names.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A service name is just a string: &lt;code&gt;config.factory&lt;/code&gt;, &lt;code&gt;entity_type.manager&lt;/code&gt;, &lt;code&gt;Symfony\Component\HttpFoundation\RequestStack&lt;/code&gt;, are all valid service names.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Starting from Drupal 10.1, most of the core services have been aliased with the Fully Qualified Class Name (FQCN) of the service class.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Change record: &lt;a href="https://www.drupal.org/node/3323122" rel="noopener noreferrer"&gt;https://www.drupal.org/node/3323122&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, you can create your own aliases in your custom modules to improve code readability and maintainability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;webprofiler.profiler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\Profiler\Profiler&lt;/span&gt;
 &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;[&lt;/span&gt;
     &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.file_storage'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
     &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@logger.channel.webprofiler'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
     &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@config.factory'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
   &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;Drupal\webprofiler\Profiler\Profiler'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.profiler'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a service name is equal to the service class FQCN, the service container can automatically resolve and inject dependencies simply by matching the requested FQCN.&lt;/p&gt;

&lt;p&gt;This feature is called autowiring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autowiring
&lt;/h2&gt;

&lt;p&gt;Autowiring is a feature of the Drupal (and Symfony) service container that allows for automatic dependency injection based on type hints. When a service is defined with autowiring enabled, the container will automatically resolve and inject the required dependencies based on the type hints specified in the constructor or method signatures.&lt;/p&gt;

&lt;p&gt;The service will be instantiated in exactly the same way as before, but there is no need to explicitly specify which arguments are required; the interfaces/classes that are declared in the service constructor will be used to discover which services should be injected.&lt;/p&gt;

&lt;p&gt;Autowire can be enabled at service level, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;_defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;autoconfigure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;webprofiler.profiler_listener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\EventListener\ProfilerListener&lt;/span&gt;
    &lt;span class="na"&gt;autowire&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or globally for all services, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;_defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;autoconfigure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;autowire&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;webprofiler.profiler_listener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\EventListener\ProfilerListener&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In Symfony, when a &lt;strong&gt;single&lt;/strong&gt; service exists for a given interface or class, the service container &lt;strong&gt;automatically&lt;/strong&gt; creates an alias for it using the FQCN. This means that you can type-hint against the interface or class in your constructor, and the container will automatically inject the correct service. This &lt;strong&gt;is not the case&lt;/strong&gt; in Drupal, where you need to &lt;strong&gt;explicitly&lt;/strong&gt; create the alias as shown above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Multiple services for the same interface
&lt;/h3&gt;

&lt;p&gt;Usually, a Drupal module extends the &lt;code&gt;logger.channel_base&lt;/code&gt; service to build a new logger with the module name, like in this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;_defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;autowire&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;autoconfigure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;logger.channel.module_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logger.channel_base&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;module_name'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;my_service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\module_name\MyService&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both &lt;code&gt;logger.channel_base&lt;/code&gt;, &lt;code&gt;logger.channel.module_name&lt;/code&gt;, and every logger defined by Core and modules are instances of the same interface: &lt;code&gt;Psr\Log\LoggerInterface&lt;/code&gt;. As there are many services in the service container that implement &lt;code&gt;Psr\Log\LoggerInterface&lt;/code&gt;, which specific implementation will be injected in a constructor like this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Log\LoggerInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;LoggerInterface&lt;/span&gt; &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the service container will throw an exception because it cannot determine which specific service to inject:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cd7hvrmj8cw494s512s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cd7hvrmj8cw494s512s.png" alt="Exception thrown when multiple services match the type hint" width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some services cannot be autowired, usually because the interface is implemented by multiple different services (like loggers or cache bins in Drupal).&lt;br&gt;
In this case, we must use the &lt;code&gt;#[Autowire]&lt;/code&gt; attribute to clearly specify which service to inject, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Log\LoggerInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\DependencyInjection\Attribute\Autowire&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;#[Autowire(service: 'logger.channel.module_name')]&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;LoggerInterface&lt;/span&gt; &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Autowiring in Controllers and Hooks
&lt;/h3&gt;

&lt;p&gt;A controller is not a service and it's not loaded by the service container. When a route is matched, Drupal uses the controller loader service (&lt;code&gt;controller_resolver&lt;/code&gt;) to create an instance of the controller class. The controller loader calls the &lt;code&gt;create&lt;/code&gt; method on the controller class to instantiate it. The &lt;code&gt;create&lt;/code&gt; method receives the entire service container and creates a new instance of the controller class with the required services. This is an implementation of the service locator &lt;strong&gt;anti-pattern&lt;/strong&gt;, as shown in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ControllerBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;Profiler&lt;/span&gt; &lt;span class="nv"&gt;$profiler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;TemplateManager&lt;/span&gt; &lt;span class="nv"&gt;$templateManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerInterface&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;DashboardController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'webprofiler.profiler'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'webprofiler.template_manager'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting from Drupal 10.2, &lt;code&gt;ControllerBase&lt;/code&gt; (the base class for controllers in Drupal) uses the &lt;code&gt;AutowireTrait&lt;/code&gt;, so if the controller constructor uses type hints and the &lt;code&gt;#[Autowire]&lt;/code&gt; attribute where necessary, we can take advantage of autowiring in controllers as well.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;AutowireTrait&lt;/code&gt; uses reflection to read the constructor parameters and their attributes, so it has a performance impact.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\DependencyInjection\AutowireTrait&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ControllerBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;AutowireTrait&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;Profiler&lt;/span&gt; &lt;span class="nv"&gt;$profiler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;TemplateManager&lt;/span&gt; &lt;span class="nv"&gt;$templateManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see in the previous example, the &lt;code&gt;create&lt;/code&gt; method is no longer required. The &lt;code&gt;AutowireTrait&lt;/code&gt; can be used for any classes that implement &lt;code&gt;ContainerInjectionInterface&lt;/code&gt; (for some reason, &lt;code&gt;FormBase&lt;/code&gt; does not use it yet, but you can easily add it to your &lt;a href="https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/dependency-injection-for-a-form#s-service-autowiring-in-forms" rel="noopener noreferrer"&gt;custom forms&lt;/a&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With the upcoming Drupal 11.3, a similar feature will be available for plugins too: &lt;a href="https://www.drupal.org/project/drupal/issues/3452852" rel="noopener noreferrer"&gt;Add create() factory method with autowired parameters to PluginBase&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Starting from Drupal 11.1, hooks can be defined in classes (&lt;a href="https://www.drupal.org/node/3442349" rel="noopener noreferrer"&gt;https://www.drupal.org/node/3442349&lt;/a&gt;). All hook classes are automatically registered as &lt;strong&gt;autowired services&lt;/strong&gt;, so you can use autowiring in hook classes as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\file\Hook&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileViewsHooks&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;EntityTypeManagerInterface&lt;/span&gt; &lt;span class="nv"&gt;$entityTypeManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;EntityFieldManagerInterface&lt;/span&gt; &lt;span class="nv"&gt;$entityFieldManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;?FieldViewsDataProvider&lt;/span&gt; &lt;span class="nv"&gt;$fieldViewsDataProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="na"&gt;#[Hook('field_views_data')]&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;fieldViewsData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;FieldStorageConfigInterface&lt;/span&gt; &lt;span class="nv"&gt;$field_storage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;fieldViewsDataProvider&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;defaultFieldImplementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$field_storage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Autowiring in Services vs Non-Services
&lt;/h3&gt;

&lt;p&gt;It's important to note that while services benefit from autowiring when properly configured, there are cases where you might want to use autowiring but cannot modify the class constructor to fix the type hint or to add the &lt;code&gt;#[Autowire]&lt;/code&gt; attribute. This is where named arguments come into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  Named Arguments
&lt;/h2&gt;

&lt;p&gt;Named arguments provide an alternative way to specify dependencies in the service definition file itself, without requiring changes to the PHP code. This is particularly useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're working with third-party classes that you cannot modify&lt;/li&gt;
&lt;li&gt;You want to keep dependency configuration separate from the code&lt;/li&gt;
&lt;li&gt;You need to inject a specific service when multiple implementations of the same interface exist (as an alternative to using the &lt;code&gt;#[Autowire]&lt;/code&gt; attribute)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Named arguments allow us to specify which arguments to pass to a service when it is being instantiated, by name rather than by position. The syntax uses the parameter name (with a &lt;code&gt;$&lt;/code&gt; prefix) as the key in the arguments section.&lt;/p&gt;

&lt;p&gt;For example, let's say we have a service class with a constructor like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Symfony\Component\Messenger\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendMessageMiddleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;SendersLocatorInterface&lt;/span&gt; &lt;span class="nv"&gt;$sendersLocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;EventDispatcherInterface&lt;/span&gt; &lt;span class="nv"&gt;$eventDispatcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of passing arguments by position, we can use named arguments in the service definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;messenger.middleware.send_message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Symfony\Component\Messenger\Middleware\SendMessageMiddleware&lt;/span&gt;
  &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;$eventDispatcher&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@event_dispatcher'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're explicitly specifying that the &lt;code&gt;$eventDispatcher&lt;/code&gt; parameter should receive the &lt;code&gt;@event_dispatcher&lt;/code&gt; service. This is much clearer than using positional arguments, especially when dealing with optional parameters or when you want to skip some arguments.&lt;/p&gt;

&lt;p&gt;Named arguments are particularly powerful when combined with autowiring. The container will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First try to autowire all type-hinted parameters based on their types&lt;/li&gt;
&lt;li&gt;Then override specific parameters with any named arguments you've defined&lt;/li&gt;
&lt;li&gt;Use default values for any remaining optional parameters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means you can let autowiring handle most dependencies automatically while using named arguments only for the specific cases where you need explicit control, such as when multiple services implement the same interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;_defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;autowire&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;autoconfigure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;my_custom_service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\my_module\MyCustomService&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;$logger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@logger.channel.my_module'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, most dependencies of &lt;code&gt;MyCustomService&lt;/code&gt; will be autowired, but we're explicitly specifying which logger to inject using a named argument, solving the ambiguity problem we discussed earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing It All Together
&lt;/h2&gt;

&lt;p&gt;Now that we understand aliases, autowiring, and named arguments, let's see how they work together to simplify service definitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Traditional Service Definition
&lt;/h3&gt;

&lt;p&gt;In older Drupal code, a service definition might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;webprofiler.profiler_listener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\EventListener\ProfilerListener&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.profiler'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@request_stack'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.matcher.exclude_path'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicitly listing every dependency&lt;/li&gt;
&lt;li&gt;Maintaining the correct order of arguments&lt;/li&gt;
&lt;li&gt;Updating the YAML file whenever constructor parameters change&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Modern Service Definition with Aliases and Autowiring
&lt;/h3&gt;

&lt;p&gt;With the concepts we've covered, we can dramatically simplify this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;_defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;autoconfigure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;autowire&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;Drupal\webprofiler\EventListener\ProfilerListener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Aliases&lt;/strong&gt;: The service is registered using its FQCN, which serves as both the service name and alias&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autowiring&lt;/strong&gt;: The container automatically resolves dependencies based on type hints in the constructor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autoconfiguration&lt;/strong&gt;: The service is automatically tagged if it implements certain interfaces&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;In Yaml, &lt;code&gt;~&lt;/code&gt; symbol (tilde) is equivalent to an empty array or null, meaning no additional configuration is needed. In this case, the tilde can be omitted entirely, but in my opinion, it's clearer to explicitly show that no further configuration is necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this second part of our deep dive into the Drupal service container, we have explored three powerful concepts that work together to modernize dependency injection in Drupal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aliases&lt;/strong&gt; enable us to reference services by their class names, making code more intuitive and refactoring safer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autowiring&lt;/strong&gt; eliminates boilerplate by automatically resolving dependencies based on type hints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Named arguments&lt;/strong&gt; provide surgical precision when we need explicit control over specific dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these features reduce boilerplate code, improve maintainability, and make service definitions more readable. They represent a significant evolution in how Drupal developers work with the service container.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next parts of this series, where we will continue to explore more advanced features of the Drupal service container:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.google.com/search?q=/en/blog/drupal-service-container-deep-dive-part-1" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt;&lt;/strong&gt; covers service tags, compiler passes, service providers, and autoconfiguration, laying the groundwork for understanding how services are defined and managed within the container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.google.com/search?q=/en/blog/drupal-service-container-deep-dive-part-3" rel="noopener noreferrer"&gt;Part 3&lt;/a&gt;&lt;/strong&gt; will cover service collectors, which aggregate multiple services into a single service for streamlined access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 4&lt;/strong&gt; will explore factories, which provide a mechanism for creating services with complex initialization logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 5&lt;/strong&gt; will discuss backend overrides, enabling developers to customize service implementations for specific environments or use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 6&lt;/strong&gt; will examine advanced features of the Drupal service container, such as service decoration and lazy loading.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;




</description>
      <category>drupal</category>
      <category>php</category>
      <category>dependency</category>
      <category>autowiring</category>
    </item>
    <item>
      <title>Drupal service container deep dive part 1: tags, compiler passes, service providers and autoconfiguration</title>
      <dc:creator>Lusso Luca</dc:creator>
      <pubDate>Mon, 03 Nov 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/drupal-service-container-deep-dive-part-1-tags-compiler-passes-service-providers-and-a95</link>
      <guid>https://dev.to/sparkfabrik/drupal-service-container-deep-dive-part-1-tags-compiler-passes-service-providers-and-a95</guid>
      <description>&lt;p&gt;In this first part of our deep dive into the Drupal service container, we explore the concepts of tags, compiler passes, service providers, and autoconfiguration.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F6897318.fs1.hubspotusercontent-na1.net%2Fhubfs%2F6897318%2FBlog%2Fdrupal_service_container-p1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F6897318.fs1.hubspotusercontent-na1.net%2Fhubfs%2F6897318%2FBlog%2Fdrupal_service_container-p1.png" title="Drupal Service Container deep dive, part 1" alt="Drupal Service Container deep dive, part 1" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The evolution of Drupal core has increasingly embraced modern PHP standards and robust object-oriented programming (OOP) principles, driven largely by its integration of &lt;strong&gt;Symfony components&lt;/strong&gt;. Central to this modernization is the &lt;strong&gt;Service Container&lt;/strong&gt;, which acts as the core registry responsible for service instantiation, dependency resolution, and lifecycle management.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;service&lt;/strong&gt; is inherently a specialized, reusable, and stateless object designed to perform a single, well-defined task, such as ConfigFactory for configuration access or EntityTypeManager for entity access.  &lt;/p&gt;

&lt;p&gt;The philosophy underpinning service usage is the promotion of loose coupling and adherence to the Dependency Inversion Principle (DIP). A class using a service should request it from the container rather than manually instantiating it with the &lt;code&gt;new&lt;/code&gt; keyword. This arrangement enables developers to swap implementations without altering consuming code.  &lt;/p&gt;

&lt;p&gt;In this series of articles, we will explore the Drupal service container in depth, focusing on its features, capabilities, and best practices for leveraging it effectively in Drupal module development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Part 1&lt;/strong&gt; will cover service tags, compiler passes, service providers, and autoconfiguration, laying the groundwork for understanding how services are defined and managed within the container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 2&lt;/strong&gt; will delve into aliases, autowiring, and name arguments, demonstrating how to resolve and inject dependencies based on type hints, reducing boilerplate code and enhancing maintainability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 3&lt;/strong&gt; will cover service collectors, which aggregate multiple services into a single service for streamlined access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 4&lt;/strong&gt; will explore factories, which provide a mechanism for creating services with complex initialization logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 5&lt;/strong&gt; will discuss backend overrides, enabling developers to customize service implementations for specific environments or use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 6&lt;/strong&gt; will examine advanced features of the Drupal service container, such as service decoration and lazy loading.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Anatomy of a Drupal service
&lt;/h2&gt;

&lt;p&gt;A Drupal service is defined within a module's &lt;code&gt;MODULE.services.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# in modules/contrib/webprofiler/webprofiler.services.yml&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;webprofiler.matcher.exclude_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\RequestMatcher\WebprofilerRequestMatcher&lt;/span&gt;
        &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@path.matcher'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@config.factory'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;exclude_paths'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# in core/core.services.yml&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path.matcher&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\Core\Path\PathMatcher&lt;/span&gt;
        &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@config.factory'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@current_route_match'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;config.factory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\Core\Config\ConfigFactory&lt;/span&gt;
    &lt;span class="na"&gt;current_route_match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\Core\Routing\CurrentRouteMatch&lt;/span&gt;
        &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@request_stack'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;request_stack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Symfony\Component\HttpFoundation\RequestStack&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When code asks for the &lt;code&gt;webprofiler.matcher.exclude_path&lt;/code&gt; service, the Drupal service container first builds all the required services and finally builds an instance of the &lt;code&gt;WebprofilerRequestMatcher&lt;/code&gt; class by injecting all the dependencies in the &lt;code&gt;__construct&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\webprofiler\RequestMatcher&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\Config\ConfigFactoryInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\Path\PathMatcherInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\RequestMatcherInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebprofilerRequestMatcher&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RequestMatcherInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;PathMatcherInterface&lt;/span&gt; &lt;span class="nv"&gt;$pathMatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;ConfigFactoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$configFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resolution graph looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqp27lietbzk4660zhrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqp27lietbzk4660zhrf.png" alt="The resolution graph looks like this" width="684" height="692"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;So Drupal first builds the &lt;code&gt;request_stack&lt;/code&gt; service, then the &lt;code&gt;current_route_match&lt;/code&gt; service (which depends on &lt;code&gt;request_stack&lt;/code&gt;), then the &lt;code&gt;config.factory&lt;/code&gt; service, then the &lt;code&gt;path.matcher&lt;/code&gt; service (which depends on both &lt;code&gt;config.factory&lt;/code&gt; and &lt;code&gt;current_route_match&lt;/code&gt;), and finally the &lt;code&gt;webprofiler.matcher.exclude_path&lt;/code&gt; service (which depends on both &lt;code&gt;path.matcher&lt;/code&gt; and &lt;code&gt;config.factory&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Notice that the third argument of the &lt;code&gt;webprofiler.matcher.exclude_path&lt;/code&gt; service is a string (&lt;code&gt;exclude_paths&lt;/code&gt;). The service container supports injecting scalar values like strings, integers, and booleans as arguments to services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@&lt;/code&gt; prefix indicates a service reference.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%&lt;/code&gt; prefix indicates a parameter reference.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@?&lt;/code&gt; indicates an optional service reference.&lt;/li&gt;
&lt;li&gt;No prefix indicates a literal value.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;param1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;some&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;string'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;some_service1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Some\Class\Name1&lt;/span&gt;

  &lt;span class="na"&gt;some_service2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Some\Class\Name2&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@some_service1'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%param1%'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;42&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;another&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;string'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@?some_service3'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the code for &lt;code&gt;some_service2&lt;/code&gt; would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Some\Class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Name2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;Name1&lt;/span&gt; &lt;span class="nv"&gt;$someService1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$param1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$param2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nv"&gt;$param3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$param4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;?Name3&lt;/span&gt; &lt;span class="nv"&gt;$someService3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Differences between Drupal and Symfony service containers
&lt;/h2&gt;

&lt;p&gt;The Drupal service container is built on top of the Symfony service container, inheriting many of its features and capabilities. However the Drupal modular architecture and specific requirements have led to several changes. On the other hand, Drupal doesn't use the Symfony Config component for service configuration, instead relying on its own YAML-based service definition files.&lt;/p&gt;

&lt;p&gt;At the end both YAML loading and service container dumping have been heavily customized in Drupal to fit its architecture and performance needs, resulting in a service container that is optimized for Drupal's unique use cases but not fully equivalent to the standard Symfony service container.&lt;/p&gt;

&lt;p&gt;Those differences can lead to some confusion when reading Symfony documentation, as some features may not be available or behave differently in Drupal. This article series aims to clarify those differences and provide a comprehensive understanding of the Drupal service container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Tags
&lt;/h2&gt;

&lt;p&gt;Service tags are metadata annotations that can be applied to service definitions within the Drupal service container. They provide a way to categorize and group services based on their functionality or purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;webprofiler.database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\DataCollector\DatabaseDataCollector&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@database'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@config.factory'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;data_collector&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="nv"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler/Collector/database.html.twig'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;database'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Database'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="nv"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;750&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tag has a mandatory &lt;code&gt;name&lt;/code&gt; attribute and can have any number of additional attributes. In the example above, the &lt;code&gt;webprofiler.database&lt;/code&gt; service is tagged with the &lt;code&gt;data_collector&lt;/code&gt; tag, along with several additional attributes such as &lt;code&gt;template&lt;/code&gt;, &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;label&lt;/code&gt;, and &lt;code&gt;priority&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Tags on their own don't actually alter the functionality of a service in any way. They are primarily used to identify services for special processing during the container compilation phase, often through the use of compiler passes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiler Passes
&lt;/h2&gt;

&lt;p&gt;Compiler passes are a mechanism that allows developers to modify the service container during its compilation phase. They provide a way to programmatically alter service definitions, add or remove services, and manipulate tags before the container is fully built and dumped to the cache&lt;/p&gt;

&lt;p&gt;Compiler passes are particularly useful for implementing complex service registration logic, such as dynamically adding services based on configuration or other runtime conditions. They are executed in a specific order during the container compilation process, allowing for fine-grained control over the final service definitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\webprofiler\Compiler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\DependencyInjection\ContainerBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfilerPass&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CompilerPassInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findTaggedServiceIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'data_collector'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="mf"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A shown in the example above, the &lt;code&gt;ProfilerPass&lt;/code&gt; class implements the &lt;code&gt;CompilerPassInterface&lt;/code&gt; and defines a &lt;code&gt;process&lt;/code&gt; method that is called during the container compilation phase. Within this method, the &lt;code&gt;findTaggedServiceIds&lt;/code&gt; function is used to retrieve all services tagged with &lt;code&gt;data_collector&lt;/code&gt;, allowing for custom processing of those services. The &lt;code&gt;process&lt;/code&gt; method can modify the service definitions as needed, such as adding additional arguments, changing class names, or even removing services from the container.&lt;/p&gt;

&lt;p&gt;A compiler pass must be registered with the container in order to be executed during the compilation phase. This is typically done within a module's service provider class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Providers
&lt;/h2&gt;

&lt;p&gt;Service providers are classes that encapsulate the logic for dynamically registering or altering services within the Drupal service container. Service providers typically extend the &lt;code&gt;ServiceProviderBase&lt;/code&gt; class and re-define the &lt;code&gt;register&lt;/code&gt; or &lt;code&gt;alter&lt;/code&gt; methods to add or modify service definitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\webprofiler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\DependencyInjection\ContainerBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\DependencyInjection\ServiceProviderBase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebprofilerServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceProviderBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;alter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name and the namespace of the service provider class must follow a specific convention: it should be named &lt;code&gt;ModuleServiceProvider&lt;/code&gt; and be located in the root namespace of the module. For example, the service provider for the &lt;code&gt;webprofiler&lt;/code&gt; module is named &lt;code&gt;WebprofilerServiceProvider&lt;/code&gt; and is located in the &lt;code&gt;Drupal\webprofiler&lt;/code&gt; namespace. If the module name contains underscores, they should be removed and the following letter capitalized (e.g., &lt;code&gt;search_api&lt;/code&gt; becomes &lt;code&gt;SearchApiServiceProvider&lt;/code&gt;). Core has its own service provider named &lt;code&gt;CoreServiceProvider&lt;/code&gt; located in the &lt;code&gt;Drupal\Core&lt;/code&gt; namespace.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;register&lt;/code&gt; method can be used to add compiler passes to the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\webprofiler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\DependencyInjection\ContainerBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\DependencyInjection\ServiceProviderBase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebprofilerServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceProviderBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCompilerPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProfilerPass&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the order of execution of compiler passes matters, you can specify the pass &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;priority&lt;/code&gt; when adding the compiler pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCompilerPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProfilerPass&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PassConfig&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TYPE_BEFORE_OPTIMIZATION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Values for &lt;code&gt;type&lt;/code&gt; can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PassConfig::TYPE_BEFORE_OPTIMIZATION&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PassConfig::TYPE_OPTIMIZE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PassConfig::TYPE_BEFORE_REMOVING&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PassConfig::TYPE_REMOVE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PassConfig::TYPE_AFTER_REMOVING&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This diagram that illustrates when compiler passes are executed during the Symfony service container compilation process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftx6d3l84mm783bzckpvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftx6d3l84mm783bzckpvl.png" alt="This diagram illustrates when compiler passes are executed during the Symfony service container compilation process" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;TYPE_BEFORE_OPTIMIZATION&lt;/strong&gt; (Blue): Where most custom compiler passes (like &lt;code&gt;ProfilerPass&lt;/code&gt;) are typically registered. This is where services are analyzed and tagged services are processed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TYPE_OPTIMIZE&lt;/strong&gt; (Purple): Internal Symfony optimization passes that inline services and optimize the container structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TYPE_BEFORE_REMOVING&lt;/strong&gt; (Orange): Validation passes that check for circular references and definition validity before cleanup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TYPE_REMOVE&lt;/strong&gt; (Red): Cleanup passes that remove unused services and private aliases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TYPE_AFTER_REMOVING&lt;/strong&gt; (Green): Final optimization passes after cleanup is complete.&lt;/p&gt;

&lt;p&gt;Within each phase, compiler passes are executed in priority order (highest to lowest), allowing for fine-grained control over the execution sequence when multiple passes are registered in the same phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autoconfiguration
&lt;/h2&gt;

&lt;p&gt;Autoconfiguration is a powerful feature of the Drupal service container that allows services to be automatically tagged based on their class definitions.&lt;/p&gt;

&lt;p&gt;When a service is defined in the container, the autoconfiguration process analyzes the class and applies the appropriate tags. For example, if a service implements a specific interface or extends a particular base class, the container can automatically apply the relevant tags to the service definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\Core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoreServiceProvider&lt;/span&gt;
    &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ServiceProviderInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServiceModifierInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nv"&gt;$container&lt;/span&gt;
          &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerForAutoconfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EventSubscriberInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'event_subscriber'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;alter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, the &lt;code&gt;CoreServiceProvider&lt;/code&gt; class registers an autoconfiguration rule that automatically tags any service implementing the &lt;code&gt;EventSubscriberInterface&lt;/code&gt; with the &lt;code&gt;event_subscriber&lt;/code&gt; tag. This means that when a service is defined that implements this interface, it will automatically receive the &lt;code&gt;event_subscriber&lt;/code&gt; tag without needing to explicitly define it in the service definition.&lt;/p&gt;

&lt;p&gt;Autoconfiguration is particularly useful for module developers, as it streamlines the process of registering services and ensures that they are properly configured without requiring extensive boilerplate code.&lt;/p&gt;

&lt;p&gt;Since Drupal 10.2.0, several interfaces have been registered for autoconfiguration in &lt;code&gt;CoreServiceProvider&lt;/code&gt;. At the time of writing (Drupal 11.3.0), those interfaces, and their corresponding tags, are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MediaLibraryOpenerInterface&lt;/code&gt; (tag: media_library.opener)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EventSubscriberInterface&lt;/code&gt; (tag: event_subscriber)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LoggerAwareInterface&lt;/code&gt; (tag: logger_aware)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PreWarmableInterface&lt;/code&gt; (tag: cache_prewarmable)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ModuleUninstallValidatorInterface&lt;/code&gt; (tag: module_install.uninstall_validator)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, custom autoconfiguration rules can be added in any module's service provider class, allowing for tailored service tagging based on specific module requirements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\sm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SmServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ServiceProviderInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerForAutoconfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TransportFactoryInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'messenger.transport_factory'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerForAutoconfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ServiceLocator&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'container.service_locator'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, autoconfiguration only works for tags that doesn't have attributes.&lt;/p&gt;

&lt;p&gt;With all those concepts in place, we can remove some boilerplate from our service definition by going from a service definition like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;webprofiler.profiler_listener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\EventListener\ProfilerListener&lt;/span&gt;
  &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.profiler'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@request_stack'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.matcher.exclude_path'&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;event_subscriber&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;webprofiler.profiler_listener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\EventListener\ProfilerListener&lt;/span&gt;
  &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.profiler'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@request_stack'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@webprofiler.matcher.exclude_path'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;assuming that the &lt;code&gt;ProfilerListener&lt;/code&gt; class implements the &lt;code&gt;EventSubscriberInterface&lt;/code&gt;, which is already registered for autoconfiguration in &lt;code&gt;CoreServiceProvider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the next part of this series, we will explore &lt;strong&gt;aliases&lt;/strong&gt;, &lt;strong&gt;autowiring&lt;/strong&gt;, and &lt;strong&gt;named arguments&lt;/strong&gt;, demonstrating how to resolve and inject dependencies based on type hints, reducing boilerplate code, enhancing maintainability, and going even further in simplifying service definitions by removing the &lt;code&gt;arguments&lt;/code&gt; section entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;webprofiler.profiler_listener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\webprofiler\EventListener\ProfilerListener&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stay tuned!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>php</category>
      <category>dependency</category>
      <category>autowiring</category>
    </item>
    <item>
      <title>Codemotion Milan 2025</title>
      <dc:creator>Daniela Bonvini</dc:creator>
      <pubDate>Wed, 22 Oct 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/codemotion-milan-2025-3hk2</link>
      <guid>https://dev.to/sparkfabrik/codemotion-milan-2025-3hk2</guid>
      <description>&lt;p&gt;Highlights and reflections from Codemotion Milan 2025, covering key talks on testing strategies, modern CSS, Chrome DevTools, and AI prompt strategies.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Codemotion Milan 2025: Highlights and Reflections
&lt;/h2&gt;

&lt;p&gt;Last week I had the chance to attend &lt;strong&gt;Codemotion Milan 2025&lt;/strong&gt;, and honestly, &lt;em&gt;it was a blast&lt;/em&gt;. Picture hundreds of developers, designers, and tech enthusiasts buzzing around packed rooms, debating over coffee, and getting genuinely excited about new ideas. It felt like the perfect mix of community, curiosity, and caffeine.&lt;/p&gt;

&lt;p&gt;The schedule was stacked with everything from frontend magic to backend mysteries, and testing strategies to AI, DevOps, and software architecture. After two days of sessions, demos, and hallway chats, a few talks really stuck with me; for their substance, their delivery, and the sparks they set off in my brain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Testing Strategy is Broken: Let’s Fix It! by Luise Freese
&lt;/h2&gt;

&lt;p&gt;Luise Freese is an amazing speaker, funny but insightful (and it doesn't hurt that she likes pink &lt;em&gt;and&lt;/em&gt; unicorns). I had the pleasure of seeing her speak last year, so I was &lt;em&gt;really&lt;/em&gt; looking forward to her session this time around.&lt;br&gt;
In this talk she took a refreshing look at what’s &lt;em&gt;wrong with&lt;/em&gt; how we usually approach &lt;em&gt;testing&lt;/em&gt;. Her point was simple but powerful: &lt;em&gt;stop testing everything&lt;/em&gt; just for the sake of it. Aiming for 100% coverage sounds good on paper, but often just creates a mountain of useless unit tests that never actually catch the things that break in production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fstages_codemotion2025.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fstages_codemotion2025.jpeg" title="Three of the multiple stages of Codemotion Milan 2025 with the respective speakers presenting to the audience" alt="Three of the multiple stages of Codemotion Milan 2025 with the respective speakers presenting to the audience" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luise argued for a &lt;em&gt;smarter, leaner approach&lt;/em&gt; — fewer tests, but better ones. Focus on how your system behaves under pressure, on integration points, on what your users will actually notice when things go wrong. As she put it, users don’t care how many tests you’ve written; they care that the software works.&lt;/p&gt;

&lt;p&gt;It was one of those talks that make you rethink your day to day habits. I left the room thinking less about coverage reports and more about value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fluise_freeze_codemotion2025.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fluise_freeze_codemotion2025.jpeg" title="Luise Freeze explaining testing strategies at Codemotion Milan 2025" alt="A person speaking in front of a crowd with a monitor behind them showing a slide about testing strategies" width="800" height="782"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Baseline Rhapsody: A Tale of Style &amp;amp; Motion by Emiliano Pisu
&lt;/h2&gt;

&lt;p&gt;Emiliano Pisu’s talk was basically a love letter to &lt;em&gt;modern CSS&lt;/em&gt;, and heaven knows if we need more CSS love in the developer community. He took us on a journey from the wild days of floats and tables to the sleek, expressive world of &lt;em&gt;container queries&lt;/em&gt;, &lt;em&gt;scroll-driven animations&lt;/em&gt;, and &lt;em&gt;CSS custom properties&lt;/em&gt;. His main message: we’re living in a golden age of frontend styling, and we should start acting like it.&lt;/p&gt;

&lt;p&gt;He introduced the new &lt;em&gt;Baseline standard&lt;/em&gt;, a sort of “truth table” for web features that tells you what’s &lt;em&gt;safe to use across browsers&lt;/em&gt; right now. No more endless guessing games or praying to the compatibility gods.&lt;/p&gt;

&lt;p&gt;What I loved most was Emiliano’s mix of technical depth and creative energy. He made CSS feel exciting again, and honestly, I walked out wanting to rebuild half our design system just to play with the new toys.&lt;/p&gt;

&lt;h2&gt;
  
  
  ChromeDevTools: Are You Confident in Your Expertise? by Luca Del Puppo
&lt;/h2&gt;

&lt;p&gt;This talk was like discovering hidden cheat codes in a game you’ve been playing for years. Luca Del Puppo took something every JavaScript dev uses daily, &lt;em&gt;Chrome DevTools&lt;/em&gt;, and showed us just how much more it can do when you dig deep.&lt;/p&gt;

&lt;p&gt;He demoed advanced debugging tricks, &lt;em&gt;performance profiling&lt;/em&gt;, and how to uncover sneaky issues like &lt;em&gt;layout thrashing&lt;/em&gt; and &lt;em&gt;memory leaks&lt;/em&gt;. It wasn’t just a feature tour, it was a hands on masterclass in how to actually &lt;em&gt;think&lt;/em&gt; with your tools.&lt;/p&gt;

&lt;p&gt;What made it memorable was Luca’s energy and real-world examples. You could tell he’s spent countless hours battling tough bugs, and he made us feel like we could take on anything with DevTools as our sidekick. I walked away with a bunch of new debugging tricks and a renewed appreciation for a tool I thought I’d already mastered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fhall_codemotion2025.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fhall_codemotion2025.jpeg" title="Main hall of Codemotion Milan 2025" alt="People walking and talking in the main hall of Codemotion Milan 2025" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt Strategies: Useful for AI (and Maybe for Everyday Life) by Francesco Sciuti
&lt;/h2&gt;

&lt;p&gt;Right before my train home, I managed to squeeze in part of Francesco Sciuti’s workshop &lt;em&gt;“Prompt Strategies: utile per l'AI e (forse) anche per l'uso quotidiano”&lt;/em&gt;, which roughly translates to &lt;em&gt;“Prompt Strategies: useful for AI (and maybe also for everyday life).”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It was less of a formal talk and more of a round table conversation. Francesco walked us through how to write prompts that actually make AI behave, how to get the answers you &lt;em&gt;want&lt;/em&gt;, in the &lt;em&gt;format&lt;/em&gt; you need, without the weird hallucinations or vague replies we’ve all seen. He shared practical examples, frameworks for structuring prompts clearly, and even a few thoughts on &lt;em&gt;Context Engineering&lt;/em&gt;. Basically, how to give an AI the right background to think straight.&lt;/p&gt;

&lt;p&gt;Sadly, I had to leave halfway through to catch my train, but what I saw was genuinely enlightening. It wasn’t just about AI — it was about &lt;em&gt;communication&lt;/em&gt;, &lt;em&gt;precision&lt;/em&gt;, and how &lt;em&gt;phrasing things clearly&lt;/em&gt; can make all the difference, whether you’re prompting a model or just talking to your team. Best new term of the year coined by Francesco: &lt;em&gt;Vibe Prototyping&lt;/em&gt;, instead of the old &lt;em&gt;Vibe Coding&lt;/em&gt;, which better represents how we can approach AI interactions in a more purposeful and cooperative way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fcard_magic_codemotion2025.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fcodemotion2025%2Fcard_magic_codemotion2025.jpeg" title="A fake Magic: The Gathering card showing the text 'Codemotion'" alt="A fake Magic: The Gathering card showing the text 'Codemotion'" width="800" height="1120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Made These Talks Stand Out
&lt;/h2&gt;

&lt;p&gt;Looking back, the sessions that I liked more had a few things in common. They were &lt;em&gt;practical&lt;/em&gt;, &lt;em&gt;grounded&lt;/em&gt;, and a little &lt;em&gt;opinionated&lt;/em&gt;, the kind of talks that give you ideas to try the next morning, not just slides to bookmark and forget that are more like someone reading the documentation to you instead of explaining a new concept with their own voice and thoughts. They also had a strong personal touch — you could tell the speakers were passionate about their topics, and that enthusiasm was contagious.&lt;/p&gt;

&lt;p&gt;Codemotion Milan 2025 nailed that vibe. It wasn’t about chasing buzzwords or hyping the latest framework. It was about &lt;em&gt;building better software, with intention and creativity&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Overall, the event was a brilliant reminder that learning in tech doesn’t have to be dry or intimidating. It can be lively, surprising, and even a little fun. The mix of talks, workshops, and casual conversations made it clear that &lt;em&gt;the heart of any tech community is curiosity, collaboration, and a willingness to experiment&lt;/em&gt;. And Codemotion Milan 2025 had all of that and even more.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>techevent</category>
      <category>codemotion</category>
      <category>community</category>
    </item>
    <item>
      <title>The Lord Of The Stores: A Quest For Angular State Mastery</title>
      <dc:creator>Daniela Bonvini</dc:creator>
      <pubDate>Thu, 04 Sep 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/the-lord-of-the-stores-a-quest-for-angular-state-mastery-2j2g</link>
      <guid>https://dev.to/sparkfabrik/the-lord-of-the-stores-a-quest-for-angular-state-mastery-2j2g</guid>
      <description>&lt;p&gt;In the complex world of NgRx state management three powerful stores can guide us: Global Store, vast and unifying; Component Store, swift and precise; Signal Store, reactive and efficient. But wielding them unwisely leads to an unmanageable state. Join this journey through NgRx best practices, avoiding pitfalls, and mastering scalability. Will your app stand strong or fall into disorder? The fate of state management rests in your hands!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The framework has changed. I feel it in the code. I feel it in the builds. I smell it in the tech forums.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It began with the forging of the Great Stores. Three were given to Angular developers—structured, scalable, and reactive above all else.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;The &lt;strong&gt;Global Store&lt;/strong&gt;, vast and powerful. The &lt;strong&gt;Component Store&lt;/strong&gt;, lightweight and precise. And the &lt;strong&gt;Signal Store&lt;/strong&gt;, fresh and efficient.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For within these stores was bound the power to manage state, to bring order to applications. Each with its own strengths, each suited for different needs.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Because the world of state management is treacherous, and without guidance, chaos can still arise. For the time will soon come when NgRx will shape the fortunes of all devs.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fhobbits_crossing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fhobbits_crossing.png" title="a danger road sign but inside of it is an hobbit silhouette and at the bottom the writing 'Danger hobbits crossing'" alt="a danger road sign but inside of it is an hobbit silhouette and at the bottom the writing 'Danger hobbits crossing'" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Obligatory disclaimer&lt;/strong&gt;: as you may have noticed after this slightly weird intro, in this article I will reference Lord Of The Rings lore, but if you’re not a fan of the movies or books don’t worry, of course it’s not needed to understand the explained concepts. (Although, I &lt;em&gt;strongly&lt;/em&gt; suggest you to watch/read it, as it is an amazing saga).&lt;/p&gt;




&lt;h2&gt;
  
  
  An Unexpected Journey
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fgandalf-confused.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fgandalf-confused.jpg" title="Gandalf confused reading a scroll with 'component store' written on it" alt="Gandalf confused reading a scroll with 'component store' written on it" width="512" height="256"&gt;&lt;/a&gt;&lt;br&gt;
The idea for this article came to me after I discussed with my team the option to start using a state management library for our application. At the time we used services that mimicked store slices and we wanted to switch them into full-fledged NgRx stores.&lt;/p&gt;

&lt;p&gt;Until that moment I had only used the &lt;strong&gt;Global Store&lt;/strong&gt;, heard of the &lt;strong&gt;Signal Store&lt;/strong&gt; and didn’t even know the &lt;strong&gt;Component Store&lt;/strong&gt; existed, until I read the NgRx official documentation (see, someone &lt;em&gt;does RTFM&lt;/em&gt; sometimes).&lt;/p&gt;

&lt;p&gt;As we didn’t have any specific requests on what to use, we were open to any one of them.&lt;/p&gt;

&lt;p&gt;We took some time researching, and I found out that, as far as I know, there are no articles or videos directly comparing the differences between these stores, their use cases, and their pros and cons.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Feasy_state_management.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Feasy_state_management.jpg" title="Gandalf telling Theoden how easy state management is" alt="Gandalf telling Theoden how easy state management is" width="570" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fast forward a couple of months later and a lot of material revised, and here we are: I hope my findings will help someone in a similar position to mine figure out a little bit easier which store to choose for their own case.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fvilya_card.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fvilya_card.png" title="A TCG card showing the ring Vilya" alt="A TCG card showing the ring Vilya" width="424" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Global Store – Vilya, The Ring of Air
&lt;/h2&gt;

&lt;p&gt;Let’s start with the &lt;strong&gt;Global Store&lt;/strong&gt;, the most powerful option, associated with &lt;em&gt;Vilya&lt;/em&gt;, the ring given to Elrond, symbolizing wisdom and governance.&lt;/p&gt;

&lt;p&gt;Likewise, the Global Store manages large state in applications, providing structure and predictability. It is &lt;strong&gt;ideal for apps with complex state that multiple components must access and update&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, this power comes with &lt;strong&gt;complexity&lt;/strong&gt;: it requires a solid understanding of reducers, actions, effects, and RxJS, which adds to the learning curve. It demands boilerplate code and many interconnected parts, which can be overwhelming, especially for smaller apps or simpler state needs.&lt;/p&gt;

&lt;p&gt;But this union of actions and effects is the Global Store’s strength, enabling features like &lt;strong&gt;time-travel debugging with native Redux DevTools&lt;/strong&gt; integration. Developers can step backward and forward in the application’s state history, making changes easier to trace and debug.&lt;/p&gt;

&lt;p&gt;Having matured over many years, the Global Store also offers an &lt;strong&gt;opinionated and structured&lt;/strong&gt; way of managing state, helping teams organize logic across files and maintain consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Global Store – Pros and Cons
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best for large-scale apps with complex state shared across multiple components&lt;/td&gt;
&lt;td&gt;High complexity (reducers, actions, effects, selectors) + RxJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easier debugging using time-travel with Redux DevTools&lt;/td&gt;
&lt;td&gt;Steep learning curve&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mature: opinionated and structured way of managing state&lt;/td&gt;
&lt;td&gt;Lots of boilerplate code to interconnect everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Too much overhead for smaller applications&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Example of use cases:&lt;/strong&gt; large apps with complex, shared business logic (multi-step forms, shopping carts shared across multiple features) or global data like feature flags, notifications, or permissions.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fnenya_card.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fnenya_card.png" title="A TCG card showing the ring Nenya" alt="A TCG card showing the ring Nenya" width="429" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Nenya – The Ring of Water, The Component Store
&lt;/h2&gt;

&lt;p&gt;Then comes the &lt;strong&gt;Component Store&lt;/strong&gt;, the underdog of the state management world, yet full of potential. I associate it with Nenya, Galadriel’s ring, symbolizing preservation and stability.&lt;/p&gt;

&lt;p&gt;The Component Store works seamlessly with the Global Store without conflict, allowing effective &lt;strong&gt;state management with minimal changes&lt;/strong&gt; to your codebase. You can see it like a &lt;strong&gt;service managing state with Subjects&lt;/strong&gt;, but with added clarity and best practices.&lt;/p&gt;

&lt;p&gt;It’s a &lt;strong&gt;lightweight solution&lt;/strong&gt; ideal for &lt;strong&gt;managing local component&lt;/strong&gt; or feature module state, promoting modularity and isolation. It supports multiple &lt;strong&gt;independent instances&lt;/strong&gt; of the same component, maintaining &lt;strong&gt;clean separation of concerns&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its API is &lt;strong&gt;simpler than that of the Global Store&lt;/strong&gt;, as it doesn't require actions or reducers, making it easier to learn. However, it lacks developer tool support like time-travel debugging since it doesn't utilize trackable actions.&lt;/p&gt;

&lt;p&gt;Trade-offs include &lt;strong&gt;scalability challenges&lt;/strong&gt;: state, updaters, selectors, and effects typically reside in the same file, which can become difficult to manage as logic increases. Also, since state is tied to the component lifecycle, it is removed when the component is destroyed, making it &lt;strong&gt;inappropriate for persistent or shared state&lt;/strong&gt; across components.&lt;/p&gt;

&lt;p&gt;In summary, the Component Store offers store-like benefits without the Global Store's complexity.&lt;/p&gt;

&lt;p&gt;Now, I must make a small confession: lately the NgRx team has put on the component store page a note saying that &lt;em&gt;they consider the signal store the new default for local state management&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fngrx_signals_new_default.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fngrx_signals_new_default.png" title="A notice saying that they recommend the signal store for managing local state" alt="A notice saying that they recommend the signal store for managing local state" width="800" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But&lt;/em&gt;, I nevertheless wanted to talk about component store as a lot of people may be &lt;strong&gt;stuck on older versions&lt;/strong&gt; of Angular and may not be able to easily upgrade to signals and signal store usage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fnpm_downloads.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fnpm_downloads.png" title="The number of downloads of the various Angular versions from npm" alt="The number of downloads of the various Angular versions from npm" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see from &lt;a href="https://www.npmjs.com/package/@angular/core?activeTab=versions" rel="noopener noreferrer"&gt;npm&lt;/a&gt;, still hundreds of thousands of people download Angular to versions less than 17 (signal store was released with NgRx version 17). But these same people may still be in need of a smaller store for their state management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Store – Pros and Cons
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lightweight solution for local component state&lt;/td&gt;
&lt;td&gt;Low scalability as everything is in the same file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple independent instances of the same component allowing separation of concerns&lt;/td&gt;
&lt;td&gt;No permanent state, as it is reset on component destruction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simple syntax and state management (no actions or reducers)&lt;/td&gt;
&lt;td&gt;No Redux DevTools time-travel debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Example of use cases:&lt;/strong&gt; managing a form’s input values, validation, and submission state, or controlling the visibility and behavior of a modal within a component.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fnarya_card.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fnarya_card.png" title="A TCG card showing the ring Narya" alt="A TCG card showing the ring Narya" width="423" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Narya – The Ring of Fire, The Signal Store
&lt;/h2&gt;

&lt;p&gt;And lastly, the &lt;strong&gt;Signal Store&lt;/strong&gt;, represented by Narya, Gandalf’s ring of courage and action.&lt;/p&gt;

&lt;p&gt;It reflects the NgRx team’s bold shift toward &lt;strong&gt;simplicity and performance&lt;/strong&gt;. Built on Angular signals, it provides &lt;strong&gt;reactive and efficient state management&lt;/strong&gt;, removing unnecessary recalculations with a &lt;strong&gt;straightforward syntax&lt;/strong&gt; that you can use right away.&lt;/p&gt;

&lt;p&gt;In this store, &lt;strong&gt;state properties are signals&lt;/strong&gt;, allowing components to access them directly without selectors or boilerplate code. Its lightweight design and optional RxJS support make it ideal for modern Angular apps that want to reduce complexity and bundle size.&lt;/p&gt;

&lt;p&gt;However, it is still new, so official &lt;strong&gt;guidelines are limited&lt;/strong&gt;. Features like selector composition, route guard integration, and DevTools support are still being developed. The Signal Store also &lt;strong&gt;forces you to use signals&lt;/strong&gt; or convert Observables into signals. This makes it best suited for &lt;strong&gt;small to medium-scale features&lt;/strong&gt; or isolated domains, while large-scale applications may still prefer the Global Store.&lt;/p&gt;

&lt;p&gt;One downside is that the Signal Store &lt;strong&gt;does not support Redux DevTools yet&lt;/strong&gt;. This means you lose features like time-travel debugging and state inspection.&lt;/p&gt;

&lt;p&gt;There is an &lt;strong&gt;unofficial alternative&lt;/strong&gt;, the &lt;a href="https://ngrx-toolkit.angulararchitects.io/docs/with-devtools" rel="noopener noreferrer"&gt;Angular Architects NgRx Toolkit&lt;/a&gt; browser extension, which offers partial support but does not fully match the Redux DevTools experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Signal Store – Pros and Cons
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;State properties as signals (no selectors)&lt;/td&gt;
&lt;td&gt;Still new, with limited official guidelines and documentation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plug and play (simple syntax and small bundle size)&lt;/td&gt;
&lt;td&gt;Advanced features are still evolving&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optional RxJS use&lt;/td&gt;
&lt;td&gt;Obligatory use of signals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good for reactive programming&lt;/td&gt;
&lt;td&gt;Best suited for small to medium-scale apps; not yet ideal for large-scale or enterprise apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extreme composability (you choose which features to use)&lt;/td&gt;
&lt;td&gt;No out-of-the-box Redux DevTools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Example of use cases:&lt;/strong&gt; managing UI-related states like toggles, modals, filters, and tabs where reactive updates are needed but complexity is low.&lt;/p&gt;




&lt;h2&gt;
  
  
  Choosing the Right Ring and Power
&lt;/h2&gt;

&lt;p&gt;We now have a better understanding of what each store can give us. But we still need to make a choice to understand which one is &lt;strong&gt;the right power for us&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Like the Elves wielding their rings wisely, developers must choose the right store for the right situation, as we know that &lt;em&gt;the wrong power in the wrong hands can lead to disastrous consequences&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fsauron.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fsauron.jpeg" title="The eye of Sauron" alt="The eye of Sauron" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We must avoid at all costs the temptation of using &lt;strong&gt;too much&lt;/strong&gt; or &lt;strong&gt;too little power&lt;/strong&gt; just because we &lt;em&gt;like&lt;/em&gt; one of the stores. Using a Global Store when local state would be better overcomplicates a simple problem. Conversely, sometimes a simple service+subjects/signals is all you need instead of any store at all.&lt;/p&gt;

&lt;p&gt;The choice between NgRx stores depends primarily on your &lt;strong&gt;project's complexity&lt;/strong&gt;, &lt;strong&gt;team size&lt;/strong&gt;, and &lt;strong&gt;growth expectations&lt;/strong&gt;. The &lt;em&gt;Global Store&lt;/em&gt; excels at enterprise-level applications. The &lt;em&gt;Signal Store&lt;/em&gt; offers a simpler alternative for smaller projects. The &lt;em&gt;Component Store&lt;/em&gt; provides a balanced approach suitable for medium-sized applications or feature modules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fstore_diagram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fstore_diagram.png" title="A diagram showing the various choices for choosing the right store" alt="A diagram showing the various choices for choosing the right store" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consider starting with the &lt;strong&gt;simplest solution&lt;/strong&gt; that meets your needs and &lt;strong&gt;scaling up&lt;/strong&gt; as your application grows.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fthe_one_ring.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fthe_one_ring.jpg" title="The one ring" alt="The one ring" width="700" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One Store to Bind All State
&lt;/h2&gt;

&lt;p&gt;But what if you want more power, more control, and you cannot choose between the three rings? Well, you also have the choice to &lt;strong&gt;combine them&lt;/strong&gt; to balance their respective flaws and strengths.&lt;/p&gt;

&lt;p&gt;For example, you can use the &lt;em&gt;Global Store&lt;/em&gt; for managing global state across the application, employ the &lt;em&gt;Component Store&lt;/em&gt; for encapsulating state within specific features, and integrate the &lt;em&gt;Signal Store&lt;/em&gt; where reactive and functional updates are most beneficial.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fthree_rings_power.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fthree_rings_power.jpg" title="The three rings combining together their strengths" alt="The three rings combining together their strengths" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These stores were deliberately made to &lt;strong&gt;work well together&lt;/strong&gt;. The complexity lies not in the implementation but in ensuring your team agrees on conventions and enforces them during reviews. Otherwise, wrongful mixes could lead to painful refactors.&lt;/p&gt;

&lt;p&gt;Having said that, I made a little &lt;a href="https://stackblitz.com/edit/fellowship-dashboard" rel="noopener noreferrer"&gt;task management dashboard on Stackblitz&lt;/a&gt;,&lt;br&gt;
to have a visual reference on how the code works.&lt;/p&gt;

&lt;p&gt;This is just a simple app to show how you can intertwine all of the aforementioned stores. Of course using all three is a bit too much, especially for this kind of small project, but this is obviously just an example to show how they can easily work together if the need arises. Usually I would suggest using only &lt;strong&gt;two of them together&lt;/strong&gt;: &lt;strong&gt;one for managing global properties&lt;/strong&gt; and &lt;strong&gt;one for managing component properties&lt;/strong&gt;.&lt;br&gt;
This dashboard has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A global quest assigner (managed by the &lt;em&gt;Global Store&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;A status card specifically for each member (managed by the &lt;em&gt;Component Store&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;A reactive search input (managed by the &lt;em&gt;Signal Store&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Fifth Age: The Age of NgRx State Management
&lt;/h2&gt;

&lt;p&gt;With the information we acquired we now know that these three stores &lt;strong&gt;bring order to the Middle Earth of state management&lt;/strong&gt;, but only if used wisely. &lt;em&gt;No one store rules them all — each has its own purpose.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Additionally, we now know that you can combine what they can do, to be even more powerful. But it is up to you to avoid the temptation of &lt;strong&gt;abusing their power&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fgaladriel_meme.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fgaladriel_meme.jpeg" title="Galadriel saying that she passed the test" alt="Galadriel saying that she passed the test" width="649" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now go into the world and use your power wisely, as the fate of Angular state management now rests in your hands.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fthe_end_hobbit.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fthe-lord-of-the-stores%2Fthe_end_hobbit.gif" title="The closing door of an hobbit home" alt="The closing door of an hobbit home" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.sparkfabrik.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ggch57mw62gl6e063r.png" alt="SparkFabrik" width="311" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ngrx</category>
      <category>statemanagement</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Public speaking is like eating chillies</title>
      <dc:creator>Daniela Bonvini</dc:creator>
      <pubDate>Mon, 01 Jul 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/public-speaking-is-like-eating-chillies-2jlg</link>
      <guid>https://dev.to/sparkfabrik/public-speaking-is-like-eating-chillies-2jlg</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This past year, after some soul searching and &lt;em&gt;a lot&lt;/em&gt; of nudging from some of the people around me, I finally took the big step and &lt;strong&gt;started giving public talks at tech conferences&lt;/strong&gt;. I started small, first at a local meetup group, then in front of my coworkers via video call, and finally in person in front of real people.&lt;/p&gt;

&lt;p&gt;In my clearly clickbait title, I compared this experience to eating chili peppers, which is one of the things I both love and fear most when I accidentally drop way too many chili flakes into a dish I just cooked.&lt;br&gt;
Why a culinary example? Well, for one thing, I like to cook, and for another, I'm Italian, so I guess it's written somewhere in our constitution that it's my civic duty to speak in food metaphors.&lt;/p&gt;

&lt;p&gt;I think it's an apt comparison: that first moment when you take that first bite of food, knowing full well that you've put &lt;em&gt;way too much&lt;/em&gt; seasoning on it, but you eat it anyway. And after the initial pain of too much spice, you realize that all in all, the dish now has &lt;strong&gt;more flavor&lt;/strong&gt; and &lt;strong&gt;more oomph&lt;/strong&gt;. But more than that, you're secretly proud of yourself for &lt;strong&gt;overcoming the fear of the initial discomfort&lt;/strong&gt;.&lt;br&gt;
Then there is the second time, when you do it again with another dish, where you have once again miscalculated the ingredients. Which is somehow made worse because you already know the initial pain, but at the same time you know the amazing amount of flavor and spiciness that would follow.&lt;br&gt;&lt;br&gt;
Well, this applies perfectly to public speaking, at least for me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8zar5hcgcgfpzxmeurkj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8zar5hcgcgfpzxmeurkj.jpeg" alt="A person speaking in front of a crowd of chilli peppers" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The first bite
&lt;/h2&gt;

&lt;p&gt;At my first local meetup talk, I was so scared that I &lt;em&gt;almost&lt;/em&gt; ran away, pretending to be sick. But then I persevered and delivered the talk I had prepared, and in the end I felt proud, both because it went well, but mostly because I did it by &lt;strong&gt;pushing through the fear of failure&lt;/strong&gt;.&lt;br&gt;
Then came another occasion of public speaking and, as in my culinary example from earlier, I was, if possible, even more frightened than before. But I persevered, and once again, overcoming the stage fright, came the satisfaction, both in myself and in what I had done.&lt;/p&gt;

&lt;p&gt;I won't sugarcoat it, that initial "&lt;em&gt;pain&lt;/em&gt;" never goes away. The majority of public speakers I have talked to say that they always get nervous, regardless of their years of experience. But they go through with it, knowing that the final morsel will be totally worth the initial suffering. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There must be a reason why it is a popular trope that in order to grow you have to get out of your comfort zone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And believe me, I know it's easier said than done; I'm extremely socially awkward, to the point where I'm afraid to even make phone calls to people or places I don't know, but trying to get over that initial discomfort with public speaking has really helped me get a little more comfortable around new people. I'm still not a party animal, but I'm starting to understand that the more you project a feeling of being relaxed to the outside world, the more your mind is tricked into thinking you're really relaxed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw6bns3fciwugsft6kq0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw6bns3fciwugsft6kq0.jpeg" alt="The roll safe meme with a caption that says 'Can't be anxious if you think you're not anxious" width="600" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately I have been feeling a little &lt;strong&gt;bolder&lt;/strong&gt; in my everyday life and people around me have been telling me that it shows that I feel &lt;strong&gt;more confident&lt;/strong&gt; and that I am speaking a lot more without being prompted. Another speaker at a conference even said that I was an extrovert and seemed perfectly at ease on stage. &lt;em&gt;Me&lt;/em&gt;. &lt;em&gt;Can you believe that&lt;/em&gt;?&lt;br&gt;
I spent most of my teenage years being told I needed to talk more, smile more, get out more, so it feels incredible to be told the opposite.&lt;/p&gt;

&lt;p&gt;In addition to the increased self-esteem, being a speaker at these kinds of events is a great way to meet other incredibly talented people who you'll most likely see at other conferences later on, thus reducing the subsequent anxiety of not knowing anyone. It's also incredibly &lt;strong&gt;good for networking&lt;/strong&gt;: I've had the opportunity to talk face-to-face with people I would never have had the chance to talk to otherwise, and to ask for advice on various topics, and I've always been treated with the utmost kindness.&lt;/p&gt;

&lt;h2&gt;
  
  
  The aftertaste
&lt;/h2&gt;

&lt;p&gt;What saddens me is that &lt;strong&gt;I see the most fear of speaking at these conferences coming from junior developers, especially female ones&lt;/strong&gt;. They are convinced that they are not good enough to be at these events because most of the speakers are already well-known or super skilled.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What they never think about is that precisely because they are a part of the tech world that is rarely represented at conferences, the reason to be that person is to become an &lt;strong&gt;inspiration to others&lt;/strong&gt; in a similar position. So those other people can think, "&lt;em&gt;hey, look at that, it's not impossible, I could do that too&lt;/em&gt;".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my personal experience, I would never have started on this path if I hadn't been part of a company that encourages participation in these events, and if I hadn't had some friends and colleagues who have achieved great things just through sheer dedication, doing things that I didn't think were possible for "&lt;em&gt;normal&lt;/em&gt;" people (&lt;em&gt;aka not senior developers or not already famous&lt;/em&gt;). Or even just for having people with the confidence in me that I lacked at that moment, but needed to embark on this adventure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I hope that these words will give some of you reading the same kind of support that I have received.&lt;/strong&gt;&lt;br&gt;
That if you are teetering on the edge of trying, but not finding the courage to send out a call for papers, that my words may inspire you to take the first step on the other side of public speaking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With my silly cooking example, I want to send a message to all the people who are curious about public speaking but don't think they are extroverted enough, good enough, knowledgeable enough, whatever enough to deserve to do it, to &lt;strong&gt;at least try it once&lt;/strong&gt;. And if after the initial discomfort you can feel the rewarding spiciness that comes afterward, then trust me, you are hooked for life.&lt;/p&gt;

&lt;p&gt;And if not, that's okay too, at least you tried, and now you'll certainly have a better understanding of yourself, and you can still be proud that you at least tried, and peacefully know that it wasn't for you, without any regrets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So go on, take that first spicy bite and get out of your comfort zone&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>publicspeaking</category>
      <category>community</category>
      <category>events</category>
    </item>
    <item>
      <title>Drupal Access Policy demystified</title>
      <dc:creator>Lusso Luca</dc:creator>
      <pubDate>Mon, 24 Jun 2024 10:35:53 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/drupal-access-policy-demystified-44bj</link>
      <guid>https://dev.to/sparkfabrik/drupal-access-policy-demystified-44bj</guid>
      <description>&lt;h2&gt;
  
  
  Access Policy in Core
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.drupal.org/blog/drupal-10-3-0" rel="noopener noreferrer"&gt;Drupal 10.3&lt;/a&gt; introduces a new way to assign permissions to users, going beyond the traditional roles and permissions system. This new system is called the &lt;strong&gt;Access Policy API&lt;/strong&gt;, and in this blog post, we'll try to explain how it works and how to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old way
&lt;/h2&gt;

&lt;p&gt;Until Drupal 10.2, the access control system was based on two main concepts: you were either in a &lt;strong&gt;role&lt;/strong&gt; that granted you a set of permissions or the &lt;strong&gt;user with UID 1&lt;/strong&gt;, and the access checks were bypassed.&lt;/p&gt;

&lt;p&gt;For example, you can have this code somewhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'access content'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code for &lt;code&gt;hasPermission&lt;/code&gt; simply checks for the two cases mentioned above: if the user is the one with UID 1 or if the user is in a role that grants that permission:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// User #1 has all privileges.&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entityTypeManager&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_role'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPermissionInRoles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getRoles&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation was quite simple and worked well when a user has a set of permissions that are valid sitewide and that don't change based on some external factors.&lt;/p&gt;

&lt;p&gt;If you need to implement use cases like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deny edit permissions on weekends&lt;/li&gt;
&lt;li&gt;allow edit permissions only if the user has 2FA enabled&lt;/li&gt;
&lt;li&gt;allow edit permissions only to contents in a group (or in a domain, or in a Commerce store, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're probably going to need &lt;em&gt;a lot&lt;/em&gt; of custom code (otherwise it's impossible to implement them).&lt;/p&gt;

&lt;h2&gt;
  
  
  The new way
&lt;/h2&gt;

&lt;p&gt;Drupal 10.3 introduced a new &lt;a href="https://www.drupal.org/node/3385551" rel="noopener noreferrer"&gt;Access Policy API&lt;/a&gt; that allows the definition of a set of policies that can be applied based on a context.&lt;/p&gt;

&lt;p&gt;If you want to know something about the genesis of this new system, you can read this blog post: &lt;a href="https://www.thedroptimes.com/40119/kristiaan-van-den-eynde-talks-about-policy-based-access-in-core" rel="noopener noreferrer"&gt;Policy-Based Access in Core by Kristiaan Van den Eynde&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The API is quite simple; you define a policy class that extends the &lt;code&gt;\Drupal\Core\Session\AccessPolicyBase&lt;/code&gt; and provide, at least, the implementation for the methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;calculatePermissions(AccountInterface $account, string $scope): RefinableCalculatedPermissionsInterface&lt;/code&gt;: Calculates the permissions for an account within a given scope&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getPersistentCacheContexts(): array&lt;/code&gt;: Gets the initial cache context this policy varies by&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A policy is then registered in the service container with the tag &lt;code&gt;access_policy.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Drupal 10.3 mimics the old behavior by providing two default policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;\Drupal\Core\Session\Access\UserRolesAccessPolicy&lt;/code&gt;: Grants permissions based on a user's roles&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\Drupal\Core\Session\Access\SuperUserAccessPolicy&lt;/code&gt;: Bypass permissions checks for the user with UID equal to 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;\Drupal\Core\Session\Access\UserRolesAccessPolicy&lt;/code&gt;, for example, is implemented as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRolesAccessPolicy&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AccessPolicyBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;EntityTypeManagerInterface&lt;/span&gt; &lt;span class="nv"&gt;$entityTypeManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculatePermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;RefinableCalculatedPermissionsInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;calculatePermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nv"&gt;$user_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entityTypeManager&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_role'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;loadMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getRoles&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

      &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_roles&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$user_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatedPermissionsItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_role&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$user_role&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCacheableDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_role&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getPersistentCacheContexts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user.roles'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous code retrieves the user's roles and adds a &lt;code&gt;CalculatedPermissionsItem&lt;/code&gt; with the permissions granted by each role. Then, it adds a cacheable dependency on the role entity so that if the role's permissions change, the cache is invalidated. Finally, the method &lt;code&gt;getPersistentCacheContexts&lt;/code&gt; returns the initial cache context that the policy varies by.&lt;/p&gt;

&lt;p&gt;We will discuss the meaning of &lt;code&gt;(Refinable)CalculatedPermissions&lt;/code&gt;, &lt;code&gt;scope&lt;/code&gt;, and &lt;code&gt;initial cache context&lt;/code&gt; shortly.&lt;/p&gt;

&lt;p&gt;The critical thing to understand here is that this new system does not aim to grant access to something, like editing a node or viewing a page. It's designed to calculate a user's permissions in a given context. The access check is still done in the old way, which checks if the user has specific permission to perform a task.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An access policy converts a context into a set of permissions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Access policies are services, allowing us to replace or decorate the implementation provided by Core. Indeed, the Core itself allows for the policy for the super user to be disabled to increase site security (&lt;a href="https://www.drupal.org/node/2910500" rel="noopener noreferrer"&gt;https://www.drupal.org/node/2910500&lt;/a&gt;). With the super user policy disabled, we may want to define a new one that grants admin permissions based on other user characteristics. For instance, we can specify that the site admins are users with a specific email domain or who have logged in through a particular authentication system.&lt;/p&gt;

&lt;p&gt;Now, let's dive into the details of the new system using some examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1 (alter permissions provided by Core)
&lt;/h3&gt;

&lt;p&gt;Let's say we want to add a new policy that grants permission to &lt;code&gt;access promotional banners&lt;/code&gt; only if the current language is English.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;LanguageAccessPolicy.php&lt;/code&gt; class may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LanguageAccessPolicy&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AccessPolicyBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;alterPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;RefinableCalculatedPermissionsInterface&lt;/span&gt; &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;
   &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Drupal&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;languageManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCurrentLanguage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'en'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatedPermissionsItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
               &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'access promotional banners'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="n"&gt;isAdmin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;overwrite&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;
         &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getPersistentCacheContexts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'languages'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To register the policy in the service container, you need to add the following to your &lt;code&gt;access_policy_demo.services.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;access_policy_demo.access_policy.language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\access_policy_demo\Access\LanguageAccessPolicy&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;access_policy&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now have this render array sonewhere in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$build&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="s1"&gt;'#markup'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'access promotional banners'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'Some promotional banner'&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'#cache'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s1"&gt;'contexts'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'languages'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
   &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous code will show the promotional banner only if the current language is English.&lt;/p&gt;

&lt;p&gt;Revoke permission is possible by setting the &lt;code&gt;overwrite&lt;/code&gt; parameter of the &lt;code&gt;addItem&lt;/code&gt; method to &lt;code&gt;TRUE&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$new_permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'view page revisions'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatedPermissionsItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$new_permissions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;isAdmin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;
   &lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="n"&gt;overwrite&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;TRUE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Altering permissions is possible because, during the access policy calculation, the object that holds the calculated permissions is an instance of the &lt;code&gt;RefinableCalculatedPermissionsInterface&lt;/code&gt; that allows the addition or removal of permissions.&lt;br&gt;
When the build and alter phases are complete, the calculated permissions are converted to an immutable object of type &lt;code&gt;CalculatedPermissionsInterface&lt;/code&gt;. Using an immutable object guarantees that the computed permissions are not altered after the access policy calculation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Drupal has moved from an RBAC (Role-Based Access Control) to a PBAC (Policy-Based Access Control) system where permissions are calculated based on a set of policies that are applied in a given context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Access policies are tagged services, so you can define the priority with which they are applied:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;access_policy_demo.access_policy.language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\access_policy_demo\Access\LanguageAccessPolicy&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;access_policy&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;100&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The priority is a positive or negative integer that defaults to 0. The higher the number, the earlier the tagged service will be located in the service collection.&lt;/p&gt;

&lt;p&gt;Now it's time to talk about &lt;strong&gt;scopes&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 2 (split the site into sections)
&lt;/h3&gt;

&lt;p&gt;Until now, we have ignored the &lt;code&gt;scope&lt;/code&gt; parameter, but look at how the &lt;code&gt;hasPermission()&lt;/code&gt; method is implemented in Drupal 10.3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;processAccessPolicies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;processAccessPolicies()&lt;/code&gt; has a second, non-mandatory parameter: the &lt;code&gt;scope&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;getItem()&lt;/code&gt; method has two non-mandatory parameters: the &lt;code&gt;scope&lt;/code&gt; and the &lt;code&gt;identifier&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Within Core, both &lt;code&gt;scope&lt;/code&gt; and &lt;code&gt;identifier&lt;/code&gt; default to &lt;code&gt;AccessPolicyInterface::SCOPE_DRUPAL&lt;/code&gt;, and you probably don't have to deal with them in most cases.&lt;/p&gt;

&lt;p&gt;But what are they used for?&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;scope&lt;/code&gt; is a string that identifies the context in which the policy is applied, like a group, a domain, a commerce store, etc. The &lt;code&gt;identifier&lt;/code&gt; is a string that identifies the specific value within the scope (like the group ID, the domain ID, etc).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;AccessPolicyInterface&lt;/code&gt; defines the &lt;code&gt;applies(string $scope): bool&lt;/code&gt; method, which determines whether the policy should be applied in a given scope.&lt;/p&gt;

&lt;p&gt;Let's try to implement (a very simplified) version of modules like &lt;a href="https://www.drupal.org/project/permissions_by_term" rel="noopener noreferrer"&gt;Permissions by Term&lt;/a&gt; or &lt;a href="https://www.drupal.org/project/tac_lite" rel="noopener noreferrer"&gt;Taxonomy Access Control Lite&lt;/a&gt; using the new system.&lt;/p&gt;

&lt;p&gt;Suppose we have a vocabulary &lt;code&gt;access&lt;/code&gt;, which terms represent a group of content that can be accessed only by a specific set of users. Content types and users are tagged with terms of this vocabulary.&lt;br&gt;
The permissions a user has are calculated based on the standard roles mechanism of Drupal. But on nodes tagged with a term of the &lt;code&gt;access&lt;/code&gt; vocabulary, if the user is tagged with the same term, the user has the permissions granted by an additional role.&lt;/p&gt;

&lt;p&gt;We have the &lt;code&gt;Content editor&lt;/code&gt; role that grants standard permissions like &lt;code&gt;Article: Create new content&lt;/code&gt; or &lt;code&gt;View own unpublished content&lt;/code&gt;, and the &lt;code&gt;Content editor in term&lt;/code&gt; role that grants permissions like &lt;code&gt;Article: Edit any content&lt;/code&gt; or &lt;code&gt;Article: Delete any content&lt;/code&gt;. An editor always has the permissions granted by the &lt;code&gt;Content editor&lt;/code&gt; role. Still, on nodes tagged with a term of the &lt;code&gt;access&lt;/code&gt; vocabulary, if the user is tagged with the same term, the user has the permissions granted by the &lt;code&gt;Content editor in term&lt;/code&gt; role too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fdrupal-access-policy-demistified%2Fuser_roles.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fdrupal-access-policy-demistified%2Fuser_roles.png" alt="User roles configuration section"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Image: User roles configuration section&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The code for the &lt;code&gt;TermAccessPolicy.php&lt;/code&gt; class may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TermAccessPolicy&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AccessPolicyBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;SCOPE_TERM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'term'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;applies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$scope&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SCOPE_TERM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculatePermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;RefinableCalculatedPermissionsInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;calculatePermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$scope&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SCOPE_TERM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="nv"&gt;$user_terms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'field_access'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;referencedEntities&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_terms&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nv"&gt;$cacheability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CacheableMetadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
         &lt;span class="nv"&gt;$cacheability&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCacheableDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

         &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
               &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatedPermissionsItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$permissions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;isAdmin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SCOPE_TERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCacheableDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cacheability&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$extra_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
         &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'field_extra_role'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;referencedEntities&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$extra_roles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nv"&gt;$extra_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$extra_roles&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$extra_role&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getPersistentCacheContexts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user.terms'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous code, we've defined a new scope &lt;code&gt;term&lt;/code&gt; and we've implemented the &lt;code&gt;applies&lt;/code&gt; method to return &lt;code&gt;TRUE&lt;/code&gt; only if the scope is &lt;code&gt;term&lt;/code&gt;.&lt;br&gt;
Then, we calculate the permissions based on the terms the user is tagged with. We add a cacheable dependency on the term entity to invalidate the cache if the term changes.&lt;/p&gt;

&lt;p&gt;Note that we've passed two more arguments to the &lt;code&gt;addItem&lt;/code&gt; method: the &lt;code&gt;scope&lt;/code&gt; and the &lt;code&gt;identifier&lt;/code&gt;. The &lt;code&gt;scope&lt;/code&gt; is the string &lt;code&gt;term&lt;/code&gt;, and the &lt;code&gt;identifier&lt;/code&gt; is the term ID.&lt;/p&gt;

&lt;p&gt;We can register the policy in the service container with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;access_policy_demo.access_policy.term&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\access_policy_demo\Access\TermAccessPolicy&lt;/span&gt;
   &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;access_policy&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getPersistentCacheContexts()&lt;/code&gt; uses a custom cache context, so we've to define it, too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserTermsCacheContext&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CalculatedCacheContextInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getLabel&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"User's terms"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="nv"&gt;$user_terms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$loaded_term&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$loaded_term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
         &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'field_access'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;referencedEntities&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$term&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user_terms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user_terms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'false'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getCacheableMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CacheableMetadata&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CacheableMetadata&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setCacheTags&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'user:'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()]);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A cache context needs to be registered in the service container, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cache_context.user.terms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\access_policy_demo\Access\UserTermsCacheContext&lt;/span&gt;
   &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@current_user'&lt;/span&gt;
   &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;cache.context&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can use the new scope to check the permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;access_policy_demo_node_access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;NodeInterface&lt;/span&gt; &lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$operation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;AccountInterface&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;AccessResultInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c1"&gt;// This node is not under access control.&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'field_access'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;AccessResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// Always allow access to view the node.&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$operation&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'view'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;AccessResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// Check if the user has access to the node.&lt;/span&gt;
   &lt;span class="nv"&gt;$terms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'field_access'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;referencedEntities&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$terms&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;\Drupal&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'access_policy_processor'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;processAccessPolicies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TermAccessPolicy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SCOPE_TERM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TermAccessPolicy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SCOPE_TERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'edit any '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' content'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'edit own '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' content'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getOwnerId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'delete'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'delete any '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' content'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'delete own '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' content'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getOwnerId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

         &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$access&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$access&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;AccessResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AccessResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forbidden&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous code is just a rough example. Still, the critical thing to note is that we've used the &lt;code&gt;TermAccessPolicy::SCOPE_TERM&lt;/code&gt; and the term ID to retrieve a &lt;code&gt;CalculatedPermissionsItem&lt;/code&gt; that contains the permissions granted by the term to the user.&lt;/p&gt;

&lt;p&gt;What a long journey! But we're not done yet.&lt;/p&gt;

&lt;p&gt;One of the new system's most important features is that access policies are cached by context, but context can be dynamic and change during permission calculation; this is where the &lt;code&gt;initial cache context&lt;/code&gt; comes into play.&lt;/p&gt;

&lt;h3&gt;
  
  
  Variation cache
&lt;/h3&gt;

&lt;p&gt;Access policies usually vary by some context, like the user roles, the time of day, the domain, etc. Drupal has a concept of cache contexts that allows you to vary the cache based on some context, but until Drupal 10.2, this can be used only to add cache contexts to render arrays.&lt;/p&gt;

&lt;p&gt;Now, all caches can use cache contexts thanks to the Variation cache.&lt;/p&gt;

&lt;p&gt;Variation cache is not a new type of cache but a wrapper around the cache backends that already exist in Drupal. It has two interesting features.&lt;br&gt;
The first one is that it allows varying a cache by context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cache.access_policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\Core\Cache\CacheBackendInterface&lt;/span&gt;
   &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;cache.bin&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
   &lt;span class="na"&gt;factory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@cache_factory'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;get'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
   &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;access_policy&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;variation_cache.access_policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\Core\Cache\VariationCacheInterface&lt;/span&gt;
   &lt;span class="na"&gt;factory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@variation_cache_factory'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;get'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
   &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;access_policy&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous example, &lt;code&gt;variation_cache.access_policy&lt;/code&gt; is a wrapper around &lt;code&gt;cache.access_policy&lt;/code&gt;. When I do something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;\Drupal&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'variation_cache.access_policy'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$cache&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'key1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'key2'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s1"&gt;'value'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user.roles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'languages:language_interface'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user.roles'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm saving &lt;code&gt;value&lt;/code&gt; at the &lt;code&gt;['key1', 'key2']&lt;/code&gt; of the &lt;code&gt;access_policy&lt;/code&gt; cache, and I'm telling the variation cache that the cache will vary by the &lt;code&gt;user.roles&lt;/code&gt; and &lt;code&gt;languages:language_interface&lt;/code&gt; contexts.&lt;/p&gt;

&lt;p&gt;Having not specified anything specific in the &lt;code&gt;tags&lt;/code&gt; section of the &lt;code&gt;cache.access_policy&lt;/code&gt; service, I get the default cache backend, typically the database one. I could have written:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;cache.bin.memory&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;default_backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;cache.backend.memory.memory&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To have a cache in memory.&lt;/p&gt;

&lt;p&gt;Variation cache uses cache contexts to build cache IDs. For example, the cid for the contexts &lt;code&gt;user.roles&lt;/code&gt; and &lt;code&gt;languages:language_interface&lt;/code&gt; when the user has roles 3 and 4, and the language is English could be something like: &lt;code&gt;key1:key2:[languages:language_interface]=en:[user.roles]=3,4&lt;/code&gt;. (Contexts are sorted in alphabetical order by name.)&lt;/p&gt;

&lt;p&gt;The second feature comes from the fact that when I save data in the variation cache, I can specify two sets of contexts: the actual ones to vary the cache on (the third argument of the &lt;code&gt;set&lt;/code&gt; method) and the "initial" ones (the fourth argument of the &lt;code&gt;set&lt;/code&gt; method).&lt;/p&gt;

&lt;p&gt;But what are these initial cache contexts? They are the ones that our data varies for sure, but they could not be the only ones. If, during the building of the data to cache, someone else adds one or more specific contexts, the cache system may not be aware of it.&lt;/p&gt;

&lt;p&gt;When the set of final cache contexts is more specific than the initial ones, the variation cache stores a cache with an ID built using the initial cache contexts. That cache will not store the data but a redirect that contains the final cache contexts to use to find the actual data. This chain of redirects can span more than one level.&lt;/p&gt;

&lt;p&gt;Let's add more complexity to our previous example about the &lt;code&gt;TermAccessPolicy&lt;/code&gt;. Suppose that terms in the &lt;code&gt;access&lt;/code&gt; vocabulary have a select field named &lt;code&gt;is_restricted&lt;/code&gt;, with two values: &lt;code&gt;Weekend&lt;/code&gt; and &lt;code&gt;Weekdays&lt;/code&gt;. We want to grant the permissions not only if the node is tagged with a term but also based on the day of the week.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fdrupal-access-policy-demistified%2Fterm_edit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftech.sparkfabrik.com%2Fimages%2Fcontent%2Fdrupal-access-policy-demistified%2Fterm_edit.png" alt="User roles configuration section"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Image: Add a restriction to an access term&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If no restrictions are set, the permissions are granted as usual. If a restriction is set, the permissions are only granted if the current day matches the restriction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_terms&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$cacheability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CacheableMetadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nv"&gt;$cacheability&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCacheableDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nv"&gt;$restricted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isRestricted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$restricted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$cacheability&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCacheContexts&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'is_restricted'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatedPermissionsItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$permissions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;isAdmin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SCOPE_TERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCacheableDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cacheability&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$calculated_permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;isRestricted&lt;/code&gt; method can be implemented as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;isRestricted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;TermInterface&lt;/span&gt; &lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$restriction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user_term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'field_restriction'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$restriction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$restriction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nv"&gt;$field_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$restriction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'value'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$field_value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'weekend'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;IsWeekendCacheContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;isWeekend&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$field_value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'weekdays'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nc"&gt;IsWeekendCacheContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;isWeekend&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;RestrictedCacheContext&lt;/code&gt; class can be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestrictedCacheContext&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CalculatedCacheContextInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getLabel&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Is Weekend?'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parameter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;isWeekend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'weekend'&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'weekday'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"is_restricted.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;isWeekend&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getCacheableMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parameter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CacheableMetadata&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CacheableMetadata&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose to have two terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Section1&lt;/code&gt; (tid=1) with the restriction set to &lt;code&gt;Weekend&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Section2&lt;/code&gt; (tid=2) with no restrictions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And two users:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;User1&lt;/code&gt; tagged with &lt;code&gt;Section1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;User2&lt;/code&gt; tagged with &lt;code&gt;Section2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And we're on Sunday.&lt;/p&gt;

&lt;p&gt;When permissions are calculated for &lt;code&gt;User1&lt;/code&gt;, the initial cache context will be &lt;code&gt;user.terms&lt;/code&gt;, but then we'll add the &lt;code&gt;is_restricted&lt;/code&gt; cache context because the &lt;code&gt;Section1&lt;/code&gt; term is restricted.&lt;br&gt;
When permissions are calculated for &lt;code&gt;User2&lt;/code&gt; the initial cache context will be &lt;code&gt;user.terms&lt;/code&gt;, and no other cache context will be added.&lt;/p&gt;

&lt;p&gt;The cache will be something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;access_policies:term:[user.terms]=2&lt;/code&gt; =&amp;gt; &lt;code&gt;Drupal\Core\Session\RefinableCalculatedPermissions&lt;/code&gt;&lt;br&gt;
&lt;code&gt;access_policies:term:[user.terms]=1&lt;/code&gt; =&amp;gt; &lt;code&gt;Drupal\Core\Cache\CacheRedirect&lt;/code&gt; (&lt;code&gt;cacheContexts: ["user.terms", "is_restricted"]&lt;/code&gt;)&lt;br&gt;
&lt;code&gt;access_policies:term:[is_restricted]=is_restricted.weekend:[user.terms]=1&lt;/code&gt; =&amp;gt; &lt;code&gt;Drupal\Core\Session\RefinableCalculatedPermissions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Variation cache stores the data for access policies that vary only by &lt;code&gt;user.terms&lt;/code&gt; directly.&lt;br&gt;
For the access policies that also vary by &lt;code&gt;is_restricted,&lt;/code&gt; it stores a redirect (along with information about the final cache contexts to look for: &lt;code&gt;user.terms&lt;/code&gt; and &lt;code&gt;is_restricted&lt;/code&gt;).&lt;br&gt;
To access a cache with more final cache contexts than the initial ones, the variation cache will need to follow a chain of redirects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The new Access Policy API is a powerful tool that allows the implementation of complex access control systems in Drupal.&lt;br&gt;
It's a big step forward from the old system based on only roles and permissions.&lt;/p&gt;

&lt;p&gt;In the future, we'll see more and more contrib modules that will use this new system to convert custom logic to the new system. At SparkFabrik, we've already started using it in custom modules for our customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;p&gt;I've set up a GitHub repository with the code used in this blog post: &lt;a href="https://github.com/lussoluca/access_policy_demo" rel="noopener noreferrer"&gt;https://github.com/lussoluca/access_policy_demo&lt;/a&gt;. You can clone it and use &lt;a href="https://ddev.com/" rel="noopener noreferrer"&gt;DDEV&lt;/a&gt; to run the code.&lt;/p&gt;

&lt;p&gt;This blog post would not have been possible without the help of the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.thedroptimes.com/40119/kristiaan-van-den-eynde-talks-about-policy-based-access-in-core" rel="noopener noreferrer"&gt;https://www.thedroptimes.com/40119/kristiaan-van-den-eynde-talks-about-policy-based-access-in-core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/node/3365546" rel="noopener noreferrer"&gt;https://www.drupal.org/node/3365546&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/node/3385551" rel="noopener noreferrer"&gt;https://www.drupal.org/node/3385551&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/node/2910500" rel="noopener noreferrer"&gt;https://www.drupal.org/node/2910500&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/node/3411485" rel="noopener noreferrer"&gt;https://www.drupal.org/node/3411485&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/docs/develop/drupal-apis/access-policy-api" rel="noopener noreferrer"&gt;https://www.drupal.org/docs/develop/drupal-apis/access-policy-api&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bpekker.dev/access-policy-api/" rel="noopener noreferrer"&gt;https://bpekker.dev/access-policy-api/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?app=desktop&amp;amp;v=pbAUselOJy0" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?app=desktop&amp;amp;v=pbAUselOJy0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>drupal</category>
      <category>opensource</category>
      <category>security</category>
    </item>
    <item>
      <title>dxday: A Report</title>
      <dc:creator>Davide Boncompagni</dc:creator>
      <pubDate>Tue, 18 Jun 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/dxday-a-report-4de0</link>
      <guid>https://dev.to/sparkfabrik/dxday-a-report-4de0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;On the 14th of March we were at &lt;a href="https://2024.dxday.it/"&gt;&lt;strong&gt;DxDay&lt;/strong&gt;&lt;/a&gt;, the first conference organised by &lt;strong&gt;GrUSP&lt;/strong&gt; dedicated to the &lt;em&gt;Developer Experience&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It was very cool to see so many different focuses on the same topic, showing how delicate and articulated the DevEx concept is.\&lt;br&gt;
GrUSP will upload the videos of the speeches in the next few months, but if you are already feeling the fear of missing out, we will try to give you the essence of the speeches in this article to give you a taste of what the conference was like.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is DevEx?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Developer Experience&lt;/strong&gt; is the study of how people, processes, culture and tools affect the ability of developers to work efficiently. This is a definition provided by Github in one of their blog posts.&lt;br&gt;
As mentioned before, developer experience is a complex and holistic concept, and we need to understand that none of these aspects can overcome the lack of another area, if you want to improve it, you need to work on each topic: technologies, tools, processes, culture and people.&lt;/p&gt;

&lt;p&gt;This means that building a good DevEx requires a lot of effort!&lt;/p&gt;

&lt;p&gt;It's also a dynamic, evolving concept, and improving it is a continuous process, not a static goal.&lt;br&gt;
But even small steps can contribute, so you should manage the improvement gradually and develop a DevEx improvement process rather than a single big action, dividing the effort required into subtasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why working to improve DevEx
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Pleasure in work brings perfection to work.&lt;/em&gt;&lt;br&gt;
(Aristotele)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main reason to improve DevEx is to &lt;strong&gt;increase productivity and quality&lt;/strong&gt; in its broadest sense.&lt;/p&gt;

&lt;p&gt;It's not only about increasing revenue, but could potentially lead to it. The goal is to remove most of the friction, reduce cognitive load, automate repetitive tasks, improve communication and processes, create a positive mindset, flesh out the company's vision and mission, and &lt;em&gt;unleash the full potential of human capital&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Striving for quality, creating a trusting environment and being transparent about areas that need improvement could create engagement and a proactive tendency where employees feel they can contribute to improving the overall structures and start to do so.&lt;br&gt;
However, the main output metric of DevEx should be increased developer motivation and perceived satisfaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Talks
&lt;/h2&gt;

&lt;p&gt;Ok, with that concept disambiguation out of the way, &lt;strong&gt;let's talk about the conference&lt;/strong&gt;.&lt;br&gt;
First of all, 4 of the 7 talks focused on tools for developers and the other 3 on process management and culture fostering.&lt;br&gt;
The speakers come from very different backgrounds, which might justify the different focuses of their talks&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools focused talks
&lt;/h3&gt;

&lt;p&gt;Let's start with the tools, &lt;strong&gt;Maxim Salnikov&lt;/strong&gt;, Developer Productivity Lead @ Microsoft showed us the power of &lt;strong&gt;GitHub Copilot&lt;/strong&gt; and its ability to understand the context of your project, a tool that claims to allow developers to request all the boring tasks that keep them in the zone, making it easier to experiment the world famous &lt;em&gt;Mihály Csíkszentmihályi&lt;/em&gt; flow state. Such a very ambitious claim and also a very ambitious goal: to offer a pair programming experience without the need for a senior engineer and increase productivity.&lt;br&gt;
If you live in the desert or come from another planet and have never heard of Copilot, take a look at this "magical" looking tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Talita Gregory Nunes Freire&lt;/strong&gt; Engineer @ Spotify and &lt;strong&gt;Vincenzo Scamporlino&lt;/strong&gt; Senior Engineer @ Spotify have demoed &lt;em&gt;Spotify Backstage&lt;/em&gt;, a tool that allows you to easily build a developer portal, an interface that could aggregate all your utilities for your microservices, allowing you to have a schematic view of your microservices' dependencies for example, but also much more! &lt;/p&gt;

&lt;p&gt;They claim to address issues such as discoverability, system ownership, fragmentation, duplication and context switching. The focus is on &lt;strong&gt;reducing cognitive load&lt;/strong&gt;, improving collaboration and transforming complex software into manageable units. We also use Backstage for some projects at SparkFabrik and its adoption is growing every day, confirming it as the de facto standard tool for complex cloud project management. Oh yeah, I forgot, this tool is completely open source, great!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lou Bichard&lt;/strong&gt;, Product Manager @ Gitpod, talked about his groundbreaking and, in such cases, futuristic Gitpod, a cloud development tool that removes the pain of onboarding and transforms your projects into code-ready, globally maintained development environments, removing the abstraction of infrastructure in your environment, what Lou called outer loop removal, a production-like environment. It looks like VSCode but in your browser, a future where you can upgrade hardware resources without changing your PC.&lt;/p&gt;

&lt;p&gt;And it's not just Gitpod's product manager who is betting on cloud environments, but also &lt;strong&gt;Francesco Corti&lt;/strong&gt;, Principal Product Manager @ Docker, with his talk on the future of growing DevEx tools, highlighting how companies are increasingly interested in this type of solution. He also tried to foresee the future of AI tools, predicting a future where we will move to a whole team of specialised AI assistants that will help you not only to automate boring tasks, but also to create documentation, debug, deploy, make data entries, get feedback on requirements, respect and test your software, an environment where developers don't usually code, but ask AI to do it for them.&lt;/p&gt;

&lt;p&gt;If you have never heard of any of these technologies, look for demos, tutorials and so on, because it takes too much effort to explain all their functionalities in this blog post, the good news is that there are tons of resources about them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Processes and culture-focused conversations
&lt;/h3&gt;

&lt;p&gt;As I said, it's not just about tools, history has taught us that: the aeolipile was the first steam engine, but it didn't lead to a revolution, probably because the Greek culture didn't need to replace servant work. For &lt;strong&gt;DevEx&lt;/strong&gt;, it is also easier to demonstrate because we work in teams: communities made up of people with social dynamics that affect our ability to perform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Abiodun Olowode&lt;/strong&gt;, Senior Engineering Manager @ Factorial, introduced us to &lt;em&gt;Documentation Driven Development&lt;/em&gt;, which focuses on process optimisation, and how this could shine a light on team collaboration and knowledge sharing, potentially reducing code churn and introducing a faster feedback loop that could accelerate development.&lt;br&gt;
One thing we've too often forgotten is that developers want to know why something works the way it does, why one implementation was chosen over another, we can understand code but we can't always deduce the reasons behind it and it's not always possible to ask someone for an explanation, we need a more robust and shared tool like documentation.&lt;br&gt;
And also this kind of development could lead to less intolerance about writing docs, because it became part of development, you don't have to pass back your whole implementation process to describe it, the task becomes progressive and manageable. However, it was cool that maintaining and developing a tool together could improve DevEx.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thomas Khalil&lt;/strong&gt;, DevEx Head of Platform &amp;amp; Site Reliability Engineering @ Trivago, with his beautiful allegory of the Wizard of Oz, described some of the behavioural patterns that people in the organisation tend to adopt in order to challenge the psychologically complex situations that our jobs require today, and how empathy and awareness could lead people to unleash their true potential.&lt;br&gt;
For Kahil, DevEx is about deeply understanding people's needs, motivations and aspirations, building trust, finding answers behind their defensive behaviours without needing a guru, keeping processes adaptable and choosing metrics wisely, keeping in mind that they are and should be holistic metrics. Even though it wasn't the focus of his talk, I'd like to focus on Kahil's use of surveys to identify areas for improvement and employee perceptions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Suffering comes from trying to control what is uncontrollable, or from neglecting what is in our power&lt;/em&gt;&lt;br&gt;
(Epictetus)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This quote used by Kahil highlights the main problem of the archetypes he describes and reminds us to try to improve what is in our power and to take care of it.&lt;/p&gt;

&lt;p&gt;Dulcis in fundo our &lt;strong&gt;Paolo Pustorino&lt;/strong&gt;, Head of HR @ SparkFabrik with his talk focused on the &lt;em&gt;influence of culture on DevEx&lt;/em&gt;, alignment of values, sense of community, engagement, commitment, caring, transparency and the importance of psychological safety as a driving engine of developer experience satisfaction. He gave a lot of information about the processes of recruitment, onboarding and also career paths within Sparkfabrik and how the company tries to support you along the way, asking you for feedback on relationships, core values, training needs and perspectives. He gave an insight into the company's goals, such as the pursuit of quality in a broad sense (not only technical quality, but also relationship quality, communication quality, which revolves around the value of transparency, etc.) and the decision to make cultural fit and team fitness the key guiding values required during recruitment in order to preserve the culture and DevEx quality within the company.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"The chef is not the best cook in the kitchen, but he helps everyone to succeed"&lt;/em&gt; is probably the most emblematic phrase describing the previous assumptions. He also talked about the so-called &lt;strong&gt;Expert's Deception&lt;/strong&gt;, the bias that innovation is a process driven by exports when their main quality is to offer experience, assumptions based on the past rather than challenging the status quo, and the desire to avoid the Peter Principle with career progression.&lt;br&gt;
He gave us an introduction to the Cynefin framework, which could help you to support line managers in their work, remembering that you need to avoid instilling fear to get people to perform at their best.&lt;/p&gt;

&lt;p&gt;I hope that you now have a broader perspective on DevEx and that you understand that a good company culture usually coincides with optimising tool adoption, but no tool adoption can improve your company culture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metrics
&lt;/h2&gt;

&lt;p&gt;We didn't talk so much about metrics to measure it, only Kahil did a little bit. We need to specify that we need to separate developer productivity or job performance metrics from DevEx metrics or job satisfaction.&lt;br&gt;
Even if your ultimate goal is to &lt;strong&gt;improve productivity&lt;/strong&gt;, make sure you have improved DevEx first. DevEx metrics could give you insight to better understand productivity metrics and could encourage hidden latent innovation processes.&lt;/p&gt;

&lt;p&gt;One of the most popular tools in this area is the &lt;strong&gt;SPACE framework&lt;/strong&gt;, which uses some performance metrics to gain insight into DevEx. It's an acronym that stands for the following concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Satisfaction and Well-being: it measures how healthy and happy developers are, with a focus on psychological safety and satisfaction, worrying about workload and detecting and acting on possible toxic practices such as &lt;em&gt;Compulsory Citizenship Behaviour (CCB)&lt;/em&gt; or lack of boundaries with personal life such as calls outside working hours. It also consists of assessments of personal goals and aspirations such as tool adoption and so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance: difficult to measure because the business outcome doesn't imply a quality outcome. To balance better quality and quantity outcomes, you will better separate the metrics for the two areas, allowing you to understand if you are sacrificing code quality to deliver fast, undermining developer satisfaction and increasing code churn with its associated costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Activity: Many activities such as brainstorming, meetings, or supporting a teammate are not usually evaluated by these metrics. Choosing the right metrics in this area could give you insights into quality, such as spending enough time on design decisions, code review, refactoring and identifying bottlenecks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Communication and Collaboration: focus on information discoverability and dissemination, network metrics, role clarity, awareness, transparency and team member contribution to team fitness. These metrics could influence all other areas of the &lt;strong&gt;SPACE framework&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Efficiency and flow: the ability to complete work with minimal interruption or delay, measured by what is known as focus time. For efficiency, we could suggest the famous DORA (DevOps Research and Assessment) metrics: deployment frequency, change lead time, change failure rate and mean time to recovery (MTTR).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these aspects could be measured individually or for teams, and we also have to mention that maximising one factor could have a negative impact on another, like for example reducing interruptions to improve flow could damage the collaboration of the team, it's not a law but consider that this could happen, so you will better have a holistic approach and also always consider that metrics by themselves are not reliable and could reflect other things, the choice of these metrics itself reflects company or team opinions and is influenced by irrationality processes.&lt;/p&gt;

&lt;p&gt;Try to extract insights from metrics rather than using them as a driving force.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Unhappy the land that is in need of heroes.&lt;/em&gt;&lt;br&gt;
(Bertolt Brecht)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;DevEx focuses on improving the development environment with tools, but also in terms of a social environment that allows people to express their full potential.&lt;br&gt;
A corporate culture less focused on workaholism and control and more on empowerment and trust contribute to DevEx, and in this sense could help the adoption of a transformational leadership style or Hansei framework, or encourage community participation and avoid silo mentality that could lead to a positive sense of identity with the larger organization and its members and could unleash Organizational Citizenship Behaviors (OCB) that consists in spontaneous mentoring, support, conscientiousness and sportsmanship that create virtuous cycles that put people in conditions to express their potential.&lt;/p&gt;

&lt;p&gt;I don't know if future tools will move from promoting staying in the zone and achieving flow experiences to leading to Maslow's peak experiences, at least for those working from the Greek concept of Meraki, but as focused on Kahil's talk, the right tool at the wrong time might not be able to improve DevEx, and certainly gurus are not the answer, as Paolo also noted, we need to foster and nurture a psychologically safe environment with transparency, trust, communication, empathy, room for mistakes to avoid spreading fear because innovations arise from failure, so &lt;strong&gt;never lose the spark&lt;/strong&gt;!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.&lt;/em&gt; &lt;br&gt;
(Samuel Beckett)&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>dxday</category>
      <category>devrel</category>
      <category>community</category>
      <category>events</category>
    </item>
    <item>
      <title>Building a Sustainable Web: a practical exploration of Open Source tools and strategies</title>
      <dc:creator>Valeria Salis</dc:creator>
      <pubDate>Thu, 13 Jun 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/building-a-sustainable-web-a-practical-exploration-of-open-source-tools-and-strategies-2683</link>
      <guid>https://dev.to/sparkfabrik/building-a-sustainable-web-a-practical-exploration-of-open-source-tools-and-strategies-2683</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the past few years I've been deeply concerned about climate change. My journey on &lt;strong&gt;web environmental sustainability&lt;/strong&gt;&lt;br&gt;
started by chance when I stumbled upon the concept of "sustainable web".&lt;/p&gt;

&lt;p&gt;I first learned how to create a better &lt;strong&gt;User Experience&lt;/strong&gt; taking in consideration sustainability principles &lt;br&gt;
and strategies, but it wasn't enough. I wanted to go deeper and understand more about the environmental impact of the web.\&lt;br&gt;
In this blog post I will share my journey, the tools and the strategies I've come across and learned and, last but not least, the &lt;br&gt;
role of Open Source and the relevance of its community aspect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's start from the beginning
&lt;/h2&gt;

&lt;p&gt;For me, &lt;strong&gt;the Internet has always been my happy place&lt;/strong&gt;: it made me discover many of my passions and hobbies, it allowed me to learn new things, connect with people, entertain myself with some tv shows or movies and &lt;em&gt;even work&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, the Internet has various cons, and one of them is that, sadly, &lt;strong&gt;it is not very environmentally friendly&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If the Internet was a country, it would be the 4th largest polluter" - &lt;a href="https://www.sustainablewebmanifesto.com/" rel="noopener noreferrer"&gt;Sustainable Web Manifesto&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The sentence above is the opening sentence of the &lt;strong&gt;Sustainable Web Manifesto&lt;/strong&gt;, and it has been the very first sentence I &lt;br&gt;
read about web sustainability.\&lt;br&gt;
It broke down the idea I had of the web being a "place" with only positive aspects and made me realize that, in reality, it&lt;br&gt;
has some responsibilities regarding the environment. &lt;/p&gt;

&lt;p&gt;In fact, &lt;strong&gt;the Internet is responsible for about 4% of total CO2 emissions&lt;/strong&gt;, which&lt;br&gt;
may seem like a small percentage, but it's actually double the emissions of the air transport sector ("only" 2%).&lt;/p&gt;

&lt;h2&gt;
  
  
  UX and Web Sustainability
&lt;/h2&gt;

&lt;p&gt;The "first stop" of my journey was related to User Experience: on the occasion of &lt;strong&gt;UX Day 2023&lt;/strong&gt;,&lt;br&gt;
an Italian conference that took place in Faenza, I had the opportunity to bring my contribution with a talk called “&lt;strong&gt;UX and Web Sustainability&lt;/strong&gt;”.&lt;/p&gt;

&lt;p&gt;You can find the recording &lt;a href="https://youtu.be/jcPiD0WG0nk?si=rK6YMqDl0akhxb8R" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3xe15k4iqpd5wo2sbr1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3xe15k4iqpd5wo2sbr1.webp" alt="Valeria Salis speaking at UX Day 2023 in Faenza, Italy. Valeria has short hair and is wearing a black t-shirt and the coloured badge from GrUSP." width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've been following this tech blog for a while, you might have encountered my previous &lt;a href="https://dev.to/en/blog/20231018_ux_and_sustainable_web/"&gt;blog post&lt;/a&gt; about this specific&lt;br&gt;
topic, but I will summarize the main points here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sustainability also means &lt;em&gt;speed&lt;/em&gt;, &lt;em&gt;performance&lt;/em&gt;, &lt;em&gt;usability&lt;/em&gt; and &lt;em&gt;accessibility&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;applying sustainability principles will make our websites load faster and help users navigate them more easily&lt;/li&gt;
&lt;li&gt;designing for the environment also means designing for everyone because when the majority of people are able to navigate our websites and applications, the energy required to run them won't be wasted.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Working towards a more environmentally friendly UX will make users happier&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Great starting point, wasn't it? It wasn't enough for me, though.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2ucllt6p4li4hrrn0h3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2ucllt6p4li4hrrn0h3.webp" alt="A cat with a bored expression." width="500" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Native Sustainability Week
&lt;/h2&gt;

&lt;p&gt;The second stop of this journey took place in October 2023 on the occasion of &lt;strong&gt;Cloud Native Sustainability Week&lt;/strong&gt;, which&lt;br&gt;
is a global event organized by the &lt;a href="https://www.cncf.io/" rel="noopener noreferrer"&gt;CNCF (Cloud Native Computing Foundation)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's a series of local meetups around the topic of &lt;strong&gt;sustainability in the cloud native ecosystem&lt;/strong&gt;: basically&lt;br&gt;
is that time of the year when the local communities involved with the CNCF dedicate time to spread awareness and share content &lt;br&gt;
(blog posts, talks, panels, etc.) about environmental sustainability.&lt;/p&gt;

&lt;p&gt;You can find more information about the event &lt;a href="https://tag-env-sustainability.cncf.io/events/cloud-native-sustainability-week/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I had the opportunity to attend the meetup in Milan and contribute with a lightning talk about "how bad we use the Cloud"&lt;br&gt;
and the consequences of our approach.\&lt;br&gt;
The main takeaway I would like to share here is that we should be more aware of the data we store because &lt;strong&gt;approximately 90% of cloud data is used only one time&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We store data and then forget about it, but it's still there, consuming energy and resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  As a software developer, what else can I do?
&lt;/h2&gt;

&lt;p&gt;By that time, I had learned the importance of applying sustainability principles to the user experience, and the benefits not only for the environment, but also for the users. I had also learned that &lt;strong&gt;we need to be more aware of our data&lt;/strong&gt;, how we use it, and its impact on the environment.&lt;/p&gt;

&lt;p&gt;But UX and cloud are just two pieces of the puzzle, and in some ways on opposite sides of our applications.\&lt;br&gt;
There's a lot more between UX and the cloud, so I kept going back to fill in the gaps I had in my head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Green software for practitioners
&lt;/h2&gt;

&lt;p&gt;One of the first resources I came across was the online course &lt;a href="https://training.linuxfoundation.org/training/green-software-for-practitioners-lfc131/" rel="noopener noreferrer"&gt;Green software for practitioners&lt;/a&gt; created by the &lt;a href="https://greensoftware.foundation/" rel="noopener noreferrer"&gt;Green Software Foundation (GSF)&lt;/a&gt; along with &lt;a href="https://www.linuxfoundation.org/" rel="noopener noreferrer"&gt;The Linux Foundation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're not familiar with the GSF, their mission is to "&lt;em&gt;build a trusted ecosystem of people, standards, tools and best practices for developing&lt;br&gt;
and building green software&lt;/em&gt;". &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Spoiler: later we will have a look at one of the tools they developed!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Getting back to the subject of this paragraph, if you're a software developer or someone involved in &lt;em&gt;building, deploying, or managing a software application&lt;/em&gt; and you want to do so in a greener way, I would recommend the Green Software for Practitioners course as a starting point.&lt;/p&gt;

&lt;p&gt;I recommend this course for several reasons, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it is an online course and entirely self-paced &lt;/li&gt;
&lt;li&gt;it gives you a complete glossary and a proper introduction to the main topics around green software development&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Today I will give you a "teaser" of some of the key concepts I've learnt from the course, but I highly recommend you to fully take it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main actions to reduce the carbon footprint of software
&lt;/h3&gt;

&lt;p&gt;To reduce the carbon footprint of software, we must consider three main actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🍃 &lt;strong&gt;Energy efficiency&lt;/strong&gt;, which consists of &lt;em&gt;consuming&lt;/em&gt; the least amount of electricity possible&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;Hardware efficiency&lt;/strong&gt;, which consists of &lt;em&gt;using&lt;/em&gt; as little embodied carbon as possible&lt;/li&gt;
&lt;li&gt;🌱 &lt;strong&gt;Carbon awareness&lt;/strong&gt;, last but not least, the purpose of this action is &lt;em&gt;doing more when the electricity is clean and less when it's dirty&lt;/em&gt; (e.g., using demand shifting and/or demand shaping methods);&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What you can't measure, you can't improve
&lt;/h3&gt;

&lt;p&gt;The second topic I wanted to share in this blog post is the importance of &lt;strong&gt;measuring&lt;/strong&gt;, which is also one of the main chapters in the course.\&lt;br&gt;
Indeed, in order to improve the environmental sustainability of our software, we need to measure its impact on the environment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Greenhouse Gases Protocol (GHG)
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://ghgprotocol.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Greenhouse Gases Protocol (GHG)&lt;/strong&gt;&lt;/a&gt; is the most widely used and internationally recognized greenhouse gas accounting standard. &lt;br&gt;
It divides emissions into three main &lt;strong&gt;scopes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope 1&lt;/strong&gt;, &lt;em&gt;direct&lt;/em&gt; emissions from operations owned or controlled by our organization (or the one we're applying this protocol for)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope 2&lt;/strong&gt;, &lt;em&gt;indirect&lt;/em&gt; emissions related to emission generation of purchased energy (for example, electricity)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope 3&lt;/strong&gt;, &lt;em&gt;other indirect&lt;/em&gt; emissions from  all the activities the organization is engaged in, including the ones from the organization's supply chain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it comes to software, knowing the scopes your emissions fall into is challenging because it depends on your specific scenario.\&lt;br&gt;
However, you will find some examples in the course.&lt;/p&gt;

&lt;h4&gt;
  
  
  Software Carbon Intensity (SCI)
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://sci.greensoftware.foundation/" rel="noopener noreferrer"&gt;&lt;strong&gt;Software Carbon Intensity (SCI)&lt;/strong&gt;&lt;/a&gt; was developed by the GSF and aims to give a score to &lt;br&gt;
a software application in order to understand &lt;em&gt;how it behaves&lt;/em&gt; in terms of carbon emissions.\&lt;br&gt;
The SCI specification has recently achieved the &lt;strong&gt;ISO standard status&lt;/strong&gt;: you can find more information in &lt;a href="https://greensoftware.foundation/articles/sci-specification-achieves-iso-standard-status" rel="noopener noreferrer"&gt;this&lt;/a&gt; article.&lt;/p&gt;

&lt;p&gt;It's not a replacement for the GHG protocol, but rather an additional metric to more specifically address the characteristics of our software to make more informed decisions. The main difference between GHG and SCI is that the former categorizes emissions into scopes, while the&lt;br&gt;
latter divides them into &lt;strong&gt;operational emissions&lt;/strong&gt; and &lt;strong&gt;embodied emissions&lt;/strong&gt; and, as its name suggests, it's an intensity rather than a total.&lt;/p&gt;

&lt;p&gt;The SCI is calculated using the following equation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SCI = ((E * I) + M) per R&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;E&lt;/strong&gt; = energy consumed by a software system (in kWh)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I&lt;/strong&gt; = location-based marginal carbon emissions (carbon emitted per kWh of energy so gCO2/kWh)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M&lt;/strong&gt; = embodied emissions of a software system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;R&lt;/strong&gt; = functional unit, it is the core characteristic of the SCI and the reason why it "becomes" an intensity and not a total&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F359bjr8k9bxqryo8o8ol.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F359bjr8k9bxqryo8o8ol.webp" alt="Two people trying to calculate the Software Carbon Intensity of a software application." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the community?
&lt;/h2&gt;

&lt;p&gt;The final step of this exploration will be about open source and the community aspect that inevitably &lt;em&gt;contributes&lt;/em&gt; in some ways to our journey. For me, it has been a pivotal element related to environmental sustainability and tech.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environmental Sustainability Technical Advisory Group
&lt;/h3&gt;

&lt;p&gt;The very first community I became part of was the &lt;a href="https://tag-env-sustainability.cncf.io/" rel="noopener noreferrer"&gt;Environmental Sustainability Technical Advisory Group&lt;/a&gt; which is part of the CNCF. The TAG Env Sustainability's goal is similar to the GSF's: their mission is to "&lt;strong&gt;advocate for, develop, support and help evaluate environmental sustainability initiatives in cloud native technologies.&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;At the moment, the TAG has two main working groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;Green Reviews&lt;/strong&gt; group (WG Green Reviews), which is more focused on technical issues, metrics and developing tools&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Communications&lt;/strong&gt; group (WG Comms), which is more focused on spreading awareness and sharing content and the work done by the Green Reviews group&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the TAG, people are involved in different ways depending on their technical skills and/or interests, but the main thing I've had the opportunity to see is that &lt;em&gt;everyone wants to do something, participate, and lend even a small helping hand to the currently active projects and discussions&lt;/em&gt;.&lt;br&gt;
Having a community of people with different backgrounds and approaches to rely on, ask questions of, share content with, and discuss with is an excellent way to learn and achieve a more complete result.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is what open source is all about: sharing, learning, contributing, and growing together.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, I've tried to give you an example of a learning path a &lt;em&gt;wannabe-greener-dev&lt;/em&gt; could follow, based on my experience and the tools and resources I've come across. &lt;/p&gt;

&lt;p&gt;Environmental sustainability is a broad topic, and since there isn't a defined clear and linear path, it can be challenging for someone to get started, especially when we're talking about engineering and software development, since it can be challenging to even understand that our work has an impact on the environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: some other tools and resources
&lt;/h2&gt;

&lt;p&gt;Here's a list of some other open source tools you might find useful in your journey towards a more sustainable web:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developers.thegreenwebfoundation.org/" rel="noopener noreferrer"&gt;Developers page of The Green Web Foundation&lt;/a&gt;, in this page you can find some projects and libraries to try out and contribute too, such as C02.js, Grid Intensity CLI, Greencheck API and a lot more&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://opensustain.tech/" rel="noopener noreferrer"&gt;Open Sustainable Technology&lt;/a&gt;, a website that collects a list of open source projects and tools environment related&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kube-green.dev/" rel="noopener noreferrer"&gt;kube-green&lt;/a&gt;, a tool that helps you reduce the carbon footprint of your Kubernetes clusters&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ecograder.com/" rel="noopener noreferrer"&gt;Ecograder&lt;/a&gt;, a tool that helps you understand how sustainable your website is and gives you some tips on how to improve it; it's based on various open source libraries. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Along with the online tools, I would recommend you the following books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://abookapart.com/products/sustainable-web-design" rel="noopener noreferrer"&gt;Sustainable Web Design&lt;/a&gt; by Tom Greenwood&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.worldwidewaste.org/" rel="noopener noreferrer"&gt;World Wide Waste&lt;/a&gt; by Gerry McGovern&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.goodreads.com/book/show/7646482-how-bad-are-bananas" rel="noopener noreferrer"&gt;How bad are bananas?&lt;/a&gt; by Mike Berners-Lee (yes, &lt;em&gt;Tim Berners-Lee's brother&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/building-green-software/9781098150617/" rel="noopener noreferrer"&gt;Building Green Software - A sustainable approach to software development and operations&lt;/a&gt; by Anne Currie, Sarah Hsu and Sara Bergman&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>sustainability</category>
      <category>envsustainability</category>
    </item>
    <item>
      <title>Open Source Day: A Report</title>
      <dc:creator>Davide Boncompagni</dc:creator>
      <pubDate>Fri, 07 Jun 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/open-source-day-a-report-mmc</link>
      <guid>https://dev.to/sparkfabrik/open-source-day-a-report-mmc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;On the 7th and 8th of March we were at the Open Source Day organised by &lt;a href="https://www.schrodinger-hat.it/"&gt;Schrödinger Hat&lt;/a&gt;, and it was a two-day conference full of enthusiasm and innovation in the framework of the innovative Nana Bianca coworker space in Florence, but if you were not there you can at least follow on YouTube their amazing talks &lt;a href="https://www.youtube.com/@SchrodingerHat/streams"&gt;https://www.youtube.com/@SchrodingerHat/streams&lt;/a&gt; or &lt;a href="https://www.youtube.com/@SchrodingerHat/videos"&gt;https://www.youtube.com/@SchrodingerHat/videos&lt;/a&gt; and the agenda &lt;a href="https://2024.osday.dev/it/agenda"&gt;https://2024.osday.dev/it/agenda&lt;/a&gt;.&lt;br&gt;
As you can see there were a lot of amazing ones and I will try to help you decide which talk you should definitely follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technology Trends
&lt;/h2&gt;

&lt;p&gt;There were 2 main trends:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI tools&lt;/strong&gt;, especially LLM related ones, how to build LLM RAG based applications using open source tools from &lt;strong&gt;Hugging Face and Ollama&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebAssembly&lt;/strong&gt; and its wider implications for software development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there was also a "shadow trend", not an explicit trend, but an ecosystem of similar technologies, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CDC (change data capture), CRDT (conflict-free replicated data types) and concurrent collaboration or real-time update platforms&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't have experience with these tools, I recommend Stefano Fiorucci's talk on what an LLM application is, how it works, how to implement it, what it is and how to implement &lt;em&gt;Retrieval Augmented Generation&lt;/em&gt; applications with &lt;strong&gt;Haystack&lt;/strong&gt;, our &lt;strong&gt;Edoardo Dusi&lt;/strong&gt; with his talk on WebAssembly, how it works and how it could become a new future standard due to its interoperability, versatility and great performance, Wasm component wrappers, integration with Docker and Kubernetes and much more, and Federico Terzi with a technical explanation of CRDT and what challenges you need to face to achieve real-time collaboration utilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  My favourite technology tool talks
&lt;/h2&gt;

&lt;p&gt;I will briefly report on my favourite talks and start with some lesser known extensions to a very famous tool, Iulia Feroli's talk, Senior Developer Advocate at &lt;strong&gt;Elastic&lt;/strong&gt;, showed us how easy and powerful Elasticseach could become with the use of some specialised clients allowing us to perform sentiment analysis and semantic search for example.&lt;/p&gt;

&lt;p&gt;Sentiment analysis is an NLP technique that allows you to identify the positive or negative polarity of a given query, while semantic search is the search or ranking of content based on contextual relevance and intent.&lt;br&gt;
For example, you could analyse a list of customer comments and intercept those that could lead to an escalation, or perform a search without having to know the exact terminology (e.g. a search for 'brave' could also return 'courage' and so on).\&lt;br&gt;
The client used to import LLM into Elasticsearch was &lt;strong&gt;Eland&lt;/strong&gt;, the ELSER NLP model was used to perform semantic searches, she also did a little briefing on how vertex search allowed us to perform semantic searches and remembered that vertex search could also be used to search for similar images for example.&lt;/p&gt;

&lt;p&gt;Noam Honig, creator of &lt;strong&gt;Remult&lt;/strong&gt; showed us a new way from backend to frontend, a full-stack CRUD framework that removes all code duplication between frontend and backend like dtos creation, data validation and so on, providing ORM-like database interaction and archiving a Typesafe and DRY architecture. With a live coding session, he showed us how fast it is to build a full-stack application with Remult. It has a lot of features, but the one I find most interesting is the ability to do live queries, long-lived queries that automatically update as results change. It can be integrated with many JavaScript frameworks and many databases.&lt;/p&gt;

&lt;p&gt;Give it a try, maybe with fast prototyping, and you will love the philosophy behind this tool with a clear focus on improving the &lt;em&gt;developer experience&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Mario Fiore Vitale, Senior Software Engineer at &lt;strong&gt;Red Hat&lt;/strong&gt;, talked about &lt;strong&gt;Debezium&lt;/strong&gt;, an open source platform that enables Change Data Capture (CDC), the ability to intercept changes in your database and propagate them across different systems, which could be very useful for synchronising multiple linked data sources, data replication, updating or invalidating a cache, updating search indexes, data synchronisation or propagating database changes via Kafka or a WebSocket. CDC enables incremental loading and eliminates the need for bulk updates. Debezium captures database changes by monitoring the database transaction log, so it doesn't impact the database itself.&lt;/p&gt;

&lt;p&gt;Other interesting technologies included &lt;strong&gt;Nanocl&lt;/strong&gt;, a Rust alternative to Kubernetes that grew out of a study project, Irine Kokilashvili's talk, &lt;strong&gt;Camunda&lt;/strong&gt;, a tool based on business process modelling (BPM), which is a way to orchestrate and describe complex microservices processes and flows, as shown by Samantha Holstine, &lt;strong&gt;LavinMq&lt;/strong&gt; a very performant message broker described by Christina Dahlén, &lt;strong&gt;Scrapoxy&lt;/strong&gt; the amazing web scraping Swiss knife by Fabien Vauchelles and finally Graziano Casto showed us &lt;strong&gt;Rönd&lt;/strong&gt;, a lightweight Kubernetes sidecar that distributes security policy enforcement throughout your application based on OpenPolicy Agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  A broad view of the conference
&lt;/h2&gt;

&lt;p&gt;As you can imagine, an open source conference doesn't just focus on tools, but also on &lt;strong&gt;high-level analysis&lt;/strong&gt; and experiences of open source development.&lt;/p&gt;

&lt;p&gt;There was a focus on &lt;strong&gt;accessibility&lt;/strong&gt; in a broad sense, not only for people with disabilities, but also for people with neurodivergence or temporary disabilities for example, and how to create an environment that helps them to be productive and satisfied with their work, improve their development experience and develop an inclusive workplace.&lt;br&gt;
Also, although it hurts, I learned that Linux doesn't currently have great accessibility tools, so if you want to start an open source project for Linux, consider that we're trying to fill that gap!&lt;/p&gt;

&lt;p&gt;Another topic was what open source is, its different forms, how to monetise or develop a business model for an open source project, how to protect it from being appropriated by big vendors and the &lt;strong&gt;differences between FOSS and OSS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They also talked about the &lt;strong&gt;security of the software supply chain&lt;/strong&gt; and how reliable open source technologies can be, with a presentation on the use of Linux in space missions.&lt;/p&gt;

&lt;p&gt;There was also space for ethics, like a UNICEF talk on the challenge of making digital solutions and services accessible and 'profitable' for the most vulnerable, and also a focus on web sustainability, like that of our &lt;strong&gt;Valeria Salis&lt;/strong&gt;, who wasn't able to be present at the event, but which you can watch from this link &lt;a href="https://www.youtube.com/watch?v=KWK8Upl9-wU"&gt;https://www.youtube.com/watch?v=KWK8Upl9-wU&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I would also like to focus on the talk by Andrey Sitnik, the maintainer of a widely used library such as &lt;strong&gt;Post-CSS&lt;/strong&gt; and so on, who gave us a complete manual on how to manage an open source project, recalling how it is fully linked to relationship management, the need to give quick feedback, to trust contributors and to consider them as the people behind what they are asking for, inviting us to empathise with them, to gain insight into why, for example, your detailed documentation is never read as carefully as you expected, or to understand why some projects that you thought might be more popular are instead ignored despite their potential, to remember how the adoption of a framework or so on depends more on irrational processes than cold analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Open Source
&lt;/h2&gt;

&lt;p&gt;What emerged from the talks was &lt;strong&gt;enthusiasm and positivity&lt;/strong&gt;, open source as a tool that could spread values of commitment, collaboration and tolerance, and develop social communities of mutual respect and status quo challenging innovation, a kind of friendly world utopia, a tool to indirectly promote a better world.&lt;br&gt;
As PJ Hagerty's talk points out, don't expect this to always be true, we need to foster good open source citizenship ourselves first.&lt;/p&gt;

&lt;p&gt;Nowadays many companies claim that their products are OSS as a marketing strategy, but this is not always completely true (especially for some AI tools) and some big projects started to change their licences to some more restrictive or sometimes closed ones.&lt;br&gt;
However, &lt;strong&gt;open source adoption is still very high&lt;/strong&gt; and it's growing, with more than 90% of developers relying on open source components in their proprietary applications.&lt;/p&gt;

&lt;p&gt;But probably in the future, the need to protect large projects from being forked and the business models of the companies behind them, the adoption of open core strategies will change the definition of open source and it will only define projects where the source code is public/available for inspection and there will be a clear distinction between OSS and FOSS where redistribution will be free.&lt;br&gt;
Until then, open source is still a philosophy, and to embrace it, to claim it, is to have a mentality around it.&lt;/p&gt;

&lt;p&gt;And speaking of mentality, I want to focus on a term that is rarely quoted, but I think it should be a core concept related to OSS, and that is the &lt;strong&gt;autotelic concept&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Autotelic is an adjective that describes &lt;em&gt;activities that exist for their own sake&lt;/em&gt;, because experiencing them is the main goal, but also people who do things moved by intrinsic motivation, not by wealth, fame, power research, not by concern for money, status, applause or recognition by others, and it's linked to the ability to experience flow more often and is used to describe some art, sport or play activities.&lt;/p&gt;

&lt;p&gt;This perspective overwhelms the idea of &lt;strong&gt;contributors being driven by ego&lt;/strong&gt;, which is relevant in open source development.&lt;/p&gt;

&lt;p&gt;Public opinion perceives OSS as a tool that promotes free culture and considers it to be a more transparent system, and therefore a more secure system, without any dark patterns inside.&lt;br&gt;
Can free access to source code be a professional standard in the future, demanded by people in the same way that we demand the components of a medicine in the package leaflet?&lt;/p&gt;

&lt;p&gt;We don't know yet, a lot will depend on how events affect public opinion, whether people start to care more about concepts like their privacy and whether they start to trust open source software more than proprietary software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will FOSS continue to exist?&lt;/strong&gt; Probably yes, because libraries or tools for developers focus on usage and if they're free it's easier for them to be adopted, also the development of these tools gives prestige to the people or companies that have worked on them and is also a way to create a process of continuous improvement.&lt;/p&gt;

&lt;p&gt;The affirmation of open source lies in the transformation of users into active actors, able to report bugs and sometimes suggest new features, and this is very common in tools for developers, but still a little lacking in general-use tools for the general public.&lt;/p&gt;

&lt;p&gt;There are also adoptions of the open source model outside of software development, such as in the arts or education, which probably need more resonance, and we probably need to spread the open source mentality beyond the boundaries of software development.&lt;/p&gt;

&lt;p&gt;There are several challenges to overcome, but we hope that open source will be able to flourish, because &lt;strong&gt;"a mind is like a parachute. It doesn't work if it's not open"&lt;/strong&gt; - and that certainly applies to software!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>schrödingerhat</category>
      <category>community</category>
      <category>events</category>
    </item>
    <item>
      <title>How (and why) to contribute to open source</title>
      <dc:creator>Edoardo Dusi</dc:creator>
      <pubDate>Thu, 01 Feb 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/how-and-why-to-contribute-to-open-source-1i9a</link>
      <guid>https://dev.to/sparkfabrik/how-and-why-to-contribute-to-open-source-1i9a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the previous post on our blog, Daniela shared her thoughts and experiences on &lt;a href="https://dev.to/sparkfabrik/how-not-to-contribute-to-open-source-77k"&gt;how difficult it can be to contribute to open source&lt;/a&gt;. It was hard for me to review this post. I felt like I had failed as a senior developer, as a mentor, and as a &lt;strong&gt;long-time member of the open source community&lt;/strong&gt;. Then I started thinking about the current state of open source, and what Daniela wrote made sense: to a newcomer, everything seems to be driven by the hype, the star count, the likes, the followers, we have tech influencers, we have tech rockstars giving keynotes at conferences, we have recruiters scanning GitHub profiles.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Contributing today is about being visible, not about being helpful. And I think my generation of developers is to blame.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this post, I will try to respond to Daniela and all the people who struggle to contribute to open source, and most importantly, I will try to talk about the motivations that should drive our contributions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing to Open Source
&lt;/h2&gt;

&lt;p&gt;First, definitions! Computer scientists have never been good at definitions. We call &lt;em&gt;"artificial intelligence"&lt;/em&gt; something that is not intelligent, and we call &lt;em&gt;"cloud"&lt;/em&gt; something that is on the ground and sometimes &lt;a href="https://news.microsoft.com/source/features/sustainability/project-natick-underwater-datacenter/" rel="noopener noreferrer"&gt;below sea level&lt;/a&gt;. We tried with &lt;strong&gt;Free Software&lt;/strong&gt; and we had to specify &lt;a href="https://www.gnu.org/philosophy/free-sw.en.html" rel="noopener noreferrer"&gt;what we meant by "free"&lt;/a&gt;, and when we realised we needed a more specific definition we created the &lt;strong&gt;Open Source Initiative&lt;/strong&gt; and we had to specify &lt;a href="https://opensource.org/osd/" rel="noopener noreferrer"&gt;what we meant by "open"&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If we cannot agree on what open source means, we cannot agree on what it means to contribute to open source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we stick to the &lt;strong&gt;OSI definition&lt;/strong&gt;, which is derived from Debian's definition of Free Software, we are only talking about how the source code can be accessed, and how the license that governs the distribution of the software should be written.&lt;/p&gt;

&lt;p&gt;But when we talk about open source, we're not just talking about code, or at least I thought we were. We are talking about a way of approaching software, of designing it, developing it, distributing it, spreading it, making it something that benefits everyone. So being a developer in this context means &lt;strong&gt;thinking of software as a common good&lt;/strong&gt;, and then contributing means making it better, and if by better we mean more useful, more accessible, more secure, more powerful, more stable, easier to use, then it is clear that we are not just talking about writing code.&lt;/p&gt;

&lt;p&gt;It would be pointless to list all the non-coding contributions, I just want to point out &lt;strong&gt;participation&lt;/strong&gt; in groups that create guidelines, documentation and translations, those that try to spread best practices, or all the working groups that deal with standardization. But think about how much valuable discussion is generated in GitHub issues, discussion that leads to better software. &lt;strong&gt;None of these activities generate a green square&lt;/strong&gt; in the contribution grid on your GitHub profile, but each one helps improve the entire ecosystem.&lt;/p&gt;

&lt;p&gt;Once we agree on the definition of open source and what it means to contribute, we can move on to the second point in this reflection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why contribute
&lt;/h2&gt;

&lt;p&gt;When I started university in Bologna in the early 2000s, the first community I came into contact with was a kind of Linux user group that organized, in a very informal way, so-called &lt;em&gt;"installation parties"&lt;/em&gt;, i.e. days when some more experienced users would guide us newbies through the first install of a Linux distribution.&lt;/p&gt;

&lt;p&gt;In addition to guiding us through the process of installing Gentoo, which was not a random choice, they would suggest &lt;strong&gt;what to do when we encountered a problem&lt;/strong&gt; or noticed something that could be improved. As you may have guessed, this included posting to our newsgroup, starting a discussion on the official Gentoo Forums, and even using the mailing list. This approach made it natural for me and my fellow travelers to think about &lt;em&gt;communicating with senior members of the community whenever the opportunity arose&lt;/em&gt;, at first just as generators of trivial questions, then more refined, and finally as proposers of solutions or improvements. I never made a commit to the Gentoo codebase, but &lt;strong&gt;I felt useful to the community&lt;/strong&gt; when I answered a colleague's question about how to fix a compile error by creating a symlink to a library that was in the wrong path.&lt;/p&gt;

&lt;p&gt;A few years later &lt;strong&gt;I started working with Drupal&lt;/strong&gt;, still one of the largest and most beautiful free software projects, and interacting with other users on issue trackers, suggesting patches, reporting bugs felt natural to me. Of course, getting the green light from automated tests on an uploaded patch was a good feeling, and when it was merged I felt like I could talk to &lt;em&gt;Dennis Ritchie&lt;/em&gt; as an equal, and so I am no stranger to this reward mechanism.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdp25y6ca2g0rin7c2xxz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdp25y6ca2g0rin7c2xxz.jpg" alt="Drake accepting the Grammy Award with the caption 'I like to thank the reviewers" width="679" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What drove me to contribute, however, &lt;strong&gt;was not the reward&lt;/strong&gt;. It became a necessity, as I was often a few bugs away from delivering a job to a client, and then I felt I had to at least give to others what I had received, so I found myself responding to those who encountered problems I knew how to overcome, or sometimes simply helping by providing my context that might help them understand how to reproduce the bug.&lt;/p&gt;

&lt;p&gt;It was therefore, and still is, &lt;strong&gt;a business motivation&lt;/strong&gt;. &lt;em&gt;"Don't reinvent the wheel"&lt;/em&gt; has been a mantra, building on what others have already introduced and perfected and then making it better, participating in advocacy groups that shape the future of a technology, and many other aspects of the open source world codified and regulated by organizations such as the OSI, but also the &lt;a href="https://www.linuxfoundation.org/" rel="noopener noreferrer"&gt;Linux Foundation&lt;/a&gt; or the &lt;a href="https://www.drupal.org/association" rel="noopener noreferrer"&gt;Drupal Association&lt;/a&gt;, are all aspects that directly impact our work and thus our business.&lt;/p&gt;

&lt;p&gt;Reading Daniela's post &lt;strong&gt;presented me with a completely different experience&lt;/strong&gt;. Talking to her, I realized first of all that she did not find the same conditions in the academic environment that I did, and later that she did not find the communities that I did.&lt;/p&gt;

&lt;p&gt;So the social, utilitarian, and "belonging" motivation that drove me, and I think many others around me, was missing, and &lt;strong&gt;what was left was rewards&lt;/strong&gt;. Of course, recognition had always helped to distinguish an active member of a community from others, but it had never generated &lt;em&gt;such strong pressures&lt;/em&gt; as to drive someone to contribute for the sole purpose of being visible. I seem to see this problem in the desperate search for a project to contribute to, any project, as long as it is popular and publicly acknowledges contributions, and especially if it is on GitHub, which here becomes the social network where a developer's popularity is measured.&lt;br&gt;
&lt;em&gt;(This also removes Drupal from the list of trendy projects...)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Gamification, badges, likes, they're nice things and we all love them, let's not be hypocritical, but if they're the main reason people contribute today, then we have a problem, and we probably created it ourselves. We've created an environment where &lt;strong&gt;it's more important to be visible than to be helpful&lt;/strong&gt;, and we've given that message to the new generation of developers, but we're telling them today that those motivations are wrong.&lt;/p&gt;

&lt;p&gt;So I think it's important to reiterate what it means to &lt;strong&gt;do open source&lt;/strong&gt;.&lt;br&gt;
Let's start from that foundation and try to adjust the focus.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to contribute - for real
&lt;/h2&gt;

&lt;p&gt;Let's start with a basic concept: &lt;strong&gt;you don't have to contribute!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are amazing programmers out there who have zero commits to public GitHub repos, yet they work with open source projects every day. Sometimes focusing on work or perhaps a busy personal life &lt;em&gt;makes it difficult to find time to contribute&lt;/em&gt;, and that's not a problem, it shouldn't make us feel guilty.&lt;br&gt;
Helping a colleague use a technology, making it more accessible by spreading it among your peers, are examples of activities that truly benefit the entire ecosystem but do not entitle you to a badge. &lt;/p&gt;

&lt;p&gt;But if, after making all these points, the desire to appear in a project's CHANGELOG remains, because it makes us more desirable in the eyes of a recruiter, or because it makes us feel more important in our community, which are all things I completely understand, then I can try to give some advice on how to contribute.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start with what you use&lt;/strong&gt;: You work with libraries or frameworks every day, and by now you know them well; these are the perfect projects to start with. If you need to customize a certain feature to make it more useful for your project, or you find a bug, or you see that some of the documentation could be improved, that's your chance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There is no such thing as a "stupid contribution"&lt;/strong&gt;: If you think you have a solution to a problem or an idea for improving something, don't be afraid to share it. If you're not sure, ask for feedback, but know that every contribution is valuable, and the worst thing that can happen is that it's rejected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't be afraid to ask&lt;/strong&gt;: If you don't understand something or aren't sure what to do, ask. There are many channels available, from the official documentation, to the issue tracker, to the community forum, to the chat, to the mailing list. Most (hopefully all) communities are welcoming and eager to help.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't overlook the non-code contributions&lt;/strong&gt;: You can help with translations, documentation, testing (&lt;em&gt;which by the way IS coding...&lt;/em&gt;), or even just by spreading the word about a project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There is more than just GitHub&lt;/strong&gt;: Many open source projects are not on GitHub, but they still need love. Just ask Drupal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Join Discussions&lt;/strong&gt;: Issues and Discussions on GitHub are the most popular, but not the only, way to get started. You can learn a lot about a project from these discussions, commenting increases your visibility and participation in the community, and code contributions can often result.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Open Source is not just code. It's a way of thinking about software, and contributing means making it better.&lt;br&gt;
You don't &lt;strong&gt;have to&lt;/strong&gt; contribute, and I hope that in the future we can create a more welcoming environment for new contributors, and that the reward mechanism will change to reflect effort and dedication, rather than just commits.&lt;/p&gt;

&lt;p&gt;Thank you for reading this far, and if you have any questions or comments, please feel free to contact me at &lt;a href="https://continuousdelivery.social/@edo" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/edoardodusi/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>community</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>DruBOM: An SBOM for Drupal</title>
      <dc:creator>Edoardo Dusi</dc:creator>
      <pubDate>Mon, 29 Jan 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/drubom-an-sbom-for-drupal-3dp6</link>
      <guid>https://dev.to/sparkfabrik/drubom-an-sbom-for-drupal-3dp6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Securing the software supply chain is a hot topic for organizations globally. The recent &lt;em&gt;SolarWinds hack&lt;/em&gt; demonstrated that even the most security-conscious organizations can be vulnerable, and as a result, government agencies and security experts worldwide agreed on the need for standards and best practices to achieve a more secure software ecosystem.&lt;/p&gt;

&lt;p&gt;One fundamental element is the ability to identify all components of a software project, including dependencies, and their versions. This is called a &lt;strong&gt;Software Bill of Materials (SBOM)&lt;/strong&gt;. With this information, organizations can track the components and their versions, and be able to identify and mitigate vulnerabilities.\&lt;br&gt;
There are several initiatives to create standard formats for SBOMs, including &lt;a href="https://cyclonedx.org/" rel="noopener noreferrer"&gt;CycloneDX&lt;/a&gt;, &lt;a href="https://spdx.dev/" rel="noopener noreferrer"&gt;SPDX&lt;/a&gt;, and &lt;a href="https://www.ntia.gov/sbom" rel="noopener noreferrer"&gt;others&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are working on a Drupal-specific SBOM called &lt;a href="https://www.drupal.org/project/drubom" rel="noopener noreferrer"&gt;DruBOM&lt;/a&gt;. In this post, we will explain what DruBOM is, how it works, and how you can use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is DruBOM?
&lt;/h2&gt;

&lt;p&gt;First of all, this is a Drupal module, it needs to be downloaded and installed using &lt;em&gt;Composer&lt;/em&gt;, and requires Drupal 9.3 and above or Drupal 10.3 and above.&lt;/p&gt;

&lt;p&gt;To generate the SBOM it integrates &lt;a href="https://github.com/anchore/syft" rel="noopener noreferrer"&gt;Anchore Syft&lt;/a&gt;, so this needs to be installed on the server. &lt;strong&gt;Syft&lt;/strong&gt; is a CLI tool written in Go that analyzes the contents of a container image or directory on the file system and generates an SBOM in various formats, including CycloneDX and SPDX.&lt;/p&gt;

&lt;p&gt;If these requirements are met, DruBOM will generate an SBOM for the Drupal project, including the Drupal core, modules, themes and libraries, as well as PHP and JavaScript dependencies. The default format is CycloneDX, but it can be configured to use other formats supported by Syft.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does DruBOM work?
&lt;/h2&gt;

&lt;p&gt;The initial version of the module is very simple. It detects the Syft binary and calls it passing the Drupal root directory and the output format as parameters, then saves the output to the key-value store with the &lt;code&gt;drubom.sbom&lt;/code&gt; key and the current timestamp.&lt;/p&gt;

&lt;p&gt;You can then download the SBOM, or better yet, use it with automated tools to detect vulnerabilities and/or licensing issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use DruBOM?
&lt;/h2&gt;

&lt;p&gt;The first step is to add the DruBOM module to your Drupal project.\&lt;br&gt;
Run &lt;code&gt;composer require sparkfabrik/drubom&lt;/code&gt; and then enable the module with &lt;code&gt;drush&lt;/code&gt; or via the Drupal administration interface.&lt;/p&gt;

&lt;p&gt;After installing and enabling the module, navigate to &lt;em&gt;Administration » Configuration » System » DruBOM settings&lt;/em&gt; and specify the path of the Syft binary. The binary must be executable by the PHP process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the PHP configuration must allow the use of &lt;code&gt;proc_open()&lt;/code&gt;, which is equivalent to &lt;code&gt;exec()&lt;/code&gt; in terms of security.&lt;/p&gt;

&lt;p&gt;Once the configuration is saved, generate the SBOM by clicking the &lt;strong&gt;Generate SBOM&lt;/strong&gt; button on the settings page or by visiting the &lt;code&gt;/drubom/generate&lt;/code&gt; path with a user who has the necessary permissions. The generated list will be saved on the Drupal DB and can be downloaded by clicking the &lt;strong&gt;Download SBOM&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4o33pw1ow28ryzvltne6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4o33pw1ow28ryzvltne6.jpg" alt="DruBOM administration page" width="800" height="447"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Image: Screenshot of a DruBOM administration page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can also use the &lt;code&gt;drush drubom:generate&lt;/code&gt; command to generate the SBOM from the command line. To download it, use the &lt;code&gt;drush drubom:download&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;The scope of the module is very specific, so we don't expect it to grow much in terms of features. During the &lt;a href="https://www.drupal.org/community/events/drupal-global-contribution-weekend-italy-2024-2024-01-27" rel="noopener noreferrer"&gt;Drupal Contribution Weekend 2024&lt;/a&gt; we improved the documentation and the administration interface, added an integration with the System Status page in Drupal administration, and started integrating with &lt;a href="https://github.com/anchore/grype" rel="noopener noreferrer"&gt;Grype&lt;/a&gt; to also detect vulnerabilities, which is a step forward in terms of security.&lt;/p&gt;

&lt;p&gt;We consider this module to be fully stable and ready for production use, so we encourage you to try it out and give us feedback. If you find any problems, please report them to the &lt;a href="https://www.drupal.org/project/issues/drubom" rel="noopener noreferrer"&gt;issue queue&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>opensource</category>
      <category>security</category>
      <category>sbom</category>
    </item>
    <item>
      <title>How (not) to contribute to open source</title>
      <dc:creator>Daniela Bonvini</dc:creator>
      <pubDate>Thu, 25 Jan 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/sparkfabrik/how-not-to-contribute-to-open-source-77k</link>
      <guid>https://dev.to/sparkfabrik/how-not-to-contribute-to-open-source-77k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The idea of contributing to open source projects is often presented as an easy task that anyone can do. However, in reality, it can be a very challenging journey. Despite hearing countless times that contributing to open source is simple, it wasn't until I tried it myself that I realized this was not the case. In this text, I will share my own experience with open source contribution to provide an honest and informative account of what it truly entails.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy5t1eu7cg97qs2bk3ar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy5t1eu7cg97qs2bk3ar.png" alt="Tidus standing in front of Zanarkand ruins for the last time in Final Fantasy X" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Act 1: The grand illusion
&lt;/h2&gt;

&lt;p&gt;In the beginning, I started to ask my colleagues for tips on where to start, and they pretty unanimously said to search for issues with &lt;strong&gt;for beginners&lt;/strong&gt; or &lt;strong&gt;help wanted&lt;/strong&gt; tags, maybe in some of the projects I was already using at work. Well, I thought, that's easy. I got a short list of the libraries I was using and/or I was interested in and started digging into their &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; repositories. I combed dozens of open issues, but either they had no &lt;strong&gt;good first issue&lt;/strong&gt; tag, or the more accessible things got snatched lightning fast.&lt;/p&gt;

&lt;p&gt;So I went back to those who had suggested this route and asked for advice again, and this time they told me that I probably couldn't look in the famous libraries, where the competition was too fierce; I had to find my hidden gem in smaller projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxons6gx8tr1wu32xyy9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxons6gx8tr1wu32xyy9.jpg" alt="Toad telling Mario that his issue is in another repo" width="534" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I restarted my search, feeling slightly disgruntled. While it's nice to offer help, it's even better if that help is given to a prestigious library that you can boast about to other developers. It's natural to want to showcase our accomplishments, especially to those who understand our work. My parents only see value in my ability to fix their phones, so let me have this one thing.&lt;/p&gt;

&lt;p&gt;I then perused less-known libraries, confident that I would be lucky this time. But I wasn't.&lt;br&gt;
All I could find were libraries with complicated tasks, even the ones marked &lt;strong&gt;for beginners&lt;/strong&gt;, in which the tag was very much misplaced, as in you had to know the codebase exceptionally well to fix even the minor stuff.&lt;br&gt;
So &lt;em&gt;OF COURSE&lt;/em&gt; I rolled up my sleeves, drew upon my inner strength, and found the perfect fix, after which everybody hailed me as the best contributor in the world.&lt;/p&gt;

&lt;p&gt;Yes, no, of course not, otherwise we wouldn't be here. I quit. Just like that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mteoqvmzlq2bo5k26xx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mteoqvmzlq2bo5k26xx.jpeg" alt="Godzilla returning to the sea saying nope" width="796" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Act 2: Reality check
&lt;/h2&gt;

&lt;p&gt;Let's jump a few months ahead, and the OS itch returned to me. I have a friend who makes videos about OS. He was doing one on Hacktoberfest &lt;sup id="fnref1"&gt;1&lt;/sup&gt;, saying that there were no physical prizes to discourage issue-taking spammers this year. This was my long-awaited chance, I was certain!&lt;/p&gt;

&lt;p&gt;So I went to the Hacktoberfest site and combed the &lt;strong&gt;starting&lt;/strong&gt; section. There, I found a link to a site that collected issues suited for first-timers, grouped by project. If they were included in the most famous site for the most famous OS event of the year, they certainly must be what I was looking for, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhv54pwr7nrm5o40s65h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhv54pwr7nrm5o40s65h.jpg" alt="padme-dev asking anakin-github if it has beginner friendly prs" width="503" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first, I tried filtering by language, trying JavaScript, and looking at some of the open issues. Even worse than with my previous attempt months before, I couldn't even find the issues this time: they were snatched so fast that the site wasn't always updated on time, so it listed things already being worked upon or even fixed and merged.&lt;br&gt;
So I narrowed my search and went where only the bravest engineers dare to go: CSS fixes.&lt;br&gt;
But even doing so, I was again faced with the problem of finding only &lt;em&gt;not-really-for-beginners-beginners-tagged&lt;/em&gt; issues. So, once more, I gave up.&lt;/p&gt;

&lt;p&gt;Third time's the charm, and now I was fixated on having to make at least one OS contribution, so after Hacktoberfest was over, I tried another of the many tips I had been given previously: fix the documentation and find typos or bugs even before an issue is opened.&lt;/p&gt;

&lt;p&gt;This was pure coincidence; I was researching &lt;a href="https://angular.dev/guide/signals#writable-signals" rel="noopener noreferrer"&gt;Angular's Signals&lt;/a&gt;, and I knew that the &lt;em&gt;.mutate()&lt;/em&gt; function was taken out of the APIs. (For context, this was just a couple of days from the announcement).&lt;br&gt;
I checked the documentation and, lo and behold, it was still there. I thought this was my chance for glory: a small, not-yet-mainstream documentation fix in a famous project. So I rushed over to the &lt;a href="https://github.com/angular" rel="noopener noreferrer"&gt;Angular GitHub&lt;/a&gt;, and I'm sure you've guessed it: It was already fixed and just waiting to be merged in. And it was snatched just before I checked, so double the annoyance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Act 3: The Hidden Gem
&lt;/h2&gt;

&lt;p&gt;That was the last straw; cumulatively, I had spent more time looking for something to do than actually doing it. But I really wanted to contribute!&lt;br&gt;
So a few more months went by, until one day I met an Italian open source maintainer and long-time speaker, Giorgio Boa, who by the way was &lt;a href="https://www.youtube.com/live/P2WVTBjh00E?si=U97cCjlNZFPtmFUZ" rel="noopener noreferrer"&gt;a guest on our podcast Continuous Delivery&lt;/a&gt;, and asked him for advice, saying that I wanted to be part of the OS world. He said he was working on a small library of &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; components and could help me if I wanted. I gladly accepted, and we found an issue that seemed pretty straightforward.&lt;br&gt;
A few days after our conversation, I followed the little README guide to install everything required, and...nothing worked. So, after a few bad words, a lot of doubt about my skills as an engineer, and self pep talks to overcome my shyness about asking for help, I contacted Giorgio again. Even with his help, at first we had some trouble figuring out what was going wrong, but in the end I finally had a working setup.&lt;/p&gt;

&lt;p&gt;Eventually, I finally had time to start working on it. It seemed easy; Boa had already given me some tips on how to get started, so I got half the work done in a short time. But then the problems started. After going in circles for about a day, I finally gave in. I did the scariest thing of all: I once again asked for help, admitting that I had no idea what was going wrong. We tried to look at it together, but we couldn't find the problem right away. So I committed the part that I did that worked, and the next day Giorgio fixed the other half and merged my very first PR into the &lt;a href="https://github.com/qwikifiers/qwik-storefront-ui" rel="noopener noreferrer"&gt;Qwik Storefront&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqr6gaihdm7vtz109oaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqr6gaihdm7vtz109oaf.png" alt="Tom from The Office saying that the merged pr is beautiful" width="522" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, in the end, I finally got what I wanted: a published contribution in a good library, but I couldn't stop wondering if it was all worth it.&lt;br&gt;
I was proud of it, of course, even though I needed some help. But I wanted more out of my work.&lt;br&gt;
In the beginning I felt like a fraud for not contributing to OS, but in the end even contributing, or trying to contribute, made me feel like a fraud for not knowing enough and being more of a burden to a senior contributor than an additional help.&lt;/p&gt;

&lt;p&gt;Looking back at it now, I think my biggest mistake was trying to do it for the hype, trying to conform to what everybody else around me said I should be doing and not because I really believed in what I was doing and why.&lt;br&gt;
It doesn't really matter what anyone else says or does, because at the end of the day it's your time that's being spent solving these issues, and that time has to mean something to you if it's being taken away from other parts of your life.&lt;/p&gt;

&lt;p&gt;I haven't resolved any other issues since then, and for now that's ok for me. I want to resolve an issue all by myself next time, but I want to be sure to do it for the right reasons this time, to avoid any unnecessary stress.&lt;br&gt;
Knowing that this time, if I do go back and contribute, it won't be for the "glory" or the FOMO (Fear Of Missing Out), but for the kindness I've been shown, and which I hope to one day give back to a fellow developer in need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: The Truth Unveiled
&lt;/h2&gt;

&lt;p&gt;So am I saying you shouldn't contribute to OS? Well, of course not. But I am stressing the importance of doing it because you really want to, or because you think the project you are working with will benefit from your contribution, not because everyone else is doing it and telling you how important it is, or because you really want a free T-shirt. As we've seen, helping in OS is not a walk in the park, so you must engage in it knowing what you're really getting into to avoid unnecessary frustration.&lt;/p&gt;

&lt;p&gt;If you enter this world fully aware of what you're up against, you'll find it easier to accept the difficulties that come with trying to start contributing to open source. It will also give you the mental strength to accept failure when the problem you thought was beginner-friendly turns out to be much more treacherous than you thought.&lt;br&gt;
What will be different is your reaction in front of this problem, as you will now know that there's no shame in not being able to close a beginner-tagged issue or even in asking somebody more skilled than you for help. Even though you'd have to ask two, three, or a hundred times. Just know that it is ok to fail and to need support and it doesn't make you any less of a developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Post Scriptum
&lt;/h3&gt;

&lt;p&gt;This post offers my personal viewpoint on contributing to open source software, with the awareness that alternative methods of contribution, such as identifying and reporting bugs or translating documentation into other languages, exist but may be less widely known to those who are new to open source communities. Rather than purporting to present the definitive truth, the aim of this post is to provide a different angle on the difficulties that beginners may encounter when trying to make their mark in this world of contribution. The text conveys a thought-provoking perspective while upholding the utmost respect for individuals who consistently contribute to the open-source world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT&lt;/strong&gt;: we also wrote a reply to this post that you can find &lt;a href="https://dev.to/sparkfabrik/how-and-why-to-contribute-to-open-source-1i9a"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnotes
&lt;/h4&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://hacktoberfest.com/" rel="noopener noreferrer"&gt;Hacktoberfest&lt;/a&gt; is an annual worldwide event held during the month of October. The event encourages open source developers to contribute to repositories for the whole month.&lt;br&gt;
Up until 2022, if 4 of your PRs got merged, you would receive a free t-shirt and sometimes other swag, which created utter chaos, with loads of fake or useless pull requests being spammed all over the GitHub universe. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>opensource</category>
      <category>web</category>
      <category>development</category>
      <category>community</category>
    </item>
  </channel>
</rss>
