<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://gohugo.io/" version="0.155.3">Hugo</generator><title type="html">Philodev Blog</title><link href="https://philodev.one/" rel="alternate" type="text/html" title="html"/><link href="https://philodev.one/index.xml" rel="alternate" type="application/rss+xml" title="rss"/><link href="https://philodev.one/index.json" rel="alternate" type="application/json" title="json"/><link href="https://philodev.one/atom.xml" rel="self" type="application/atom+xml" title="atom"/><updated>2026-03-11T21:57:15+01:00</updated><author><name>Sofia Fischer</name><email>sofia@philodev.com</email></author><id>https://philodev.one/</id><entry><title type="html">📚 Book takeaways Refactoring by Martin Fowler</title><link href="https://philodev.one/posts/2026-02-refactoring/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-10-queues-in-practice/?utm_source=atom_feed" rel="related" type="text/html" title="Consuming and Publishing to an external Service with Symfony Messenger"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><link href="https://philodev.one/posts/2024-04-event-sourcing/?utm_source=atom_feed" rel="related" type="text/html" title="Event Sourcing for long living projects"/><link href="https://philodev.one/posts/2024-01-symfony-queues/?utm_source=atom_feed" rel="related" type="text/html" title="Symfony Messenger Component step by step"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><id>https://philodev.one/posts/2026-02-refactoring/</id><published>2026-02-28T10:20:44+02:00</published><updated>2026-02-28T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>A classic book by Martin Fowler about refactoring, providing a collection of code smells and refactoring techniques to improve them</blockquote><div class="lead !mb-9 text-xl">
  A classic book by Martin Fowler about refactoring, providing a collection of code smells and refactoring techniques to
improve them.
</div>

<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>In these call-outs I flag my personal opinion or additions.
Like for other books, this post reflects my learnings and opinions. It does not aim for a true representation or summary
of the book. Some chapters (like the one about self-testing code) are missing completely, because I honestly did not
feel like this book is a good way to learn about tests compared to books which are focused on modern test strategies.</p>
<p>I very much changed the structure of the book. As a reader I may enjoy the freedom of reading it the way I
please and find easy to follow, regardless on the structure the author envisioned.
In this case this means, Martin Fowler offered one chapter of code smells linking to
the following chapters of categorized ways of refactoring with examples; while I will present here a selection of code
smells with examples and the best fitting refactorings to fix them. The code examples are all self designed code smell
asci monsters (even if they look like a tree).</p>
</span>
</div>

<h2 id="refactoring" class="relative group">Refactoring <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#refactoring" aria-label="Anchor">#</a></span></h2><p>Refactoring is a code change that does not change the external behavior of the Code.</p>
<p>It should be driven by change, not by personal opinions on code aesthetics.</p>
<p>Reasons and moments to refactor could be:</p>
<ul>
<li>If a new feature should be implemented, and there is no simple way to add the new code</li>
<li>Reducing the future cost of change. Modularity can improve the speed in which new functionality can be added (if we
are aware of the upcoming functionality)</li>
<li>Emphasize architecture decisions that sometimes get buried under short term decisions</li>
<li>Comprehensive Refactoring to understand complicated code</li>
<li>Litter pickup to always leave the code cleaner that you encountered it</li>
<li>Refactor as review style</li>
</ul>
<p>Refactoring can always be performed step by step, with reliable tests running, and do not need a massive change of the
code base with hours of trying to get a now completely different code running to the same tests. Every refactoring is
possible in a loop of one line change, tests passing, and the next one line change. Need to refactor a property into a
getter? Write the getter, replace property access by property access with the getter. Need to extract a function (and
don&rsquo;t want to use the IDEs refactor function)? Move it line by line into the function, while keeping the tests passing.
Having a hard time with many variables? Replace them with function calls during refactoring to enable you to move slowly
with passing tests.</p>
<p>Because refactoring does not change the external behavior, it can be completely separated from feature development,
coining the phrase <code>First make the change easy, then make the easy change</code>. This emphasizes feature adding and
refactoring are two steps, valuing different skills and knowledge, and aiming for different goals - different jobs that
can be imagined as two hats be worn to different occasions, never simultaneously.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">I even would add a Optimization hat for even another job: identifying and improving bottlenecks in a system.</span>
</div>

<p>






  
  
<figure><img src="/images/2026-02-refactoring.png" alt="Cowboy Refactoring hat, Code Wizards Cylinder, Optimization Artist Beret" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h3 id="refactoring-and-performance" class="relative group">Refactoring and Performance <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#refactoring-and-performance" aria-label="Anchor">#</a></span></h3><p>Most performance issues are located in a very small fraction of the code. Most of the time, refactoring makes it easier
to identify and tackle those bottlenecks, which in practise is often more relevant than performance drawbacks from
refactoring e.g. running through the same loop twice to separate two steps of processing.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>In most cases, replacing a variable with a query does not harm the performance in a way that matters, but it can be a
good idea to check if the query is expensive to execute before doing this refactoring. By expensiveness, I don&rsquo;t mean
algorithmic complexity growing from O(n) to O(2n), but more excessive database queries that cost measurable amounts of
resources in a software system.</p>
<p>Many arguments regarding performance because of refactorings in my experience are not based on actual measurements, but
rather on a gut feeling, that often not even accounts for the languages / compiler specific optimizations. If a
refactoring causes a measurable performance decrease (to which I would call number of database queries), then the
refactoring is questionable.</p>
</span>
</div>

<h2 id="code-smells" class="relative group">Code Smells <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#code-smells" aria-label="Anchor">#</a></span></h2><h3 id="mysterious-name" class="relative group">Mysterious Name <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#mysterious-name" aria-label="Anchor">#</a></span></h3><p>Naming is hard, and renaming a function, property, or variable is one of the most common refactorings. While it is easy
to call out &ldquo;rename it&rdquo; as a solution, complicated names can often be a sign of deeper design issues.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">I am a big fan Ubiquitous Naming, one of the core principles of Domain Driven Design. Concepts in code should be named
how the user would name the concept when using the software. If there is something in the code, that the developer has a
hard time to name, and the user does not have a clear name for it, maybe it indicates that it should not be in the code
at all?</span>
</div>

<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">caliginous_string</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">      -------
</span></span></span><span class="line"><span class="cl"><span class="s2">      │  ?  │
</span></span></span><span class="line"><span class="cl"><span class="s2">    dbqpdbqpdbq
</span></span></span><span class="line"><span class="cl"><span class="s2">      ( o.o )
</span></span></span><span class="line"><span class="cl"><span class="s2">      @≥ - ≤@
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="change-the-declaration-of-a-function-property-or-variable" class="relative group">Change the declaration of a function, property or variable <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#change-the-declaration-of-a-function-property-or-variable" aria-label="Anchor">#</a></span></h4><p>Functions represents building blocks of the software system. A well-defined function name can replace the need of
finding out what the function does and how it is used. This also applies to parameters, properties and variables - a
clear names enables the future developer to understand the code, its purpose and how it is used without needing to read
the implementation. The more widely something is used, the more important is the clarity of its name.</p>
<h3 id="duplicated-code" class="relative group">Duplicated Code <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#duplicated-code" aria-label="Anchor">#</a></span></h3><p>Using the same code in multiple places can indicate a missed opportunity for abstraction. Abstracting would emphasize
the differences between similar code, instead of costing the reader time to question if there is a difference.
If the difference might even be big and consistent enough to
be <a href="#extract-a-function">separated into multiple functions</a>.</p>
<p>To ensure euphoric deduplication is not making the code more complex than it needs to be, the &ldquo;Rule of three&rdquo; can
be used as a guidance to allow duplications until at least three variants did present themselves to understand how
different variants might behave.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">twin_monster</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">      -------
</span></span></span><span class="line"><span class="cl"><span class="s2">      │  ?  │
</span></span></span><span class="line"><span class="cl"><span class="s2">    dbqpdbqpdbq
</span></span></span><span class="line"><span class="cl"><span class="s2">      ( ^.^ )
</span></span></span><span class="line"><span class="cl"><span class="s2">      @≥ - ≤@
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="slide-move-statements" class="relative group">Slide (Move) Statements <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#slide-move-statements" aria-label="Anchor">#</a></span></h4><p>Code is easier to understand when related statements are close to each other. Sliding statements means moving statements
together. This can be a preparation for an <a href="#extract-a-function">Extract Function</a>.</p>
<h3 id="long-function" class="relative group">Long Function <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#long-function" aria-label="Anchor">#</a></span></h3><p>A long function hides where the main logic is defined, and will cause every reader time to parse through the entire
function to understand it and where the new feature should be placed. This can be avoided by shortening and structuring
the function in way, that makes it easy to understand and place a new feature. The main goal should not be to reach a
maximum line number a function should have, but to separate intention and implementation. A function should have a
specific reason and context to exist in, which might be a concrete implementation, or stating an intention that calls
implementations.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">long_function_monster</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Start building the snake</span>
</span></span><span class="line"><span class="cl">    <span class="n">snake</span> <span class="o">=</span> <span class="s2">&#34;    ___   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;  &gt;{_σ │  </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Changed to left turning snake by 2020</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">now</span> <span class="o">&gt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2020</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">15</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;      \ \  </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Rolling release in 2025</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">now</span> <span class="o">&gt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2025</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;   ____) )</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">now</span> <span class="o">&lt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2025</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34; / _____/ </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">now</span> <span class="o">&lt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2025</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;( (___    </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">now</span> <span class="o">&lt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2025</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34; \___ \   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">now</span> <span class="o">&lt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2025</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;     \/   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Feature flag with auto enable in 2022</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">now</span> <span class="o">&lt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2022</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">20</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34; \___ \   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">now</span> <span class="o">&gt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2022</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;     \/   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;  ___/ /  </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">now</span> <span class="o">&gt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2023</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">14</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34; / _____/   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">now</span> <span class="o">&lt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2023</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">4</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;( (___ __ </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">now</span> <span class="o">&gt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2023</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">31</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34; \_____  </span><span class="se">\\</span><span class="s2">n&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># Parse the override string</span>
</span></span><span class="line"><span class="cl">            <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Special handling for empty results (added for client X)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">now</span> <span class="o">&lt;</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2024</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34; / _____/ </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Tail handling</span>
</span></span><span class="line"><span class="cl">    <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;( (___    </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34; \___ \   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">snake</span> <span class="o">+=</span> <span class="s2">&#34;     \/   </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">snake</span>
</span></span></code></pre></div><p>Similar to this, <strong>Large classes</strong> cause the same problems, which might or might not allow the <a href="#extract-class">extraction of whole
class</a>. Additionally, here identifying
and <a href="#replace-conditional-with-polymorphism">replacing possible subclasses with different types</a> might help, this way
properties and functions that only belong to some subtypes are moved out of the way to only leave the things that are
common and used among all subclasses.</p>
<h4 id="extract-a-function" class="relative group">Extract a Function <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#extract-a-function" aria-label="Anchor">#</a></span></h4><p>A function symbolizes a differentiation between intent and implementation. Extracting a function means replacing the old
code fragment with a function call named after the intent of the code fragment. The parameters of the extracted function
highlight dependencies and differences between its usages. With this goal in mind, having a function that just hase one
line of code can be valid if it describes the intent of the code fragment better than the code fragment itself. In that
way extracting a function can replace the need of a comment.</p>
<p>A large block of code can have a clearer intention if the code blogs within conditionals are extracted, leaving just the
conditional easily readable in the original function. How the conditions are structured can also have drawbacks and
benefits. Sometimes it is a clean solution to have on consolidated check that replaces a big nested check can make
things easier to understand than a big conditional with many branches.</p>
<p>Pulling up a method means moving a method from a subclass to its superclass. This is useful when the method is
duplicated in multiple subclasses, or only differs in small parts, naming, or parameters.</p>
<p>One hint, that a function is too long and should be splitted. If a variable is the result of a complex calculation, but
is then re-assigned, that can be a sign that the function and that variable is doing too much and might work better
splitted.</p>
<h4 id="replace-variable-property-or-parameter-with-query" class="relative group">Replace Variable, Property, or Parameter with Query <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#replace-variable-property-or-parameter-with-query" aria-label="Anchor">#</a></span></h4><p>Variables or Parameters can capture and name a value, but they also introduce something the developer needs to keep in
mind. Replacing variables with small functions can make the code easier to read and to perform other refactorings
because the local dependency of the variable is removed.</p>
<p>Replacing properties with queries can also remove mutable data that can also be calculated freshly, removing any danger
to corrupt or stale the value.</p>
<p>Replacing a variable with a query only makes sense if the redone calculation of the variables will not change the
outcome. While formatting for example would always produce the same result, a database query might produce different
results each time it is executed (which can be intentional in the same function, but sometimes is not).</p>
<h4 id="replace-function-with-command" class="relative group">Replace Function with Command <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#replace-function-with-command" aria-label="Anchor">#</a></span></h4><p>A command in this context is a function that is encapsulated into an object. In this form, the function can have its own
set of subfunctions and properties. This can be useful when the function is too complex to be easily understood, or when
it is intended to be used as a single unit of work that can be executed, undone, or queued.</p>
<h4 id="replace-conditional-with-polymorphism" class="relative group">Replace Conditional with Polymorphism <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#replace-conditional-with-polymorphism" aria-label="Anchor">#</a></span></h4><p>Complex conditional logic is often the hardest thing to code in a readable, intuitive way. One way to solve this is to
separate the conditions into different circumstances that are wrapped into different subclasses, each handling an
understandable subset of the conditional logic. This can be Variants with given parameter options, variants that match
certain assumptions, or variants that belong to different types.</p>
<h4 id="split-loop-intp-pipeline" class="relative group">Split Loop (intp Pipeline) <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#split-loop-intp-pipeline" aria-label="Anchor">#</a></span></h4><p>It is a common anty pattern that a loop is used to do things at the same. This comes with the drawback, that whenever
the loop is touched, both things need to be understood. Splitting such a loop into two loops, each doing its own task,
can be a good solution for that. Many hesitate to do this because of performance concerns, which are covered
in <a href="#refactoring-and-performance">Refactoring and Performance</a></p>
<p>If that loop does multiple things, this can be further clarified by using Pipelines like Map, Filter, Reduce to further
emphasise how the data is processed.</p>
<h3 id="long-parameter-list" class="relative group">Long Parameter List <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#long-parameter-list" aria-label="Anchor">#</a></span></h3><p>Long parameter lists happen, sometimes for historic reasons, sometimes because more and more functionality was added
over the iterations. It indicates in any case that the behavior of functions may vary in many ways, which ways exactly
is obfuscated by the number of variables that the reading developer needs to keep in mind to parse the function.</p>
<p>One straight forward way is to <a href="#replace-variable-property-or-parameter-with-query">replace a Parameter with Query</a> to
reduce the number of parameters, although this would keep the coupling.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">parameter_hungry_monster</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">has_teeth</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">teeth_count</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">tongue_count</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">tonsils</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">extra_jaw_size</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">teeth_count</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="n">teeth_count</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="s2">&#34; _&#34;</span> <span class="o">+</span> <span class="s2">&#34;_&#34;</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34;δδ) </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">+=</span> <span class="s2">&#34;() &#34;</span> <span class="o">+</span> <span class="s2">&#34; &#34;</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34; | </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">+=</span> <span class="s2">&#34;  &#34;</span> <span class="o">+</span> <span class="p">(</span><span class="s2">&#34;v&#34;</span> <span class="k">if</span> <span class="n">has_teeth</span> <span class="k">else</span> <span class="s2">&#34;~&#34;</span><span class="p">)</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34;\ |</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">tonsils</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">monster</span> <span class="o">+=</span> <span class="s2">&#34; &#34;</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34;   |│</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">tongue</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tongue_count</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">monster</span> <span class="o">+=</span> <span class="s2">&#34; &gt;≈&#34;</span> <span class="o">+</span> <span class="s2">&#34;≈&#34;</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34;|│</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">extra_jaw_size</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">extra_jaw_size</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">monster</span> <span class="o">+=</span> <span class="s2">&#34; &#34;</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34;   |│</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">+=</span> <span class="s2">&#34; (&#34;</span> <span class="o">+</span> <span class="s2">&#34;^&#34;</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34;  │ </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">+=</span> <span class="s2">&#34; &#34;</span> <span class="o">*</span> <span class="n">teeth_count</span> <span class="o">+</span> <span class="s2">&#34;ΣΣ ß&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">monster</span>
</span></span></code></pre></div><h4 id="introduce-parameter-object" class="relative group">Introduce Parameter Object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#introduce-parameter-object" aria-label="Anchor">#</a></span></h4><p>Often a set of parameters travel together even through multiple functions. Such data clump can be replaced by a data
class, emphasizing their relationship. Also, this will make the code more consistent and reducing the parameter list.
They also open up the possibility to restructure the code around this new-found abstraction.</p>
<p>It sometimes happens that a couple of properties of an object are separated just to be put into one function. This is
prone to future touches as any change of the object might require touching the function. This can be avoided if the
whole object would become the parameter. Although sometimes the dependency to the object can be a problem itself.</p>
<p>Another example of replacing parameters is replacing boolean flag arguments with more meaningful enums, even replace
other parameters.</p>
<h4 id="combine-functions-into-class" class="relative group">Combine Functions into Class <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#combine-functions-into-class" aria-label="Anchor">#</a></span></h4><p>Classes bind functions together in a shared environment, exposing some behavior for outside functions to interact.
Moving sets of functions into a class makes the shared environment they act in visible.</p>
<h3 id="mutable-data" class="relative group">Mutable Data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#mutable-data" aria-label="Anchor">#</a></span></h3><p>Mutable data often leads to a change of data here causes unintended side effects in a different place.
The easiest, but not always straight forward solution is to prefer values to references. Instead of changing data
objects, they then should be re-instantiated with the new values.</p>
<p>One way to solve this is to <a href="#extract-a-function">extract the re-instantiation into a function</a>
or <a href="#replace-variable-property-or-parameter-with-query">replacing the mutable
variable directly with a query</a>.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>Rust does a great job in sensitizing one on the restrictions of mutable data. In Rust everything is immutable by
default, requiring the dev to explicitly declare it as mutable. Even pointers may be mutable or not.</p>
<p>Rust has the concept of Ownership - every object has an owner that may the only one who may mutate a mutable object.
This again causes more friction for the developer, forcing them to be conscious about mutability and hinting towards
queries over variables.</p>
</span>
</div>

<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">mutable_data_monster</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&#34; ,---.</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="s2">&#34;( @ @ )</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="s2">&#34; ).-.(</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="s2">&#34;&#39;/|||\`</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="s2">&#34;) &#39;|` (</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">_bubbly</span><span class="p">(</span><span class="n">_mutate_tentacle</span><span class="p">(</span><span class="n">monster</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_mutate_tentacle</span><span class="p">(</span><span class="n">monster</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="n">monster</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;|||&#34;</span><span class="p">,</span> <span class="s2">&#34;( )&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="n">monster</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="s2">&#34;)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">monster</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\\</span><span class="s2">&#34;</span><span class="p">,</span> <span class="s2">&#34;(&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_bubbly</span><span class="p">(</span><span class="n">monster</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="n">monster</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">,</span> <span class="s2">&#34;~&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="n">monster</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;`&#34;</span><span class="p">,</span> <span class="s2">&#34;)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="n">monster</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;&#39;&#34;</span><span class="p">,</span> <span class="s2">&#34;(&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">monster</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;,&#34;</span><span class="p">,</span> <span class="s2">&#34;●&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="encapsulate-variable-into-a-function" class="relative group">Encapsulate Variable into a function <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#encapsulate-variable-into-a-function" aria-label="Anchor">#</a></span></h4><p>Data is trickier to refactor than functions, as functions can be easily called from multiple places through multiple
functions; but changing a data structure often requires change in all cases in which the data is accessed. This is why
routing access to a mutable data property can be routed through a function (like an accessor / getter function) allows
for easier refactoring in the future.</p>
<p>The next step to this would be to remove setting methods to replace them by enforcing settings on initialisation, making
the configuration of a class immutable. If that initialisation becomes more and more complex a factory function can help
to organise the initialisation of classes in a readable and flexible way.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Even some patterns like Builder pattern can help here to collect the information needed to initialise a function in
multiple places.</span>
</div>

<h4 id="separate-query-from-modifier" class="relative group">Separate Query from Modifier <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#separate-query-from-modifier" aria-label="Anchor">#</a></span></h4><p>The differentiation between functions with and without side effects - Commands and Query Separation.
A common pattern is that functions that return a value should not have side effects (queries).</p>
<h3 id="divergent-change" class="relative group">Divergent Change <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#divergent-change" aria-label="Anchor">#</a></span></h3><p>Divergent Change happens if a module is touched for many reasons. If a class or function has too many responsibilities,
it needs changes often and becomes harder to understand as it touches multiple contexts. The goal here is straight
forward to sort the different contexts into different places in a way that allows the developer to ignore the rest when
changing just one context.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">A nice way of identifying a file that suffers from this code smell can be a combination of Cyclomatic Complexity and
change frequency. Spots of high complexity and frequent change often indicate that a nicer abstraction / partition is
needed.</span>
</div>

<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Literal</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">divergent_monster</span><span class="p">(</span><span class="n">phase</span><span class="o">=</span><span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;Protocell&#34;</span><span class="p">,</span> <span class="s2">&#34;Prokaryote&#34;</span><span class="p">,</span> <span class="s2">&#34;Eukaryote&#34;</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">membrane</span> <span class="o">=</span> <span class="n">get_membrane</span><span class="p">(</span><span class="n">phase</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">core</span> <span class="o">=</span> <span class="n">get_cell_core</span><span class="p">(</span><span class="n">phase</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">extra</span> <span class="o">=</span> <span class="n">get_mitochondrion</span><span class="p">(</span><span class="n">phase</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">monster</span> <span class="o">=</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&#34;       </span><span class="si">{</span><span class="n">membrane</span><span class="si">}{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">  </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;     </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">       </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;  </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">            </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">                 </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">     </span><span class="si">{</span><span class="n">core</span><span class="si">}{</span><span class="n">core</span><span class="si">}{</span><span class="n">core</span><span class="si">}</span><span class="s2">             </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">    </span><span class="si">{</span><span class="n">core</span><span class="si">}</span><span class="s2">  </span><span class="si">{</span><span class="n">core</span><span class="si">}{</span><span class="n">core</span><span class="si">}</span><span class="s2">       </span><span class="si">{</span><span class="n">extra</span><span class="si">}</span><span class="s2">    </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">     </span><span class="si">{</span><span class="n">core</span><span class="si">}{</span><span class="n">core</span><span class="si">}{</span><span class="n">core</span><span class="si">}</span><span class="s2">                </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">                       </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34; </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">       </span><span class="si">{</span><span class="n">extra</span><span class="si">}</span><span class="s2">      </span><span class="si">{</span><span class="n">extra</span><span class="si">}</span><span class="s2">    </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;    </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">             </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;     </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="s2">      </span><span class="si">{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">               <span class="sa">f</span><span class="s2">&#34;       </span><span class="si">{</span><span class="n">membrane</span><span class="si">}{</span><span class="n">membrane</span><span class="si">}{</span><span class="n">membrane</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">monster</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_membrane</span><span class="p">(</span><span class="n">phase</span><span class="o">=</span><span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;Protocell&#34;</span><span class="p">,</span> <span class="s2">&#34;Prokaryote&#34;</span><span class="p">,</span> <span class="s2">&#34;Eukaryote&#34;</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">match</span> <span class="n">phase</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="s2">&#34;Protocell&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="s2">&#34;  &#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="s2">&#34;||&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_cell_core</span><span class="p">(</span><span class="n">phase</span><span class="o">=</span><span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;Protocell&#34;</span><span class="p">,</span> <span class="s2">&#34;Prokaryote&#34;</span><span class="p">,</span> <span class="s2">&#34;Eukaryote&#34;</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">match</span> <span class="n">phase</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="s2">&#34;Eukaryote&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="s2">&#34;▒&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_mitochondrion</span><span class="p">(</span><span class="n">phase</span><span class="o">=</span><span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;Protocell&#34;</span><span class="p">,</span> <span class="s2">&#34;Prokaryote&#34;</span><span class="p">,</span> <span class="s2">&#34;Eukaryote&#34;</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">match</span> <span class="n">phase</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="s2">&#34;Prokaryote&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="s2">&#34;⬤&#34;</span>
</span></span></code></pre></div><h4 id="split-phase" class="relative group">Split Phase <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#split-phase" aria-label="Anchor">#</a></span></h4><p>If a function or class models a process or sequence of steps, those steps can be separated into different phases. This
can if the steps in question happen by business logic and are called in an order, the phases are needed for technical
reasons like a compiler requiring parsing as a separate step. The first step in this direction would be <a href="#extract-a-function">extracting a
function per phase</a>.</p>
<h4 id="reorganise-or-move" class="relative group">Reorganise or Move <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#reorganise-or-move" aria-label="Anchor">#</a></span></h4><p>To separate different context not only programmatically but also visibly they can be moved into different modules,
files, classes. This can be valid for moving fields, functions, classes. This should leave only the relevant code in the
view of the developer or the functions that call it, but also gather all needed code in one place.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>This reminds to the clean-up rules of &ldquo;Family, Friends, Coworkers&rdquo; for physical objects. A beany hat might be placed
with its family of other beany hats, with its friends of all sorts of head covers, or with its coworkers the set of
gloves, shoes, jacket that are currently the daily things needed to go outside.</p>
<p>A function making a database query might live with its family in a query builder for a specific model, or with its
friends in a repository next to queries that might also call other models, directly in business code.</p>
</span>
</div>

<h4 id="extract-class" class="relative group">Extract Class <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#extract-class" aria-label="Anchor">#</a></span></h4><p>Similar to extracting functions, a class might often be too big to be understood. Indicators of where to split a class
are sets of functions that rely on the same set of properties or data, sets of function that are always called together,
or sets of function that are called for subtypes of the class.</p>
<h3 id="shotgun-surgery-or-feature-envy" class="relative group">Shotgun Surgery or Feature Envy <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#shotgun-surgery-or-feature-envy" aria-label="Anchor">#</a></span></h3><p>This smell is the opposite of the <a href="#divergent-change">Divergent Change</a>, it is code that if you want to make one change
to, you have to go to many places to do that change. When those changes are scattered over multiple files and classes,
it is time costly to find and easy to miss one of them. Sometimes <a href="#reorganise-or-move">reorganisation</a> is not straight
forward to do.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">shotgun_monster</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Todo: Customer requested that the cat should have whiskers
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ears</span> <span class="o">=</span> <span class="s2">&#34; /\_/\ </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">face</span> <span class="o">=</span> <span class="s2">&#34;( o.o )</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">legs</span> <span class="o">=</span> <span class="s2">&#34;(n   n)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">name</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&#34;a&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">ears</span> <span class="o">=</span> <span class="s2">&#34; /\_/@ </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="s2">&#34;Sir &#34;</span> <span class="ow">in</span> <span class="n">name</span> <span class="ow">or</span> <span class="s2">&#34;Lady &#34;</span> <span class="ow">in</span> <span class="n">name</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">face</span> <span class="o">=</span> <span class="s2">&#34;( δ.δ )</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">legs</span> <span class="o">=</span> <span class="s2">&#34;| || |</span><span class="se">\n</span><span class="s2">(∞   ∞)=======//&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;Big&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">face</span> <span class="o">=</span> <span class="s2">&#34;(  o.o  )</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">legs</span> <span class="o">=</span> <span class="s2">&#34;( Ω   Ω )&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ears</span> <span class="o">+</span> <span class="n">face</span> <span class="o">+</span> <span class="n">legs</span>
</span></span></code></pre></div><h4 id="combine-functions-into-transform" class="relative group">Combine Functions into Transform <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#combine-functions-into-transform" aria-label="Anchor">#</a></span></h4><p>The goal of this refactoring is to identify if multiple derived properties of a data instance are used and requested in
multiple spots in the code. A single function or class is introduced to calculate all derive properties and hold them in
one object to be used throughout the code. This makes it easier to track how different derived properties affect the
data flow in the code and makes it easy to add features.</p>
<p>In a extreme form, this can lead to
the <a href="#combine-functions-into-class">combination of all the functions into one new class</a>.</p>
<h4 id="inline-function-variable-or-inline-class" class="relative group">Inline Function, Variable, or Inline Class <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#inline-function-variable-or-inline-class" aria-label="Anchor">#</a></span></h4><p>This is the opposite of extracting a function or class - copying the the body to all occurrences in which the function
would be called. This can sometimes help to restructure the class or function design completely and can free one from
the past refactoring decisions made.</p>
<h3 id="feature-envy" class="relative group">Feature Envy <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#feature-envy" aria-label="Anchor">#</a></span></h3><p>Feature Envy can be a subset of this smell. Programs are usually modularized into parts with high cohesion, minimizing
interaction between code of different zones. If a function spends more time communicating with code in different modules
that can be a code smell and the code should be <a href="#reorganise-or-move">restructured</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">envy_monster</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">bark</span> <span class="o">=</span> <span class="n">get_membrane</span><span class="p">(</span><span class="s2">&#34;Eukaryote&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">leaf</span> <span class="o">=</span> <span class="n">get_mitochondrion</span><span class="p">(</span><span class="s2">&#34;Eukaryote&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&#34;  </span><span class="si">{</span><span class="n">leaf</span><span class="si">}{</span><span class="n">leaf</span><span class="si">}</span><span class="s2">  </span><span class="si">{</span><span class="n">leaf</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">leaf</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">leaf</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">leaf</span><span class="si">}{</span><span class="n">leaf</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;  </span><span class="si">{</span><span class="n">leaf</span><span class="si">}{</span><span class="n">leaf</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">leaf</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;    </span><span class="si">{</span><span class="n">bark</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;    </span><span class="si">{</span><span class="n">bark</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;    </span><span class="si">{</span><span class="n">bark</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="data-clumps" class="relative group">Data Clumps <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#data-clumps" aria-label="Anchor">#</a></span></h3><p>If the same data items show up throughout the code, they might belong together, especially if they only make sense
with all present they should
be <a href="#extract-class">encapsulated into their own class</a> or <a href="#introduce-parameter-object">object</a> to emphasize their
combined meaning.</p>
<h3 id="primitive-obsession" class="relative group">Primitive Obsession <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#primitive-obsession" aria-label="Anchor">#</a></span></h3><p>Primitives are the basic typing foundations provided in programming - integers, floats, strings, booleans in more or
less granulated types are common. Slightly more defined types are welcomed, like dates or currencies. But many
developers seem to avoid creating dataclasses that hold primitives with a meaning like coordinates that come in pairs of
floats between 0 and 360, ranges that imply start is smaller than end, or distance that hold a unit. Such different
types can be <a href="#replace-conditional-with-polymorphism">refactored into Polymorphism</a></p>
<p>For the practice of passing strings around, although custom types seem way more appropriate the term &ldquo;stringly typed&rdquo; is
coined.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">primitive_monster</span><span class="p">(</span><span class="n">length</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="n">length</span> <span class="o">&gt;</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="n">length</span> <span class="o">&lt;=</span> <span class="mi">255</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="n">length</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="s2">&#34; )  (</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;( &#39;_&#39;)</span><span class="si">{</span><span class="s1">&#39;} &#39;</span> <span class="o">*</span> <span class="n">length</span><span class="si">}</span><span class="s2"> </span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;      </span><span class="si">{</span><span class="s1">&#39;^ &#39;</span> <span class="o">*</span> <span class="n">length</span><span class="si">}</span><span class="s2"> </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="replace-primitive-with-object" class="relative group">Replace Primitive with Object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#replace-primitive-with-object" aria-label="Anchor">#</a></span></h4><p>Packing a primitive into an object provides a single point of validation, data extraction, and defines the value.
Objects can answer the questions about the data like &ldquo;is this <code>amount</code> in cent or euro?&rdquo;, &ldquo;Do telephone numbers always
include a country code?&rdquo;, &ldquo;Can this <code>length</code> be negative?&rdquo;. Such objects also provide space for comparing or
calculating. This is strongly tied, but not limited to <a href="#introduce-parameter-object">Parameter Objects</a></p>
<h3 id="speculative-generality" class="relative group">Speculative Generality <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#speculative-generality" aria-label="Anchor">#</a></span></h3><p>There are cases in which the code is made more flexible that it really needs to be. Sometimes because a refactoring
aimed for features that never came, sometimes because business mentioned featured that never reached the code but their
preparation did, sometimes a developer is eager to implement a pattern that is too complex for the current code.</p>
<p>Code that is not reachable can be removed. Version control system enable us to just delete code, not just commenting
them out. If removing code enables, then also the unused (or now always
equal) <a href="#change-the-declaration-of-a-function-property-or-variable">function parameters should be removed</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Monster</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">identifier</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">SpeculativeMonster</span><span class="p">(</span><span class="n">Monster</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">identifier</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">&#39;SpeculativeMonster&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">speculative_monster</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nd">@staticmethod</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">speculative_monster</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">   .-----.   
</span></span></span><span class="line"><span class="cl"><span class="s2"> /         \ 
</span></span></span><span class="line"><span class="cl"><span class="s2">|\/(o) (o)\/|
</span></span></span><span class="line"><span class="cl"><span class="s2">|           | 
</span></span></span><span class="line"><span class="cl"><span class="s2"> \         / 
</span></span></span><span class="line"><span class="cl"><span class="s2">   \_____/
</span></span></span><span class="line"><span class="cl"><span class="s2">        &#34;&#34;&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="collapse-hierarchy" class="relative group">Collapse Hierarchy <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#collapse-hierarchy" aria-label="Anchor">#</a></span></h4><p>If a class hierarchy is no longer needed, remove them. Changes to the parent class always affect children - if this
behavior is causing more work than benefits, an interface might provide the same benefits without the strong coupling.
Work step by step and move all functions from the parent to the child in question, and remove the heritage.
Collapse Hierarchy</p>
<h3 id="message-chains-or-middle-mans" class="relative group">Message Chains or Middle Mans <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#message-chains-or-middle-mans" aria-label="Anchor">#</a></span></h3><p>Following the flow of data sometimes reveals a series of getters. Navigating this path of getters means the original
client caller is coupled to each class stepped through. Often this can be simplified by
the <a href="#extract-a-function">extraction of these methods</a> to a place in which multiple clients may access the data.</p>
<p>A special case of this would be a Middle Man, a class that only offers or redirect delegates. Maybe the class had a
reason to exist in the past, or some idea of encapsulation got carried out a bit too much. One first step might be to
<a href="#inline-function-variable-or-inline-class">inline the functions</a> and see if the class is actually bringing benefit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Client</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get_output</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Service</span><span class="p">()</span><span class="o">.</span><span class="n">get_monster</span><span class="p">()</span><span class="o">.</span><span class="n">speculative_monster</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Monster</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">speculative_monster</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">     \ ________
</span></span></span><span class="line"><span class="cl"><span class="s2">      |          \  
</span></span></span><span class="line"><span class="cl"><span class="s2">     /_/~~~~| |\ /9`\__‚  
</span></span></span><span class="line"><span class="cl"><span class="s2">    |b      |b   \/~~~~/
</span></span></span><span class="line"><span class="cl"><span class="s2">            &#34;&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Service</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get_monster</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Monster</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Monster</span><span class="p">()</span>
</span></span></code></pre></div><h4 id="hide-delegate" class="relative group">Hide Delegate <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#hide-delegate" aria-label="Anchor">#</a></span></h4><p>Is some client code calls a method that is defined on an object provided by some service, the client requires knowledge
about the delegate object. This coupling can be removed by adding a function on the service that will call the method of
the delegate and only returns its result, hiding the delegate. Changes made to the delegate do not propagate to the
(or even multiple) client(s), only to the service.</p>
<h4 id="replace-middle-man-by-delegate" class="relative group">Replace Middle Man by Delegate <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#replace-middle-man-by-delegate" aria-label="Anchor">#</a></span></h4><p>If I hide a delegate too often, this can also cause a lot of code that is hard to maintain, especially the class used to
hide the delegate does not provide any other benefit. Then a getter function may be introduced to get the whole object
and all get_delegate_property functions may be replaced by that.</p>
<p>This can applicable as well for Superclasses. If it does not make sense for a subclass to use or overwrite all the
functions of its superclass, it might be that inheritance is too strong of a coupling, and a delegate object instead of
a superclass might be more fitting. Same for the subclass if more axes variations is needed than practical for
inheritance, or is the coupling between subclasses causes problems.</p>
<h3 id="alternative-classes-with-different-interfaces" class="relative group">Alternative classes with different interfaces <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#alternative-classes-with-different-interfaces" aria-label="Anchor">#</a></span></h3><p>One of the best benefits of classes are the option to substitute classes. Matching interfaces (so matching function
declarations) allow substitution in the long term and helps to find patterns in the current code.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">How I miss Dependency Injection with different classes 🥲 But honestly I did not really cross a two classes that itched
to follow the same interface when that was not intended from the very beginning.</span>
</div>

<h3 id="comments" class="relative group">Comments <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#comments" aria-label="Anchor">#</a></span></h3><p>If you need a comment to explain what the code does it either has
a <a href="#mysterious-name">bad name</a>, <a href="#extract-a-function">can be a function</a>, or should
be <a href="#replace-primitive-with-object">encapsulated and validated by a dataclass</a>.</p>
<p>Comments may be helpful to explain business decisions (&ldquo;This contradicts industry standard, but we decided to accept the
message anyway&rdquo;), historical learnings (&ldquo;Cannot be deleted to maintain backwards compatibility&rdquo;), or explain
uncertainty (&ldquo;Checking data consistency because imported data might be inconsistent here&rdquo;).</p>
<h1 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h1><p>The book provides a nice overview over code smells and how to fix them. It was quite fun to explore the code smells,
think about how to display them in code, and also keeping an eye on my work code base spotting both code smells and nice
refactorings.</p>
<p>Besides all the hard skill learnings, the idea of refactoring line by line, with passing tests, always ensuring no
external behavior is changed is the most enlightening skill I took from this book. It is a challenge, and I am not
saying that I will never again look at smelly code and just creating a new file rewriting it from scratch, I now know I
always have the option to only change it in a save and sane way, bit by bit (and might request the same for code I
review).</p>
<p>Happy Coding :)</p>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/><category scheme="taxonomy:Tags" term="book" label="Book"/></entry><entry><title type="html">Is it my Imposter Syndrome or is it our Team Culture?</title><link href="https://philodev.one/posts/2026-01-imposter-syndrom/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-07-writing-documentation/?utm_source=atom_feed" rel="related" type="text/html" title="Writing useful Documentation"/><link href="https://philodev.one/posts/2024-05-agile-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="Agile Software Architecture"/><link href="https://philodev.one/posts/2023-11-using-data-to-ignite-action/?utm_source=atom_feed" rel="related" type="text/html" title="Using data for Sprint Planning"/><link href="https://philodev.one/posts/2023-04-communicating-between-teams/?utm_source=atom_feed" rel="related" type="text/html" title="Communication between different teams working on the same codebase"/><link href="https://philodev.one/posts/2022-09-sprint-retro/?utm_source=atom_feed" rel="related" type="text/html" title="Improving Retros from a Devs Perspective"/><id>https://philodev.one/posts/2026-01-imposter-syndrom/</id><published>2026-01-29T10:20:44+02:00</published><updated>2026-01-29T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Is Imposter Syndrome an individual problem or a team culture issue? How can team dynamics influence feelings of inadequacy among developers?</blockquote><div class="lead !mb-9 text-xl">
  Is Imposter Syndrome an individual problem or a team culture issue? How can team dynamics influence
feelings of inadequacy among developers?
</div>

<h2 id="from-individual-problem-to-team-culture-issue" class="relative group">From Individual Problem to Team Culture Issue <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#from-individual-problem-to-team-culture-issue" aria-label="Anchor">#</a></span></h2><blockquote>
<p>The term [Imposter Syndrom] pathologizes the insecurities regarding ones capabilities [&hellip;] to a mental illness to be
cured, not as a reaction to a lack of recognition, missing role models, absence of promotion opportunities,
discrimination in the workplace.</p>
</blockquote>
<p>Sophia Fritz, Toxische Weiblichkeit (Toxic Femininity), my translation</p>
<p>Reading this changed my perspective on Imposter Syndrome, moved it from something that everyone has to deal
with on their own, to something that is influenced by the team culture and environment.
Changing team culture will not solve systemic issues, nor will it prevent any feeling of insecurity.
The point is that it is not just a personal task to build confidence, but a shared team responsibility to create an
environment where every team member feels recognised, authentic, and competent.</p>
<h2 id="looking-into-scientific-literature" class="relative group">Looking into Scientific Literature <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#looking-into-scientific-literature" aria-label="Anchor">#</a></span></h2><p>Following the Hierarchy of Evidence, I looked for Meta-Studies and Systematic Reviews on the topic of Imposter
Syndrome. I would recommend &ldquo;Workplace Imposter Thoughts, Imposter Feelings, and Impostorism&rdquo;<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>; other papers
focused only on the pathology of Imposter Syndrome in individuals <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, or did not as dive deep into the
comparison of results of multiple studies<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<p>One very interesting paper is the first paper that coined the term &ldquo;Imposter (Phenomenon)&rdquo; a 1978 Paper from two
Psychologists &ldquo;The Imposter Phenomenon in High Achieving Women&rdquo; <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> which observed and named the feeling
based on observations of high achieving woman during a time in which woman where quite new in (academic) careers.</p>
<h3 id="history-definition-and-symptoms" class="relative group">History, Definition, and Symptoms <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#history-definition-and-symptoms" aria-label="Anchor">#</a></span></h3><p>&ldquo;Imposter Syndrome&rdquo; is a very modern term, that got more popular since around 2015.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">I am kinda sad that the connection my mind made to the 2018 Game &ldquo;Among Us&rdquo; is completely wrong.</span>
</div>

<p>Throughout the years the term is defined by the cognitive belief that others overestimate one’s competence at work.
But it also includes feeling of intellectual incompetence, concerns about being exposed as a fraud, or feeling
unauthentic.
There are multiple hypotheses about the cause of Imposter Syndrome<sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>:</p>
<ul>
<li>Perfectionism and Fear of Failure: Perfectionism, especially socially defined perfectionism makes individuals highly
sensitive to perceived failures. This can cause a black-and-white thinking of anything that is not a perfect success
must be a failure.</li>
<li>Social Comparison Theory: People define their own worth based on how they compare to others, Imposter feelings are a
result of comparing one with high-achieving peers - even if the comparison is biased like comparing new joiners with
long term employees.</li>
<li>Cognitive Dissonance Theory: If people have the belief that they are not competent, any success will create a
dissonance that is resolved by downplaying the success or attributing it to external factors.</li>
</ul>
<p>Imposter Syndrome is linked to lowered job satisfaction, higher stress levels, even depression and burnout. Although,
some studies found the imposter phenomenon was a critical driver of work productivity of management consultants or
working hours of students.<sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">While the paper is multiple times cited for showing the benefits of Imposter feelings on productivity, I want to point
out that the upsides mainly benefit the organization - while many of the negative impacts are on the expense of the
individual.</span>
</div>

<h3 id="trait-or-state" class="relative group">Trait or State? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#trait-or-state" aria-label="Anchor">#</a></span></h3><p>There are studies that link Imposter Syndrome to situational factors - starting a new role that differs from
experiences, working after career breaks, or as a result of competitions.</p>
<p>Still, Imposter Syndrome is often described as a personality trait, focusing on correlations with low self-esteem,
neuroticism, and perfectionism. Multiple studies found higher prevalence among woman and other marginalized groups.
Not all studies find such correlations though, especially when comparing people within the same role (the surveyed roles
were leadership roles or surgeons); while students and post-graduates showed the highest gender disparity<sup id="fnref2:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>The connection of Imposter Syndrome to marginalized groups is tricky. Some symptoms of Imposter Syndrome like lack of
belonging or doubt in own skills are often central obstacles marginalized groups face in their careers.</p>
<p>Imposter feelings are also associated with lower career striving, (perceived) higher stress, underestimation of own
skills, and lower job satisfaction - which could lead to less representation of marginalized groups in senior roles,
leaving a bias in studies focusing on such roles. The origin of this can both be because people with imposter syndrome
might not apply for such roles or people who do not advance in their careers are more prone to develop imposter
feelings.</p>
<p>In my opinion, papers linking Imposter Syndrome to marginalized groups to argue that Imposter syndrome is a trait of
individuals in such groups, are underestimating the complexity of causal relationship; ignoring the
question if imposter syndrome might be a symptom (or even a driver?) of career inequalities in marginalized groups.</p>
</span>
</div>

<p>To conclude, the beliefs that feed Imposter Syndrome can come both from individuals themselves or the situations they
are in. In either cases, it is not a trait that someone has throughout their life or never at all - but a state that can
change over time and with context, and for which some people might be more susceptible.</p>
<h2 id="team-culture-patterns-and-anti-patterns-to-reduce-imposter-feelings" class="relative group">Team Culture Patterns and Anti-Patterns to reduce Imposter Feelings <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#team-culture-patterns-and-anti-patterns-to-reduce-imposter-feelings" aria-label="Anchor">#</a></span></h2><p>During my research I learned that there are different types of psychotherapy. Depth psychology focuses on the
unconscious and experiences to resolve current problems; Cognitive Behavioral Therapy focuses on changing the
current beliefs and behaviors to resolve current problems; and (quite new) Systemic Therapy focuses on the interactions
between people and their environment to resolve current problems.
Systemic Therapy aims to recognize that one cannot change people or systems, and to find creative nudges to which helps
the system to change themselves.</p>
<p>Regardless of the question of Trait vs State, in a team context one can always assume that team culture is easier to
change than personality traits of individuals. Therefore, I want to share some nudges that can help to create a team
culture that reduces feelings of inadequacy and fosters feelings of belonging and competence.</p>
<h3 id="a-feeling-of-belonging" class="relative group">A feeling of belonging <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#a-feeling-of-belonging" aria-label="Anchor">#</a></span></h3><p><strong>Celebrate Learning new Things in a Safe Environment</strong> Social rules that are stated explicitly and are valued by the
whole team are a basis for creating a safe environment. A good example are the Social Rules of the Recurse
Center <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<ul>
<li>&ldquo;No feigning surprise&rdquo; - don&rsquo;t act surprised when someone does not know something</li>
<li>&ldquo;No well actually&rsquo;s&rdquo; - don&rsquo;t correct someone if the correction does not benefit the conversation</li>
<li>&ldquo;No Backseat Driving&rdquo; - don&rsquo;t give unsolicited advice on how to solve a problem you are not working on</li>
<li>&ldquo;No Subtle -isms&rdquo; - no sexism, racism, ableism, ageism, or any other -ism that can make people feel excluded</li>
</ul>
<p><strong>Anticipate New Joiners</strong> &ldquo;You are here because we want you to be here and believe in you!&rdquo;
This feeling that is easier for teams to spread that have the autonomy to select new members, but still
possible in more hierarchical structures. Something I mostly observed for new joiners, who are well known within a
community, but a habit that I would wish every new joiner:
In the first days showing excitement about the new team member joining, show interested in past projects, skills, and
experiences. Maybe the manager already provided some information, a blog, a past project,
or open source contributions. This helps to create a feeling of being wanted and welcomed for the skills and
experiences.</p>
<p><strong>Show a Shared Vision</strong> Belonging to a team means working on a shared goal. A critical part of that is also to be able
to connect the current tasks to the big picture. There will be &ldquo;high impact&rdquo; tasks that are directly contributing, and
they should be shared in the team. On the other hand, the &ldquo;low impact&rdquo; tasks require a context to connect them to the
vision.</p>
<p><strong>Have a Diverse Team and Diverse Leaders</strong>. Missing representation can lead to feelings of not belonging. If there is
no one that resembles your background / culture / gender in the hierarchy above you, it is harder to believe that you
can also reach such a position. Diverse teams also help to create an environment where different perspectives are
valued, and different communication and working styles are accepted.<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<p><strong>Asking for Help is Normalized</strong> Asking for pairing should not just be done by the team members who are looking for
guidance - but also by team members who want to share knowledge. It does not require a &ldquo;I need some help here&rdquo;, it can
be &ldquo;Is someone up for discussions on the technical approach?&rdquo; or &ldquo;Would be great to share knowledge about this domain&rdquo;.
Any habit that is only perceived from juniors or new joiners will create a hesitation to pursue such habit - this can be
asking for help, seeking validation, or admitting mistakes. <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></p>
<h3 id="make-it-easy-to-achieve" class="relative group">Make it easy to Achieve <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#make-it-easy-to-achieve" aria-label="Anchor">#</a></span></h3><p><strong>Enable Achievements Outside of Code</strong> Software Development is more than coding - Shadowing Users, Writing
documentation, improving processes, code reviews, sharing knowledge &hellip; Such tasks should be recognized as valuable
contributions to the team vision, should be mentioned, should be celebrated.</p>
<p><strong>Let Ticket Refinements Happen in the Team</strong> A refinement can be a safe space to ask questions, clarify the business
need behind the ticket, and discuss possible implementations. This can easily change the perspective from a ticket that
sounds &ldquo;too complex or to hard for me&rdquo; to a ticket for which &ldquo;I know the solution and the pitfalls to avoid&rdquo;. It is
easier to pick up such a refined ticket, easier to start working without big code investigation, it instantly provides a
feeling of competence for the task.</p>
<p><strong>There Should be Easy Tickets</strong> An easy ticket should include all necessary information, enable one immediately to
start coding, and be achievable in less than a day. This is important for new joiners, as distraction from highly
complex tasks, or on dull afternoons.
Never will all tickets be easy - but there should always be some easy tickets available to pick from.</p>
<p><strong>Tickets Should Have a Definition of Done.</strong> Having to go over and over a task because the result is unclear or
requires multiple feedback loops is a common source of frustration and self-doubt. Why didn&rsquo;t I got it right the first
time? Why don&rsquo;t I understand what is expected from me? A clear definition of done helps to avoid such situations and
also helps to estimate ones resources required to finish the task.</p>
<h3 id="have-a-culture-of-recognition---not-competition" class="relative group">Have a Culture of Recognition - not Competition <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#have-a-culture-of-recognition---not-competition" aria-label="Anchor">#</a></span></h3><p><strong>Love Power Sharing - Hate Power Trips</strong> In this context &ldquo;Power&rdquo; does not mean &ldquo;authority&rdquo;, Power means having a
privilege another person is lacking - not having Imposter feelings, knowing the codebase well, not being part of a
marginalized group&hellip;
A team member that calls out the achievements of others, shows vulnerability, shares knowledge altruistically, is open
for cooperation / pairing shares power<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>.</p>
<p><strong>Post only Team Metrics - Never Individual Metrics</strong> Any metric that compares the performance of individuals will be
exploited by team members who are driven by competition and will foster a feeling of inadequacy in those who are not.
No metric will adequately reflect productivity. It cannot capture learning curves, mentoring efforts, or
the contributions in discussions, documentations, mentoring, code reviews, or team culture.
AFrom looking up &ldquo;the number of PRs per month for each team member&rdquo; to weekly postings of &ldquo;who closed the most
tickets&rdquo; - any of those metrics should be handed with care.</p>
<p><strong>Everyone Should be Part of Celebration</strong> Celebrating team successes helps to create a feeling of belonging and
achievement - but only if everyone is included. Meaning, on that celebration slide every team member should find
at least one point they connect to their contributions. This does not mean that everyone has to be named (I personally
would even discourage that), but that everyone can find their part in the success story.</p>
<p><strong>Mentoring</strong> Mentors or Buddies can provide constant guidance and affirmation. They can help to navigate the new
environment, provide technical guidance, and be a safe space to discuss insecurities. <sup id="fnref2:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> They can
ask coaching questions to help overcome self-doubt and imposter feelings.</p>
<h2 id="personal-strategies" class="relative group">Personal Strategies <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#personal-strategies" aria-label="Anchor">#</a></span></h2><p>There are also personal strategies to deal with Imposter feelings. While the papers showed the success of Cognitive
Behavioral Therapy, that is a very personal decision to pursue, and nothing I have any qualification to comment on.</p>
<p>I want to provide some questions and reflections that can help to better understand ones own feelings</p>
<ul>
<li><strong>Observe</strong> When do I have feelings of Incompetence? Are there specific situations that trigger these feelings? When
am I not feeling this way? What do I feel when achieving something, and what if I fail?</li>
<li><strong>Question Believes</strong>  Was there ever a person stating that I lack a skill or trait, or is it my interpretation of the
situation? If the latter, which situations trigger this thought? What beliefs do I have about my own competence? If I
allow Myself to be curious about these beliefs, where do they come from?</li>
<li><strong>Investigate Alternatives</strong> How do I define Success and Competence? Do I like my definition? Are there other team
members struggling with similar issues? Can I talk to them about it?</li>
<li><strong>What can Help?</strong> What does help I with these feelings? How can I ground Myself in moments of insecurity, and remind
Myself of my skills and achievements? Can I do a training that helps me to get more confident in the skill I feel
lacking?</li>
</ul>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Imposter Syndrome was and is a companion in my career, but it&rsquo;s strength and impact is
highly influenced by the team culture I am in.
I worked at companies where I did felt valuable and competent after a few days, others in which I was struggling with
feelings of inadequacy for months. I worked in teams where a belonging and communication was a high priority, and other
where it wasn&rsquo;t. I had managers who emphasized my growth and opportunities, and others who only cared about results and
numbers of whatever metric they valued.</p>
<p>I am striving to create a culture in my team in which Imposter Feelings are acknowledged and quickly replaced by
feelings of belonging and value.</p>
<p>Happy <del>Coding</del> Communicating :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Workplace Impostor Thoughts, Impostor Feelings, and Impostorism: An Integrative, Multidisciplinary Review of
Research on the Impostor Phenomenon by Basima Tewfik, Jeremy Yip, Sean Martin.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Impostor phenomenon: a narrative review of manifestations, diagnosis, and treatment by Abdullah Al Lawati,
Nouf Al Rawahi, Tahlil Waladwadi, Reem Almadailwi and more&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Imposter Syndrome in Academic and Professional Contexts: A Systematic Review of Prevalence,
Psychological Impact, Cultural Influences, and Intervention Strategies by Sonali Panda, Dr. Megha Das&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>The Imposter Phenomenon in High Achieving Women: Dynamics and Therapeutic Intervention Pauline Rose
Clance &amp; Suzanne Imes&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://www.recurse.com/social-rules" target="_blank" rel="noreferrer">Social Rules of the Recurse Center</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://www.forbes.com/sites/forbeshumanresourcescouncil/2021/08/25/the-role-of-representation-in-combating-imposter-syndrome/" target="_blank" rel="noreferrer">Imposter Syndrome Isn&rsquo;t A Confidence
Problem</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://www.impostersyndrome.ie/blog/how-workplace-culture-fuels-imposter-syndrome-and-how-to-fix-it/" target="_blank" rel="noreferrer">How Workplace Culture Fuels Imposter
Syndrome</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>On the 39C3 the phrase &ldquo;Love Power sharing - Hate Power Trips&rdquo; was used on multiple occasions to describe how
to create inclusive environments in and outside the hacker community.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="agile" label="Agile"/><category scheme="taxonomy:Tags" term="developer-life" label="Developer Life"/></entry><entry><title type="html">Registry Patterns in Python</title><link href="https://philodev.one/posts/2025-12-python-registry/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2025-06-bitemporal-data/?utm_source=atom_feed" rel="related" type="text/html" title="Bitemporal Data: Timetravel your Data"/><link href="https://philodev.one/posts/2025-05-python-meta-programming/?utm_source=atom_feed" rel="related" type="text/html" title="Meta Programming in Python"/><link href="https://philodev.one/posts/2025-04-from-php-to-python/?utm_source=atom_feed" rel="related" type="text/html" title="Learning a new language - from PHP to Python"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><id>https://philodev.one/posts/2025-12-python-registry/</id><published>2025-12-14T10:20:44+02:00</published><updated>2025-12-14T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Discovering Patterns for one Problem - Different requests reach the system, and based on the properties of each request a different implementation should handle the request</blockquote><div class="lead !mb-9 text-xl">
  <strong>The Problem</strong>: Different requests reach the system, and based on the properties of each request a different
implementation should handle the request. Many patterns exist to solve this problem, each with its pros and cons. This
post explores some off then, while in between diving deep into Python&rsquo;s import system.
</div>

<h2 id="registry-by-factory" class="relative group">Registry by Factory <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#registry-by-factory" aria-label="Anchor">#</a></span></h2><p>The most straightforward solution is to use a Factory that returns the appropriate implementation based on the request.
Often this is the best solution, especially if there are only a few implementations to choose from, if the selection
logic is not based on one property but on complex business rules, or it is unlikely that new implementations will be
added in the future.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Collie</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Husky</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Labrador</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DogFactory</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get_dog_for</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Collie</span> <span class="o">|</span> <span class="n">Husky</span> <span class="o">|</span> <span class="n">Labrador</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">match</span> <span class="n">request_type</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">case</span> <span class="s2">&#34;Pulling&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">Husky</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="k">case</span> <span class="s2">&#34;Herding&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">Collie</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="k">case</span> <span class="s2">&#34;Service Dog&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">Labrador</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">Labrador</span><span class="p">()</span>
</span></span></code></pre></div><p>The implementation is straightforward and easy to understand - no magic involved. Whenever a new implementation is
needed, the Factory needs to be modified, violating the Open/Closed Principle.</p>
<h3 id="testing-the-factory" class="relative group">Testing the Factory <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#testing-the-factory" aria-label="Anchor">#</a></span></h3><p>The most simple test is to check that the Factory returns the expected implementation for a given request.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_dog_factory</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">DogFactory</span><span class="p">()</span><span class="o">.</span><span class="n">get_dog_for</span><span class="p">(</span><span class="s2">&#34;Pulling&#34;</span><span class="p">),</span> <span class="n">Husky</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">DogFactory</span><span class="p">()</span><span class="o">.</span><span class="n">get_dog_for</span><span class="p">(</span><span class="s2">&#34;Herding&#34;</span><span class="p">),</span> <span class="n">Collie</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">DogFactory</span><span class="p">()</span><span class="o">.</span><span class="n">get_dog_for</span><span class="p">(</span><span class="s2">&#34;Service Dog&#34;</span><span class="p">),</span> <span class="n">Labrador</span><span class="p">)</span>
</span></span></code></pre></div><p>The Factory can not be tested in an abstract way, it is barely possible to write a test that ensures that every
implementation is reachable, or that a new implementation will be added to the factory without re-implementing the
selection logic of the Factory in the test.</p>
<h2 id="registry-by-config-file-or-list" class="relative group">Registry by config file or list <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#registry-by-config-file-or-list" aria-label="Anchor">#</a></span></h2><p>Applying the Open/Closed Principle leads to the next simplest solution: A configuration file or list that contains the
mapping. In its simplest form, this can be a dictionary in Python code, but especially in use cases in which different
environments require different mappings, an external configuration file (YAML, JSON, etc.) is a good tool.
Even further goes the idea of a database table that contains the mapping, which can be changed at runtime without a new
deployment, is nice to test, but requires seeding / other solution for local development.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">BaseDog</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Collie</span><span class="p">(</span><span class="n">BaseDog</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Husky</span><span class="p">(</span><span class="n">BaseDog</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Labrador</span><span class="p">(</span><span class="n">BaseDog</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">DOG_CONFIG</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">type</span><span class="p">[</span><span class="n">BaseDog</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Pulling&#34;</span><span class="p">:</span> <span class="n">Husky</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Herding&#34;</span><span class="p">:</span> <span class="n">Collie</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Service Dog&#34;</span><span class="p">:</span> <span class="n">Labrador</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DogRegistry</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get_dog_for</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">BaseDog</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">found</span> <span class="o">=</span> <span class="n">DOG_CONFIG</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">request_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">found</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">Labrador</span><span class="p">()</span>
</span></span></code></pre></div><p>This solution is still straightforward and easy to understand. The selection logic is now separated from the mapping,
new implementations can be added without modifying the code.</p>
<p>A pattern that I personally find &ldquo;topologically equal&rdquo; is a having a function that registers all handlers in a
dictionary <code>handler_registry.register(&quot;Pulling&quot;, Husky)</code> individually. That is verbose, and allows programmatic &quot;
un-register&quot;<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. The post also discovers very similar patterns. Mind that in that blog post mentioned
solution of importing and looping through all subclasses causes the similar import-based problems, as a missing Handler
in an init file will cause the Handler to remain undiscovered.</p>
<h3 id="testing-the-config-registry--test-to-ensure-a-new-implementation-is-listed-in-the-config" class="relative group">Testing the Config Registry / Test to ensure a new implementation is listed in the config <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#testing-the-config-registry--test-to-ensure-a-new-implementation-is-listed-in-the-config" aria-label="Anchor">#</a></span></h3><p>Tests can be separated into testing the selection logic and testing the configuration. Also, tests
that ensure that every implementation is reachable and that a new configuration is added correctly are possible.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">magic_registry</span> <span class="kn">import</span> <span class="n">magic</span>  <span class="c1"># example function at the end of this post</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">config</span> <span class="kn">import</span> <span class="n">registry</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">config</span> <span class="kn">import</span> <span class="n">dogs</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_config_returns_husky</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">DogRegistry</span><span class="p">()</span><span class="o">.</span><span class="n">get_dog_for</span><span class="p">(</span><span class="s2">&#34;Pulling&#34;</span><span class="p">),</span> <span class="n">dogs</span><span class="o">.</span><span class="n">Husky</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_config_is_complete</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34; Test to ensure that all BaseDog implementations are registered in the DOG_CONFIG &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">all_dogs_registered</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">DOG_CONFIG</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">    <span class="kn">import</span> <span class="nn">config</span> <span class="k">as</span> <span class="nn">module</span>
</span></span><span class="line"><span class="cl">    <span class="n">all_dogs_in_module</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">magic</span><span class="o">.</span><span class="n">autodiscover</span><span class="p">(</span><span class="n">in_module</span><span class="o">=</span><span class="n">module</span><span class="p">,</span> <span class="n">of_subclass</span><span class="o">=</span><span class="n">dogs</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="n">all_dogs_registered</span> <span class="o">==</span> <span class="n">all_dogs_in_module</span>
</span></span></code></pre></div><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>If there is magic involved to test the completeness of the configuration, why not use magic to register the
implementations? One obvious answer to this would be, that magic in tests is far easier to maintain than magic in
business code. If the test gets too hard to debug, it can be re-written, if the test causes more headaches than it
saves devs from forgetting to add new implementations to the config, it can just be removed.</p>
<p>It is a question of dev-user friendliness, and depends on the registry use case.</p>
</span>
</div>

<h2 id="registry-by-init_" class="relative group">Registry by <em><strong>init_subclass</strong></em> <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#registry-by-init_" aria-label="Anchor">#</a></span></h2><p>Looking at the Python features, there is a built-in hook method called <code>__init_subclass__</code> that is invoked whenever a
subclass is <del>defined</del> imported. The corresponding PEP even provides an example of a registry
pattern <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. Based on this, there is a <code>BaseDog</code> base class that registers every subclass to a
dictionary, and the <code>DogRegister</code> using that to return the appropriate implementation.</p>
<p>By this solution, it is fair to assume that there will be a directory, which contains all implementations, like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Project/
</span></span><span class="line"><span class="cl">├─ init_registry/
</span></span><span class="line"><span class="cl">│  ├─ __init__.py
</span></span><span class="line"><span class="cl">│  ├─ dogs/
</span></span><span class="line"><span class="cl">│  │  ├─ __init__.py
</span></span><span class="line"><span class="cl">│  │  ├─ husky.py
</span></span><span class="line"><span class="cl">│  │  ├─ common.py
</span></span><span class="line"><span class="cl">|  │  └─ corgi.py
</span></span><span class="line"><span class="cl">|  └─ registry.py
</span></span><span class="line"><span class="cl">└─ tests/ 
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1">#  ------------- registry.py ------------- </span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">BaseDog</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">__init_subclass__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">__init_subclass__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">DOG_REGISTRY</span><span class="p">[</span><span class="n">request_type</span><span class="p">]</span> <span class="o">=</span> <span class="bp">cls</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">DOG_REGISTRY</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">BaseDog</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DogRegister</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># import init_subclass.dogs.corgi # Import corgi to register it</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get_dog_for</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">BaseDog</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">found</span> <span class="o">=</span> <span class="n">DOG_REGISTRY</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">request_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">found</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="kn">from</span> <span class="nn">init_subclass</span> <span class="kn">import</span> <span class="n">dogs</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">dogs</span><span class="o">.</span><span class="n">Labrador</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#  ------------- dogs/common.py ------------- </span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">init_subclass</span> <span class="kn">import</span> <span class="n">registry</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Collie</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">,</span> <span class="n">request_type</span><span class="o">=</span><span class="s2">&#34;Herding&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Labrador</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">,</span> <span class="n">request_type</span><span class="o">=</span><span class="s2">&#34;Service Dog&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#  ------------- dogs/husky.py ------------- </span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">init_subclass</span> <span class="kn">import</span> <span class="n">registry</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Husky</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">,</span> <span class="n">request_type</span><span class="o">=</span><span class="s2">&#34;Pulling&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># -------------  dogs/corgi.py ------------- </span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">init_subclass</span> <span class="kn">import</span> <span class="n">registry</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Corgi</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">,</span> <span class="n">request_type</span><span class="o">=</span><span class="s2">&#34;Mascot&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># -------------  dogs/__init__.py ------------- </span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">husky</span><span class="p">,</span> <span class="n">common</span>
</span></span></code></pre></div><p>While the other implementations had the logic in one file, this one requires the developers action to look in the base
class. And then, probably many developers would need to look up what <code>__init_subclass__</code> is doing, as it is not that
commonly used, but considering the very similar example in the PEP, I would consider its readability okay.</p>
<p>😈 Anyway, how long would it take a dev to understand the code is not working and why?</p>
<h3 id="import-based-registry---and-what-can-go-wrong" class="relative group">Import-based Registry - and what can go wrong <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#import-based-registry---and-what-can-go-wrong" aria-label="Anchor">#</a></span></h3><p>Based on the above example, the first test will pass, but the second test will fail:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">init_subclass</span> <span class="kn">import</span> <span class="n">registry</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">init_subclass</span> <span class="kn">import</span> <span class="n">dogs</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_init_subclass_returns_husky</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">DogRegister</span><span class="p">()</span><span class="o">.</span><span class="n">get_dog_for</span><span class="p">(</span><span class="s2">&#34;Pulling&#34;</span><span class="p">),</span> <span class="n">dogs</span><span class="o">.</span><span class="n">husky</span><span class="o">.</span><span class="n">Husky</span><span class="p">)</span>  <span class="c1"># passes</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_init_subclass_will_not_find_secret_corgi</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">DogRegister</span><span class="p">()</span><span class="o">.</span><span class="n">get_dog_for</span><span class="p">(</span><span class="s2">&#34;Mascot&#34;</span><span class="p">),</span> <span class="n">dogs</span><span class="o">.</span><span class="n">common</span><span class="o">.</span><span class="n">Labrador</span><span class="p">)</span>  <span class="c1"># fails</span>
</span></span></code></pre></div><p>The <code>DogRegister().get_dog_for(&quot;Mascot&quot;)</code> should return a <code>corgi.Corgi</code>, but it returns the default
<code>common.Labrador</code>. The reason for that is that the <code>corgi.Corgi</code> class is never imported, and therefore never registered
in the <code>DOG_REGISTRY</code>. Which is especially tricky to test, because if there was a test implemented to test the
<code>corgy.py</code>. It would import the <code>corgi.Corgi</code> class and would also make the above test pass.</p>
<p>Python has one dictionary called <code>sys.modules</code> that contains all imported modules. Looking into that dictionary during a
debugging session shows that only the <code>husky</code> and <code>common</code> modules are imported, but not the <code>corgi</code> module. Importing
the <code>corgi</code> module during the debugging session registers the <code>corgi.Corgi</code> class, and then the test would pass.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Importing sys</span>
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; <span class="o">(</span>Pdb<span class="o">)</span> import sys
</span></span><span class="line"><span class="cl"><span class="c1"># sys.modules is a dict of all imported modules, looking for Husky module</span>
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; <span class="o">(</span>Pdb<span class="o">)</span> sys.modules<span class="o">[</span><span class="s1">&#39;init_subclass.dogs.husky&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">&lt;module <span class="s1">&#39;init_subclass.dogs.husky&#39;</span> from <span class="s1">&#39;/Users/sofia/dev/PythonProject/src/init_subclass/dogs/husky.py&#39;</span>&gt;
</span></span><span class="line"><span class="cl"><span class="c1"># Looking for Corgi module, but failing</span>
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; <span class="o">(</span>Pdb<span class="o">)</span> sys.modules<span class="o">[</span><span class="s1">&#39;init_subclass.dogs.corgi&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">*** KeyError: <span class="s1">&#39;init_subclass.dogs.corgi&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Importing the Corgi module</span>
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; <span class="o">(</span>Pdb<span class="o">)</span> from init_subclass.dogs import corgi
</span></span><span class="line"><span class="cl"><span class="c1"># Now the Corgi module is in sys.modules</span>
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; <span class="o">(</span>Pdb<span class="o">)</span> sys.modules<span class="o">[</span><span class="s1">&#39;init_subclass.dogs.corgi&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">&lt;module <span class="s1">&#39;init_subclass.dogs.corgi&#39;</span> from <span class="s1">&#39;/Users/sofia/dev/PythonProject/src/init_subclass/dogs/corgi.py&#39;</span>&gt;
</span></span><span class="line"><span class="cl"><span class="c1"># And the Corgi module used points to the same via sys.modules</span>
</span></span><span class="line"><span class="cl">&gt;&gt;&gt;<span class="o">(</span>Pdb<span class="o">)</span> dogs.corgi
</span></span><span class="line"><span class="cl">&lt;module <span class="s1">&#39;init_subclass.dogs.corgi&#39;</span> from <span class="s1">&#39;/Users/sofia/dev/PythonProject/src/init_subclass/dogs/corgi.py&#39;</span>&gt;
</span></span></code></pre></div><h3 id="side-quest-understanding-python-imports" class="relative group">Side Quest: Understanding Python imports <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#side-quest-understanding-python-imports" aria-label="Anchor">#</a></span></h3><p>The import statement in python creates a module object, calling its module body, and by this defining a <code>__name__</code> as
the key, and <code>__file__</code> as the file path value in <code>sys.modules</code>. If the module is already in <code>sys.modules</code>, the existing
module object is used instead, which saves time.</p>
<p>The module in which the execution of a python project starts has <code>__main__</code> both as <code>__name__</code> and key in <code>sys.modules</code>.
Modules may check if they are run as <code>__main__</code> by checking <code>if __name__ == &quot;__main__&quot;:</code>. For example Django is doing
that in its <code>manage.py</code> file to set up the project settings and import Django.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>The imported Django module is actually a package. A package is a module that contains other modules, and is identified
by the presence of an <code>__init__.py</code> file in the directory, which is its module body .
When a package is imported, the module body in the <code>__init__.py</code> file will be executed, importing all sub-modules listed
in it. If a sub-module is not listed there, it is not imported.</p>
<p>This also explains why circular imports raise an exception, as the module body execution and the registration in
<code>sys.modules</code> is suspended while waiting for the imports inside the module body to finish. If the first module is
eventually imported inside its own body, the module is not yet in <code>sys.modules</code>, and would start
an infinit loop, if not excepted before. <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>Every module uses a <code>__dict__</code> attribute as its namespace, which is a dictionary-like object that maps its attributes
to their values. Any class or attribute defined in the module body is added to this namespace, which means under the
hood that <code>my_module.my_class</code> is (somewhat) equivalent to <code>my_module.__dict__['my_class']</code>. Therefore, for very
attribute, for example a class defined in the module body, Python creates an object by calling its Metaclass (usually
<code>type.__new__</code>) to create the class object, It calls the <code>__set_name__</code> method, <code>super()</code>, in which <code>__init_subclass__</code>
of the base class is called. The fully initialized class object is then bound to the namespace that the module body is
executed in. <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<p><strong>Manipulating sys.modules</strong> is also possible (maybe not the best solution). In theory, deleting the module from
<code>sys.modules</code> will ensure that the tests of import-based registries work deterministically, even if other tests import
some implementations.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">module_identifier</span> <span class="o">=</span> <span class="s2">&#34;init_subclass.dogs&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">modules_to_delete</span> <span class="o">=</span> <span class="p">[</span><span class="n">name</span> <span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span> <span class="k">if</span> <span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">module_identifier</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">modules_to_delete</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">del</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
</span></span></code></pre></div><h2 id="registry-by-decorator" class="relative group">Registry by decorator <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#registry-by-decorator" aria-label="Anchor">#</a></span></h2><p>Another way to register implementations is to use a decorator. It looks a bit more modern that <code>__init_subclass__</code>, but
it has the same problem: If the module containing the implementation is not imported, the implementation is not
registered, as the decorators are evaluated also on creation of the class type.
I wrote a <a href="https://philodev.one/posts/2025-05-python-meta-programming/">post about decorators</a> before, so I will not go into
detail here.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">register_dog</span><span class="p">(</span><span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">DOG_REGISTRY</span><span class="p">[</span><span class="n">request_type</span><span class="p">]</span> <span class="o">=</span> <span class="bp">cls</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="bp">cls</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">decorator</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">DOG_REGISTRY</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">type</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@register_dog</span><span class="p">(</span><span class="n">request_type</span><span class="o">=</span><span class="s2">&#34;Herding&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Collie</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@register_dog</span><span class="p">(</span><span class="n">request_type</span><span class="o">=</span><span class="s2">&#34;Pulling&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Husky</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@register_dog</span><span class="p">(</span><span class="n">request_type</span><span class="o">=</span><span class="s2">&#34;Service Dog&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Labrador</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DogRegister</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get_dog_for</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Husky</span> <span class="o">|</span> <span class="n">Labrador</span> <span class="o">|</span> <span class="n">Collie</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">found</span> <span class="o">=</span> <span class="n">DOG_REGISTRY</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">request_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">found</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">Labrador</span><span class="p">()</span>
</span></span></code></pre></div><h2 id="registry-by-pkgutiliter_modules" class="relative group">Registry by <code>pkgutil.iter_modules</code> <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#registry-by-pkgutiliter_modules" aria-label="Anchor">#</a></span></h2><p>If python has a way to iterate through all sub-modules of a given module, and registers all attributes including their
types, it is possible to implement a registry that imports all modules in a given package, and registers all.</p>
<p>Frameworks often utilize similar mechanisms to auto-discover modules or classes to register them automatically, and
provide <em>magically working experience</em> for the framework user. Examples of this are in Django
<code>django.utils.module_loading.autodiscover_modules</code> which auto-discovers modules named a certain way (e.g., <code>admin.py</code>);
that can be assumed are imported. This is utilized in Django&rsquo;s admin interface to auto-register models for the admin
interface. Another example, in which Django is not expecting a certain module name, is loading all migration
files <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">This implementation is heavily inspired by (/shamelessly copied from) <a href="https://github.com/markush" target="_blank" rel="noreferrer">Markus</a>.
Big thanks for the inspiration for this blog post!</span>
</div>

<p>This <code>discover_classes()</code> function uses the same <code>pkgutil</code> to iterate through all sub-modules of a given module,
collecting all python files even if only a subset is listed in the <code>__init__.py</code> file. It returns
<code>pkgutil.ModuleInfo(module_finder, name, ispkg)</code>, which is the mentioned module object.
Its <code>name</code> can be used to import the sub-module with <code>importlib.import_module</code>; and <code>ispkg</code> can be used to check if the
sub-module is a package itself, in which case the function is called recursively.
Then, <code>inspect.getmembers</code> is used to get all members of the sub-module, filtering for classes that are subclasses of
the provided Dog base class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># ------------- registry.py -------------</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">importlib</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">inspect</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pkgutil</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Generator</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">types</span> <span class="kn">import</span> <span class="n">ModuleType</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">BaseDog</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DogRegister</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">_registry</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">type</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">register_dogs</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="kn">import</span> <span class="nn">iter_modules.dogs</span> <span class="k">as</span> <span class="nn">module</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">dog</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">discover_classes</span><span class="p">(</span><span class="n">in_module</span><span class="o">=</span><span class="n">module</span><span class="p">,</span> <span class="n">of_subclass</span><span class="o">=</span><span class="n">BaseDog</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">dog</span><span class="p">,</span> <span class="nb">type</span><span class="p">(</span><span class="n">BaseDog</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">_registry</span><span class="p">[</span><span class="n">dog</span><span class="p">()</span><span class="o">.</span><span class="n">request_type</span><span class="p">]</span> <span class="o">=</span> <span class="n">dog</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get_dog_for</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">BaseDog</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">found</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_registry</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">request_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">found</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="kn">from</span> <span class="nn">iter_modules</span> <span class="kn">import</span> <span class="n">dogs</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">dogs</span><span class="o">.</span><span class="n">common</span><span class="o">.</span><span class="n">Labrador</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">discover_classes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">in_module</span><span class="p">:</span> <span class="n">ModuleType</span><span class="p">,</span> <span class="n">of_subclass</span><span class="p">:</span> <span class="nb">type</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Generator</span><span class="p">[</span><span class="nb">type</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">sub_module_info</span> <span class="ow">in</span> <span class="n">pkgutil</span><span class="o">.</span><span class="n">iter_modules</span><span class="p">(</span><span class="n">in_module</span><span class="o">.</span><span class="n">__path__</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># import sub-module</span>
</span></span><span class="line"><span class="cl">            <span class="n">sub_module</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">in_module</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">sub_module_info</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># get classes matching Base</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">inspect</span><span class="o">.</span><span class="n">getmembers</span><span class="p">(</span><span class="n">sub_module</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># check if it&#39;s a class and subclass of Base (and not Base itself)</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="n">inspect</span><span class="o">.</span><span class="n">isclass</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">of_subclass</span><span class="p">)</span> <span class="ow">and</span> <span class="n">obj</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">of_subclass</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                    <span class="k">yield</span> <span class="n">obj</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">sub_module_info</span><span class="o">.</span><span class="n">ispkg</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># recurse into sub-package</span>
</span></span><span class="line"><span class="cl">                <span class="k">yield from</span> <span class="bp">self</span><span class="o">.</span><span class="n">discover_classes</span><span class="p">(</span><span class="n">in_module</span><span class="o">=</span><span class="n">sub_module</span><span class="p">,</span> <span class="n">of_subclass</span><span class="o">=</span><span class="n">of_subclass</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ------------- dogs/any file, any __init__.py content-------------</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">iter_modules</span> <span class="kn">import</span> <span class="n">registry</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Collie</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">request_type</span> <span class="o">=</span> <span class="s2">&#34;Herding&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Labrador</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">request_type</span> <span class="o">=</span> <span class="s2">&#34;Service Dog&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Husky</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">BaseDog</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">request_type</span> <span class="o">=</span> <span class="s2">&#34;Pulling&#34;</span>
</span></span></code></pre></div><h3 id="testing-the-pkgutil-registry" class="relative group">Testing the <code>pkgutil</code> Registry <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#testing-the-pkgutil-registry" aria-label="Anchor">#</a></span></h3><p>Similar to the config-based registry, the selection logic and the completeness of the registry can be tested separately.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">iter_modules</span> <span class="kn">import</span> <span class="n">registry</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">iter_modules</span> <span class="kn">import</span> <span class="n">dogs</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_init_subclass_returns_husky</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">dog_registry</span> <span class="o">=</span> <span class="n">registry</span><span class="o">.</span><span class="n">DogRegister</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">dog_registry</span><span class="o">.</span><span class="n">register_dogs</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">dog_registry</span><span class="o">.</span><span class="n">get_dog_for</span><span class="p">(</span><span class="s2">&#34;Pulling&#34;</span><span class="p">),</span> <span class="n">dogs</span><span class="o">.</span><span class="n">husky</span><span class="o">.</span><span class="n">Husky</span><span class="p">)</span>
</span></span></code></pre></div><p><strong>When to trigger registration?</strong> This solution is not triggered automatically on import by anything, and only uses the
iteration over modules to ensure all are imported. So, when to call the <code>register_dogs()</code> function?
One option is to utilize framework hooks like Django&rsquo;s AppConfig <code>ready()</code> method <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>, or implement
similar hooks to control when the registration should happen.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p><em>Magically working dev experience</em> and <em>hard to debug code</em> often go hand in hand. Still, things can be done to minimize
the knowledge required from the developer to use the code. Tests that fail with dev-friendly messages when something is
not imported or registered correctly can help a lot, and move the magic to the tests instead of the business code.
If the magic is in the business code, good documentation to spread awareness about the pitfalls of the current
implementation and minimizing the errors developers can make is crucial.</p>
<p>Again big thanks to <a href="https://github.com/markush" target="_blank" rel="noreferrer">Markus</a> for the debugging help on import related bugs, many
insights about python and inspiration for this post!</p>
<p>Happy coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://dev.to/dentedlogic/stop-writing-giant-if-else-chains-master-the-python-registry-pattern-ldm" target="_blank" rel="noreferrer">Registry Patterns in Python</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://peps.python.org/pep-0487/#subclass-registration" target="_blank" rel="noreferrer">PEP 487</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://github.com/django/django/blob/4702b36120ea4c736d3f6b5595496f96e0021e46/django/conf/project_template/manage.py-tpl" target="_blank" rel="noreferrer">Django main entry</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://learning.oreilly.com/library/view/python-in-a/9781098113544" target="_blank" rel="noreferrer">&ldquo;Python in a Nutshell&rdquo; by Alex Martelli</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://docs.python.org/3/reference/datamodel.html#creating-the-class-object" target="_blank" rel="noreferrer">The Python Data Model</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://github.com/django/django/blob/0174a85770356fd12e4c8daa42a4f1c752ae00e6/django/db/migrations/loader.py#L112-L116" target="_blank" rel="noreferrer">Django discovering Migrations</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://docs.djangoproject.com/en/5.2/ref/applications/#django.apps.AppConfig.ready" target="_blank" rel="noreferrer">Django AppConfig ready()</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="python" label="Python"/><category scheme="taxonomy:Tags" term="patterns" label="Patterns"/><category scheme="taxonomy:Tags" term="architecture" label="Architecture"/></entry><entry><title type="html">Looking at Observability</title><link href="https://philodev.one/posts/2025-09-datadog/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><id>https://philodev.one/posts/2025-09-datadog/</id><published>2025-11-30T10:20:44+02:00</published><updated>2025-11-30T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>My learnings about monitoring, alerting and observability in software systems.</blockquote><div class="lead !mb-9 text-xl">
  I have spent some time improving the monitoring and alerting in the team I am currently working to design monitors
that capture the current state of the system and alert before users find issues severe enough to report them.
This blog post summarizes some of the things I have learned along the way.
</div>

<h2 id="if-the-goal-is-observability-what-is-the-data-to-collect" class="relative group">If the goal is Observability, what is the data to collect? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#if-the-goal-is-observability-what-is-the-data-to-collect" aria-label="Anchor">#</a></span></h2><blockquote>
<p>Raw data is a oxymoron, there are always decisions made what to collect and how to store it.
(Pydata 25 Melbourne, &ldquo;Falshoods Devs believe&rdquo;)</p>
</blockquote>
<h3 id="three-pillars-of-observability---how-to-collect-data" class="relative group">Three pillars of observability - how to collect data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#three-pillars-of-observability---how-to-collect-data" aria-label="Anchor">#</a></span></h3><p>Observability starts with collecting data about the system. The three pillars of observability are the main three ways
in which data may be collected. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<ul>
<li><strong>Logs</strong> - timestamped, semi-structured text records of discrete events, like error messages, transaction records,
user actions. Mind that power of logs comes from their structure, the inclusion of meta-data like request IDs, request
type, user group, trace id,&hellip; makes logs much more useful to search and to correlate. Compared to events, logs are
more flexible and allow for more experimentation to find the right structure. Mind that logs should never contain
sensitive data.</li>
<li><strong>Metrics</strong> - numerical data points collected over time, like request latency, error rates, business cases processed.
They are an efficient way to monitor the health data over time, and can be aggregated and visualized in dashboards.
While logs often are limited to some recent time window, metrics can be stored for longer periods to analyze trends.</li>
<li><strong>Traces</strong> - A static trace id in a request can be used to track a request life-cycle across multiple components.
Traces are useful to understand the flow of requests, identify bottlenecks, and debug issues in complex
distributed systems.</li>
</ul>
<h3 id="service-level-indicators-slis-service-level-objectives-slos-and-service-level-agreements-slas" class="relative group">Service Level Indicators (SLIs), Service Level Objectives (SLOs) and Service Level Agreements (SLAs) <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#service-level-indicators-slis-service-level-objectives-slos-and-service-level-agreements-slas" aria-label="Anchor">#</a></span></h3><p><strong>Service Level Indicators (SLIs)</strong> measures on service level, for example request latency, availability, throughput.
Which indicators are important to a system depends on what the users care about.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>Mind the Users Perspective: Different users care about different indicators, depending on their use case.</p>
<p>A human facing Web Service might care about <em>Does the service response (Availability)? How long does it take to
respond (Latency)? Does it respond without errors (Error Rate)?</em>.</p>
<p>A Data Pipelines might care more about <em>How long does it take to process data (End-to-end-latency)? How much data
can be processed (Throughput)? Is the data correct (Correctness)?</em>.</p>
</span>
</div>

<p><strong>Service Level Objectives (SLOs)</strong> are target values or ranges for a service level indicator over a period of time or
fraction of requests, like 99.9% of requests should be below 100ms latency, or 99.9% availability over a month.
Choosing and publishing SLOs can communicate expected performance to users, and can guide developer decisions.</p>
<p><strong>Service Level Agreements (SLAs)</strong> are explicit or implicit contracts between service providers and users.
Explicit SLAs can be legally binding requirements, while implicit SLAs are expectations of the users.</p>
<p>A special form of SLA is the error budget, which defines for developers how much unreliability is acceptable within a
certain period, until developers need to focus on reliability improvements over feature development.</p>
<h3 id="how-to-choose-what-to-monitor" class="relative group">How to choose what to monitor <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#how-to-choose-what-to-monitor" aria-label="Anchor">#</a></span></h3><p>The golden signals are a good starting point for choosing what to monitor: <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<ul>
<li>Latency - Time to process a request</li>
<li>Traffic - Amount of requests</li>
<li>Errors - Rate of failed requests</li>
<li>Saturation - Resource utilization with focus on bottlenecks</li>
</ul>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>Monitoring (like so many other things) have multiple audiences with different needs:</p>
<ul>
<li><strong>Developers</strong> want to understand how the system behaves, and be able to debug issues quickly.</li>
<li><strong>Operators</strong> (who might also be Developers) want to ensure the system is running smoothly, and be alerted when
something goes wrong.</li>
<li><strong>Business Stakeholders</strong> want to understand how the system is performing against business goals, and make informed
decisions based on data, or evaluate experiments.</li>
</ul>
<p>If your audience can not phrase their needs, the best metrics are still found in their perspective.
What are Operators talking in incident post-mortems - Which indicator spiked frist or would have helped to detect the
incident earlier or identify the root cause faster? What are Business Stakeholders asking about the system?
What find Users so severe that they report incidents? <strong>Talk and Listen to your Audience!</strong></p>
</span>
</div>

<p><strong>First principles</strong> are basic assumption about the system that are not deduced from other assumptions.
The idea of first principles is usefully as good observability should allow a developer to debug a system without a lot
of prior knowledge about it. As software systems grow in complexity, it becomes more valuable to have a solid foundation
to reason on facts rather that relying on years of experience with a system. <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<h2 id="alerting-and-monitoring" class="relative group">Alerting and Monitoring <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#alerting-and-monitoring" aria-label="Anchor">#</a></span></h2><p>Assuming there are metrics and logs collected about the system, anomalies need to be detected and acted upon.
There are three main ways to deal with anomalies: <sup id="fnref1:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<ul>
<li><strong>Collecting</strong> information about anomalies that do not require action. For example, higher load on mondays morning is
a good thing to be aware of, but not something that needs action.</li>
<li><strong>Tickets</strong> can be created for anomalies that need to be investigated, but do not require immediate action. For
example, an increased error rate for one user group.</li>
<li><strong>Alerts</strong> are created when immediate action is required and possible. If the throughput of a data pipeline drops
below a certain threshold, an alert can notify to investigate and mitigate the issue.</li>
</ul>
<p>Alerts should be designed carefully, as they create cognitive load for developers and operators. The worst alert are
repeatedly false alarms, alarms on which no action can be taken, or constant alarms that are ignored over time.</p>
<h3 id="alert-design" class="relative group">Alert Design <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#alert-design" aria-label="Anchor">#</a></span></h3><p>An alert should be actionable. It should be common practice to define runbooks for every alert. What are possible
causes, and how to investigate, and how to mitigate the issue? Information like who will be notified, escalation paths,
or user impact should also be part of the runbook. Alerts should also require intelligence to investigate - if the
runbook looks so well-defined, that it can be automated, it should be.</p>
<h3 id="choosing-targets-for-alerting" class="relative group">Choosing Targets for Alerting <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#choosing-targets-for-alerting" aria-label="Anchor">#</a></span></h3><p>Externally Service Level Indicators (SLIs) do not need to match internal alerting targets.
If the external targets are higher than the current (sub)system performance, alerting will be frequent and therefore
ignored in the long run; and if the external targets are lower than the current (sub)system performance, alerts can be
used to strive for higher performance.</p>
<h2 id="using-dashboards" class="relative group">Using Dashboards <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-dashboards" aria-label="Anchor">#</a></span></h2><p>Observability should enable developers to understand and debug the system. Dashboards and Monitors should be designed
around usability - next to the alert that some request time is out of bounds, developers should be able to quickly find
information about possible causes, like request rates spiking, database connections being exhausted, or error rates
increasing. Looking at a dashboard full of flashing graphs is not useful, even if it might look impressive.</p>
<h3 id="distribution-over-averages" class="relative group">Distribution over Averages <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#distribution-over-averages" aria-label="Anchor">#</a></span></h3><p>Data viewed in distribution reveals patterns, anomalies, and offers more actionable insights compared to simple
averages. For example, the average response time of a web service is nice to have, the information that 95% of requests
are below 200ms while 5% take over 2 seconds provides a actionable insight that can lead to performance improvements or
clearer expectations for users.
Software system often have non-normal distributions, with outliers and long tails that would be hidden by averages, but
are visible by using distribution aware tools like percentiles. <sup id="fnref2:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M421.7 220.3L188.5 453.4L154.6 419.5L158.1 416H112C103.2 416 96 408.8 96 400V353.9L92.51 357.4C87.78 362.2 84.31 368 82.42 374.4L59.44 452.6L137.6 429.6C143.1 427.7 149.8 424.2 154.6 419.5L188.5 453.4C178.1 463.8 165.2 471.5 151.1 475.6L30.77 511C22.35 513.5 13.24 511.2 7.03 504.1C.8198 498.8-1.502 489.7 .976 481.2L36.37 360.9C40.53 346.8 48.16 333.9 58.57 323.5L291.7 90.34L421.7 220.3zM492.7 58.75C517.7 83.74 517.7 124.3 492.7 149.3L444.3 197.7L314.3 67.72L362.7 19.32C387.7-5.678 428.3-5.678 453.3 19.32L492.7 58.75z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>k-th Percentiles</strong> are a statistical tool to express the value or score point below which a given percentage <strong>k</strong> of
the data points fall. For example, a 95th percentile latency of 300ms means that 95% of requests are served in under
300ms.</span>
</div>

<p>Distributions is not limited to distribution over amount of data points, but can also be used to show distribution over
time, resources, user groups, &hellip;</p>
<ul>
<li>95% of requests are served in under 200ms</li>
<li>On 95% of days, the response time was under 200ms</li>
<li>95% of our users in the low-data throughput group experienced response times under 200ms</li>
<li>90% of our containers served requests in under 200ms</li>
</ul>
<p>This already hints at what meta-data is useful to collect alongside the primary metrics.</p>
<h3 id="dashboards-like-medical-monitors" class="relative group">Dashboards like Medical Monitors <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#dashboards-like-medical-monitors" aria-label="Anchor">#</a></span></h3><p>Ever looked at a medical monitor with heart rate, blood pressure, oxygen saturation and wondered if the values are good
or not? Reading ECG requires training and experience, knowledge about the p-wave, qrs-complex and t-wave, and what how
specific patterns indicate health issues.
The moment a health metric drops or rises above a certain threshold, the monitor will indicate that by a color change, a
easy description (e.g. &ldquo;HR low&rdquo;), and an alarm sound that fits the severity of the issue. This enables medical staff to
act fast, without needing to interpret the raw data to understand the situation, and without knowledge about the type of
monitor.</p>
<p>If you think about dashboard designs like medical monitors, the time series data requires a lot of training and
experience to read, and while it can be interesting, it is often hard to judge what is normal and what is not.</p>
<p>Dashboards should therefore include baselines, indicating what is normal for a metric:</p>
<ul>
<li>Display a shaded area around the time series, indicating the average over the past weeks</li>
<li>Provide high and low thresholds for normal ranges</li>
<li>Color indications when the metric is outside normal ranges with severity levels</li>
<li>For every numerical metric, provide the average metric over the past weeks as a reference point</li>
<li>Provide context about external factors that influence the metric, like deployments, incidents, marketing campaigns,</li>
<li>Have meaningful titles, and add hints, explanations, links to runbooks to help interpreting the data</li>
</ul>
<h3 id="dashboard-graphs-should-tell-a-story" class="relative group">Dashboard Graphs should tell a Story <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#dashboard-graphs-should-tell-a-story" aria-label="Anchor">#</a></span></h3><p>On the question of how to use graphics to communicate data effectively, I learned a lot from the book &ldquo;Communication
Patterns&rdquo;, which I wrote about in <a href="https://philodev.one/posts/2025-10-communication-patterns/">my previous blog post</a></p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>I searched for good resources about observability, monitoring and alerting, and found way less than I anticipated.
Especially good practices about what data to collect, how to design dashboards are hard to find (but honestly, so are
good designed Dashboards). I hope to learn more about this topic in the future, and share my learnings in future blog
posts.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>A four times two-hour training by DataDog I joined in October 2025.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Side Reliability
Engineering - <a href="https://sre.google/sre-book/table-of-contents/" target="_blank" rel="noreferrer">Google SRE Book</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://learning.oreilly.com/library/view/observability-engineering/9781492076438/" target="_blank" rel="noreferrer">Observability Engineering</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="metrics" label="Metrics"/><category scheme="taxonomy:Tags" term="observability" label="Observability"/></entry><entry><title type="html">📚 Communication Patterns</title><link href="https://philodev.one/posts/2025-10-communication-patterns/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><id>https://philodev.one/posts/2025-10-communication-patterns/</id><published>2025-10-10T10:20:44+02:00</published><updated>2025-10-10T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>My learnings, thoughts, and key aspects of the book &ldquo;Communication Patterns&rdquo; by Jacqui Read</blockquote><div class="lead !mb-9 text-xl">
  &ldquo;Communication Patterns&rdquo; by Jacqui Read
</div>

<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>Expectation Management</strong> : This blog post reflects my personal takeaways from the book. Chapters that I did not find
interesting or relevant to my work are not covered, chapters that particularly resonated with me are covered in more
detail. In between I added information I found useful to understand the context of the book. Overall I changed the
structure and order of topics.</p>
<p>I will add personal opinion and context in these alerts.</p>
</span>
</div>

<h2 id="communication-patters---about-the-book" class="relative group">Communication Patters - about the book <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#communication-patters---about-the-book" aria-label="Anchor">#</a></span></h2><blockquote>
<p>Successful communication is the art and science of sharing or exchanging ideas and information, using a common set of
symbols, signs, or behaviors, resulting in shared understanding.
— Jacqui Read, Communication Patterns
<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
</blockquote>
<p>Communication can be hard, and the cost of miscommunication can be high. Refining existing communication patterns into
named patterns can form a toolbox for good communication and awareness of dark patterns.</p>
<p>A <strong>Pattern</strong> is a reusable solution to a commonly occurring problem within that is known to be effective.
An <strong>Anti-pattern</strong> on the other hand is a solution that looks right, but its consequences outweigh its benefits.</p>
<h2 id="think-about-the-users-perspective" class="relative group">Think about the Users Perspective <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#think-about-the-users-perspective" aria-label="Anchor">#</a></span></h2><p>Identifying the audience / user to communicate with is key to successful communication.</p>
<ul>
<li>What Role does the User fulfill? How much technical knowledge does the User have? Can they understand technical terms,
or technical diagrams like UML?</li>
<li>What does the User want to know? What do you want from the User? In what level of detail do they need the information?</li>
<li>What do they already know? Do they might know outdated information that needs to be corrected?</li>
</ul>
<p><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>Diataxis</strong> : Is a framework that helps to structure documentation based on the user needs. It answers some of the
questions above by sorting them into four categories: Tutorials, How-To Guides, Explanation, and Reference.</p>
<p>Tutorials: A practical lesson or introduction to a topic, guiding a user who is unknown to the topic through a series of
steps to learn how to solve future problems, by solving a example problem.</p>
<p>How-To Guides: A step-by-step guide to accomplish a specific real world task, for users who know what they want to do
and focus on work rather than study the topic.</p>
<p>Reference: A technical description for the user who needs to look up specific information to continue work.</p>
<p>Explanation: A deep dive into the background and context of a topic, for users who want to understand why the system a
given way.</p>
</span>
</div>

<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<h2 id="visual-communication" class="relative group">Visual Communication <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#visual-communication" aria-label="Anchor">#</a></span></h2><h3 id="which-diagram-to-choose" class="relative group">Which diagram to choose? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#which-diagram-to-choose" aria-label="Anchor">#</a></span></h3><p>Giving the following bad example:</p>
<div class="mermaid" align="center">
  
gantt
title Time People need to understand this Diagrams
dateFormat YYYY-MM-DD
section Questioning Diagram Type
❌ Why is this even a Gantt Chart?!                              :2025-01-01, 30d
🛠️ C4 Diagram would barely help here...                          :2025-01-05, 20d
C4 🤓 Context-Container-Component-Code                           :2025-01-10, 25d
❌ Why explaining the C4 if nothing else is explained?           :2025-01-20, 25d
section Questioning Content
🏅 Does this match the upcoming headings?                        :2025-01-05, 30d
💡 Is this even content or a just a bad example?                 :2025-01-20, 25d

</div>

<h4 id="-anti-pattern-choosing-the-wrong-diagram-for-the-user" class="relative group">❌ Anti Pattern: Choosing the wrong Diagram for the User <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-anti-pattern-choosing-the-wrong-diagram-for-the-user" aria-label="Anchor">#</a></span></h4><p>Different Users will understand and appreciate different diagrams. Talking in stereotypical roles, the steak holder who
wants to understand the system would prefer a User Journey over a Class Diagram, while a Developer would probably gain
quite some information from the latter.</p>
<p>The goal should be to choose a diagram that the User is familiar with, that will match their question or conveys the
message they should receive, and it should contain the amount of detail that the User needs.</p>
<h4 id="-anti-pattern-mixing-levels-of-abstraction----tool-c4-model" class="relative group">❌ Anti Pattern: Mixing Levels of Abstraction - 🛠 Tool: C4 Model <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-anti-pattern-mixing-levels-of-abstraction----tool-c4-model" aria-label="Anchor">#</a></span></h4><p>Developer Example:<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">feed</span><span class="p">(</span><span class="n">corgi</span><span class="p">:</span> <span class="n">Corgi</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># easily readable level of abstraction</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">corgi</span><span class="o">.</span><span class="n">is_fed</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="n">food</span> <span class="o">=</span> <span class="n">_get_food</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">corgi</span><span class="o">.</span><span class="n">ate</span><span class="o">.</span><span class="n">appent</span><span class="p">(</span><span class="n">food</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># awkwardly detailed level of abstraction</span>
</span></span><span class="line"><span class="cl">    <span class="n">corgi</span><span class="o">.</span><span class="n">last_fed</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">corgi</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># the last 2-3 lines could have been a method,</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># making this much more readable. </span>
</span></span></code></pre></div><p>Every diagram will be an abstraction of something, but not everything that can be useful for the reader should be
compressed into one diagram. Individual tickets do not belong into a roadmap, as it would clutter the model or even
raise the questions what these little details mean if they are so important to be mentioned here.</p>
<p>One Solution to this is offered by the C4 Hierarchy of abstractions. Starting from a big picture it starts with the
<strong>System Context</strong> in which the system interacts with its environment.
The <strong>Container</strong> level displays the components of system with their interaction in between them or the external
entities.
While the <strong>Component</strong> levels zooms into one Container of the last level and dissects its subcomponents.
The finest level is the <strong>Code</strong>, which reveals actual implementation.</p>
<h4 id="-best-practice-representational-consistency" class="relative group">🏅 Best Practice: Representational Consistency <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-representational-consistency" aria-label="Anchor">#</a></span></h4><p>When working with multiple diagrams, for example after applying the C4 Model, all references to the same component,
role, entity should be easily identifiable as the same. With diagrams, we often do not have the luxury to step in and
out of details with one click or having a compiler checking that naming is consistent over multiple diagrams.
A role could be named the same and use the same pictogram; a component could be named the same and be framed by the
same symbol and color in a system context diagram and a container diagram.</p>
<h4 id="-best-practice-single-responsibility" class="relative group">💡 Best Practice: Single Responsibility <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-single-responsibility" aria-label="Anchor">#</a></span></h4><p>This commonly known software pattern describes that a building block should only have a single responsibility.
The most repeated reason for this is maintainability, as there is also only one reason to change; giving a block of code
a single responsibility makes it wat easier to understand. The same applies to diagrams, if a diagram tries to convey
multiple messages, it will be hard to understand and less effective in conveying that message.</p>
<p>The main differentiation of responsibilities are between <em>Behavior</em> and <em>Structure</em>.
Behavior diagrams like Sequence Diagrams show how the system achieves which goal.
Structure diagrams like Class Diagrams show what the system is made of and who it interacts with.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>I see the point how even any reporting diagram can be sorted into these two categories, but when designing a diagram I
would find it useful to have more responsibilities as inspiration what the responsibility of the diagram could be.</p>
<ul>
<li><strong>State</strong> : What states a system can reach or what life cycle can be mapped.</li>
<li><strong>Reporting</strong> : What is the historic, current, or future performance of a system.</li>
<li><strong>Observability</strong> : Modelling what structures can be observed while they behave in a certain way.</li>
</ul></span>
</div>

<h3 id="diagram-layout" class="relative group">Diagram Layout <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#diagram-layout" aria-label="Anchor">#</a></span></h3><p>After choosing a fitting diagram type, the layout of the diagram should be designed to easily convey the message to the
User.</p>
<p>A bad example would be:</p>
<div class="mermaid" align="center">
  
graph BT

subgraph Topics
subgraph Antipatterns
A1(["❌ Boxes in Boxes in Boxes"])
A2(["❌ Relationship Spiderweb"])
end
subgraph Proven Patterns
A3(["🦚 Create Visual Balance"])
A4(["💡 Match the Expectations, Tell a Story"])
end
end
subgraph Current Chapter
A[Patterns around Diagram Layout]
end

    %% Links
    A --is about and first topic--> A1
    A --is about--> A2
    A --is about--> A3
    A --is about--> A4
    A1 --second topic--> A2
    A2 --third topic--> A3
    A3 --fourth topic--> A4


</div>

<h4 id="-anti-pattern-boxes-in-boxes-in-boxes" class="relative group">❌ Anti Pattern: Boxes in Boxes in Boxes <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-anti-pattern-boxes-in-boxes-in-boxes" aria-label="Anchor">#</a></span></h4><p>Boxes are a great tool to group related items together, if done correctly they can be used to indicate consistent
entities over multiple diagrams, e.g. if the box that represents a Component in a Container Diagram is the same as the
box that contains a component Diagram.
However, boxes within boxes can quickly lead to confusion, and can then cost more time to understand the
diagram.</p>
<p>A possible developer analogy might be nested functions, or nesting function logic into multiple levels of classes.</p>
<p><strong>=&gt; White Space reduces Cognitive Load, while lines and boxes increase it.</strong></p>
<h4 id="-anti-pattern-relationship-spiderweb" class="relative group">❌ Anti Pattern: Relationship Spiderweb <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-anti-pattern-relationship-spiderweb" aria-label="Anchor">#</a></span></h4><p>The connection between diagram elements should have a defined meaning, which should be consistent over the diagram and
easy to be identified by the User.</p>
<p>Examples of Relationships are:</p>
<ul>
<li>Hierarchical: Illustrating parent-child connection, like in taxonomies or organizational charts.</li>
<li>Sequential: Progress of steps or stages, like in flowcharts or step-by-step guides.</li>
<li>Causal: Showing cause-effect relationships, like in decision trees.</li>
<li>Spatial: Representing physical or conceptual proximity, like in mind maps.</li>
<li>Proportional: Indicating relative scale or size, like in pie charts or bar graphs.</li>
</ul>
<p>Mixing multiple types of connections or not planning the layout to avoid crossing lines can quickly lead to a spiderweb
of connections that is hard to understand.</p>
<h4 id="-best-practice-create-visual-balance" class="relative group">🏅 Best Practice: Create Visual Balance <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-create-visual-balance" aria-label="Anchor">#</a></span></h4><p>Balance is a innate human expectation. Similar to photos, a diagram that is visually balanced will be easier to
understand and appealing to look at. There is no character limit or maximum lines of code per file for diagrams, and
fiddling with mermaid directions to achieve a visually balanced diagram can be annoying, but it is worth the effort.</p>
<h4 id="-best-practice-match-the-flow-the-user-expects-tell-a-story" class="relative group">💡 Best Practice: Match the Flow the User Expects, Tell a Story <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-match-the-flow-the-user-expects-tell-a-story" aria-label="Anchor">#</a></span></h4><p>A human will find a diagram easier to understand if the flow of information matches their expectations, providing a
start point (of a user journey, a state machine, the main class things evolve around), evolving around the message or
story the diagram should tell, and a conclusion or end point.</p>
<p>While there are cultural differences, western cultures will expect information to flow from left to right and top to
bottom. Anyway, it is easier to follow a flow that is consistent throughout the diagram, and if possible unidirectional.</p>
<h3 id="diagram-elements" class="relative group">Diagram Elements <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#diagram-elements" aria-label="Anchor">#</a></span></h3><h4 id="-best-practice-balance-text" class="relative group">🏅 Best Practice: Balance Text <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-balance-text" aria-label="Anchor">#</a></span></h4><p>Big walls of text obfuscate the message of a diagram. Often test can be reduced or moved into a footnote or legend.</p>
<div class="mermaid" align="center">
  
graph LR
subgraph Users Reaction
M[Declutter Text and Content]
O[Increased Mental load]
end
subgraph .
L[User needs to declutter the Text from Content]
N[User needs additional mental load to read the text]
end

</div>

<p>Like Code, Diagrams should be understandable without comments or additional explanations.
Good naming, understandable composition, carefully chosen colors and style, and known symbols can aid a well formulated
diagram message.</p>
<h4 id="-best-practice-add-a-legend" class="relative group">🏅 Best Practice: Add a Legend <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-add-a-legend" aria-label="Anchor">#</a></span></h4><p>Not including a legend means assuming that the User understands all elements, abbreviations, or symbols used.
That assumption will in the end reduce the audience of the diagram, not only because Users unfamiliar with technical
knowledge will not understand it, but also Users of other cultural backgrounds might interpret symbols or colors
differently.</p>
<h4 id="-anti-pattern-color-overload" class="relative group">❌ Anti Pattern: Color Overload <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-anti-pattern-color-overload" aria-label="Anchor">#</a></span></h4><p>Colors should have a meaning - Using too many colors can quickly lead to confusion.
Colors are a great tool provide an additional layer of information, e.g. grouping related items, or indicating
status, risk levels, or role.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>Choosing Colors is not trivial!</strong></p>
<ul>
<li>Colors should have sufficient contrast to be distinguishable by color-blind users. There are help tools to check color
contrast, e.g. <a href="https://www.accessibilitychecker.org/color-contrast-checker/" target="_blank" rel="noreferrer">Accessibility Checker</a>.</li>
<li>Colors should match cultural expectations, e.g. red and green for stop and go, red and blue for hot and cold.</li>
<li>Colors should be consistent over multiple diagrams and company standards</li>
<li>Colors should work printed and digitally (check color spaces RGB and CMYK)</li>
</ul></span>
</div>

<p>It is a best practice not to rely solely on colors to convey information, and always use a pattern or at least color hue
to differentiate items, and included their meaning in the legend.</p>
<p><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Syntax Highlighting Colors in IDEs should have a meaning</strong>: Many IDE Color Schemes are bright and colorful,
highlighting so many parts of the code, that nothing stands out. Modern color schemes should use colors sparingly;
highlighting docs, (magic) constants, and structural information like function or class definitions.</span>
</div>
 <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<h4 id="-best-practice-use-meta-style" class="relative group">💡 Best Practice: Use Meta Style <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-use-meta-style" aria-label="Anchor">#</a></span></h4><p>Style can also convey information. Using a dashed border for deprecated items or a scribbled style for ideas or future
features. While many choose a style based on personal preference, choosing between Excalidraw or Mermaid can convey much
more information than taste. Every Shape can have meaning by convention or association, and can be much more than style.</p>
<h4 id="-anti-pattern-misleading-the-user" class="relative group">❌ Anti Pattern: Misleading the User <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-anti-pattern-misleading-the-user" aria-label="Anchor">#</a></span></h4><p>Dark Patterns are well famous in UX Design, but can also be applied to Diagrams. Starting an axis at a non-zero value,
using non-linear scales, emotional colors or pictures to influence the User &hellip; Every diagram has a message to convey,
but misleading the User is plain unethical.</p>
<h2 id="written-communication" class="relative group">Written Communication <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#written-communication" aria-label="Anchor">#</a></span></h2><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">I wrote a blog post about <a href="https://philodev.one/posts/2024-07-writing-documentation/" target="_blank" rel="noreferrer">Writing Good Documentation</a> which I am
still happy with, that covers many aspects also mentioned in this chapter. Therefore I will only highlight a few points
from the book here.</span>
</div>

<h4 id="-best-practice-big-picture-first" class="relative group">🏅 Best Practice: Big picture first <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-big-picture-first" aria-label="Anchor">#</a></span></h4><p>As a User of written communication, knowing the order of the things I am going to learn, will help to organize the
information into my mental model. Starting with the big picture provides a narrative, helping to navigate into the
details a user might look for and improves retention of information.</p>
<p>🛠<strong>Minto Pyramid</strong>: The Minto Pyramid Principle is a technique to structure information in a way that is easy to
understand.</p>
<ol>
<li>Start with the key message. For the User it is easier to understand the details if the key idea is known upfront.</li>
<li>Write out the details of information to convey with the message.</li>
<li>Group related information together, and structure them again into key messages and details.</li>
</ol>
<h4 id="-anti-pattern-testing-the-audiences-knowledge" class="relative group">❌ Anti Pattern: Testing the Audiences Knowledge <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-anti-pattern-testing-the-audiences-knowledge" aria-label="Anchor">#</a></span></h4><p>The goal of communication is to convey a message. Any word, phrase, or concept that is unknown to the Audience but used
by the communicator will make it harder to convey the message. It is important to know the Audience and what knowledge
to expect from them in regard to technical terms, domain knowledge, language skills / vocabulary, diagram standards, and
cultural context.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Any documentation should aim for the broadest audience possible. Acronyms are not helpful, especially if they are
not &ldquo;googleable&rdquo;. If there are terms that require a context to be researchable, a glossary should be provided and the
context to look them up should be given. Domain Driven Design proposes the Ubiquitous Language to create a common
vocabulary throughout a product, that is used by stakeholders, product managers, technical writers, and developers
alike. Consistency in naming and terminology reduces cognitive load and improves communication.</span>
</div>

<h4 id="-know-about-biases" class="relative group">💡 Know about Biases <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-know-about-biases" aria-label="Anchor">#</a></span></h4><p>Humans show systematic patterns of deviation from rationality in judgment, known as cognitive biases. They can affect
how important we perceive information, how we interpret messages, and how we make decisions based on what we read or
hear. As communicators, being aware of these biases can help us craft messages that are clearer and more effective.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">While the book lists some biases, I recommend reading about the many forms of cognitive biases and logical fallacies
to be aware of them when communicating, not only in written form but also in our daily business and private live.</span>
</div>

<h4 id="-knowledge-management-principles" class="relative group">🏅 Knowledge Management Principles <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-knowledge-management-principles" aria-label="Anchor">#</a></span></h4><ul>
<li><strong>Product over Project</strong>: Keep the long term focus on domain knowledge that lives beyond the life cycle of a project.</li>
<li><strong>Ensure Visibility</strong>: Make knowledge accessible to those who need it. Centralize documentation in a known location,
with open access for people even from different teams if they work on the same product or domain.</li>
<li><strong>Enable Reusability</strong>: Templates and standards for documentation can help to create consistent and reusable knowledge
artifacts, while also decreasing entry barriers for contributors.</li>
<li><strong>Prioritize Searchability</strong>: Structure documentation using Metadata, Tags, and a clear structure.</li>
</ul>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>Sharing knowledge in an organization is in my experience simultaneously never perceived as well working and always
perceived as easy to improve. The small line between having not documented anything in an accessible way and having
AI generated documentation that no one reads is used by some organizations as metaphoric jump rope.</p>
<p>Especially as somebody who values documentation, reading AI generated walls of texts that look impressive, and yet
spread little information feels frustrating. Having beautiful looking docs that in the end do not convey an easy,
compact, and correct view of the system they aim to model are prone to become <strong>AI Slop</strong>, causing way more workhours
than their creator wanted to save themselves.</p>
</span>
</div>

<h4 id="-best-practice-get-feedback" class="relative group">🏅 Best Practice: Get Feedback <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#-best-practice-get-feedback" aria-label="Anchor">#</a></span></h4><p>Getting feedback from the multiple Audiences is crucial to successful communication. It is the best way to identify
errors and possible optimisations early, establish a dialogue with the Audience, align expectations, evaluate risks, and
share the load of communication and documentation. Like Pull Requests in Software Development, having a review process
is an effective way to ensure quality and establish shared ownership of communication artifacts.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Looking at the parallels of modeling a system as code and modeling a system in visual communication provides very
interesting point of views. Modern code is designed to be reused, easy to understand, and easy to maintain.
Why not apply the same principles and patterns to communication artifacts as well?</p>
<p>The book also covers much more information about verbal communication, meetings, and presentations, goes into great
detail about the individual patterns, and provides many more examples - after all these are just my personal takeaways,
biased by the knowledge I already had and the ignorance of topics I currently do not appreciate.</p>
<p>Happy coding :) (and communicating)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://jacquiread.com/books/communication-patterns/" target="_blank" rel="noreferrer">Jacqui Read</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://diataxis.fr" target="_blank" rel="noreferrer">Diataxis Framework</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://medium.com/thinkster-io/code-smell-changing-levels-of-abstraction-521cfc8094a2" target="_blank" rel="noreferrer">Mixing levels of abstraction</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://tonsky.me/blog/syntax-highlighting/" target="_blank" rel="noreferrer">Color overload in IDEs</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="book" label="Book"/><category scheme="taxonomy:Tags" term="documentation" label="Documentation"/></entry><entry><title type="html">What is Graphic Recording?</title><link href="https://philodev.one/posts/2025-11-graphic-recording/?utm_source=atom_feed" rel="alternate" type="text/html"/><id>https://philodev.one/posts/2025-11-graphic-recording/</id><published>2025-09-14T10:20:44+02:00</published><updated>2025-09-14T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Graphic Recording is the skill of listening, synthesizing, and translating given information into a drawing.</blockquote><p>Graphic Recording is a visual practice that involves capturing and synthesizing information in real-time during
meetings, workshops, or presentations. It combines elements of drawing, writing, and design to create large-scale visual
representations of the content being discussed.</p>
<p>I want to learn Graphic Recording to enhance my ability to communicate complex ideas and concepts in a more engaging
way. It combines my interests in art and communication. To learn this skill I started with the book &ldquo;Graphic Recording -
das 1 x 1 der Live-Visualisierung&rdquo; <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> by Martina Grigoleit, and various online resources and booklets.</p>
<p>While I learned about graphic recording when visiting the DevOps Days in 2023, I also got inspired by the blog posts from
Julia Evans <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<p>






  
  
<figure><img src="/images/2025-11-graphic-recording.png" alt="Graphic Recording" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.oreilly.com/library/view/graphic-recording/9783747502686/" target="_blank" rel="noreferrer">https://www.oreilly.com/library/view/graphic-recording/9783747502686/</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://jvns.ca/" target="_blank" rel="noreferrer">https://jvns.ca/</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></entry><entry><title type="html">Leveling Up Git Skills</title><link href="https://philodev.one/posts/2025-08-understanding-git/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2025-06-bitemporal-data/?utm_source=atom_feed" rel="related" type="text/html" title="Bitemporal Data: Timetravel your Data"/><link href="https://philodev.one/posts/2025-05-python-meta-programming/?utm_source=atom_feed" rel="related" type="text/html" title="Meta Programming in Python"/><link href="https://philodev.one/posts/2025-04-from-php-to-python/?utm_source=atom_feed" rel="related" type="text/html" title="Learning a new language - from PHP to Python"/><link href="https://philodev.one/posts/2024-10-queues-in-practice/?utm_source=atom_feed" rel="related" type="text/html" title="Consuming and Publishing to an external Service with Symfony Messenger"/><link href="https://philodev.one/posts/2024-07-writing-documentation/?utm_source=atom_feed" rel="related" type="text/html" title="Writing useful Documentation"/><id>https://philodev.one/posts/2025-08-understanding-git/</id><published>2025-08-10T10:20:44+02:00</published><updated>2025-08-10T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Git is a powerful tool for version control, but it can be complex and unintuitive. I tried to dive in the concepts of git, and learn why and how to keep a clean commit history.</blockquote><div class="lead !mb-9 text-xl">
  Git is a powerful tool for version control, but it can be complex and unintuitive. I tried to dive in the concepts of
git, and learn why and how to keep a clean commit history.
</div>

<h2 id="git-step-by-step-from-file-to-commit" class="relative group">Git Step by Step from File to Commit <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#git-step-by-step-from-file-to-commit" aria-label="Anchor">#</a></span></h2><p>Working with Git is a common task for developers. Different projects have different expectations on git should be used.
In the last months I had to upgrade my git skills and wanted to share some of the things I learned.</p>
<p>‼️ This post about what I learned additionally, therefore some basic git knowledge is assumed.</p>
<p>Within this blog post I mainly used the Git Book <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> and the O&rsquo;Reilly Course <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<h3 id="hashes-as-object-ids" class="relative group">Hashes as Object IDs <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#hashes-as-object-ids" aria-label="Anchor">#</a></span></h3><p>Git uses a lot of hashes of files referred to as Object IDs (OID).
Hash the content of the file. This hashing creates a unique (40 char) identifier for the content (using SHA-1). For two
files with the same content, the hash will be the same, the file name or location does not matter.
Adding two files with the same content will result in the same hash being created.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">&gt; cat README.md <span class="p">|</span> git hash-object --stdin
</span></span><span class="line"><span class="cl">0588748a531675ba06e473ae4d74532cdb2f94d3
</span></span></code></pre></div><h2 id="blob-is-one-git-object" class="relative group">Blob is one Git Object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#blob-is-one-git-object" aria-label="Anchor">#</a></span></h2><p>Git will create a blob in the <code>.git</code> directory with the hash as name and the zipped content of the file as content.
Git is a Content addressable file system, which means that the content of the file is used to determine the file
location.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">.git/objects
</span></span><span class="line"><span class="cl">├── 05
</span></span><span class="line"><span class="cl">│   └── 88748a531675ba06e473ae4d74532cdb2f94d3
</span></span><span class="line"><span class="cl">|       &#34;Blob of the file content (zipped)&#34;
</span></span><span class="line"><span class="cl">├── info
</span></span><span class="line"><span class="cl">└── pack
</span></span></code></pre></div><p>If multiple filed are added, one blob is created for each file. Two files with the same content will be added as one
blob. Editing a file will create a new blob with a new hash, the old blob will still be there. Without a commit, this
blob is not reachable, git only keeps history of committed files.
<strong>Git is Immutable</strong> - a blob cannot be changed, only new blobs can be created. The git garbage collector will remove
the blobs that are not referenced by any link eventually.</p>
<p>Git is not copying the files. Unchanged files are not copied, only the tree object is created with the hash of the blob
of the unchanged file pointing to one content.</p>
<h3 id="a-tree-is-a-git-object" class="relative group">A Tree is a Git Object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#a-tree-is-a-git-object" aria-label="Anchor">#</a></span></h3><p>To store the relation of the file name and the blob, git creates a tree object. A Tree object is a file that contains a
list in which the file type, file name, and the Hash Object ID. The Tree file hashed will again be the Object ID for the
tree, therefore it will also be the same if all file contents and the file names in the tree are the same.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">&gt; git write-tree
</span></span><span class="line"><span class="cl">2d66c1b551aae5efa0d242cc105b8531d3ae5e4b
</span></span><span class="line"><span class="cl">&gt; git cat-file -p 2d66c1b551aae5efa0d242cc105b8531d3ae5e4b
</span></span><span class="line"><span class="cl"><span class="m">040000</span> tree 9b6bc3d88d357e1f02cda9e279f0bc9a9c5c11a3	content
</span></span><span class="line"><span class="cl"><span class="m">040000</span> tree b8e6c8eb08befc5a0fde3b0c2821c806c7be2b36	public
</span></span><span class="line"><span class="cl"><span class="m">100644</span> blob 0588748a531675ba06e473ae4d74532cdb2f94d3	readme.md
</span></span><span class="line"><span class="cl"><span class="m">100644</span> blob 0588748a531675ba06e473ae4d74532cdb2f94d3	readme_copy.md
</span></span><span class="line"><span class="cl"><span class="m">040000</span> tree bac8dc35897c3fe58c6f3d321deea5ee7dfff50f	resources
</span></span></code></pre></div><p><code>git write-tree</code> creates a tree object from the staged files, this is usually done automatically when committing.
In the tree file, different files with the same content will point to the same hash (blob).
The output shows the tree object with the following structure:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">100644 blob 0588748a531675ba06e473ae4d74532cdb2f94d3	readme.md
</span></span><span class="line"><span class="cl">100644     -&gt; Git file Type (binary 1000 (regular file), 1010 (symbolic link) and 1110 (gitlink) 
</span></span><span class="line"><span class="cl">              and Linux file mode, binary authorization (0644/-rw-r--r--)
</span></span><span class="line"><span class="cl">blob       -&gt; The type of the object, in this case a blob. Subdirectories (like public) 
</span></span><span class="line"><span class="cl">              are modeled as trees. 
</span></span><span class="line"><span class="cl">0588748a...-&gt; The OID (Object ID), Hash of the blob
</span></span><span class="line"><span class="cl">readme.md  -&gt; The name of the file
</span></span></code></pre></div><p>While staged the tree objects are also added to the <code>.git/objects.</code> directory.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">.git/objects
</span></span><span class="line"><span class="cl">├── 2d   # The root tree object
</span></span><span class="line"><span class="cl">│   └── 66c1b551aae5efa0d242cc105b8531d3ae5e4b 
</span></span><span class="line"><span class="cl">├── 9b   # The tree object for the content directory
</span></span><span class="line"><span class="cl">│   └── 6bc3d88d357e1f02cda9e279f0bc9a9c5c11a3 
</span></span><span class="line"><span class="cl">├── b8   # The tree object for the public directory
</span></span><span class="line"><span class="cl">│   └── e6c8eb08befc5a0fde3b0c2821c806c7be2b36
</span></span><span class="line"><span class="cl">├── 05   # The blob object for the readme.md file
</span></span><span class="line"><span class="cl">│   └── 88748a531675ba06e473ae4d74532cdb2f94d3
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">├── info
</span></span><span class="line"><span class="cl">└── pack
</span></span></code></pre></div><h3 id="a-commit-is-a-git-object" class="relative group">A Commit is a Git Object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#a-commit-is-a-git-object" aria-label="Anchor">#</a></span></h3><p>Git creates a commit object, which again is a file containing the hash of a tree object, the hash of the parent commit,
an author and committer, and the commit message. The commit object also has a hash stored in the <code>.git/objects</code>
directory.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">❯ git cat-file -p 46cbcbdd595811bb59cbbc307d061dfaa7478a85
</span></span><span class="line"><span class="cl">  tree 6a58a71284938e520f1c21f24971dbe14821fbd7
</span></span><span class="line"><span class="cl">  parent 45dda006756054c4fd77fd9a0423a7033f21dbfd
</span></span><span class="line"><span class="cl">  author Sofia Fischer &lt;sofia@philodev.com&gt; <span class="m">1752449645</span> +0200
</span></span><span class="line"><span class="cl">  committer Sofia Fischer &lt;sofia@philodev.com&gt; <span class="m">1752449645</span> +0200
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  ✨ Post about bitemporal data
</span></span></code></pre></div><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Git allways commits the whole tree</strong>:
Every git commit contains the whole tree, not just the changes.
This means git can allways provide the repository in one point in time without calculating any stacking diffs.<br>
This behavior is the what did set git apart from other versin control systems in the past (although now alternatives
with this behavior exist)</span>
</div>

<h2 id="branches-heads-tags" class="relative group">Branches, Heads, Tags <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#branches-heads-tags" aria-label="Anchor">#</a></span></h2><h3 id="branches" class="relative group">Branches <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#branches" aria-label="Anchor">#</a></span></h3><p>A Branch is a named reference to a commit. The branches are stored in the <code>.git/refs/heads</code> directory.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">❯ ls .git/refs/heads
</span></span><span class="line"><span class="cl">master  bitemporal
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">❯ cat .git/refs/heads/master
</span></span><span class="line"><span class="cl">96b73cbfd9cb66356737ce3282986c2f8aa225b1
</span></span></code></pre></div><p>Deleting a branch will only delete the file with the reference to one commit. If the commit is not fully merged, this
might delete the only reference to the commit making the commit &ldquo;orphaned&rdquo; and unreachable.</p>
<h3 id="head" class="relative group">Head <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#head" aria-label="Anchor">#</a></span></h3><p>The head is a reference to the current branch. The head is stored in <code>.git/HEAD</code> and contains the name of the current
The head references the commit that will be the parent of the next commit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">❯ cat .git/HEAD
</span></span><span class="line"><span class="cl">ref: refs/heads/main
</span></span></code></pre></div><p>Head may also point to a commit directly, this is called a &ldquo;detached head&rdquo;. What sounds spooky, is actually a nice way
to travel back in time and look at the state of the repository at a specific commit. The reason why &ldquo;detached head&rdquo;
causes panic is that the next commit will not be on a branch, and will be orphaned if head is changed. It is a feature
of branches that they change on commit to point to the latest commit on the branch. So the solution is to just switch
back to a branch.</p>
<p>One way to &ldquo;save&rdquo; a commit in a detached head state is to add a tag to the commit. Tags are references to a specific
commit. Now when head is changed, the commit will not be orphaned, as the tag will still point to the commit.</p>
<h2 id="making-pretty-git-commits-in-practice" class="relative group">Making pretty Git Commits in Practice <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#making-pretty-git-commits-in-practice" aria-label="Anchor">#</a></span></h2><p>While the git commits of some developers look like the developer had a plan for their feature, which unfolded
flawlessly - one commit contained refactoring to make the change easy, one commit added unreachable new code with tests,
and one connected it in multiple places. The dream of every reviewer is most commonly not the result of a developer who
planned all actions upfront in perfection, but rather the result of using git to create readable, easy to review
commits.</p>
<h2 id="commiting-some-lines-of-a-file" class="relative group">Commiting some lines of a file <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#commiting-some-lines-of-a-file" aria-label="Anchor">#</a></span></h2><p>Many of the features I can implement start out as a single commit, but then I realise some refactoring that should go in
a separate commit.
Git allows to stage only parts of a file with <code>git add -p</code> or <code>git add --patch</code>. This will show the changes in the file
and allow you to select a subset of the changes to stage. For each patch of code git will ask you if you want to stage
it:</p>
<ul>
<li><code>y</code> - yes, stage this hunk</li>
<li><code>n</code> - no, do not stage this hunk</li>
<li><code>a</code> - stage this and all the remaining hunks in the file</li>
<li><code>d</code> - do not stage this hunk nor any of the remaining hunks in the file</li>
<li><code>g</code> - go to the selected hunk</li>
<li><code>/</code> - search for a hunk matching the given regex</li>
<li><code>j</code> - leave this hunk undecided, see next undecided hunk</li>
<li><code>J</code> - leave this hunk undecided, see next hunk</li>
<li><code>k</code> - leave this hunk undecided, see previous undecided hunk</li>
<li><code>K</code> - leave this hunk undecided, see previous hunk</li>
<li><code>s</code> - split the current hunk into smaller hunks</li>
<li><code>e</code> - edit the current hunk manually</li>
<li><code>?</code> - print help”</li>
</ul>
<p>In PyCharm (or Intellij) you can also stage parts of a file by selecting the lines you want to stage in the preview of
the commit dialog.</p>
<h2 id="change-something-in-a-commited-commit" class="relative group">Change something in a commited commit <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#change-something-in-a-commited-commit" aria-label="Anchor">#</a></span></h2><p>It is also possible to change something in a past commit to ensure a clean commit history. The easiest way to do this is
using <code>git commit --amend</code>. This will take the current staged changes and add them to the last commit. This is only
possible if the commit to change is the last commit.</p>
<p>If the commit is not further down the commit history, git allows to change a past commit by adding a new commit with the
message <code>fixup! &lt;commit message&gt;</code>. As an easier way to do this, you can use <code>git commit --fixup &lt;commit hash&gt;</code>, in the
GUI of PyCharm by right clicking on the commit to change and selecting &ldquo;Fixup commit&rdquo;.</p>
<p>As an example, to fix some spelling mistakes in a blog post <code>✨add post about bitemporal data</code> after I changed the some
internal things for my blog, I could end up with the following commits:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">d01fd6 fixup! ✨add post about bitemporal data
</span></span><span class="line"><span class="cl">c028f4 🚀 use go modules instead of git submodules
</span></span><span class="line"><span class="cl">b032c2 ✨add post about bitemporal data
</span></span></code></pre></div><p>The fixup commit will be squashed into the <code>b032c2</code> commit on interactive rebase or on merge if used with
<code>--autosquash</code>.</p>
<h2 id="interactive-rebase" class="relative group">Interactive Rebase <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#interactive-rebase" aria-label="Anchor">#</a></span></h2><p>Interactive rebase is a powerful tool to change the commit history. It allows you to reorder, squash, or edit commits.</p>
<p><code>git rebase -i &lt;commit hash&gt;</code> will open an editor with a list of commits starting from the given commit hash.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">&gt; git rebase --interactive 96b73cbfd9cb66356737ce3282986c2f8aa225b1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">pick 1e57725 <span class="c1"># ✨  Post about git</span>
</span></span><span class="line"><span class="cl">pick be9293c <span class="c1"># 🖋continue on git post</span>
</span></span><span class="line"><span class="cl">pick 3003a57 <span class="c1"># 🖋add disclaimer for git post</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rebase 96b73cb..3003a57 onto 96b73cb (3 commands)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Commands:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># p, pick &lt;commit&gt; = use commit</span>
</span></span><span class="line"><span class="cl"><span class="c1"># r, reword &lt;commit&gt; = use commit, but edit the commit message</span>
</span></span><span class="line"><span class="cl"><span class="c1"># e, edit &lt;commit&gt; = use commit, but stop for amending</span>
</span></span><span class="line"><span class="cl"><span class="c1"># s, squash &lt;commit&gt; = use commit, but meld into previous commit</span>
</span></span><span class="line"><span class="cl"><span class="c1"># f, fixup [-C | -c] &lt;commit&gt; = like &#34;squash&#34; but keep only the previous</span>
</span></span><span class="line"><span class="cl"><span class="c1">#                    commit&#39;s log message, unless -C is used, in which case</span>
</span></span><span class="line"><span class="cl"><span class="c1">#                    keep only this commit&#39;s message; -c is same as -C but</span>
</span></span><span class="line"><span class="cl"><span class="c1">#                    opens the editor</span>
</span></span><span class="line"><span class="cl"><span class="c1"># x, exec &lt;command&gt; = run command (the rest of the line) using shell</span>
</span></span><span class="line"><span class="cl"><span class="c1"># b, break = stop here (continue rebase later with &#39;git rebase --continue&#39;)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># d, drop &lt;commit&gt; = remove commit</span>
</span></span><span class="line"><span class="cl"><span class="c1"># l, label &lt;label&gt; = label current HEAD with a name</span>
</span></span><span class="line"><span class="cl"><span class="c1"># t, reset &lt;label&gt; = reset HEAD to a label</span>
</span></span></code></pre></div><p>Don&rsquo;t Panik - this is vim 😬 In this text file the pick can be replaced with for example <code>break</code> which will stop the
reabase at this commit and allow making changes to the commit. Also, the order of the commits can be changed.
With the decision what should be done with each commit, <code>:wq</code> will save the changes and exit the editor, and start the
rebase. If all the commits are picked, the rebase will continue without stopping as a regular rebase.
If there is a commit set to <code>break</code>, the rebase will stop at that commit, any changes can be made to the files; after
which I can add / stage the changes and continue the rebase with <code>git rebase --continue</code>.</p>
<p>Mind that creating a new commit in this stage will insert a new commit into the history before the commit that is
currently being edited.</p>
<p>In the GUI of PyCharm, the interactive rebase can be started by right-clicking on a commit and selecting &ldquo;Interactive
Rebase from here&rdquo;. The GUI will show a list of commits than can be reordered, or selected and breaked by clicking on
the &ldquo;pause&rdquo; button.
The IDE will then stop at the selected commit and allow to make changes to the files, then again adding and
continuing is also possible graphically (in the current version of PyCharm, the continue button is in the top left).</p>
<h2 id="why-the-fuzz-conclusion" class="relative group">Why the fuzz? Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#why-the-fuzz-conclusion" aria-label="Anchor">#</a></span></h2><p>Many of these features are not easy to learn, and feel spooky even the third time. Many people who use git find it hard
to understand and not very user-friendly - which is just true. Git is so unintuitively that it even has the concept of &quot;
porcelane commands&quot; which are commands that are easier to use and follow a mental model of git storing changes instead
of trees; and &ldquo;plumbing commands&rdquo; which are the commands that require understanding of how git works internally.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>There are alternatives</strong>: While git is the gold standard for version control, there are alternatives that build on top
of git, like <a href="https://jj-vcs.github.io/jj/latest/github/" target="_blank" rel="noreferrer">Jujutsu</a> which keep a much simpler mental model and detailed
operation history. It is build to edit past commits, without the need for interactive rebase; it provides a much nicer
UI by supporting things like &ldquo;undo&rdquo; (what a concept!), and it does not neet to separate between &ldquo;plumbing&rdquo; and &quot;
porcelain&quot; commands.</p>
<p>Looking into this is on my to-do list, but I am already missing the GUI of PyCharm to visualize the changes.</p>
</span>
</div>

<p>But there are reasons why an advanced usage of git is worth the effort:
A clean commit history provides information about how a file or repository evolved, which can be useful for new
developers or those who revisit their project after some time.
Clean commits in a Pull Request makes reviews much more understandable, and therefor easier and faster. It can separate
the steps taken to implement a feature, and allow to understand the reasoning behind the changes.
Also, I found it a good practice to split up the work in smaller steps that still all pass tests and work, makes my
implementation more reliable, easier to map in my head, and easier to debug.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://git-scm.com/book/en/v2" target="_blank" rel="noreferrer">Pro Git Book</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://www.oreilly.com/live-events/git-next-steps/0636920457459/" target="_blank" rel="noreferrer">Git Next Steps by Raju Gandhi</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Bitemporal Data: Timetravel your Data</title><link href="https://philodev.one/posts/2025-06-bitemporal-data/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2025-05-python-meta-programming/?utm_source=atom_feed" rel="related" type="text/html" title="Meta Programming in Python"/><link href="https://philodev.one/posts/2025-04-from-php-to-python/?utm_source=atom_feed" rel="related" type="text/html" title="Learning a new language - from PHP to Python"/><link href="https://philodev.one/posts/2024-10-queues-in-practice/?utm_source=atom_feed" rel="related" type="text/html" title="Consuming and Publishing to an external Service with Symfony Messenger"/><link href="https://philodev.one/posts/2024-07-writing-documentation/?utm_source=atom_feed" rel="related" type="text/html" title="Writing useful Documentation"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><id>https://philodev.one/posts/2025-06-bitemporal-data/</id><published>2025-07-10T10:20:44+02:00</published><updated>2025-07-10T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Bitemporal data is a way to store data that has two time dimensions - the actual time and the record time.</blockquote><div class="lead !mb-9 text-xl">
  Storing historic data becomes more complex if the historic data changes over time and if those changes
should be accessible. Bitemporal data is a way to store data that has two time dimensions: the actual time and the
record time.
</div>

<h2 id="from-temporal-data-to-bitemporal-state-data" class="relative group">From Temporal Data to Bitemporal State Data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#from-temporal-data-to-bitemporal-state-data" aria-label="Anchor">#</a></span></h2><h3 id="temporal-data" class="relative group">Temporal Data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#temporal-data" aria-label="Anchor">#</a></span></h3><p>Temporal data is data modelling historic changes of something. Most data in modern dataases is temporal data just by
storing a <code>created_at</code>. But intentionally temporal data is often implemented by a model having a <code>actual_from</code> and
<code>actual_to</code> properties (or <code>valid_to</code>, <code>active_to</code>, <code>ended_at</code> &hellip;), which correspond to non-overlapping time periods.</p>
<p>Some examples for this:</p>
<ul>
<li>Price tracking over time: The cupcake did cost 3,55€ in the last week, but this week the price was increased to 3,75€,
and on monday there will be a sale and it will only cost 3€</li>
<li>library book rental history: The book was rented by Ari from 01.03 until 01.04, nobody took it for a month, then Noa
took it and still has it.</li>
<li>Chameleon color change over time: The color was green yesterday, and today the color changed from green to magenta.</li>
</ul>
<p>From a technical point of view, this enables a nice implementation; a database constrain can ensure that there are no
overlapping time periods.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">datetime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ChameleonColor</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">actual_from</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span>
</span></span><span class="line"><span class="cl">    <span class="n">actual_to</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span><span class="p">:</span> <span class="nb">str</span>
</span></span></code></pre></div><h3 id="non-linear-data-reporting" class="relative group">Non linear data reporting <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#non-linear-data-reporting" aria-label="Anchor">#</a></span></h3><p>The moment the data becomes available not in a linear way, the simple temporal data model becomes more complex to
handle.
What if the information on what color the chameleon has arrives not at the moment it changes, but only as it has been
recorded to the system.</p>
<p>Keeping those reports can be necessary to proof what knowledge was present in a point in time, or just to
understand what has happened when an error occurred, or to being able to react to unreliable data that might be
canceled later.</p>
<p>This adds a new time dimension to the existing model: the point in time in which the actual information was recorded,
and the point in time in which the recorded time was overwritten by more recent data. The naming of those properties
vary (because naming is hard), a common combinations are <code>actual_from</code> and <code>recorded_at</code> coined by Martin
Fowler <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, <code>valid_from</code> and <code>recorded_at</code> coined by Richard Snodgrass <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">datetime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ChameleonColor</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">actual_from</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span>
</span></span><span class="line"><span class="cl">    <span class="n">actual_to</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">recorded_at</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span>
</span></span><span class="line"><span class="cl">    <span class="n">record_overwritten_at</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span>
</span></span></code></pre></div><h3 id="understanding-bitemporal-data" class="relative group">Understanding Bitemporal Data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#understanding-bitemporal-data" aria-label="Anchor">#</a></span></h3><p><strong>Do we need a <code>record_overwritten_at</code>?</strong></p>
<p>Just looking at a query to retrieve the state of the chameleon at a specific point in time, there is no need to add a
column that just records when a period was overwritten. But to utilize database constraints to ensure that there are no
overlapping time periods in the calculated reality, a <code>record_overwritten_at</code> that is <code>None</code> for the valid period makes
everything easier.</p>
<p><strong>How to read bitemporal data?</strong></p>
<p>Looking at an example of a chameleon that was recorded green at 2025-01-01, then changed to magenta at 2025-01-05, but
the system only recorded the change at 2025-01-09.</p>
<table>
  <thead>
      <tr>
          <th>actual_from</th>
          <th>actual_to</th>
          <th>color</th>
          <th>recorded_at</th>
          <th>record_overwritten_at</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>2025-01-01</td>
          <td>NULL</td>
          <td>green</td>
          <td>2025-01-01</td>
          <td>2025-01-09</td>
      </tr>
      <tr>
          <td>2025-01-01</td>
          <td>2025-01-05</td>
          <td>green</td>
          <td>2025-01-09</td>
          <td>NULL</td>
      </tr>
      <tr>
          <td>2025-01-05</td>
          <td>NULL</td>
          <td>magenta</td>
          <td>2025-01-09</td>
          <td>NULL</td>
      </tr>
  </tbody>
</table>
<p>The SQL query to retrieve the current state of the chameleon at 2025-01-07 would look like this and return <code>magenta</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">color</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="n">chameleon_color</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">WHERE</span><span class="w"> </span><span class="n">actual_from</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="s1">&#39;2025-01-07&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">AND</span><span class="w"> </span><span class="p">(</span><span class="n">actual_to</span><span class="w"> </span><span class="k">IS</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="k">OR</span><span class="w"> </span><span class="n">actual_to</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="s1">&#39;2025-01-07&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">AND</span><span class="w"> </span><span class="p">(</span><span class="n">record_overwritten_at</span><span class="w"> </span><span class="k">IS</span><span class="w"> </span><span class="k">NULL</span><span class="p">)</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span></span></span></code></pre></div><p>Visually, this can be represented as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">- - - - - - - - - - - - - - - -  Point in time imagine we are - now
</span></span><span class="line"><span class="cl">2025-01-09 ------█|██   magenta
</span></span><span class="line"><span class="cl">2025-01-09 -█████----   new green period
</span></span><span class="line"><span class="cl">2025-01-01 -░░░░░░|░░   green, invalidated
</span></span><span class="line"><span class="cl">                  ↑ Point in time we are looking for at 2025-01-07
</span></span></code></pre></div><p>The SQL query to retrieve the state of the chameleon at a specific point in time (like 2025-01-07) from the perspective
of one day later (2025-01-08) asking effectively &ldquo;it was 2025-01-07, which color would we think the chameleon had
yesterday?&rdquo; The SQL query would look something like this and return <code>green</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">color</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="n">chameleon_color</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">WHERE</span><span class="w"> </span><span class="n">actual_from</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="s1">&#39;2025-01-07&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">AND</span><span class="w"> </span><span class="p">(</span><span class="n">actual_to</span><span class="w"> </span><span class="k">IS</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="k">OR</span><span class="w"> </span><span class="n">actual_to</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="s1">&#39;2025-01-07&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">AND</span><span class="w"> </span><span class="n">recorded_at</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="s1">&#39;2025-01-08&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">AND</span><span class="w"> </span><span class="p">(</span><span class="n">record_overwritten_at</span><span class="w"> </span><span class="k">IS</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="k">OR</span><span class="w"> </span><span class="n">record_overwritten_at</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="s1">&#39;2025-01-08&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">recorded_at</span><span class="w"> </span><span class="k">ASC</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span></span></span></code></pre></div><p>Visually, this can be represented as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2025-01-09 ------█|██   magenta
</span></span><span class="line"><span class="cl">2025-01-09 -█████----   new green period
</span></span><span class="line"><span class="cl">- - - - - - - - - - - - - - - -  Point in time imagine we are at 2025-01-08
</span></span><span class="line"><span class="cl">2025-01-01 -░░░░░░|░░   green, invalidated
</span></span><span class="line"><span class="cl">                  ↑ Point in time we are looking for at 2025-01-07
</span></span></code></pre></div><p>Mind that we do not get the &ldquo;real&rdquo; state of the chameleon at 2025-01-07, but the state as the system thought it was.</p>
<p><strong>In case of a collision, should we add more rows or update?</strong></p>
<p>Looking at an example of trying to insert a new period, that should overwrite an existing period:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">A ------███-  more recent period
</span></span><span class="line"><span class="cl">B -███████--  old period
</span></span></code></pre></div><p>We could just split the old period, saving pressures database storage:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">A ------███-  more recent period
</span></span><span class="line"><span class="cl">B -█████----  valid part of old period
</span></span><span class="line"><span class="cl">B ------░---  invalid part of old period
</span></span></code></pre></div><p>While this works in theory, it is much harder to recalculate the reality of the data at a specific point in time.
What accountants use since centuries to add a new period for to replace invalid old data preserves the history of the
data. Making the rows immutable except for the <code>record_overwritten_at</code> column, allows much more trust in the
data ensures no data is lost.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">A ------███-  more recent period
</span></span><span class="line"><span class="cl">B -█████----  valid state old period
</span></span><span class="line"><span class="cl">B -░░░░░░░--  invalid state of old period
</span></span></code></pre></div><p><strong>How to insert an period</strong></p>
<p>An new period is inserted by</p>
<ul>
<li>find any collisions with existing periods</li>
<li>invalidate the existing, older periods by setting their <code>record_overwritten_at</code> to the new periods <code>recorded_at</code></li>
<li>insert new periods to represent the current actual state of the data with <code>recorded_overwritten_at</code> set to <code>NULL</code></li>
</ul>
<h2 id="inserting-bitemporal-data" class="relative group">Inserting Bitemporal Data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#inserting-bitemporal-data" aria-label="Anchor">#</a></span></h2><p>Inserting a new period in chronological order with always open-ended periods is easy: invalidate the existing period,
and create a new &ldquo;existing&rdquo; period that ends as the new period starts, and the new period.</p>
<p>But what if finite periods can be inserted in any order? Lets look at this example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2025-01-05 --█-------  teal
</span></span><span class="line"><span class="cl">2025-01-04 ------██--  turquoise
</span></span><span class="line"><span class="cl">- - - - - - - - - -  Point in time magenta is inserted spanning over the whole time
</span></span><span class="line"><span class="cl">2025-01-02 ██--------  green
</span></span><span class="line"><span class="cl">2025-01-01 ----█-----  blue
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">With new data
</span></span><span class="line"><span class="cl">2025-01-05 --█-------  teal
</span></span><span class="line"><span class="cl">2025-01-04 ------██--  turquoise
</span></span><span class="line"><span class="cl">- - - - - - - - -  
</span></span><span class="line"><span class="cl">2025-01-03 --------█-  magenta 
</span></span><span class="line"><span class="cl">2025-01-03 ---███----  magenta
</span></span><span class="line"><span class="cl">2025-01-03 -█--------  magenta
</span></span><span class="line"><span class="cl">2025-01-03 █---------  green
</span></span><span class="line"><span class="cl">2025-01-03 -░░░░░░░░-  magenta
</span></span><span class="line"><span class="cl">- - - - - - - - - 
</span></span><span class="line"><span class="cl">2025-01-02 ░░--------  green
</span></span><span class="line"><span class="cl">2025-01-01 ----░-----  blue
</span></span></code></pre></div><p>To insert the magenta period,</p>
<ul>
<li>the blue and green periods need to be invalidated, as they are older and colliding with the new period</li>
<li>the new magenta period needs to be inserted, but invalidated as there are more recent, colliding periods</li>
<li>a new green period needs to be inserted, because while the green period is partially colliding with the magenta
period, it started before the magenta period and is still valid until the start of the magenta period.</li>
<li>a new magenta period needs to be inserted to fill the gap between the green and teal period</li>
<li>a new magenta period needs to be inserted to fill the gap between the teal and turquoise period</li>
<li>a new magenta period needs to be inserted for the fraction of the magenta period that lasts longer than the turquoise
period.</li>
</ul>
<h3 id="types-of-collisions-side-quest" class="relative group">Types of Collisions (Side Quest) <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#types-of-collisions-side-quest" aria-label="Anchor">#</a></span></h3><p>Following a first thought, I wanted to go by the flow of time and deciding for each period if it is newer or older, and
what insertions or updates need to be performed.</p>
<p>The relationships between two periods can be one out of 13 defined relationships, mathematically defined by James
Allen [^snodgrass]. While periods can be ordered by many things (the length, the start, the end, creation date),
ordering by the start date leaves 7 relationship between each period and the next one.</p>
<table>
  <thead>
      <tr>
          <th>Relationship</th>
          <th>Visualisation</th>
          <th>Definition</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A before B</td>
          <td><code>A -███------</code> <br> <code>B ------███-</code></td>
          <td>A₂ &lt; B₁</td>
      </tr>
      <tr>
          <td>A meets B</td>
          <td><code>A -████-----</code> <br> <code>B -----██---</code></td>
          <td>A₂ = B₁</td>
      </tr>
      <tr>
          <td>A overlaps B</td>
          <td><code>A -████-----</code> <br> <code>B ----█████-</code></td>
          <td>A₁ &lt; B₁ AND B₂ &lt; A₂</td>
      </tr>
      <tr>
          <td>A equals B</td>
          <td><code>A ---████---</code> <br> <code>B ---████---</code></td>
          <td>A₁ = B₁ AND A₂ = B₂</td>
      </tr>
      <tr>
          <td>A starts B</td>
          <td><code>A ---███----</code> <br> <code>B ---██████-</code></td>
          <td>A₁ = B₁ AND A₂ &lt; B₂</td>
      </tr>
      <tr>
          <td>A finished by B</td>
          <td><code>A -██████---</code> <br> <code>B ------█---</code></td>
          <td>A₁ &lt; B₁ AND B₂ = A₂</td>
      </tr>
      <tr>
          <td>A contains B <br> (B is during A)</td>
          <td><code>A ---██████-</code> <br> <code>B ----███---</code></td>
          <td>A₁ &lt; B₁ AND B₂ &lt; A₂</td>
      </tr>
  </tbody>
</table>
<p>Out of the 7 relationships, 6 will result in a collision that needs to be handled, and will result in at least two rows
to be touched.
Considering that any in any the 6 relationships, any of the periods can be the newer one, there are 12 cases to handle -
a number of ifs that can quickly grow out of hand.</p>
<p>But looking at the complex example, the solution might be much simpler.</p>
<h3 id="handling-sets-of-collisions" class="relative group">Handling sets of collisions <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#handling-sets-of-collisions" aria-label="Anchor">#</a></span></h3><p>Instead of trying to handle each period individually, it is much easier to handle sets of periods that are colliding.</p>
<ol>
<li>The first set ist the set of all periods that are colliding with the new period, but are older and must be
invalidated.</li>
<li>There might be one period that started before the new period started, and was invalidated by the new period.
It has a fraction that must remain valid until the start of the new period. That fraction needs to be inserted as a
new valid period.</li>
<li>There might be one period that ended after the new period ended, and was invalidated by the new period.
It has a fraction that must remain valid after the end of the new period. That fraction needs to be inserted as a new
valid period.</li>
<li>Create the new period, valid if there are no newer periods colliding with the new period, otherwise invalid.</li>
<li>The last set consists of all periods that are colliding with the new period, but are more recent than the new period.
For each gab between those periods, a new period needs to be inserted that covers the gap and corresponds to the new
period.</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">datetime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">insert_period</span><span class="p">(</span><span class="n">actual_from</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">,</span> <span class="n">actual_to</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">color</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                  <span class="n">recorded_at</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">colliding_periods</span> <span class="o">=</span> <span class="n">queries</span><span class="o">.</span><span class="n">get_ordered_colliding_valid_periods</span><span class="p">(</span><span class="n">actual_from</span><span class="p">,</span> <span class="n">actual_to</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">colliding_older_periods</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">period</span> <span class="k">for</span> <span class="n">period</span> <span class="ow">in</span> <span class="n">colliding_periods</span> <span class="k">if</span> <span class="n">period</span><span class="o">.</span><span class="n">recorded_at</span> <span class="o">&lt;=</span> <span class="n">recorded_at</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">colliding_newer_periods</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">period</span> <span class="k">for</span> <span class="n">period</span> <span class="ow">in</span> <span class="n">colliding_periods</span> <span class="k">if</span> <span class="n">period</span><span class="o">.</span><span class="n">recorded_at</span> <span class="o">&gt;</span> <span class="n">recorded_at</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 1. invalidate all colliding periods that are older than the new period</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">period</span> <span class="ow">in</span> <span class="n">colliding_older_periods</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">period</span><span class="o">.</span><span class="n">recorded_at</span> <span class="o">&lt;=</span> <span class="n">recorded_at</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">period</span><span class="o">.</span><span class="n">recorded_overwritten_at</span> <span class="o">=</span> <span class="n">recorded_at</span>
</span></span><span class="line"><span class="cl">            <span class="n">period</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 2. check for start fraction of older periods</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">first_period</span> <span class="o">:=</span> <span class="n">colliding_older_periods</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="ow">and</span> <span class="n">first_period</span><span class="o">.</span><span class="n">actual_from</span> <span class="o">&lt;</span> <span class="n">actual_from</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">create_period</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">actual_from</span> <span class="o">==</span> <span class="n">first_period</span><span class="o">.</span><span class="n">actual_from</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">actual_to</span><span class="o">=</span><span class="n">start</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">color</span><span class="o">=</span><span class="n">first_period</span><span class="o">.</span><span class="n">color</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">recorded_at</span><span class="o">=</span><span class="n">recorded_at</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 3. check for end fraction of older periods</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">((</span><span class="n">last_period</span> <span class="o">:=</span> <span class="n">colliding_older_periods</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="ow">and</span> <span class="n">actual_to</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">            <span class="ow">and</span> <span class="p">(</span><span class="n">last_period</span><span class="o">.</span><span class="n">actual_to</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">last_period</span><span class="o">.</span><span class="n">actual_to</span> <span class="o">&gt;</span> <span class="n">actual_to</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">        <span class="n">create_period</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">actual_from</span><span class="o">=</span><span class="n">actual_to</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">actual_to</span><span class="o">=</span><span class="n">last_period</span><span class="o">.</span><span class="n">actual_to</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">color</span><span class="o">=</span><span class="n">last_period</span><span class="o">.</span><span class="n">color</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">recorded_at</span><span class="o">=</span><span class="n">recorded_at</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 4. create new period</span>
</span></span><span class="line"><span class="cl">    <span class="n">maybe_overwriten_at</span> <span class="o">=</span> <span class="n">colliding_newer_periods</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">recorded_at</span> <span class="k">if</span> <span class="n">colliding_newer_periods</span> <span class="k">else</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_period</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">actual_from</span><span class="o">=</span><span class="n">actual_from</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">actual_to</span><span class="o">=</span><span class="n">actual_to</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">recorded_at</span><span class="o">=</span><span class="n">recorded_at</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">record_overwritten_at</span><span class="o">=</span><span class="n">maybe_overwriten_at</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 5. handle gaps between newer periods</span>
</span></span><span class="line"><span class="cl">    <span class="n">fractions</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="n">current_start</span> <span class="o">=</span> <span class="n">actual_from</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">period</span> <span class="ow">in</span> <span class="n">colliding_newer_periods</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">current_start</span> <span class="o">&lt;</span> <span class="n">period</span><span class="o">.</span><span class="n">actual_from</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">fractions</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">current_start</span><span class="p">,</span> <span class="n">period</span><span class="o">.</span><span class="n">actual_from</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">period</span><span class="o">.</span><span class="n">actual_to</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">period</span><span class="o">.</span><span class="n">actual_to</span> <span class="o">&gt;</span> <span class="n">actual_to</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">fractions</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">current_start</span><span class="p">,</span> <span class="n">actual_to</span><span class="p">))</span>
</span></span></code></pre></div><h3 id="bitemporal-databases" class="relative group">Bitemporal Databases <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#bitemporal-databases" aria-label="Anchor">#</a></span></h3><p>These patterns do not feel like most relational database patterns. After some reasearch, I found databases that are
specialised to bitemporal data, like <a href="https://github.com/xtdb/xtdb" target="_blank" rel="noreferrer">XTDB</a>. The database is written in Clojure, and uses
event storage under the hood to handle second dimensions of time <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.
Looking at the pattern, the partial immutability of the data, and the inserting of new periods as new entries, even if
it to update existing data, id displays indeed many similarities to event sourcing.</p>
<h2 id="some-thoughts-on-downsides-of-bitemporal-data" class="relative group">Some Thoughts on downsides of Bitemporal Data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#some-thoughts-on-downsides-of-bitemporal-data" aria-label="Anchor">#</a></span></h2><p>Looking back at the example, inserting 5 rows for a new single new period is a lot. There is not really a way to
euphemise an algorithm that will worst case insert n + 1 rows for a new record, with n being the number of existing
records.
Tables of this bitemporal state data can grow very large, and the database will need to handle a lot of rows.
The patterns discussed here are not trivial, and do not match what at least I learned in university about normalized
databases.</p>
<p>But looking at alternatives; updating the rows and then handling all the case of overlapping periods will result in
an even more complex algorithm, and will provide less trust in the data. Also, this concept of bitemporal data is not
new, some sources I found date back to 2000, and there are many resources to find on the topic. Having the need for
bitemporal data, and trying to optimize for storage consumption, is a trade-off that will cost in readability,
complexity, and reasearchability of the used patterns - if you think otherwise I would be happy to hear your thoughts!</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Bitemporal data is always complex to wrap around.
The amount of articles and resources on this topic is extensive, and I did read through many of posts,
one book, and one podcasts to understand some more granular details of the patterns. They all use different
visualizations, often different namings, with mostly the same approaches to the problem. So while I am confident that
the approach I presented here is one proven way to handle bitemporal data.</p>
<p>The main inspiration for this article was Simeon (big thanks!), who phrased it in his talks as &ldquo;You understand
bitemporal data, until you don&rsquo;t. And when you need it, you understand it again&rdquo;.</p>
<p>This article, as all my public learnings, is my way to understand things, and hopefully have an easy time to
re-understand the concepts and patterns.</p>
<p>Happy coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://martinfowler.com/articles/bitemporal-history.html" target="_blank" rel="noreferrer">Martin Fowler on Bitemporal Data</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Developing Time-Oriented Database Applications in SQL (The Morgan Kaufmann Series in Data Management
Systems) by Richard T. Snodgrass&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://podcasts.apple.com/au/podcast/bitemporal-databases-what-they-are-and-why-they/id1687271887?i=1000616019962" target="_blank" rel="noreferrer">Clojure Podcast on XTDB</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="python" label="Python"/><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Meta Programming in Python</title><link href="https://philodev.one/posts/2025-05-python-meta-programming/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2025-04-from-php-to-python/?utm_source=atom_feed" rel="related" type="text/html" title="Learning a new language - from PHP to Python"/><link href="https://philodev.one/posts/2024-10-queues-in-practice/?utm_source=atom_feed" rel="related" type="text/html" title="Consuming and Publishing to an external Service with Symfony Messenger"/><link href="https://philodev.one/posts/2024-07-writing-documentation/?utm_source=atom_feed" rel="related" type="text/html" title="Writing useful Documentation"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><link href="https://philodev.one/posts/2024-09-o-auth-2/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding other oAuth flows"/><id>https://philodev.one/posts/2025-05-python-meta-programming/</id><published>2025-05-03T10:20:44+02:00</published><updated>2025-05-03T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Metaprogramming is a powerful tool in Python, but it should be used with caution. In this post, we will explore what Python can do with itself, and how it is used in frameworks.</blockquote><div class="lead !mb-9 text-xl">
  Metaprogramming is a powerful tool in Python, but it should be used with caution. In this post, we will explore what
Python can do with itself, and how it is used in frameworks.
</div>

<h2 id="meta-programming" class="relative group">Meta Programming <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#meta-programming" aria-label="Anchor">#</a></span></h2><p>As the name suggests, Metaprogramming means writing programs that interact with the code itself.</p>
<p>The most simple example is checking the type of a variable, so gathering information about the code at runtime, and
making decisions based of that. Especially when coding within a framework, there are many contact points with meta
programming, for example when using decorators that &ldquo;magically&rdquo; transform a function into a job, inheriting from a class
that &ldquo;magically&rdquo; transforms a class into a model that triggers migrations on change. Metaprogramming is a powerful tool,
especially when writing code that is used by other developers consuming their code, like a framework.</p>
<h3 id="when-to-use-it" class="relative group">When to use it? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#when-to-use-it" aria-label="Anchor">#</a></span></h3><p>Metaprogramming should be used with caution. It is often used to hide complexity from the developer who just wants to
use the magic. This hiding is what makes many frameworks so magically working without the need to understand the
internal processes. But on the other hand, it makes it really hard to go through the code, following the flow of data,
because it is hidden - objects or classes are touched, manipulated, or read at places where it is not expected.</p>
<p>It sometimes can be tempting to implement a program using metaprogramming, but it is often better to use simpler,
understandable code to ensure the next developer can continue.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Metaprogramming is a powerful hammer in a world with only very few nails. Use it with caution, if you are not developing
a framework, and your code aims to be maintainable, most likely you should use a different tool.</span>
</div>

<p>






  
  
<figure><img src="/images/2025-05-dark-magic.png" alt="Corgi warnging for dark magic" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="metaprogramming-in-python" class="relative group">Metaprogramming in Python <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#metaprogramming-in-python" aria-label="Anchor">#</a></span></h2><p>This post is strongly inspired by the Meta Programming Course by Trey Hunner <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<h3 id="introspection-i-want-to-know-about-the-technical-properties-of-an-object" class="relative group">Introspection: I want to know about the technical properties of an object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#introspection-i-want-to-know-about-the-technical-properties-of-an-object" aria-label="Anchor">#</a></span></h3><p>Python provides many built-in functions to introspect objects like does it have a certain attribute <code>hasattr</code>, what is
the type of the object <code>type</code>, what is the name of the class <code>__name__</code>, or is it callable <code>callable</code>. I would like to
highlight Annotated Properties, because they not only enable reading meta information about a property, but also a way
to add meta information to a class property.</p>
<p>An easy, somewhat common form of Metaprogramming, given meta information about a class property, that are stored
there using the Annotated Property. Using the <code>__annotations__</code> attribute of a class, you can get the annotation of a
class, and build therefore code based on how the other code is written or types.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Annotated</span><span class="p">,</span> <span class="n">get_args</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Magic</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">is_dark</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">is_dark</span> <span class="o">=</span> <span class="n">is_dark</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Wizard</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">wand</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="s2">&#34;magic&#34;</span><span class="p">,</span> <span class="n">Magic</span><span class="p">(</span><span class="kc">True</span><span class="p">)]</span> <span class="o">=</span> <span class="s2">&#34;Magic Staff&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">merlina</span> <span class="o">=</span> <span class="n">Wizard</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">annotation</span> <span class="o">=</span> <span class="n">merlina</span><span class="o">.</span><span class="vm">__annotations__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;wand&#34;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">annotation</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">magic</span><span class="p">,</span> <span class="n">Magic</span><span class="p">)</span> <span class="k">for</span> <span class="n">magic</span> <span class="ow">in</span> <span class="n">get_args</span><span class="p">(</span><span class="n">annotation</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Merlina can use magic!&#34;</span><span class="p">)</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">typing.Annotated[str, &#39;magic&#39;, &lt;__main__.Magic object at 0x1006bffd0&gt;]
Merlina can use magic!
</code></pre><h3 id="decorators-i-want-to-add-functionality-to-a-function" class="relative group">Decorators: I want to add functionality to a function <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#decorators-i-want-to-add-functionality-to-a-function" aria-label="Anchor">#</a></span></h3><p>Decorators are meta programmatic tools that diverge from the expected flow of the code. They are used to wrap around a
function (or class). A decorator is a function that takes another function as an argument and returns a new function
that adds some kind of behaviors. <sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>The wrapper function should be able to receive the same arguments as the original function, so it needs to hand down its
<code>*args, **kwargs</code> to the original function. It should also return the value of the original function.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">make_magic</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">magic_wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;✨Magic started ✨&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">value</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;✨Magic ended ✨&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">value</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">magic_wrapper</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">abracadabra</span><span class="p">(</span><span class="nb">input</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Abracadabra &#34;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="s2">&#34;!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">abracadabra</span> <span class="o">=</span> <span class="n">make_magic</span><span class="p">(</span><span class="n">abracadabra</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">abracadabra</span><span class="p">(</span><span class="s2">&#34;Hoc&#34;</span><span class="p">)</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">✨Magic started ✨
Abracadabra Hoc!
✨Magic ended ✨
</code></pre><p>Now the original <code>abracadabra</code> function is overwritten by the <code>magic_wrapper</code> function which contains the original
function. Python provides a syntactic sugar to make this easier, using the <code>@</code> symbol to decorate the function instead
of <code>abracadabra = make_magic(abracadabra)</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@make_magic</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">abracadabra</span><span class="p">(</span><span class="nb">input</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Abracadabra &#34;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="s2">&#34;!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">abracadabra</span><span class="p">(</span><span class="s2">&#34;Hic&#34;</span><span class="p">)</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">✨Magic started ✨
Abracadabra Hic!
✨Magic ended ✨
</code></pre><p>Decorators can be very versatile! They can be used to add functionality to a function, allow some meta information added
to the function, add a parameter, or (e.g. a decorator to skip a test) even to replace the function itself.</p>
<p>Mind the scopes, variables defined in the decorator are not available in the wrapper function, but Python allows adding
variables to</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">make_magic</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">magic_wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;✨Magic started ✨&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">value</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">magic_wrapper</span><span class="o">.</span><span class="n">mana</span> <span class="o">-=</span> <span class="nb">len</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">kwargs</span><span class="p">))</span> <span class="o">-</span> <span class="mi">6</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;✨Magic ended ✨Mana left: &#34;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">magic_wrapper</span><span class="o">.</span><span class="n">mana</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">value</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Mind the scopes! A variable defined in the decorator is not available in the wrapper function.</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Also avoid adding variables to the wrapped function (func) itself to avoid unexpected side effects. </span>
</span></span><span class="line"><span class="cl">    <span class="n">magic_wrapper</span><span class="o">.</span><span class="n">mana</span> <span class="o">=</span> <span class="mi">100</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">magic_wrapper</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@make_magic</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">abracadabra</span><span class="p">(</span><span class="nb">input</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;  A magic function that prints a message. &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Abracadabra &#34;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="s2">&#34;!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">abracadabra</span><span class="p">(</span><span class="s2">&#34;Mundus&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">abracadabra</span><span class="p">(</span><span class="s2">&#34;est&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">abracadabra</span><span class="p">(</span><span class="s2">&#34;magia&#34;</span><span class="p">))</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">✨Magic started ✨
Abracadabra Mundus!
✨Magic ended ✨Mana left: 93
✨Magic started ✨
Abracadabra est!
✨Magic ended ✨Mana left: 89
✨Magic started ✨
Abracadabra magia!
✨Magic ended ✨Mana left: 83
</code></pre><p>There is one problem with this approach: What looks like the original function is in fact a wrapper function. The
information of identity, DocStrings, etc is lost.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">help</span><span class="p">(</span><span class="n">abracadabra</span><span class="p">))</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">Help on function magic_wrapper in module __main__:

magic_wrapper(*args, **kwargs)
</code></pre><p>To avoid this, Python provides a <code>functools.wraps</code> decorator. This decorator is used to update the wrapper function with
all the attributes of the original function, including its name, docstring, and module. Internally it adds the original
function to the <code>__wrapped__</code> property of the wrapper function.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">wraps</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">make_magic</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nd">@wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">magic_wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;✨Magic started ✨&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">value</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;✨Magic ended ✨&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">value</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">magic_wrapper</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@make_magic</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">abracadabra</span><span class="p">(</span><span class="nb">input</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;  A magic function that prints a message. &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Abracadabra &#34;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="s2">&#34;!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">help</span><span class="p">(</span><span class="n">abracadabra</span><span class="p">))</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">Help on function abracadabra in module __main__:

abracadabra(input: str) -&gt; None
A magic function that prints a message.
</code></pre><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Be a nice developer and add <code>@wraps</code> to every decorator you implement. And reconsider the need for a decorator in the
first place.</span>
</div>

<p><strong>Decorators in Practice:</strong> Most frameworks use decorators to add functionality to functions or classes, even many
libraries. For example Celery <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> uses decorators to define tasks. Well written decorators are easy to find a
project by searching for <code>@wraps</code> in the code, so feel free to find out how your project uses decorators.</p>
<p><strong>Class Decorator</strong> work the same way, but instead of a function, a class is passed to the decorator, and a class is
returned. A common used Class Decorator is <code>@dataclass</code>, which returns the same class as was passed in, but with dunder
methods added.</p>
<h3 id="descriptors-i-want-to-control-how-a-class-attribute-is-accessed-or-modified" class="relative group">Descriptors: I want to control how a class attribute is accessed or modified <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#descriptors-i-want-to-control-how-a-class-attribute-is-accessed-or-modified" aria-label="Anchor">#</a></span></h3><p>Sometimes it is handy to have an attribute that is not just a simple value, but calculated based on another value, like
the radius of a circle and its area. Also it would be nice if the attribute could be set and the related value would
also update. Such a behavior can be implemented using a descriptor.</p>
<p>Descriptors are objects that define how attributes are accessed or modified. They are defined by a class that
implements either of the three methods <code>__get__</code>, <code>__set__</code>, or <code>__delete__</code> <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. A descriptor that
implements only the <code>__get__</code> method is called a non-data descriptor, while a descriptor that implements more is called
a data descriptor. To understand how descriptors work, it is important to understand how Python looks up attributes.</p>
<p>To understand how Python looks up attributes on an object the <code>__dict__</code> attribute of the object is used. This attribute
is a dictionary that contains the properties of the object, or if used on the type of the object, the class properties.
Instance properties override class properties.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Potion</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">milliliter</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">50</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;yellow&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">color</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">color</span> <span class="o">=</span> <span class="n">color</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">invisibility_potion</span> <span class="o">=</span> <span class="n">Potion</span><span class="p">(</span><span class="s2">&#34;magenta&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Instance Dict&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">invisibility_potion</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Class Dict&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">Potion</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">)</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">Instance Dict
{&#39;color&#39;: &#39;magenta&#39;}
Class Dict
{&#39;__module__&#39;: &#39;__main__&#39;, &#39;__annotations__&#39;: {&#39;milliliter&#39;: &lt;class &#39;int&#39;&gt;, &#39;color&#39;: &lt;class &#39;str&#39;&gt;}, &#39;milliliter&#39;: 50, &#39;color&#39;: &#39;yellow&#39;, &#39;__init__&#39;: &lt;function Potion.__init__ at 0x105751f30&gt;, &#39;__dict__&#39;: &lt;attribute &#39;__dict__&#39; of &#39;Potion&#39; objects&gt;, &#39;__weakref__&#39;: &lt;attribute &#39;__weakref__&#39; of &#39;Potion&#39; objects&gt;, &#39;__doc__&#39;: None}
</code></pre><p>In Python the logic of attribute lookup is implemented in C for performance reasons (after all, this code will run on
every attribute access). The Code can be found in
the <a href="https://github.com/python/cpython/blob/3e256b9118eded25e6aca61e3939fd4e03b87082/Objects/object.c#L1670" target="_blank" rel="noreferrer">CPython repository</a>
in a method called <code>_PyObject_GenericGetAttrWithDict</code>. But a pure Python implementation is provided in the Python
docs<sup id="fnref1:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">object_getattribute</span><span class="p">(</span><span class="n">instance</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="n">attribute</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34; Emulate PyObject_GenericGetAttr() in Objects/object.c &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">instances_type</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">instance</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">type_dict_at_attribute</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">instances_type</span><span class="p">,</span> <span class="s1">&#39;__dict__&#39;</span><span class="p">,</span> <span class="p">{})[</span><span class="n">attribute</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># NonData Descriptors are defined by implementing __get__ method</span>
</span></span><span class="line"><span class="cl">    <span class="n">has_non_data_descriptor</span> <span class="o">=</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">type_dict_at_attribute</span><span class="p">,</span> <span class="s1">&#39;__get__&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Data Descriptors are NonData Descriptors that implement __set__ or __delete__ method</span>
</span></span><span class="line"><span class="cl">    <span class="n">has_data_descriptor</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">has_non_data_descriptor</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">type_dict_at_attribute</span><span class="p">,</span> <span class="s1">&#39;__set__&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">type_dict_at_attribute</span><span class="p">,</span> <span class="s1">&#39;__delete__&#39;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">has_data_descriptor</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># if there is a Data Descriptor, return the result of its __get__ method</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">has_data_descriptor</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">type_dict_at_attribute</span><span class="o">.</span><span class="fm">__get__</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">instances_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># If the attribute is defined in the instance&#39;s __dict__, return it</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">attribute</span> <span class="ow">in</span> <span class="n">instance</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">instance</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">attribute</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># If there is a non-data descriptor, return the result of its __get__ method</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">has_non_data_descriptor</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">type_dict_at_attribute</span><span class="o">.</span><span class="fm">__get__</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">instances_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># If the attribute is defined in the class&#39;s __dict__,</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">attribute</span> <span class="ow">in</span> <span class="n">instances_type</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">instances_type</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">attribute</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="n">attribute</span><span class="p">)</span>
</span></span></code></pre></div><p><strong>Python Descriptors in Practice</strong> Descriptors are commonly used in Python to implement properties using the decorator
<code>@property</code>, which disguises the setter and getter methods into methods of the class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Potion</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">milliliters</span> <span class="o">=</span> <span class="mi">50</span>
</span></span><span class="line"><span class="cl">    <span class="n">usage_size</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">use</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">milliliters</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">milliliters</span> <span class="o">-=</span> <span class="bp">self</span><span class="o">.</span><span class="n">usage_size</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&#34;Potion is empty&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nd">@property</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">usages</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">milliliters</span> <span class="o">//</span> <span class="bp">self</span><span class="o">.</span><span class="n">usage_size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nd">@usages.setter</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">usages</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">milliliters</span> <span class="o">=</span> <span class="n">value</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">usage_size</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">invisibility_potion</span> <span class="o">=</span> <span class="n">Potion</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;I made 🧪 Potion with </span><span class="si">{</span><span class="n">invisibility_potion</span><span class="o">.</span><span class="n">milliliters</span><span class="si">}</span><span class="s2">ml&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">invisibility_potion</span><span class="o">.</span><span class="n">use</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;After using the potion, I have </span><span class="si">{</span><span class="n">invisibility_potion</span><span class="o">.</span><span class="n">milliliters</span><span class="si">}</span><span class="s2">ml left&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">invisibility_potion</span><span class="o">.</span><span class="n">usages</span> <span class="o">=</span> <span class="mi">20</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;After refilling the potion, I have </span><span class="si">{</span><span class="n">invisibility_potion</span><span class="o">.</span><span class="n">milliliters</span><span class="si">}</span><span class="s2">ml left&#34;</span><span class="p">)</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">I made 🧪 Potion with 50ml
After using the potion, I have 40ml left
After refilling the potion, I have 200ml left
</code></pre><p>An example of a data descriptor that abstracts logic away would be Djangos <code>ForeignKey</code> <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. While the developer
who wants to use the framework does not need to know how the <code>ForeignKey</code> works, they can use it like property, but
Django uses the descriptor to implement the retrival or storage of the related object in the database.</p>
<h3 id="metaclasses-i-want-to-create-a-new-type-and-control-how-classes-are-created" class="relative group">MetaClasses: I want to create a new Type and control how classes are created <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#metaclasses-i-want-to-create-a-new-type-and-control-how-classes-are-created" aria-label="Anchor">#</a></span></h3><p>All Types in Python are(Meta)Classes that inherit from <code>type</code>, but all instances of a Type are Classes.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Wizard</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;A wizard instance is: &#34;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">Wizard</span><span class="p">())))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Wizard class is a: &#34;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">Wizard</span><span class="p">)))</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">A wizard instance is: &lt;class &#39;__main__.Wizard&#39;&gt;
Wizard class is a: &lt;class &#39;type&#39;&gt;
</code></pre><p>Having a MeterClass allows to control how classes are created, for example if they are Singletons <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.
The usage of methods like <code>__new__</code> and <code>__init__</code> can be overwritten to control the creation of many classes.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">OrderOfWizards</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    The Maiar of the Order of Wizards may be found in many places,
</span></span></span><span class="line"><span class="cl"><span class="s2">    but wherever one class of Maiar is found, it will be always the same instance.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">wizards</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="s2">&#34;OrderOfWizards&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="n">wizard_class</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">str</span><span class="p">(</span><span class="n">wizard_class</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">wizard_class</span><span class="o">.</span><span class="n">wizards</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">wizard_class</span><span class="o">.</span><span class="n">wizards</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">wizard_class</span><span class="p">)]</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">OrderOfWizards</span><span class="p">,</span> <span class="n">wizard_class</span><span class="p">)</span><span class="o">.</span><span class="fm">__call__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">wizard_class</span><span class="o">.</span><span class="n">wizards</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">wizard_class</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Gandalf</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">OrderOfWizards</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;grey&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">gandalf</span> <span class="o">=</span> <span class="n">Gandalf</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;There he is, Gandalf the </span><span class="si">{</span><span class="n">gandalf</span><span class="o">.</span><span class="n">color</span><span class="si">}</span><span class="s2">!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">gandalf</span><span class="o">.</span><span class="n">color</span> <span class="o">=</span> <span class="s2">&#34;white&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">gandalf</span> <span class="o">=</span> <span class="n">Gandalf</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;There he is, Gandalf the </span><span class="si">{</span><span class="n">gandalf</span><span class="o">.</span><span class="n">color</span><span class="si">}</span><span class="s2">!&#34;</span><span class="p">)</span>
</span></span></code></pre></div><pre tabindex="0"><code class="language-terminaloutput" data-lang="terminaloutput">There he is, Gandalf the grey!
There he is, Gandalf the white!
</code></pre><p><strong>Metaclasses in practice:</strong> Django uses metaclasses to control models. The <code>Model</code> class that is extended by all models
has the BaseModel as MetaClass<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>. This class is used to handle Model metadata, like the database table or
the migration status.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>All these tools are powerful, and looking how frameworks use them to provide a magically smooth experience for the
developer can be inspiring. But it is important to understand, that many of these tools are not easy to understand
without knowing the underlying mechanics. They are hard to debug, it&rsquo;s not easy to follow the flow of code, and when not
implemented correctly, they can lead to unexpected behavior.</p>
<p>If you think about using them, ask yourself if you just want to use the magic like a dark magic apprentice, or if you
explicitly want to hide complexity from the developer who will use your code.</p>
<p>On this very post, Happy Understanding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.oreilly.com/live-events/python-metaprogramming-in-practice/0642572014596/" target="_blank" rel="noreferrer">Meta Programming by Trey Hunner</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://book.pythontips.com/en/latest/decorators.html" target="_blank" rel="noreferrer">Python Decorators in Python Tips</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html#django-first-steps" target="_blank" rel="noreferrer">Celery using Decorators</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://docs.python.org/3/howto/descriptor.html#descriptor-protocol" target="_blank" rel="noreferrer">Python Descriptors</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://github.com/django/django/blob/main/django/db/models/fields/related_descriptors.py" target="_blank" rel="noreferrer">Django ForeignKeys as Descriptors</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://python-course.eu/oop/metaclasses.php" target="_blank" rel="noreferrer">Meta Classes as Singletons</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://github.com/django/django/blob/main/django/db/models/base.py" target="_blank" rel="noreferrer">Django Models usage of Meta Classes</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="python" label="Python"/><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Learning a new language - from PHP to Python</title><link href="https://philodev.one/posts/2025-04-from-php-to-python/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-10-queues-in-practice/?utm_source=atom_feed" rel="related" type="text/html" title="Consuming and Publishing to an external Service with Symfony Messenger"/><link href="https://philodev.one/posts/2024-07-writing-documentation/?utm_source=atom_feed" rel="related" type="text/html" title="Writing useful Documentation"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><link href="https://philodev.one/posts/2024-09-o-auth-2/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding other oAuth flows"/><link href="https://philodev.one/posts/2024-08-o-auth/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding oAuth Authentication Code Flow"/><id>https://philodev.one/posts/2025-04-from-php-to-python/</id><published>2025-04-20T10:20:44+02:00</published><updated>2025-04-20T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Learning a new language is like learning a new way of thinking. It is not just about the syntax, but also about the patterns, the culture.</blockquote><div class="lead !mb-9 text-xl">
  Learning a new language is like learning a new way of thinking. It is not just about the syntax, but also about the
patterns, the culture.
</div>

<h2 id="changing-language" class="relative group">Changing Language <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#changing-language" aria-label="Anchor">#</a></span></h2><p>I have been coding in PHP since 2018 professionally, and after 6 years I am now switching to Python.</p>
<p>Coding in one language does mean more than knowing that syntax. Mastering a language meaning understanding pitfalls, how
some parts of the language work internally, what tools the language provides for meta programming; it includes knowing
the best practices, the accepted and unacceptable hacks, which style will be understood by the next developer and
what is too &ldquo;we don&rsquo;t to that in our language&rdquo;. Examples of what I mean by that are excessive use of
pass-by-references in PHP or &ldquo;Panic-driven&rdquo; GoLang Code.</p>
<p>The language influences the architecture, the usage of patterns, and the tools - and often underestimated: the projects.
Maybe there is a PHP Developer out there who never had to implement a Web Shop, but I guess they are as rare as Python
Developers who never implemented a Data Science project. Different languages have different ecosystems, different
specializations. Python has a strong Data Science and Machine Learning community, historically because of its
beginner-friendliness, to now owning established libraries for data manipulation and interpretation. While PHP still
dominates the web, historically started as template engine, growing whatever Wordpress is now, and powering many old and
new web projects.</p>
<p>






  
  
<figure><img src="/images/2025-04-python.png" alt="Corgi meeting a snake" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="the-different-levels-of-learning-a-new-language" class="relative group">The different levels of learning a new language <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-different-levels-of-learning-a-new-language" aria-label="Anchor">#</a></span></h2><p>First, how do you run the code, aka how do you get the &ldquo;Hello World&rdquo; on the screen? Is the common practice using a
docker container or a virtualenv to control language version? How do you install packages? How do you run the tests?
Which frameworks are common?</p>
<p>Supported by a nice coding AI, its about learning the syntax, the data structures, the libraries, and the tools. What
can you do with the langauge, where are limits and the pit falls? How are tests written and how does debugging work?</p>
<p>At some point, it is unavoidable to include the human factor. How doe the developers of the language think, what are the
common practices and patterns? How do they uses the given tools?</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>This is no tutorial</strong>: This are fractions of what I learned that I found interesting and wanted to share.</span>
</div>

<h3 id="python-data-structures" class="relative group">Python Data Structures <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#python-data-structures" aria-label="Anchor">#</a></span></h3><p>Typing: Typing always conveys intention, and in Python this can be done even more verbose than in PHP. Python provides
Generators, supports Union types, specialised Types like Literals, and Annotated Types.
Python Datastructures are so diverse and can convey so many intentions:  Is the content ordered like a list? May it not
contain duplicates like a set? Is it immutable like a tuple? Is it handled lazy like a generator? Does it have defaults
like a DefaultDict? Is it designed to be stored in a database like a flag? <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>Description</th>
          <th>Mutable</th>
          <th>Ordered</th>
          <th>Duplicates</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>List</td>
          <td>A collection that is meant to be iterated over or indexed, <code>[1, &quot;two&quot;]</code></td>
          <td>✅</td>
          <td>✅</td>
          <td>✅</td>
      </tr>
      <tr>
          <td>Range</td>
          <td>Immutable sequence of numbers and is commonly used for looping <code>list(range(0, 10, 3)) == [0, 3, 6, 9]</code></td>
          <td>❌</td>
          <td>✅</td>
          <td>✅</td>
      </tr>
      <tr>
          <td>Tuple</td>
          <td>Immutable collection, e.g. an extracted database row <code>(4, &quot;Ball Python&quot;, &quot;#EA387D&quot;)</code></td>
          <td>❌</td>
          <td>✅</td>
          <td>✅</td>
      </tr>
      <tr>
          <td>Set</td>
          <td>A collection free of duplicates, containing only immutable objects <code>{&quot;#EA387D&quot;, &quot;#003F23&quot;}</code></td>
          <td>✅</td>
          <td>❌</td>
          <td>❌</td>
      </tr>
      <tr>
          <td>FrozenSet</td>
          <td>Immutable Sets <code>frozenset(&quot;Frozen Snakey&quot;)</code></td>
          <td>❌</td>
          <td>❌</td>
          <td>❌</td>
      </tr>
      <tr>
          <td>Dictionary</td>
          <td>A key value structure, possibly nested like a json <code>{&quot;animal&quot;: &quot;Ball Python&quot;, &quot;name&quot;: &quot;Snickers&quot;}</code></td>
          <td>✅</td>
          <td>✅</td>
          <td>(🔑❌)</td>
      </tr>
  </tbody>
</table>
<p>Table infos from <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>Lists are the most common data structure as they support many operations that also make them easy to use stacks or
queues. Also they support the awesome list comprehensions to create lists almost in mathematical notation.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="p">[</span><span class="n">snake</span> <span class="k">for</span> <span class="n">snake</span> <span class="ow">in</span> <span class="n">snakes</span> <span class="k">if</span> <span class="n">snake</span><span class="o">.</span><span class="n">size</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">]</span>
</span></span></code></pre></div><p>As mutable data structures, they also cause one of the weirdest pitfalls: Python uses pass by reference, even
on function parameter defaults. The Python compiler will go through a function parameter with the default value
<code>[]</code> and will create a pointer to a list. If the function is called multiple times, the same pointer is used,
potentially reusing a filled list. Avoid this by using <code>None</code> as default value or use immutable data structures like
tuples. <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<h3 id="magic-methods" class="relative group">Magic Methods <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#magic-methods" aria-label="Anchor">#</a></span></h3><p>In Python there are magic methods that allow you to overload operators and define what happens with the Class on
casting, or how Classes can behave like a list or a dictionary - &ldquo;Dunder Methods&rdquo; (because &ldquo;Doubler Underscore&rdquo;)
Be careful with them - if it is not doubtlessly clear what the code does, the developer can not easily click on the
operator to check the behavior like with a non-magic function, eventually tracing down inheritances to find the magic
method to understand the code.</p>
<p>Nevertheless, they are a powerful tool to make the code more readable and to convey intention.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Snake</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">latin_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;Serpens&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">size</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">size</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;Constructor&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;String representation&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;&gt;-@&#34;</span> <span class="o">+</span> <span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">+</span> <span class="s2">&#34;---&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&#34;Snake&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;Add two snakes together with a + operator&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Snake</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&#34;Can only add Snake to Snake&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Snake</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">+</span> <span class="n">other</span><span class="o">.</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;Check if two snakes are equal&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Snake</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&#34;Can only compare Snake to Snake&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">size</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="s2">&#34;Snake&#34;</span><span class="p">,</span> <span class="s2">&#34;Snake&#34;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;Call the instance like a function&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">half_size</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Snake</span><span class="p">(</span><span class="n">half_size</span><span class="p">),</span> <span class="n">Snake</span><span class="p">(</span><span class="n">half_size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;Iterate over the snake like it is a list&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">segment</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">yield</span> <span class="n">Snake</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">index</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&#34;Snake&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;Get a segment of the snake like it is a dictionary&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">index</span> <span class="o">&gt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">IndexError</span><span class="p">(</span><span class="s2">&#34;Index out of range&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Snake</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span></code></pre></div><p>These are only a few examples of the magic methods that Python provides. Much more are listed here by Trey Hunner
<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<h3 id="typing" class="relative group">Typing <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#typing" aria-label="Anchor">#</a></span></h3><p>Python allows much more Typing options than PHP, while both support Type unions, None type, and casting (and magic
methods to cast), Python also has some special things.</p>
<p><strong>Type Alias</strong> Because Python Types are somewhat classes, you can create Type Aliases.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">Hydra</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">Snake</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">snakes</span><span class="p">:</span> <span class="n">Hydra</span> <span class="o">=</span> <span class="p">[</span><span class="n">Snake</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="n">Snake</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="n">Snake</span><span class="p">(</span><span class="mi">3</span><span class="p">)]</span>
</span></span></code></pre></div><p><strong>Type Hinted Functions</strong> Python supports Typed Functions, which I feel like a blessing, as it seems to be &ldquo;Pythonic&rdquo; to
hand over functions as parameters to make functions work in different use cases.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">feed</span><span class="p">(</span><span class="n">snake</span><span class="p">:</span> <span class="n">Snake</span><span class="p">,</span> <span class="n">food_count</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Snake</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">snake</span><span class="o">.</span><span class="n">size</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">snake</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">sleep</span><span class="p">(</span><span class="n">snake</span><span class="p">:</span> <span class="n">Snake</span><span class="p">,</span> <span class="n">days</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Snake</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">snake</span><span class="o">.</span><span class="n">size</span> <span class="o">-=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">snake</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">snake_care_methods</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">Callable</span><span class="p">[[</span><span class="n">Snake</span><span class="p">,</span> <span class="nb">int</span><span class="p">],</span> <span class="n">Snake</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[</span><span class="n">feed</span><span class="p">,</span> <span class="n">sleep</span><span class="p">]</span>
</span></span></code></pre></div><p><strong>Generics</strong> A feature PHP misses, Generics allow to define that a Type will stay consistent, for example that a
function that sorts a list of one type will also return a list of the same type, independent of the type.</p>
<p><strong>Annotated</strong> Python even allows adding more meta information to a Type, although this is often not checked by the type
checker, but it can be used with <code>ValueRange</code> or other self implemented classes, to give contexts like &ldquo;Is this
Percentage a float between 0 and 100, or 0 and 1?&rdquo;, or &ldquo;Does country refer to a country code or a country name?&rdquo;.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Annotated</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Snake</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">size</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="s2">&#34;Should be nice&#34;</span><span class="p">,]</span> <span class="o">=</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">severus</span> <span class="o">=</span> <span class="n">Snake</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">severus</span><span class="o">.</span><span class="vm">__annotations__</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&gt;&gt;</span> <span class="o">&gt;</span> <span class="p">{</span><span class="s1">&#39;size&#39;</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Annotated</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="s1">&#39;Should be nice&#39;</span><span class="p">]}</span>
</span></span></code></pre></div><h2 id="pythonic-culture" class="relative group">Pythonic Culture <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#pythonic-culture" aria-label="Anchor">#</a></span></h2><p>Code should be natural to interact with, which also means that if follows cultural conventions (which starts with
naming, but extends up to patterns). It means that it uses magic with caution, and is braced for misuse - which is
easiest if the developer is well-informed about how the language can be misused or what magic is common
knowledge. <sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>In Python there is so much possible. There are many conventions on how to solve common things, and while the fun part
about switching languages is sometimes challenging those conventions, there is also a lot to learn.
When to use dataclasses, when Attr, and when Pydentic <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>? Why to Python developers so rarely use Dependency
Injection, and how else do I solve Inverting Control Problems <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>? When to use Flags? Why is nobody
using match case?</p>
<p>What Pythonic is and what not is still something I am learning, but while many learnings in a new language can be
discovered in self-study; this is something that requires working in one project with other experienced developers.</p>
<h2 id="conclusion-stay-curious" class="relative group">Conclusion: Stay Curious <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion-stay-curious" aria-label="Anchor">#</a></span></h2><p>Looking back, it wasn&rsquo;t a big step, but in between it felt like one. In between, I can contribute with my
experiences of a different language and its patterns to architecture decisions, while at the same time asking questions
why my for loop doesn&rsquo;t work.</p>
<p>I am looking forward to share my experiences with learning Python.</p>
<p>Happy coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.oreilly.com/library/view/robust-python/9781098100650/" target="_blank" rel="noreferrer">Robust Python</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://docs.python.org/3/library/stdtypes.html" target="_blank" rel="noreferrer">Python Docs</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://www.pythonmorsels.com/mutable-default-arguments/" target="_blank" rel="noreferrer">Mutable Arguments and their problems</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://www.pythonmorsels.com/every-dunder-method/" target="_blank" rel="noreferrer">Magic Methods in Python</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://jackmckew.dev/dataclasses-vs-attrs-vs-pydantic.html" target="_blank" rel="noreferrer">Dataclass vs Attrs vs Pydantic</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://seddonym.me/2019/08/03/ioc-techniques/" target="_blank" rel="noreferrer">Dependency Injection in Python</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="python" label="Python"/><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Consuming and Publishing to an external Service with Symfony Messenger</title><link href="https://philodev.one/posts/2024-10-queues-in-practice/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-01-symfony-queues/?utm_source=atom_feed" rel="related" type="text/html" title="Symfony Messenger Component step by step"/><link href="https://philodev.one/posts/2024-04-event-sourcing/?utm_source=atom_feed" rel="related" type="text/html" title="Event Sourcing for long living projects"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="related" type="text/html" title="About Actions, Jobs, Repositories, Events"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><id>https://philodev.one/posts/2024-10-queues-in-practice/</id><published>2024-10-20T10:20:44+02:00</published><updated>2024-10-20T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Implementing a Queue Request / Response with Symfony Messenger to explore the benefits of asynchronous communication between services</blockquote><div class="lead !mb-9 text-xl">
  Implementing a Queue Request / Response with Symfony Messenger to explore the benefits of asynchronous communication
between services
</div>

<h2 id="queues" class="relative group">Queues <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#queues" aria-label="Anchor">#</a></span></h2><p>Queues are a way to manage asynchronous communication between different parts of a system.</p>
<p>Message queues are like a mailbox where messages are stored by one service, and independently / asynchronously picked up
by (another or the same) service for processing.</p>
<p>Queues come with great benefits:</p>
<ul>
<li>Decoupling of services of different technologies or even programming languages</li>
<li>Control of the flow of messages and therefore the system performance</li>
<li>Increase loose coupling and scalability</li>
</ul>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>How well is a Queue Performing?</strong> The main attributes to look at are the Queue Age (the age of the oldest message in
queue) and the Queue Size (the number of messages in the queue). A queue with one thousand messages doesn&rsquo;t need to be a
Problem if the oldest message is only a second</span>
</div>

<h3 id="amqp" class="relative group">AMQP <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#amqp" aria-label="Anchor">#</a></span></h3><p>AMQP 0-9-1 (Advanced Message Queuing Protocol) is a messaging protocol that enables conforming client applications to
communicate with conforming messaging middleware brokers, or</p>
<blockquote>
<p>A defined set of messaging capabilities called the &ldquo;Advanced Message Queuing Protocol
Model&rdquo; (AMQ model). The AMQ model consists of a set of components that route and store messages
within the broker service, plus a set of rules for wiring these components together.</p>
</blockquote>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 568 249"
      >
      <g transform='translate(8,16)'>
<text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='8' y='196' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='228' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='212' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='16' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='24' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='24' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='32' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='32' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='40' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='40' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='148' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='180' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='40' y='196' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='40' y='212' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='40' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='48' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='68' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='48' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='48' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='56' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='56' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='212' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='56' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='64' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='64' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='64' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='72' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='72' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='72' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='80' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='80' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='196' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='80' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='80' y='228' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='88' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='96' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='112' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='144' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='152' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='152' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='196' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='152' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='152' y='228' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='160' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'>E</text>
<text text-anchor='middle' x='160' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='212' fill='currentColor' style='font-size:1em'>E</text>
<text text-anchor='middle' x='160' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='168' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='212' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='168' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='176' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'>&gt;</text>
<text text-anchor='middle' x='176' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='212' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='184' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='184' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='148' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='180' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='184' y='196' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='184' y='212' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='184' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='192' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='192' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='212' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='192' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='200' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='212' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='200' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='208' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='212' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='208' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='216' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='216' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='224' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='196' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='224' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='224' y='228' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='232' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='272' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='280' y='116' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='296' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'>Q</text>
<text text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='352' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='352' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='196' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='352' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='352' y='228' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='360' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='20' fill='currentColor' style='font-size:1em'>Q</text>
<text text-anchor='middle' x='360' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='116' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='360' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='212' fill='currentColor' style='font-size:1em'>Q</text>
<text text-anchor='middle' x='360' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='368' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='368' y='132' fill='currentColor' style='font-size:1em'>&gt;</text>
<text text-anchor='middle' x='368' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='368' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='376' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='376' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='148' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='180' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='376' y='196' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='376' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='376' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='384' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='164' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='384' y='180' fill='currentColor' style='font-size:1em'>&lt;</text>
<text text-anchor='middle' x='384' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='384' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='392' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='392' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='392' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='400' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='400' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='400' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='400' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='196' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='400' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='400' y='228' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='408' y='164' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='408' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='164' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='416' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='164' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='424' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='432' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='432' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='164' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='440' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='164' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='456' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='464' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='164' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='472' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='480' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='480' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='480' y='164' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='480' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='196' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='480' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='480' y='228' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='488' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='20' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='488' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='164' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='488' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='212' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='488' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='496' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='164' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='496' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='496' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='504' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='504' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='212' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='504' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='20' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='512' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='512' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='148' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='180' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='196' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='512' y='212' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='512' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='520' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='520' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='20' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='528' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='212' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='528' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='536' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='536' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='544' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='196' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='544' y='228' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='552' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='552' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='552' y='196' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='552' y='212' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='228' fill='currentColor' style='font-size:1em'>┘</text>
</g>

    </svg>
  
</div>
<p>In the AMQP model messages are published to an exchange, a metaphorical letter box.
The Exchange routes the message to a queue based often on the routing key, or other defined rules.
A Binding is a link between an exchange and a queue, defining the routing rules for messages.
The Queue stores the message until a consumer retrieves it.
After the consumer processes the message, it acknowledges receipt, allowing the broker to remove the message from the
queue.</p>
<p>The AMQP model provides different types of exchanges:</p>
<ul>
<li><strong>Direct Exchange</strong>: Routes messages with a routing key are routed to a queue with the same name.</li>
<li><strong>Fanout Exchange</strong>: Routes messages to all queues bound to it, regardless of the routing key.</li>
<li><strong>Topic Exchange</strong>: Routes messages to one or more queues based on wildcard matches between the routing key and the
queue names.</li>
</ul>
<p>The protocol itself is implemented by various brokers, such as RabbitMQ, or Kafka. A broker is a service that
receives, stores, and forwards messages.</p>
<h2 id="implementing-a-queue-request--response-with-symfony-messenger" class="relative group">Implementing a Queue Request / Response with Symfony Messenger <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#implementing-a-queue-request--response-with-symfony-messenger" aria-label="Anchor">#</a></span></h2><p>Symfony Messenger provides a powerful way to handle message. I very much enjoyed going through the implementation in
more detail in a previous post <a href="https://philodev.one/posts/2024-01-symfony-queues/">The Symfony Messanger step by step</a>.</p>
<p>While the Symfony documentation<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> works out of the box for having one queue with the Php Application
producing and consuming all messages, to utilize the main benefit of queues I had to look through some documentation or
examples to understand what was happening.</p>
<p>The use case I want to cover is that I want to produce a message in my application and dispatch it so that a different
service can consumes it, and again dispatches the result for my application to consume.
In use cases of very long processing times I found this solution to be very useful instead of an HTTP request.</p>
<h3 id="dispatching-the-request-to-a-queue" class="relative group">Dispatching the Request to a Queue <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#dispatching-the-request-to-a-queue" aria-label="Anchor">#</a></span></h3><p>In Symfony the only requirement for a message is that it can be serialized.
I want <code>RequestMessage</code> to be produced by my application, but a different service will consume it.</p>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">readonly class RequestMessage
{
    public function __construct(public string $content)
    {
    }
}
</code></pre><p>To dispatch the message, I need to inject the <code>MessageBusInterface</code> into a Service from which I will dispatch
the message.</p>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">class RequestMessageClient
{
    public function __construct(private MessageBusInterface $bus) {}
    
    public function __invoke(RequestMessage $message)
    {
        $this-&gt;bus-&gt;dispatch($message);
    }
}
</code></pre><h3 id="listening-to-the-response-message" class="relative group">Listening to the Response Message <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#listening-to-the-response-message" aria-label="Anchor">#</a></span></h3><p>I can again have any serializable class as <code>ResponseMessage</code>.</p>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">readonly class ResponseMessage
{
    public function __construct(public string $content, public int $code)
    {
    }
}
</code></pre><p>The only special thing on the Listener is that I need to define the transport from which it will consume messages.</p>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">#[AsMessageHandler(fromTransport: &#39;external_messages&#39;)]
class ResponseMessageListener
{
    public function __invoke(ResponseMessage $message)
    {
        // ... do some business
    }
}
</code></pre><h3 id="wiring-the-transport-in-symfony-config" class="relative group">Wiring the Transport in Symfony config <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#wiring-the-transport-in-symfony-config" aria-label="Anchor">#</a></span></h3><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># config/packages/messenger.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">framework</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">parameters</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">amqp_dsn</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;amqp://gues:guest@rabbitmq:5672/&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">messenger</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">transports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">internal_messages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="l">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">external_messages</span><span class="p">:</span><span class="w"> </span><span class="c"># (1)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">dsn</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;%amqp_dsn%&#39;</span><span class="w"> </span><span class="c"># (2)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">serializer</span><span class="p">:</span><span class="w"> </span><span class="l">App\Serializer\ExternalMessageSerializer </span><span class="w"> </span><span class="c"># (3)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">options</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">exchange</span><span class="p">:</span><span class="w"> </span><span class="c"># (4)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;queue.external&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">topic</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c"># The Messages I dispatch from this transport will have this routing key</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">default_publish_routing_key</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;queue.external.request&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">queues</span><span class="p">:</span><span class="w"> </span><span class="c"># (5)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c"># I don&#39;t want to consume our own messages</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c"># queue.external.request:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c">#   binding_keys: [&#39;queue.external.request&#39;]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">queue.external.response</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">binding_keys</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s1">&#39;queue.external.response&#39;</span><span class="w"> </span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">routing</span><span class="p">:</span><span class="w"> </span><span class="c"># (6)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># I want to send my RequestMessage to the external_messages queue</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">&#39;App\Message\RequestMessage&#39;</span><span class="p">:</span><span class="w"> </span><span class="l">external_messages</span><span class="w">
</span></span></span></code></pre></div><ol>
<li>Define the transport for external messages. There might be already a transport defined for internal messages, or a
synchron transport for testing.</li>
<li>Define the DSN for the RabbitMQ server. I did assume there is a (Docker) RabbitMQ server running.</li>
<li>The default Serializer will deserialize based on fully classified class names. When working with other services this
is no option; independently it is a great feature to have an Anti Corruption Layer. The solution is a custom Message
Serializer. Just in case, this step is missing when error message appears
<code>Could not decode message using PHP serialization</code>.</li>
<li>The exchange, so the postbox for messages, is defined here. I want to use a topic exchange, because I want to use the
same exchange for dispatching and consuming my messages. I defined the routing key for the messages I will dispatch,
so the exchange can route them correctly to the queue that will store my requests.</li>
<li>The queues that will be used for consuming messages are defined here. I want to consume the response messages, but I
don&rsquo;t want to consume my own request messages.</li>
<li>The routing defines which transport will be used for which dispatched message class. I maybe want to use my internal
message queue by default, and only send my <code>RequestMessage</code> to the external transport.</li>
</ol>
<h3 id="the-messageserializer" class="relative group">The MessageSerializer <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-messageserializer" aria-label="Anchor">#</a></span></h3><p>The majority the Serializer is shamelessly copied from the Symfony Messanger Serializer <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, and there
is for sure a cleaner solution to handle the serialization of the stamps.</p>
<p>Also other blogs provided a simpler solution without stamps<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">use App\Message\ResponseMessage;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface as MessageSerializerInterface;
use Symfony\Component\Serializer\SerializerInterface;

class ExternalMessageSerializer implements MessageSerializerInterface
{
    private const STAMP_HEADER_PREFIX = &#39;X-Message-Stamp-&#39;;

    public function __construct(private SerializerInterface $serializer)
    {
    }
    
     /**
     * Decodes an envelope and its message from an encoded-form.
     *
     * The `$encodedEnvelope` parameter is a key-value array that
     * describes the envelope and its content, that will be used by the different transports.
     *
     * @throws MessageDecodingFailedException
     */
    public function decode(array $encodedEnvelope): Envelope
    {
        $body = $encodedEnvelope[&#39;body&#39;];

        try {
            $message = $this-&gt;serializer-&gt;deserialize($body, ResponseMessage::class, &#39;json&#39;);
        } catch (\Throwable $throwable) {
            throw new MessageDecodingFailedException($throwable-&gt;getMessage())
        }

        $stamps = [];
        foreach ($encodedEnvelope[&#39;headers&#39;] as $name =&gt; $value) {
            if (!str_starts_with($name, self::STAMP_HEADER_PREFIX)) {
              continue;
            }
            
            try {
                $stamps[] = $this-&gt;serializer-&gt;deserialize($value, substr($name, \strlen(self::STAMP_HEADER_PREFIX)).&#39;[]&#39;, &#39;json&#39;);
            } catch (ExceptionInterface $e) {
                throw new MessageDecodingFailedException(&#39;Could not decode stamp: &#39;.$e-&gt;getMessage(), $e-&gt;getCode(), $e);
            }
        }

        return new Envelope($message, $stamps);
    }

    /**
     * Encodes an envelope content (message &amp; stamps) to a common format understandable by transports.
     * The encoded array should only contain scalars and arrays.
     *
     * Stamps that implement NonSendableStampInterface should not be encoded.
     */
    public function encode(Envelope $envelope): array
    {
        return [
            &#39;body&#39; =&gt; $this-&gt;serializer-&gt;serialize($envelope-&gt;getMessage(), &#39;json&#39;),
            &#39;headers&#39; =&gt; [
                &#39;type&#39; =&gt; get_class($envelope-&gt;getMessage()),
                &#39;stamps&#39; =&gt; $this-&gt;serializer-&gt;serialize($envelope-&gt;all(), &#39;json&#39;),
            ],
        ];
    }
}
</code></pre><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">The MessageSerializer <code>@throws MessageDecodingFailedException</code> if the message cannot be decoded.
Throwing this exception will remove the message from the queue.
Any other exception will trigger a retry.</span>
</div>

<h3 id="testing" class="relative group">Testing <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#testing" aria-label="Anchor">#</a></span></h3><p>Debugging with queues is a great way to ensure that your messages are being sent and received correctly.
And also a nice way to document the process.</p>
<p>This is more of an integration test, I would prefer to have dedicated tests with the test transport.</p>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">class RequestMessageTest extends KernelTestCase
{
    public function testRouting(): void
    {
        /** @var AmqpTransport $transport */
        $transport = $this-&gt;getContainer()-&gt;get(&#39;messenger.transport.external_messages&#39;);
        
        $response = new ResponseMessage(&#39;Hello World&#39;, 200);
        
        // Send the response message to the queue with a routing key so that my transport can consume it
        $transport-&gt;send(new Envelope($response), [new AmqpStamp(&#39;queue.external.response&#39;)]);
        
        // Check if the message is consumed by the transport
        $envelope = iterator_to_array($transport-&gt;get())[0];
        $this-&gt;assertSame($response, $envelope-&gt;getMessage());
        $transport-&gt;ack($envelope);
    }
    
    public function testDispatching(): void
    {
        /** @var AmqpTransport $transport */
        $transport = $this-&gt;getContainer()-&gt;get(&#39;messenger.transport.external_messages&#39;);
        
        $request = new RequestMessage(&#39;Hello World&#39;);
        $client = $this-&gt;getContainer()-&gt;get(RequestMessageClient::class);
        $client($request);

        // Check that there is no consumable message
        $this-&gt;assertEmpty(iterator_to_array($transport-&gt;get()));
        
        // Check that the message is consumable by the other queue
        $envelope = iterator_to_array($transport-&gt;getFromQueues([&#39;queue.external.request&#39;]))[0];
        $this-&gt;assertSame($request, $envelope-&gt;getMessage());
        $transport-&gt;ack($envelope);
    }
}
</code></pre><h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Working with queues is a great way to decouple services and to ensure that your application can handle a high load of
requests. I definitely learned some things about the Symfony configuration and how it reflects in the RabbitMQ options.
Also, I am amazed by how easily the messages can be tested.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://symfony.com/doc/current/messenger.html" target="_blank" rel="noreferrer">Symfony Messenger</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://github.com/symfony/symfony/blob/7.1/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php" target="_blank" rel="noreferrer">Symfony Messenger Serializer</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://medium.com/@sfmok/consume-external-messages-using-symfony-messenger-92f7490d1194" target="_blank" rel="noreferrer">Consume External Messages Using Symfony Messenger</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="symfony" label="Symfony"/><category scheme="taxonomy:Tags" term="queue" label="Queue"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Writing useful Documentation</title><link href="https://philodev.one/posts/2024-07-writing-documentation/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-05-agile-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="Agile Software Architecture"/><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="📚 Book takeaways: Building Evolutionary Architecture"/><link href="https://philodev.one/posts/2024-09-o-auth-2/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding other oAuth flows"/><link href="https://philodev.one/posts/2024-08-o-auth/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding oAuth Authentication Code Flow"/><link href="https://philodev.one/posts/2024-04-event-sourcing/?utm_source=atom_feed" rel="related" type="text/html" title="Event Sourcing for long living projects"/><id>https://philodev.one/posts/2024-07-writing-documentation/</id><published>2024-10-06T10:20:44+02:00</published><updated>2024-10-06T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Exploring useful, well written, up-to-date documentation to get away from the outdated mess.</blockquote><div class="lead !mb-9 text-xl">
  Docs, or it didn&rsquo;t happen.
</div>

<p>Documentation can determine how fast new developers can be onboarded, how easy consumers can answer their questions, and
can serve as public communication point between team and product or other teams - it is both time saver and opportunity
provider. It may be well-structured, even interesting to read, the start of discussion points for feature development,
consumed for automation (like Open Api files), or on the other hand, it can be a mess of outdated information.</p>
<h2 id="the-readers-perspective" class="relative group">The Readers Perspective <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-readers-perspective" aria-label="Anchor">#</a></span></h2><p>Documentation is always written for somebody and to answer their question - not the curiosity of the writer.</p>
<ul>
<li><strong>Know Your Audience</strong> : Define audience by roles with certain knowledge. For example, a developer that just
started in the company; a backend developer of a different team; a product owner &hellip;</li>
<li><strong>Understand the Audience&rsquo;s Needs</strong> : What do they want? Meeting the needs of the audience is the primary goal of
documentation.</li>
<li><strong>Know what you want from the audience</strong> : Do you need them to make decisions? Do you want them to understand the
system? Do you want them to use the system?</li>
<li><strong>Understand the Audience&rsquo;s Knowledge</strong> : Experts often suffer from the curse of knowledge, which means that their
expert understanding of a topic ruins their
explanations to newcomers. What is their technical understanding? What is their domain knowledge? What
diagrams can they understand?</li>
</ul>
<p>The best documentation is written by a person with empathy for their audience. Understanding the audience is key to
communication. How much does the audience know about the topic? Does the audience know about similar topics, which
analogies can they understand? Does the audience know the stated, but hasn&rsquo;t used the knowledge since some time? Does
your audience have out of date knowledge? What is the audience&rsquo;s motivation to read the documentation? What does the
audience need to learn to accomplish their goal? Does the audience need to act in a certain order?  <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Written communication holds all the complexity of spoken communication. Humans will always interpret the text, and will
resist any message if they think their needs are not understood. Dropping empathy in business communication is not
constructive, demonstrating understanding and alignment of goals is. Persuasion is progress.</span>
</div>

<p>For every audience, the documentation should follow a <strong>narrative</strong>. When deciding on the structure of a documentation (
and even the structure of each diagram or chapter in it), consider drafting a narrative as guidance.
Example narratives could be <strong>a Success Story</strong> how a solution was implemented successfully, <strong>a Failure Story</strong> how a
solution failed and what lessons were learned, <strong>a Use Case</strong> a visualisation on how the system is used, <strong>a Clarity
Story</strong> to expain why a decision was made.</p>
<h3 id="accessibility" class="relative group">Accessibility <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#accessibility" aria-label="Anchor">#</a></span></h3><p><strong>Accessibility is Inclusiveness</strong> : The curb cut effect describes how designing for accessibility benefits everyone.
Originally, curb cuts (sidewalk ramps) were designed for people in wheelchairs. However, many people benefit from curb
cuts, such as anyone with a stroller, suitcase, or delivery cart. <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>Accessibility in documentation means that the documentation is usable by everyone, including people who are colorblind,
using an uncommon screen ratio, who have problems reading unstructured text due to neurodiversity, or have any other
form of impairment possible in the audience. Things to consider could be: <sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<ul>
<li>Do not rely on color alone to convey information (additionally form, text, or symbols). Pay attention to contrast and
color choices in pictures or diagrams. Use tools like <a href="https://colororacle.org/" target="_blank" rel="noreferrer">Color Oracle</a>to simulate color
blindness.</li>
<li>Mind the device that the audience is using. Especially for phones or screen readers using tables can make the
information harder to access.</li>
<li>Structure the text using linkable headings. Use paragraphs for related ideas, and use the first paragraph in a chapter
to communicate the main idea, as readers pay more attention to the first paragraph. Use Clear language (easy to read,
listen to, and translate)</li>
<li>Provide an alternative text for images that explain images in the context of the text.</li>
<li>Use Inclusive language and examples.</li>
</ul>
<p><strong>Keep your writing culturally neutral</strong> : &ldquo;Piece of cake&rdquo; and &ldquo;Bob&rsquo;s your uncle&rdquo; are culturally specific idioms that
can only be understood by people from certain cultural backgrounds.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Accessibility also refers to the availability of skills of the audience. When there is only a subset of people that
can read UML Diagrams, that parts of documentation are not accessible to the whole audience. If there are even less
people who can write UML Diagrams, the documentation is prone to become stale.</span>
</div>

<h3 id="feedback-loops" class="relative group">Feedback loops <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#feedback-loops" aria-label="Anchor">#</a></span></h3><p>Get feedback early and often from multiple audiences. Get feedback on small parts as well as the overall design.
Identify errors and misunderstandings early, when they were not yet repeated in the documentation. Ensure alignment with
business. Identify risks and challanges early. <sup id="fnref2:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p><strong>Establish a dialogue with the audience</strong>. Documentation can have a formal pull request process, scrum reviews can also
present documentation.</p>
<p>Focus your feedback requests on useful and representable picks of the audience. Generic feedback is not helpful, but
regular contact with the audience can help to understand their needs and to adjust the documentation to them.</p>
<h2 id="technical-writing" class="relative group">Technical Writing <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#technical-writing" aria-label="Anchor">#</a></span></h2><h3 id="terminology" class="relative group">Terminology <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#terminology" aria-label="Anchor">#</a></span></h3><p>Naming things is hard. Every project should take away one thing from Domain Driven Design - the ubiquitous language that
is shared between developers and users, and listed in the documentation. The language should be consistent, as simple
and precise as possible (like <code>invoiceSum</code> instead of <code>commutativeTotalSum</code>), best if the terms are &ldquo;googleable&rdquo;.
Consider that some part of the audience are using a translation tool, using simple language avoids translation errors.
When possible introduce (or link to the glossary) new terminology in the beginning of the paragraph that rely on
them. <sup id="fnref1:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>While one central point &ldquo;glossary&rdquo; for the ubiquitous language can help the users and the developers.</p>
<p>Acronyms should be avoided. They do not provide any benefits, but only the opportunity for misunderstandings.</p>
<h3 id="writing-style" class="relative group">Writing Style <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#writing-style" aria-label="Anchor">#</a></span></h3><p>The first paragraph of a Documentation page should state the audience, topic and goal of the page.</p>
<p><strong>Answer what, why, and how</strong> : Good paragraphs answer these three questions:
What are you trying to tell your reader?
Why is it important for the reader to know this?
How should the reader use this knowledge? Alternatively, how should the reader know your point to be true?</p>
<blockquote>
<p><strong>Minto Pyramid Principle</strong> The easiest order for a reader is to receive the major, more abstract ideas before he is
required to take in the minor supporting ones. And since the major ideas are always derived from the minor ones, the
ideal structure of the ideas will always be a pyramid of groups of ideas tied together by a single overall
thought.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
</blockquote>
<ul>
<li>Adopt a style guide</li>
<li>Replace this or that with the appropriate noun.</li>
<li>Prefer active voice to passive voice <code>The Code is interpreted by Python, but the code is compiled by C++</code> vs
<code>Python interprets the code, but C++ compiles the code</code></li>
<li>Reduce there is / there are
<code>There are setences starting with &quot;there is&quot; or &quot;there are&quot; that should be avoided or rewritten to replace the generic topic with a more specific one</code>
vs
<code>Sentences starting with &quot;there is&quot; or &quot;there are&quot; should be avoided or rewritten to replace the generic topic with a more specific one</code></li>
<li><strong>Keep it short</strong> - Shorter documentation reads faster. Focus each sentence on a single idea and break up long
sentences into lists.xf</li>
</ul>
<h3 id="diagrams" class="relative group">Diagrams <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#diagrams" aria-label="Anchor">#</a></span></h3><p>An audience should be guided from high abstraction to detailed information, using diagrams with intention and without
clutter. <sup id="fnref3:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p><strong>Keep the Abstraction level consistent</strong> : Levels of abstraction refer to the granularity of the information presented.
Mixing abstraction levels can confuse readers, and depending on the audience turn a diagram unreadable.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>C4 Model Hierarchy of abstraction</strong> describes the four levels of abstraction for software architecture diagrams:</p>
<ul>
<li>Context Level Diagrams show the system in its environment</li>
<li>Container Level Diagrams show the high-level structure of the system</li>
<li>Component Level Diagrams show the components inside the containers</li>
<li>Code Level Diagrams show the implementation inside the components</li>
</ul></span>
</div>

<p><strong>Representational Consistency</strong> : When the audience is navigating between diagrams of different levels of abstraction,
it should be easy to understand the relationships between the diagrams. Consistency in naming, style, and added
container / component boxes should guide the reader and reduce cognitive load.</p>
<p><strong>Purposeful Styling</strong> : Colors can be used to highlight important information, but they should be used with the
intention to provide an extra level of information (like categories, or status). Same goes for shapes and lines. Styling
a box in a sketched way can indicate that the component is not yet implemented and can again add an extra level of
information.</p>
<p><strong>Simplify the geometry</strong> : The excessive use of boxes, relationships, and lines can make a diagram unreadable. A good
starting point can be to make a diagram symmetrical with non-crossing, uni directional lines. If you do not want to
communicate something particular, all similar objects should have the same size. A good abstraction may
redesign reality like subway maps are an abstraction stripped by the reality of a city map to make it more readable and
understandable. Relationships can be of hierarchical, sequential, causal, proportional (scale) or spatial (relative
position) nature.</p>
<p><strong>Include a legend and labels</strong> : Labels should be placed if they help the audience to understand the message of the
diagram, and be moved to a legend or note if not. Similar to a coder naming a function or variable to avoid a comment,
the message of a diagram should be explicit by composition, component, and labels.</p>
<p><strong>Utalise the audiences expectations</strong> : Match the diagram to expectations (of content, shapes, and flow). from
left-to-right, top-to-bottom,
with start of information in the top left corner, and the end in the bottom right. The audience may also expect certain
shapes to represent certain things.
Like a narrative, the diagram should have a beginning with which the audience starts reading, a middle, and an end with
a result or conclusion.</p>
<p><strong>Single Responsibility Principle</strong> : A diagram should have a single purpose to effectively comm unicate a single
message. It should either describe the behavior of a system or the structure of a system. Structure diagrams communicate
what and where, visualising relationships or physical location of hardware. Behavior diagrams communicate how and whom,
visualising the flow of data or state changes.</p>
<p><strong>Example Code should work</strong> : Example code should perform the task it claims to perform and be as production-ready as
possible. Language-specific conventions should be followed.</p>
<h3 id="structure" class="relative group">Structure <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#structure" aria-label="Anchor">#</a></span></h3><p><strong>Product over Project</strong> : A project is a temporary endeavor with a defined beginning and end, while a product is
something that is ongoing and has a lifecycle. Documentation should be written for products, not projects.</p>
<p>A Product Mindset comes with a long term view, and a focus on the customer. Collaboration and reusability will benefit
on product centered documentations, especially with more than one team working on a product, or products that witch
switching teams. The documentation can a holistic view of a product not a snapshot of a project.
Consistency across products can emerge from templates and shared best practices.</p>
<p><strong>Use Metadata</strong> : Metadata can be used to structure the documentation, and to provide context to the reader. It may
contain tags to categorize the documentation, a version number, a date of last update, or a list of contributors or
responsible team.</p>
<p><strong>Perspective Driven Documentation</strong> : A pattern that focuses on Perspectives, a collection of one or more artifacts
that address one (or multiple related) concerns of a particular audience. One key principle is to no repeat information
and use links and references instead. Perspectives are fractal and can be embedded into other perspectives. An example
for this can be layered diagrams, which respond to different perspectives of different audiences depending on the</p>
<p><strong>Just in Time Documentation</strong> : &ldquo;You are not gonna need it&rdquo; is a development principle to only implement functionality
that is needed not to avoid overengineering for use cases that never come. A principle that can be applied to
Documentation and Knowledge management. This encourages faster, more efficient working on a more up-to-date
documentation that is clear of fortune told waste pages, written document pages that are lost and never used. There can
be a place to record information that could be relevant in the future.</p>
<p><strong>Use Architecture Design Records and document Architecture</strong>: Document architecture decisions, reasons, and future
risks in the code base using ADRs (which I explained also in
<a href="https://philodev.one/posts/2023-04-communicating-between-teams/">this post about team communication</a>. Architecture can also be
documenting by recording Architecture Characteristics (discussed in
<a href="https://philodev.one/posts/2024-05-agile-architecture/">this post about agile architecture</a> or by following evolutionary
architecture and document decisions via fitness functions (discussed in
<a href="https://philodev.one/posts/2024-09-evolutionary-architecture/">this post about Evolutionary Architecture</a></p>
<p><strong>Company-wide Documentation</strong> : Documentation does not only exist in the context of a product. It should be searchable
and accessible throughout the company where needed, if possible with the company-wide wiki or knowledge management tool.
Also, there are documentation types about the company, like a tech radar, or how to things work around the company (from
using HRs &ldquo;products&rdquo; like how to access educational resources and of course the companies platform tools).</p>
<h2 id="testing-and-automating-documentation" class="relative group">Testing and Automating Documentation <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#testing-and-automating-documentation" aria-label="Anchor">#</a></span></h2><p><strong>Documentation as Code</strong>
Documentation should be created, updated, and live in the same environment (e.g. IDE) as the code it describes. This
allows easier workflows, utalises existing review processes, better discoverability, enabled collaboration, and
automation.</p>
<p><strong>Automating Documentation Publishing</strong> : Not every audience is able to read documentation from the code base. Subsets
of the documentation should be readable from outside the team or even the company. This can be enabled by providing an
endpoint which always returns the current state of the Open Api File which is based in the code base. But it can also
mean syncing parts of the markdown documentation files to other documentation systems like syncing the glossary to
Confluence.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">I made perfect experiences writing the glossary as code, matching it to class and variable names, and ensuring a
developer wrote and one reviewed the description; and syncing it to confluence to provide visibility and exchange with
management or product.</span>
</div>

<p><strong>Generating Documentation</strong> : Generating documentation should be used with care. Using AI to generate documentation
especially, as AI tools are still in their infancy. But generating selected parts of the architecture can be very
helpful and ease keeping the docs up to date; like generating a state graph out of the events and handlers in an
event-driven architecture.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Especially with generated Open Api Files I did make unpleasant experiences which is why I would suggest consumer facing
documentation to be written by hand. But it can help a lot to either generate code based on the Open Api file, or to
<a href="https://philodev.one/posts/2023-03-testing-open-api-specs/" target="_blank" rel="noreferrer">test the implementation against the expected Open Api File</a>.</span>
</div>

<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Documentation is a key part of the development process. It should be written with empathy for the audience, with care,
with a spark of creativity.</p>
<p>Happy documenting :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.oreilly.com/library/view/communication-patterns/9781098140533/" target="_blank" rel="noreferrer">Communication Patterns by Jacqui Read</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref3:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://developers.google.com/tech-writing/overview" target="_blank" rel="noreferrer">Google Technical writing courses</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Barbara Minto about the Pyramid Principle. Citation copied from &ldquo;Communication Patterns by Jacqui Read&rdquo;&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="agile" label="Agile"/></entry><entry><title type="html">📚 Book takeaways: Building Evolutionary Architecture</title><link href="https://philodev.one/posts/2024-09-evolutionary-architecture/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-09-o-auth-2/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding other oAuth flows"/><link href="https://philodev.one/posts/2024-08-o-auth/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding oAuth Authentication Code Flow"/><link href="https://philodev.one/posts/2024-05-agile-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="Agile Software Architecture"/><link href="https://philodev.one/posts/2024-04-event-sourcing/?utm_source=atom_feed" rel="related" type="text/html" title="Event Sourcing for long living projects"/><link href="https://philodev.one/posts/2024-02-feature-flags/?utm_source=atom_feed" rel="related" type="text/html" title="Gitlab Feature Flags (for Backends)"/><id>https://philodev.one/posts/2024-09-evolutionary-architecture/</id><published>2024-09-27T10:20:44+02:00</published><updated>2024-09-27T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>With evolving requirements and knowledge about the product, the architecture must evolve as well. This book provides an explanation of the concept, examples of fitness functions for architectures, and recommendations on how to build incrementally.</blockquote><p><div class="lead !mb-9 text-xl">
  Building Evolutionary Architectures
Neal Ford, Rebecca Parsons, Patrick Kua, and Pramod Sadalage.
</div>

<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>Expectation Management</strong> : This blog post reflects my personal takeaways from the book. Chapters that I did not find
interesting or relevant to my work are not covered, chapters that particularly resonated with me are covered in more
detail. In between I added information I found useful to understand the context of the book.</p>
<p>I will add personal opinion and context in these alerts.</p>
</span>
</div>

<h2 id="evolutionary-architecture" class="relative group">Evolutionary Architecture <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#evolutionary-architecture" aria-label="Anchor">#</a></span></h2><p>Evolutionary Algorithms are used for optimization problems, where the search space is too large to be searched.
Inspired by biological evolution, the algorithm uses a population of (more or less random) solutions, and evolves them
over generations. The algorithms utilise a fitness function to evaluate the solutions. the solutions are then modified
by (more or less random) mutations to generate a new population. The generations will be selected and mutated over time
to localise local optimums.</p>
<p>This concept can be transferred to software architecture. With small incremental changes, the architecture can evolve
with the current requirements, while data-driven tested by certain fitness functions to check if the evolution is in the
right direction.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>While the concept and the term fitness function are very helpful when dealing with architecture, I would like to
think about the limitations. Architecture is not only a performance optimization problem, but also a communication tool
to the developers. In a good architecture, developers know why certain decisions have been made, and can use that
understanding to make more decisions. It also a way of communicating guidelines to developers and imply limitations of
the product.
Architects sometimes focus more on the restrictions of developers and communicate through long wiki pages instead of
providing guidance and expectations.</p>
<p>I want to emphasize that the concept of Evolutionary Architecture can be a great tool for communicating the boundaries
and reasons for architectural decisions, but it can also be misused to enforce restrictions on developers, especially if
the fitness functions are written in a way that do not provide the needed context and reason for failure.</p>
</span>
</div>

<h2 id="mechanics" class="relative group">Mechanics <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#mechanics" aria-label="Anchor">#</a></span></h2><p>The mechanics of Evolutionary Architecture are covering fitness functions, as well as practices, metrics, and tools that
support architectural governance.
These mechanics are a tool for architects to guide teams in their architectural decision-making.</p>
<h3 id="architecture-characteristics" class="relative group">Architecture Characteristics <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#architecture-characteristics" aria-label="Anchor">#</a></span></h3><p>Software solutions should fulfill the requirements of the product. Defining these requirements is something I wrote
about in a previous blog post about <a href="https://philodev.one/posts/2024-05-agile-architecture/">Agile Architecture</a>.
These architecture characteristics represent critical requirements for the success and maintainability of the product.
The common characteristics in the book include Auditability, Performance, Security, Requirements, Data, Legality,
Scalability.
As the business requirements evolve over time the architectural characteristics utilizes fitness functions to project
the quality of the architecture.</p>
<blockquote>
<p>Decide early what the objective drivers are and prioritize decisions accordingly.</p>
</blockquote>
<p>In an agile development environment, many decisions are made incrementally, so should not all architecture decisions be
made upfront, but at the <em>last responsible moment</em>. Decisions should bring benefits to the current product, and should
therefore be sacrificial in the possible future of the product.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>One of the most important characteristics of an architecture (in my opinion) is <em>testability</em>. An easily testable
system often comes already with its own set of fitness functions.</p>
<p>Testable systems have components that can be tested individually, might use contract testing to conform to outside
expectations, have easy fakable data structures, and provide separations of ports and adapters to test a complete flow.
A system that is easily testable for a developer is often also easier to understand and maintain.</p>
</span>
</div>

<h3 id="fitness-functions" class="relative group">Fitness Functions <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#fitness-functions" aria-label="Anchor">#</a></span></h3><blockquote>
<p>An architectural fitness function is any mechanism that provides an objective integrity assessment of some
architectural characteristic(s).</p>
</blockquote>
<p>Fitness functions in practice make take the form of:</p>
<ul>
<li>Architecture tests that run against the current implementation to check for architectural definitions, e.g. that
certain components are not dependent on each other to ensure <em>maintainability</em>.</li>
<li>Monitoring tools that measure e.g. the response time of a service to ensure <em>performance</em>.</li>
<li>Code Metrics that check things like cyclomatic complexity to ensure <em>maintainability</em>.</li>
<li>Chaos Engineering that tests the <em>resilience</em> of the system.</li>
<li>Security Scanning that check for vulnerabilities to ensure <em>security</em>.</li>
<li>Contract tests ensure <em>requirements</em> are met.</li>
</ul>
<p>These functions allow a feedback cycle for architecture decisions. A new deployment may be evaluated for its effects on
the architecture fitness functions. As Continuous Deliver strives for data driven results, architecture decisions can
evolve data-driven with the product.</p>
<p>Fitness function may have different characteristics:</p>
<p><strong>Atomic or Holistic</strong> : Atomic fitness functions are focused on a single context and aspect of the
architecture, like an architecture test that checks for dependencies between components.
Holistic fitness run against shared contexts and for example measure the response time throughout contexts.</p>
<p><strong>Triggered or Continual or Temporal or Manual</strong> :
Triggered fitness functions are run triggered like an architecture test, most common in the deployment or merge
pipeline.
Continual fitness functions are run continuously like a monitoring tool.
Temporal fitness functions run in defined time frames, like a reminder for a static key rotation or dependency check to
alert on outdated libraries.
Manual fitness functions are run by humans, like a QA review.</p>
<p><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">In this context, Monitor Driven Development is mentioned, and seems like something I need to look into!</span>
</div>

<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p><strong>Static or Dynamic results</strong> : Static fitness functions have fixed results like a passed or failed test.
Dynamic fitness functions rely on the context like the response time of a service with increasing numbers of users.</p>
<p><strong>Intentional or Emerged</strong> :
Intentional fitness functions are defined upfront to project the architecture characteristics.
Emerged fitness functions are defined when a behavior is observed during product development.</p>
<h3 id="examples-of-fitness-functions" class="relative group">Examples of Fitness functions <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#examples-of-fitness-functions" aria-label="Anchor">#</a></span></h3><p>There are libraries for many programming languages that can be used to define fitness functions. Some of those must be
precisely defined for the domain, others are more general and can be used in many contexts.</p>
<ul>
<li><strong>Afferent and Efferent Coupling</strong> : Afferent Coupling measures the number incoming connections to a code artifact (
components, class, etc.), while Efferent Coupling measures the number of outgoing connections. These Couplings are
should be limited to make the code easy to understand (with all side effects), enable easy testing and if needed easy
replacement of the code artifact.</li>
</ul>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">$afferentCoupling = count($incomingConnections);
$efferentCoupling = count($outgoingConnections);
</code></pre><ul>
<li><strong>Abstractness</strong> : The ratio of abstract classes to concrete classes in a package.</li>
</ul>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">$abstractness = count($abstractClasses) / count($concreteClasses + $abstractClasses);
</code></pre><ul>
<li><strong>Instability</strong> : The ratio of efferent coupling to the total coupling. Higher instability means the code is more
likely to break if a small portion of it is changed. If a component is changed, the number of resulting, potential
code changes grows with the instability. On the other hand, a component with low instability is reused more.</li>
</ul>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">$instability = $efferentCoupling / ($efferentCoupling + $afferentCoupling);
</code></pre><ul>
<li><strong>Distance from the Main Sequence</strong> : Combines the abstractness and instability. A codebase that is too abstract
becomes difficult to understand and use, while a codebase that is too concrete becomes difficult to change.</li>
</ul>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">$distanceFromMainSequence = abs($abstractness + $instability - 1);
</code></pre><ul>
<li>
<p><strong>Direction of Imports</strong> : It might an architectural decision to let certain components only import from other
components, but not the other way around. This can be enforced by a fitness function.</p>
</li>
<li>
<p><strong>Cyclomatic Complexity</strong> : The number of independent paths through a code artifact. The metric is taken from graph
theory and takes the lines of code as edges and the number of decision points (like  <code>if</code> or <code>switch</code>) as
the nodes. By this measure a formatted if-else statement in php will generate a complexity of 5 - 1 + 2 = 6, while a
turnery operator will generate a complexity of 1 - 1 + 2 = 2.
High cyclomatic complexity makes the code hard to understand and test.
The industry threshold is value below 10 for complex domains, and below 5 for simple domains.</p>
</li>
</ul>
<pre tabindex="0"><code class="language-injectablephp" data-lang="injectablephp">$cyclomaticComplexity = count($linesOfCode) - count($decisionsPoints) + 2;
</code></pre><ul>
<li>
<p><strong>Communication Governance</strong> : Defining which services are allowed to communicate with each other withing which
contracts. Services like PACT may be used to define and test these contracts, but additional fitness functions may be
required to ensure that services without a contract are not allowed to communicate.</p>
</li>
<li>
<p><strong>Chaos Engineering</strong> : The practice of testing the resilience of a system by injecting failures, such as high
latency, packet loss, whole services or databases going down. Chaos Engineering is a practice that is used to ensure
that the system is resilient. Netflix is a well-known company that uses Chaos Engineering continuously to ensure
developers take care of the resilience of their services.</p>
</li>
<li>
<p><strong>Fidelity Fitness</strong> : If a service is replaced by another service, the new service should have the same fidelity as
the old service. A fidelity fitness function may compare both services side by side to measure to which degree the new
service has the same feature set, results, or performance.</p>
</li>
</ul>
<h2 id="structure" class="relative group">Structure <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#structure" aria-label="Anchor">#</a></span></h2><p>The topology of the software system has a significant impact on the ability to evolve it. The book describes different
form of coupling in software architecture.</p>
<h3 id="connascence" class="relative group">Connascence <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#connascence" aria-label="Anchor">#</a></span></h3><blockquote>
<p>Two components are connascent if a change in one would require the other to be modified in order to maintain the
overall correctness of the system.</p>
</blockquote>
<p>Connascence is a measure of the coupling between components. Different types of Connascence are more desirable than
other, the order of desirability listed here from most strong to weak.</p>
<p>Static Connascence is a measure of the coupling between components on code level, so on what two code artifacts must
agree on to function correctly.</p>
<ul>
<li><strong>Connascence of Name</strong> : Multiple components must agree on the name of an entity.</li>
<li><strong>Connascence of Type</strong> : Multiple components must agree on the type of entity.</li>
<li><strong>Connascence of Meaning</strong> : Multiple components must agree on the meaning of particular values, like enums.</li>
<li><strong>Connascence of Position</strong> : Multiple components must agree on the position of a value, like the order of parameters
in a function.</li>
</ul>
<p>Dynamic Connascence is a measure of the coupling between components on runtime level.</p>
<ul>
<li><strong>Connascence of Execution</strong> : Multiple components must agree on the order of execution, like adding a header before
dispatching a message is a connascence between a messenger component and business code.</li>
<li><strong>Connascence of Timing</strong> : If the timing of execution is important, to avoid for example race conditions.</li>
<li><strong>Connascence of Value</strong> : If certain values relate to one another to maintain the integrity of the datastructures.</li>
<li><strong>Connascence of Identity</strong> : If the identity of an entity must be the same in multiple components.</li>
</ul>
<p>The Locality of Connascence describes the proximal location to one another in the codebase. As the distance decreases
weaker forms of connascence can be used. Domain Driven Design uses the concept of Bounded Contexts to recognize that
each entity works within a localized context, implying strong connascence within the context and weak connascence
between contexts.</p>
<p>The Degree of Connascence describes the size of impact. A connaissance of type has less impact on a software system if it
used a normalisation / anti corruption layer to not drag type changes of the other system through it.</p>
<p>The Book provides guidelines from Page-Jones for using connascence to improve systems modularity:</p>
<ul>
<li>Minimize overall connascence by breaking the system into encapsulated elements.</li>
<li>Minimize any remaining connascence that crosses encapsulation boundaries.</li>
<li>Maximize the connascence within encapsulation boundaries.</li>
</ul>
<h3 id="architectural-quantum" class="relative group">Architectural Quantum <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#architectural-quantum" aria-label="Anchor">#</a></span></h3><blockquote>
<p>An architectural quantum is an independently deployable component with high functional cohesion, high static
coupling, which includes all the structural elements required for the system to function properly.</p>
</blockquote>
<p>Independently deployable means that the component can be deployed without the need to deploy other components.
High static coupling refers how services are wired together (in contrast to dynamic coupling, which refers to how
services call one another at run time).
High functional cohesion means it includes all behavior and data to implement a particular domain workflow.</p>
<p>The common example of an architectural quantum is a microservice. Any system that uses a shared database is one
architectural quantum, even if that database is an event storage. High degrees of decoupling into architectural quanta
allows developers to move quickly without being concert about the other services.</p>
<p>Dynamic coupling in quanta is a question of communication (sync or async), (eventual) consistency, and coordination (
orchestrator vs. choreographer).</p>
<h3 id="orthogonal-coupling" class="relative group">Orthogonal Coupling <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#orthogonal-coupling" aria-label="Anchor">#</a></span></h3><blockquote>
<p>Two parts of an architecture may be orthogonally coupled if they serve two distinct purposes that still
intersect to form a complete solution</p>
</blockquote>
<p>An example of such orthogonal coupling would be a service that is responsible for the business logic and a service that
is responsible for monitoring the requests.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>I mark many things here as my opinion, as I am not sure if I got the concepts of the book correctly, and asked for other
help, and think it&rsquo;s worth noting down my learnings, even if they might differ from the book.</p>
<p>Moving the orthogonal coupling to the Kubernetes world, both services would be containers in one pod.
A pod is a small deployable unit in Kubernetes. It is a group of one or more containers,
each container may be defined as Docker Image. The containers in a pod share the same network (the same IP Address) and
storage. The containers in a pod are always deployed together.</p>
<p>Containers that might run in the same pod are for example logging services, or a nginx reverse proxy.
The database is often handled differently, to scale it independently and avoid data loss when their service is
restarted. Only containers are in one pod if they scale together and should exist for each deployment (not application).</p>
<p>Following the concept of orthogonal coupling, any two containers in one pod might be orthogonal coupled.</p>
</span>
</div>

<p>This is a concept connected to the Side Car Pattern, in which an application has a service as &ldquo;side-car&rdquo; that is managed
more centralized e.g. by the platform team.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>If each pod has a side-car responsible for request handling (in php world for example a nginx), this allows to move
authorization to the side-car completely. Any request in and out of the pod would go through the side-car, so
any tokens can be added or checked in this service. This is a Service Mesh.</p>
<p>If all requests go through this service, it can be used gain monitoring data from the requests, resulting in a map of
requests between all pods in the company as well as to or from the outside. This enables many for example the fitness
function that tests which services are allowed to communicate with each other, if the service communication is
satisfying the contracts, and if there are performance bottlenecks in the communication.</p>
</span>
</div>

<h3 id="evolutionary-data" class="relative group">Evolutionary Data <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#evolutionary-data" aria-label="Anchor">#</a></span></h3><blockquote>
<p>Evolutionary design in databases occurs when developers can build and evolve the structure of the database as
requirements change over time</p>
</blockquote>
<p>This requires migrations to change the database schema:</p>
<ul>
<li>Versioned: The database schema is versioned, and migrations are applied in order.</li>
<li>Incremental: Migrations are applied incrementally, so that the database is always in a consistent state.</li>
<li>Tested: Migrations are tested to ensure that they work correctly.</li>
<li>Respect legacy data and integration points: Data migrations should keep data in a backwards compatible way if there
are dependencies on the data.</li>
</ul>
<p>Fitness functions may also be used to ensure that data constraints are met, for example that identify is kept throughout
the system, or that data deletions are propagated to other services.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>I am missing the concept of database normalisations in this context. Databases normalisation is a process of organizing
a relational database according to a set of defined rules to ensure data integrity and minimize redundancy.</p>
<p>Depending on the use case the highest normal form of a database is not always the one that satisfies the requirements
the best, still in my experience many databases that where hard to evolve where not normalized enough.</p>
</span>
</div>

<h2 id="my-opinion" class="relative group">My Opinion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#my-opinion" aria-label="Anchor">#</a></span></h2><p>Enabling a data driven work flow for architecture decisions is a great way to document and communicate architectural
decisions that will work better than long wiki pages. Fitness functions put technical product goals into code, and make
them measurable.
The book provides a great overview of the concept and examples of fitness functions, and how to implement them into the
development process. In between I also learned more on software topology and the importance of component coupling.
When putting that into practice, the most emphasis lies on the possibility of incremental changes (as in continuous
delivery).</p>
<p>I am looking forward to applying the concept of fitness functions to my work, and maybe I have motivated you to also
read a new book.</p>
<p>Happy coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.oreilly.com/library/view/building-evolutionary-architectures/9781492097532/" target="_blank" rel="noreferrer">Building Evolutionary Architectures</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://benjiweber.co.uk/blog/2015/03/02/monitoring-check-smells/" target="_blank" rel="noreferrer">Monitor Driven Development</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="book" label="Book"/><category scheme="taxonomy:Tags" term="architecture" label="Architecture"/><category scheme="taxonomy:Tags" term="metrics" label="Metrics"/><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Understanding other oAuth flows</title><link href="https://philodev.one/posts/2024-09-o-auth-2/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-08-o-auth/?utm_source=atom_feed" rel="related" type="text/html" title="Understanding oAuth Authentication Code Flow"/><link href="https://philodev.one/posts/2024-02-feature-flags/?utm_source=atom_feed" rel="related" type="text/html" title="Gitlab Feature Flags (for Backends)"/><link href="https://philodev.one/posts/2023-03-testing-open-api-specs/?utm_source=atom_feed" rel="related" type="text/html" title="Testing Open Api files"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><link href="https://philodev.one/posts/2024-05-agile-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="Agile Software Architecture"/><id>https://philodev.one/posts/2024-09-o-auth-2/</id><published>2024-09-10T10:20:44+02:00</published><updated>2024-09-10T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>oAuth pprovides more flows than just the authentication of a user, but also authentication of services against one Authentication Server or a federated net of Authentication Servers.</blockquote><div class="lead !mb-9 text-xl">
  oAuth pprovides more flows than just the authentication of a user, but also authentication of services against one
Authentication Server or a federated net of Authentication Servers.
</div>

<h2 id="what-was-the-basic-oauth-flow-and-what-to-know-additionally" class="relative group">What was the basic oAuth flow and what to know additionally? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#what-was-the-basic-oauth-flow-and-what-to-know-additionally" aria-label="Anchor">#</a></span></h2><p>The Authorication Code Flow is the most common flow for authenticating a human against an Authorization Server, often
combined with Open ID Connect. This flow is described in my last
Post: <a href="https://philodev.one/posts/2024-08-o-auth/">Understanding oAuth Authentication Code Flow</a>.</p>
<h3 id="terminology" class="relative group">Terminology <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#terminology" aria-label="Anchor">#</a></span></h3><p><strong>Actors:</strong></p>
<ul>
<li><strong>Resource Owner</strong> - The human that can authenticate</li>
<li><strong>Resource Server</strong> - The server that holds the resources, for basic authentication this might be only the user
identifier</li>
<li><strong>Client</strong> - The service that wants to know who the user is</li>
<li><strong>Authorization Server</strong> - The server that authenticates the user and issues tokens</li>
<li><strong>Access Token</strong> - credentials used to access protected resources.</li>
<li><strong>Refresh Token</strong> - credentials used to obtain a new access token when the current access token becomes invalid.</li>
</ul>
<p>The flows are defined in the RFC 6749<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, while I found the best overview at curity.io <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> and
Auth0 <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<h2 id="client-credentials-flow---a-service-wants-to-authenticate-against-another-service-without-a-user-present" class="relative group">Client Credentials Flow - A Service wants to authenticate against another service without a user present <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#client-credentials-flow---a-service-wants-to-authenticate-against-another-service-without-a-user-present" aria-label="Anchor">#</a></span></h2><p>This flow is used when the Client wants to authenticate itself against another service without an involved Human.
This does not authenticate the Client as a specific user, but as a service; therefore, the Client does not get access to
any human resources.</p>
<p>The benefit of this flow is that the Client can authenticate itself (e.g. against other microservices) in an unified
way, with the possibility to change permissions on the fly, while minimizing the number of calls using static
credentials.</p>
<ol>
<li>
<p>The client authenticates with the authorization server and requests an access token from the token endpoint with its
<code>client_id</code>, <code>client_secret</code>, and <code>scope</code>.</p>
<p><code>client_id</code>, <code>client_secret</code>: The credentials of the Client to authenticate itself against the Authorization</p>
</li>
<li>
<p>The authorization server authenticates the client, and if valid, issues an access token.</p>
</li>
</ol>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 528 201"
      >
      <g transform='translate(8,16)'>
<text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='8' y='148' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='180' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='164' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='16' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='24' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='164' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='24' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='32' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='148' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='32' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='40' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='116' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='40' y='132' fill='currentColor' style='font-size:1em'>&lt;</text>
<text text-anchor='middle' x='40' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='40' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='116' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='48' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='116' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='64' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='64' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='148' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='64' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='64' y='180' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='72' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='116' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='72' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='116' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='80' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='88' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='88' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='88' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='96' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='96' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='96' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='104' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='104' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='112' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='112' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='112' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='120' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='120' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='128' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='128' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='136' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='136' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='144' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='144' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='144' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='152' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='168' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='176' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='192' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='192' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='216' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='224' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='232' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='232' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='240' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='240' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='248' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='256' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='264' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='272' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='272' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='280' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='288' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='296' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='296' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='304' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='304' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='304' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='312' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='320' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='320' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='328' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='328' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='336' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='336' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='344' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='344' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='352' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='352' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='352' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='352' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='148' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='352' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='352' y='180' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='360' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='20' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='360' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='68' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='360' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='360' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='164' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='360' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='368' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='368' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='368' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='164' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='368' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='376' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='68' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='376' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='376' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='376' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='20' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='384' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='384' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='164' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='384' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='392' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='392' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='392' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='400' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='116' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='400' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='400' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='408' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='408' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='408' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='20' fill='currentColor' style='font-size:1em'>z</text>
<text text-anchor='middle' x='416' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='416' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='164' fill='currentColor' style='font-size:1em'>z</text>
<text text-anchor='middle' x='416' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='424' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='84' fill='currentColor' style='font-size:1em'>&gt;</text>
<text text-anchor='middle' x='424' y='116' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='424' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='164' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='424' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='432' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='432' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='432' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='432' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='432' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='432' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='432' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='432' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='432' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='432' y='148' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='432' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='432' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='440' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='440' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='448' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='448' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='456' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='456' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='20' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='464' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='164' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='464' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='472' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='472' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='480' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='480' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='20' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='488' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='164' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='488' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='496' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='496' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='504' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='504' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='512' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='512' y='148' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='512' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='512' y='180' fill='currentColor' style='font-size:1em'>┘</text>
</g>

    </svg>
  
</div>
<h3 id="why-use-the-client-credentials-flow" class="relative group">Why use the Client Credentials Flow? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#why-use-the-client-credentials-flow" aria-label="Anchor">#</a></span></h3><p>From the first look, the Client Credentials Flow seems to use static credentials, and there are not many benefits over
API keys. From the security perspective, the Client Credentials Flow requests the authentication token from a
Authentication Server, which might revoke the token if the Client is compromised (without an additional deployment). The
Client can also request a new token with the refresh token, which is not possible with API keys.</p>
<p>From a human developer perspective, the Client Credentials Flow is a unified way to authenticate services in a
microservice environment. Unified means, testers or developers who join the team don&rsquo;t need to be introduced to the
authentication of the service whenever they switch teams, but can use the same flow for all services. DevOps Engineers
can rely on the same flow for all services, which makes the deployment and monitoring easier.</p>
<p>Such human benefits are often underestimated, but neglecting them causes a lot of friction in the development process,
deployment delays, and security issues.</p>
<h2 id="refresh---a-service-has-a-token-and-wants-a-new-token-without-the-user-present" class="relative group">Refresh - A Service has a token and wants a new token without the user present <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#refresh---a-service-has-a-token-and-wants-a-new-token-without-the-user-present" aria-label="Anchor">#</a></span></h2><p>To keep the access token short-lived and the user experience smooth, the Client can request a new access token with the
refresh token. To prevent malicious usage, the <code>refresh_token</code> in the response is not the same as the one that was sent
and the Client has to update their refresh token.</p>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 648 201"
      >
      <g transform='translate(8,16)'>
<text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='8' y='148' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='180' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='164' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='16' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='24' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='164' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='24' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='32' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='148' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='32' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='40' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='116' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='40' y='132' fill='currentColor' style='font-size:1em'>&lt;</text>
<text text-anchor='middle' x='40' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='40' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='116' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='48' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='116' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='64' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='64' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='148' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='64' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='64' y='180' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='72' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='116' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='72' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='116' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='80' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='88' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='88' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='88' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='96' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='96' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='96' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='104' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='104' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='112' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='112' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='112' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='120' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='120' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='128' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='128' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='136' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='136' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='144' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='144' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='144' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='152' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='168' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='176' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='192' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='192' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='216' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='224' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='232' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='232' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='240' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='240' y='116' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='248' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='256' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='264' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='272' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='272' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='280' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='280' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='288' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='296' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='296' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='304' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='304' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='312' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='320' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='320' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='328' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='328' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='336' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='336' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='344' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='344' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='68' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='352' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='360' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='360' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='368' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='368' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='376' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='376' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='68' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='384' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='384' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='392' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='392' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='400' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='408' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='408' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='68' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='416' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='416' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='424' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='424' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='432' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='432' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='432' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='432' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='440' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='440' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='448' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='456' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='464' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='464' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='472' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='472' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='472' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='472' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='472' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='148' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='472' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='472' y='180' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='480' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='20' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='480' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='68' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='480' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='480' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='164' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='480' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='488' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='488' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='488' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='164' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='488' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='496' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='68' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='496' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='496' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='496' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='20' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='504' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='504' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='164' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='504' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='512' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='512' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='512' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='520' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='116' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='520' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='520' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='528' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='528' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='528' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='20' fill='currentColor' style='font-size:1em'>z</text>
<text text-anchor='middle' x='536' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='536' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='164' fill='currentColor' style='font-size:1em'>z</text>
<text text-anchor='middle' x='536' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='544' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='84' fill='currentColor' style='font-size:1em'>&gt;</text>
<text text-anchor='middle' x='544' y='116' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='544' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='164' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='544' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='552' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='552' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='552' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='552' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='552' y='148' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='552' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='552' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='560' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='560' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='560' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='560' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='560' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='560' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='568' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='568' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='576' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='576' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='20' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='584' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='164' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='584' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='600' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='600' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='20' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='608' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='164' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='608' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='616' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='616' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='624' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='624' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='632' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='632' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='632' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='632' y='148' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='632' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='632' y='180' fill='currentColor' style='font-size:1em'>┘</text>
</g>

    </svg>
  
</div>
<h2 id="token-exchange-flow---a-service-has-a-token-but-wants-one-from-a-different-authentication-authority" class="relative group">Token Exchange Flow - A Service has a token, but wants one from a different Authentication Authority <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#token-exchange-flow---a-service-has-a-token-but-wants-one-from-a-different-authentication-authority" aria-label="Anchor">#</a></span></h2><p>If a Client has an access token from one Authorization Server, it may need a token from the same Authorization Server
with other privileges to conform the least-privileges principle. Token exchange also allows you to cross security
domains by exchanging a token from one trust domain to a token of a
different one <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<ul>
<li><strong>Subject token</strong> - The token that the Client has</li>
<li><strong>Actor token</strong> - Optional Deligation token if the Client acts on behalf of a human or another service</li>
<li><strong>Requested token</strong> - The token that the Authorization Server returns</li>
</ul>
<p>In processing the request, the authorization server must perform the appropriate validation procedures for the indicated
token type and, if the actor token is present, also perform the appropriate validation procedures for its indicated
token type.</p>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 736 201"
      >
      <g transform='translate(8,16)'>
<text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='8' y='148' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='8' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='8' y='180' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='16' y='164' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='16' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='24' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='24' y='164' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='24' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='32' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='32' y='148' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='32' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='40' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='68' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='40' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='132' fill='currentColor' style='font-size:1em'>&lt;</text>
<text text-anchor='middle' x='40' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='40' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='40' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='68' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='48' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='48' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='56' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='56' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='64' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='64' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='116' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='64' y='148' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='64' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='64' y='180' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='72' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='72' y='116' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='72' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='80' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='80' y='116' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='80' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='88' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='88' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='96' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='96' y='116' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='96' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='104' y='116' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='104' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='112' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='112' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='112' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='120' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='120' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='128' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='128' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='136' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='136' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='144' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='144' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='144' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='152' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='152' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='160' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='168' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='168' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='176' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='176' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='184' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='192' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='192' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='216' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='224' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='232' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='232' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='240' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='240' y='116' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='248' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='256' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='264' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='272' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='272' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='280' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='280' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='288' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='296' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='296' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='304' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='304' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='304' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='312' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='320' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='328' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='328' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='328' y='116' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='336' y='68' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='336' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='344' y='68' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='344' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='68' fill='currentColor' style='font-size:1em'>j</text>
<text text-anchor='middle' x='352' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='360' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='360' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='368' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='368' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='376' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='376' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='376' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='384' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='384' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='384' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='392' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='392' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='392' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='400' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='400' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='400' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='68' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='408' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='408' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='408' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='416' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='416' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='416' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='424' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='424' y='116' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='424' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='432' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='432' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='432' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='432' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='440' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='440' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='448' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='448' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='448' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='68' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='456' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='456' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='68' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='464' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='464' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='464' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='68' fill='currentColor' style='font-size:1em'>j</text>
<text text-anchor='middle' x='472' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='472' y='116' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='472' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='480' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='480' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='480' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='488' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='488' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='488' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='496' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='496' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='496' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='504' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='504' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='504' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='512' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='512' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='512' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='520' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='520' y='116' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='520' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='68' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='528' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='528' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='528' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='536' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='536' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='536' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='544' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='544' y='116' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='544' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='552' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='552' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='552' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='560' y='4' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='560' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='560' y='36' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='560' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='560' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='560' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='560' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='560' y='148' fill='currentColor' style='font-size:1em'>┌</text>
<text text-anchor='middle' x='560' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='560' y='180' fill='currentColor' style='font-size:1em'>└</text>
<text text-anchor='middle' x='568' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='20' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='568' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='68' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='568' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='568' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='568' y='164' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='568' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='576' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='68' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='576' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='576' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='576' y='164' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='576' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='584' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='584' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='584' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='584' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='584' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='20' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='592' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='68' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='592' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='592' y='164' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='592' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='600' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='116' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='600' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='600' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='600' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='608' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='608' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='608' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='616' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='616' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='616' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='20' fill='currentColor' style='font-size:1em'>z</text>
<text text-anchor='middle' x='624' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='68' fill='currentColor' style='font-size:1em'>.</text>
<text text-anchor='middle' x='624' y='84' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='624' y='164' fill='currentColor' style='font-size:1em'>z</text>
<text text-anchor='middle' x='624' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='632' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='632' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='632' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='632' y='68' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='632' y='84' fill='currentColor' style='font-size:1em'>&gt;</text>
<text text-anchor='middle' x='632' y='132' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='632' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='632' y='164' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='632' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='640' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='640' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='640' y='36' fill='currentColor' style='font-size:1em'>┬</text>
<text text-anchor='middle' x='640' y='52' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='640' y='68' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='640' y='84' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='640' y='100' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='640' y='116' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='640' y='132' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='640' y='148' fill='currentColor' style='font-size:1em'>┴</text>
<text text-anchor='middle' x='640' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='640' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='648' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='648' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='648' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='648' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='648' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='648' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='656' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='656' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='656' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='656' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='656' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='656' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='664' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='664' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='664' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='664' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='664' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='664' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='672' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='672' y='20' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='672' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='672' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='672' y='164' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='672' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='680' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='680' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='680' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='680' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='680' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='680' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='688' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='688' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='688' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='688' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='688' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='688' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='696' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='696' y='20' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='696' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='696' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='696' y='164' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='696' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='704' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='704' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='704' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='704' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='704' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='704' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='712' y='4' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='712' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='712' y='36' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='712' y='148' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='712' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='712' y='180' fill='currentColor' style='font-size:1em'>─</text>
<text text-anchor='middle' x='720' y='4' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='720' y='20' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='720' y='36' fill='currentColor' style='font-size:1em'>┘</text>
<text text-anchor='middle' x='720' y='148' fill='currentColor' style='font-size:1em'>┐</text>
<text text-anchor='middle' x='720' y='164' fill='currentColor' style='font-size:1em'>│</text>
<text text-anchor='middle' x='720' y='180' fill='currentColor' style='font-size:1em'>┘</text>
</g>

    </svg>
  
</div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The Request of the Client to exchange the code for an access token.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;grant_type&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The value must be `urn:ietf:params:oauth:token-type:access_token` to indicate that a token exchange is being performed&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;resource&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;A URI that indicates the target service or resource where the client intends to use the requested security token&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;audience&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The logical name of the target service where the client intends to use the requested security token&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;scope&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;array&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Additional (space separated) resources of the requested token&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;requested_token_type&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;array&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;An identifier for the type of the requested security token&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;subject_token&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;array&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;A security token that represents the identity of the party on behalf of whom the request is being made&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;subject_token_type&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;array&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;An identifier for the type of the subject token&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;actor_token&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;array&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;A security token that represents the identity of the acting party&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;actor_token_type&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;array&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;An identifier for the type of the actor token. Required when the actor_token parameter is present&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;grant_type&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;subject_token&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;subject_token_type&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The Token Types are defined in the RFC, for example <code>urn:ietf:params:oauth:token-type:access_token</code>
Indicates that the token is an OAuth access token issued by the given authorization server.</p>
<h3 id="why-use-the-token-exchange-flow" class="relative group">Why use the Token Exchange Flow? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#why-use-the-token-exchange-flow" aria-label="Anchor">#</a></span></h3><p>A big request for the Token Exchange Flow is to enable a federated network of Authentication Authorities.
Here are some use cases<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>:</p>
<p><strong>Pipelines with tokens instead of credentials</strong></p>
<p>CI/CD pipelines that need to authenticate against a different service to upload artifacts or read secrets.
Github (but also Gitlab) injects a token into the pipeline <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>, which can be used to access some github
endpoints, but also to be exchanged for a token from another Authentication Authority, like your artifact
repository <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>, or accessing some other resources.
For this to work, the Authentication Authority must trust the token from Github, and still validate the token (not every
Github token is should access the resources).</p>
<p><strong>Using federated authentication to authenticate against third parties</strong></p>
<p>When working with third parties authentication is often a pain, eased by static credentials. But with the Token Exchange
Flow, the Client can authenticate against the third party with a token from the Authorization Server (if both parties
are willing to use oAuth). Again the Authorization Server must trust the third party Authorisation Server and validate
the token.</p>
<p>One benefit of this is again that the token may be revoked. If a service is deployed already with token (like some cloud
provider already inject into the container), the token can be exchanged at the third party Authentication Server for a
third party resource authorizing token. After a new deployment, the previous token can be revoked, meaning in case of a
breach a redeployment is enough to revoke the access.</p>
<p>Again, this requires trust between the Authentication Authorities.</p>
<p><strong>Up or downstreaming tokens</strong></p>
<p>Sometimes, the current token is not enough to access a resource, but the Client can exchange the token for a new one
with higher privileges - or vice versa (to not use a token with too many privileges, following the least-privileges
principle).</p>
<p><strong>Connect a service with oAuth that otherwise does not comply</strong></p>
<p>Imagine working on a project, that does not support oAuth, while all other surrounding (and depending) services do.
Exchanging an injected token for a token that the service can use to authenticate against other services might be a
first step into a more secure and easier to use environment.</p>
<h2 id="other-flows" class="relative group">Other flows <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#other-flows" aria-label="Anchor">#</a></span></h2><p>There are more flows in the oAuth specification, which are not covered in this post, but honorable mentions are:</p>
<p><strong>Device Flow</strong>: A Service wants to authenticate a User on a device with limited input capabilities (e.g. a TV)</p>
<p><strong>Revoke Flow</strong>: A Service wants to invalidate a refresh token before it expires</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>oAuth can do so much more than just authenticate a human against an Authorization Server.</p>
<p>I made the experience, that developer do underestimate the benefits of using oAuth for services, and overestimate the
complexity (if libraries are used). Not only user facing, but also in the pure service-to-service communication, oAuth
provides a unified way to authenticate services over different domains.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://datatracker.ietf.org/doc/html/rfc6749" target="_blank" rel="noreferrer">RFC 6749 - The OAuth 2.0 Authorization Framework</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://curity.io/resources/learn/oauth-overview/" target="_blank" rel="noreferrer">The OAuth 2.0 by Curity</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use" target="_blank" rel="noreferrer">The OAuth 2.0 by Auth0</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://datatracker.ietf.org/doc/html/rfc8693" target="_blank" rel="noreferrer">RFC 8693 - OAuth 2.0 Token Exchange</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://sagarag.medium.com/oauth2-token-exchange-in-practice-5a12a6d2e0d" target="_blank" rel="noreferrer">More on token exchanges</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication" target="_blank" rel="noreferrer">GitHub Tokens</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://cookbook.geuer-pollmann.de/azure/azure-access-from-github-and-gitlab-pipelines-without-secrets" target="_blank" rel="noreferrer">Federated CI/CD Pipelines Authentication without Secrets</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="devops" label="DevOps"/><category scheme="taxonomy:Tags" term="standards" label="Standards"/></entry><entry><title type="html">Understanding oAuth Authentication Code Flow</title><link href="https://philodev.one/posts/2024-08-o-auth/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-02-feature-flags/?utm_source=atom_feed" rel="related" type="text/html" title="Gitlab Feature Flags (for Backends)"/><link href="https://philodev.one/posts/2023-03-testing-open-api-specs/?utm_source=atom_feed" rel="related" type="text/html" title="Testing Open Api files"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><link href="https://philodev.one/posts/2024-05-agile-architecture/?utm_source=atom_feed" rel="related" type="text/html" title="Agile Software Architecture"/><link href="https://philodev.one/posts/2024-04-event-sourcing/?utm_source=atom_feed" rel="related" type="text/html" title="Event Sourcing for long living projects"/><id>https://philodev.one/posts/2024-08-o-auth/</id><published>2024-09-09T10:20:44+02:00</published><updated>2024-09-09T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>oAuth is a hard to get into because of its (necessary) complexity. A basic understanding of the standard flow and the actors involved can help to make better decisions and understand the security implications of the choices.</blockquote><div class="lead !mb-9 text-xl">
  oAuth is a hard to get into because of its (necessary) complexity. A basic understanding of the standard flow and the
actors involved can help to make better decisions and understand the security implications of the choices.
</div>

<h2 id="who-is-the-user-and-how-trivial-is-this-question" class="relative group">Who is the User and how trivial is this question? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#who-is-the-user-and-how-trivial-is-this-question" aria-label="Anchor">#</a></span></h2><p>A Service need to know who the requesting user is, what the user is allowed to do and if that information is still
valid. The most common way to achieve this is by using static credentials (like username and password) - assuming that
if the credentials are known, the requesting user must be the user to which the credentials belong.
Such static credentials often come with a lot of problems <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>:</p>
<ul>
<li>Anyone with the credentials can impersonate the user</li>
<li>Static credentials may be brute-forced or leaked</li>
<li>Humans are humans and will write them down, use them multiple times, or share them with others</li>
<li>It&rsquo;s hard to revoke credentials without changing them or the system</li>
<li>Credentials don&rsquo;t include any information about the user or their permissions</li>
<li>Credentials are often used for a long time because changing them is hard (and humans don&rsquo;t like it)</li>
</ul>
<p>Instead of trusting that only the two parties know the static credentials, a service should trust a third party to
verify the identity of the user. One very simple implementation including a third party is using the mail provider as
authentication authority. The user logs in with the email and a random string that was sent to the email.</p>
<p>However, this flow is neither very secure nor very user-friendly. The user has to switch between their email client and
the application; and mails offer many attack vectors, with the simplest being that the mail is intercepted used for
authentication before the user can use it.</p>
<h2 id="why-oauth-and-why-is-it-so-complicated" class="relative group">Why oAuth and why is it so complicated? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#why-oauth-and-why-is-it-so-complicated" aria-label="Anchor">#</a></span></h2><p>If you log in to a service by authenticating against a different service, you might use oAuth. The process of clicking
on &ldquo;login using xyz&rdquo; on a website that is not xyz, entering your credentials for xyz, and then being redirected back is
the oAuth flow.</p>
<p>






  
  
<figure><img src="/images/2024-09-oauth.png" alt="oAuth image example" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<p><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">&ldquo;But what about OpenID Connect?&rdquo; OpenID Connect is a layer on top of oAuth that adds an identity layer. In theory, oAuth
can work by only providing an access token with a scope (which can be used as permissions) without any information about
the user. OpenID Connect builds on the oAuth protocol and adds an identity layer.</span>
</div>
 <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>Authentication is a requirement that so many services have in common, and therefore a range of attacks on user identity
have been developed.
The need for an user-friendly authentication that also considers even unknown attack vectors is why oAuth was defined -
it is a protocol that that defines how a service may authenticate a user in diverse use cases.
It contains flows that might appear complicated at first, but are necessary to cover all attack vectors and use cases.</p>
<h3 id="terminology" class="relative group">Terminology <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#terminology" aria-label="Anchor">#</a></span></h3><p><strong>Actors:</strong></p>
<ul>
<li><strong>Resource Owner</strong> - The human that can authenticate</li>
<li><strong>Resource Server</strong> - The server that holds the resources, for basic authentication this might be only the user
identifier</li>
<li><strong>Client</strong> - The service that wants to know who the user is</li>
<li><strong>Authorization Server</strong> - The server that authenticates the user and issues tokens</li>
</ul>
<p>As precondition, the Client must register themselves at the Authorization Server to get their own <code>client_id</code> to
identify themselves towards this Authorization Server.</p>
<p>Each request should contain the <code>grant_type</code> to specify the flow that is used.</p>
<p><strong>Tokens:</strong></p>
<ul>
<li><strong>Access Token</strong> - credentials used to access protected resources. The access token provides an abstraction layer,
replacing different authorization constructs (e.g., username and password) with a single token understood by the
resource server.</li>
<li><strong>Refresh Token</strong> - credentials used to obtain a new access token when the current access token becomes invalid or
expires. The Access Token should be short-lived to minimize the damage if it ever got stolen or invalid. If the human
decides to revoke the access, the Access token may remain valid, but the Refresh token will not work anymore.</li>
</ul>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p>Json Web Tokens (JWT) are a common format for tokens. The RFC which defines oAuth does not specify the token format, but
JWT is very common, because it can be easily signed/validated and can contain all necessary information.</p>
<p>OpenID Connect uses JWT as the token format, but oAuth does not require JWT.</p>
</span>
</div>

<h2 id="oauth-authentication-flows" class="relative group">oAuth Authentication Flows <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#oauth-authentication-flows" aria-label="Anchor">#</a></span></h2><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">It is okay to not understand every protocol detail - a web developer doesn&rsquo;t need to know all about oAuth flows to
authenticate a user if they just use an existing library and authentication service.
For most languages and frameworks, there are libraries that implement oAuth and make it easy to use.</span>
</div>

<p>The flows are defined in the RFC 6749<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, while I found the best overview at curity.io <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> and
Auth0 <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. Swagger provides some open api specifications for oAuth flows <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<h3 id="browser-flow---a-service-wants-to-know-who-the-user-is" class="relative group">Browser Flow - A Service wants to know who the user is <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#browser-flow---a-service-wants-to-know-who-the-user-is" aria-label="Anchor">#</a></span></h3><ol>
<li>The Client initiates the flow by directing the human to the Authorization Server. The Client includes its
<code>client_id</code>, <code>scope</code>, <code>state</code>, <code>code_challenge</code> and <code>redirect_uri</code>.</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The Request with which the client starts the oAuth flow to receive a token.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;client_id&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The ID of the requesting client obtained when registering the client with the Authorization Server.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;response_type&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Defines the flow type, this post only covers the latest `code` flow.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;scope&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Additional (space separated) resources of the human. The Client may request certain scopes 
</span></span></span><span class="line"><span class="cl"><span class="s2">        (e.g. access to the users photos), the Authorization Server may ignore them based on their policy or the humans
</span></span></span><span class="line"><span class="cl"><span class="s2">        instructions (e.g. the human may have disabled the sharing of their photos during the consent step)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;state&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Client generated string to maintain state between the request and callback 
</span></span></span><span class="line"><span class="cl"><span class="s2">        (like a authentication-attempt-id for the Client) to prevent cross-site request forgery&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;redirect_uri&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The URI to which the human will be redirected after the Authorization Server has processed the 
</span></span></span><span class="line"><span class="cl"><span class="s2">        request and the human has granted access.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;code_challenge&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;A hash of a random string (the `code_verifier`) that the Client will use to authenticate itself later&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;client_id&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;response_type&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="2">
<li>
<p>The Authentication Server checks if the <code>redirect_uri</code> is registered for the <code>client_id</code> to prevent Redirect URI
manipulation (that would authenticate the human for one Client and then redirect the human and access information to
an evil side). Then the Authentication Server authenticates the resource owner and requests grating.</p>
</li>
<li>
<p>The Authorization Server redirects the Human back to the Client to the <code>redirect_uri</code>. The redirection URI includes
an authorization <code>code</code> and the <code>state</code> provided by the Client earlier.</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The &#39;response&#39; (but a http request to the `redirect_uri` from the Authorization Server to the Client after the human has granted access&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;state&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The state that was provided by the Client to identify the started flow attempt.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;code&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;A code with which the Client can request an access token from the Authorization Server.  The Authorization Server
</span></span></span><span class="line"><span class="cl"><span class="s2">        does not directly add the access code to the redirected uri to make sure that the access token is not visible in the
</span></span></span><span class="line"><span class="cl"><span class="s2">        Humans side history and could then be misused&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;state&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;code&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="4">
<li>
<p>The Client check if the given <code>state</code> matches the stored state (so this oAuth attempt is the same that was started on
this earlier).</p>
</li>
<li>
<p>The Client requests an access token from the Authorization Server by providing the <code>code</code>,
<code>redirect_uri</code>, and the original `code to authenticate itself.</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The Request of the Client to exchange the code for an access token.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;client_id&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The ID of the requesting client obtained when registering the client with the Authorization Server.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;grant_type&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;value must be set to `authorization_code`&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;code&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The authorization code received from the Authorization server&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;redirect_uri&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The same redirect_uri that was used in the first request&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;code_verifier&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The original code_verifier that was used to hash the code_challenge&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;client_id&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;grant_type&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;code&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;redirect_uri&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="6">
<li>The Authorization Server validates the authorization <code>code</code>, hashes the given <code>code_verifier</code> to check if it matches
the previous <code>code_challange</code> to ensure that the service who requests the access token is actually the service that
started the process, and ensures that the <code>redirect_uri</code> matches the URI used to redirect the Client in step 3 to
ensure that the intended uri is still the same.
Finally, the Authorization Server responds back with an access token and, optionally, a refresh token.</li>
</ol>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 1088 745"
      >
      <g transform='translate(8,16)'>
<path d='M 0,0 L 64,0' fill='none' stroke='currentColor'></path>
<path d='M 296,0 L 376,0' fill='none' stroke='currentColor'></path>
<path d='M 896,0 L 1072,0' fill='none' stroke='currentColor'></path>
<path d='M 0,32 L 64,32' fill='none' stroke='currentColor'></path>
<path d='M 296,32 L 376,32' fill='none' stroke='currentColor'></path>
<path d='M 896,32 L 1072,32' fill='none' stroke='currentColor'></path>
<path d='M 40,80 L 328,80' fill='none' stroke='currentColor'></path>
<path d='M 352,96 L 736,96' fill='none' stroke='currentColor'></path>
<path d='M 344,112 L 352,112' fill='none' stroke='currentColor'></path>
<path d='M 360,128 L 736,128' fill='none' stroke='currentColor'></path>
<path d='M 352,144 L 752,144' fill='none' stroke='currentColor'></path>
<path d='M 344,160 L 352,160' fill='none' stroke='currentColor'></path>
<path d='M 360,176 L 752,176' fill='none' stroke='currentColor'></path>
<path d='M 344,224 L 976,224' fill='none' stroke='currentColor'></path>
<path d='M 576,240 L 960,240' fill='none' stroke='currentColor'></path>
<path d='M 976,256 L 984,256' fill='none' stroke='currentColor'></path>
<path d='M 584,272 L 960,272' fill='none' stroke='currentColor'></path>
<path d='M 40,320 L 976,320' fill='none' stroke='currentColor'></path>
<path d='M 40,368 L 976,368' fill='none' stroke='currentColor'></path>
<path d='M 344,416 L 976,416' fill='none' stroke='currentColor'></path>
<path d='M 352,432 L 760,432' fill='none' stroke='currentColor'></path>
<path d='M 344,448 L 352,448' fill='none' stroke='currentColor'></path>
<path d='M 360,464 L 760,464' fill='none' stroke='currentColor'></path>
<path d='M 344,512 L 976,512' fill='none' stroke='currentColor'></path>
<path d='M 528,528 L 960,528' fill='none' stroke='currentColor'></path>
<path d='M 976,544 L 984,544' fill='none' stroke='currentColor'></path>
<path d='M 536,560 L 960,560' fill='none' stroke='currentColor'></path>
<path d='M 432,576 L 960,576' fill='none' stroke='currentColor'></path>
<path d='M 976,592 L 984,592' fill='none' stroke='currentColor'></path>
<path d='M 440,608 L 960,608' fill='none' stroke='currentColor'></path>
<path d='M 528,624 L 960,624' fill='none' stroke='currentColor'></path>
<path d='M 976,640 L 984,640' fill='none' stroke='currentColor'></path>
<path d='M 536,656 L 960,656' fill='none' stroke='currentColor'></path>
<path d='M 344,704 L 976,704' fill='none' stroke='currentColor'></path>
<path d='M 0,0 L 0,32' fill='none' stroke='currentColor'></path>
<path d='M 32,48 L 32,720' fill='none' stroke='currentColor'></path>
<path d='M 64,0 L 64,32' fill='none' stroke='currentColor'></path>
<path d='M 296,0 L 296,32' fill='none' stroke='currentColor'></path>
<path d='M 336,48 L 336,304' fill='none' stroke='currentColor'></path>
<path d='M 336,336 L 336,352' fill='none' stroke='currentColor'></path>
<path d='M 336,384 L 336,720' fill='none' stroke='currentColor'></path>
<path d='M 352,112 L 352,128' fill='none' stroke='currentColor'></path>
<path d='M 352,160 L 352,176' fill='none' stroke='currentColor'></path>
<path d='M 352,448 L 352,464' fill='none' stroke='currentColor'></path>
<path d='M 376,0 L 376,32' fill='none' stroke='currentColor'></path>
<path d='M 432,592 L 432,608' fill='none' stroke='currentColor'></path>
<path d='M 528,544 L 528,560' fill='none' stroke='currentColor'></path>
<path d='M 528,640 L 528,656' fill='none' stroke='currentColor'></path>
<path d='M 576,256 L 576,272' fill='none' stroke='currentColor'></path>
<path d='M 744,112 L 744,128' fill='none' stroke='currentColor'></path>
<path d='M 760,160 L 760,176' fill='none' stroke='currentColor'></path>
<path d='M 768,448 L 768,464' fill='none' stroke='currentColor'></path>
<path d='M 896,0 L 896,32' fill='none' stroke='currentColor'></path>
<path d='M 968,256 L 968,272' fill='none' stroke='currentColor'></path>
<path d='M 968,544 L 968,560' fill='none' stroke='currentColor'></path>
<path d='M 968,592 L 968,608' fill='none' stroke='currentColor'></path>
<path d='M 968,640 L 968,656' fill='none' stroke='currentColor'></path>
<path d='M 984,48 L 984,720' fill='none' stroke='currentColor'></path>
<path d='M 1072,0 L 1072,32' fill='none' stroke='currentColor'></path>
<path d='M 764,424 L 772,440' fill='none' stroke='currentColor'></path>
<path d='M 964,616 L 972,632' fill='none' stroke='currentColor'></path>
<path d='M 964,568 L 972,584' fill='none' stroke='currentColor'></path>
<path d='M 756,136 L 764,152' fill='none' stroke='currentColor'></path>
<path d='M 740,88 L 748,104' fill='none' stroke='currentColor'></path>
<path d='M 964,520 L 972,536' fill='none' stroke='currentColor'></path>
<path d='M 964,232 L 972,248' fill='none' stroke='currentColor'></path>
<path d='M 32,40 L 32,48' fill='none' stroke='currentColor'></path>
<path d='M 336,40 L 336,48' fill='none' stroke='currentColor'></path>
<path d='M 336,304 L 336,312' fill='none' stroke='currentColor'></path>
<path d='M 336,328 L 336,336' fill='none' stroke='currentColor'></path>
<path d='M 336,352 L 336,360' fill='none' stroke='currentColor'></path>
<path d='M 336,376 L 336,384' fill='none' stroke='currentColor'></path>
<path d='M 352,104 L 352,112' fill='none' stroke='currentColor'></path>
<path d='M 352,128 L 352,136' fill='none' stroke='currentColor'></path>
<path d='M 352,152 L 352,160' fill='none' stroke='currentColor'></path>
<path d='M 352,440 L 352,448' fill='none' stroke='currentColor'></path>
<path d='M 432,584 L 432,592' fill='none' stroke='currentColor'></path>
<path d='M 528,536 L 528,544' fill='none' stroke='currentColor'></path>
<path d='M 528,560 L 528,568' fill='none' stroke='currentColor'></path>
<path d='M 528,632 L 528,640' fill='none' stroke='currentColor'></path>
<path d='M 576,248 L 576,256' fill='none' stroke='currentColor'></path>
<path d='M 744,128 L 744,136' fill='none' stroke='currentColor'></path>
<path d='M 984,40 L 984,48' fill='none' stroke='currentColor'></path>
<polygon points='48.000000,320.000000 36.000000,314.399994 36.000000,325.600006' fill='currentColor' transform='rotate(180.000000, 40.000000, 320.000000)'></polygon>
<polygon points='336.000000,80.000000 324.000000,74.400002 324.000000,85.599998' fill='currentColor' transform='rotate(0.000000, 328.000000, 80.000000)'></polygon>
<polygon points='352.000000,416.000000 340.000000,410.399994 340.000000,421.600006' fill='currentColor' transform='rotate(180.000000, 344.000000, 416.000000)'></polygon>
<polygon points='352.000000,704.000000 340.000000,698.400024 340.000000,709.599976' fill='currentColor' transform='rotate(180.000000, 344.000000, 704.000000)'></polygon>
<polygon points='984.000000,224.000000 972.000000,218.399994 972.000000,229.600006' fill='currentColor' transform='rotate(0.000000, 976.000000, 224.000000)'></polygon>
<polygon points='984.000000,368.000000 972.000000,362.399994 972.000000,373.600006' fill='currentColor' transform='rotate(0.000000, 976.000000, 368.000000)'></polygon>
<polygon points='984.000000,512.000000 972.000000,506.399994 972.000000,517.599976' fill='currentColor' transform='rotate(0.000000, 976.000000, 512.000000)'></polygon>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>H</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='68' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='48' y='356' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='56' y='356' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='64' y='356' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='72' y='356' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='80' y='356' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='88' y='356' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='96' y='356' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'>G</text>
<text text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'>\</text>
<text text-anchor='middle' x='312' y='20' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='320' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='344' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='352' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='352' y='212' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='352' y='500' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='360' y='212' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='360' y='500' fill='currentColor' style='font-size:1em'>5</text>
<text text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='368' y='164' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='368' y='212' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='368' y='452' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='368' y='500' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='376' y='116' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='376' y='164' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='376' y='452' fill='currentColor' style='font-size:1em'>4</text>
<text text-anchor='middle' x='384' y='116' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='384' y='164' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='384' y='212' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='384' y='452' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='384' y='500' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='392' y='212' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='392' y='500' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='400' y='116' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='400' y='164' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='400' y='212' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='400' y='452' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='400' y='500' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='408' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='408' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='408' y='212' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='408' y='452' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='408' y='500' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='416' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='416' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='416' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='416' y='452' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='416' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='424' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='424' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='424' y='212' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='424' y='452' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='424' y='500' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='432' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='432' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='432' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='432' y='452' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='432' y='500' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='440' y='212' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='440' y='500' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='448' y='116' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='448' y='164' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='448' y='212' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='448' y='452' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='448' y='500' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='448' y='596' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='456' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='456' y='164' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='456' y='212' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='456' y='452' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='456' y='500' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='456' y='596' fill='currentColor' style='font-size:1em'>6</text>
<text text-anchor='middle' x='464' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='464' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='464' y='212' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='464' y='500' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='464' y='596' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='464' y='692' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='472' y='116' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='472' y='164' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='472' y='452' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='472' y='692' fill='currentColor' style='font-size:1em'>6</text>
<text text-anchor='middle' x='480' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='480' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='480' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='480' y='452' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='480' y='500' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='480' y='596' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='480' y='692' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='488' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='488' y='164' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='488' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='488' y='452' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='488' y='500' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='488' y='596' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='496' y='116' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='496' y='164' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='496' y='212' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='496' y='452' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='496' y='500' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='496' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='496' y='692' fill='currentColor' style='font-size:1em'>{</text>
<text text-anchor='middle' x='504' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='504' y='212' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='504' y='452' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='504' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='504' y='596' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='504' y='692' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='512' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='512' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='512' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='512' y='452' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='512' y='500' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='512' y='596' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='512' y='692' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='520' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='520' y='164' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='520' y='212' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='520' y='452' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='520' y='692' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='528' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='528' y='212' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='528' y='500' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='528' y='596' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='528' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='536' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='536' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='536' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='536' y='452' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='536' y='500' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='536' y='596' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='536' y='692' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='544' y='116' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='544' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='544' y='212' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='544' y='404' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='544' y='452' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='544' y='500' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='544' y='548' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='544' y='644' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='544' y='692' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='552' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='552' y='164' fill='currentColor' style='font-size:1em'>"</text>
<text text-anchor='middle' x='552' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='552' y='404' fill='currentColor' style='font-size:1em'>3</text>
<text text-anchor='middle' x='552' y='452' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='552' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='552' y='548' fill='currentColor' style='font-size:1em'>6</text>
<text text-anchor='middle' x='552' y='596' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='552' y='644' fill='currentColor' style='font-size:1em'>6</text>
<text text-anchor='middle' x='552' y='692' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='560' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='560' y='212' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='560' y='404' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='560' y='500' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='560' y='548' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='560' y='596' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='560' y='644' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='560' y='692' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='568' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='568' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='568' y='212' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='568' y='452' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='568' y='500' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='568' y='596' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='568' y='692' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='576' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='576' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='576' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='576' y='404' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='576' y='452' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='576' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='576' y='548' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='576' y='596' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='576' y='644' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='576' y='692' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='584' y='116' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='584' y='212' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='584' y='404' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='584' y='452' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='584' y='500' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='584' y='548' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='584' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='584' y='644' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='584' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='116' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='592' y='164' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='592' y='260' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='592' y='404' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='592' y='452' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='500' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='592' y='548' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='596' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='592' y='644' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='692' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='600' y='164' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='600' y='212' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='600' y='260' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='600' y='404' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='600' y='500' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='600' y='548' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='600' y='644' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='600' y='692' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='608' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='608' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='608' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='608' y='260' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='608' y='404' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='608' y='452' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='608' y='500' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='608' y='548' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='608' y='596' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='608' y='644' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='616' y='116' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='616' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='616' y='212' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='616' y='404' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='616' y='452' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='616' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='616' y='596' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='616' y='692' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='624' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='624' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='624' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='624' y='260' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='624' y='404' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='624' y='500' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='624' y='548' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='624' y='596' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='624' y='644' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='624' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='632' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='632' y='260' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='632' y='404' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='632' y='452' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='632' y='500' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='632' y='548' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='632' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='632' y='644' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='632' y='692' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='640' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='640' y='164' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='640' y='212' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='640' y='260' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='640' y='452' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='640' y='596' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='640' y='692' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='648' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='648' y='164' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='648' y='260' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='648' y='500' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='648' y='548' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='648' y='596' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='648' y='644' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='648' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='656' y='116' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='656' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='656' y='212' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='656' y='260' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='656' y='404' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='656' y='452' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='656' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='656' y='548' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='656' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='656' y='644' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='656' y='692' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='664' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='664' y='164' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='664' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='664' y='404' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='664' y='452' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='664' y='500' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='664' y='548' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='664' y='596' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='664' y='644' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='664' y='692' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='672' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='672' y='164' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='672' y='212' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='672' y='260' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='672' y='452' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='672' y='500' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='672' y='548' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='672' y='596' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='672' y='644' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='672' y='692' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='680' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='680' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='680' y='260' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='680' y='404' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='680' y='500' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='680' y='548' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='680' y='596' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='680' y='644' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='680' y='692' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='688' y='116' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='688' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='688' y='212' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='688' y='404' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='688' y='452' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='688' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='688' y='548' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='688' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='688' y='644' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='688' y='692' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='696' y='164' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='696' y='212' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='696' y='260' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='696' y='404' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='696' y='452' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='696' y='500' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='696' y='548' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='696' y='596' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='696' y='644' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='696' y='692' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='704' y='116' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='704' y='164' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='704' y='212' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='704' y='260' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='704' y='404' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='704' y='452' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='704' y='500' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='704' y='548' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='704' y='644' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='704' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='712' y='116' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='712' y='164' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='712' y='212' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='712' y='260' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='712' y='404' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='712' y='452' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='712' y='500' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='712' y='548' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='712' y='596' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='712' y='644' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='712' y='692' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='720' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='720' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='720' y='212' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='720' y='260' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='720' y='404' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='720' y='452' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='720' y='500' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='720' y='548' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='720' y='596' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='720' y='644' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='720' y='692' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='728' y='116' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='728' y='164' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='728' y='212' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='728' y='260' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='728' y='404' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='728' y='452' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='728' y='500' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='728' y='548' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='728' y='596' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='728' y='644' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='736' y='164' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='736' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='736' y='260' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='736' y='404' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='736' y='452' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='736' y='500' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='736' y='548' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='736' y='596' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='736' y='644' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='736' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='744' y='164' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='744' y='212' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='744' y='260' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='744' y='404' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='744' y='452' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='744' y='500' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='744' y='548' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='744' y='596' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='744' y='644' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='744' y='692' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='752' y='212' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='752' y='260' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='752' y='404' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='752' y='452' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='752' y='548' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='752' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='752' y='644' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='752' y='692' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='760' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='760' y='260' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='760' y='404' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='760' y='548' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='760' y='596' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='760' y='644' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='760' y='692' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='768' y='212' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='768' y='260' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='768' y='404' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='768' y='548' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='768' y='644' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='768' y='692' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='776' y='260' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='776' y='308' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='776' y='404' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='776' y='548' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='776' y='596' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='776' y='644' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='776' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='784' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='784' y='260' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='784' y='308' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='784' y='548' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='784' y='596' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='784' y='644' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='784' y='692' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='792' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='792' y='308' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='792' y='404' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='792' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='792' y='692' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='800' y='212' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='800' y='260' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='800' y='308' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='800' y='404' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='800' y='548' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='800' y='596' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='800' y='644' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='800' y='692' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='808' y='212' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='808' y='260' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='808' y='404' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='808' y='548' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='808' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='808' y='644' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='808' y='692' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='816' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='816' y='260' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='816' y='308' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='816' y='404' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='816' y='548' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='816' y='596' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='816' y='644' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='816' y='692' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='824' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='824' y='260' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='824' y='308' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='824' y='548' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='824' y='596' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='824' y='644' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='832' y='212' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='832' y='260' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='832' y='308' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='832' y='404' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='832' y='548' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='832' y='596' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='832' y='644' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='832' y='692' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='840' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='840' y='260' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='840' y='308' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='840' y='404' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='840' y='548' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='840' y='644' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='840' y='692' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='848' y='212' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='848' y='260' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='848' y='308' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='848' y='404' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='848' y='548' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='848' y='596' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='848' y='644' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='848' y='692' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='856' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='856' y='308' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='856' y='404' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='856' y='596' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='856' y='692' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='864' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='864' y='260' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='864' y='308' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='864' y='404' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='864' y='548' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='864' y='596' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='864' y='644' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='864' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='872' y='212' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='872' y='260' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='872' y='308' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='872' y='404' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='872' y='548' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='872' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='872' y='644' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='872' y='692' fill='currentColor' style='font-size:1em'>,</text>
<text text-anchor='middle' x='880' y='212' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='880' y='308' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='880' y='404' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='880' y='596' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='888' y='260' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='888' y='308' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='888' y='404' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='888' y='548' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='888' y='596' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='888' y='644' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='888' y='692' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='896' y='260' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='896' y='308' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='896' y='404' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='896' y='548' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='896' y='596' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='896' y='644' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='896' y='692' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='904' y='260' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='904' y='308' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='904' y='404' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='904' y='548' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='904' y='596' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='904' y='644' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='904' y='692' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='912' y='20' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='912' y='260' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='912' y='308' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='912' y='404' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='912' y='548' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='912' y='596' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='912' y='644' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='912' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='920' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='920' y='260' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='920' y='404' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='920' y='548' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='920' y='596' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='920' y='644' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='920' y='692' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='928' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='928' y='260' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='928' y='308' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='928' y='404' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='928' y='548' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='928' y='596' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='928' y='644' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='928' y='692' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='936' y='20' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='936' y='260' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='936' y='308' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='936' y='404' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='936' y='548' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='936' y='596' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='936' y='644' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='936' y='692' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='944' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='944' y='260' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='944' y='308' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='944' y='404' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='944' y='548' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='944' y='596' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='944' y='644' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='944' y='692' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='952' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='952' y='260' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='952' y='308' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='952' y='404' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='952' y='548' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='952' y='596' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='952' y='644' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='952' y='692' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='960' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='960' y='308' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='960' y='404' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='960' y='692' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='968' y='20' fill='currentColor' style='font-size:1em'>z</text>
<text text-anchor='middle' x='968' y='308' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='968' y='404' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='968' y='692' fill='currentColor' style='font-size:1em'>}</text>
<text text-anchor='middle' x='976' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='984' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='992' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='1000' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='1008' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='1016' y='20' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='1024' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='1032' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='1040' y='20' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='1048' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='1056' y='20' fill='currentColor' style='font-size:1em'>r</text>
</g>

    </svg>
  
</div>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>oAuth web flow is a complex protocol that is necessary to cover all attack vectors and use cases, but enables a secure
and convenient way of authentication and authorisation. The complexity of the protocol is hidden behind libraries, but a
developer who is aware of the flows can make better decisions and understand the security implications of their choices.</p>
<p>Because the complexity is hidden, developers should not hesitate to use oAuth for their services. It is a secure,
user-friendly way to authenticate users and should be preferred over static credentials.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://schlomo.schapiro.org/2016/05/lifting-curse-of-static-credentials.html" target="_blank" rel="noreferrer">Static Credentials and why they are one of the biggest hazards in modern IT</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://auth0.com/docs/authenticate/protocols/openid-connect-protocol" target="_blank" rel="noreferrer">OpenID Connect</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://datatracker.ietf.org/doc/html/rfc6749" target="_blank" rel="noreferrer">RFC 6749 - The OAuth 2.0 Authorization Framework</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://curity.io/resources/learn/oauth-overview/" target="_blank" rel="noreferrer">The OAuth 2.0 by Curity</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use" target="_blank" rel="noreferrer">The OAuth 2.0 by Auth0</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://swagger.io/docs/specification/authentication/oauth2/" target="_blank" rel="noreferrer">Swagger oAuth Flows</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="devops" label="DevOps"/><category scheme="taxonomy:Tags" term="standards" label="Standards"/></entry><entry><title type="html">Agile Software Architecture</title><link href="https://philodev.one/posts/2024-05-agile-architecture/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-04-event-sourcing/?utm_source=atom_feed" rel="related" type="text/html" title="Event Sourcing for long living projects"/><link href="https://philodev.one/posts/2024-02-feature-flags/?utm_source=atom_feed" rel="related" type="text/html" title="Gitlab Feature Flags (for Backends)"/><link href="https://philodev.one/posts/2024-01-symfony-queues/?utm_source=atom_feed" rel="related" type="text/html" title="Symfony Messenger Component step by step"/><link href="https://philodev.one/posts/2024-01-using-php-attributes/?utm_source=atom_feed" rel="related" type="text/html" title="Dive into PHP Attributes"/><link href="https://philodev.one/posts/2023-11-using-data-to-ignite-action/?utm_source=atom_feed" rel="related" type="text/html" title="Using data for Sprint Planning"/><id>https://philodev.one/posts/2024-05-agile-architecture/</id><published>2024-05-28T10:20:44+02:00</published><updated>2024-05-28T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Architecture is no longer a set of diagrams that define upfront how features are implemented, but a continuously growing and evolving set of decisions</blockquote><div class="lead !mb-9 text-xl">
  Architecture is no longer a set of diagrams that define upfront how features are implemented, but a continuously growing
and evolving set of decisions
</div>

<h2 id="agile-architecture" class="relative group">Agile Architecture <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#agile-architecture" aria-label="Anchor">#</a></span></h2><p>One change that came with the agile culture was replacing detailed architecture plans and class structure diagrams &quot;
YAGNI&quot; mentality of only developing the current ticket losing overview over the bigger picture. Both extremes are not
practical and will end up in an agile architecture.</p>
<p>The term Agile Architecture implies that a software system is designed in a versatile, easy to-evolve, changeable way,
while also being resilient to change; but also that the architecture is contiguously growing in an iterative live cycle
to evolve with respect to the upcoming features of the product.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>In every software project, some decisions need to be made upfront, that will highly influence the architecture of the
project - programming language, database decision, authentication, patterns &hellip;
These decisions should not be solved by the first feature ticket by one developer. But I had the experience that exactly
that happens - one developer gets the task of &ldquo;build the project&rdquo;, locks themselves in a dark room and emerges after
weeks with a bare bone of a project every other team member is forced to use from that point on.</p>
<h2 id="defining-architecture-and-their-requirements" class="relative group">Defining Architecture and their Requirements <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#defining-architecture-and-their-requirements" aria-label="Anchor">#</a></span></h2><p>From my idealistic point of view, the architecture decisions should be discussed in the team, after understanding the
idea of the product, to design an agile architecture that is flexible enough to be iterated on.
For this to work, architecture can not be defined the same way as in Waterfall projects in which the architecture was
designed and set in stone before the first ticket was started. &ldquo;The software architecture isn&rsquo;t a set of diagrams, it&rsquo;s
not a set of review meetings, it&rsquo;s not a software architecture document, but it is a set of decisions that the team
makes about some critical aspects of the system&rdquo;. <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<h3 id="capturing-and-documenting-architecture" class="relative group">Capturing and Documenting Architecture <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#capturing-and-documenting-architecture" aria-label="Anchor">#</a></span></h3><p>Viewing Architecture as a set of decisions makes the Architecture Decision Records a very relatable way of documenting
architecture.
Drawing fancy diagrams - something I enjoy to do - is a great way to document how a system is working, but often enough
the question of why it was built this way is the more important question if developers see themselves confronted with
the need for change.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Architecture Design Records: A set of point in time documentation of architectural decisions, usually stored in the code
base to get information on the thoughts and reasons why the code was implemented in a certain
way. <a href="https://www.blog.philodev.one/posts/2023-04-communicating-between-teams/#architecture-decision-records" target="_blank" rel="noreferrer">I wrote more about it in this post</a>.</span>
</div>

<p>The boundary of the architectural decision in contrast to an implementation decision is not easy, by may be defined for
practical reasons - if the cost of changing a decision, it is probably an architectural decision.</p>
<h3 id="architecture-perspectives-for-requirements" class="relative group">Architecture Perspectives for Requirements <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#architecture-perspectives-for-requirements" aria-label="Anchor">#</a></span></h3><p>While Agile Methodologies provide a wide range of tools to define the requirements for products from a user and a
business perspective; they often lack the perspective of an architect, future developer, or tester.
When formulating the User Story, the architectural requirements are often left out, which means in agile they are
invisible to time constraints, deadlines, and work recognition.</p>
<p>There is one common framework existing that deals with the definition of such architectural or quality attribute
requirements: The Six Part Scenario</p>
<ul>
<li>Source of stimulus (some entity or event, e.g. a user, an attacker)</li>
<li>Stimulus (condition that needs to be considered, e.g. faulty request)</li>
<li>Environment (providing context, e.g. during overloaded times, while DB is recovering from an error)</li>
<li>Artifact (what part of the system is acting)</li>
<li>Response (activity undertaken after the arrival of the stimulus, e.g. reporting, escalating, restarting)</li>
<li>Response measure (make the response measurable and testable)
<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></li>
</ul>
<p>Some examples of these requirements, that highly interfere with the architecture:</p>
<ul>
<li>A User requires the handling of a large numbers items by a microservice, in an environment that does not require sync
processes, but handling of the microservice failing; the services uses an async communication, the current state and
number of tries should be reported (may lead to a Queue that supports retry mechanisms)</li>
<li>An event is dispatched to trigger a command, but the command will fail as the Database is currently recovering; the
command should be retried automatically several times before it fails and reports an error.</li>
<li>One User requests a separate file format and therefore requires the usage of a different (third party) service instead
of the most used, in a normal business environment; the system should be able to automatically detect file format by
input and switch the service used, the used client should be stored and visible to the user. (Might lead to something
like a driver pattern)</li>
<li>A User want to authenticate against the system and related microservices in a normal business environment; The
authentication process should include the permissions to also authenticate against the microservices, the system
should run without a separate authentication (might lead to something like oAuth)</li>
<li>A User requests a list of data entries without the need to store something, during a timeslot with very high demand;
the system should direct such request to a read replica of the DB; the Master-DB statistics should reflect a much
lower number of only read statements (might lead to Query Command Segregation)</li>
</ul>
<p>These requirements match partially with the idea of non-functional requirements; but functional requirements do not by
definition have the major impact on development cost.
Architectural / Design Requirements may enable or stop non-functional requirements, and functional requirements should
be consulted to create architectural decisions. How many microseconds a request may take is a non-functional requirement
that may be satisfied without making costly future decisions. As sidenote, the idea of framing non-functional
requirements in a quantitative, measurable, testable number (target number and unacceptable number) also underlines that
these requirements are revisited regularly, influenced by the architecture, but not causing architectural changes per
se  <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<h3 id="documenting-architecture-characteristics-update-06102024" class="relative group">Documenting Architecture Characteristics (update 06.10.2024) <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#documenting-architecture-characteristics-update-06102024" aria-label="Anchor">#</a></span></h3><p>The analysis that resulted in the Architecture Characteristics will impact their effectiveness. From all architecture
characteristics, the (random number, 7) most important should be documented, with the areas of the system the
characteristics apply to and the sources of the characteristics (like an event storming session).</p>
<p>If the characteristics are measurable, documenting them as
<a href="https://philodev.one/posts/2024-09-evolutionary-architecture/">fitness functions</a> can be a great pattern.</p>
<h2 id="how-to-design-agile-architecture" class="relative group">How to design Agile Architecture <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#how-to-design-agile-architecture" aria-label="Anchor">#</a></span></h2><h3 id="minimal-viable-architecture" class="relative group">Minimal Viable Architecture <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#minimal-viable-architecture" aria-label="Anchor">#</a></span></h3><p>Similar to the concept of a Minimum Viable Product, the idea of a Minimum Viable Architecture is to deliver an
architecture that fulfils the current point in time relevant requirements. This architecture is iterated over in the
upcoming features and requirements.<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<ul>
<li><em>Model the architecture</em>: The Model should be a tool for communication (not documentation)</li>
<li><em>Consider Alternatives</em>: Following the LEAN principles, discuss more than one option and consider drawbacks and
benefits</li>
<li><em>Mind Conways Law</em>: Companies tend to implement systems that reflect their communication structure. If there is no
functioning communication structure to the team that builds the service that your system requires, the implementation
might reflect that</li>
<li><em>Architect for change</em>: The Architecture will change within the agile process, it can not and should not be defined in
a way that eliminates future opportunities</li>
<li><em>Mind testability, deploy-ability, and developer usability</em>: The Devs, Testers, and Infra are the users of the
architecture that is built. It should be clear and easy to use it.</li>
<li><em>Keep minimal viable</em>: Travel light - Making too many decisions too early might restrict future implementations. If
there is a decision that might as well be set in stone later, delay it</li>
</ul>
<h3 id="feedback-loops" class="relative group">Feedback loops <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#feedback-loops" aria-label="Anchor">#</a></span></h3><p>One of the form my point of view most important perspectives of the Quality Attribute Requirements is the visibility of
the result. How are those architectural requirements visible to the user, the dev (so the user of the code), or the
tester?</p>
<p>Looking at the former requirements, the respective user may be asked if the decisions led to the desired quality
attributes. When a new Developer joins the team, is the code structure easy to follow and understand? How clear is it
for the tester to confirm the testability? How easy is the project to deploy and how often do the architecture decisions
cause interruptions? Do the current devs enjoy working in the architecture?</p>
<p>Refining such quality attributes and assessing them across teams might be a part of the modern interpretation of an
architect&rsquo;s role.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Architecture is no longer a step in development, but a continuous process of iterative decisions. As those decisions
happen in strong coupling with the current product requirements and the developers who are working on the code they can
and should not be practised in a closed room, but in an open space. Architecture decisions should be documented,
evaluated, experimented, and assessed.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://insights.sei.cmu.edu/documents/1395/2014_101_001_493902.pdf" target="_blank" rel="noreferrer">How to Agilely Architect an Agile Architecture</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://www.infoq.com/podcasts/continuous-architecture/" target="_blank" rel="noreferrer">Continuous Architecture with Kurt Bittner and Pierre Pureur</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://www.win.tue.nl/~wstomv/edu/2ii45/year-0910/Software_Architecture_in_Practice_2nd_Edition_Chapter4.pdf" target="_blank" rel="noreferrer">Software Architecture in Practice, Felix Bachman and Mark Klein</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://scaledagileframework.com/nonfunctional-requirements/" target="_blank" rel="noreferrer">Non Functional Requirements</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://continuousarchitecture.com/2021/12/21/minimum-viable-architecture-how-to-continuously-evolve-an-architectural-design-over-time/" target="_blank" rel="noreferrer">Minimal Viable Architecture</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="agile" label="Agile"/></entry><entry><title type="html">Event Sourcing for long living projects</title><link href="https://philodev.one/posts/2024-04-event-sourcing/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2024-01-symfony-queues/?utm_source=atom_feed" rel="related" type="text/html" title="Symfony Messenger Component step by step"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="related" type="text/html" title="About Actions, Jobs, Repositories, Events"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><id>https://philodev.one/posts/2024-04-event-sourcing/</id><published>2024-04-28T10:20:44+02:00</published><updated>2024-04-28T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Event Sourcing is a software pattern for stateful entity management. Instead of storing the current state of an Entity, only the state changes are stored. This blog post is about the advantages and disadvantages of the pattern, and how to avoid some challenges I faced in long living projects.</blockquote><div class="lead !mb-9 text-xl">
  Event Sourcing is a software pattern for stateful entity management. Instead of storing the current state of an Entity,
only the state changes are stored. This blog post is about the advantages and disadvantages of the pattern, and how to
avoid some challenges I faced in long living projects.
</div>

<h2 id="about-event-sourcing" class="relative group">About Event Sourcing <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#about-event-sourcing" aria-label="Anchor">#</a></span></h2><p>Event Sourcing is a software pattern for stateful entity management. Instead of storing the current state of an (
aggregate) entity, the state is derived from a sequence of (domain) events.</p>
<p>To implement such a pattern, the entity must have some kind of livecycle. This can be a finite state machine, for
example the state of an order (<code>placed</code>, <code>paid</code>, <code>shipped</code>, <code>delivered</code>, <code>returnRequested</code> &hellip;); or a tracking of state
like a bank account (<code>+12.4€</code>, <code>-0.33€</code>, <code>+145.29</code>, &hellip;).
In any case, the final entity state is derived from the sequence of events that happened to the entity.</p>
<h3 id="implementation-idea" class="relative group">Implementation Idea <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#implementation-idea" aria-label="Anchor">#</a></span></h3><p>Arbitrary Idea for the Implementation: &ldquo;As a Dog Owner, I want a system to track the contest results of my dog&rdquo;.</p>
<p>Let&rsquo;s start with the event requirements.
The Product/Dog Owner wants a list of all the contests, and track the current state of their dog. This includes if the
current local Dog License is passed or not, what the last achievement was, and what the all-time record ranking of the
dog is.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">abstract</span> <span class="k">class</span> <span class="nc">Achievement</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="nx">readonly</span> <span class="nx">DateTime</span> <span class="nv">$recordedAt</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">private</span> <span class="nx">string</span> <span class="nv">$contestIdentifier</span><span class="p">,</span> <span class="nx">DateTimeImmutable</span> <span class="nv">$recordedAt</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">recordedAt</span> <span class="o">=</span> <span class="nv">$recordedAt</span> <span class="o">??</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>        
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ObedienceAchievement</span> <span class="k">extends</span> <span class="nx">Achievement</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">private</span> <span class="nx">string</span> <span class="nv">$contestIdentifier</span><span class="p">,</span> <span class="k">private</span> <span class="nx">int</span> <span class="nv">$points</span><span class="p">,</span> <span class="k">private</span> <span class="nx">int</span> <span class="nv">$ranking</span><span class="p">,</span> <span class="nx">DateTimeImmutable</span> <span class="nv">$recordedAt</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">parent</span><span class="o">::</span><span class="na">__construct</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">contestIdentifier</span><span class="p">,</span> <span class="nv">$recordedAt</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DogLicenseAchievement</span> <span class="k">extends</span> <span class="nx">Achievement</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">private</span> <span class="nx">string</span> <span class="nv">$contestIdentifier</span><span class="p">,</span> <span class="k">private</span> <span class="nx">bool</span> <span class="nv">$passed</span><span class="p">,</span> <span class="nx">DateTimeImmutable</span> <span class="nv">$recordedAt</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">parent</span><span class="o">::</span><span class="na">__construct</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">contestIdentifier</span><span class="p">,</span> <span class="nv">$recordedAt</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// The Event Table
</span></span></span><span class="line"><span class="cl"><span class="nx">CREATE</span> <span class="nx">TABLE</span> <span class="nx">achievements</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nx">id</span> <span class="nx">UUID</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">dog_id</span> <span class="nx">UUID</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">context_identifier</span> <span class="nx">VARCHAR</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">recorded_at</span> <span class="nx">TIMESTAMP</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">data</span> <span class="nx">JSON</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></div><p>This makes storing new achievements very easy, the controller can do a single, very fast query to add the newest
achievement to the database without caring about any state change.
Because of the different event types with different data, the <code>data</code> column is a JSON column, like no developer ever
regretted adding json data fields in relational databases. The <code>dogId</code> is not part of the event, but part of the table
to ensure a foreign relation to a dogs table, which holds data that does not change the state, e.g. the breed, owner, or
birthday.</p>
<p>Now to the entity, the Dog. Ignoring the contents of the dogs table, the Dog Entity is made up of an apply function,
which on instantiation applies each event until the current state is reproduced.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Dog</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">array</span> <span class="nv">$achievements</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nx">bool</span> <span class="nv">$dogLicensePassed</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="o">?</span><span class="nx">int</span> <span class="nv">$allTimeRanking</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="o">?</span><span class="nx">int</span> <span class="nv">$lastObediencePoints</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="o">?</span><span class="nx">DateTime</span> <span class="nv">$lastAchievement</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">apply</span><span class="p">(</span><span class="k">array</span> <span class="nv">$achievements</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">achievements</span><span class="p">[]</span> <span class="o">=</span> <span class="nv">$achievement</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span> <span class="p">(</span><span class="nv">$achievements</span> <span class="k">as</span> <span class="nv">$achievement</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">lastAchievement</span> <span class="o">=</span> <span class="nv">$achievement</span><span class="o">-&gt;</span><span class="na">recordedAt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">            <span class="k">switch</span> <span class="p">(</span><span class="k">true</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">case</span> <span class="nv">$achievement</span> <span class="nx">instanceof</span> <span class="nx">ObedienceAchievement</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">                    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">lastObediencePoints</span> <span class="o">=</span> <span class="nv">$achievement</span><span class="o">-&gt;</span><span class="na">points</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">allTimeRanking</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">allTimeRanking</span> <span class="o">===</span> <span class="k">null</span> 
</span></span><span class="line"><span class="cl">                        <span class="o">?</span> <span class="nv">$achievement</span><span class="o">-&gt;</span><span class="na">ranking</span> 
</span></span><span class="line"><span class="cl">                        <span class="o">:</span> <span class="nx">min</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">allTimeRanking</span><span class="p">,</span> <span class="nv">$achievement</span><span class="o">-&gt;</span><span class="na">ranking</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="k">case</span> <span class="nv">$achievement</span> <span class="nx">instanceof</span> <span class="nx">DogLicenseAchievement</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">                    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">dogLicensePassed</span> <span class="o">=</span> <span class="nv">$achievement</span><span class="o">-&gt;</span><span class="na">passed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                    <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The <code>apply</code> function is called with the events from the database, and the entity is in the correct state. For this
pattern a repository is pattern that will help to control the hydration from the DB. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<h3 id="advantages" class="relative group">Advantages <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#advantages" aria-label="Anchor">#</a></span></h3><p>Especially when coming from Eloquents Active Record Pattern, this seems a bit complicated, and require some awareness of
the benefits of segregating storing state changes and querying the state.</p>
<ul>
<li><strong>Audit Trail</strong>: The event table is a perfect audit trail, as it holds all the changes to the entity. For some
projects of the financial sector this can be required by law, for others a history is &ldquo;only&rdquo; a required user feature,
and worst case this is great to replay the state of the entity at any given point in time for debugging. <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></li>
<li><strong>Scalability</strong>: The event table is append only, which makes it very easy to scale the database. The only thing that
needs to be ensured is that the events are stored in the correct order. Also horizontal scaling can become very easy
as splitting by <code>dog_id</code> can be done.</li>
<li><strong>Performance</strong>: The event table is very fast to write, and the separation of query and command ensures that the
database is not blocked by long running queries. For many use cases the reliability of storing has a higher priority.</li>
<li><strong>Simplicity</strong>: Since years devs (in my bubble) are discussing event sourcing as great pattern, so many devs are aware
of the pattern and will know their way around the code.</li>
<li><strong>Testing</strong>: Any testcase can be defined and prepared by the starting list of events, and the expected state of the
entity. This makes testing very easy, and the tests very readable.</li>
</ul>
<h3 id="disadvantages" class="relative group">Disadvantages <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#disadvantages" aria-label="Anchor">#</a></span></h3><ul>
<li><strong>Memory</strong>: Besides the really big table that holds the event data, in our case with the potentially big JSON column,
the entity in memory can become quite big. When one entity is loaded, all events need to be applied to the entity, and
therefore fetched into RAM. Those are problems that are manageable, but need to be considered.</li>
<li><strong>Eventual consistency</strong>: The entity is not in a consistent state at any given point in time. There might be two
events simultaneously that change the same state, and the order of the events is important. Again here are technical
solutions like locking, or business solutions like making each event idempotent.</li>
<li><strong>Querying</strong>: The json column might hold events of different types, and the query to get the current state of the
entity can become quite complex. This can be solved by a view, or by storing important information as separate
columns (like in this case <code>contestIdentifier</code>). But when the Product/Dog Owner wants to know if one dog is the best
of breed in all Obedience Contests, the query can become quite complex, when also all other achievements have to be
sorted out.</li>
<li><strong>Serialization</strong>: The JSON column might hold old events, former versions. The serialization of the events might
change, and the entity might not be able to apply the old events. This can be solved by versioning the events and a
custom deserialization.</li>
</ul>
<h2 id="event-sourcing-in-long-living-projects" class="relative group">Event Sourcing in long living projects <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#event-sourcing-in-long-living-projects" aria-label="Anchor">#</a></span></h2><p>In theory many software patterns are great, but implementing them in a long living project can reveal some challenges.
I would like to share some solutions of the challenges I faced.</p>
<h3 id="the-database-decision" class="relative group">The database decision <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-database-decision" aria-label="Anchor">#</a></span></h3><p>If the goal of the event sourcing is only storing the current value over time - hold your horses dear PHP Devs - maybe a
relational database is not what you are looking for. Time series databases might be an option. On the other hand if you
don&rsquo;t need to query too much, and just hold the maybe changing data points, a document oriented database might the
easiest solution.</p>
<p>If you go the for the relational database, most probably because you have a somewhat structured data model and the
requirement to query large sets of data points based on properties in typed columns, there still might be a need for a
json column. If I could choose to avoid it, I would. If the feature sets does not allow avoiding it, I highly recomend
Postgres&rsquo; jsonb column (with or without an index) over mariaDbs json column. <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<h3 id="event-versioning-using-a-discriminator-map" class="relative group">Event Versioning using a discriminator map <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#event-versioning-using-a-discriminator-map" aria-label="Anchor">#</a></span></h3><p>The day might come in which the event structure changes. A new field is added to an event, an old event is obsolete -
one day there will be an event stored in the database that is not easily applied to the entity. An implementation where
this can not happen, because all events are serialized to the same class, with the identifier stored in an enum to hide
the complexity of versioning is possible - which would make this paragraph obsolete. Often the different events are
instantiated to different classes.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Decisions like how to name the identifier and what process to follow when an event is changed should be discussed in the
team and best case documented in e.g. Architecture Decision Records.</span>
</div>

<p>There needs to be an identifier to the type. In the easiest implementation the fully classified class name is stored in
the database - which would cause migrations on a directory name change. Therefore, the identifier should be a string.
As the string should be only used by the constant, it doesn&rsquo;t need to be human-readable.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="c1">// a string identifier with version
</span></span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">const</span> <span class="no">ACHIEVED_OBEDIENCE</span> <span class="o">=</span> <span class="s1">&#39;achieved.v1.obidience&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// a string that is non human-readable, to decouple class name and identifier
</span></span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="k">const</span> <span class="no">ACHIEVED_OBEDIENCE_V2</span> <span class="o">=</span> <span class="s1">&#39;achieved.cda6d2f8-feaf-4818-a061-95228e0f3957&#39;</span><span class="p">;</span>
</span></span></code></pre></div><p>In Laravel this can be handled by Morph Maps and a Morph Many Relationship <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">Relation</span><span class="o">::</span><span class="na">enforceMorphMap</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Achievement</span><span class="o">::</span><span class="na">ACHIEVED_OBEDIENCE_V1</span><span class="p">,</span> <span class="nx">Achievement</span><span class="o">::</span><span class="na">ACHIEVED_OBEDIENCE_V2</span> <span class="o">=&gt;</span> <span class="nx">ObedienceAchievement</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Achievement</span><span class="o">::</span><span class="na">ACHIEVED_DOG_LICENSE_V1</span> <span class="o">=&gt;</span> <span class="nx">DogLicenseAchievement</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span></code></pre></div><p>In Symfony the instantiation often happens more declarative, which also might cause a lot more boilerplate code. But
Symfony does support a similar feature <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. These exact implementation will not be discussed here, as I
personally had multiple problems implementing it. On one hand in this particular project the attributes were not an
option, on the other I require the discriminator map to be in code for better maintainability (if you can not click on
it, you will not maintain it); also, I found myself debugging the Injection of the resulting serializer very hard -
please feel free to teach me better and share your implementation.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">function</span> <span class="nf">fromArray</span><span class="p">(</span><span class="k">array</span> <span class="nv">$row</span><span class="p">)</span><span class="o">:</span> <span class="nx">Achievement</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$identifier</span> <span class="o">=</span> <span class="nv">$data</span><span class="p">[</span><span class="s1">&#39;identifier&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">match</span> <span class="p">(</span><span class="nv">$identifier</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">self</span><span class="o">::</span><span class="na">ACHIEVED_OBEDIENCE_V2</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">ObedienceAchievement</span><span class="p">(</span><span class="nv">$row</span><span class="p">[</span><span class="s1">&#39;contestIdentifier&#39;</span><span class="p">],</span> <span class="nv">$row</span><span class="p">[</span><span class="s1">&#39;points&#39;</span><span class="p">],</span> <span class="nv">$row</span><span class="p">[</span><span class="s1">&#39;ranking&#39;</span><span class="p">],</span> <span class="nv">$row</span><span class="p">[</span><span class="s1">&#39;recordedAt&#39;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// historically there was no contest identifier in the past, however all contests before the change had the same identifier
</span></span></span><span class="line"><span class="cl">        <span class="nx">self</span><span class="o">::</span><span class="na">ACHIEVED_OBEDIENCE_V1</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">ObedienceAchievement</span><span class="p">(</span><span class="s1">&#39;Obedience Trail 2023&#39;</span><span class="p">,</span> <span class="nv">$row</span><span class="p">[</span><span class="s1">&#39;points&#39;</span><span class="p">],</span> <span class="nv">$row</span><span class="p">[</span><span class="s1">&#39;ranking&#39;</span><span class="p">],</span> <span class="nv">$row</span><span class="p">[</span><span class="s1">&#39;recordedAt&#39;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">        <span class="k">default</span> <span class="o">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">InvalidArgumentException</span><span class="p">(</span><span class="s1">&#39;Unknown identifier: &#39;</span> <span class="o">.</span> <span class="nv">$identifier</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="event-deserialization" class="relative group">Event deserialization <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#event-deserialization" aria-label="Anchor">#</a></span></h3><p>Repository classes containing to instantiate entities from the database are sometimes quite big and messy.
A cleaner solution for this problem that comes in handy with instantiating events from json or from a raw database row
is using a normalizer. <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">AchievementNormalizer</span> <span class="k">implements</span> <span class="nx">NormlizerInterface</span><span class="p">,</span> <span class="nx">DenormalizerInterface</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">const</span> <span class="no">ACHIEVEMENTS_MAP</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Achievement</span><span class="o">::</span><span class="na">ACHIEVED_OBEDIENCE_V1</span><span class="p">,</span> <span class="nx">Achievement</span><span class="o">::</span><span class="na">ACHIEVED_OBEDIENCE_V2</span> <span class="o">=&gt;</span> <span class="nx">ObedienceAchievement</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Achievement</span><span class="o">::</span><span class="na">ACHIEVED_DOG_LICENSE_V1</span> <span class="o">=&gt;</span> <span class="nx">DogLicenseAchievement</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">private</span> <span class="nx">ObjectNormalizer</span> <span class="nv">$normalizer</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">normalize</span><span class="p">(</span><span class="nv">$object</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$format</span> <span class="o">=</span> <span class="k">null</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="p">[])</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">normalizer</span><span class="o">-&gt;</span><span class="na">normalize</span><span class="p">(</span><span class="nv">$object</span><span class="p">,</span> <span class="nv">$format</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">denormalize</span><span class="p">(</span><span class="nv">$data</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$type</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$format</span> <span class="o">=</span> <span class="k">null</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="p">[])</span><span class="o">:</span> <span class="nx">Achievement</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$identifier</span> <span class="o">=</span> <span class="nv">$data</span><span class="p">[</span><span class="s1">&#39;identifier&#39;</span><span class="p">]</span> <span class="o">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">InvalidArgumentException</span><span class="p">(</span><span class="s1">&#39;No identifier found&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$identifier</span> <span class="o">==</span> <span class="s1">&#39;*the super old identifier we do barely support*&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">new</span> <span class="nx">DepricatedAchievement</span><span class="p">(</span><span class="nv">$identifier</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">        <span class="nv">$type</span> <span class="o">=</span> <span class="nx">self</span><span class="o">::</span><span class="na">ACHIEVEMENTS_MAP</span><span class="p">[</span><span class="nv">$identifier</span><span class="p">]</span> <span class="o">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">InvalidArgumentException</span><span class="p">(</span><span class="s1">&#39;Unknown type: &#39;</span> <span class="o">.</span> <span class="nv">$identifier</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">normalizer</span><span class="o">-&gt;</span><span class="na">denormalize</span><span class="p">(</span><span class="nv">$data</span><span class="p">,</span> <span class="nv">$type</span><span class="p">,</span> <span class="nv">$format</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">supportsDenormalization</span><span class="p">(</span><span class="nv">$data</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$type</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$format</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span><span class="o">:</span> <span class="nx">bool</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$type</span> <span class="o">===</span> <span class="nx">Achievement</span><span class="o">::</span><span class="na">class</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getSupporedClass</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">[</span><span class="nx">Achievement</span><span class="o">::</span><span class="na">class</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Having a special normalizer for this enables the developer to have a clean repository class, but still provides a place
to hook into the deserialization process, set defaults for old fields, or throw exceptions for unknown fields.
The discriminator map is hold in code, so any code editor can jump to the events, and back.</p>
<p>A test could look like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">function</span> <span class="nf">testSerializeAndDeserialize</span><span class="p">()</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$achievement</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ObedienceAchievement</span><span class="p">(</span><span class="s1">&#39;Obedience Trail 2023&#39;</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$encodedAchievement</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">serializer</span><span class="o">-&gt;</span><span class="na">serialize</span><span class="p">(</span><span class="nv">$achievement</span><span class="p">,</span> <span class="s1">&#39;json&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nv">$achievementArray</span> <span class="o">=</span> <span class="nx">json_decode</span><span class="p">(</span><span class="nv">$encodedAchievement</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertArrayHasKey</span><span class="p">(</span><span class="s1">&#39;identifier&#39;</span><span class="p">,</span> <span class="nv">$achievementArray</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertEquals</span><span class="p">(</span><span class="nx">Achievement</span><span class="o">::</span><span class="na">ACHIEVED_OBEDIENCE_V2</span><span class="p">,</span> <span class="nv">$achievementArray</span><span class="p">[</span><span class="s1">&#39;identifier&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nv">$deserialized</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">serializer</span><span class="o">-&gt;</span><span class="na">deserialize</span><span class="p">(</span><span class="nv">$encodedAchievement</span><span class="p">,</span> <span class="nx">Achievement</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="s1">&#39;json&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertInstanceOf</span><span class="p">(</span><span class="nx">ObedienceAchievement</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nv">$deserialized</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Also, a test that grabs all achievements from the directory folder and checks if they can be deserialized should be
added to ensure that the map is always updated when a developer adds a new achievement.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Event Sourcing is a great pattern, and for certain use cases the best solution. The implementation can be quite tricky,
but if the team works through the current and future challenges, the pattern can be a great addition to the project.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Implementation idea and code snippets are inspired by the book &ldquo;Implementing Domain-Driven Design&rdquo; by
Vaughn Vernon.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://event-driven.io/en/audit_log_event_sourcing/" target="_blank" rel="noreferrer">Audit Trailing via event sourcing</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://www.postgresql.org/docs/current/datatype-json.html" target="_blank" rel="noreferrer">Postgres JSONB</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://laravel.com/docs/11.x/eloquent-relationships#custom-polymorphic-types" target="_blank" rel="noreferrer">Laravel Morph Maps</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://symfony.com/doc/current/components/serializer.html#serializing-interfaces-and-abstract-classes" target="_blank" rel="noreferrer">Symfony Discriminator Map</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://symfony.com/doc/current/serializer/custom_normalizer.html" target="_blank" rel="noreferrer">Symfony Normalizer</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/><category scheme="taxonomy:Tags" term="symfony" label="Symfony"/></entry><entry><title type="html">Gitlab Feature Flags (for Backends)</title><link href="https://philodev.one/posts/2024-02-feature-flags/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2023-03-testing-open-api-specs/?utm_source=atom_feed" rel="related" type="text/html" title="Testing Open Api files"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><link href="https://philodev.one/posts/2024-01-symfony-queues/?utm_source=atom_feed" rel="related" type="text/html" title="Symfony Messenger Component step by step"/><link href="https://philodev.one/posts/2024-01-using-php-attributes/?utm_source=atom_feed" rel="related" type="text/html" title="Dive into PHP Attributes"/><link href="https://philodev.one/posts/2023-04-communicating-between-teams/?utm_source=atom_feed" rel="related" type="text/html" title="Communication between different teams working on the same codebase"/><id>https://philodev.one/posts/2024-02-feature-flags/</id><published>2024-03-05T10:20:44+02:00</published><updated>2024-03-05T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Feature Flags are both - a hit on the bullshit bingo and case for a trigger warning. This blog post is about how they can help, and how to use them in Gitlab.</blockquote><div class="lead !mb-9 text-xl">
  Feature Flags are both - a hit on the bullshit bingo and case for a trigger warning. This blog post is about how they
can help, and how to use them in Gitlab.
</div>

<h2 id="about-feature-flags" class="relative group">About Feature Flags <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#about-feature-flags" aria-label="Anchor">#</a></span></h2><p>Feature flags are a way to control the reachability of a feature in your application. For a basic implementation a
simple if-else statement can be used.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="c1">// todo: set to false before release
</span></span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="k">false</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">someGreatNewFeature</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">oldFeature</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>In a more advanced solution, there might be a setting in a config, or even an environment variable to toggle a feature
on or off. Again the next step might be an if statement depending on the user who is logged in, if they have a certain
permission or &ldquo;developer cookie&rdquo;.
But the most recent approach is to use a Feature Flag Service with an Api call to toggle it without a deployment.</p>
<h3 id="why-feature-flags" class="relative group">Why Feature Flags? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#why-feature-flags" aria-label="Anchor">#</a></span></h3><p>Feature Flags are a development tool that is very easy to sell. Business loves it, as they can see the new features
before they are completely released; Quality Assurance loves it, as they can test the new features without big hassle
with production data; database enthusiasts love it, as they can see the data behavior and performance in an early stage;
and release managers love it, as they can release the new feature step by step, maybe starting with a small group of
users who are a selected, well known, edge case free group of users.</p>
<p>There is a new epic to be released, and the mvp only satisfies a fraction of the possible users - feature flag can be
the tool to control the continuous release of the epic to more and more users.
Unsure if the release will work well? Only redirect a small percentage of the users to the new feature, and see if
exceptions are hitting the monitoring, and roll back if necessary.
Not sure if the build is even useful? Only release it to half the users and see which groups results in better KPIs (
A/B Testing).
Two systems deployed separately with the same code and new features should only be released to one of the systems?
Feature Flags again can solve the problem.
Also there are different kind of Feature Flags - from a certain point of view a permission system is a feature flag.
Some users may have access to a feature, that stay hidden for others. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<h3 id="red-flag-feature-flags" class="relative group">Red Flag Feature Flags? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#red-flag-feature-flags" aria-label="Anchor">#</a></span></h3><p>Feature flags come with downsides. The most obvious is the introduction of technical dept. Every Feature Flag introduced
in the code is on a certain level an if statement with a guaranteed future removal. At some point the feature is
activated for all users, or removed completely.</p>
<p>With that planned obsolescence, there is added complexity. The simpler the feature flag is designed, the bigger the
hassle to remove it, while on the other hand any work in designing nice feature flag mechanism is also work put into
technical dept. At one point people might ask &ldquo;What code is currently running?&rdquo;, &ldquo;Is that feature now used by
everyone?&rdquo;, &ldquo;Where did we put that flag again?&rdquo;, &ldquo;Why does that work for Jeff, and not me?&rdquo;, &ldquo;That worked on a different
environment!&rdquo;. Inconsistency is never a good thing, and Feature Flags are a way to introduce it <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<p><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Feature Flags are a release tool, not a configuration tool. They should be short lived, used for a specific purpose, and
keep in mind you always have to clean after them. And I repeat myself, they are short lived (days or weeks)</span>
</div>

<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>






  
  
<figure><img src="/images/2024-02-feature-flags.png" alt="Corgi with a flag" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="feature-flags-in-gitlab" class="relative group">Feature Flags in Gitlab <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#feature-flags-in-gitlab" aria-label="Anchor">#</a></span></h2><p>Depending on the User Case, different choices in Technology should be made. For a permission system there are better
solutions that anything that calls itself feature flag, and for A/B testing many Feature Flag libraries are not enough
focused on metrics.</p>
<p>In my Use Case I was looking for a simple implementation, an accessible overview of the current
feature flags, and a way to control the feature flags by user or context without a deployment. Gitlab offers an Unleash
Hosting which served my needs, bonus points to automatically track and display usages of feature flags in the code, and
not tracking a lot of metrics I don&rsquo;t need.</p>
<h3 id="adding-gitlab-feature-flags-with-the-stupid-questions-answered" class="relative group">Adding Gitlab Feature Flags with the stupid questions answered <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#adding-gitlab-feature-flags-with-the-stupid-questions-answered" aria-label="Anchor">#</a></span></h3><p>All together Gitlab Feature flags are easy to implement, and if you can avoid typos in the feature flag definition I
am confident you can make it around two hours faster than I was ;)</p>
<h4 id="adding-the-unleash-client" class="relative group">Adding the Unleash Client <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#adding-the-unleash-client" aria-label="Anchor">#</a></span></h4><p>**What is Unleash? ** Unleash is the Feature Flag Service Gitlab uses. Even the self-hosted Gitlab offers the Unleash
API to control Feature Flags that you can easily configure in the Gitlab UI. It is also possible to host Unleash
without Gitlab.</p>
<p>I found the PHP Client more versatile than the Symfony Client <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. While digging through the Unleash Client I
found clean written, supporting a lot of the Unleash API, and a very good documentation. Gitlab does not support all of
the possible Features, which I consider as a good thing, as it keeps the Feature Flags simple and easy to use.</p>
<p>For the implementation the Unleash Docs are great help <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. Mind that the AppName is the Gitlab Environment.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">class</span> <span class="nc">FeatureFlagService</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nx">Unleash</span> <span class="nv">$unleash</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nx">UnleashContext</span> <span class="nv">$context</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// configs can be found in the Gitlab GUI
</span></span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">unleash</span> <span class="o">=</span> <span class="nx">UnleashBuilder</span><span class="o">::</span><span class="na">createForGitlab</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">withInstanceId</span><span class="p">(</span><span class="s1">&#39;H9sU9yVHVAiWFiLsH2Mo&#39;</span><span class="p">)</span> <span class="c1">// this is an api key, keep it secret
</span></span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">withAppUrl</span><span class="p">(</span><span class="s1">&#39;https://git.example.com/api/v4/feature_flags/unleash/1&#39;</span><span class="p">)</span> <span class="c1">// url to unleash api
</span></span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">withGitlabEnvironment</span><span class="p">(</span><span class="s1">&#39;Production&#39;</span><span class="p">)</span> <span class="c1">// this is the environment name in Gitlab
</span></span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">context</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">UnleashContext</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">isEnabled</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$feature</span><span class="p">,</span> <span class="nx">bool</span> <span class="nv">$default</span> <span class="o">=</span> <span class="k">true</span><span class="p">)</span><span class="o">:</span> <span class="nx">bool</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">unleash</span><span class="o">-&gt;</span><span class="na">isEnabled</span><span class="p">(</span><span class="nv">$feature</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">context</span><span class="p">,</span> <span class="nv">$default</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setUser</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">)</span><span class="o">:</span> <span class="nx">bool</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">context</span><span class="o">-&gt;</span><span class="na">setCurrentUserId</span><span class="p">(</span><span class="nv">$id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h4 id="some-words-on-the-context" class="relative group">Some words on the Context <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#some-words-on-the-context" aria-label="Anchor">#</a></span></h4><p>The most interesting part of the Unleash Client is the Context. The Context holds the information about the user, as
Feature Flags usually close to the user and therefore in the front end. But from data perspective it can be more
interesting context to enable features on a subset of the entities. Use Cases for this are some kind of metrics, or the
replacement of a feature set with a new solutions in different service.</p>
<h4 id="using-the-feature-flags" class="relative group">Using the Feature Flags <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-the-feature-flags" aria-label="Anchor">#</a></span></h4><p>The Service can be injected into the Authentication Middleware to set the User, and then used in the Controller to check
if the Feature is enabled.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">NewController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">(</span><span class="nx">Request</span> <span class="nv">$request</span><span class="p">,</span> <span class="nx">FeatureFlagService</span> <span class="nv">$featureFlagService</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$featureFlagService</span><span class="o">-&gt;</span><span class="na">setUser</span><span class="p">(</span><span class="nv">$request</span><span class="o">-&gt;</span><span class="na">getUser</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$featureFlagService</span><span class="o">-&gt;</span><span class="na">isEnabled</span><span class="p">(</span><span class="s1">&#39;new-feature&#39;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">new</span> <span class="nx">JsonResponse</span><span class="p">(</span><span class="s1">&#39;Feature not enabled&#39;</span><span class="p">,</span> <span class="mi">404</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> 
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">newFeature</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h4 id="gitlab-ui-and-first-test--troubleshooting" class="relative group">Gitlab UI and First Test / Troubleshooting <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#gitlab-ui-and-first-test--troubleshooting" aria-label="Anchor">#</a></span></h4><p>This part is trivial, Gitlab offers a nice documentation of the GUI and it is mostly self-explanatory. <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>
The interface allows the developer to define a Feature Flag, toggle it usages, limit it to a certain user or a
predefined user group, and to see the usages of the Feature Flag in the code. No additional metrics are tracked.</p>
<p>With the first feature tested, it might work out of the box.
If it doesn&rsquo;t work, check if the Feature Flag is defined in the Gitlab UI and the spelling matches the one in the code.
To check if Gitlab is reachable and the credentials are working, the Unleash API can be called directly.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -L -X GET <span class="s1">&#39;https://git.example.com/api/v4/feature_flags/unleash/1/client/features&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-H <span class="s1">&#39;Accept: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-H <span class="s1">&#39;Authorization: H9sU9yVHVAiWFiLsH2Mo&#39;</span>
</span></span></code></pre></div><p>Or the still somewhat supported legacy API that does use a different Header</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -L -X GET <span class="s1">&#39;https://git.example.com/api/v4/feature_flags/unleash/1/client/features&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-H <span class="s1">&#39;Accept: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-H <span class="s1">&#39;UNLEASH-INSTANCEID: H9sU9yVHVAiWFiLsH2Mo&#39;</span>
</span></span></code></pre></div><h4 id="clean-up-your-test-flags" class="relative group">Clean up your Test Flags <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#clean-up-your-test-flags" aria-label="Anchor">#</a></span></h4><h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Feature Flags are a powerful tool to control the release of new features, and the experience to use such a tool with
such an easy set up makes it tempting to just experiment with it.</p>
<p>Happy Coding!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://martinfowler.com/articles/feature-toggles.html" target="_blank" rel="noreferrer">Types and usages of Feature Flags</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://jeromedane.medium.com/feature-flags-are-dangerous-88ef9d6c9f04" target="_blank" rel="noreferrer">Danger of Feature Flags</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://docs.getunleash.io/topics/feature-flags/feature-flag-best-practices" target="_blank" rel="noreferrer">Best Practices</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://github.com/Unleash/unleash-client-php" target="_blank" rel="noreferrer">Php Unleash Client</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://docs.getunleash.io/reference/sdks/php#gitlab-specifics" target="_blank" rel="noreferrer">Unleash Docs</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://docs.gitlab.com/ee/operations/feature_flags.html" target="_blank" rel="noreferrer">Gitlab Feature Flags Docs</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="devops" label="DevOps"/><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Symfony Messenger Component step by step</title><link href="https://philodev.one/posts/2024-01-symfony-queues/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="related" type="text/html" title="About Actions, Jobs, Repositories, Events"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><link href="https://philodev.one/posts/2024-01-using-php-attributes/?utm_source=atom_feed" rel="related" type="text/html" title="Dive into PHP Attributes"/><id>https://philodev.one/posts/2024-01-symfony-queues/</id><published>2024-02-01T10:20:44+02:00</published><updated>2024-02-01T10:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>How does the Symfony Messenger Component work; How can I hook into the process; and how can I use it for my own needs?</blockquote><div class="lead !mb-9 text-xl">
  How does the Symfony Messenger Component work; How can I hook into the process; and how can I use it for my own needs?
</div>

<h2 id="symfony-messages-and-symfony-events" class="relative group">Symfony Messages and Symfony Events <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#symfony-messages-and-symfony-events" aria-label="Anchor">#</a></span></h2><p>Coming from Laravel, and knowing how Laravel handles Events, I hat quite some bits to learn when I dived into the
Symfony world <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. The most obvious change is while Laravel has Events, Symfony has Messages and Events.</p>
<p>The Symfony Events are synchronous, and are used to communicate between different parts of the application <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.
This simple property makes it easy to decide if an event or a messages can solve your problem, events are the better
choice if you need the result of the event to be communicated back, or if you don&rsquo;t have the time/thread requirements to
implement a queue. This Post will not Cover Events, but Messages only.</p>
<h2 id="stepping-through-symfony-dispatcher-and-consumer" class="relative group">Stepping through Symfony Dispatcher and Consumer <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#stepping-through-symfony-dispatcher-and-consumer" aria-label="Anchor">#</a></span></h2><p>Frameworks can seem magical in the beginning, but the more a developer knows about their inner workings, the better it
can be used. If a developer is aware of the posible hooks and tricks very often very easy solutions for common problems
can be implemented.
To discover a framework, I go for a scribbled test and the debugger. In this case I wanted to know how the Symfony queue
is consumed, and so I dispatched a command using a dependency injected CommandBus and stepped into every function on my
way to my command handler.</p>
<p>






  
  
<figure><img src="/images/2024-02-messanges.png" alt="Corgi Stamps and Envelopes" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h3 id="dispatching-a-job-and-adding-stamps" class="relative group">Dispatching a job and adding Stamps <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#dispatching-a-job-and-adding-stamps" aria-label="Anchor">#</a></span></h3><p>The first step leads to the <code>Symfony\Component\Messenger\MessageBusInterface</code>, which leads to three possible Symfony
implementation, which might add context but all end up in the same <code>Symfony\Component\Messenger\MessageBus::dispatch()</code>
function. The dispatch method also allows to add Stamps, little pieces of meta information about the Message.
The dispatch function then creates a <code>Symfony\Component\Messenger\Envelope</code>, which is a wrapper for the Message and the
Stamps.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">✉️ I&rsquo;ll give you a moment to be amazed by the naming - because I find it so cute! If you want a piece of your code to
know some bits of information and act upon it, you put that info in an envelope, and than attach some stamps on it; the
framework will look at the stamps and know how to route it to the right piece of code 💌.</span>
</div>

<p>The Stamps are also a way to transport context over to the worker. One use case could be tracing an entity through your
application.</p>
<h3 id="middlewares" class="relative group">Middlewares <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#middlewares" aria-label="Anchor">#</a></span></h3><p>Still in the dispatch methods, the Envelope is passed to the MiddlewareStack. The MiddlewareStack is a collection of
Classes following the Pipeline Pattern. Pipeline Pattern is a way to execute a list of operations on a given input,
where the result of each of the operations is passed to the next operation. In this case the input is the Envelope, and
each Middleware adds or acts upon the mentioned Stamps; e.g. if the envelope needs to be sent (and where), if it failed,
or if it&rsquo;s received and needs to be handled.</p>
<p>The Middlewares are walked through in the same order both when the message is sent to a queue and when the message is
consumed from a queue. The order of the Middlewares is important, the default order of the implemented Symfony
Middlewares is:</p>
<ul>
<li><code>TraceableMiddleware</code>: which traces and tracks the execution of the middlewares</li>
<li><code>AddBusNameStampMiddleware</code>: which adds the name of the bus to the message</li>
<li><code>AddDispatchAfterCurrentBusMiddleware</code>: messages with a DispatchAfterCurrentBusStamp are handled once the current
dispatching is fully handled.</li>
<li><code>FailedMessageProcessingMiddleware</code>: If the Message doesn&rsquo;t have the <code>ReceivedStamp</code> but
a <code>SentToFailureTransportStamp</code>, it adds the <code>ReceivedStamp</code> to ensure the envelope is not sent to the failing
transport again.</li>
<li>Your own collection of Middlewares: Could add Logging Context, Metrics, Tracing Information&hellip;</li>
<li><code>SendMessageMiddleware</code>: if there is no <code>ReceivedStamp</code> and routing is configured for the transport, this sends messages
to that transport</li>
<li><code>HandleMessageMiddleware</code>: calls the message handler(s) for the given message.</li>
</ul>
<p>Simplified example of one of the Middlewares <code>SendMessageMiddleware</code> <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">SendMessageMiddleware</span> <span class="k">implements</span> <span class="nx">MiddlewareInterface</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">handle</span><span class="p">(</span><span class="nx">Envelope</span> <span class="nv">$envelope</span><span class="p">,</span> <span class="nx">StackInterface</span> <span class="nv">$stack</span><span class="p">)</span><span class="o">:</span> <span class="nx">Envelope</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$sender</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">//  check if the envelope is already received
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$envelope</span><span class="o">-&gt;</span><span class="na">all</span><span class="p">(</span><span class="nx">ReceivedStamp</span><span class="o">::</span><span class="na">class</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// it&#39;s a received message, do not send it back
</span></span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// send the message to all senders
</span></span></span><span class="line"><span class="cl">            <span class="k">foreach</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">sendersLocator</span><span class="o">-&gt;</span><span class="na">getSenders</span><span class="p">(</span><span class="nv">$envelope</span><span class="p">)</span> <span class="k">as</span> <span class="nv">$sender</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$envelope</span> <span class="o">=</span> <span class="nv">$sender</span><span class="o">-&gt;</span><span class="na">send</span><span class="p">(</span><span class="nv">$envelope</span><span class="o">-&gt;</span><span class="na">with</span><span class="p">(</span><span class="k">new</span> <span class="nx">SentStamp</span><span class="p">(</span><span class="nv">$sender</span><span class="o">::</span><span class="na">class</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// if there is no sender, call the next middleware
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">null</span> <span class="o">===</span> <span class="nv">$sender</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nv">$stack</span><span class="o">-&gt;</span><span class="na">next</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">handle</span><span class="p">(</span><span class="nv">$envelope</span><span class="p">,</span> <span class="nv">$stack</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// message should only be sent and not be handled by the next middleware
</span></span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$envelope</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>SideQuest-Question: How are the Middlewares set up and how are custom Middlewares added?
Symfony does a great job in dependency injection. In the <code>config/packages/messenger.yaml</code> is the
place to add additional Middlewares. To also understand how the Middlewares are configured, I dug a bit deeper in the
<code>Symfony/Component/DependencyInjection/Loader/Configurator/messenger.php</code> file. Here are the defaults set for all
mentioned Middlewares. Custom Middlewares are read from the config in the
<code>FrameworkBundle/DependencyInjection/Configuration.php::addMessengerSection()</code>. And looking at the code, that&rsquo;s a story
for another post.</p>
<h3 id="consuming-messages" class="relative group">Consuming Messages <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#consuming-messages" aria-label="Anchor">#</a></span></h3><p>Assuming the SendMessageMiddleware sent the message to a Transport of your choice, the message was in a queue which
picked it up is now calling a console command <code>messenger:consume</code> which is a
<code>Symfony\Component\Messenger\Command\ConsumeMessagesCommand</code>. This instantiates a Worker, which <code>Messenger/Worker</code> which
performs the actual consumption of an Envelope.</p>
<p>A simplified version of the Worker <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="nf">handleMessage</span><span class="p">(</span><span class="nx">Envelope</span> <span class="nv">$envelope</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$transportName</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// throughout the whole process, events are dispatched to allow to hook into the process
</span></span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">eventDispatcher</span><span class="o">?-&gt;</span><span class="na">dispatch</span><span class="p">(</span><span class="k">new</span> <span class="nx">WorkerMessageReceivedEvent</span><span class="p">(</span><span class="nv">$envelope</span><span class="p">,</span> <span class="nv">$transportName</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// the message is dispatched to the bus, which calls the middlewares
</span></span></span><span class="line"><span class="cl">        <span class="c1">// the ReceivedStamp is added
</span></span></span><span class="line"><span class="cl">        <span class="nv">$envelope</span> <span class="o">=</span> <span class="nv">$event</span><span class="o">-&gt;</span><span class="na">getEnvelope</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$envelope</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">bus</span><span class="o">-&gt;</span><span class="na">dispatch</span><span class="p">(</span><span class="nv">$envelope</span><span class="o">-&gt;</span><span class="na">with</span><span class="p">(</span><span class="k">new</span> <span class="nx">ReceivedStamp</span><span class="p">(</span><span class="nv">$transportName</span><span class="p">),</span> <span class="k">new</span> <span class="nx">ConsumedByWorkerStamp</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">ack</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>So here the Middlewares are called again, but this time the <code>HandleMessageMiddleware</code> is called, in which the Handler(s)
are determined and called. The HandlerLocator uses mostly a config to determine the Handler (but I guess an Attribute
would be possible too). Foreach Handler the <code>HandledStamp</code> is added to the Envelope, to ensure the message is not
handled multiple times.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Symfony Messenger is a great tool to decouple parts of your application. Looking under its hood, it is a well-designed
tool, it&rsquo;s awesomely named, and it&rsquo;s more versatile than I personally found the Laravel solution to the same
problem. The middlewares are easy and spot on in their utility. I am looking forward to using it in future blog posts.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.blog.philodev.one/posts/2022-12-queues/" target="_blank" rel="noreferrer">How Laravel Queues work</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://symfonycasts.com/screencast/messenger/messenger-event-dispatcher" target="_blank" rel="noreferrer">Symfony Events</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://github.com/symfony/messenger/blob/7.0/Middleware/SendMessageMiddleware.php" target="_blank" rel="noreferrer">Symfony Messenger SendMessageMiddleware</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://github.com/symfony/messenger/blob/7.0/Worker.php" target="_blank" rel="noreferrer">Symfony Messenger Worker</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="symfony" label="Symfony"/><category scheme="taxonomy:Tags" term="queue" label="Queue"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/><category scheme="taxonomy:Tags" term="development" label="Development"/></entry><entry><title type="html">Dive into PHP Attributes</title><link href="https://philodev.one/posts/2024-01-using-php-attributes/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2023-03-testing-open-api-specs/?utm_source=atom_feed" rel="related" type="text/html" title="Testing Open Api files"/><link href="https://philodev.one/posts/2023-01-laravel-custom-casts/?utm_source=atom_feed" rel="related" type="text/html" title="Laravel Custom Casts"/><link href="https://philodev.one/posts/2022-12-rules-with-validators/?utm_source=atom_feed" rel="related" type="text/html" title="Laravel Validations"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><link href="https://philodev.one/posts/2022-08-etchical-development/?utm_source=atom_feed" rel="related" type="text/html" title="Ethical Development"/><id>https://philodev.one/posts/2024-01-using-php-attributes/</id><published>2024-01-20T14:20:44+02:00</published><updated>2024-01-20T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>PHP attributes are a great addition to the language. But how are they used, can I use them, and what are Use Cases?</blockquote><div class="lead !mb-9 text-xl">
  PHP attributes are a great addition to the language. But how are they used, can I use them, and what are Use Cases?
</div>

<h2 id="what-attributes-can-do" class="relative group">What Attributes can do <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#what-attributes-can-do" aria-label="Anchor">#</a></span></h2><p>Attributes are one of the greatly expected features of PHP 8.0. They are a way to add metadata to classes, methods, or
properties/ constants. The feature itself is no new idea PHP came up, but many other languages already utilize
Attributes or Annotations (as many languages call them) - and therfore we can learn from Frameworks like Spring to learn
how to use Attributes <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Attributes are awesome! But as you will se in the implementation examples, they are a bit of magic. I personally
consider them less &ldquo;magic&rdquo; than Laravel&rsquo;s partially visible Providers, or Symfonie&rsquo;s yaml config files.</span>
</div>

<h3 id="implementation-example-of-attributes-as-listener-config" class="relative group">Implementation Example of Attributes as Listener Config <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#implementation-example-of-attributes-as-listener-config" aria-label="Anchor">#</a></span></h3><p>Depending on the Framework there are implementations for Listener Wiring, Symfony already switched the <code>.yaml</code> config
for Attributes. The following example is a simplified version of this Idea.</p>
<p>Dev-User Perspective first, what should be achieved? Possible Solutions to add the attribute to the class and
implementing a <code>function on(EventInterface $event): void</code> method. In that case the Attribute should target the class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="c1">#[ListensTo(UserCreated::class)]
</span></span></span><span class="line"><span class="cl"><span class="nx">readonly</span> <span class="k">class</span> <span class="nc">UserListener</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">on</span><span class="p">(</span><span class="nx">EventInterface</span> <span class="nv">$event</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>But we can also target the method, which would be a bit more verbose, but impractical if there are multiple events that
require actions by multiple methods.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">readonly</span> <span class="k">class</span> <span class="nc">UserListener</span> <span class="k">implements</span> <span class="nx">EventListenerInterface</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">#[ListensTo(UserCreated::class)]
</span></span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">onUserCreated</span><span class="p">(</span><span class="nx">UserCreated</span> <span class="nv">$event</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The Attribute itself is implemented as class. Here the implementation for the Listener on the class. As it should be
possible to register more than one event on the listener, the Attribute is marked as <code>IS_REPEATABLE</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="c1">#[Attribute(Attribute::TARGET_CLASS| Attribute::IS_REPEATABLE)] readonly class ListensTo
</span></span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">public</span> <span class="nx">string</span> <span class="nv">$event</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>A list of possible targets are listed in the Attribute class <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>:</p>
<ul>
<li><code>TARGET_CLASS = 1</code> Marks that attribute declaration is allowed only in classes</li>
<li><code>TARGET_FUNCTION = 2</code> Marks that attribute declaration is allowed only in functions</li>
<li><code>TARGET_METHOD = 4</code> Marks that attribute declaration is allowed only in class methods</li>
<li><code>TARGET_PROPERTY = 8</code> Marks that attribute declaration is allowed only in class properties</li>
<li><code>TARGET_CLASS_CONSTANT = 16</code> Marks that attribute declaration is allowed only in class constants</li>
<li><code>TARGET_PARAMETER = 32</code> Marks that attribute declaration is allowed only in function or method parameters</li>
<li><code>TARGET_ALL = 63</code> Marks that attribute declaration is allowed anywhere</li>
<li><code>IS_REPEATABLE = 64</code> Notes that an attribute declaration in the same place is allowed multiple times</li>
</ul>
<p>To read out the attributes, the Reflection API is used. In this case a Method is called during the container build.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">(</span><span class="nx">EventListenerInterface</span> <span class="nv">$listener</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$reflection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ReflectionClass</span><span class="p">(</span><span class="nv">$listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">foreach</span> <span class="p">(</span><span class="nv">$reflection</span><span class="o">-&gt;</span><span class="na">getAttributes</span><span class="p">(</span><span class="nx">ListensTo</span><span class="o">::</span><span class="na">class</span><span class="p">)</span> <span class="k">as</span> <span class="nv">$attribute</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="sd">/** @var ListensTo $listensTo */</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$listensTo</span> <span class="o">=</span> <span class="nv">$attribute</span><span class="o">-&gt;</span><span class="na">newInstance</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">listeners</span><span class="p">[</span><span class="nv">$listensTo</span><span class="o">-&gt;</span><span class="na">event</span><span class="p">][]</span> <span class="o">=</span> <span class="nv">$listener</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This was the point where I was amazed how easy this was! Of cause using the Reflection API always feels like performing
black magic, but in this example I find it way more readable than some configs.</p>
<h3 id="replacing-configs-with-attributes" class="relative group">Replacing configs with Attributes <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#replacing-configs-with-attributes" aria-label="Anchor">#</a></span></h3><ul>
<li>Symfony requires configs for Dependency Injection, which could be replaced by a Spring inspired [#Autowired]
Attribute.</li>
<li>The mentioned Listener Wiring could be replaced by a [#ListensTo] Attribute.</li>
<li>The [#Route] Attribute could replace the <code>routes.yaml</code> config file (or the <code>routes/api.php</code> in Laravel). There are
already some implementations for this <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</li>
<li>The [#Handels] Attribute could map Commands to CommandHandlers</li>
</ul>
<h3 id="validation" class="relative group">Validation <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#validation" aria-label="Anchor">#</a></span></h3><p>Validation using Attributes comes in so easy, readable, and minimalistic.
Imagine a Request could look like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserCreateRequest</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">#[Required()]
</span></span></span><span class="line"><span class="cl">  <span class="k">public</span> <span class="nx">readonly</span> <span class="nx">string</span> <span class="nv">$name</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">#[Min(1)]
</span></span></span><span class="line"><span class="cl">  <span class="c1">#[Max(10)]
</span></span></span><span class="line"><span class="cl">  <span class="k">public</span> <span class="nx">readonly</span> <span class="nx">string</span> <span class="nv">$numberBetweenOneAndTen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">#[Pattern(&#34;^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$&#34;)]
</span></span></span><span class="line"><span class="cl">  <span class="k">public</span> <span class="nx">readonly</span> <span class="o">?</span><span class="nx">string</span> <span class="nv">$ipAddress</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="other-use-cases" class="relative group">Other use cases <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#other-use-cases" aria-label="Anchor">#</a></span></h3><ul>
<li>[#Example] Attribute to give an example, but maybe also to generate mini fixture</li>
<li>[#Dataset] Provide a dataset for a test</li>
<li>[#SupressWarnings] could replace the <code>phpstan-ignore</code> comments</li>
</ul>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Attributes are a great addition to PHP. I am looking forward to see how they will be used in the future, and hope they
will replace some configs, classes, and make code more readable.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.javatpoint.com/spring-boot-annotations" target="_blank" rel="noreferrer">Spring Framework - Annotations</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://php.watch/articles/php-attributes" target="_blank" rel="noreferrer">Very good Article about Attributes</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://stitcher.io/blog/route-attributes" target="_blank" rel="noreferrer">Route Attributes for Laravel</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="php" label="PHP"/></entry><entry><title type="html">Using data for Sprint Planning</title><link href="https://philodev.one/posts/2023-11-using-data-to-ignite-action/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2023-04-communicating-between-teams/?utm_source=atom_feed" rel="related" type="text/html" title="Communication between different teams working on the same codebase"/><link href="https://philodev.one/posts/2022-09-sprint-retro/?utm_source=atom_feed" rel="related" type="text/html" title="Improving Retros from a Devs Perspective"/><id>https://philodev.one/posts/2023-11-using-data-to-ignite-action/</id><published>2023-11-21T14:20:44+02:00</published><updated>2023-11-21T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>It is better to be vaguely right than exactly wrong. - Carveth Read. While the trend goes in a direction to put a metric on everything to drive decisions, most teams I have worked with are still in the beginning of this journey. Here is a collection on Information on what, how, and why to collect Data for project planning</blockquote><p><div class="lead !mb-9 text-xl">
  &ldquo;It is better to be vaguely right than exactly wrong.&rdquo; - Carveth Read. While the trend goes
in a direction to put a metric on everything to drive decisions, most teams I have worked with are still in the
beginning of this journey.
</div>

<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<h2 id="using-data-to-ignite-action" class="relative group">Using Data to Ignite Action <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-data-to-ignite-action" aria-label="Anchor">#</a></span></h2><p>In one of my favorite talks from DevOpsDays <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> Julie Starling is talking here about using data to drive
conversations.</p>
<p>On of the key takeaways for my was the Idea of Probabilistic Forecasts. This means using past data to make a prediction
about the future with the awareness that the prediction is not 100% accurate, focusing on a probability in a range.
For example &ldquo;There is a 80% chance of delivering 10 or more Story Points this Sprint&rdquo; (How much will we do?);
or &ldquo;There is a 90% chance of finishing 10 Story Points in the next 14 Days or less&rdquo; (When will we get it?).</p>
<h3 id="monte-carlo-method" class="relative group">Monte Carlo Method <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#monte-carlo-method" aria-label="Anchor">#</a></span></h3><p>Monte Carlo Method: Builds a model of possible results by using the Law of greater
Numbers; OR Simulations to calculate the probability of a range of outcomes, which somewhat if we run a
Simulation based on our last 10 Sprints, x% of the time we would have delivered a minimum of y Story Points in time.
The accuracy of the prediction increases with the increased number of inputs - although in a development environment
with experiments, changes in tech stacks, or changes in team composition, less inputs might be sometimes more accurate.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Monte Carlo might not include correct risk dependencies. If one ticket fails, dependent might or might not fail too.</span>
</div>

<h3 id="using-data-to-drive-conversations" class="relative group">Using Data to Drive Conversations <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-data-to-drive-conversations" aria-label="Anchor">#</a></span></h3><p>Julie uses Monte Carlo Simulations multiple times throughout the Sprint, to get a better and better prediction - and to
react at the earliest possible time. The moment the probability of delivering the minimum Story Points in time drops, or
the expected date to finish all work items is after the deadline, there is a need for a conversation.
This Conversation might include a change of expectations or a change of scope.</p>
<h2 id="the-flaw-of-averages-by-sam-l-savage" class="relative group">The Flaw of Averages (by Sam L. Savage) <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-flaw-of-averages-by-sam-l-savage" aria-label="Anchor">#</a></span></h2><p>This book is a great starting point to understand why Averages are not the best metric to plan actions.  <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>Plans based on average assumptions are wrong on average. Every developer knows the struggle to explain to PO that 10
Tickets with all the same estimation of one week will only be on average be delivered in a week, and therefor
behind schedule half of the time.</p>
<h3 id="the-weak-and-strong-form-of-the-flaw-of-averages" class="relative group">The weak and strong form of the Flaw of Averages <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-weak-and-strong-form-of-the-flaw-of-averages" aria-label="Anchor">#</a></span></h3><p>The weak form of the Flaw of Averages states is forecasting a result based on a single number instead of the
distribution
of outcomes. One kinda german example for this would looking at the average win of a lottery without considering the
average cost or the probability distribution.</p>
<p>The baseline to avoid this is &ldquo;View uncertainty as a shape, not a number.&rdquo; (Normal distribution, even distribution, &hellip;)</p>
<p>The strong form of the Flaw of Averages states that the average inputs do not equal the average outputs. The output of
the average team is not equal to average output of all teams.</p>
<h3 id="the-seven-deadly-sins-of-averages" class="relative group">The seven deadly sins of Averages <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-seven-deadly-sins-of-averages" aria-label="Anchor">#</a></span></h3><ul>
<li>The average often does not exists (like the 1.5 child people have)</li>
<li>The average task length is not the average project length</li>
<li>Diversification works for projects management: If you add more independent tasks, the form of the distribution
histogram will approach a bell curve.</li>
<li>Be clear if your risk depends on restriction (how many people can work on a task) or on opportunity (how much will
performance increase from refactor).</li>
<li>Optionality - can you remove costs in case of losses?</li>
<li>Cost of average demand is not the average cost.</li>
<li>Things may happen by chance =&gt; we are just doing hypothesis testing.</li>
</ul>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Flaws of Extremes</strong>: Budgeting for risks becomes exponentially expensive.</span>
</div>

<h2 id="current-state-of-error" class="relative group">Current State of Error <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#current-state-of-error" aria-label="Anchor">#</a></span></h2><p>After this theory, I am still in the process of implementing this in my team. Moving away from the simple
calculation of Averages to complex modelling while spending enough time in this to make it a valid experiment, and not
falling for sunk cost fallacy or spending more time on it than the team would benefit from it.</p>
<p>I wish I could write more about how this changed my team, or how we implemented it; but this is my current state of
error.</p>
<p>Keep Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.gutenberg.org/files/18440/18440-h/18440-h.html" target="_blank" rel="noreferrer">Logic - DEDUCTIVE AND INDUCTIVE</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://www.youtube.com/watch?v=91l3rtL81xs" target="_blank" rel="noreferrer">DevOpsDays Amsterdam 2023</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://www.flawofaverages.com/foa-overview" target="_blank" rel="noreferrer">Flaw Of Averages</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="agile" label="Agile"/><category scheme="taxonomy:Tags" term="devops" label="Devops"/></entry><entry><title type="html">Communication between different teams working on the same codebase</title><link href="https://philodev.one/posts/2023-04-communicating-between-teams/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2023-03-testing-open-api-specs/?utm_source=atom_feed" rel="related" type="text/html" title="Testing Open Api files"/><link href="https://philodev.one/posts/2022-09-sprint-retro/?utm_source=atom_feed" rel="related" type="text/html" title="Improving Retros from a Devs Perspective"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><id>https://philodev.one/posts/2023-04-communicating-between-teams/</id><published>2023-04-16T14:20:44+02:00</published><updated>2023-04-16T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Effective communication is essential in software development. As per Conway&rsquo;s Law, the structure and architecture of a software system are influenced by the communication patterns and structures within the organization.</blockquote><div class="lead !mb-9 text-xl">
  Effective communication is essential in software development. As per Conway&rsquo;s Law, the structure and architecture of a
software system are influenced by the communication patterns and structures within the organization.
</div>

<h2 id="conways-law" class="relative group">Conways Law <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conways-law" aria-label="Anchor">#</a></span></h2><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Conways Law</strong>:
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the
organization&rsquo;s communication structure. [^conwaysLaw]</span>
</div>

<p>Conway&rsquo;s Law means that the communication structures and patterns within the team will impact the design and
architecture of the software system a set of Developer Teams is developing.
If the team is structured in a way that promotes collaboration and communication between different members and
departments, the resulting software system will likely be well-structured and modular, with clear interfaces between
different components.
On the other hand, if the team is siloed and communication is poor, the software system may end up being poorly
organized and difficult to maintain.
Silos can occur when teams are organized around a specific product and do not have the chance to collaborate with other
teams or consider reuse of existing work.</p>
<h2 id="ways-to-improve-communication" class="relative group">Ways to improve communication <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#ways-to-improve-communication" aria-label="Anchor">#</a></span></h2><p>There are many ways to improve the communication between teams, some will be outlined here.</p>
<p>






  
  
<figure><img src="/images/2023-04-talk.png" alt="Talk to the Corgi Butt" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h3 id="architecture-decision-records" class="relative group">Architecture Decision Records <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#architecture-decision-records" aria-label="Anchor">#</a></span></h3><p>Tests, comments, and human-readable code are in my experience the most read and used documentation.
But still, there are situations in which the way the code is written only makes sense in the context in which the
decision was made.
Often enough, that bad looking class has a reason to exists in that way - and even if the explanation is &ldquo;because of
historic reasons&rdquo;, it something in a lot of codebases has to be communicated verbally.
Especially in cases, where multiple teams work on the same code base this can be a problem - that is why Architecture
Decisn Records (ADR) can fill that communication gap.</p>
<p><strong>Hype or Established?</strong> The concept of ADRs was coined in 2011 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, was added in the thoughtworks tech
radar in 2016 <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, and is now in usage in multiple tech companies (often if the teams are very independent).
The tools on the other hand are often open source, sometimes still working, and rarely maintained well <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.
My personal two cents are: Architecture Decision Records are established, but the tools are often more hyped that
practical.</p>
<p><strong>Update 06.10.2024</strong>
<strong>Which decision should be recorded?</strong> ADRs are used to document decisions that are important to the team in long-term.
Decisions that are easy to change, or which are not backed by the team don&rsquo;t need to be recorded. Recorded decisions
should have a reason to be recorded <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>:</p>
<ul>
<li>Decisions that impact the way developers work, e.g. the decision to use a specific framework or library, or to
implement a specific pattern.</li>
<li>Decisions that are hard to change.</li>
<li>Decisions that are often revisited to record the reasons for the decisions, trials, failures, and more context.</li>
<li>Decisions that are often asked by new team members, or that are hard to understand without context.</li>
</ul>
<p>Example of an ADR:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gh"># Use Markdown for Architecture Decision Records
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Context and Problem Statement
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">We want to record architectural decisions made in this project. The following requirements apply:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> The format should be human readable and easy to write.
</span></span><span class="line"><span class="cl"><span class="k">-</span> The files should be inside the code base, such that a new decision can be made using a pull request.
</span></span><span class="line"><span class="cl"><span class="k">-</span> The format should enable references to older decisions or files in the code base.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Some established solutions:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">*</span> [<span class="nt">MADR</span>](<span class="na">https://adr.github.io/madr/</span>) - Some simple Markdown solution
</span></span><span class="line"><span class="cl"><span class="k">*</span> Michael Nygard&#39;s template [^techRadar] – Markdown with Status and Consequences
</span></span><span class="line"><span class="cl"><span class="k">*</span> The Y-Statements - &#34;we decided for XXX and against ZZZ to achieve A and B, accepting that C&#34;.
</span></span><span class="line"><span class="cl"><span class="k">*</span> Formless – No conventions for file format and structure
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Decision Outcome
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The benefits of Michael Nygard&#39;s template are the Consequences, so a section to update information on the decision, e.g.
</span></span><span class="line"><span class="cl">by now a new feature has replaced this decision, but this one customer still needs it, so it is marked deprecated.
</span></span><span class="line"><span class="cl">This contradicts the idea that these files a immutable, but here I am still coding PHP so what do I know.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Status
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">I wrote a blog post, will have hold a presentation in my current company, and see what happens.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Consequences
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">//
</span></span></code></pre></div><h3 id="kpis-as-a-common-goal" class="relative group">KPIs as a common goal <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#kpis-as-a-common-goal" aria-label="Anchor">#</a></span></h3><p>To fight Silos, one option is to give teams common, meaningful KPIs and missions that contribute towards larger
goals, encouraging collaboration and avoiding the siloing of teams.
Communication is also key to breaking down silos, and teams should seek opportunities to work together and learn from
each other&rsquo;s areas of expertise <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>.</p>
<h3 id="team-structure" class="relative group">Team Structure <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#team-structure" aria-label="Anchor">#</a></span></h3><p>Silos can develop in software development when teams or departments become isolated and focused only on their own goals
and objectives, without considering how their work impacts the rest of the organization.
This can lead to a lack of collaboration, poor communication, and a fragmented approach to software development.</p>
<ul>
<li>Shared accountability: Cross-functional teams are accountable for the success of the project as a whole, not just
their individual tasks.</li>
<li>Improved communication: Cross-functional teams encourage open communication between team members from different
disciplines, which can help to break down silos by promoting a culture of knowledge sharing and collaboration.</li>
<li>Shared knowledge: Cross-functional teams bring together different areas of expertise, which can help to reduce silos
by sharing knowledge and skills across the team.</li>
<li>Faster decision-making: Cross-functional teams can make faster decisions as there is no need to wait for approval from
different departments.</li>
</ul>
<p>Also switching around the teams can improve communication and collaboration, as well as knowledge sharing.</p>
<h3 id="common-meetings" class="relative group">Common Meetings <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#common-meetings" aria-label="Anchor">#</a></span></h3><p>A possible Agenda may vary from meeting to meeting, but the goal is to have a common meeting where all teams can
participate and exchange knowledge.</p>
<ul>
<li><strong>Latest Features</strong>: A meeting in which each team presents the latest features they have implemented, including the
added dependencies or patterns.</li>
<li><strong>Latest Wins</strong>: Talking about patterns which have proven useful, Code styles that made things easier to read, or
anything else that has been a win for the team and can be a win for others.</li>
<li><strong>Latest Fails</strong>: Having a shared Post Mortem of a failed feature or a failed deployment can help to avoid the same
mistakes in the future.</li>
<li><strong>New Ideas</strong>: A meeting in which a new Idea is pitched to be discussed and feedback is given.</li>
<li><strong>Social</strong>: The goal of such a meeting may be nothing more than social interaction, just having a pub quiz as only
agenda point can
be relaxing from time to time.</li>
</ul>
<h3 id="culture" class="relative group">Culture <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#culture" aria-label="Anchor">#</a></span></h3><p>All the comminucation tools and structures only can work if the culture of the company is pushing towards sharing
knowledge.</p>
<ul>
<li><strong>Redirect to Documentations or ADRs</strong>: When others asks, redirect to the documentation next to an explanation.</li>
<li><strong>Make Decision Recording a habit</strong>: Write down Meeting outcomes in chats, ADRs, or other shared notes.</li>
<li><strong>Hold up Review standards for Documentation and ADRs</strong>: Documentation and ADRs should be reviewed with the same
caution as code. The motivation for that should also focus on sharing knowledge.</li>
</ul>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>There are ways to improve Team communication, and the way the communication is organized, how hygienic and structured it
is, can have a huge impact on the software system that is being developed. I would not dare to enforce long, daily or
weekly meetings on developers who prefer sitting in their cellar and coding, because communication does not need to be a
meeting, nor a formal setup with 50 people.</p>
<p>Happy communicating!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions" target="_blank" rel="noreferrer">Michael Nygard: Architecture Decision Records</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://www.thoughtworks.com/en-us/radar/techniques/lightweight-architecture-decision-records" target="_blank" rel="noreferrer">Thoughtworks Tech Radar</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://adr.github.io/" target="_blank" rel="noreferrer">ADR Tools</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://www.oreilly.com/library/view/communication-patterns/9781098140533/" target="_blank" rel="noreferrer">Communication Patterns by Jacqui Read</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://www.infoq.com/podcasts/balancing-synchronous-asynchronous-work/" target="_blank" rel="noreferrer">Becoming a Great Engineering Manager and Balancing Synchronous and Asynchronous Work - InfoQ Podcast</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="agile" label="Agile"/><category scheme="taxonomy:Tags" term="devops" label="DevOps"/></entry><entry><title type="html">Testing Open Api files</title><link href="https://philodev.one/posts/2023-03-testing-open-api-specs/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><link href="https://philodev.one/posts/2023-01-laravel-custom-casts/?utm_source=atom_feed" rel="related" type="text/html" title="Laravel Custom Casts"/><link href="https://philodev.one/posts/2022-12-rules-with-validators/?utm_source=atom_feed" rel="related" type="text/html" title="Laravel Validations"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><link href="https://philodev.one/posts/2022-08-etchical-development/?utm_source=atom_feed" rel="related" type="text/html" title="Ethical Development"/><id>https://philodev.one/posts/2023-03-testing-open-api-specs/</id><published>2023-03-28T14:20:44+02:00</published><updated>2023-03-28T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Using Tests to verify the type and nullable correctness of an Open Api file is one way to ensure a usable documentation (if the file cannot be generated). This blog post is the result of a use case on testing requests and responses to Open Api conformity.</blockquote><div class="lead !mb-9 text-xl">
  Using Tests to verify the type and nullable correctness of an Open Api file is one way to ensure a usable
documentation (if the file cannot be generated). This blog post is the result of a use case on testing requests and
responses to Open Api conformity.
</div>

<h2 id="use-case" class="relative group">Use Case <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#use-case" aria-label="Anchor">#</a></span></h2><p>PHP Apis are famous for their inconsistent typing and the lack of respect of nullable values. This is a problem, because
other languages do (thankfully) not cast any value to any other value without complaining neither on compile time nor on
run time.
PHP Developer have nether the less started to use Open Api files to document their Apis - and often enough included
their typing inconsistency in their Open Api file.
While some are in the great position to generate the Open Api file, others might require a handwritten and maintained
Open Api file (or a combination of both).</p>
<p>The Base Assumption therefore is: Developers have to maintain the Open Api File by hand - or as user story: As a
Developer, I want a Test to fail if the Open Api file is conflicting with the actual Api.</p>
<p>






  
  
<figure><img src="/images/2023-03-tests.png" alt="Casting Corgi" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="mise-en-place-reading-and-validating-the-open-api-file" class="relative group">Mise en place: Reading and validating the Open Api File <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#mise-en-place-reading-and-validating-the-open-api-file" aria-label="Anchor">#</a></span></h2><p>Fortunately, there is at least one great library that can read an Open Api file and hold it as an object, as well as
writing it to a file <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>The Library does a great job at making the Open Api file accessible in PHP. In case a third party is consuming the Open
Api File (like readme.io), this also enables you to write a Command that will generate a fresh open Api File with
resolved cross file references (in case you want to generate parts of your Open Api file ;) ).</p>
<p>One other library that I will use in this post is using the above to validate Requests and Responses against the Open
File. <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<h2 id="request-validation" class="relative group">Request Validation <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#request-validation" aria-label="Anchor">#</a></span></h2><p>Easy steps first: The Request usually does not cause any problems on PHP Apis. Any value that comes it, and should be a
boolean but is a string, a number, or anything else will be easily converted to a boolean. Although some Api consumers
might not share PHPs view of an empty string as falsy value.</p>
<h3 id="using-defined-data-providers--test-sets" class="relative group">Using defined data providers / test sets <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-defined-data-providers--test-sets" aria-label="Anchor">#</a></span></h3><p>If there are already defined test sets to be used in the API, and those are used by the developer for new features (
maybe even enhanced regularly), it is easy to use those test sets to validate the Open Api file.</p>
<p>So a simple tests would just use the same data set used for testing the Api (or Api validation) and validate the test
request data against the Open Api definition <sup id="fnref1:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. Any changes made to the test files (e.g. for a
new feature) or an updated Test file will automatically be validated against the Open Api file.</p>
<p>PRO</p>
<ul>
<li>Easy to implement</li>
<li>Easy to maintain / debug</li>
<li>Deterministic</li>
</ul>
<p>CON</p>
<ul>
<li>The tests are only as good as the test data set</li>
</ul>
<h3 id="contract-testing-using-open-api-as-contract" class="relative group">Contract Testing using Open Api as Contract <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#contract-testing-using-open-api-as-contract" aria-label="Anchor">#</a></span></h3><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Contract Testing</strong>:
Contract testing is a methodology for ensuring that two separate systems (such as two microservices) are compatible and
can communicate with one other. It captures the interactions that are exchanged between each service, storing them in a
contract, which then can be used to verify that both parties adhere to it. [^contractTesting]</span>
</div>

<p>So, the idea is to assume the Open Api is the Contract between the Api and the Api Consumer.
The Consumer should be able to send any kind of request that conforms the Open Api, and the Api should be able to
respond.</p>
<p>Using e.g. the Laravel Generator, writing a Request Generator is not hard.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param  \cebe\openapi\spec\Schema|\cebe\openapi\spec\Operation  $schema
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param $pointer
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">mockData</span><span class="p">(</span><span class="nx">Schema</span> <span class="nv">$schema</span><span class="p">,</span> <span class="nv">$pointer</span> <span class="o">=</span> <span class="s1">&#39;root&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">oneOf</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">anyOf</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$options</span> <span class="o">=</span> <span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">oneOf</span> <span class="o">??</span> <span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">anyOf</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$randomIndex</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">faker</span><span class="o">-&gt;</span><span class="na">numberBetween</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">count</span><span class="p">(</span><span class="nv">$options</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mockData</span><span class="p">(</span><span class="nv">$options</span><span class="p">[</span><span class="nv">$randomIndex</span><span class="p">],</span> <span class="nv">$pointer</span> <span class="o">.</span> <span class="s1">&#39;-&gt;&#39;</span> <span class="o">.</span> <span class="nv">$randomIndex</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">allOf</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mockAllOf</span><span class="p">(</span><span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">allOf</span><span class="p">,</span> <span class="nv">$pointer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">match</span> <span class="p">(</span><span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Type</span><span class="o">::</span><span class="na">INTEGER</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">faker</span><span class="o">-&gt;</span><span class="na">numberBetween</span><span class="p">(</span><span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">minimum</span><span class="p">,</span> <span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">maximum</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Type</span><span class="o">::</span><span class="na">NUMBER</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">faker</span><span class="o">-&gt;</span><span class="na">randomFloat</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">minimum</span><span class="p">,</span> <span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">maximum</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Type</span><span class="o">::</span><span class="na">BOOLEAN</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">faker</span><span class="o">-&gt;</span><span class="na">boolean</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Type</span><span class="o">::</span><span class="na">STRING</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mockString</span><span class="p">(</span><span class="nv">$schema</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Type</span><span class="o">::</span><span class="na">ARRAY</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mockArray</span><span class="p">(</span><span class="nv">$schema</span><span class="p">,</span> <span class="nv">$pointer</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Type</span><span class="o">::</span><span class="na">OBJECT</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mockObject</span><span class="p">(</span><span class="nv">$schema</span><span class="p">,</span> <span class="nv">$pointer</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="k">default</span> <span class="o">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">\Exception</span><span class="p">(</span><span class="s1">&#39;Unsupported datatype &#39;</span> <span class="o">.</span> <span class="nv">$schema</span><span class="o">-&gt;</span><span class="na">type</span> <span class="o">.</span> <span class="s1">&#39; at &#39;</span> <span class="o">.</span> <span class="nv">$pointer</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>I am looking forward to publish the code as soon as I can. For now, this is all I dare to show, at least the
learning of handing down the pointer to give accurate error messages in case of failure is some value. The Types and
Schema are used using the Open Api Library <sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, while the Faker is the Laravel Generator <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<p>PRO</p>
<ul>
<li>Might test the Api through every option eventually</li>
<li>Can point out bugs in the code beyond the Open Api file verification</li>
</ul>
<p>CON</p>
<ul>
<li>Non-deterministic =&gt; Make sure the failing messages contain the exact request that failed!</li>
<li>Not straight forward to implement</li>
<li>Might need constant attention as it might return errors weeks after a bug was introduced</li>
<li>Has limits</li>
</ul>
<p>The Limits: E.g Laravel Validation goes far beyond the Open Api file. Validations like &ldquo;exits in database&rdquo; are near to
impossible to implement in the Open Api file; validations like &ldquo;required if another field is set&rdquo; are possible, but
working with the OneOf, AnyOf, AllOf causes more trouble down the road.</p>
<h2 id="response-validation" class="relative group">Response Validation <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#response-validation" aria-label="Anchor">#</a></span></h2><p>The Response Validation is more delicate, as this causes more problems for the Api Consumer - while Laravel Resources
are especially frustrating to keep correctly typed; even other Frameworks have similar problems.</p>
<p>The same as for the Request Validation, the same applies for the Response Validation. This can either be the DataSets to
test the Resources (if such datasets exist) or the Test Sets to test the Api can run on the response of a Controller.
Of cause, using random generated input data, and then checking the resulting response would be the most complete way to
test.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">testOpenApiGetUserResponse</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$user</span> <span class="o">=</span> <span class="nx">User</span><span class="o">::</span><span class="na">factory</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">create</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$response</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="nx">route</span><span class="p">(</span><span class="s1">&#39;user.index&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$response</span><span class="o">-&gt;</span><span class="na">assertSuccessful</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertValidAgainstOpenApi</span><span class="p">(</span><span class="nv">$response</span><span class="p">,</span> <span class="s1">&#39;/users&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Assert that a Response is fits to a path in the specified Open Api File
</span></span></span><span class="line"><span class="cl"><span class="sd">     *
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Debugging Hint fot the OneOfMany switch:
</span></span></span><span class="line"><span class="cl"><span class="sd">     * The Exception with more information why a sub schema failed is thrown in
</span></span></span><span class="line"><span class="cl"><span class="sd">     * vendor/league/openapi-psr7-validator/src/Schema/SchemaValidator.php
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="k">function</span> <span class="nf">assertValidAgainstOpenApi</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="nx">\Illuminate\Testing\TestResponse</span> <span class="nv">$response</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">string</span> <span class="nv">$path</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">string</span> <span class="nv">$method</span> <span class="o">=</span> <span class="s1">&#39;get&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$result</span> <span class="o">=</span> <span class="nx">ValidatorBuilder</span><span class="o">::</span><span class="na">fromYaml</span><span class="p">(</span><span class="nx">config</span><span class="p">(</span><span class="s1">&#39;openapi.path&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">getValidator</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">validate</span><span class="p">(</span><span class="nv">$response</span><span class="o">-&gt;</span><span class="na">baseResponse</span><span class="p">,</span> <span class="nv">$path</span><span class="p">,</span> <span class="nv">$method</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertTrue</span><span class="p">(</span><span class="nv">$result</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Don&rsquo;t be the PHP Developer that Api consumers hate because their Open Api file feels like an inspiration for the typing
in the Api Parameters and Responses. If you can not generate a correct Open Api file, write a test that will remind you
to maintain it.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://github.com/cebe/php-openapi" target="_blank" rel="noreferrer">Read and write OpenAPI 3.0.x YAML and JSON files and make the content accessible in PHP objects</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://github.com/osteel/openapi-httpfoundation-testing" target="_blank" rel="noreferrer">OpenAPI PSR-7 Validator</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://github.com/FakerPHP/Faker" target="_blank" rel="noreferrer">Faker that Laravel uses as well</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="testing" label="Testing"/><category scheme="taxonomy:Tags" term="devops" label="DevOps"/></entry><entry><title type="html">Laravel Custom Casts</title><link href="https://philodev.one/posts/2023-01-laravel-custom-casts/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-12-rules-with-validators/?utm_source=atom_feed" rel="related" type="text/html" title="Laravel Validations"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="related" type="text/html" title="About Actions, Jobs, Repositories, Events"/><link href="https://philodev.one/posts/2022-06-customer-search/?utm_source=atom_feed" rel="related" type="text/html" title="Technical Job Interview questions 2022"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><id>https://philodev.one/posts/2023-01-laravel-custom-casts/</id><published>2023-01-28T14:20:44+02:00</published><updated>2023-01-28T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Casts are already a great feature of Laravel. They allow you to easily convert a value from the database to the scalar value actually needed. But in case of Arrays, especially in a Domain Driven Design context, the default Laravel Casts are reaching their limits. In this post, I want to celebrate the power of Laravel Custom Casts and how an implementation could look like.</blockquote><div class="lead !mb-9 text-xl">
  Casts are already a great feature of Laravel. They allow you to easily convert a value from the database to the scalar
value actually needed. But in case of Arrays, especially in a Domain Driven Design context, the default Laravel Casts
are reaching their limits. In this post, I want to celebrate the power of Laravel Custom Casts and how an implementation
could look like.
</div>

<h2 id="json-in-relational-databases" class="relative group">Json in relational Databases <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#json-in-relational-databases" aria-label="Anchor">#</a></span></h2><p>There are different types of databases - most common in the Laravel ecosystem are relational databases.
And they fulfill their purpose great - they hold structured, typed data; display relations between data; and are
known by most developers, which means people know how to use them and how to optimise them.
Still, sometimes the flexibility of Json objects is needed in a relational database - and although people love arguing
about when to use a document database instead, there are reasons not to: Maybe the flexibility, a situation in which
the developer is still drafting, or storing temporary data that is not meant to be analysed or queried <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<h2 id="laravel-casting" class="relative group">Laravel Casting <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#laravel-casting" aria-label="Anchor">#</a></span></h2><p>But if the decision was made and there is a json column in the database, how can it be used in the code?
My personal favorite is to use a custom cast, so lets hop into this little deep dive on casts.</p>
<p>The Laravel documentation offers the Array cast as best practice for json columns, which would look like
this <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="nv">$casts</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;notification_settings&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;array&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The function <code>Illuminate/Database/Eloquent/Concerns/HasAttributes::castAttribute</code>, holds the gigantic switch case that
calls the surprisingly simple code <code>return json_decode($value ?? '', ! $asObject)</code>.</p>
<p>What was stored as a json string in the database, is now decoded into an array - and now offers all the problems of
arrays, being untyped, doomed for misuse, only understandable with examples no one will keep up to date.
Or, we don&rsquo;t cast it to an array, but to a value object (call it Data Transfer Object if you feel like it, but please
don&rsquo;t appreciate it to DTO&hellip; please&hellip;). This is supported by Laravel and mentioned in the Documentation, but from my
point of view it is not practiced enough!<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>






  
  
<figure><img src="/images/2023-01-cast.png" alt="Casting Corgi" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h3 id="defining-a-value-object" class="relative group">Defining a Value Object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#defining-a-value-object" aria-label="Anchor">#</a></span></h3><p><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>Value Objects</strong>:
Using objects instead of arrays has some benefits:</p>
<ul>
<li>The object describes a thing in the domain - by giving it a name communication with developers and business gets
easier.</li>
<li>The type of the data is clear, so the developer can use the IDE to autocomplete the properties.</li>
<li>The data is immutable, so it can&rsquo;t be changed by accident.</li>
<li>The data is valid as it is typed and can&rsquo;t be changed to an invalid state.</li>
</ul></span>
</div>

<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>To make a value object out of the json column, we need to define a class that holds the data and can implements
the <code>JsonSerializable</code> trait. In this easy example that would not be necessary, but if the object gets bigger, this
function ensures that the value object is serialized in the desired way. I also included a default using the
constructor, it is not necessary as well, just a nice feature (if the Value Object is not replaced when the model is
saved, the Database Value will still be null)</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">JsonSerializable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Support\Arrayable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">NotificationSettings</span> <span class="k">implements</span> <span class="nx">JsonSerializable</span><span class="p">,</span> <span class="nx">Arrayable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="k">public</span> <span class="nx">readonly</span> <span class="nx">bool</span> <span class="nv">$receivesAlerts</span> <span class="o">=</span> <span class="k">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="k">public</span> <span class="nx">readonly</span> <span class="nx">bool</span> <span class="nv">$receivesInfos</span> <span class="o">=</span> <span class="k">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="k">public</span> <span class="nx">readonly</span> <span class="nx">string</span> <span class="nv">$notificationTime</span> <span class="o">=</span> <span class="s1">&#39;daily&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">fromJson</span><span class="p">(</span><span class="nx">string</span><span class="o">|</span><span class="k">null</span> <span class="nv">$value</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">$decoded</span> <span class="o">=</span> <span class="nx">json_decode</span><span class="p">((</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$value</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="k">new</span> <span class="nx">NotificationMessageTypeBooleanGroup</span><span class="p">(</span><span class="nv">$decoded</span><span class="p">[</span><span class="s1">&#39;receivesAlerts&#39;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">            <span class="k">new</span> <span class="nx">NotificationMessageTypeBooleanGroup</span><span class="p">(</span><span class="nv">$decoded</span><span class="p">[</span><span class="s1">&#39;receivesInfos&#39;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">            <span class="k">new</span> <span class="nx">NotificationMessageTypeBooleanGroup</span><span class="p">(</span><span class="nv">$decoded</span><span class="p">[</span><span class="s1">&#39;notificationTime&#39;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">jsonSerialize</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;receivesAlerts&#39;</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">errors</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;receivesInfos&#39;</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">successfulReceivedMessages</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;notificationTime&#39;</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">successfulSendMessages</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">toArray</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">jsonSerialize</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Arrayable</strong>:
The <code>Arrayable</code> interface is used to ensure that the value object can be converted to an array.
This is a must if you use the Models toArray() function at any moment (which the framework does e.g. when using the
Laravel Request without JsonResources)</span>
</div>

<h3 id="casting-the-value-object" class="relative group">Casting the Value Object <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#casting-the-value-object" aria-label="Anchor">#</a></span></h3><p>Now the value object needs to be connected to the User Model using a custom Cast.
The important thing is to implement the <code>CastsAttributes</code> interface, which requires the <code>get</code> and <code>set</code> methods.
I decided to put most of the logic in the Value Object class, a valid and maybe more pattern based approach would be to
put the logic in the Cast class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">App\Support\ValueObjectsNotificationSetting</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Database\Eloquent\CastsAttributes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">NotificationSettingsCast</span> <span class="k">implements</span> <span class="nx">CastsAttributes</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">(</span><span class="nv">$model</span><span class="p">,</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="nv">$attributes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">NotificationSettings</span><span class="o">::</span><span class="na">fromJson</span><span class="p">(</span><span class="nv">$value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">set</span><span class="p">(</span><span class="nv">$model</span><span class="p">,</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="nv">$attributes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">json_encode</span><span class="p">(</span><span class="nv">$value</span><span class="o">-&gt;</span><span class="na">jsonSerialize</span><span class="p">(),</span> <span class="nx">JSON_THROW_ON_ERROR</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Last step to make it work is to add the cast to the User Model:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">protected</span> <span class="nv">$casts</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;notification_settings&#39;</span> <span class="o">=&gt;</span> <span class="nx">NotificationSettingsCast</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span></code></pre></div><h3 id="how-the-cast-is-called-by-the-framework" class="relative group">How the Cast is called by the Framework <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#how-the-cast-is-called-by-the-framework" aria-label="Anchor">#</a></span></h3><p>Going back to the <code>Illuminate/Database/Eloquent/Concerns/HasAttributes::castAttribute</code>, if the switch case can not
handle the default case, the NotificationSettingsCast is identified as <code>isClassCastable</code>, and it&rsquo;s <code>get</code> method is
called with <code>$model</code> the User Model, <code>$key</code> the name of the column, <code>$value</code> the value of the column, and <code>$attributes</code>
the other attributes of the model as array.
Vise versa, the <code>set</code> method is called when the model is saved, and the value object is serialized to json.</p>
<h2 id="but-wait-there-is-more-other-usages-of-casts" class="relative group">But wait, there is more! Other usages of Casts <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#but-wait-there-is-more-other-usages-of-casts" aria-label="Anchor">#</a></span></h2><p>Casts can also be used to fill &ldquo;imaginary&rdquo; columns, that are not stored in the database, but are calculated from other
sources. For example calculating the current State of a model, based on the timestamps of the model (or the existince of
certain Relations) can be performed by a Cast.</p>
<h3 id="boolean-cast-for-time-stamps" class="relative group">Boolean Cast for Time Stamps <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#boolean-cast-for-time-stamps" aria-label="Anchor">#</a></span></h3><p>Often boolean values are stored as timestamps in the database, most common example would be the <code>email_verified_at</code>
column. While the information when the email was verfiied is interesting, most times in the code only the fact it is not
null is relevant.</p>
<p>For this use case, a parameter is passed to the cast, which is the name of the column that holds the timestamp.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">protected</span> <span class="nv">$casts</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;is_email_verified&#39;</span> <span class="o">=&gt;</span> <span class="nx">DateToBoolenCast</span><span class="o">::</span><span class="na">class</span> <span class="o">.</span> <span class="s1">&#39;:email_verified_at&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span></code></pre></div><p>In this setting requires a Castable class to inject the parameter into the Cast class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Database\Eloquent\Castable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DateToBoolenCast</span> <span class="k">implements</span> <span class="nx">Castable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">castUsing</span><span class="p">(</span><span class="k">array</span> <span class="nv">$arguments</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">NullableEnumCast</span><span class="p">(</span><span class="nv">$arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>While the Cast class performs the actual casting.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Database\Eloquent\CastsAttributes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">NullableEnumCast</span> <span class="k">implements</span> <span class="nx">CastsAttributes</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="k">private</span> <span class="nx">readonly</span> <span class="nx">string</span> <span class="nv">$column</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">(</span><span class="nv">$model</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$attributes</span><span class="p">)</span><span class="o">:</span> <span class="nx">bool</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">(</span><span class="nx">bool</span><span class="p">)</span> <span class="nv">$model</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">column</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param $model
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param  bool|null  $value
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @return mixed
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">set</span><span class="p">(</span><span class="nv">$model</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$attributes</span><span class="p">)</span><span class="o">:</span> <span class="o">?</span><span class="nx">string</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$model</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">column</span><span class="p">}</span> <span class="o">=</span> <span class="nx">now</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>Casts are a powerful tool to extend the functionality of the Eloquent ORM. They can be used to define Value Objects,
calculate states, or fix columns to a more readable type.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://arctype.com/blog/json-database-when-use/" target="_blank" rel="noreferrer">If you want to read about when to use json in a relational db</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://laravel.com/docs/9.x/eloquent-mutators#array-and-json-casting" target="_blank" rel="noreferrer">Laravel Array Cast</a>.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://laravel.com/docs/9.x/eloquent-mutators#value-object-casting" target="_blank" rel="noreferrer">Laravel Custom Cast Docs</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://www.perlego.com/book/527020/domaindriven-design-in-php-pdf" target="_blank" rel="noreferrer">Value Objects explained in Domain Driven Design in PHP by Buenosvinos</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/></entry><entry><title type="html">Laravel Validations</title><link href="https://philodev.one/posts/2022-12-rules-with-validators/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="related" type="text/html" title="The Laravel Queue"/><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="related" type="text/html" title="About Actions, Jobs, Repositories, Events"/><link href="https://philodev.one/posts/2022-06-customer-search/?utm_source=atom_feed" rel="related" type="text/html" title="Technical Job Interview questions 2022"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><link href="https://philodev.one/posts/2022-05-relationships/?utm_source=atom_feed" rel="related" type="text/html" title="Useful and Useless Relationship Definitions"/><id>https://philodev.one/posts/2022-12-rules-with-validators/</id><published>2022-12-26T14:20:44+02:00</published><updated>2022-12-26T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Validations are great for ensuring that the data you receive is in the format you expect, while also handling a lot of edge cases (like ids that are not in the database). This ensures not only a fast failing of the request, but also gives the user (or front-end developer) a clear error message. Laravel offers great tools, in which I would like to dig deeper up to a final form of unintended usage - like Recursive Validations.</blockquote><div class="lead !mb-9 text-xl">
  Validations are great for ensuring that the data you receive is in the format you expect, while also handling a lot of
edge cases (like ids that are not in the database). This ensures not only a fast failing of the request, but also gives
the user (or front-end developer) a clear error message. Laravel offers great tools, in which I would like to dig deeper
up to a final form of unintended usage - like Recursive Validations.
</div>

<h2 id="validation-in-form-requests" class="relative group">Validation in Form Requests <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#validation-in-form-requests" aria-label="Anchor">#</a></span></h2><p>A custom FormRequest can have a <code>function rules()</code> which returns an array of rules, which are used to validate the data.
The magic behind this function includes the <code>Validator</code> class (<code>Illuminate\Validation\Validator</code>) which loops over all
key-value pairs, resolves the corresponding Rule (like &lsquo;min:2&rsquo; into Rule::min(2)) and checks if they fail.
The &lsquo;old school&rsquo; Rules are classes that implement a <code>function passes()</code> that will return a boolean whether the given
data is valid or not; based on that a translated error message is added to an Error Bag (and depending on the '
stopOnFirstFailure&rsquo; the loop continues <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>All this happens by magic if correctly injected in the Controller Method.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">App\Http\Requests</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Foundation\Http\FormRequest</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Validation\Rule</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">OrderRequest</span> <span class="k">extends</span> <span class="nx">FormRequest</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">rules</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;nullable&#39;</span><span class="p">,</span> <span class="s1">&#39;integer&#39;</span><span class="p">,</span> <span class="s1">&#39;min:1&#39;</span><span class="p">,</span> <span class="s1">&#39;max:100&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;game_id&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="s1">&#39;exists:games,id&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// mind, that the Rules can be called as static methods
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;role&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="nx">Rule</span><span class="o">::</span><span class="na">in</span><span class="p">([</span><span class="s1">&#39;knight&#39;</span><span class="p">,</span> <span class="s1">&#39;thief&#39;</span><span class="p">,</span> <span class="s1">&#39;ghost&#39;</span><span class="p">,</span> <span class="s1">&#39;wizard&#39;</span><span class="p">])],</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// and that they may get closures as parameters
</span></span></span><span class="line"><span class="cl">            <span class="c1">// (this will return the default error message)
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;items&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nx">Rule</span><span class="o">::</span><span class="na">requiredIf</span><span class="p">(</span><span class="nx">fn</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">role</span> <span class="o">===</span> <span class="s1">&#39;thief&#39;</span><span class="p">),</span> <span class="s1">&#39;array&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// or that a custom rule can be implemented as closure
</span></span></span><span class="line"><span class="cl">            <span class="c1">// this will return special error messages
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;spells&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;array&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$attribute</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="nv">$fail</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">role</span> <span class="o">!==</span> <span class="s1">&#39;wizard&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nv">$fail</span><span class="p">(</span><span class="s1">&#39;Only wizards can cast spells&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="nx">count</span><span class="p">(</span><span class="nv">$value</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nv">$fail</span><span class="p">(</span><span class="s1">&#39;A wizard can only cast 3 spells&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}],</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="custom-rules" class="relative group">Custom Rules <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#custom-rules" aria-label="Anchor">#</a></span></h2><p>Often enough, these validations will contain some duplication. For example, in this RPG example, the <code>game_id</code> may only
belong to a game which is not finished yet. This can be implemented as a custom rule.
Laravel provides this using Invokable Rules, which contain a single method: __invoke. This method receives the
attribute name, its value, and a callback that should be invoked on failure with the validation error message.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">App\Http\Rules</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Validation\InvokableRule</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UnfinishedGameRule</span> <span class="k">implements</span> <span class="nx">InvokableRule</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param  string  $attribute
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param  mixed  $value
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__invoke</span><span class="p">(</span><span class="nv">$attribute</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="nv">$fail</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$game</span> <span class="o">=</span> <span class="nx">Game</span><span class="o">::</span><span class="na">find</span><span class="p">(</span><span class="nv">$value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$game</span><span class="o">-&gt;</span><span class="na">isFinished</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$fail</span><span class="p">(</span><span class="s1">&#39;The game is already finished&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This rule can be used in the FormRequest as
follows:</p>
<p><code>$request-&gt;validate(['game_id' =&gt; ['required', 'exists:games,id', new UnfinishedGameRule]]);</code></p>
<p>Rules offer some quite nice additions, like adding parameters to the Rule using its constructor, or implementing
the <code>DataAwareRule</code> Interface which allows you to access the data of the request.</p>
<h2 id="validations-in-rules" class="relative group">Validations in Rules <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#validations-in-rules" aria-label="Anchor">#</a></span></h2><p>In theory, this should be enough &hellip; but when working with complex objects, it would be so nice to have a validation
inside the Rule Object. Just implementing a new Validator inside of the Rule would be a nice solution, but leads to some
problems:</p>
<ol>
<li>The Validator will not return the correct error message, as it is not aware of the full attribute name (e.g. <code>name</code>
instead of <code>items.0.name</code>)</li>
<li>The nesting of the Error Bag will be messed up</li>
<li>The original Validator will not be aware of the new rules, so it will not be able to access the data using $request-&gt;
safe(&rsquo;name&rsquo;)</li>
<li><code>dependentRules</code> will not be displayed using the correct attribute name (e.g. if one value must be greater than
another, the error message will not be displayed correctly)</li>
</ol>
<p>To solve this, we can use the <code>ValidatorAwareRule</code> Interface, which allows us to inject the Validator into the Rule.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">App\Http\Rules</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Validation\InvokableRule</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Validation\ValidatorAwareRule</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\Facades\Validator</span> <span class="k">as</span> <span class="nx">ValidatorFacade</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Validation\Validator</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ItemRule</span> <span class="k">implements</span> <span class="nx">InvokableRule</span><span class="p">,</span> <span class="nx">ValidatorAwareRule</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="nx">Validator</span> <span class="nv">$validator</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__invoke</span><span class="p">(</span><span class="nv">$attribute</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="nv">$fail</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 1. fix attribute name
</span></span></span><span class="line"><span class="cl">        <span class="nv">$attributeNames</span> <span class="o">=</span> <span class="nx">collect</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">rules</span><span class="p">(</span><span class="nv">$value</span><span class="p">))</span><span class="o">-&gt;</span><span class="na">keys</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">mapWithKeys</span><span class="p">(</span><span class="nx">fn</span> <span class="p">(</span><span class="nx">string</span> <span class="nv">$key</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$attribute</span> <span class="o">.</span> <span class="s1">&#39;.&#39;</span> <span class="o">.</span> <span class="nv">$key</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">toArray</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">$validator</span> <span class="o">=</span> <span class="nx">ValidatorFacade</span><span class="o">::</span><span class="na">make</span><span class="p">(</span><span class="nv">$value</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">rules</span><span class="p">(</span><span class="nv">$value</span><span class="p">),</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">messages</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">setAttributeNames</span><span class="p">(</span><span class="nv">$attributeNames</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// 2. The errors will be added to the parent validator.
</span></span></span><span class="line"><span class="cl">        <span class="k">foreach</span> <span class="p">(</span><span class="nv">$validator</span><span class="o">-&gt;</span><span class="na">errors</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getMessages</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$message</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">validator</span><span class="o">-&gt;</span><span class="na">getMessageBag</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">add</span><span class="p">(</span><span class="nv">$attribute</span> <span class="o">.</span> <span class="s1">&#39;.&#39;</span> <span class="o">.</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$message</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">??</span> <span class="s1">&#39;Validation failed&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setValidator</span><span class="p">(</span><span class="nv">$validator</span><span class="p">)</span><span class="o">:</span> <span class="k">static</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">validator</span> <span class="o">=</span> <span class="nv">$validator</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="k">function</span> <span class="nf">rules</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="s1">&#39;string&#39;</span><span class="p">,</span> <span class="s1">&#39;min:2&#39;</span><span class="p">,</span> <span class="s1">&#39;max:100&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;description&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;nullable&#39;</span><span class="p">,</span> <span class="s1">&#39;string&#39;</span><span class="p">,</span> <span class="s1">&#39;min:2&#39;</span><span class="p">,</span> <span class="s1">&#39;max:100&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;price&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="s1">&#39;numeric&#39;</span><span class="p">,</span> <span class="s1">&#39;min:0&#39;</span><span class="p">,</span> <span class="s1">&#39;max:1000&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;amount&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="s1">&#39;integer&#39;</span><span class="p">,</span> <span class="s1">&#39;min:1&#39;</span><span class="p">,</span> <span class="s1">&#39;max:100&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="k">function</span> <span class="nf">messages</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="fixing-the-problems-of-validations-in-rules" class="relative group">Fixing the problems of Validations in Rules <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#fixing-the-problems-of-validations-in-rules" aria-label="Anchor">#</a></span></h3><ol>
<li>Fixing the Attribute name</li>
</ol>
<p>Prefixing the attribute names will cause the error message to correctly display the path, e.g. &ldquo;The items.0.name field
is required&rdquo; instead of &ldquo;The name field is required&rdquo;.</p>
<p>BUT, this will not work if Rule again includes a nested Rule, as the attribute name will need to be prefixed again.
Assuming that the array separator <code>.</code> is used, the contained attribute can be prefixed again.
This code is not even close to a readable, good solution; if you have a better idea, please let me know.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="c1">// The errors will be added to the parent validator.
</span></span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nv">$validator</span><span class="o">-&gt;</span><span class="na">errors</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getMessages</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$message</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="nv">$newMessage</span> <span class="o">=</span> <span class="nx">is_array</span><span class="p">(</span><span class="nv">$message</span><span class="p">)</span> <span class="o">?</span> <span class="nv">$message</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">:</span> <span class="nv">$message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="c1">// If the rule is nested, we need to replace the {key} placeholder with the parent key.
</span></span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="nx">str_contains</span><span class="p">((</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$newMessage</span><span class="p">,</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$key</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">str_contains</span><span class="p">((</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$key</span><span class="p">,</span> <span class="s1">&#39;.&#39;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">       <span class="nv">$newMessage</span> <span class="o">=</span> <span class="nx">str_replace</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$attribute</span> <span class="o">.</span> <span class="s1">&#39;.&#39;</span> <span class="o">.</span> <span class="nv">$key</span><span class="p">,</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$newMessage</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">validator</span><span class="o">-&gt;</span><span class="na">getMessageBag</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">add</span><span class="p">(</span><span class="nv">$attribute</span> <span class="o">.</span> <span class="s1">&#39;.&#39;</span> <span class="o">.</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$newMessage</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol start="2">
<li>Fixing the Error Bag</li>
</ol>
<p>The errors will be added to the parent validator, so both the messages and the errors will not be empty. Mind
that I only add the first error message.</p>
<p>Conveniently, the Validators will bubble their ErrorBags up, so this allows for recursive usage of nested Rules.</p>
<ol start="3">
<li>Fixing the Rules</li>
</ol>
<p>Because this is an array (I suppose), this works just fine without adding the rules to the original Validator. In other
cases code like this might be helpful:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">  <span class="c1">// The rules will be added to the parent validator to access the attributes using e.g. $request-&gt;safe(&#39;key)
</span></span></span><span class="line"><span class="cl">  <span class="nv">$newRules</span> <span class="o">=</span> <span class="nx">collect</span><span class="p">(</span><span class="nv">$validator</span><span class="o">-&gt;</span><span class="na">getRules</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">      <span class="o">-&gt;</span><span class="na">mapWithKeys</span><span class="p">(</span><span class="nx">fn</span> <span class="p">(</span><span class="nv">$rules</span><span class="p">,</span> <span class="nv">$key</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$attribute</span> <span class="o">.</span> <span class="s1">&#39;.&#39;</span> <span class="o">.</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$rules</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">      <span class="o">-&gt;</span><span class="na">toArray</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">validator</span><span class="o">-&gt;</span><span class="na">addRules</span><span class="p">(</span><span class="nv">$newRules</span><span class="p">);</span>
</span></span></code></pre></div><ol start="4">
<li>Fixing the Dependent Rule messages</li>
</ol>
<p>This will work with the fix of 1.</p>
<h3 id="recursive-rules" class="relative group">Recursive Rules <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#recursive-rules" aria-label="Anchor">#</a></span></h3><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>New Feature Unlocked</strong>:
For the validation of recursive data structures - this is one implementation idea.
Adding a private property of the current nesting level to the Rule and incrementing it on each call of the Rule will
enable the validation of the whole data without too much extra code, and enforce changing maximum nesting levels.</span>
</div>

<p>Example for nesting:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">function</span> <span class="nf">rules</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="s1">&#39;string&#39;</span><span class="p">,</span> <span class="s1">&#39;min:2&#39;</span><span class="p">,</span> <span class="s1">&#39;max:100&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;description&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;nullable&#39;</span><span class="p">,</span> <span class="s1">&#39;string&#39;</span><span class="p">,</span> <span class="s1">&#39;min:2&#39;</span><span class="p">,</span> <span class="s1">&#39;max:100&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;price&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="s1">&#39;numeric&#39;</span><span class="p">,</span> <span class="s1">&#39;min:0&#39;</span><span class="p">,</span> <span class="s1">&#39;max:1000&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;amount&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;required&#39;</span><span class="p">,</span> <span class="s1">&#39;integer&#39;</span><span class="p">,</span> <span class="s1">&#39;min:1&#39;</span><span class="p">,</span> <span class="s1">&#39;max:100&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;subItems&#39;</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">currentNestingLevel</span> <span class="o">&gt;=</span> <span class="mi">3</span> <span class="o">?</span> <span class="p">[</span><span class="s1">&#39;prohibited&#39;</span><span class="p">]</span> <span class="o">:</span> <span class="p">[</span><span class="s1">&#39;nullable&#39;</span><span class="p">,</span> <span class="s1">&#39;array&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;subItems.*&#39;</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">&#39;nullable&#39;</span><span class="p">,</span> <span class="k">new</span> <span class="nx">self</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">currentNestingLevel</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)],</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>If such a complex validation is needed, it might be a good idea to use a custom Rule.
If that custom Rule would benefit from implementing its own validation, this is possible with some workarounds.
If recursive validation is needed, this can be achieved by enhancing the Rule with a private property for the nesting
level.</p>
<p>If, on the other hand, the validation is not that complex, keep it simple.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://laravel.com/docs/9.x/validation" target="_blank" rel="noreferrer">That and more explained in the Laravel Docs</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/><category scheme="taxonomy:Tags" term="validation" label="Validation"/></entry><entry><title type="html">The Laravel Queue</title><link href="https://philodev.one/posts/2022-12-queues/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="related" type="text/html" title="About Actions, Jobs, Repositories, Events"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><link href="https://philodev.one/posts/2022-06-customer-search/?utm_source=atom_feed" rel="related" type="text/html" title="Technical Job Interview questions 2022"/><link href="https://philodev.one/posts/2022-05-relationships/?utm_source=atom_feed" rel="related" type="text/html" title="Useful and Useless Relationship Definitions"/><id>https://philodev.one/posts/2022-12-queues/</id><published>2022-12-11T14:20:44+02:00</published><updated>2022-12-11T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>After debugging problems with the Serialisation of Classes, I learned I know way too little about Laravel Queues. So this article is me stepping down from the zenith of my personal Dunning–Kruger Effect curve and deconstructing the Laravel Queue</blockquote><div class="lead !mb-9 text-xl">
  After debugging problems with the Serialisation of Classes, I learned I know way too little about Laravel Queues. So
this article is me stepping down from the zenith of my personal Dunning–Kruger Effect curve and deconstructing the
Laravel Queue
</div>

<p>To do this, I started my journey with a test - this is not for testing anything, it&rsquo;s just a tool to lure the
way through the magical forest of Laravel.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">Tests\Feature</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">App\Models\Game</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">App\Queue\Events\TestEvent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\Facades\Artisan</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Tests\TestCase</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">EventTest</span> <span class="k">extends</span> <span class="nx">TestCase</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">testEvent</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="sd">/** @var Game $game */</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$game</span> <span class="o">=</span> <span class="nx">Game</span><span class="o">::</span><span class="na">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nx">TestEvent</span><span class="o">::</span><span class="na">dispatch</span><span class="p">(</span><span class="nv">$game</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">Artisan</span><span class="o">::</span><span class="na">call</span><span class="p">(</span><span class="s1">&#39;queue:work --queue=game-queue&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertTrue</span><span class="p">(</span><span class="nv">$game</span><span class="o">-&gt;</span><span class="na">refresh</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">token</span> <span class="o">===</span> <span class="s1">&#39;Tested by Event&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="dispatching-the-event" class="relative group">Dispatching the Event <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#dispatching-the-event" aria-label="Anchor">#</a></span></h2><p>The Event that is dispatched in the first step is simple enough to be interesting inside the queue.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">App\Models\Game</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Broadcasting\InteractsWithSockets</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Queue\ShouldQueue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Foundation\Events\Dispatchable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Queue\SerializesModels</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TestEvent</span> <span class="k">implements</span> <span class="nx">ShouldQueue</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="nx">Dispatchable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="nx">InteractsWithSockets</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="nx">SerializesModels</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">public</span> <span class="nx">Game</span> <span class="nv">$game</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Mind the <code>Dispatchable</code> trait, which will lead (using some magic helper function)
to <code>Illuminate\Events\Dispatcher::dispatch()</code>. Ignoring Broadcasts here, the Dispatcher will determine the Listeners. To
emphasize this - it is not the Event that is pushed to the Queue, it is the Listener.</p>
<p><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Underrated Laravel Feature</strong>:
Laravel has a Feature that enables the Connection of Events and Listeners without the usage ofa Service Provider. By
just correctly Typehinting the Event in the Listener. Might be that it introduces more complexity for your deployment as
you have to care more about Cache.</span>
</div>

<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">App\Queue\Events\TestEvent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Queue\ShouldQueue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TestListener</span> <span class="k">implements</span> <span class="nx">ShouldQueue</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="nv">$connection</span> <span class="o">=</span> <span class="s1">&#39;database&#39;</span><span class="p">;</span> <span class="c1">// can be in the env
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="nv">$queue</span> <span class="o">=</span> <span class="s1">&#39;game-queue&#39;</span><span class="p">;</span> <span class="c1">// was fun testing
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">handle</span><span class="p">(</span><span class="nx">TestEvent</span> <span class="nv">$event</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$event</span><span class="o">-&gt;</span><span class="na">game</span><span class="o">-&gt;</span><span class="na">update</span><span class="p">([</span><span class="s1">&#39;token&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Tested by Event&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Each Listener determines if it is queueable (which means if it implements the ShouldQueue Interface). If not, the
current container resolves the Listener and calls the <code>handle</code> function.
If yes, the Listener is handed to the <code>queueHandler</code>.
In this step, the Listener (and the Event it receives in its method parameters) are deconstructed. The Handle Method
Arguments are mapped into an Array including ALL its attributes (including private or protected ones). If the Event
contains complex properties, this might cause problems. An Event should be as simple as possible.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"> <span class="nv">$arguments</span> <span class="o">=</span> <span class="nx">array_map</span><span class="p">(</span><span class="k">function</span> <span class="p">(</span><span class="nv">$a</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="nx">is_object</span><span class="p">(</span><span class="nv">$a</span><span class="p">)</span> <span class="o">?</span> <span class="k">clone</span> <span class="nv">$a</span> <span class="o">:</span> <span class="nv">$a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span> <span class="nx">func_get_args</span><span class="p">())</span>
</span></span></code></pre></div><p>After mapping the arguments the Listener will receive, the Listener is packed in
a <code>new CallQueuedListener($class, $method, $arguments)</code>. This object is also filled with the Queue Name and the
Connection, both usually set in the environment, but can be overwritten in the Listener.</p>
<h2 id="pushing-and-serializing-the-listener" class="relative group">Pushing and serializing the Listener <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#pushing-and-serializing-the-listener" aria-label="Anchor">#</a></span></h2><p>Then, corresponding again to the connection, the Queue is called via <code>Illuminate/Queue/DatabaseQueue::push</code>. The
Queue is responsible for defining the Payload. For this the Job (which holds the Listener) is
Serialized <code>serialize(clone $job);</code> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> and then pushed to the Queue.</p>
<p>The goal of Serialization is to convert a complex data structure into a storable representation of a value (in this case
a JSON String).
This should not be used for storing objects in the Database in a normal case, but in this case, it&rsquo;s used
to store the Listener in some kind of queue, as well as its current state. The Constructor is not serialized, so
dependency Injection is still possible in the Listener.</p>
<p>Small loop back the Event and the SerializesModels Trait. This Trait contains implements a <code>__serialize()</code> function,
which overwrites the normal serialization, so the object stored on the queue is way smaller and only contains the
identifier, a list of eager loaded relations and changed attributes.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Warnings regarding Serialization</strong>:  When serialize() serializes objects, the leading
backslash is not included in the class name of namespaced classes for maximum compatibility. Also, not everything is
serializable, one limit are Closures.</span>
</div>

<p>With all that the payload looks something like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;uuid&#34;</span><span class="p">:</span> <span class="s2">&#34;66b9777e-221d-4c8e-9b4e-8870d7d6aec2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;displayName&#34;</span><span class="p">:</span> <span class="s2">&#34;App\\Queue\\Listeners\\TestListener&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;job&#34;</span><span class="p">:</span> <span class="s2">&#34;Illuminate\\Queue\\CallQueuedHandler@call&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;maxTries&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;maxExceptions&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;failOnTimeout&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;backoff&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;timeout&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;retryUntil&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;commandName&#34;</span><span class="p">:</span> <span class="s2">&#34;Illuminate\\Events\\CallQueuedListener&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;class&#34;</span><span class="p">:</span> <span class="s2">&#34;App\\Queue\\Listeners\\TestListener&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;method&#34;</span><span class="p">:</span> <span class="s2">&#34;handle&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;arePublicsGettingSerialized&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;game&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;class&#34;</span><span class="p">:</span> <span class="s2">&#34;App\\Models\\Game&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;relations&#34;</span><span class="p">:</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">          <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;socket&#34;</span><span class="p">:</span> <span class="kc">null</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;tries&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;maxExceptions&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;backoff&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;retryUntil&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;timeout&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;shouldBeEncrypted&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;job&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;connection&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;queue&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;chainConnection&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;chainQueue&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;chainCatchCallbacks&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;delay&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;afterCommit&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;middleware&#34;</span><span class="p">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;chained&#34;</span><span class="p">:</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><p><strong>Notes on Method Locations</strong>:<br>
While most of the above happen inside the specific Queue (like <code>DatabaseQueue</code>), all Queues I found are using
the <code>createPayload()</code> inside the <code>Illuminate\Queue\Queue</code>. I assume this is to make sure the Payload looks the same for
every Driver and can be read by every worker. But here is one weakness of the Laravel Queue:</p>
<p>In complex systems it might be useful to use Events to communicate between different Services throughout the System,
writing and listening to the same queue. Implementing something like that in Laravel would require writing a new Queue,
maybe not using the <code>createPayload()</code> function, which sounds like a slippery slope; but if you went it down, I would be
curious to hear about it.</p>
</span>
</div>

<p>Now, what&rsquo;s left is building the Database entry. After this the container might get deconstructed, the PHP thread
changes, everything after this step happens at a different time - maybe on a different server!
What feels like implementing an &ldquo;empty&rdquo; Interface like <code>ShouldQueue</code> without a great impact on local Development
with <code>QUEUE_CONNECTION=sync</code> hides the code and context switches happening on production.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">protected</span> <span class="k">function</span> <span class="nf">buildDatabaseRecord</span><span class="p">(</span><span class="nv">$queue</span><span class="p">,</span> <span class="nv">$payload</span><span class="p">,</span> <span class="nv">$availableAt</span><span class="p">,</span> <span class="nv">$attempts</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;queue&#39;</span> <span class="o">=&gt;</span> <span class="nv">$queue</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;attempts&#39;</span> <span class="o">=&gt;</span> <span class="nv">$attempts</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;reserved_at&#39;</span> <span class="o">=&gt;</span> <span class="k">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;available_at&#39;</span> <span class="o">=&gt;</span> <span class="nv">$availableAt</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;created_at&#39;</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">currentTime</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;payload&#39;</span> <span class="o">=&gt;</span> <span class="nv">$payload</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="working-the-queue" class="relative group">Working the Queue <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#working-the-queue" aria-label="Anchor">#</a></span></h2><p>Working the queue is triggered by a Command, the <code>Illuminate\Queue\Console\WorkCommand::handle()</code>. This command triggers
a worker to run as daemon, which means it uses a <code>while(true)</code> loop to run until its break conditions (e.g. Maintenance
Mode) are triggered <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.
To emphasize this: The Worker is not a daemon in the sense of a Linux Daemon, it&rsquo;s php code running inside a
Laravel application. Which for me raised the question if all Jobs processed by the Worker are processed in the same
context / Container. Short answer is Yes, or as it&rsquo;s stated in the Laravel Docs:</p>
<blockquote>
<p>Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they
will not notice changes in your code base after they have been started. <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
</blockquote>
<p>Not so short answer is: in production, no. A line of code I even put in my deployment script includes a Supervisor which
will restart the worker every hour or after a certain number of jobs <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. Again emphasizing, because I did not
expect it to work like this: Laravel uses a non Laravel Superviser task to control a Laravel Container which would
otherwise just keep on running on the server, which is working all the jobs in the same context in its queue with no
build in capability of sharing that queue with other applications. I mean it works.</p>
<p>In this loop, it will call <code>Illuminate/Queue/DatabaseQueue::pop</code> to fetch the next Job and unpack it into a Job,
in this case, an <code>Illuminate/Queue/Jobs/DatabaseJob</code>. The Worker will raise an Event before the Job starts and after the
Job finished (or failed). Finally, the Jobs <code>fire()</code> method can be called, which instantiates the Listener and calls the
specified method with the Event as a parameter.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>I wrote this article to understand the Laravel Queue better, what parts can be dangerous and what hooks I can use if I
need a different behavior than the Laravel default.</p>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://laravel.com/docs/9.x/events#event-discovery" target="_blank" rel="noreferrer">Laravel provides some information about the queue</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://www.php.net/manual/en/function.serialize.php" target="_blank" rel="noreferrer">Serialise function, how to overload it, and more</a>.
As so often, the best comments are better than the manual.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://divinglaravel.com/queue-workers-how-they-work" target="_blank" rel="noreferrer">Deep Dive into Laravel Work Command</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://laravel.com/docs/9.x/queues#the-queue-work-command" target="_blank" rel="noreferrer">Laravel Docs</a> to explain how the worker is
a long-lived process&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://laravel.com/docs/9.x/queues#supervisor-configuration" target="_blank" rel="noreferrer">Supervisor</a> is a process control system
that allows you to monitor and control a worker&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/><category scheme="taxonomy:Tags" term="queue" label="Queue"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/></entry><entry><title type="html">Improving Retros from a Devs Perspective</title><link href="https://philodev.one/posts/2022-09-sprint-retro/?utm_source=atom_feed" rel="alternate" type="text/html"/><id>https://philodev.one/posts/2022-09-sprint-retro/</id><published>2022-10-10T14:20:44+02:00</published><updated>2022-10-10T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>As a developer, most of the meetings I join I either want to talk about code, or I am asking myself why I joined the meeting, and if I would not be more productive writing code. Retrospectives are an exception. I love retrospectives. I enjoy the feeling of improvement after a retro, I like the open communication of retros, and I like the feeling of being heard.</blockquote><div class="lead !mb-9 text-xl">
  As a developer, most of the meetings I join I either want to talk about code, or I am asking myself why I joined the
meeting, and if I would not be more productive writing code. Retrospectives are an exception. I love retrospectives. I
enjoy the feeling of improvement after a retro, I like the open communication of retros, and I like the feeling of
being heard.
</div>

<h2 id="retros-by-scrum-definition" class="relative group">Retros by Scrum Definition <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#retros-by-scrum-definition" aria-label="Anchor">#</a></span></h2><p>A Retrospective is a meeting that is focused around improving the processes in and around a team. It often happens after
the sprint and addresses stumble stones that happened during the sprint. It&rsquo;s neither about blaming people nor about
whining, it&rsquo;s about improving productivity, effectiveness, and developer happiness.
In the Retrospectives I attended, common discussion topics include how much can business interrupt in the sprint; how
should communication happen between teams, how is the team defining definition of done / ready / production ready; or
what meetings should be required for developers or maybe need time changes <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">During the Sprint Retrospective, the team discusses: <br>
What went well in the Sprint <br>
What could be improved <br>
What will we commit improving in the next Sprint</span>
</div>

<h3 id="little-dangers-of-retros" class="relative group">Little dangers of Retros <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#little-dangers-of-retros" aria-label="Anchor">#</a></span></h3><p>Retrospectives come with some dangers. They are often all-hand-meetings, which means if they become useless often two
working hours per developer and scrum master are wasted. The developer happiness wasted by frustrating meetings is
what bugs me personally, but for some managers, it is easier to argue with the cost of a meeting. The hours of meeting,
times the number of people, times the hourly rate of everybody quickly ends up in a number big enough that even the
cost-focused managers value the time of team members.</p>
<p>To keep the Retrospectives useful, they need to be goal-oriented, honest, and what I would call in german &ldquo;kurzweilig&rdquo; -
which translates to feeling quick and amusing. More agile definition trained people have written posts on how important
it is to make it a safe space for the team to talk about what is not working; and how it is important to have measurable
changes that have an impact on the team. What I was missing in the retrospectives I attended was a bit of the fun part.</p>
<h2 id="retrospectives-gamification" class="relative group">Retrospectives Gamification <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#retrospectives-gamification" aria-label="Anchor">#</a></span></h2><p>I went to some retrospectives where the team was asked to display their mood using a weather frog in the best case,
or to write down their problems on sticky notes and then put them on the same three colored miro rectangles every sprint
in the worst case. It&rsquo;s not bad&hellip; it&rsquo;s just boring.</p>
<p>For my current team, I started to make the retrospectives a bit more fun. I started with different themes, and people
enjoyed it. People started to ask how I created them, what my references where, and how I would come up with the ideas -
so this post will be both an idea for interested, a guide for creators, <strike> and a collection of themes for those
who just want ready to use themes </strike> (never mind that; explained in the last paragraph).</p>
<h3 id="using-themes-for-asking-different-questions" class="relative group">Using themes for asking different questions <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-themes-for-asking-different-questions" aria-label="Anchor">#</a></span></h3><h4 id="start-stop-keep" class="relative group">Start, Stop, Keep <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#start-stop-keep" aria-label="Anchor">#</a></span></h4><p>The most commonly described Retro Questions are <strong>What should we start to do?</strong>, <strong>What should we stop doing?</strong>, <strong>What
should we keep doing?</strong>.
Those questions have their reasons and fulfill what a Retrospective wants to achieve. However, asking every time the
same
questions in my experience leads to the same answers. Although Scrum Masters would appreciate it, most Dev Teams do not
collect various points to improve throughout the sprint, and then discuss them in the retro. Instead, they discuss what
comes to their mind the moment they are asked - This is not blaming, it&rsquo;s mostly self-observation.</p>
<p>The following Questions are more or less rephrasing these base questions of Retrospectives. Asking in different ways
can lead to new answers and also can give each Retro a theme by itself, a team that is happy in the current setting
might benefit more from talking about what tools or practices could be added, while a fresh team might focus on
well-being.</p>
<p>All upcoming ideas are focused on the idea of sharing a view (live or virtual) and placing post-it like notes on a
board.</p>
<h4 id="finding-good-and-bad-practices" class="relative group">Finding good and bad practices <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#finding-good-and-bad-practices" aria-label="Anchor">#</a></span></h4><p>When evaluating practices it can be helpful to guide the team using one (or multiple) axes. Depending on the Situation
just asking for good or bad practices can be enough, but e.g. after a troubled sprint it might be helpful to ask for
specific practices for prevention or future firefighting; if the Team is looking for new technology a cloud or tree can
be used to group discussions in different branches of topics; and if working with existing metrics those metrics can be
used to place member opinions; during special occasions just rephrasing the question can be fun - like asking for the
best tricks or treats in Halloween themed retro.</p>
<p>






  
  
<figure><img src="/images/2022-10-retro-1.png" alt="Finding good and bad practices" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h4 id="communicating-doubts" class="relative group">Communicating Doubts <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#communicating-doubts" aria-label="Anchor">#</a></span></h4><p>Although this might be included in the bad practices, often enough precisely asking for problems and doubts can reveal
more problems and encourage a discussion in the team. To support the discussion in the Retrospective, different axes and
designs can again add value compared to the (still valid and useful) word cloud.
Some examples are adding Priorisation to encourage the team to not only add topics that need improvements but also to
rank them on their urgency; if the topics that need change are already known, a heatmap can be visualised what the
important pain points are; on the other hand to discover new improvement points a categorisation can refine and increase
the results; last but not least sometimes negating the question can lead to a different point of view and again reveal
unknown concerns.</p>
<p>






  
  
<figure><img src="/images/2022-10-retro-2.png" alt="Communicating Doubts" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h4 id="finding-vision-and-celebrating-success" class="relative group">Finding Vision and Celebrating Success <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#finding-vision-and-celebrating-success" aria-label="Anchor">#</a></span></h4><p>Celebrations are often left out, but I enjoy the idea of celebrating the little learning we found to
communicate them and to encourage going deep to understand the framework, the domain, or the customer better.
For developers who don&rsquo;t enjoy bragging in the daily about what they learned, dedicated badges can be a nice starting
point. (I would award code, features, ideas, or situations instead of people).
Regarding Vision and goals, of course the word cloud is again a valid idea (the theme example of dishes as above can be
reused - &ldquo;what spices are missing in our success / code recipe?&rdquo;). But it&rsquo;s again more effective to also rate the
improvement ideas by the time frame in which an idea adds value to the company / team / codebase.
If the main goal is to first come up with any ideas, a Venn Diagram can be helpful to identify differences between the
team goals (like a well tested code base) and the business goals (like new features now).</p>
<p>






  
  
<figure><img src="/images/2022-10-retro-3.png" alt="Finding Vision and Value" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h4 id="mood-check" class="relative group">Mood Check <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#mood-check" aria-label="Anchor">#</a></span></h4><p>Last but not least, a mood check can be helpful to identify the general feeling of the team and can be just fun.
Any spectrum of &ldquo;feeling alive?&rdquo; can give a quick overview of the individual mood; if sticking your note in the same
place every time became a habit, it can be helpful to move the &ldquo;feeling good&rdquo; spot on an axis to the center.
Also, a fun exercise is to give a theme and ask for one word to describe the last sprint.
Similar to the other questions, of course categorisation can again help to discover new problems in the team by
enforcing
questioning some practices in the team.</p>
<p>






  
  
<figure><img src="/images/2022-10-retro-4.png" alt="Finding Vision and Value" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="special-retros-updated-29122023" class="relative group">Special Retros (updated 29.12.2023) <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#special-retros-updated-29122023" aria-label="Anchor">#</a></span></h2><p>From time to time, a special retro can provide an overview of the team&rsquo;s long-term state, can be used to celebrate
very big milestones, or fill retros which will presumably not be very productive.</p>
<h3 id="timeline-retros" class="relative group">Timeline Retros <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#timeline-retros" aria-label="Anchor">#</a></span></h3><p>Perfect for pre new year retrospectives, or for retrospectives after finishing a great milestone.</p>
<p>First Step - Reconstruct the timeline: A timeline over a selected time frame (e.g. the last half year) is provided.
Additionally, a set of categories (new Team member started, achievement unlocked, new technology introduced, &hellip;) or
some timeline distinctions (team events, company events, &hellip;) may be provided as help.
In our team, it was helpful to do this step as discussion instead of individual work, as already in this step the team
discovered that the team does not remember achievements and want to celebrate them more.</p>
<p>I already find this step very valuable, and the next step depends on the team capabilities to communicate their
feelings. Not all teams are comfortable sharing their feelings, but if they are, the next step can provide nice
insides.</p>
<p>Second Step - Match the teams feelings: The team is asked to place their feelings on the timeline.
This can be used to discuss what events changed the team&rsquo;s mood, and what events can maybe celebrated or discussed in
future.</p>
<p>






  
  
<figure><img src="/images/2023-12-retro-5.png" alt="Timeline Retro" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="collection-of-themes" class="relative group">Collection of Themes <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#collection-of-themes" aria-label="Anchor">#</a></span></h2><p>The idea of this blog was to publish my themes. I made themes like:</p>
<ul>
<li>Pokemon: What was your hardest battle? On a scale of &ldquo;Developer fainted&rdquo; to &ldquo;Developer had a critical hit&rdquo; - how was
the sprint? &hellip;</li>
<li>Don&rsquo;t Starve (the video game): What is your sanity level after the sprint? What monsters scared you the most? &hellip;</li>
<li>Pen and Paper: What was your hardest dungeon? What was your best item? &hellip;</li>
<li>Beer pong: What was your best trickshot? &hellip;</li>
<li>&hellip; (an more, this list will not be updated) <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></li>
</ul>
<p>BUT, I don&rsquo;t feel comfortable publishing them because I am scared of copyright problems. I respect the work of the
different artist, I am sure if I would ask them I could use the pictures, but honestly, I am too lazy for that as well.
So take this advice:</p>
<blockquote>
<p>Be creative, use cool themes, make your developers smile at your themes - everything is
allowed. Steal the questions and setups from this and other blogs, and color it with whatever your devs enjoy;
when in doubt, add a unicorn 🦄.</p>
</blockquote>
<p>Happy Coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Stolen from <a href="https://www.agilealliance.org/glossary/retrospective/" target="_blank" rel="noreferrer">Scrum.org</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>For inspiration use
this <a href="https://www.scrum.org/resources/blog/retrospective-ideas" target="_blank" rel="noreferrer">Set of Themes with questions and online tools</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="agile" label="Agile"/></entry><entry><title type="html">Ethical Development</title><link href="https://philodev.one/posts/2022-08-etchical-development/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-06-customer-search/?utm_source=atom_feed" rel="related" type="text/html" title="Technical Job Interview questions 2022"/><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="related" type="text/html" title="About Actions, Jobs, Repositories, Events"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><link href="https://philodev.one/posts/2022-05-relationships/?utm_source=atom_feed" rel="related" type="text/html" title="Useful and Useless Relationship Definitions"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><id>https://philodev.one/posts/2022-08-etchical-development/</id><published>2022-08-31T14:20:44+02:00</published><updated>2022-08-31T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Ethical behaviour helps a social group to flourish and strives to develop the best possible version possible. Formulating it this way maybe describes why even the most rational minds in development should hold a second to think about the code they are designing, implementing, or requesting. From an ethical point of view: Is your code good?</blockquote><div class="lead !mb-9 text-xl">
  Ethical behaviour helps a social group to flourish, and strives to develop the best possible version.
Formulating it this way maybe describes why even the most rational minds in development should hold a second
to think about the code they are designing, implementing, or requesting.
This post is focused on one question: From an ethical point of view - Is your code good?
</div>

<h2 id="why-ethical-values-matter-in-development" class="relative group">Why ethical values matter in Development? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#why-ethical-values-matter-in-development" aria-label="Anchor">#</a></span></h2><p>The trend towards ethical development is present in many ways. Social Networks may implement algorithms to reinforce
hateful but wide spreading content; smart home gadgets may contain sensors and microphones and therefore provide
more features and more engagement for exploiting; Governmental software is developed around the small border between
functionality and respect for their user privacy. Not in every company or context does society benefit from caring about
ethical issues; bitching about the cookie policy of a start-up might not make the world a better place;
but many developers, product owners, managers do not realise the ethical impacts of their decisions.</p>
<h3 id="where-to-learn-ieee" class="relative group">Where to learn: IEEE <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#where-to-learn-ieee" aria-label="Anchor">#</a></span></h3><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Many clever people are thinking about the topic, my first touching point was IEEE, and it nudged me to wander down in
the
IEEE forest of interesting thoughts of engaged people all around the topic of ethics in technology. The fact that I did
that, does not mean it&rsquo;s the only source of truth, neither that it is best, nor that you should do the same - It was/is
my path, and I want to share my experience with that, and maybe inspire you to click on one of the links at stroll
yourself through the forest of information about ethics in IT.</span>
</div>

<p>






  
  
<figure><img src="/images/2022-08-thinker.png" alt="Corgi thinking about ethical questions?" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="contemplating-ethical-stumbling-stones" class="relative group">Contemplating ethical stumbling stones <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#contemplating-ethical-stumbling-stones" aria-label="Anchor">#</a></span></h2><blockquote>
<p>IEEE’s CertifAIEd program objective is to enable, enhance and reinforce trust through AI Ethics specifications,
training, criteria, and certification. It stems from the rationale that an entity benefits from an independent
ethical evaluation and certification of its AIS. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
</blockquote>
<p>Although I have worked with AI, in my day-to-day business it&rsquo;s a tool I use, not the focus of my development business.
Anyway, the information IEEE offered was enlightening beyond the topic of machine learning. Being more aware
of the different areas in which I as a developer can encounter ethical issues while designing, implementing, or
maintaining a feature is a great help in avoiding ethical issues even before the first function call is written.</p>
<p>The following sections are the information I remember from the training. &ldquo;Remember&rdquo; like a not-complete list of hints,
metaphors, information, etc, that I found interesting enough to keep in mind. The CertifAIEd Program has (at time of
this post) 4 areas on interest: Transparency, Accountability, Algorithmic Bias, and Ethical Privacy.</p>
<h3 id="transparency" class="relative group">Transparency <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#transparency" aria-label="Anchor">#</a></span></h3><p>Metaphor: In case of questions about a past flight (e.g. in case of a successful emergency landing, or a crash) there
are two black boxes on an airplane. The first one, the flight data recorder (FDR) records multiple technical parameters
about the state of the airplane and its surrounding. The second, the cockpit voice recorder (CVR) records the
conversation of the pilots in the cockpit. This metaphor can guide the two aspects of transparency.</p>
<p>The first is technical transparency. What data is recorded, how does it flow through the systems, and which decisions
are made by inside code? Especially in the context of anything that is labeled AI - to what degree does the developer
understand their algorithm? Is it clear to the developer how the system will be used by the end user? Who are the users,
is authentication tracked, activities logged, and errors handled? Mentioning the user, does the end user know how the
system works, are they aware of any automated systems that make decisions in the background, do they understand or at
least suspect how the algorithm decided on the displayed content, do they realise how the data is evaluated, stored, or
sold?</p>
<p>Secondly, the cockpit voice recorder: How did management make their decisions? Which business assumptions were made,
and how have they been communicated to development or sales? Does the company have an ethical set of values, and do
structures exist to enforce these? Those questions are not always easy, sometimes impossible to publish. But if possible
a company may benefit from providing information about their values.</p>
<h3 id="accountability" class="relative group">Accountability <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#accountability" aria-label="Anchor">#</a></span></h3><p>Rubber stamps were used since the 18th century to mark documents as &ldquo;seen and approved&rdquo; by a given person following
some bureaucratic process. From that origin, the metaphor of rubber-stamping describes the tendency to uncritically
approve a given statement.</p>
<p>This tendency is one red flag when looking for accountability in a company. Enough bureaucracy can bury any liability -
some person approved this, some person for sure took responsibility for this; or vice versa the tendency to approve
something uncritically as part of the process without questioning them to be approved.</p>
<p>Being accountable does not end with a signature below a document to mark it as seen. An accountable person should be
able to display enough understanding of the subsystem in question to answer questions reliably. There is no black box
argument excuse to this - even if the subsystem in question is a black box for the accountable, answerability is not
optional. Additionally, this is not restricted to technical subsystems, but includes decisions and policies.</p>
<p>My two cents as a developer on this: As a developer, I often find myself in the position in which a manager might be
accountable for the feature I am asked to implement, while at the same time I might be capable of foreseeing ethical
issues he can&rsquo;t in context of the requested way of implementation.
This includes unethical features, like tracking sensible data, as well as unethical ways of implementation, like keeping
deleted user data in the backup files. I find myself responsible for at least questioning such requests, double-checking
if the ethical problems have been accounted for, and sometimes refusing to fulfil the request.
Not only, but especially as a developer, my decisions can have an impact on feature development, my workforce is one of
the most powerful resources I have to influence the future. Ethical value standards should come top to bottom, but I
encourage everybody to not underestimate the power of a single person questioning management requests.</p>
<h3 id="algorithmic-bias" class="relative group">Algorithmic Bias <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#algorithmic-bias" aria-label="Anchor">#</a></span></h3><p>Computers are rational and free of human bias. That&rsquo;s what a lot of people, developers often up front, assume. People
tend to forget that every line of code is written by a human, prone to human bias. The view of computers as rational,
correctly calculating machines is especially dangerous if their algorithms contain repeatable errors, making decisions
about human beings resulting in unfair outcomes for one subgroup of users - all covered in the disguise of rational
calculations <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<p>The classical examples for these situations are Human Resources applicant classification algorithms fed with the biased
data of preferably male employees which will transfer these biases into the hiring processes;
or an image recognition algorithm that will not be able to identify people of colour with the same accuracy if it was
fed the predominantly white images.
Of course, examples that are worth mentioning, and far from being solved; but examples a lot of developers already have
in mind. Still, there are many ways a product or service may show bias in situations in which developers are less aware
of possible problems.</p>
<p>One of these situations is neglected product context. A product or service may work without bias in on situation or
target group, but cause unfair outcomes when used under different circumstances.
But bias can be minimal and sublet, like online forms which do assume that a family name has a minimum length or that
there is exactly one (or exactly two) family names, forms which assume a postal code is numeric, forms which assume
certain letters do not exist in names or email addresses - in general, assumptions developers made often without
realising that there are edge-cases in which their desiccation impedes the usage of their web site to some users.</p>
<h3 id="ethical-privacy" class="relative group">Ethical Privacy <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#ethical-privacy" aria-label="Anchor">#</a></span></h3><p>Have you accepted the cookies for this page? No, you did not. There are no cookies, no trackers, no information I
collect about you, dear reader.
The main reason for this is not that I am not interested in who is visiting this page, instead, I avoid the fuss of
respecting your data ethically and legally.
While this blog does not, a lot of IT business models are based on the collection, classification, and interpretation of
user data. This is nothing bad, it just is the usage of the technology we have often enough with good intentions to
offer services people are consuming.</p>
<p>Collected data becomes an object of ethical considerations if it is misused, its usage is mis-communicated, or if the
data is available to third parties due to the carelessness of the company.</p>
<p>Respecting the person and their digital representation comes with a separation of the data that a company may be able to
collect, data a company needs to collect to provide a service, and data that might be useful for the company but is not
part of its current daily business.
This leads to the question if the company has communicated which data is collected for which reason. Thanks to
over-complicated laws, Terms and Conditions offer a length which feels similar to the modern infinity scroll of
Instagram. What part of the Terms and Conditions do you read? Do you scroll through the settings of any installed
application to switch out any data sharing options? Do you share the crash report if a software on your computer
experienced an unexpected event?</p>
<p>A company may offer the user options to decide which data they want to share, and a company may decide on how clear,
understandable, and accessible these options are. Same holds for information on how the data is used. It&rsquo;s the company&rsquo;s
decision how to present this information to the user.</p>
<h2 id="so-what-now" class="relative group">So what now? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#so-what-now" aria-label="Anchor">#</a></span></h2><p>Takeaway so far: at least I was surprised how often I touch ethical problems without thinking about them when writing
those colourful letters on dark background. But what to do with that feeling of newfound awareness?
The first thing that changed for me is positively or negatively recognize when software, websites, or IT companies
cared about ethical values.
Secondly, I am in a position in which I might be able to change a feature of a software product during its design and
development. I am not in the position to certify or consult a company - pointing to the accountability section - but I
do hold my ground to call out ethical concerns as I encounter them in new features. This is no framework, nor guidelines
but barely personal recommendations.</p>
<h3 id="introduce-the-new-stakeholder" class="relative group">Introduce the new stakeholder <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#introduce-the-new-stakeholder" aria-label="Anchor">#</a></span></h3><p>In every Feature discussion, there are more stakeholders than visible at first glance. There is the capitalistic
stakeholder asking for short-term revenue, the C-Level asking for long time revenue, the marketing people who want the
feature to fit on an online ad, the motivated tech person who is looking forward to trying out that new technology,
the concerned senior dev who wants their code base clean and tidy. One physical person may function as multiple
stakeholders. With the ethical topics in mind, having one person in such meetings who will play the role of the
concerned activist, or the role of a not digital native who has a hard time understanding how their data will be used,
or the role of a critical thinker who wants to know how the company makes a decision, or the role of a person of a
minority group. A feature is always viewed from a different point of view, take your time to add additional views to
be aware of ethical problems <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<h3 id="know-your-values" class="relative group">Know your values <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#know-your-values" aria-label="Anchor">#</a></span></h3><p>A finance company might value privacy, a company that offers CO2 tracking might value sustainability. Not every company
has the same values, and objectivity of values is a discussion of its own. So take some time to talk about the values
of your company. Talk about the ideas and values of the management and C-Level, about the deal-breaker for developers,
and the ethical standards that you agree upon for your business. Business values do not need to be the same as private
values, there are valid reasons why you as person does not agree with the values of a social network, but as a (
self-chosen) employee, your values should at least align with the company values.</p>
<h3 id="talk-about-and-document-the-company-values" class="relative group">Talk about and document the company values <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#talk-about-and-document-the-company-values" aria-label="Anchor">#</a></span></h3><p>Make it a habit to talk about the values, to document the problems you found in a feature. Make a comment above a code
you wrote for an ethical reason or about the danger you expect if that line might be changed. Encourage the discussion
and share blog posts that point out wrong assumptions in programming or UX <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. Provide a space for such
discussions and maybe even support that people educate themselves on such topics.</p>
<h3 id="accept-the-possibility-to-stop-a-feature-if-it-does-not-fit-your-values" class="relative group">Accept the possibility to stop a feature if it does not fit your values <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#accept-the-possibility-to-stop-a-feature-if-it-does-not-fit-your-values" aria-label="Anchor">#</a></span></h3><p>All of the above does not hold value if you are not able to stop the development of a feature if you can not align it
with the decided company values. Even if some CEO thinks it&rsquo;s a great benefit to misuse user data, or accounting would
go for profit optimisation by selling user data, or some developer would like to keep that cool backdoor they put
in the code for whatever reason.</p>
<p>If you want to check your product or service for ethical problems, but you are not convinced to change something if you
find some; rethink your incentives, because they might be more marketing focused than actually ethical doubts.</p>
<h2 id="conclusion" class="relative group">Conclusion <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#</a></span></h2><p>This post is aims to inspire, to sensibilize for stumbling stones that might have been overlooked easily. I
want to encourage the reader to think about values when coding. Because even though it feels like a developer is focused
on the technical problems they solve daily, there are social and ethical problems they should not ignore.</p>
<p>Please feel free to, if you feel curious, have a look the IEEE Standards. The people behind the standards are motivated,
super open for critique, and offer a great set of courses I can only recommend.</p>
<p>Happy and respectful coding :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Check our <a href="https://engagestandards.ieee.org/ieeecertifaied.html" target="_blank" rel="noreferrer">the CertifAIEd programm by IEEE</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Algorithm Watch has a <a href="https://algorithmwatch.org/en/autocheck-guidebook-discrimination/" target="_blank" rel="noreferrer">great Article</a>
with multiple case studies on this topic, and also offers a checklist to reduce the biases in software.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Ethically Aligned Design, including the book more information about this
process <a href="https://ethicsinaction.ieee.org/" target="_blank" rel="noreferrer">here</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>For your next discussion about validation rules on forms
read <a href="https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/" target="_blank" rel="noreferrer">Falsehoods Programmers Believe About Names</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="ethical-development" label="Ethical Development"/><category scheme="taxonomy:Tags" term="developer-life" label="Developer Life"/></entry><entry><title type="html">About Actions, Jobs, Repositories, Events</title><link href="https://philodev.one/posts/2022-07-action-and-other-patterns/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><link href="https://philodev.one/posts/2022-06-customer-search/?utm_source=atom_feed" rel="related" type="text/html" title="Technical Job Interview questions 2022"/><link href="https://philodev.one/posts/2022-05-relationships/?utm_source=atom_feed" rel="related" type="text/html" title="Useful and Useless Relationship Definitions"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><id>https://philodev.one/posts/2022-07-action-and-other-patterns/</id><published>2022-07-31T14:20:44+02:00</published><updated>2022-07-31T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Simple REST APIs are nice. But once a Controller needs to perform more than the basic update, create, and index methods; Once a Controller maybe ought to handle multiple little tasks, tasks that may be used in various places in the code base, there is a need for a Software Pattern. Something that fulfills the desire to have one class or method do only one thing - Single Responsibility. This Post compares Repositories, Services, Actions, Jobs, and Events (and gives inspiration for piptes) - not to find the best for all use cases, but to formulate some words on the question when the different patterns offer advantages over the others.</blockquote><div class="lead !mb-9 text-xl">
  Simple REST APIs are nice. But once a Controller needs to perform more than just the basic update, create,
and index methods; Once a Controller maybe ought to handle multiple little tasks, tasks that may be used in various
places in the code base, there is a need for a Software Pattern. Something that fulfills the desire to have one
class or method do only one thing - Single Responsibility. This Post compares Repositories, Services, Actions, Jobs, and
Events - not to find the best for all use cases, but to formulate some words on the question when the different patterns
offer advantages over the others.
</div>

<h2 id="writing-a-controller-that-adds-a-new-user-as-player-to-an-existing-game" class="relative group">Writing a Controller that adds a new user as player to an existing game <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#writing-a-controller-that-adds-a-new-user-as-player-to-an-existing-game" aria-label="Anchor">#</a></span></h2><p>Taking my favorite example, <a href="https://round-robin.philodev.one/" target="_blank" rel="noreferrer">Round Robin</a> - a little round-based gaming platform to
register and play games with friends. A new user just registered and already has a game token, so they can just join an
existing game. This means, within the request to (1) create that user, also a (2) player needs to be created, and (3)
that player must be configured e.g. become a member of a color-coded team.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Of course there are reasons to do some things using precisely one pattern (like sending an email using an event, or
updating using a repository). This blog is a collection to compare some patterns that want to move code from
the controller to different files. The example is used for visualisation, not because it is so hard to decide which
pattenr to use in this case</span>
</div>

<p>






  
  
<figure><img src="/images/2022-07-orchestrate.png" alt="Orchestrate - but how?" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h3 id="just-a-controller" class="relative group">Just a Controller <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#just-a-controller" aria-label="Anchor">#</a></span></h3><p>For simplicity, let&rsquo;s assume all security validations have been made in the request by magic. The reason for this post
is that multiple things are ought to happen in this controller, some of those things are also happening in different
parts of the application, and I need to find a pattern to organize my code.</p>
<p>So using nothing but the Model View Controller pattern, I end up with this code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">(</span><span class="nx">Request</span> <span class="nv">$request</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// step 1: create the user
</span></span></span><span class="line"><span class="cl">        <span class="nv">$user</span> <span class="o">=</span> <span class="nx">User</span><span class="o">::</span><span class="na">create</span><span class="p">(</span><span class="nv">$request</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Auth</span><span class="o">::</span><span class="na">login</span><span class="p">(</span><span class="nv">$user</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;game.index&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">         <span class="c1">// step 2: Create the player
</span></span></span><span class="line"><span class="cl">        <span class="nv">$game</span> <span class="o">=</span> <span class="nx">Game</span><span class="o">::</span><span class="na">query</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">,</span> <span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">firstOrFail</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">        <span class="nv">$player</span> <span class="o">=</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">players</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">create</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;uuid&#39;</span>    <span class="o">=&gt;</span> <span class="nx">Str</span><span class="o">::</span><span class="na">uuid</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;user_id&#39;</span> <span class="o">=&gt;</span> <span class="nx">Auth</span><span class="o">::</span><span class="na">id</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="p">]);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">         <span class="c1">// step 3: Prepare the Player for the game
</span></span></span><span class="line"><span class="cl">        <span class="nv">$redPlayers</span> <span class="o">=</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">players</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;color&#39;</span><span class="p">,</span> <span class="s1">&#39;red&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">count</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$bluePlayers</span> <span class="o">=</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">players</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;color&#39;</span><span class="p">,</span> <span class="s1">&#39;blue&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">count</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$player</span><span class="o">-&gt;</span><span class="na">color</span> <span class="o">=</span>   <span class="nv">$redPlayers</span> <span class="o">&gt;</span> <span class="nv">$bluePlayers</span> <span class="o">?</span> <span class="s1">&#39;blue&#39;</span> <span class="o">:</span> <span class="s1">&#39;red;&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$player</span><span class="o">-&gt;</span><span class="na">save</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;GamePage&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;game&#39;</span> <span class="o">=&gt;</span> <span class="nv">$game</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Not very reusable&hellip; so let&rsquo;s have a look at the Laravel Docs and common Patterns to improve the situation.</p>
<h3 id="repository-pattern" class="relative group">Repository Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#repository-pattern" aria-label="Anchor">#</a></span></h3><p>If there was a layer between the Database and the Controller, something that handles the creation of models - wouldn&rsquo;t
that be nice? Using Dependency Injection of Laravel, you could follow such a pattern:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">(</span><span class="nx">Request</span> <span class="nv">$request</span><span class="p">,</span> <span class="nx">UserRepository</span> <span class="nv">$userRepository</span><span class="p">,</span> <span class="nx">PlayerRepository</span> <span class="nv">$playerRepository</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// step 1: create the user
</span></span></span><span class="line"><span class="cl">        <span class="nv">$user</span> <span class="o">=</span> <span class="nv">$userRepository</span><span class="o">-&gt;</span><span class="na">createUser</span><span class="p">(</span><span class="nv">$request</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;game.index&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">         <span class="c1">// step 2: Create the player
</span></span></span><span class="line"><span class="cl">         <span class="nv">$player</span> <span class="o">=</span> <span class="nv">$playerRepository</span><span class="o">-&gt;</span><span class="na">createPlayer</span><span class="p">([</span><span class="s1">&#39;token&#39;</span> <span class="o">=&gt;</span> <span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">)]);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">         <span class="c1">// step 3: Prepare the Player for the game
</span></span></span><span class="line"><span class="cl">        <span class="nv">$redPlayers</span> <span class="o">=</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">players</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;color&#39;</span><span class="p">,</span> <span class="s1">&#39;red&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">count</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$bluePlayers</span> <span class="o">=</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">players</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;color&#39;</span><span class="p">,</span> <span class="s1">&#39;blue&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">count</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$player</span><span class="o">-&gt;</span><span class="na">color</span> <span class="o">=</span>   <span class="nv">$redPlayers</span> <span class="o">&gt;</span> <span class="nv">$bluePlayers</span> <span class="o">?</span> <span class="s1">&#39;blue&#39;</span> <span class="o">:</span> <span class="s1">&#39;red;&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$player</span><span class="o">-&gt;</span><span class="na">save</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;GamePage&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;game&#39;</span> <span class="o">=&gt;</span> <span class="nv">$player</span><span class="o">-&gt;</span><span class="na">game</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The great thing about a Repository is, that it is the single point in the code base, that creates, updates, or queries
Models. There are a lot of use cases in which this can be super helpful - e.g. if you want to validate your Models
before updating or authorizing queries. The separation of the writing and reading part of a Repository can be achieved
by
using <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. The Repository does a great deal for separation of concerns and single responsibility (
your software pattern bingo game should have caused one win by now).</p>
<p>But it can&rsquo;t solve all problems, as you can see the third step is not the job of the Repository. Arguably it could be
implemented there, as one can argue that the correct color of a player is somewhat a validation topic, but treating a
Repository like that will make it the &ldquo;core service&rdquo; of the application soon. It is not the job of the Repository to
care
about everything that occurs with the creation of a Model, it just cares about the creation of the Model.</p>
<h3 id="service-pattern" class="relative group">Service Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#service-pattern" aria-label="Anchor">#</a></span></h3><p>If there was a place to just hold all the methods that might be used multiple times - wouldn&rsquo;t that be nice? Mind that
this is not the Service Provider that Laravel mentions, at least I could not come up with a reason why a Service like
that would need to be registered or requires to be a singleton.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">(</span><span class="nx">Request</span> <span class="nv">$request</span><span class="p">,</span> <span class="nx">UserService</span> <span class="nv">$userService</span><span class="p">,</span> <span class="nx">PlayerService</span> <span class="nv">$playerService</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// step 1: create the user
</span></span></span><span class="line"><span class="cl">        <span class="nv">$user</span> <span class="o">=</span> <span class="nv">$userService</span><span class="o">-&gt;</span><span class="na">register</span><span class="p">(</span><span class="nv">$request</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;game.index&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">         <span class="c1">// step 2: Create the player
</span></span></span><span class="line"><span class="cl">         <span class="nv">$player</span> <span class="o">=</span> <span class="nv">$playerService</span><span class="o">-&gt;</span><span class="na">createPlayer</span><span class="p">(</span><span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">         <span class="c1">// step 3: Prepare the Player for the game
</span></span></span><span class="line"><span class="cl">         <span class="nv">$player</span> <span class="o">=</span> <span class="nv">$playerService</span><span class="o">-&gt;</span><span class="na">initatePlayer</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;GamePage&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;game&#39;</span> <span class="o">=&gt;</span> <span class="nv">$player</span><span class="o">-&gt;</span><span class="na">game</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Feel the freedom of doing more than just creating and updating, listen to the single Responsibility Pattern softly
crying in the corner, and watch your services grow to reach the 4-digit line numbers! Services are a great way to
encapsulate logic around one component. In my experience, it is just hard to set boundaries, and in a larger application
(or one that can have the potential to grow) I would not use this pattern and go for something that gives the next
developer
who might continue on my code a stricter line on where to find and add code.</p>
<p>One additional note: there is no limit on patterns, Services and Repositories might work together quite well
and <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<h3 id="action-pattern" class="relative group">Action Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#action-pattern" aria-label="Anchor">#</a></span></h3><p>If there was just one class, that does exactly the one thing, and may be reused in Controllers, Jobs, Commands,
whatever - wouldn&rsquo;t that be nice?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Request</span> <span class="nv">$request</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">        <span class="nx">UserCreateAction</span> <span class="nv">$userCreateAction</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">        <span class="nx">PlayerCreateAction</span> <span class="nv">$playerCreateAction</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">        <span class="nx">PlayerInitialisationAction</span> <span class="nv">$playerInitialisationAction</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// step 1: create the user
</span></span></span><span class="line"><span class="cl">        <span class="nv">$userCreateAction</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">(</span><span class="nv">$request</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;game.index&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">         <span class="c1">// step 2: Create the player
</span></span></span><span class="line"><span class="cl">         <span class="nv">$playerCreateAction</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">(</span><span class="nx">token</span><span class="o">:</span> <span class="nv">$request</span><span class="o">-&gt;</span><span class="na">input</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">         <span class="c1">// step 3: Prepare the Player for the game
</span></span></span><span class="line"><span class="cl">         <span class="nv">$playerInitialisationAction</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// imagine there is a custom Auth Facade extending the Auth Facade ...
</span></span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;GamePage&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;game&#39;</span> <span class="o">=&gt;</span> <span class="nx">Auth</span><span class="o">::</span><span class="na">player</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">game</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>One Action, one class per action, one concern per class - everything is separated and clean. Using this pattern can lead
to very clean actions, that can be inside of Controllers as well as Jobs as well as Nova Actions. Every bit of the
Business Logic broken down into simple pieces. And the single Actions are just so easy to test - some unit tests per
Action will increase the Test coverage fast and if all the little gears are working half the bugs are avoided. And then
you can just avoid using Events at all, because using the right packages will enable your actions to run on
queue <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<p>This pattern is the reason for this post. I am working with this pattern for some months now and have to admit, it is
neat. Combined with some naming convention (spare some fuzz, suffix your actions with &lsquo;Action&rsquo; from the very
beginning&hellip; and while you are at it, just suffix everything that is not a Model).</p>
<p>I still have my concerns: While the Project grows, so first and for most your <code>/actions</code> folder grows, there is one
feature of Actions that I see as the biggest pro and con. Compared to Events, which are created, put on queue, and in
some ballet of Laravel Magic listened to at some point; Actions stay controllable. The Controller, or what ever point of
execution is calling the Actions like a conductor is flicking their want to initiate a calculated, controlled set of
actions. In a lot of use cases, this is a great tool of control - in others the freedom of hooking in between and after
any of those actions can be integrating, sometimes even necessary. Following the Action Pattern, such add-a-hook changes
can be frustrating to implement as each conductor has to follow the new life cycle, instead of having one place in which
such a life cycle event may be added.</p>
<h3 id="using-jobs-for-action-pattern" class="relative group">Using Jobs for Action Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-jobs-for-action-pattern" aria-label="Anchor">#</a></span></h3><p>This little question bugged me after discussing the topic with some colleagues. Why use Actions, if they could be Jobs?
Why not use the Framework that we Artisans admire, and just take the Jobs, may or may not make it Dispatchable or /
and Queueable and just use those as queueable actions without any package dependency? All the special features of Jobs,
like rerunning on error, or unique running could come in super handy.</p>
<p>It is like taking a sledgehammer to crack a nut, but starting a Job should not be that much of a time spent,
especially if it is not Queueable anyway. One drawback for sure is the missing option to return something from your
action, which I would argue is a bit of code smell anyway.</p>
<p>Honest answer to this section: No idea, would love to try, if you have a comment on that - please email me, I would
appreciate the discussion!</p>
<h3 id="event---listener-pattern" class="relative group">Event - Listener Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#event---listener-pattern" aria-label="Anchor">#</a></span></h3><p>If we could just state what happened in the Controller, everything that wants to react to the thing that happened can
do so - wouldn&rsquo;t that be nice?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">(</span><span class="nx">Request</span> <span class="nv">$request</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// step 1: create the user
</span></span></span><span class="line"><span class="cl">        <span class="nv">$user</span> <span class="o">=</span> <span class="nx">User</span><span class="o">::</span><span class="na">create</span><span class="p">(</span><span class="nv">$request</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Auth</span><span class="o">::</span><span class="na">login</span><span class="p">(</span><span class="nv">$user</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="nx">UserCreated</span><span class="o">::</span><span class="na">dispatch</span><span class="p">(</span><span class="nv">$user</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;GamePage&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;game&#39;</span> <span class="o">=&gt;</span> <span class="nx">Auth</span><span class="o">::</span><span class="na">player</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">game</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// In the Event Service Provider
</span></span></span><span class="line"><span class="cl"><span class="k">protected</span> <span class="nv">$listen</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="nx">UserCreated</span><span class="o">::</span><span class="na">class</span> <span class="o">=&gt;</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// step 2: Create the player
</span></span></span><span class="line"><span class="cl">        <span class="nx">CreatePlayerIfTokenIsPresent</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">PlayerCreated</span><span class="o">::</span><span class="na">class</span> <span class="o">=&gt;</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// step 3: Prepare the Player for the game
</span></span></span><span class="line"><span class="cl">        <span class="nx">InitiatePlayer</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span></code></pre></div><p>So little code&hellip; so clean, almost no newbie will know where to find everything, but a Laravel affine Developer might
look at the Service Provider (that might be one of many Service Providers, e.g. one for each Domain), and see how Data
might flow through the Application in a barely controllable way once the event has been dispatched.</p>
<p>This is the pattern of choice if your tasks should run on Queue, but any listener that misses
the <code>implements ShouldQueue</code> (which can be expressed by an empty Interface <code>Should RunImmediately</code>) is not queued at
all, but will be executed in the old PHP line by line fashion - like an Action. So Events come with most of the Benefits
of Actions, Testability, Single Responsibility; but introduce their own set of drawbacks. They are way harder to parse
in mind, can hard to follow through multiple layers of events, and are even harder to test in combination than Actions.</p>
<p>If you want to offer some frustrating learning experiences for Developers new to the code, Silent <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>
are
using the same pattern and will listen for Model Events that are thrown automatically (this is the reason there is
a <code>$user-&gt;saveQuietly()</code> method).</p>
<h3 id="pipeline-pattern" class="relative group">Pipeline Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#pipeline-pattern" aria-label="Anchor">#</a></span></h3><p>If the steps that need to be performed are just running through a pre-defined set of classes - wouldn&rsquo;t that be nice?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">(</span><span class="nx">Request</span> <span class="nv">$request</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>        
</span></span><span class="line"><span class="cl">        <span class="nv">$player</span> <span class="o">=</span> <span class="nx">app</span><span class="p">(</span><span class="nx">Pipeline</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">send</span><span class="p">(</span><span class="nv">$request</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">through</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// step 1: create the user
</span></span></span><span class="line"><span class="cl">                <span class="nx">\App\Pipes\CreateUser</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// step 2: Create the player
</span></span></span><span class="line"><span class="cl">                <span class="nx">\App\Pipes\CreatePlayer</span><span class="o">::</span><span class="na">class</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// step 3: Prepare the Player for the game
</span></span></span><span class="line"><span class="cl">                <span class="nx">\App\Pipes\InitatePlayer</span><span class="o">::</span><span class="na">class</span>
</span></span><span class="line"><span class="cl">            <span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">thenReturn</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nv">$player</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;game.index&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">&#39;GamePage&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;game&#39;</span> <span class="o">=&gt;</span> <span class="nv">$player</span><span class="o">-&gt;</span><span class="na">game</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This would be where I would state my experiences, advantages when designing, drawbacks on production - If I had any
experience. Looking forward to someday building a pipeline pattern. If I ever do, I might come back here to update the
post ;) However, I can give you some <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> on where to start understanding the pattern for yourself.</p>
<h2 id="so-what-now" class="relative group">So what now? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#so-what-now" aria-label="Anchor">#</a></span></h2><p>The answer to the question &ldquo;What pattern should I use?&rdquo; is the same as for so many other questions in life: &ldquo;it
depends&hellip;&rdquo;. Every Pattern offers drawbacks, and every pattern has use cases in which it shines with all its advantages.
In every use case there will be developers arguing there was a better pattern anyway, and some will see the bright
side of the architect&rsquo;s decision. For some over-the-thump-rules:</p>
<ul>
<li>One single point in the app that stores Models? Repository Pattern</li>
<li>Only need a bunch of methods to be reusable? Service Pattern</li>
<li>A lot of reusable Code snippets that work very reliable? Action Pattern</li>
<li>Something that may happen on the queue? Event Listener Pattern</li>
<li>Wanna build something creative and tell me how it went? Pipeline Pattern</li>
<li>Multiple things of the above? Use multiple patterns</li>
</ul>
<p>If you have more Patterns, or disagree with my opinion, feel free to send me some feedback. I am not the only one how
had this idea, so check out what other people think too <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<p>Happy Coding Everyone :)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.blog.philodev.one/posts/2022-05-custom-query-builder-pattern/" target="_blank" rel="noreferrer">This Post</a> offers
some examples and sources&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://stackoverflow.com/questions/57363816/is-it-okey-to-call-events-from-repository-pattern-in-laravel" target="_blank" rel="noreferrer">Here</a>
is an example from Stack Overflow in which this is elaborated&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://lorisleiva.com/why-i-wrote-laravel-actions" target="_blank" rel="noreferrer">Here</a> is one of the many Action favorable Posts. I
learned the pattern using the book &ldquo;Laravel beyond CRUD&rdquo;.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://laravel.com/docs/9.x/eloquent#observers" target="_blank" rel="noreferrer">Laravel Docs</a> for more information&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://dev.to/abrardev99/pipeline-pattern-in-laravel-278p" target="_blank" rel="noreferrer">A Tutorial</a> to understand the
basics, <a href="https://laravel.com/api/8.x/Illuminate/Pipeline/Pipeline.html" target="_blank" rel="noreferrer">the Pipeline Docs</a>, and
an <a href="https://www.blog.philodev.one/posts/2022-06-customer-search/#how-does-a-request-live-through-laravel" target="_blank" rel="noreferrer">example of the Pipeline Pattern</a>
in Laravels Middleware Handling.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://laravel-news.com/controller-refactor" target="_blank" rel="noreferrer">This blog</a> did similar things to refactor a controller
in multiple ways.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/><category scheme="taxonomy:Tags" term="queue" label="Queue"/></entry><entry><title type="html">Technical Job Interview questions 2022</title><link href="https://philodev.one/posts/2022-06-customer-search/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Manager and Driver Pattern - pattern, implementation, and usage"/><link href="https://philodev.one/posts/2022-05-relationships/?utm_source=atom_feed" rel="related" type="text/html" title="Useful and Useless Relationship Definitions"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><id>https://philodev.one/posts/2022-06-customer-search/</id><published>2022-06-02T14:20:44+02:00</published><updated>2022-06-02T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Looking for a customer is the same process compared to looking for a job. I use the usual platforms to find companies that are looking for my tech stack and send a spontaneous application, maybe I get invited for an interview, maybe a technical interview with dev-related questions, or sometimes a coding challenge. In this post I want to look back on the technical questions I got asked.</blockquote><div class="lead !mb-9 text-xl">
  Looking for a customer is the same process compared to looking for a job. I use the usual platforms to find
companies that are looking for my tech stack and send a spontaneous application, maybe I get invited for an interview,
maybe a technical interview with dev-related questions, or sometimes a coding challenge. In this post I want to look
back on the technical questions I got asked.
</div>

<h2 id="interview-questions-i-remembered" class="relative group">Interview Questions I remembered <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#interview-questions-i-remembered" aria-label="Anchor">#</a></span></h2><p>The kind of questions I want to write about are not the &ldquo;describe yourself in a three minutes&rdquo; or &ldquo;explain your
experience&rdquo; questions. I want to rethink some technical interview questions I was asked and could or could not answer at
that point in time.</p>
<p>






  
  
<figure><img src="/images/2022-06-code-for-money.png" alt="Would code for money?" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="laravel-questions" class="relative group">Laravel Questions <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#laravel-questions" aria-label="Anchor">#</a></span></h2><h3 id="what-laravel-feature-do-you-love-about-laravel-9" class="relative group">What Laravel Feature do you love about Laravel 9? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#what-laravel-feature-do-you-love-about-laravel-9" aria-label="Anchor">#</a></span></h3><p>That question should have been easy. One of the big features are the new accessors and mutators <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. I kinda
dislike getters and setters anyway, so I don&rsquo;t use them. The next big feature is the usage of Enums <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, which I
don&rsquo;t use in practice because I can&rsquo;t use them as array keys, which might change in the future, but until that is fixed
I get quite frustrated about this little drawback to honestly state it in an interview <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. Every other new
feature I found very small, and the only one I am looking forward to using is the <code>str()</code> helper function which replaces
the <code>Str::of()</code>.</p>
<h3 id="what-feature-do-you-miss-about-laravel" class="relative group">What Feature do you miss about Laravel? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#what-feature-do-you-miss-about-laravel" aria-label="Anchor">#</a></span></h3><p>I think Laravel uses too many provider / list files that are not easier or less magic than other implementations. The
auto-discovery of event listener <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> is one way to replace one provider with something easier; another
feature that would get rid of the route file would the Spring (Kotlin Framework) inspired Route binding using
Annotations / Attributes <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>.</p>
<p>In PHP Annotations are often used (at least by me) to type-hint methods and properties. For example, if I define a
relation in Laravel I type-hint the corresponding relation attribute call, now I have typed <code>$game-&gt;rounds()</code> which
returns a query builder, and <code>$game-&gt;rounds</code> which returns the collection (<code>$game-&gt;rounds()-&gt;get()</code>).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @property \Illuminate\Support\Collection rounds
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @see \App\Models\Game::rounds()
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">rounds</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasMany</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasMany</span><span class="p">(</span><span class="nx">Round</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><p>But since PHP 8, Attributes are a new feature. And they are offering quite some
opportunities <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>. Besides the inconvenient naming, I like the idea and can&rsquo;t wait for
Attributes to replace the route file <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>. (For anyone who misses the route file for an overall overview
has never seen a big route file and does not know the <code>php artisan route:list</code> command)</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Spatie\RouteAttributes\Attributes\Get</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyController</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">#[Get(&#39;my-route&#39;)]
</span></span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">myMethod</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="what-standard-changes-or-libraries-do-you-apply-to-every-laravel-project" class="relative group">What standard changes or libraries do you apply to every Laravel Project? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#what-standard-changes-or-libraries-do-you-apply-to-every-laravel-project" aria-label="Anchor">#</a></span></h3><p>Most times I join existing projects, and my private projects are most times to test something out and therefore focused
on whatever I want to try out, and not follow my favorite Laravel styles. I will try to add something to this list, but
if you have an answer to this question, I am curious to read it.</p>
<p><strong>Clean up Laravel Sail and switch to Prostgres</strong> Not only because it saves some (for me usually not needed) Docker
space, but because Prostgres is the better choice for a relational Database (Enums, Money Types, in-json search, (and
the Docker Image works great for M1)).</p>
<p><strong>Write a UUID Traid</strong> Because writing <code>Str::uuid()</code> on every model creation is annoying. I use uuids to obscure the id
towards the client, but use the numeric id for relationships.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">trait</span> <span class="nx">HasUuid</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// fill uuid column
</span></span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">booted</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">static</span><span class="o">::</span><span class="na">created</span><span class="p">(</span><span class="nx">fn</span> <span class="p">(</span><span class="nv">$model</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$model</span><span class="o">-&gt;</span><span class="na">uuid</span> <span class="o">=</span> <span class="nx">Str</span><span class="o">::</span><span class="na">uuid</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// set route key name
</span></span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getRouteKeyName</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;uuid&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="how-does-a-request-live-through-laravel" class="relative group">How does a request live through Laravel? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#how-does-a-request-live-through-laravel" aria-label="Anchor">#</a></span></h3><p>One of my favorite questions - so I spend some time digging into the Laravel Code to find out.</p>
<p><strong>Starting the Application <code>public/index.php</code></strong></p>
<p>Laravel said <code>$kernel = $app-&gt;make(Kernel::class);</code> and there was a Kernel. Out of the box, this is
the <code>app/Http/Kernel.php</code>. In this step the Application (which holds path information, registers
Providers&hellip;) <sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> and Router (which is the class behind Route Facade) are instantiated.</p>
<p><strong>Handling <code>app/Http/Kernel.php</code></strong>
The Kernel extends <code>vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php</code>, and the important method call
is <code>handle()</code>. In the handle function the Kernel tries to send the Request through the Router, configure error handling,
configure logging, and detect the application environment. After this, and before the call returns the response
the <code>RequestHandled</code> Event is dispatched.</p>
<p><strong>Pipelines <code>app/Http/Kernel.php</code></strong></p>
<blockquote>
<p>The Pipeline Design Pattern is a software design pattern that provides ability to execute a sequence of operations
where data flows through a sequence of tasks or stages. <sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></p>
</blockquote>
<p>Every Middleware in Laravel is a pipe the request is sent though and a small task is performed on the Request. In this
step the HTTP Session, CSRF Token, Maintenance Prevention, and whatever Middleware you added in the Kernel.</p>
<p><strong>Dispatch to Router</strong> <code>vendor/laravel/framework/src/Illuminate/Routing/Router.php</code></p>
<p>The Router matches the Route from the Routes defined in the <code>routes/*</code> files (or other places if specified), dispatches
a <code>RouteMatched</code> Event, and again uses a Pipeline to run through the Route specific Middlewares which might include
Authentication or Authorisation.</p>
<p><strong>Run route, run</strong> <code>vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php</code></p>
<p>The Route matches its Controller or Callback, whatever convention was followed. Then the Controller Dispatcher tries to
satisfy the Method Dependencies <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup>, e.g. if you injected a Repository or FormRequest. For every
Parameter (besides the Model Bindings), a Reflection Class is created and after that an Instant of that class is made.
Some magic later the FormRequestServiceProvider kicks in (what here happens is Container Magic. Laravel Container are
something interesting, something that cause itchy bugs, and something I need to dedicate learning time to understand -
so this is magic for me at the current point in time).</p>
<p><strong>Validation</strong> <code>vendor/laravel/framework/src/Illuminate/Foundation/Providers/FormRequestServiceProvider.php</code></p>
<p>The Validation is triggered in the <code>vendor/laravel/framework/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php</code>
first checking the Authorization, followed by the Validation. If either is not specified, a default is created.</p>
<p><strong>Controller</strong></p>
<p>After the Dependency Injection of everything the Controller needs, the business code is executed, the Controller returns
e.g. a Resource.</p>
<p><strong>Wrapping into a Response</strong> <code>vendor/laravel/framework/src/Illuminate/Routing/Router.php</code></p>
<p>The Response is wrapped into a Response again in the Router - so from Code Perspective we are already on the way back.
From that point on there is not much more to write, the Response bubbles up the way it came and is returned to the
Kernel in which it is the (Symfony) Response to build Header and Body and send the information.</p>
<h2 id="php-questions" class="relative group">PHP Questions <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#php-questions" aria-label="Anchor">#</a></span></h2><h3 id="what-php-8-feature-do-you-like-the-most" class="relative group">What PHP 8 Feature do you like the most? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#what-php-8-feature-do-you-like-the-most" aria-label="Anchor">#</a></span></h3><p>A lot! Using Laravel examples:</p>
<p><strong>Constructor Properties</strong>, especially for Events: Method parameters can now include the declaration of public and
private properties.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PlayerJoined</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">public</span> <span class="nx">Game</span> <span class="nv">$game</span><span class="p">,</span> <span class="k">public</span> <span class="nx">Player</span> <span class="nv">$player</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>Union Types</strong> are great for Events as well</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UpdatePlayerInformation</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">handle</span><span class="p">(</span><span class="nx">PlayerJoined</span><span class="o">|</span><span class="nx">PlayerLeft</span> <span class="nv">$event</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>Nullsafe Operator</strong> is just neat. <code>$player-&gt;user ? $player-&gt;user-&gt;name : null</code> = <code>$player?-&gt;user-&gt;name</code></p>
<p><strong>Match Expression</strong> a bit better switch statement</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"> <span class="nv">$score</span> <span class="o">=</span> <span class="nx">match</span> <span class="p">(</span><span class="nv">$playerRole</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;WEREWOLF&#39;</span><span class="p">,</span><span class="s1">&#39;MINION&#39;</span>  <span class="o">=&gt;</span> <span class="nv">$werewolfScore</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;TANNER&#39;</span>             <span class="o">=&gt;</span> <span class="nv">$tannerScore</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;WATCHER&#39;</span>            <span class="o">=&gt;</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span>              <span class="o">=&gt;</span> <span class="nv">$villagerScore</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// match(true) is the same half shady, half awesome solution as switch(true)
</span></span></span><span class="line"><span class="cl"><span class="nv">$score</span> <span class="o">=</span> <span class="nx">match</span> <span class="p">(</span><span class="k">true</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$diffFromTarget</span> <span class="o">&lt;=</span> <span class="mi">5</span> <span class="o">=&gt;</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$diffFromTarget</span> <span class="o">&lt;=</span> <span class="mi">10</span> <span class="o">=&gt;</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$diffFromTarget</span> <span class="o">&lt;=</span> <span class="mi">20</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span> <span class="o">=&gt;</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="dev-tool-questions" class="relative group">Dev Tool Questions <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#dev-tool-questions" aria-label="Anchor">#</a></span></h2><h3 id="your-query-is-slow-how-to-tackle-the-task-to-improve-it" class="relative group">Your Query is slow, how to tackle the task to improve it? <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#your-query-is-slow-how-to-tackle-the-task-to-improve-it" aria-label="Anchor">#</a></span></h3><p>A basic, &ldquo;do you know your tools?&rdquo; question.</p>
<p><strong>What can cause long client-side waiting time?</strong> Client Issues, long boot time on Laravel side, long Query time, third
Party Api calls &hellip; The Flow Chart I would follow would like: Is it a Backend problem? Can I replicate the</p>
<p><strong>How can I debug performance?</strong> Simulate on Dev Environment (Seeders, Feature Tests), Postman debugging, Laravel Debug
bar <sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup>, Logging of benchmarks, Logging with third party analytics (e.g. Performance logging in Sentry)</p>
<p>Bonus hint if you don&rsquo;t use the Debugbar: Illuminate fires an <code>illuminate.query</code> Event that you can listen for (
preferably in a Service Provider).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">Event</span><span class="o">::</span><span class="na">listen</span><span class="p">(</span><span class="s1">&#39;illuminate.query&#39;</span><span class="p">,</span> <span class="nx">fn</span><span class="p">(</span><span class="nv">$query</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">var_dump</span><span class="p">(</span><span class="nv">$query</span><span class="p">));</span>
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Laravel 9 has
new <a href="https://laravel.com/docs/9.x/eloquent-mutators#accessors-and-mutators" target="_blank" rel="noreferrer">Accessors and Mutators</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Laravel 9 has new  <a href="https://laravel.com/docs/9.x/releases#enum-casting" target="_blank" rel="noreferrer">Enums</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>You can not use Enums as Object keys, discussed <a href="https://wiki.php.net/rfc/object_keys_in_arrays" target="_blank" rel="noreferrer">here</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Laravel offers great <a href="https://laravel.com/docs/9.x/events#event-discovery" target="_blank" rel="noreferrer">Auto Discovery of Events</a>
that I prefer over EventServiceProvider&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Spring offers a nice way for route binding using Annotations
-&gt; <a href="https://docs.spring.io/spring-integration/docs/2.0.0.RC1/reference/html/router.html" target="_blank" rel="noreferrer">Spring Docs</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Some more infos
on <a href="https://wiki.php.net/rfc/attributes_v2#why_not_extending_doc_comments" target="_blank" rel="noreferrer">Attributes at wiki.php</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Best in <a href="https://php.watch/articles/php-attributes" target="_blank" rel="noreferrer">Depth Article about Attributes</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>There is a <a href="https://github.com/spatie/laravel-route-attributes" target="_blank" rel="noreferrer">spatie package</a> which implements what
I want, I just hope it will find a way in the &ldquo;Laravel way of working&rdquo;&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>The Laravel Application corresponds to the <a href="https://laravel.com/docs/9.x/container" target="_blank" rel="noreferrer">Service Container</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Great Article about <a href="https://blog.toothpickapp.com/pipeline-in-laravel-2/" target="_blank" rel="noreferrer">Pipeline usage in Laravel</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Learn more about Dependency Injection in Controller in
the <a href="https://laravel.com/docs/9.x/controllers#constructor-injection" target="_blank" rel="noreferrer">Laravel Docs</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Awesome Feature every Laravel Developer should
use <a href="https://github.com/barryvdh/laravel-debugbar" target="_blank" rel="noreferrer">here on GitHub</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/><category scheme="taxonomy:Tags" term="developer-life" label="Developer Life"/></entry><entry><title type="html">Manager and Driver Pattern - pattern, implementation, and usage</title><link href="https://philodev.one/posts/2022-05-driver-manager-pattern/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><link href="https://philodev.one/posts/2022-05-relationships/?utm_source=atom_feed" rel="related" type="text/html" title="Useful and Useless Relationship Definitions"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><id>https://philodev.one/posts/2022-05-driver-manager-pattern/</id><published>2022-05-22T08:13:44+02:00</published><updated>2022-05-22T08:13:44+02:00</updated><content type="html"><![CDATA[<blockquote>Driver-based Development is a coding pattern that is common in the Laravel world and used in multiple instances in the framework. It&rsquo;s important to understand how Drivers and Managers work to understand how the framework solves some problems, but it&rsquo;s also a nice pattern to keep in mind for example to write tests that usually work with third-party APIs</blockquote><div class="lead !mb-9 text-xl">
  Driver-based Development is a coding pattern that is common in the Laravel world and used in multiple instances in the
framework. It&rsquo;s important to understand how Drivers and Managers work to understand how the framework solves some
problems, but it&rsquo;s also a nice pattern to keep in mind for example to write tests that usually work with third-party
APIs
</div>

<h2 id="manager-and-driver-pattern-ad-other-patterns" class="relative group">Manager and Driver Pattern (ad other Patterns) <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#manager-and-driver-pattern-ad-other-patterns" aria-label="Anchor">#</a></span></h2><p>I started the research for this post to learn more about the software patterns. After my last learning on the usage of
the Repository Pattern in <a href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/">this post</a> about something similar
to the Repository Pattern. So to keep this from happening, I want to give a small overview of the patterns that crossed
my research path. This resulted in some learning, some confusion, and a somewhat understanding of the different patterns
that people associated with the Driver Pattern. Keep in mind, in the end, Software Patterns are proven concepts that
solve common problems in programming.</p>
<p>






  
  
<figure><img src="/images/2022-05-patterns.png" alt="Why do I care for Software Patterns?" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h3 id="builder-pattern" class="relative group">Builder Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#builder-pattern" aria-label="Anchor">#</a></span></h3><p>The Builder Pattern enables the build-up of complex objects, the most common example would be the ORM Eloquent. Every
Laravel developer has used it to build the complex object representation of a SQL query. Another example are Laravel
Factories, which also use a number of methods to create a complex object in a readable way. I
recommend <a href="http://snags88.github.io/builder-pattern-in-laravel" target="_blank" rel="noreferrer">this post to learn more</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$users</span> <span class="o">=</span> <span class="nx">User</span><span class="o">::</span><span class="na">factory</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">has</span><span class="p">(</span><span class="nx">Post</span><span class="o">::</span><span class="na">factory</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">count</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">suspended</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">make</span><span class="p">();</span>
</span></span></code></pre></div><h3 id="provider-pattern" class="relative group">Provider Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#provider-pattern" aria-label="Anchor">#</a></span></h3><p>The Provider Pattern has more definitions than I expected&hellip; It can refer to the Data Provider pattern I used in Flutter
and Angular to store and hold data; it may refer to the encapsulation of methods that do different things like a plugin
or STK; or in the Laravel world Provider refer to application bootstrapping and configuration, they register routes,
singletons, or bind listeners to events. I recommend asking the person who mentioned it to explain to what they refer.</p>
<h3 id="factory-pattern" class="relative group">Factory Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#factory-pattern" aria-label="Anchor">#</a></span></h3><p>The Factory Pattern (not Laravel Factories!) enables the creation of various types of objects on runtime. The decision
on which precise class to create is done during runtime, but usually the same in different environments. It can be
powerful if you don&rsquo;t know which type of object to create, e.g. if the client may decide this; or you want to have the
creation of multiple objects in one class to localise them or share functions they both need. I
recommend <a href="https://www.sitepoint.com/understanding-the-factory-method-design-pattern/" target="_blank" rel="noreferrer">this post to learn more</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">ProductFactory</span><span class="o">::</span><span class="na">build</span><span class="p">(</span><span class="s1">&#39;Computer&#39;</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="the-driver-pattern-in-contrast-to-all-of-them" class="relative group">The Driver Pattern in contrast to all of them <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-driver-pattern-in-contrast-to-all-of-them" aria-label="Anchor">#</a></span></h3><p>Different Drivers enable different implementations to perform the same tasks. The most common example is sending
messages using different services. A driver could be <code>sms</code>, one <code>mail</code>, and one <code>push notification</code>. The task is always
sending the message to the given set of users, but the implementation is different, other third-party APIs might be used
and sometimes the decision of which driver to use is done on runtime. Another example in the Laravel world is the Cache
Driver that stores your cache in <code>redis</code> or <code>table</code>, or the Database Driver that translates your Eloquent to <code>mySql</code>
or <code> pgsql</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">Message</span><span class="o">::</span><span class="na">channel</span><span class="p">(</span><span class="s1">&#39;mail&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">to</span><span class="p">(</span><span class="nv">$user</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">content</span><span class="p">(</span><span class="s1">&#39;Do not think about pink elephants&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">send</span><span class="p">();</span>
</span></span></code></pre></div><p>Now about the different Patterns: This code utilizes the Builder Pattern to set the properties of the object step by
step, but the Driver Pattern Magic happens just in the first line which determines how the message is sent. In the
Driver class itself somewhere the implementation of the sending must be, and there I would call some Service class or
library for actually sending emails and another one for sending SMS. The Factory Pattern might look similar at first
sight as it also creates an object on runtime based on a string, but the Factory Pattern aims to instantiate Models
while the Driver Pattern aims to instantiate classes that offer defined functionalities.</p>
<h2 id="when-to-use-a-driver-manager-solution" class="relative group">When to use a Driver Manager Solution <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#when-to-use-a-driver-manager-solution" aria-label="Anchor">#</a></span></h2><p>The most common answer to this question I found was:</p>
<blockquote>
<p>A driver-based service is the right choice when the same utility can be provided by more than one technology.
<a href="https://inspector.dev/how-to-extend-laravel-with-driver-based-services/" target="_blank" rel="noreferrer">Source</a></p>
</blockquote>
<p>So whenever you discover a problem that might now (or in the future) be solved by multiple or changing technologies,
this pattern can make it easy and simple to switch between the technologies depending on runtime decisions, database
entries, or environment variables.</p>
<p><strong>But there is more</strong>! I want to emphasize two other options when this pattern can be a handy tool:</p>
<p><strong>Testing and local development</strong> can be a non-trivial task if you use third-party APIs or your own Micro Services.
During tests (and sometimes during local development) you don&rsquo;t care about the correctness of the technology you are
using, and maybe don&rsquo;t even want to trigger any outside communication. Based on your Environment (<code>testing</code> or <code>local</code>)
you can then switch to a FakerDriver that maybe can be configured in the test to simulate a long request, a wrong
answer, or just correct behavior.</p>
<p><strong>A-B Testing of Services</strong> The first time I came in contact with this pattern, one of the reasons (besides many others)
why we went for this pattern was the easy implementation of an A-B Test of a new Recommendation System. In a situation
in which you have two technologies to do the same job, but want to compare how the users react to both of them you can
implement a Driver pattern to let different users use different technologies and compare the individual engagement rate
of features for different user groups.</p>
<h2 id="implementation" class="relative group">Implementation <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#implementation" aria-label="Anchor">#</a></span></h2><h3 id="folder-structure" class="relative group">Folder Structure <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#folder-structure" aria-label="Anchor">#</a></span></h3><p>Here is the plan: The two Driver are <code>FakeDriver</code> and <code>HugoDriver</code> (No need to search for that name, I just made it up).
To ensure the next developer who implements a Driver will implement everything we need, the <code>RecommenderContract</code>
defines which methods should be in a Driver. The <code>RecommenderManager</code> is the file in which we define which string causes
the instantiation of which Driver, and which Driver is the Default. And the <code>Recommender</code> is the Facade we will be using
in practice.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Support
</span></span><span class="line"><span class="cl">└─── Drivers
</span></span><span class="line"><span class="cl">│   │   RecommenderContract.php
</span></span><span class="line"><span class="cl">│   │   FakeDriver.php
</span></span><span class="line"><span class="cl">│   │   HugoDriver.php
</span></span><span class="line"><span class="cl">│
</span></span><span class="line"><span class="cl">└─── Facades
</span></span><span class="line"><span class="cl">│   │   Recommender.php
</span></span><span class="line"><span class="cl">│
</span></span><span class="line"><span class="cl">└─── Managers
</span></span><span class="line"><span class="cl">    │   RecommenderManager.php
</span></span></code></pre></div><p>To now understand the implementation I would like to follow the code starting with the usage I aim for.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="c1">// using default driver
</span></span></span><span class="line"><span class="cl"><span class="nx">Recommender</span><span class="o">::</span><span class="na">recommendationsForUser</span><span class="p">(</span><span class="nv">$user</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// using custom driver
</span></span></span><span class="line"><span class="cl"><span class="nx">Recommender</span><span class="o">::</span><span class="na">driver</span><span class="p">(</span><span class="s1">&#39;hugo&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">recommendationsForUser</span><span class="p">(</span><span class="nv">$user</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="facade" class="relative group">Facade <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#facade" aria-label="Anchor">#</a></span></h3><p>To achieve this code, we first need a <a href="https://laravel.com/docs/9.x/facades#main-content" target="_blank" rel="noreferrer">Laravel Facade</a>. This Facade
will call the Recommender Manager.</p>
<blockquote>
<p>In a Laravel application, a facade is a class that provides access to an object from the container.
The machinery that makes this work is in the Facade class. Laravel&rsquo;s facades, and any custom facades you create,
will extend the base Illuminate\Support\Facades\Facade class.</p>
</blockquote>
<p>As so often I recommend to type-hint all methods to utilize autocompletion as well as the possibility to &ldquo;click through&rdquo;
your code easily.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\Facades\Facade</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * Class Recommender
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @method recommendationsForUser(array $models, ?int $userId = null)
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @see \App\Support\Drivers\HugoDriver::recommendationsForUser()
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @method driver(string $name)
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @see \App\Support\Managers\RecommenderManager
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Recommender</span> <span class="k">extends</span> <span class="nx">Facade</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">getFacadeAccessor</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">RecommenderManager</span><span class="o">::</span><span class="na">class</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="manager" class="relative group">Manager <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#manager" aria-label="Anchor">#</a></span></h3><p>The Manager defines which Driver is initiated. For this extend the <code>Illuminate\Support\Manager</code>. To implement this class
you need to define the method <code>getDefaultDriver</code>. If you want a different default per environment, this would be the
place to either return a config value or an environment variable. Then you need one method per Driver you want to build.
The Illuminate Manager will guess the method name based on the string you put in (e.g. <code>'fake'</code>)
using <code> $method = 'create'.Str::studly($driver).'Driver';</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\Manager</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">RecommenderManager</span> <span class="k">extends</span> <span class="nx">Manager</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getDefaultDriver</span><span class="p">()</span><span class="o">:</span> <span class="nx">string</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">env</span><span class="p">(</span><span class="s1">&#39;RECOMMENDER_DRIVER&#39;</span><span class="p">,</span> <span class="s1">&#39;fake&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">createHugoDriver</span><span class="p">()</span><span class="o">:</span> <span class="nx">HugoDriver</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">HugoDriver</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">createFakeDriver</span><span class="p">()</span><span class="o">:</span> <span class="nx">FakeDriver</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">FakeDriver</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>One step is missing until this is working - registering the Manager. This is done using
a <a href="https://laravel.com/docs/9.x/providers" target="_blank" rel="noreferrer">Laravel Service Provider</a>. As I don&rsquo;t plan to use the Recommender
functionality in every request I made it a deferred Provider.</p>
<blockquote>
<p>If your provider is only registering bindings in the service container, you may choose to defer its registration until
one of the registered bindings is actually needed. Deferring the loading of such a provider will improve the
performance of your application, since it is not loaded from the filesystem on every request.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\ServiceProvider</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Contracts\Support\DeferrableProvider</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">RecommenderServiceProvider</span> <span class="k">extends</span> <span class="nx">ServiceProvider</span> <span class="k">implements</span> <span class="nx">DeferrableProvider</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">register</span><span class="p">()</span><span class="o">:</span> <span class="nx">void</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">app</span><span class="o">-&gt;</span><span class="na">singleton</span><span class="p">(</span><span class="nx">RecommenderManager</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">fn</span> <span class="p">(</span><span class="nv">$app</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">RecommenderManager</span><span class="p">(</span><span class="nv">$app</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">provides</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="nx">RecommenderManager</span><span class="o">::</span><span class="na">class</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="driver" class="relative group">Driver <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#driver" aria-label="Anchor">#</a></span></h3><p>The Facade calls the Manager, and the Manager decides which Driver to call, now the Driver is missing implementation.
This is very straightforward. Whatever Hugo does, Hugo does it here!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\Collection</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">HugoDriver</span> <span class="k">implements</span> <span class="nx">RecommenderContract</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">recommendationsForUser</span><span class="p">(</span><span class="k">array</span> <span class="nv">$models</span><span class="p">,</span> <span class="o">?</span><span class="nx">int</span> <span class="nv">$userId</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span><span class="o">:</span> <span class="nx">Collection</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// implement magic here
</span></span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">collect</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="additional" class="relative group">Additional <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#additional" aria-label="Anchor">#</a></span></h3><p>As I mentioned I use this to test my code if it utilises third-party technology. So when I write a FakeDriver I
implement additional methods, that allow me to fake different states, time delays, or other things. Sure, you can also
write tiny Unit Tests to test such behaviors, I made the best experience with feature tests and this method of faking
data during the tests.</p>
<h2 id="happy-coding" class="relative group">Happy Coding <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#happy-coding" aria-label="Anchor">#</a></span></h2><p>This was my two cents on Manager and Drivers, and the way I implemented it. When I discovered the pattern I read through
this <a href="https://itnext.io/building-driver-based-components-in-laravel-5b390dc25bd9" target="_blank" rel="noreferrer">post by Orobo</a>, as well
as <a href="https://inspector.dev/how-to-extend-laravel-with-driver-based-services/" target="_blank" rel="noreferrer">this on by Valerio</a>.</p>
<p>If you spot an error, please don&rsquo;t hesitate on enlighten me,</p>
<p>Happy Coding :)</p>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/></entry><entry><title type="html">Useful and Useless Relationship Definitions</title><link href="https://philodev.one/posts/2022-05-relationships/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="related" type="text/html" title="Model Specific Query Builder - an Alternative to Scopes"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><id>https://philodev.one/posts/2022-05-relationships/</id><published>2022-05-20T14:20:44+02:00</published><updated>2022-05-20T14:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Programmer giving Relationship Advice - A summary about Laravel / Eloquent relationships including some hints, advanced techniques to use and misuse relations</blockquote><div class="lead !mb-9 text-xl">
  Programmer giving Relationship Advice - A summary about Laravel / Eloquent relationships including some
hints, advanced techniques to use and misuse relations
</div>

<h2 id="relationships-are-great" class="relative group">Relationships are great <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#relationships-are-great" aria-label="Anchor">#</a></span></h2><p>Relational Databases like mySql or postgres tend to have that thing called relations. There are used in almost all
Laravel Projects with a database and most Laravel developers know them and know how to use them. But not every developer
knows <a href="https://laravel.com/docs/9.x/eloquent-relationships" target="_blank" rel="noreferrer">the Laravel Docs</a> by heart and there are even some features
that are not mentioned in the Laravel Docs at all, but can only be discovered by clicking through the Eloquent code.</p>
<p>






  
  
<figure><img src="/images/2022-05-relations.png" alt="Example Image with Humans, Dogs, and Toys to explain Relationships" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<p>This blog post wants to sum up the basic relations Eloquent offers, hinting at some special ways to define relations and
advanced techniques to create relations that might be useful for querying. However, this post does not cover the usage
of relations, their benefits for query optimization, or general explanations of how they work (for learning that I
recommend the Laravel Docs or <a href="https://geekflare.com/laravel-eloquent-model-relationship/" target="_blank" rel="noreferrer">this Blog Article</a>) - only
the definition of them.</p>
<h2 id="example-database-structure" class="relative group">Example Database structure <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#example-database-structure" aria-label="Anchor">#</a></span></h2><p>Let&rsquo;s play a game, shall we? Let&rsquo;s have some <code>games</code>, each with a <code>hostPlayer</code>, some <code>players</code> who belong to a game and
a user. A game consists of multiple <code>rounds</code>, in each round one player is active, and all players may make a <code>move</code>
resulting in a score per round.</p>
<h3 id="class-diagram" class="relative group">Class diagram <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#class-diagram" aria-label="Anchor">#</a></span></h3><pre tabindex="0"><code><div class="mermaid" align="center">
   
classDiagram 
Move --> Round : Round has many Moves, </br> Move belongs to a Round
Round --> Player : Player has many Rounds as Active-Player, </br> Round belongs to an Active-Player
Round --> Game : Game has many Rounds, </br> Round belongs to a Game 
Move --> Player : Player has many Moves, </br> Move belongs to a Player 
Player --> Game : Game has many Players, </br> Player belongs to a Game 
Game --> Player : Player has many Games as Host, </br> Game belongs to a Host-Player


class Game { 
id
host_player_id
started_at
}

class Player { 
id
game_id
user_id
color
}

class Round { 
id
game_id
active_player_id
completed_at
}

class Move { 
id
round_id
player_id
score
}


</div>

</code></pre><h2 id="one-to-one" class="relative group">One to One <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#one-to-one" aria-label="Anchor">#</a></span></h2><h3 id="hasone-and-belongsto" class="relative group"><strong>HasOne</strong> and <strong>BelongsTo</strong> <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#hasone-and-belongsto" aria-label="Anchor">#</a></span></h3><p>If a model has a column containing another model&rsquo;s id, forming a One to One Relationship. Every Relationship has its
inverse form - if a User <strong>HasOne</strong> Level, a Level <strong>BelongsTo</strong> a User. A Model with a <strong>HasOne</strong>
says &ldquo;the id of mine is in on another table&rdquo;, the standard example would be:</p>
<pre tabindex="0"><code><div class="mermaid" align="center">
   
classDiagram 
User <-- Level: User has one Level </br> Level belongs to User

class User { 
id 
email 
password
}

class Level { 
id 
user_id 
over_all_score
}


</div>

</code></pre><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">level</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasOne</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasOne</span><span class="p">(</span><span class="nx">Level</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Level</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">user</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\BelongsTo</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">belongsTo</span><span class="p">(</span><span class="nx">User</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><h3 id="creative-usage-of-the-extra-parameters" class="relative group">&ldquo;Creative&rdquo; usage of the extra Parameters <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#creative-usage-of-the-extra-parameters" aria-label="Anchor">#</a></span></h3><p><strong>A word on parameter naming</strong> The <code>something_id</code> column is called <code>foreign_id</code>, while the id column of this model is
referred to as <code>local_id</code>; the model to which this foreign_id belongs is the owner model, and its id column is referred
to as <code>owner_id</code>. In Laravel it is possible to enter alternative values (other than Laravel&rsquo;s guessed
values <code>$this-&gt;belongsTo(User::class, 'user_id', 'id')</code>) for reasons like using <code>uuids</code> or naming conventions.</p>
<p>But you can use these parameters also in more creative ways, let&rsquo;s say you want to display the level of the user next to
a players icon:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Player</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">level</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasOne</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasOne</span><span class="p">(</span><span class="nx">Level</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="s1">&#39;user_id&#39;</span><span class="p">,</span> <span class="s1">&#39;user_id&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">The idea of &ldquo;misusing&rdquo; relations in this way is considerable, strange, not intuitive for readers, and confusing for
beginners - so maybe just don&rsquo;t do them. With this blog post I just want to point out, that this way of working with
relationships is possible, works for some cases great, and is kinda fun to think about.</span>
</div>

<p>If I need the relation (for eager loading, query optimization&hellip;) it is handy to take the shortcut of just using the
user_ids. The problems I want to point out:</p>
<ul>
<li>Using the create function will not create a user, and honestly, I have no idea what would happen or which id would be
set there</li>
<li>This query will not check if the user exists or is deleted</li>
</ul>
<h3 id="default-models" class="relative group">Default Models <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#default-models" aria-label="Anchor">#</a></span></h3><p>Both <strong>HasOne</strong> and <strong>BelongsTo</strong> relations may have a default which (for example for a level) comes in handy because
you don&rsquo;t have to store a model for a user who maybe never plays a game.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">level</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasOne</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasOne</span><span class="p">(</span><span class="nx">Level</span><span class="o">::</span><span class="na">class</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">withDefault</span><span class="p">([</span><span class="s1">&#39;overall_score&#39;</span> <span class="o">=&gt;</span> <span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><h2 id="one-to-many" class="relative group">One To Many <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#one-to-many" aria-label="Anchor">#</a></span></h2><h3 id="hasmany-and-belongsto" class="relative group"><strong>HasMany</strong> and <strong>BelongsTo</strong> <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#hasmany-and-belongsto" aria-label="Anchor">#</a></span></h3><p>The more common One to Many relations are indistinguishable from a database perspective (if there is no <code>unique</code>
constraint on the foreign key column). The difference is the possibility of the Owner to have more than one model
belonging to it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">rounds</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasMany</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasMany</span><span class="p">(</span><span class="nx">Round</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Round</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">game</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\BelongsTo</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">belongsTo</span><span class="p">(</span><span class="nx">Game</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><h3 id="queries-in-relations" class="relative group">Queries in Relations <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#queries-in-relations" aria-label="Anchor">#</a></span></h3><p>Compared to <code>ofMany</code> adding extra queries on the relation is possible as well and can come in quite handy:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">redPlayers</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasMany</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasMany</span><span class="p">(</span><span class="nx">Player</span><span class="o">::</span><span class="na">class</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;color&#39;</span><span class="p">,</span> <span class="s1">&#39;red&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">playersWithoutMove</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasMany</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasMany</span><span class="p">(</span><span class="nx">Player</span><span class="o">::</span><span class="na">class</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">whereDosntHave</span><span class="p">(</span><span class="s1">&#39;move&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="using-hasone-ofmany" class="relative group">Using <strong>HasOne</strong>-&gt;ofMany <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-hasone-ofmany" aria-label="Anchor">#</a></span></h3><p>But <code>HasOne</code> also offers great options if you are often looking for one special model of a <strong>HasMany</strong> Relationship.
This use case is very common, so I think the <code>ofMany</code> function is underrated.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Round</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// latest (current) Move
</span></span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">latestMove</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasOne</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasOne</span><span class="p">(</span><span class="nx">Move</span><span class="o">::</span><span class="na">class</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">latestOfMany</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// best Move
</span></span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">latestMove</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasOne</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasOne</span><span class="p">(</span><span class="nx">Move</span><span class="o">::</span><span class="na">class</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">latestOfMany</span><span class="p">(</span><span class="s1">&#39;score&#39;</span><span class="p">,</span> <span class="s1">&#39;max&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// best, latest move where score is positive
</span></span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">bestLatestMoveWithPositiveScore</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasOne</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasOne</span><span class="p">(</span><span class="nx">Move</span><span class="o">::</span><span class="na">class</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">ofMany</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="s1">&#39;created_at&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;max&#39;</span><span class="p">,</span> <span class="s1">&#39;score&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;max&#39;</span><span class="p">],</span> 
</span></span><span class="line"><span class="cl">            <span class="nx">fn</span> <span class="p">(</span><span class="nv">$query</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$query</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;score&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><h3 id="creative-one-to-many-relations" class="relative group">&ldquo;Creative&rdquo; One to Many Relations <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#creative-one-to-many-relations" aria-label="Anchor">#</a></span></h3><p>Breaking it down to the minimal requirement, a <code>HasMany</code> relation requires that there is another table, which holds an
identifier that the local table holds as well.</p>
<p>If you look at our class diagram, for example, there is no direct connection between <code>Move</code> and <code>Game</code>, if you want the
moves of a game you have to use the <code>Round</code> as a middleman. Now let&rsquo;s say I want a statistic that proves that my game is
fair and that the host player does not make moves with higher scores or so - whatever reason I might have to create such
a relation.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">hostPlayerMoves</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasMany</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasMany</span><span class="p">(</span><span class="nx">Moves</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="s1">&#39;player_id&#39;</span><span class="p">,</span> <span class="s1">&#39;host_player_id&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Again, creating this kind of relationships might be smelly or hacky, but it can be handy if you keep the possibilities
in mind that relations offer.</span>
</div>

<h3 id="having-things-through" class="relative group">Having Things Through <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#having-things-through" aria-label="Anchor">#</a></span></h3><p>Laravel provides a relation for two consecutive <code>HasMany</code> relations.</p>
<pre tabindex="0"><code><div class="mermaid" align="center">
   
classDiagram 
Round --> Game : Game has many Rounds, </br> Round belongs to a Game 
Move --> Round : Round has many Moves, </br> Move belongs to a Round
Move <-- Game : Game has many Moves through Round

class Game { 
id
host_player_id
started_at
}

class Round { 
id
game_id
active_player_id
completed_at
}

class Move { 
id
round_id
player_id
score
}


</div>

</code></pre><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">moves</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasManyThrough</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasManyThrough</span><span class="p">(</span><span class="nx">Move</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">Round</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><h4 id="creative-hasmanythroughs" class="relative group">&ldquo;Creative&rdquo; HasManyThroughs <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#creative-hasmanythroughs" aria-label="Anchor">#</a></span></h4><p>Let&rsquo;s say we want to display the Level of the overall Game - maybe to match with other Games or whatever. Again we can
use the additional parameters to skip some tables on the way between Game and Level. Usually, we would start at the
Game, and look for the players, look for the users, look for the levels. But both the levels and the players share the
same user_id - why not skip the User?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">levels</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasManyThrough</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">hasManyThrough</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Level</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Player</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;game_id&#39;</span><span class="p">,</span> <span class="c1">// Foreign key on the players table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;user_id&#39;</span><span class="p">,</span> <span class="c1">// Foreign key on the levels table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="c1">// Local key on the games table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;user_id&#39;</span> <span class="c1">// Local key on the players table
</span></span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300">Again, creating this kind of relationships might be smelly or hacky, but it can be handy if you keep the possibilities
in mind that relations offer.</span>
</div>

<h2 id="many-to-many" class="relative group">Many To Many <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#many-to-many" aria-label="Anchor">#</a></span></h2><p>Many to Many relations are the kind of relations that require a pivot table. If compared to the implementation depicted
in the examples above, where a user has a player per game I could have implemented a Many to Many relation using
a <code>game_user</code> or <code>game^user</code> or <code>games_2_users</code> table or other conventional namings for pivot tables. That would look
like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">player</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\HasManyThrough</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">belongsToMany</span><span class="p">(</span><span class="nx">User</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="s1">&#39;game_user&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><p>The point I don&rsquo;t like about this is #1 the naming convention does not reflect the meaning of the relation; I prefer
calling a thing by their name, in this case, <code>players</code>. 2# The first thing especially bugs me after you start adding
more columns in the pivot table, starting with timestamps, then maybe a soft delete, and then a custom link or so. At
some point, a lot of the pivot tables I saw would have looked cleaner, and caused less code smell if they were models
from the very beginning.</p>
<p>This does not mean, that many to many relations are useless. As I mentioned in the last examples, there are many ways to
use the additional parameters in the relationship functions. So if you see <code>Player</code> as a pivot model, you can still
define this relation:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">users</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\BelongsToMany</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">belongsToMany</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nx">User</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="c1">// target model
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;players&#39;</span><span class="p">,</span> <span class="c1">// pivot table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;game_id&#39;</span><span class="p">,</span> <span class="c1">// Foreign key on pivot player table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;user_id&#39;</span><span class="p">,</span> <span class="c1">// Foreign key on pivot player table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="c1">// Parent key on the games table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;id&#39;</span> <span class="c1">// Related key on the users table
</span></span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><p>Any table with two foreign ids may be used as a pivot table!</p>
<h3 id="creative-many-to-many-relations" class="relative group">&ldquo;Creative&rdquo; Many to Many Relations <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#creative-many-to-many-relations" aria-label="Anchor">#</a></span></h3><p>You may again use this information even further and again create sometimes useful relations by using the additional
function parameters. For example, if you want to have the Levels instead of the Users of a Game.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Game</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">levels</span><span class="p">()</span><span class="o">:</span> <span class="nx">\Illuminate\Database\Eloquent\Relations\BelongsToMany</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">belongsToMany</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Level</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="c1">// target model
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;players&#39;</span><span class="p">,</span> <span class="c1">// pivot table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;game_id&#39;</span><span class="p">,</span> <span class="c1">// Foreign key on pivot player table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;user_id&#39;</span><span class="p">,</span> <span class="c1">// Foreign key on pivot player table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="c1">// Parent key on the games table
</span></span></span><span class="line"><span class="cl">            <span class="s1">&#39;user_id&#39;</span> <span class="c1">// Related key on the levels table
</span></span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><h2 id="last-words" class="relative group">Last words <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#last-words" aria-label="Anchor">#</a></span></h2><p>This was a collection of infos, hints, and hacks about the definition of Laravel or Eloquent Relationships. If you found
any mistakes or have additional tricks please feel free to contact me :D</p>
<p>Happy coding</p>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/></entry><entry><title type="html">Model Specific Query Builder - an Alternative to Scopes</title><link href="https://philodev.one/posts/2022-05-custom-query-builder-pattern/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="related" type="text/html" title="Demo Environments and what I learned from implementing one"/><id>https://philodev.one/posts/2022-05-custom-query-builder-pattern/</id><published>2022-05-14T08:20:44+02:00</published><updated>2022-05-14T08:20:44+02:00</updated><content type="html"><![CDATA[<blockquote>Scopes are nice, but by extending the Eloquent Builder for a Model enables you to add custom, model-specific methods that are often used or should have a central definition</blockquote><div class="lead !mb-9 text-xl">
  Scopes are nice, but by extending the Eloquent Builder for a Model enables you to add custom,
model-specific methods that are often used or should have a central definition
</div>

<h2 id="scopes-are-great-but-" class="relative group">Scopes are great, but &hellip; <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#scopes-are-great-but-" aria-label="Anchor">#</a></span></h2><p>Local scopes allow you to define common sets of query constraints that you may easily re-use throughout your
application; read more in <a href="https://laravel.com/docs/9.x/eloquent#local-scopes" target="_blank" rel="noreferrer">the Laravel Docs</a>. Also, if you want to
have a definition of a scope in one central place to maybe come back and change in at one place, instead of everywhere -
a common example in practise is an <code>activeUser</code> scope (email confirmed? password not older than one year? &hellip; ).</p>
<p>Scopes are great, but have two major drawbacks from my point of view: #1 no autocompletion / no &ldquo;jump in your code by
clicking&rdquo; on it, no type hinting. This is because drawback #2 they are executed by Laravel magics. The Framework checks
if the method you are trying to call is defined in <code>scope&lt;yourMethodNameInCamelCase&gt;</code> in the model and uses it then.</p>
<h2 id="about-patterns" class="relative group">About Patterns <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#about-patterns" aria-label="Anchor">#</a></span></h2><p>Laravel Scopes are build utilizing the <strong>Builder Pattern</strong>, which enables the build-up of complex object (in this case
the object representation of a SQL Query) step by step using methods to change the query bit by bit. Now, scopes are
also following the pattern but in use cases in which a set of queries if performed often, they make the code more
readable and maintainable.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<h3 id="repository-pattern" class="relative group">Repository Pattern <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#repository-pattern" aria-label="Anchor">#</a></span></h3><p>One pattern is partially similar, the Repository Pattern was the closest I could find. Most times the Repository handles
create, delete, and index methods, while this post focuses on index / query methods only. The only I could not find a
specific Pattern I could match the custom query builder with, but</p>
<p>The Repository is an abstraction Layer of Data, from this abstraction Layer the data may be retrieved using function
like <code>Post::getAll()</code> or in the case of Eloquent <code>Post::all()</code>. Most implementations of the Repository pattern I found
are doing the above step of overwriting Eloquent methods with their own <code>getAll</code> method. But instead of overwriting the
Eloquent methods, why not just extend them? <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<h2 id="writing-a-custom-builder-that-extends-the-eloquent-builder" class="relative group">Writing a Custom Builder that Extends the Eloquent Builder <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#writing-a-custom-builder-that-extends-the-eloquent-builder" aria-label="Anchor">#</a></span></h2><p>The Builder that Laravel uses behind every <code>::query()</code> is the <code>Illuminate\Database\Eloquent\Builder</code>. A class that
extends this Builder for one Model offers the opportunity to add custom methods to the Builder.</p>
<p>Compared to Scopes I want to highlight, that neither the Scope Prefix is needed, nor the $query parameter. Additionally,
this utilises the fully typed / auto-completion feature I value so much <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">App\Models\Builders</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">App\Models\User</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Eloquent\Builder</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @template TModelClass of \App\Models\Post
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @extends Builder&lt;TModelClass&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PostBuilder</span> <span class="k">extends</span> <span class="nx">Builder</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">published</span><span class="p">()</span><span class="o">:</span> <span class="nx">self</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;published&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">whereHasMedia</span><span class="p">()</span><span class="o">:</span> <span class="nx">self</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="nx">fn</span> <span class="p">(</span><span class="nx">self</span> <span class="nv">$query</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$query</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">whereHas</span><span class="p">(</span><span class="s1">&#39;image&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">orWhereHas</span><span class="p">(</span><span class="s1">&#39;video&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">visibleToUser</span><span class="p">(</span><span class="nx">User</span> <span class="nv">$user</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">published</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="nx">fn</span> <span class="p">(</span><span class="nx">PostBuilder</span> <span class="nv">$query</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$query</span>
</span></span><span class="line"><span class="cl">                <span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;privacy&#39;</span><span class="p">,</span> <span class="s1">&#39;public&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="o">-&gt;</span><span class="na">when</span><span class="p">(</span><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">isAdmin</span><span class="p">(),</span> <span class="nx">fn</span> <span class="p">(</span><span class="nx">PostBuilder</span> <span class="nv">$query</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$query</span>
</span></span><span class="line"><span class="cl">                    <span class="o">-&gt;</span><span class="na">orWhere</span><span class="p">(</span><span class="s1">&#39;privacy&#39;</span><span class="p">,</span> <span class="s1">&#39;friends&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This will not work out of the box, how should Laravel know that we don&rsquo;t want to use the Eloquent Buidler?</p>
<p>To solve this we first have to overwrite the <code>query</code> Method to get the Typehints and autocompletion. Secondly we have to
overwrite the Model <code>newEloquentBuilder</code> method. Inside the <code>Illuminate\Database\Eloquent\Model</code> this methods usually
initiates a new <code>\Illuminate\Database\Query\Builder</code> using the <code>$query</code> parameter. As our <code>PostBuilder</code> extends this
Class, we can just use it the same.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Post</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @return PostBuilder&lt;\App\Models\Post&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">query</span><span class="p">()</span><span class="o">:</span> <span class="nx">PostBuilder</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">parent</span><span class="o">::</span><span class="na">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param \Illuminate\Database\Query\Builder $query
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @return PostBuilder&lt;\App\Models\Post&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">newEloquentBuilder</span><span class="p">(</span><span class="nv">$query</span><span class="p">)</span><span class="o">:</span> <span class="nx">PostBuilder</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">PostBuilder</span><span class="p">(</span><span class="nv">$query</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span></code></pre></div><h2 id="enjoy-the-usage" class="relative group">Enjoy the Usage <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#enjoy-the-usage" aria-label="Anchor">#</a></span></h2><p>Let&rsquo;s feel the joy of what we have implemented:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$posts</span> <span class="o">=</span> <span class="nx">Post</span><span class="o">::</span><span class="na">query</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">visibleToUser</span><span class="p">(</span><span class="nx">Auth</span><span class="o">::</span><span class="na">user</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">paginate</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$latestPostedImage</span> <span class="o">=</span> <span class="nx">Post</span><span class="o">::</span><span class="na">query</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">where</span><span class="p">(</span><span class="s1">&#39;user_id&#39;</span><span class="p">,</span> <span class="mi">41</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">whereHasMedia</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">published</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">latest</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$latestPostedImage</span> <span class="o">=</span> <span class="nv">$user</span><span class="o">-&gt;</span><span class="na">posts</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">published</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$userWithPublishedPosts</span> <span class="o">=</span> <span class="nx">User</span><span class="o">::</span><span class="na">query</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">whereHas</span><span class="p">(</span><span class="s1">&#39;post&#39;</span><span class="p">,</span> <span class="nx">fn</span> <span class="p">(</span><span class="nx">PostBuilder</span> <span class="nv">$query</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$query</span><span class="o">-&gt;</span><span class="na">published</span><span class="p">(</span><span class="nv">$user</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">get</span><span class="p">();</span>
</span></span></code></pre></div><p>Can you feel it? No, you can&rsquo;t - you have to try it to get the satisfying feeling of your IDE proposing the
Model-dependent extra methods like &lsquo;published&rsquo; while typing, or when you go through old or unknown code the possibility
to click on the method and get directly to the implementation without any Laravel Plugin or searching for a ScopeMethod.</p>
<p>There a some additional things to mention:</p>
<ul>
<li>If you don&rsquo;t use the <code>query</code> Method (like <code>Post::first()</code>) the <code>newEloquentBuilder</code> Method will be called anyway, but
you don&rsquo;t have Typehints</li>
<li>Usage of the two patterns are the same, the main different is the way ScopeMethods are implemented and the two extra
Methods in the Model</li>
<li>In case your super high complexity Project can utilize it: Builder classes may share traits ;)</li>
</ul>
<h2 id="bonus" class="relative group">Bonus: <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#bonus" aria-label="Anchor">#</a></span></h2><p>If custom query builders is not enough for you to play with, try customising Collections <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. If there
is any set of collection methods you always use, or you are missing, you can just extend the Laravel Collections
yourself!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">AppServiceProvider</span> <span class="k">extends</span> <span class="nx">ServiceProvider</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">boot</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Collection</span><span class="o">::</span><span class="na">macro</span><span class="p">(</span><span class="s1">&#39;firstWhereMin&#39;</span><span class="p">,</span> <span class="nx">fn</span> <span class="p">(</span><span class="nx">string</span> <span class="nv">$key</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">firstWhere</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">min</span><span class="p">(</span><span class="nv">$key</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>I am still looking for a nice way to keep my beloved autocompletion, but for just the functionality I can recommend you
to just write all the Collection methods you might miss. <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<h2 id="bonus-hin-custom-collections" class="relative group">Bonus hin: custom Collections <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#bonus-hin-custom-collections" aria-label="Anchor">#</a></span></h2><p>Next to the custom query builder, Laravel allows to also have customized the collections that get instntiated when e.g.
a HasMany Relation is called without brackets or a query is call using <code>get()</code>. <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Eloquent\Collection</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PostCollection</span> <span class="k">extends</span> <span class="nx">Collection</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">published</span><span class="p">()</span><span class="o">:</span> <span class="nx">self</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">filter</span><span class="p">(</span><span class="nx">fn</span> <span class="p">(</span><span class="nx">Post</span> <span class="nv">$post</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$post</span><span class="o">-&gt;</span><span class="na">published_at</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Post</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">newCollection</span><span class="p">(</span><span class="k">array</span> <span class="nv">$models</span> <span class="o">=</span> <span class="p">[])</span><span class="o">:</span> <span class="nx">PostCollection</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">PostCollection</span><span class="p">(</span><span class="nv">$models</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>In <a href="https://philodev.one/posts/2022-05-driver-manager-pattern/">this post</a> I write more about
patterns&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>In my personal point of view the only reason to completely implement this pattern is to generate
everything starting from routes, to controller, and resources based on an openApi file or so,
but <a href="https://laravelarticle.com/repository-design-pattern-in-laravel" target="_blank" rel="noreferrer">here is an example</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>When I looked through the web, the only blog articles I could find, which did implement this pattern
where <a href="https://martinjoo.dev/build-your-own-laravel-query-builders" target="_blank" rel="noreferrer">this one by Martin Joo</a>
and <a href="https://timacdonald.me/dedicated-eloquent-model-query-builders/" target="_blank" rel="noreferrer">this one by Tim MacDonald</a>. Both do not overwrite
the query method, but every thing else is quite similar to this post.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Read through the <a href="https://laravel.com/docs/9.x/collections#extending-collections" target="_blank" rel="noreferrer">Laravel Docs</a>
regarding this&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://github.com/spatie/laravel-collection-macros" target="_blank" rel="noreferrer">Spatie has a package</a> with nice examples if
you are looking for something pre-build or inspiration&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Found in this book which refers to quite some topics I like: LARAVEL BEYOND CRUD by Brent Roose&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="software-pattern" label="Software Pattern"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/></entry><entry><title type="html">Demo Environments and what I learned from implementing one</title><link href="https://philodev.one/posts/2022-05-demo-env/?utm_source=atom_feed" rel="alternate" type="text/html"/><id>https://philodev.one/posts/2022-05-demo-env/</id><published>2022-05-11T20:36:22+02:00</published><updated>2022-05-11T20:36:22+02:00</updated><content type="html"><![CDATA[<blockquote>I got the task to implement a Demo environment, learned something about Laravel Factories and the usage of an environment to give possible customers / investors a taste of your product and the developers to find response time / query problems and UX bugs</blockquote><div class="lead !mb-9 text-xl">
  I got the task to implement a Demo environment, learned something about Laravel Factories and the usage of
an environment to give possible customers / investors a taste of your product and the developers to find response time /
query problems and UX bugs
</div>

<h1 id="a-demo-feature-request" class="relative group">A &ldquo;Demo&rdquo; Feature Request <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#a-demo-feature-request" aria-label="Anchor">#</a></span></h1><p>This card was proposed in a sprint planning and sparked a discussion around multiple problems and ideas.</p>
<blockquote>
<p>As a future Analytics-Component User I want to see a version of the Analytics-Component fully functional with
generated data, so that I can see how the page would look like, before I buy the Analytics Component</p>
</blockquote>
<p>First, the ideas: this company sold a software platform with one of its components being a set of graphs, statistics,
and informative texts to display the usage of the other platform features. The Analytics Component was not meant for
intern analytics, but a feature set for business customers. Allowing business customers to play around with such a page
before making decisions is a nice to have feature - who dislikes demos? A nice demo page is reachable for the interested
customer, can&rsquo;t break - even if the customer has no idea what they are doing, and should display as many features as
possible accurately, up-to-date, and in sense-full context.</p>
<p>Then, the discussion: We sure will not re-build the multi-page Analytics Component with some mocked graphs to only
forget about updating it whenever we add a page to the real product. After some discussion we want to generate (only the
needed) data to display all graphs and information correctly, but sure don&rsquo;t want any of it to be in our production
database. So we decided the best thing to do is to set up a demo environment that became part of our pipelines and would
receive the same features while holding the maximum workload one customer could cause. The demo account would be
reachable to potential customers by offering the demo user credentials and link to the environment, so the future
customer could play around with the page without breaking anything.</p>
<p>






  
  
<figure><img src="/images/2022-05-demo.png" alt="Trueman Show Reference. &ldquo;Show Customers, Show Investors, Test UX, Test Performance&rdquo;" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h2 id="implementation" class="relative group">Implementation <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#implementation" aria-label="Anchor">#</a></span></h2><p>Setting up a cost-efficient small server, building some pipelines, and branching a new &lsquo;demo&rsquo; branch from master. Before
starting the implementation I would like to set some constraints on the task. The Analytics Component could was
displaying data starting from yesterday, and keep historical data up to one year. The data required was a mix of
multiple models - a great thanks to the business for allowing the dev team to refactor most of the respective data to an
Event-Sourced pattern some weeks ago. The Component should work and display data every day, so there had to be a job to
generate new data every night. So what I build was:</p>
<ul>
<li>A Command triggered by every deployment to re-generate the data if needed, e.g. if a feature changed an additional
data had to be generated</li>
<li>A Job to run every night (as nobody was relying on the server one slow job would be fine). This job generates new data
every day, and deletes every data that is older than a year.</li>
</ul>
<h3 id="laravel-usage-of-factories" class="relative group">Laravel Usage of Factories <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#laravel-usage-of-factories" aria-label="Anchor">#</a></span></h3><div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Laravel Learning</strong>: Cascading Factories</span>
</div>

<p>Factories are a great way to generate data. One problem I run into was writing a factory that could also generate the
corresponding EventS-ource Model. Event Sourcing in one sentence describes a pattern in which the changes of a state are
stored in a database. Imagine we have Users who can collect Experience Points by playing Games. Instead of increasing a
column in the <code>users</code> table, or summing up the score column of the <code>games</code> table (because maybe there are more ways to
earn points), we create a table <code>experiences</code> which holds the user who earned points, the cause of points and the number
of points earned. This can be a great pattern if you plan on having some analytics (which then only need to query one
table), or want to leverage the &ldquo;event&rdquo; part of the pattern and have multiple background/ async jobs happening whenever
the state is changing.</p>
<p>The corresponding factory to generate games with experiences would be:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">GameFactory</span> <span class="k">extends</span> <span class="nx">Factory</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="nv">$model</span> <span class="o">=</span> <span class="nx">Game</span><span class="o">::</span><span class="na">class</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">definition</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;user_id&#39;</span> <span class="o">=&gt;</span> <span class="nx">User</span><span class="o">::</span><span class="na">factory</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;score&#39;</span>   <span class="o">=&gt;</span>  <span class="nx">random_int</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">withExperience</span><span class="p">()</span><span class="o">:</span> <span class="nx">self</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">afterCreating</span><span class="p">(</span><span class="nx">fn</span> <span class="p">(</span><span class="nx">Game</span> <span class="nv">$game</span><span class="p">)</span> <span class="o">=&gt;</span> 
</span></span><span class="line"><span class="cl">            <span class="nx">Experience</span><span class="o">::</span><span class="na">factory</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">create</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">                <span class="s1">&#39;game_id&#39;</span>    <span class="o">=&gt;</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">id</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                <span class="s1">&#39;user_id&#39;</span>    <span class="o">=&gt;</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">user_id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s1">&#39;created_at&#39;</span> <span class="o">=&gt;</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">created_at</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s1">&#39;updated_at&#39;</span> <span class="o">=&gt;</span> <span class="nv">$game</span><span class="o">-&gt;</span><span class="na">updated_at</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="p">]));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And it could be used like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$game</span> <span class="o">=</span> <span class="nx">Game</span><span class="o">::</span><span class="na">factory</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">withExperience</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">create</span><span class="p">();</span>
</span></span></code></pre></div><h3 id="about-generating-data-with-context" class="relative group">About generating data with context <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#about-generating-data-with-context" aria-label="Anchor">#</a></span></h3><p>Generating random data is tricky. There are some learnings I want to share while I wrote the job:</p>
<ul>
<li>Whenever it makes sense, after generating a bunch of models I invalidated and soft-deleted a subset of those. This
helped to get a realistic view and I hoped I could spot a bug if did so.</li>
<li>When working with data created every day I had a look at the average user - in this case people were more active on
weekdays compared to weekends. This is no simulation, I avoided holidays or anything, but a small line with the
integrated Carbon function was easy enough to give some realistic flow in the
data <code>$date-&gt;isWeekend() ? random_int(2, 15) : random_int(45, 101)</code></li>
<li>The Pages of the Analytics Component were my guide on how to vary the data - when the UX Designer worked on this, what
data did they or the business expect? If there was a ranking I decided in the implementation which subset of models
would be used more often to from relations to have live-like rankings.</li>
<li>Keep it simple: Whenever there was a model that was not in any way needed to display the Analytics Component - I would
not seed it.</li>
</ul>
<h2 id="using-the-demo-env-as-stress-test-and-bug-revealer" class="relative group">Using the Demo Env as Stress Test and Bug Revealer <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#using-the-demo-env-as-stress-test-and-bug-revealer" aria-label="Anchor">#</a></span></h2><p>Some writing of colorful text on dark background later we deployed and watched the system taking disturbing 16 seconds
to load some pages. Did I mention that the company was a Start-Up without a customer who had been causing data of that
size for a year? The product owner opened a fresh pack of post-its to note down every end-point that required query
optimisation as we developers got shameful credit for the not scalable system we had built. Additionally, not all graphs
that we did imagine worked out with that many data points, while some other inspired completely new ways do structure
the data.</p>
<div class="flex rounded-md bg-primary-100 px-4 py-3 dark:bg-primary-900">
  <span class="pe-3 text-primary-400">
    <span class="icon relative inline-block px-1 align-text-bottom"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/></svg>
</span>
  </span>
  <span class="dark:text-neutral-300"><strong>Development Process Learning</strong>: Having a demo environment with generated data can point
out response time problems, visualisation problems and be an inspiring point of view for UX and Code Development</span>
</div>

<p>The query optimisation was not too hard, avoid over-fetching, let SQL do whatever it can to faster than PHP, and use
eager loading whenever possible. The big learning of this experience was not how I optimised the queries, but how the
bottleneck was discovered. The reason I write this article is, that I recommend any high aiming Start Up to try this.
Not only is it a nice feature to present your investors a view on your page &ldquo;if people would use it&rdquo;, but also it can
uncover some bottlenecks you mind not have thought of in an early stage but would regret in case of that exponential
growth the business owner is promising next month.</p>
]]></content><category scheme="taxonomy:Tags" term="development" label="Development"/><category scheme="taxonomy:Tags" term="devops" label="DevOps"/><category scheme="taxonomy:Tags" term="laravel" label="Laravel"/></entry></feed>