<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Can Burak Sofyalioglu</title>
    <description>The latest articles on DEV Community by Can Burak Sofyalioglu (@canburaks).</description>
    <link>https://dev.to/canburaks</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F161632%2F1c88f1c5-3232-4b0e-b7ce-e23af550261d.jpg</url>
      <title>DEV Community: Can Burak Sofyalioglu</title>
      <link>https://dev.to/canburaks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/canburaks"/>
    <language>en</language>
    <item>
      <title>Road to State Machines VI - But What If Independent Work Finishes in a Different Order?</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Sat, 24 Oct 2026 18:56:51 +0000</pubDate>
      <link>https://dev.to/canburaks/road-to-state-machines-vi-but-what-if-independent-work-finishes-in-a-different-order-2eho</link>
      <guid>https://dev.to/canburaks/road-to-state-machines-vi-but-what-if-independent-work-finishes-in-a-different-order-2eho</guid>
      <description>&lt;p&gt;Our order can now wait for a shipping inquiry without pretending that shipping has already succeeded.&lt;/p&gt;

&lt;p&gt;The request receives an identifier. The order enters &lt;code&gt;CHECKING_SHIPPING&lt;/code&gt;. A matching response may move it to &lt;code&gt;READY_TO_SHIP&lt;/code&gt;, while a timeout or unsuccessful result returns it to &lt;code&gt;PAID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But Part V ended with another requirement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before proceeding, the system must obtain both a carrier response and an inventory result.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those operations may finish in either order.&lt;/p&gt;

&lt;p&gt;The carrier might answer first. The inventory system might answer first. One might fail while the other is still working.&lt;/p&gt;

&lt;p&gt;How do we combine their results without depending on a particular sequence?&lt;/p&gt;

&lt;h3&gt;
  
  
  Start with the smallest solution
&lt;/h3&gt;

&lt;p&gt;We could simply perform the checks one after another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;carrier_available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;check_carrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;carrier_available&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;inventory_available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;check_inventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a reasonable design.&lt;/p&gt;

&lt;p&gt;It has an obvious execution order. If the carrier rejects the destination, we avoid the inventory lookup entirely. There is little coordination logic to maintain.&lt;/p&gt;

&lt;p&gt;We should preserve that option when the work is cheap, the second operation depends on the first, or avoiding unnecessary requests matters more than overlapping their execution.&lt;/p&gt;

&lt;p&gt;But suppose both checks can begin from information we already possess. Neither needs the other’s result.&lt;/p&gt;

&lt;p&gt;The serial implementation imposes a dependency that the business rule does not require:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Carrier finishes
        ↓
Inventory may begin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we actually require is different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Carrier succeeds
        +
Inventory succeeds
        ↓
The combined check succeeds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both must finish successfully. Neither must finish first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separate checking inventory from reserving it
&lt;/h3&gt;

&lt;p&gt;Before introducing concurrent execution, we need to settle what the inventory operation does.&lt;/p&gt;

&lt;p&gt;Checking whether stock is available is not the same as reserving it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;What it establishes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check inventory&lt;/td&gt;
&lt;td&gt;The inventory service reports whether the order’s items are currently available.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reserve inventory&lt;/td&gt;
&lt;td&gt;The inventory service commits stock to this order under its reservation policy.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release inventory&lt;/td&gt;
&lt;td&gt;The service removes an earlier reservation.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The end of Part V raised inventory reservation as a future requirement. We will reach its failure consequences later in this part.&lt;/p&gt;

&lt;p&gt;First, we will implement two &lt;strong&gt;read-only availability checks&lt;/strong&gt;. Neither books a shipment nor reserves stock.&lt;/p&gt;

&lt;p&gt;This lets us establish the coordination rule without quietly introducing external changes that would need to be undone.&lt;/p&gt;

&lt;p&gt;Our inventory adapter will look up the order’s item requirements using its identifier. We are not adding an item model in this lesson. As with the destination in Part V, those requirements remain fixed during one check.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;READY_TO_SHIP&lt;/code&gt; therefore remains a state in our local simulation. It does not promise that stock is reserved or that carrier capacity will remain available indefinitely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fork the work, then join the results
&lt;/h3&gt;

&lt;p&gt;Starting independent branches from one request is commonly described as a &lt;strong&gt;fork&lt;/strong&gt;. Combining their results before continuing is a &lt;strong&gt;join&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Our intended flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Shipping check
                          │
                         fork
                     ┌────┴────┐
                     ▼         ▼
                 Carrier    Inventory
                  check       check
                     │         │
                     └────┬────┘
                         join
                          │
                          ▼
                  Combined result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The join is not simply the point where two lines meet in a diagram.&lt;/p&gt;

&lt;p&gt;It must answer a precise question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Have all the required branches for this particular request succeeded?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are two valid execution sequences:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;First result&lt;/th&gt;
&lt;th&gt;Second result&lt;/th&gt;
&lt;th&gt;Combined outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Carrier available&lt;/td&gt;
&lt;td&gt;Inventory available&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory available&lt;/td&gt;
&lt;td&gt;Carrier available&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After the first successful result, the combined answer is still incomplete.&lt;/p&gt;

&lt;p&gt;Starting both operations is not enough. Finishing either operation is not enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Readiness requires a successful result from every required branch of the current check.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a completion counter is insufficient
&lt;/h3&gt;

&lt;p&gt;We might begin with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;completed_checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then increment it whenever a successful result arrives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;completed_checks&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;completed_checks&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;report_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now deliver these messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Carrier&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;
&lt;span class="n"&gt;Carrier&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="n"&gt;again&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The counter reaches two.&lt;/p&gt;

&lt;p&gt;The inventory system has not answered.&lt;/p&gt;

&lt;p&gt;We counted messages when the rule required distinct prerequisites.&lt;/p&gt;

&lt;p&gt;A duplicate result must not satisfy another branch’s obligation. We need to remember &lt;strong&gt;which branch&lt;/strong&gt; answered, not merely how many messages arrived.&lt;/p&gt;

&lt;p&gt;We also need to retain the request identifier from Part V. A carrier answer from yesterday must not combine with an inventory answer for today’s request.&lt;/p&gt;

&lt;p&gt;The group of results belongs to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;order identifier
+
check request identifier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within that group, each result belongs to a named branch.&lt;/p&gt;

&lt;p&gt;This is the coordination problem described by the &lt;strong&gt;Aggregator&lt;/strong&gt; pattern in &lt;em&gt;Enterprise Integration Patterns&lt;/em&gt;: collect related messages, determine when enough information has arrived, and produce one combined result. The pattern separates correlation, completeness, and the rule used to combine results.[2]&lt;/p&gt;

&lt;p&gt;For our case, those decisions are:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr17f78tm4th26o41tcui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr17f78tm4th26o41tcui.png" alt=" " width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep the order’s lifecycle intact
&lt;/h3&gt;

&lt;p&gt;We do not need to expose every partial combination as another &lt;code&gt;OrderState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The order can remain in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while a smaller coordination component tracks the branch results.&lt;/p&gt;

&lt;p&gt;This preserves the lifecycle from Part V:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAID
    ↓ CHECK_SHIPPING
CHECKING_SHIPPING
    ↓ combined positive result
READY_TO_SHIP
    ↓ SHIP_ORDER
SHIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The meaning of the positive result is now broader.&lt;/p&gt;

&lt;p&gt;Previously, &lt;code&gt;SHIPPING_AVAILABLE&lt;/code&gt; meant that the carrier inquiry succeeded. In this version, it means that &lt;strong&gt;both required availability checks succeeded&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is an intentional change in the operation’s contract. A raw carrier response must no longer go directly to the order as &lt;code&gt;SHIPPING_AVAILABLE&lt;/code&gt;. It must first pass through the component that combines the results.&lt;/p&gt;

&lt;p&gt;The outer &lt;code&gt;ShippingCheckResult&lt;/code&gt; envelope can remain unchanged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order receives one combined answer through the same interface.&lt;/p&gt;

&lt;p&gt;Partial progress belongs inside the check, not in the order’s public lifecycle vocabulary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give branch results their own vocabulary
&lt;/h3&gt;

&lt;p&gt;Let’s distinguish where a reply came from and what it reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replace&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;CARRIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;carrier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;INVENTORY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inventory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;AVAILABLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;available&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;UNAVAILABLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unavailable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;FAILED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BranchResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CheckBranch&lt;/span&gt;
    &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;UNAVAILABLE&lt;/code&gt; means that the lookup completed and returned a negative answer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FAILED&lt;/code&gt; means that an expected service failure prevented us from obtaining an answer.&lt;/p&gt;

&lt;p&gt;Those outcomes both prevent readiness under our current policy, but they do not say the same thing.&lt;/p&gt;

&lt;p&gt;We can now retain partial progress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckProgress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ShippingCheck&lt;/span&gt;
    &lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;conclusion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The existing &lt;code&gt;ShippingCheck&lt;/code&gt; contains the order identifier, request identifier, and copied delivery address.&lt;/p&gt;

&lt;p&gt;The two branch fields initially contain &lt;code&gt;None&lt;/code&gt;, meaning no result has been accepted for that branch.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;conclusion&lt;/code&gt; is also initially absent. Once set, this check is closed.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;
&lt;span class="n"&gt;carrier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AVAILABLE&lt;/span&gt;
&lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;conclusion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means that one prerequisite has succeeded and the check is still waiting.&lt;/p&gt;

&lt;p&gt;This is not “half an order transition.” It is a complete, valid configuration of the coordination process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decide what failure means before writing the handler
&lt;/h3&gt;

&lt;p&gt;There are several reasonable completion policies.&lt;/p&gt;

&lt;p&gt;We could wait for every result, even after one branch fails. That would collect more diagnostic information.&lt;/p&gt;

&lt;p&gt;We could stop once success becomes impossible. That would avoid waiting for an answer that can no longer change the overall decision.&lt;/p&gt;

&lt;p&gt;For these read-only checks, we will choose the second policy:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Accepted branch result&lt;/th&gt;
&lt;th&gt;Coordinator action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First positive result&lt;/td&gt;
&lt;td&gt;Record it and continue waiting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second distinct positive result&lt;/td&gt;
&lt;td&gt;Conclude &lt;code&gt;SHIPPING_AVAILABLE&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any negative result&lt;/td&gt;
&lt;td&gt;Conclude &lt;code&gt;SHIPPING_UNAVAILABLE&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any expected lookup failure&lt;/td&gt;
&lt;td&gt;Conclude &lt;code&gt;SHIPPING_CHECK_FAILED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate of an accepted result&lt;/td&gt;
&lt;td&gt;Do not count it again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Result for another request&lt;/td&gt;
&lt;td&gt;Do not apply it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once a conclusion exists, later replies cannot reopen the check.&lt;/p&gt;

&lt;p&gt;If different failures compete, the first decisive result processed by the coordinator determines the reported outcome. This is an ordering policy, not a claim that the same failure detail will win under every possible schedule.&lt;/p&gt;

&lt;p&gt;For successful checks, however, the completion order must not matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apply one branch result at a time
&lt;/h3&gt;

&lt;p&gt;The following function receives the current progress and one reply. It returns updated progress and, only when the check first concludes, a combined result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CheckProgress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BranchResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CheckProgress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ShippingCheckResult&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Result belongs to a different order.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown check branch.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown check outcome.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conclusion&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;carrier&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CARRIER&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Conflicting result for one branch.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CARRIER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FAILED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_CHECK_FAILED&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UNAVAILABLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_UNAVAILABLE&lt;/span&gt;

    &lt;span class="nf"&gt;elif &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;carrier&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AVAILABLE&lt;/span&gt;
        &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AVAILABLE&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_AVAILABLE&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conclusion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function does not call either service. It does not change the order. It calculates the consequence of receiving one result.&lt;/p&gt;

&lt;p&gt;An identical duplicate leaves progress unchanged.&lt;/p&gt;

&lt;p&gt;A contradictory second answer for an already recorded branch raises an error while the group is still open. Our protocol expects one final answer per branch. It does not support silently revising an earlier answer.&lt;/p&gt;

&lt;p&gt;After the group closes, subsequent replies are irrelevant to its decision. A production diagnostic path could still record them, but they cannot authorize another transition.&lt;/p&gt;

&lt;p&gt;We now have a small stateful process inside the larger workflow.&lt;/p&gt;

&lt;p&gt;Its control condition is whether it has concluded. Its supporting data identifies the request and the accepted branch outcomes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the join without relying on task scheduling
&lt;/h3&gt;

&lt;p&gt;Let’s construct a request and its two successful replies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check-A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;carrier_available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BranchResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CARRIER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AVAILABLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;inventory_available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;carrier_available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INVENTORY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now test both possible success orders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carrier_available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inventory_available&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventory_available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;carrier_available&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CheckProgress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conclusion&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_AVAILABLE&lt;/span&gt;

    &lt;span class="n"&gt;closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;

    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repeated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;repeated&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neither branch can complete the join alone. Either can complete it when its counterpart has already succeeded.&lt;/p&gt;

&lt;p&gt;The last assertions verify another property: a closed check does not produce a second combined result when a reply repeats.&lt;/p&gt;

&lt;p&gt;That is a local property of this coordinator instance. It is not an exactly-once delivery guarantee across crashes or restarts.&lt;/p&gt;

&lt;p&gt;Now test the counter mistake directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CheckProgress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;carrier_available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;after_first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;

&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;carrier_available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;after_first&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two carrier messages still satisfy only the carrier prerequisite.&lt;/p&gt;

&lt;p&gt;An inventory result from an older request must also remain irrelevant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;stale_inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inventory_available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;older-check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stale_inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;after_first&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, a negative answer closes the current check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;inventory_unavailable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inventory_available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UNAVAILABLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory_unavailable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_UNAVAILABLE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a later positive reply arrives, it does not reverse this conclusion. Starting another inquiry requires a new request identifier and a new &lt;code&gt;CheckProgress&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  An older model for independent conditions
&lt;/h3&gt;

&lt;p&gt;Carl Adam Petri’s 1962 dissertation, &lt;em&gt;Kommunikation mit Automaten&lt;/em&gt;, investigated the foundations of communication between computational mechanisms.[3]&lt;/p&gt;

&lt;p&gt;Petri nets provide a way to model concurrent processes using &lt;strong&gt;places&lt;/strong&gt;, &lt;strong&gt;transitions&lt;/strong&gt;, and &lt;strong&gt;tokens&lt;/strong&gt;. Places describe conditions, tokens mark which conditions currently hold, and transitions consume and produce tokens. The token distribution is called a &lt;em&gt;marking&lt;/em&gt;.[4]&lt;/p&gt;

&lt;p&gt;The successful path of our check can be sketched as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dot"&gt;&lt;code&gt;                 &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;check&lt;/span&gt; &lt;span class="nv"&gt;requested&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
                         &lt;span class="err"&gt;│&lt;/span&gt;
                       &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                    &lt;span class="err"&gt;┌────┴────┐&lt;/span&gt;
                    &lt;span class="err"&gt;▼&lt;/span&gt;         &lt;span class="err"&gt;▼&lt;/span&gt;
          &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;carrier&lt;/span&gt; &lt;span class="nv"&gt;pending&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inventory&lt;/span&gt; &lt;span class="nv"&gt;pending&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
                    &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;│&lt;/span&gt;
          &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;carrier&lt;/span&gt; &lt;span class="nv"&gt;succeeds&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;inventory&lt;/span&gt; &lt;span class="nv"&gt;succeeds&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                    &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;│&lt;/span&gt;
                    &lt;span class="err"&gt;▼&lt;/span&gt;         &lt;span class="err"&gt;▼&lt;/span&gt;
           &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;carrier&lt;/span&gt; &lt;span class="nv"&gt;passed&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inventory&lt;/span&gt; &lt;span class="nv"&gt;passed&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
                    &lt;span class="err"&gt;└────┬────┘&lt;/span&gt;
                       &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;join&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                         &lt;span class="err"&gt;│&lt;/span&gt;
                         &lt;span class="err"&gt;▼&lt;/span&gt;
                   &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;checks&lt;/span&gt; &lt;span class="nv"&gt;passed&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parentheses represent places; brackets represent transitions.&lt;/p&gt;

&lt;p&gt;The join requires a token from both successful branches. Firing it consumes those prerequisites and produces the combined completion condition.[4]&lt;/p&gt;

&lt;p&gt;This drawing shows only the successful path. Negative results and abandonment need additional paths.&lt;/p&gt;

&lt;p&gt;Our Python coordinator is not a general Petri-net engine. But it applies the same useful distinction: independent conditions can become true in either order, while a later action requires their conjunction.&lt;/p&gt;

&lt;p&gt;The diagram does not make network calls atomic. It describes when the modeled continuation becomes eligible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Did we escape state machines?
&lt;/h3&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;A bounded set of branch outcomes can still be represented by a finite machine with a state for every combination.&lt;/p&gt;

&lt;p&gt;For two branches, that may even be manageable.&lt;/p&gt;

&lt;p&gt;The problem is not that a flat FSM is incapable of describing the behavior. The problem is that manually naming every combination makes the independent structure harder to see.&lt;/p&gt;

&lt;p&gt;Our representation keeps that structure visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Carrier progress
+
Inventory progress
+
Completion rule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full configuration still has combinations. We have organized them rather than eliminated them.&lt;/p&gt;

&lt;p&gt;This is also why the join is more precise than another large lifecycle label. It states which conditions must coexist before the process continues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the branches concurrently without letting them mutate the order
&lt;/h3&gt;

&lt;p&gt;We can now connect the decision logic to asynchronous work.&lt;/p&gt;

&lt;p&gt;Python’s &lt;code&gt;TaskGroup&lt;/code&gt; starts and owns related tasks, waits for their completion, and propagates unexpected failures. Its task management does not decide whether our business prerequisites passed; that remains the coordinator’s responsibility.[1]&lt;/p&gt;

&lt;p&gt;The following executor replaces the single-carrier executor from Part V.&lt;/p&gt;

&lt;p&gt;Both adapters receive the immutable &lt;code&gt;ShippingCheck&lt;/code&gt;. The carrier adapter uses its destination. The inventory adapter resolves the fixed item requirements using its order identifier.&lt;/p&gt;

&lt;p&gt;Expected service failures are translated into &lt;code&gt;AvailabilityLookupError&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Awaitable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AvailabilityLookupError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="n"&gt;AvailabilityLookup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;Awaitable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now execute and combine the two branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AvailabilityLookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AvailabilityLookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CheckProgress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;replies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BranchResult&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_branch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AvailabilityLookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;AvailabilityLookupError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FAILED&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Availability lookup must return bool.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AVAILABLE&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;CheckOutcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UNAVAILABLE&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;replies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;BranchResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ShippingCheckResult&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TaskGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;run_branch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CARRIER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;run_branch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CheckBranch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INVENTORY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;replies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accept_branch_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;replies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task_done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scheduling callback from Part V now supplies both adapters when it starts this executor.&lt;/p&gt;

&lt;p&gt;Neither branch receives the mutable order. Each produces a &lt;code&gt;BranchResult&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One coordinator processes those results sequentially and updates its own local &lt;code&gt;CheckProgress&lt;/code&gt;. Only the combined result enters the order’s inbox.&lt;/p&gt;

&lt;p&gt;The private queue has room for the two messages these adapters can produce. Its FIFO behavior orders arrivals to this coordinator; it does not impose an order on events in remote services.[5]&lt;/p&gt;

&lt;p&gt;We have separated two forms of activity:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;External work overlaps. Local decisions about the collected results remain sequential.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A finished task is not necessarily a successful prerequisite
&lt;/h3&gt;

&lt;p&gt;An inventory adapter returning &lt;code&gt;False&lt;/code&gt; has completed normally as a Python task.&lt;/p&gt;

&lt;p&gt;It has not satisfied the inventory prerequisite.&lt;/p&gt;

&lt;p&gt;That distinction is why we translate the return value into an explicit outcome rather than treating task completion as business success.&lt;/p&gt;

&lt;p&gt;The executor catches only the expected &lt;code&gt;AvailabilityLookupError&lt;/code&gt;. An invalid return type or another programming error is not silently converted into “unavailable.”&lt;/p&gt;

&lt;p&gt;On a decisive negative result or expected lookup failure, the coordinator requests cancellation of unfinished sibling tasks. The task group waits for them to finish their cleanup before the executor publishes the combined result.[1]&lt;/p&gt;

&lt;p&gt;The adapters must use bounded I/O waits and cooperate with cancellation. A task that blocks the event loop or suppresses cancellation can still delay cleanup.&lt;/p&gt;

&lt;p&gt;The task group gives the asynchronous work a lifetime boundary. It does not make arbitrary adapter code reliable.&lt;/p&gt;

&lt;p&gt;For a simple case with no need to inspect partial results, a task group followed by an &lt;code&gt;all()&lt;/code&gt; check could be enough. Our explicit coordinator earns its place when branch identity, duplicates, stale messages, and early completion rules need to be examined and tested separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens to the timeout from Part V?
&lt;/h3&gt;

&lt;p&gt;The order’s existing timeout still applies to the entire &lt;code&gt;ShippingCheck&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is associated with the same request identifier, not separately with “the first branch” or “the second branch.”&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Order behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Check A begins&lt;/td&gt;
&lt;td&gt;Enter &lt;code&gt;CHECKING_SHIPPING&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Carrier A succeeds&lt;/td&gt;
&lt;td&gt;No aggregate result yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;The overall timeout for A is handled&lt;/td&gt;
&lt;td&gt;Return to &lt;code&gt;PAID&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Inventory A succeeds&lt;/td&gt;
&lt;td&gt;Coordinator may produce a result for A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;That result reaches the order&lt;/td&gt;
&lt;td&gt;Ignore it because A is no longer outstanding&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The outer handler from Part V still checks both the order’s state and the request identifier.&lt;/p&gt;

&lt;p&gt;Even a correctly combined result can arrive too late to affect the order.&lt;/p&gt;

&lt;p&gt;An overall timeout does not automatically cancel the executor. The surrounding runtime may cancel that task to stop unnecessary work, but the correlation check remains necessary because completion and cancellation can race.&lt;/p&gt;

&lt;p&gt;Nor does returning to &lt;code&gt;PAID&lt;/code&gt; restore or remove anything in another service. That is safe here because both branches were explicitly defined as read-only inquiries.&lt;/p&gt;

&lt;p&gt;We have preserved Part V’s distinction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stopping our wait is not proof that remote work stopped.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Both positive replies are not a distributed transaction
&lt;/h3&gt;

&lt;p&gt;Suppose the carrier answers at one moment and inventory answers slightly later.&lt;/p&gt;

&lt;p&gt;Our join records two positive observations. It does not prove that both conditions will remain true when another operation eventually tries to book a shipment or reserve stock.&lt;/p&gt;

&lt;p&gt;It also does not create one simultaneous snapshot across two services.&lt;/p&gt;

&lt;p&gt;For this lesson, the combined result authorizes the next step of our local simulation under the fixed-input assumptions. A production policy might additionally require quotation expiry, inventory holds, or revalidation when committing the real operation.&lt;/p&gt;

&lt;p&gt;Those requirements should be introduced explicitly.&lt;/p&gt;

&lt;p&gt;Otherwise, the reassuring word &lt;code&gt;READY&lt;/code&gt; can claim more than the system actually established.&lt;/p&gt;

&lt;h3&gt;
  
  
  Now replace the stock check with a reservation
&lt;/h3&gt;

&lt;p&gt;We can now see why the earlier distinction mattered.&lt;/p&gt;

&lt;p&gt;Imagine that the inventory branch actually reserves stock:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inventory reservation succeeds.
Carrier check fails.
The combined operation cannot proceed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Discarding &lt;code&gt;CheckProgress&lt;/code&gt; would not release the reservation.&lt;/p&gt;

&lt;p&gt;Cancelling a local task would not necessarily release it either. The inventory service may already have committed the change.&lt;/p&gt;

&lt;p&gt;We need another operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReserveInventory
        ↓ later failure
ReleaseReservation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;compensating action&lt;/strong&gt; counteracts a completed business operation when a larger process cannot finish. It is application-specific, may fail itself, and does not necessarily restore the exact earlier world.[6]&lt;/p&gt;

&lt;p&gt;For this example, a release operation would need the reservation identifier. If release fails, the system must retain enough information to continue recovery rather than quietly return to an ordinary state.&lt;/p&gt;

&lt;p&gt;An even harder case is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reservation succeeds remotely.
Its response is lost.
The local request times out.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the system does not know whether a reservation exists.&lt;/p&gt;

&lt;p&gt;That requires durable request identity, a way to reconcile the remote outcome, and safe retry or compensation rules. A join condition alone does not supply those mechanisms.&lt;/p&gt;

&lt;p&gt;This is why our current executor must not be renamed &lt;code&gt;reserve_inventory&lt;/code&gt; without changing its contract and recovery design.&lt;/p&gt;

&lt;p&gt;We have implemented concurrent observations. We have not implemented a distributed transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  What must remain true as we add more branches?
&lt;/h3&gt;

&lt;p&gt;The code is small, but its correctness depends on several explicit rules.&lt;/p&gt;

&lt;p&gt;Each run has one order identifier and one request identifier. Each required branch contributes at most one accepted final result. Success is produced only after every required branch succeeds. A closed run cannot be reopened by a duplicate or late reply.&lt;/p&gt;

&lt;p&gt;These rules are independent of which branch happens to finish first.&lt;/p&gt;

&lt;p&gt;They also determine what should be tested. Beyond the success permutations, useful cases include a failure before any success, a failure after one success, conflicting replies while a run is open, a reply for another order, and a result arriving after the outer order has timed out.&lt;/p&gt;

&lt;p&gt;The runtime tests should separately check that unexpected exceptions propagate and that cancelling the executor cleans up its child tasks. Neither concern should be hidden inside the pure combination logic.&lt;/p&gt;

&lt;p&gt;The current implementation still stores its progress in memory. A process crash loses the partial results and the queued output. Producing at most one result during one invocation is not durable exactly-once execution.&lt;/p&gt;

&lt;p&gt;That limitation has not changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The order and the concurrent work now have different responsibilities
&lt;/h3&gt;

&lt;p&gt;The order’s state machine answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this combined outcome applicable to the request the order is currently waiting for?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The coordinator answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do the results of the required branches justify producing that combined outcome?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The adapters answer their own service questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu6le3vylu4axbpbb3mkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu6le3vylu4axbpbb3mkw.png" alt=" " width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The coordinator is stateful, but it does not own the order’s lifecycle.&lt;/p&gt;

&lt;p&gt;The adapters perform work, but they do not decide when the order becomes ready.&lt;/p&gt;

&lt;p&gt;That division keeps independent work from becoming independent mutation of the same record.&lt;/p&gt;

&lt;h3&gt;
  
  
  But who protects that ownership boundary?
&lt;/h3&gt;

&lt;p&gt;Our order consumer processes its inbox sequentially.&lt;/p&gt;

&lt;p&gt;Yet the code that created the mutable &lt;code&gt;Order&lt;/code&gt; may still hold a reference to it. Another component could assign its status without sending a message. A queued command could also contain a mutable object that its sender changes after submission.&lt;/p&gt;

&lt;p&gt;More queues would not automatically prevent either problem.&lt;/p&gt;

&lt;p&gt;We have learned how to collect independent results into one decision. The next problem is making sure that one authority actually controls the state affected by that decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When many orders are active, who owns each order’s record, who may change it, and how should every other component communicate with that owner?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;[1]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html" rel="noopener noreferrer"&gt;Coroutines and Tasks&lt;/a&gt;&lt;/em&gt;. Concurrent task execution, task groups, exception propagation, and cancellation. The example uses APIs available in Python 3.11 and later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[2]&lt;/strong&gt; Gregor Hohpe and Bobby Woolf, &lt;a href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/Aggregator.html" rel="noopener noreferrer"&gt;“Aggregator”&lt;/a&gt;, &lt;em&gt;Enterprise Integration Patterns&lt;/em&gt;. Correlation, completeness conditions, and combining related messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[3]&lt;/strong&gt; Carl Adam Petri, &lt;em&gt;&lt;a href="https://edoc.sub.uni-hamburg.de/informatik/volltexte/2011/160/" rel="noopener noreferrer"&gt;Kommunikation mit Automaten&lt;/a&gt;&lt;/em&gt;, doctoral dissertation, 1962. University of Hamburg archival record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[4]&lt;/strong&gt; Carl Adam Petri and Wolfgang Reisig, &lt;a href="https://www.scholarpedia.org/article/Petri_net" rel="noopener noreferrer"&gt;“Petri Net”&lt;/a&gt;, &lt;em&gt;Scholarpedia&lt;/em&gt;, 3(4):6477, 2008. Places, transitions, tokens, and the modeling of concurrent processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[5]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/asyncio-queue.html" rel="noopener noreferrer"&gt;asyncio Queues&lt;/a&gt;&lt;/em&gt;. FIFO behavior, bounded queues, and task bookkeeping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[6]&lt;/strong&gt; Microsoft, &lt;em&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction" rel="noopener noreferrer"&gt;Compensating Transaction Pattern&lt;/a&gt;&lt;/em&gt;, Azure Architecture Center. Application-specific compensation, recovery information, and failures during compensating work.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>systemdesign</category>
      <category>programming</category>
    </item>
    <item>
      <title>Part V - But How Does the Machine Wait for Something That Happens Later?</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:21:31 +0000</pubDate>
      <link>https://dev.to/canburaks/part-v-but-how-does-the-machine-wait-for-something-that-happens-later-2k6j</link>
      <guid>https://dev.to/canburaks/part-v-but-how-does-the-machine-wait-for-something-that-happens-later-2k6j</guid>
      <description>&lt;p&gt;Our shipping transition now considers more than the order’s status.&lt;/p&gt;

&lt;p&gt;It requires a valid paid order and a supported delivery address. The operation that changes the order and the function that lists available actions consult the same transition definition.&lt;/p&gt;

&lt;p&gt;That works because the address guard can answer from information already available in the program.&lt;/p&gt;

&lt;p&gt;But Part IV ended with a different requirement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The carrier must confirm whether it can accept a shipment to this destination.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That answer may arrive later. The request may fail. Another command may arrive while we wait.&lt;/p&gt;

&lt;p&gt;How do we represent the order during that interval?&lt;/p&gt;

&lt;h3&gt;
  
  
  Start by making the external question explicit
&lt;/h3&gt;

&lt;p&gt;We should first distinguish three operations that are easy to collapse into one:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;What it establishes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check availability&lt;/td&gt;
&lt;td&gt;The carrier reports whether it currently supports the proposed shipment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Book a shipment&lt;/td&gt;
&lt;td&gt;The carrier accepts a request to arrange a shipment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirm dispatch&lt;/td&gt;
&lt;td&gt;There is evidence that the package has actually been dispatched.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this part, we will implement only a &lt;strong&gt;read-only availability inquiry&lt;/strong&gt;. It reserves nothing and dispatches nothing. Our existing &lt;code&gt;ship_order()&lt;/code&gt; operation will remain a local simulation.&lt;/p&gt;

&lt;p&gt;This boundary matters when handling failures. Repeating a read-only inquiry is different from potentially booking the same package twice.&lt;/p&gt;

&lt;p&gt;We will also keep the example’s availability policy fixed for an unchanged destination. Real bookings may require fresh validation, expiring quotations, or capacity reservations. Those are additional requirements, not guarantees we get from recording an availability response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not just wait inside the shipping function?
&lt;/h3&gt;

&lt;p&gt;We could call the carrier, wait for an answer, and then continue:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgarp5wjcuk2cfa8mjl7l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgarp5wjcuk2cfa8mjl7l.png" alt=" " width="799" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a small request that has no other work to handle while waiting, this may be sufficient. A state machine does not require a message queue merely because a network call exists.&lt;/p&gt;

&lt;p&gt;But our current order would remain &lt;code&gt;PAID&lt;/code&gt; throughout the wait.&lt;/p&gt;

&lt;p&gt;Another caller could not distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Paid, with no availability inquiry started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Paid, with an inquiry already in progress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both could attempt to start the operation.&lt;/p&gt;

&lt;p&gt;Making the function asynchronous does not resolve that modeling problem. In Python, an &lt;code&gt;await&lt;/code&gt; can suspend a task while the event loop runs other tasks. It does not, by itself, establish which task owns the order or prevent another task from acting on the same record.[1]&lt;/p&gt;

&lt;p&gt;We need to represent the unfinished work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give waiting a place in the lifecycle
&lt;/h3&gt;

&lt;p&gt;Let’s separate asking the question from using its answer.&lt;/p&gt;

&lt;p&gt;We add a &lt;code&gt;CHECK_SHIPPING&lt;/code&gt; command. An accepted command starts an availability inquiry and moves the order into &lt;code&gt;CHECKING_SHIPPING&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A positive response moves it to &lt;code&gt;READY_TO_SHIP&lt;/code&gt;. Only then does our simulated &lt;code&gt;SHIP_ORDER&lt;/code&gt; command become eligible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwgpp95cuuw5td5wqgpe4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwgpp95cuuw5td5wqgpe4.png" alt=" " width="798" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This deliberately changes the rule from Part IV. &lt;code&gt;PAID + SHIP_ORDER&lt;/code&gt; is no longer sufficient.&lt;/p&gt;

&lt;p&gt;The new states represent different behavior:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;What the machine should accept next&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PAID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A request to check shipping availability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CHECKING_SHIPPING&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A result for the outstanding inquiry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;READY_TO_SHIP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The simulated shipping command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SHIPPED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No further command in our current lifecycle&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We are not adding states merely because an operation takes time. We are adding them because the set of eligible inputs changes while that operation is outstanding.&lt;/p&gt;

&lt;p&gt;Replace the state and command definitions with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;CREATED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;PAID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;checking_shipping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;READY_TO_SHIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ready_to_ship&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;SHIPPED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;capture_payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;CHECK_SHIPPING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check_shipping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ship_order&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;READY_TO_SHIP&lt;/code&gt; does not claim that a package has been booked or dispatched. It records that our prerequisite inquiry succeeded.&lt;/p&gt;

&lt;p&gt;An answer to a question is not the completion of the entire workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remember what we are waiting for
&lt;/h3&gt;

&lt;p&gt;A waiting state alone is insufficient.&lt;/p&gt;

&lt;p&gt;Suppose the carrier returns an answer. Which order does it concern? Which inquiry? Which destination did we submit?&lt;/p&gt;

&lt;p&gt;Let’s retain the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request contains a copy of the destination, not a reference to the mutable order.&lt;/p&gt;

&lt;p&gt;We then extend &lt;code&gt;Order&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;shipping_check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Payment&lt;/code&gt; remains unchanged.&lt;/p&gt;

&lt;p&gt;While checking availability, &lt;code&gt;shipping_check&lt;/code&gt; identifies the outstanding request. After a successful response, we retain it to identify the destination that was checked.&lt;/p&gt;

&lt;p&gt;This is an example of a &lt;strong&gt;correlation identifier&lt;/strong&gt;: a value carried from a request into its reply so the receiver can connect the two. &lt;em&gt;Enterprise Integration Patterns&lt;/em&gt; describes this request–reply relationship explicitly.[2]&lt;/p&gt;

&lt;p&gt;The order identifier answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which order?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The request identifier answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which particular inquiry for that order?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are not interchangeable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extend the invariants with the new states
&lt;/h3&gt;

&lt;p&gt;The payment rule still applies: every state after &lt;code&gt;CREATED&lt;/code&gt; requires the captured payment record.&lt;/p&gt;

&lt;p&gt;We also need rules for the shipping inquiry:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lifecycle state&lt;/th&gt;
&lt;th&gt;Required shipping-check data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;CREATED&lt;/code&gt;, &lt;code&gt;PAID&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;No active or accepted check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CHECKING_SHIPPING&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The request currently awaiting a result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;READY_TO_SHIP&lt;/code&gt;, &lt;code&gt;SHIPPED&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The request whose positive result was accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this model, the recorded destination must match the order’s destination. We have not introduced an address-editing operation that invalidates and restarts a check.&lt;/p&gt;

&lt;p&gt;Replace the validator with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status must be an OrderState member.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A created order cannot contain a captured payment.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This state requires a Payment record.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;needs_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READY_TO_SHIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shipping_check&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;needs_check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This state requires a ShippingCheck.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;
            &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;
            &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_address&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_address&lt;/span&gt;
        &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Shipping check does not match the order.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No shipping check belongs in this state.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents a result for one destination from being silently used after someone changes the order to another destination.&lt;/p&gt;

&lt;p&gt;It does not prove that the carrier sent a positive response. That depends on how we control the transition into &lt;code&gt;READY_TO_SHIP&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As before, validating a snapshot and validating the path into that snapshot are separate responsibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  A reply is an event, not another shipping command
&lt;/h3&gt;

&lt;p&gt;The user requests a check. The carrier reports an outcome.&lt;/p&gt;

&lt;p&gt;Let’s give those outcomes names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;SHIPPING_AVAILABLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipping_available&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;SHIPPING_UNAVAILABLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipping_unavailable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;SHIPPING_CHECK_FAILED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipping_check_failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;SHIPPING_CHECK_TIMED_OUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipping_check_timed_out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They have different meanings.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SHIPPING_UNAVAILABLE&lt;/code&gt; means the inquiry completed and returned a negative answer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SHIPPING_CHECK_FAILED&lt;/code&gt; means an expected lookup failure prevented us from obtaining an answer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SHIPPING_CHECK_TIMED_OUT&lt;/code&gt; means our application stopped waiting for that inquiry. It does not mean the carrier answered negatively.&lt;/p&gt;

&lt;p&gt;The last event comes from our timer, not the carrier.&lt;/p&gt;

&lt;p&gt;All four can use the same envelope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this part, a negative answer, a lookup failure, or a timeout returns the order to &lt;code&gt;PAID&lt;/code&gt;. That means no usable availability confirmation is retained, and another check may be requested.&lt;/p&gt;

&lt;p&gt;This policy is safe for our &lt;strong&gt;read-only inquiry&lt;/strong&gt;. We must not generalize it to a shipment-booking request: a lost booking response could leave an actual booking in the external system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep the new behavior in the transition table
&lt;/h3&gt;

&lt;p&gt;We retain the &lt;code&gt;Transition&lt;/code&gt; class and the local &lt;code&gt;has_supported_address()&lt;/code&gt; guard from Part IV.&lt;/p&gt;

&lt;p&gt;The local guard remains useful as an initial filter. It can reject a destination before we contact the carrier. Passing it no longer claims that all shipping conditions have been satisfied.&lt;/p&gt;

&lt;p&gt;Replace the transition table with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MappingProxyType&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECK_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;has_supported_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;rejection_reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The delivery address is not supported.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READY_TO_SHIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_AVAILABLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READY_TO_SHIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_UNAVAILABLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_CHECK_FAILED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_CHECK_TIMED_OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commands and events are now both inputs to the machine. We keep their types separate because requesting an operation and reporting a result are different responsibilities.&lt;/p&gt;

&lt;p&gt;Update the selector accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trigger must be an OrderCommand or OrderEvent.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot handle &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;while the order is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rejection_reason&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;capture_payment()&lt;/code&gt; and &lt;code&gt;ship_order()&lt;/code&gt; from Part IV can remain unchanged. Their destinations and eligibility now come from this table.&lt;/p&gt;

&lt;p&gt;The previous &lt;code&gt;available_actions()&lt;/code&gt; implementation also continues to work: it iterates over &lt;code&gt;OrderCommand&lt;/code&gt;, not &lt;code&gt;OrderEvent&lt;/code&gt;. Carrier outcomes therefore do not appear as buttons a user may press.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start the check before starting the external work
&lt;/h3&gt;

&lt;p&gt;The new operation prepares a request and records that the machine is waiting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid4&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_shipping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECK_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nb"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shipping_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned value describes work to perform. The function does not contact the carrier.&lt;/p&gt;

&lt;p&gt;After it returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;
&lt;span class="n"&gt;shipping_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;prepared&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only then should another component submit the inquiry.&lt;/p&gt;

&lt;p&gt;Why this order?&lt;/p&gt;

&lt;p&gt;If the external component can produce a result before we record the pending request, the result handler could receive an answer the order does not yet recognize.&lt;/p&gt;

&lt;p&gt;We are establishing local state before allowing external work to respond.&lt;/p&gt;

&lt;p&gt;This is still an in-memory sequence of assignments. It does not survive a crash between recording the request and submitting it. We will need a durable boundary later.&lt;/p&gt;

&lt;p&gt;For now, it makes the normal execution order explicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accept a result only for the current inquiry
&lt;/h3&gt;

&lt;p&gt;Receiving &lt;code&gt;SHIPPING_AVAILABLE&lt;/code&gt; is not enough.&lt;/p&gt;

&lt;p&gt;A late answer for an older request must not complete a newer request.&lt;/p&gt;

&lt;p&gt;Our handler therefore checks both the lifecycle state and request identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;apply_shipping_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Result was routed to the wrong order.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown shipping result event.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shipping_check&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shipping_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;True&lt;/code&gt; means that the result was applied.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;False&lt;/code&gt; means that this well-formed result no longer belongs to the active inquiry. It does not mean shipping failed.&lt;/p&gt;

&lt;p&gt;We treat a wrong order identifier differently: that is a routing error, not an obsolete reply.&lt;/p&gt;

&lt;p&gt;On success, the request remains attached to the order and the state becomes &lt;code&gt;READY_TO_SHIP&lt;/code&gt;. On an unsuccessful outcome, the request is cleared and the order returns to &lt;code&gt;PAID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The handler does not perform shipment as a side effect of receiving availability. That remains a separate command.&lt;/p&gt;

&lt;h3&gt;
  
  
  A late answer can be valid and still be irrelevant
&lt;/h3&gt;

&lt;p&gt;Consider this sequence:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Input or action&lt;/th&gt;
&lt;th&gt;Current condition afterward&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Start inquiry A&lt;/td&gt;
&lt;td&gt;Waiting for A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;A times out locally&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PAID&lt;/code&gt;, no accepted check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Start inquiry B&lt;/td&gt;
&lt;td&gt;Waiting for B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Positive response for A arrives&lt;/td&gt;
&lt;td&gt;Still waiting for B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Positive response for B arrives&lt;/td&gt;
&lt;td&gt;&lt;code&gt;READY_TO_SHIP&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The answer for A may accurately describe the carrier’s response to A. It is nevertheless irrelevant to the inquiry we are now waiting for.&lt;/p&gt;

&lt;p&gt;Checking only the order identifier would accept it.&lt;/p&gt;

&lt;p&gt;Checking only &lt;code&gt;CHECKING_SHIPPING&lt;/code&gt; would also accept it.&lt;/p&gt;

&lt;p&gt;We need the request identifier because the machine may revisit the same waiting state many times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Being in the right state is necessary. Receiving the right result is necessary too.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Who calls the result handler?
&lt;/h3&gt;

&lt;p&gt;So far, our domain functions are synchronous. They inspect the order, decide, update it, and return.&lt;/p&gt;

&lt;p&gt;The network interaction can run separately and produce a message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Awaitable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CarrierLookupError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Awaitable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;CarrierLookupError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_CHECK_FAILED&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Carrier lookup must return a bool.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_AVAILABLE&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_UNAVAILABLE&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The supplied &lt;code&gt;carrier&lt;/code&gt; adapter performs the actual lookup. Its contract is to return a Boolean or translate an expected carrier or transport failure into &lt;code&gt;CarrierLookupError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We do not catch every exception. A programming error is not automatically a negative availability answer.&lt;/p&gt;

&lt;p&gt;More importantly, this function receives a frozen request not the mutable order. It can wait, fail, or finish without directly changing lifecycle state.&lt;/p&gt;

&lt;p&gt;Its output goes into a queue.&lt;/p&gt;

&lt;p&gt;The component processing that queue decides whether the result still applies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Process one local reaction at a time
&lt;/h3&gt;

&lt;p&gt;We now need an execution rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For this order, finish handling one input before beginning the next local state-machine reaction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is &lt;strong&gt;run-to-completion&lt;/strong&gt; behavior.&lt;/p&gt;

&lt;p&gt;SCXML formalizes this boundary: processing an external event finishes its resulting internal steps before the next external event is handled. Its interpreter separately describes waiting for events and invoking external processes.[3]&lt;/p&gt;

&lt;p&gt;The useful lesson is not that we need XML. It is that a transition’s local work and an external operation’s lifetime are different intervals.&lt;/p&gt;

&lt;p&gt;For our order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Handle CHECK_SHIPPING:
    validate
    create request
    enter CHECKING_SHIPPING
    schedule external work
    return

Later, handle ShippingCheckResult:
    validate
    check request identity
    apply the permitted result
    return
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We do not hold the first reaction open until the carrier answers.&lt;/p&gt;

&lt;p&gt;That allows the machine to inspect another incoming command while the inquiry is outstanding. A duplicate check request is rejected because &lt;code&gt;CHECKING_SHIPPING&lt;/code&gt; has no &lt;code&gt;CHECK_SHIPPING&lt;/code&gt; transition.&lt;/p&gt;

&lt;h3&gt;
  
  
  A small event-processing loop
&lt;/h3&gt;

&lt;p&gt;Python’s &lt;code&gt;asyncio.Queue&lt;/code&gt; provides FIFO ordering and allows a consumer to wait when the queue is empty. It is intended for asynchronous code, not unsynchronized access from arbitrary threads.[4]&lt;/p&gt;

&lt;p&gt;We will use one consumer for one order. Commands and results enter the same queue.&lt;/p&gt;

&lt;p&gt;Payment capture needs its argument, so it gets a small message wrapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CapturePaymentRequested&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;


&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CapturePaymentRequested&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ShippingCheckResult&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The consumer delegates to the domain operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;start_check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;ShippingCheck&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;report_rejection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CapturePaymentRequested&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECK_SHIPPING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;check_shipping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;start_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="nf"&gt;apply_shipping_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unsupported message or missing command arguments.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;InvalidOrderOperation&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;report_rejection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task_done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;start_check&lt;/code&gt; is an injected scheduling function. It schedules &lt;code&gt;execute_check()&lt;/code&gt; and a timeout; it must return without waiting for the carrier. The surrounding application owns those tasks and their shutdown. Python task groups are one way to manage related asynchronous tasks.[1]&lt;/p&gt;

&lt;p&gt;&lt;code&gt;report_rejection&lt;/code&gt; reports an expected command rejection without changing the order. Invalid records and unexpected implementation errors are not swallowed.&lt;/p&gt;

&lt;p&gt;There is deliberately no &lt;code&gt;await&lt;/code&gt; inside the local handlers. The consumer waits for the next message only after the current handler returns.&lt;/p&gt;

&lt;p&gt;Under our single-event-loop assumption, and provided all order mutations go through this consumer, another coroutine cannot interleave its own mutation into those synchronous handlers.[1]&lt;/p&gt;

&lt;p&gt;That is a local execution guarantee not database atomicity, thread safety, or crash recovery.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;task_done()&lt;/code&gt; is queue bookkeeping. It does not mean that an external inquiry has finished or that anything was durably committed.[4]&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;None&lt;/code&gt; message is an orderly stop signal, intended to be sent after message producers have been stopped or drained. This loop is not a complete service-lifecycle implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Waiting for a result is not the same as blocking the consumer
&lt;/h3&gt;

&lt;p&gt;A tempting implementation would put this inside &lt;code&gt;run_order()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python could run other tasks during that wait. But this particular consumer would remain inside the handler and would not inspect its next queued message until the lookup finished.&lt;/p&gt;

&lt;p&gt;Alternatively, we could create a separate task for every message handler. That would allow handlers for the same mutable order to interleave.&lt;/p&gt;

&lt;p&gt;Our design chooses a different boundary:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;External work may overlap. Decisions that mutate this order do not.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The event loop runs asynchronous work. The order consumer serializes local reactions. The state machine defines what each reaction may do.&lt;/p&gt;

&lt;p&gt;Those are three related responsibilities, not three names for the same mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  A timeout is another input
&lt;/h3&gt;

&lt;p&gt;Suppose the carrier never answers.&lt;/p&gt;

&lt;p&gt;We need a local policy for ending the wait.&lt;/p&gt;

&lt;p&gt;A timer can enqueue the same kind of result envelope, using the request identifier it was created for. For example, a scheduler using our unbounded, same-event-loop queue could arrange:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_running_loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_later&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put_nowait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_CHECK_TIMED_OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;call_later()&lt;/code&gt; schedules a callback using the event loop’s clock. It does not guarantee an exact wall-clock execution instant.[5]&lt;/p&gt;

&lt;p&gt;The timer does not mutate the order. It produces an input that the owner will process.&lt;/p&gt;

&lt;p&gt;If the carrier response is processed first, the order leaves &lt;code&gt;CHECKING_SHIPPING&lt;/code&gt;. The later timeout becomes obsolete.&lt;/p&gt;

&lt;p&gt;If the timeout is processed first, that inquiry is abandoned. A later response for it becomes obsolete.&lt;/p&gt;

&lt;p&gt;This is an explicit policy: &lt;strong&gt;the first applicable outcome processed by the owner settles that inquiry&lt;/strong&gt;. It is not a rule based on the carrier’s remote timestamp.&lt;/p&gt;

&lt;p&gt;A hard deadline based on timestamps would require additional recorded timing information and a different acceptance rule.&lt;/p&gt;

&lt;p&gt;We could cancel the timer after accepting a response to avoid unnecessary work. But cancellation cannot be our only protection against stale timeout events. SCXML’s cancellation semantics acknowledge the same issue: a delayed event may already have been delivered when cancellation is attempted.[3]&lt;/p&gt;

&lt;p&gt;The request check remains the correctness boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test event sequences, not network timing
&lt;/h3&gt;

&lt;p&gt;We can test these rules without making a network call or waiting five seconds.&lt;/p&gt;

&lt;p&gt;Begin with a paid order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit_card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment-81&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;120.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start inquiry A, then deliver its timeout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;check_shipping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;applied&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;apply_shipping_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_CHECK_TIMED_OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;applied&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shipping_check&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start inquiry B. The old positive response must not complete it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;check_shipping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;applied&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;apply_shipping_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_AVAILABLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;applied&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHECKING_SHIPPING&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shipping_check&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now deliver the result that actually belongs to B:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;apply_shipping_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_AVAILABLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READY_TO_SHIP&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even B’s own timeout is now too late:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;apply_shipping_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ShippingCheckResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPING_CHECK_TIMED_OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;READY_TO_SHIP&lt;/span&gt;

&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests control the input order directly. They verify the behavior we chose rather than depending on a convenient scheduler race.&lt;/p&gt;

&lt;p&gt;Other important sequences include duplicate check commands while waiting, duplicate replies, negative answers, lookup failures, results routed to the wrong order, and attempted shipping before confirmation.&lt;/p&gt;

&lt;h3&gt;
  
  
  What ordering does the queue actually provide?
&lt;/h3&gt;

&lt;p&gt;FIFO ordering means the consumer receives messages in the order they enter this queue.[4]&lt;/p&gt;

&lt;p&gt;It does not establish the order in which remote events occurred.&lt;/p&gt;

&lt;p&gt;A carrier may generate a response before our deadline, yet network delay may cause its message to arrive after the timeout message. Our current policy accepts the timeout in that case.&lt;/p&gt;

&lt;p&gt;We must distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When something happened elsewhere
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When this machine received and processed information about it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue gives us a local sequence. The state and request checks give that sequence a defined interpretation.&lt;/p&gt;

&lt;p&gt;Neither mechanism makes the outside world globally ordered.&lt;/p&gt;

&lt;h3&gt;
  
  
  What have we gained?
&lt;/h3&gt;

&lt;p&gt;The order can now represent an unfinished interaction without pretending it has already succeeded.&lt;/p&gt;

&lt;p&gt;Its lifecycle records whether a check may begin, whether a result is expected, and whether shipping is eligible. Its supporting data identifies the exact request and destination. External work produces messages instead of mutating the order. One consumer applies those messages in a local sequence.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;reactive execution model&lt;/strong&gt;: the machine progresses by handling inputs as they arrive, rather than requiring one uninterrupted call to complete the entire process.&lt;/p&gt;

&lt;p&gt;The central guarantee is now:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Only a result for the currently outstanding inquiry may advance the waiting order.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That does not provide general event deduplication or exactly-once execution. It prevents obsolete results from completing the wrong inquiry under our current, controlled execution path.&lt;/p&gt;

&lt;p&gt;Nor is the waiting durable. A process crash still loses this queue, its timers, and the in-memory order. Failed scheduling after a local update still needs recovery we have not implemented.&lt;/p&gt;

&lt;p&gt;The read-only inquiry also matters. Returning to &lt;code&gt;PAID&lt;/code&gt; after a timeout means we discarded an unanswered check. It would not prove that a timed-out booking or payment request had no external effect.&lt;/p&gt;

&lt;p&gt;We have made waiting explicit. We have not yet made external effects recoverable.&lt;/p&gt;

&lt;h3&gt;
  
  
  But what if the order is waiting for more than one thing?
&lt;/h3&gt;

&lt;p&gt;Our model allows one shipping inquiry at a time.&lt;/p&gt;

&lt;p&gt;Now suppose preparation requires both carrier availability and an inventory reservation. Either result may arrive first. Both must succeed before the order can proceed.&lt;/p&gt;

&lt;p&gt;We could add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WAITING_FOR_CARRIER_AND_INVENTORY
CARRIER_READY_WAITING_FOR_INVENTORY
INVENTORY_READY_WAITING_FOR_CARRIER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then introduce one more independent check.&lt;/p&gt;

&lt;p&gt;The lifecycle begins accumulating combinations again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we represent independent work that can run concurrently, finish in either order, and then join into one permitted next step?&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;[1]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html" rel="noopener noreferrer"&gt;Coroutines and Tasks&lt;/a&gt;&lt;/em&gt;. Cooperative scheduling, task suspension, and task groups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[2]&lt;/strong&gt; Gregor Hohpe and Bobby Woolf, &lt;a href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/CorrelationIdentifier.html" rel="noopener noreferrer"&gt;“Correlation Identifier”&lt;/a&gt;, &lt;em&gt;Enterprise Integration Patterns&lt;/em&gt;. Associating a reply with the request that produced it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[3]&lt;/strong&gt; World Wide Web Consortium, &lt;em&gt;&lt;a href="https://www.w3.org/TR/2015/REC-scxml-20150901/" rel="noopener noreferrer"&gt;State Chart XML: State Machine Notation for Control Abstraction&lt;/a&gt;&lt;/em&gt;, W3C Recommendation, 2015. See Appendix D for run-to-completion execution and §6.3 for cancellation of delayed events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[4]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/asyncio-queue.html" rel="noopener noreferrer"&gt;Queues&lt;/a&gt;&lt;/em&gt;. FIFO behavior, asynchronous queue operations, task bookkeeping, and thread-safety limitations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[5]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/asyncio-eventloop.html#scheduling-delayed-callbacks" rel="noopener noreferrer"&gt;Event Loop - Scheduling Delayed Callbacks&lt;/a&gt;&lt;/em&gt;. Timer scheduling and the event loop’s monotonic clock.&lt;/p&gt;

</description>
      <category>python</category>
      <category>statemachines</category>
      <category>systemdesign</category>
      <category>ai</category>
    </item>
    <item>
      <title>Road to State Machines IV - But How Do We Let Data Influence Transitions Without Turning Every Value into Another State?</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Fri, 02 Oct 2026 14:59:16 +0000</pubDate>
      <link>https://dev.to/canburaks/road-to-state-machines-iv-but-how-do-we-let-data-influence-transitions-without-turning-every-4k0k</link>
      <guid>https://dev.to/canburaks/road-to-state-machines-iv-but-how-do-we-let-data-influence-transitions-without-turning-every-4k0k</guid>
      <description>&lt;p&gt;Our lifecycle now has one explicit transition table. For a valid order, it tells us:&lt;/p&gt;

&lt;p&gt;The operations consult that table before making a change. The code that lists available actions consults it too.&lt;/p&gt;

&lt;p&gt;But Part III ended with another requirement:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffudksa1gumc1ssd9ipic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffudksa1gumc1ssd9ipic.png" alt="Order Lifecycle Transition Process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consider two orders. Both are paid, and both retain their captured payment records:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Order&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Payment record&lt;/th&gt;
&lt;th&gt;Delivery address&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PAID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Present&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PAID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Present&lt;/td&gt;
&lt;td&gt;Unsupported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both records satisfy our existing invariants. Both reach the same transition-table entry.&lt;/p&gt;

&lt;p&gt;Yet the shipping request should succeed for only one of them.&lt;/p&gt;

&lt;p&gt;The table knows where an order is in its lifecycle. It does not yet consider all the information needed to decide whether shipping is permitted.&lt;/p&gt;

&lt;p&gt;How do we extend it without losing the clarity we just gained?&lt;/p&gt;

&lt;h3&gt;
  
  
  Start with the smallest additional check
&lt;/h3&gt;

&lt;p&gt;We already have a &lt;code&gt;delivery_address&lt;/code&gt; field. We do not need to change the order model to inspect it.&lt;/p&gt;

&lt;p&gt;For this example, let’s use a deliberately small, fixed rule: &lt;code&gt;"Istanbul"&lt;/code&gt; and &lt;code&gt;"Izmir"&lt;/code&gt; are supported destination labels. Every other string is unsupported.&lt;/p&gt;

&lt;p&gt;This is an illustrative policy, not a statement about real carrier coverage. We are also treating the existing strings as destination labels, not implementing postal-address parsing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;has_supported_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_address&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Izmir&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could call this function from the shipping operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;has_supported_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The delivery address is not supported.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a reasonable first change. The function still rejects invalid records and invalid lifecycle movements. It now also rejects unsupported destinations before changing the order.&lt;/p&gt;

&lt;p&gt;But what does &lt;code&gt;available_actions()&lt;/code&gt; report?&lt;/p&gt;

&lt;p&gt;Its implementation from Part III checks whether the transition table contains an entry. For both paid orders, it finds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAID + SHIP_ORDER → SHIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It therefore offers shipping for both.&lt;/p&gt;

&lt;p&gt;The shipping function has acquired a rule that the action listing does not know about. We could copy the address check into the listing, but that would recreate the duplication we just removed.&lt;/p&gt;

&lt;p&gt;The new condition belongs with the transition it controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  A condition that enables a transition
&lt;/h3&gt;

&lt;p&gt;A condition that determines whether a transition is eligible is called a &lt;strong&gt;guard&lt;/strong&gt;. State-machine notations commonly distinguish the triggering input from the Boolean condition that must also hold.[1]&lt;/p&gt;

&lt;p&gt;For our shipping transition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dot"&gt;&lt;code&gt;&lt;span class="nv"&gt;PAID&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nv"&gt;SHIP_ORDER&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;has_supported_address&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nv"&gt;SHIPPED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command asks for the change. The guard decides whether this particular order may take that transition.&lt;/p&gt;

&lt;p&gt;Our rule now has three separate requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The existing order must satisfy its invariants.&lt;/li&gt;
&lt;li&gt;Its current state must permit the requested command.&lt;/li&gt;
&lt;li&gt;The transition’s guard must pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Only then may the operation proceed.&lt;/p&gt;

&lt;p&gt;Notice that the address check did not replace the payment checks. A supported address does not make an unpaid order eligible for shipping.&lt;/p&gt;

&lt;h3&gt;
  
  
  An unsupported destination does not make the order inconsistent
&lt;/h3&gt;

&lt;p&gt;Should we put &lt;code&gt;has_supported_address()&lt;/code&gt; into &lt;code&gt;validate_order()&lt;/code&gt; instead?&lt;/p&gt;

&lt;p&gt;Not for the rule we have chosen.&lt;/p&gt;

&lt;p&gt;A paid order with an unsupported destination can still be a consistent record. The customer paid; the captured payment is recorded; the delivery destination is known. What the order cannot do is take the shipping transition under our current policy.&lt;/p&gt;

&lt;p&gt;Compare the cases:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Current record&lt;/th&gt;
&lt;th&gt;Interpretation&lt;/th&gt;
&lt;th&gt;Shipping outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PAID&lt;/code&gt;, no payment record&lt;/td&gt;
&lt;td&gt;Inconsistent order&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;InvalidOrderState&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;CREATED&lt;/code&gt;, no payment record&lt;/td&gt;
&lt;td&gt;Consistent, but shipping is not permitted&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;InvalidOrderOperation&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PAID&lt;/code&gt;, payment present, unsupported destination&lt;/td&gt;
&lt;td&gt;Consistent, but the shipping guard fails&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;InvalidOrderOperation&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PAID&lt;/code&gt;, payment present, supported destination&lt;/td&gt;
&lt;td&gt;Consistent and eligible&lt;/td&gt;
&lt;td&gt;Move to &lt;code&gt;SHIPPED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The invariant asks whether the record makes sense.&lt;/p&gt;

&lt;p&gt;The guard asks whether a particular transition is allowed now.&lt;/p&gt;

&lt;p&gt;There is another reason not to confuse them. If shipping coverage later changes, that does not necessarily make an already shipped order invalid. A condition checked when an operation begins is not automatically a condition that must remain true forever.&lt;/p&gt;

&lt;p&gt;For this part, coverage stays fixed. The distinction is still useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do we need two kinds of paid state?
&lt;/h3&gt;

&lt;p&gt;Another possible solution would be to split &lt;code&gt;PAID&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAID_WITH_SUPPORTED_ADDRESS
PAID_WITH_UNSUPPORTED_ADDRESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can represent the distinction, but it makes the lifecycle responsible for carrying a fact already available in the supporting data.&lt;/p&gt;

&lt;p&gt;Now suppose we also distinguish three payment providers. We could start creating combinations such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAID_WITH_SUPPORTED_ADDRESS_PROVIDER_A
PAID_WITH_UNSUPPORTED_ADDRESS_PROVIDER_A
PAID_WITH_SUPPORTED_ADDRESS_PROVIDER_B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add another condition.&lt;/p&gt;

&lt;p&gt;Each independent dimension multiplies the combinations we might have to name. Most of those names would describe data combinations rather than useful lifecycle stages.&lt;/p&gt;

&lt;p&gt;More states are not inherently wrong. A separate state can be useful when it represents a different phase with its own permitted operations. But our present requirement does not introduce another phase. It adds a condition to an existing transition.&lt;/p&gt;

&lt;p&gt;Both orders remain paid.&lt;/p&gt;

&lt;p&gt;Their supporting data determines whether they may ship.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep the condition with the transition
&lt;/h3&gt;

&lt;p&gt;Our table currently maps a state–command pair directly to a target state. Let’s give each entry room to describe an optional guard as well.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;OrderState&lt;/code&gt;, &lt;code&gt;OrderCommand&lt;/code&gt;, &lt;code&gt;Order&lt;/code&gt;, and &lt;code&gt;Payment&lt;/code&gt; definitions remain unchanged.&lt;/p&gt;

&lt;p&gt;We add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;
    &lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;rejection_reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transition conditions are not satisfied.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;guard&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;guard&lt;/code&gt; is either absent or a function that receives an order and returns a Boolean result.&lt;/p&gt;

&lt;p&gt;An absent guard means this entry has no additional data-dependent condition. It does &lt;strong&gt;not&lt;/strong&gt; mean that record validation or command-argument validation should be skipped.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;frozen=True&lt;/code&gt; setting prevents ordinary assignment to the transition definition’s fields after construction. It does not make the orders passed to its guard immutable.[2]&lt;/p&gt;

&lt;p&gt;Now replace the earlier table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MappingProxyType&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;


&lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MappingProxyType&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;has_supported_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;rejection_reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The delivery address is not supported.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lifecycle is still small:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Additional guard&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CREATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CAPTURE_PAYMENT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PAID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PAID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHIP_ORDER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Supported address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHIPPED&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We have not added another order state.&lt;/p&gt;

&lt;p&gt;We have made one transition more precise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Select the next state using the order
&lt;/h3&gt;

&lt;p&gt;The selection function needs access to the supporting data, so its signature must change.&lt;/p&gt;

&lt;p&gt;Previously, it received only a state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will now receive the order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following definition replaces the version from Part III:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;command must be an OrderCommand member.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;while the order is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rejection_reason&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sequence is deliberate.&lt;/p&gt;

&lt;p&gt;First, validate the record using the unchanged validator from Part III. A &lt;code&gt;created&lt;/code&gt; order must have no captured payment, while a &lt;code&gt;paid&lt;/code&gt; or &lt;code&gt;shipped&lt;/code&gt; order must contain a &lt;code&gt;Payment&lt;/code&gt; record.&lt;/p&gt;

&lt;p&gt;Then find a transition for the current state and command.&lt;/p&gt;

&lt;p&gt;Finally, evaluate that transition’s optional guard.&lt;/p&gt;

&lt;p&gt;The function returns a target or raises an exception. It still does not change the order.&lt;/p&gt;

&lt;p&gt;A missing transition and a failed guard both reject the operation, but they explain different failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The lifecycle contains no such movement.&lt;/li&gt;
&lt;li&gt;The movement exists, but this order does not currently satisfy its condition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We keep those explanations separate without inventing extra lifecycle states.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update the operations to use the new selector
&lt;/h3&gt;

&lt;p&gt;Because &lt;code&gt;next_state()&lt;/code&gt; now validates the order itself, the operations do not need to repeat that call.&lt;/p&gt;

&lt;p&gt;Replace both operations with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment must be a Payment record.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The address condition no longer appears inside &lt;code&gt;ship_order()&lt;/code&gt;. It is attached to the shipping transition.&lt;/p&gt;

&lt;p&gt;Payment capture still checks its supplied argument and stores it. We have not made shipping coverage a prerequisite for recording a payment. That would be another business rule, not a consequence we should introduce accidentally.&lt;/p&gt;

&lt;p&gt;The expected rejection checks still run before mutation.&lt;/p&gt;

&lt;p&gt;These operations also retain their earlier scope: payment capture records the supplied &lt;code&gt;Payment&lt;/code&gt;, and shipping changes the local lifecycle status. Neither calls an external service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let the read path evaluate the same guard
&lt;/h3&gt;

&lt;p&gt;Now update the action listing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The listing and the write path now use the same transition definitions and the same guard evaluation.&lt;/p&gt;

&lt;p&gt;For a valid paid order with an unsupported address, shipping is neither advertised nor executed.&lt;/p&gt;

&lt;p&gt;This is a stronger agreement than sharing the state–command table alone. Both readers now consider the supporting data that controls the transition.&lt;/p&gt;

&lt;p&gt;The listing remains an eligibility report, not permission to bypass the operation. It does not validate a payment argument that has not yet been supplied, establish user authorization, or reserve the order against future changes.&lt;/p&gt;

&lt;p&gt;The operation must still check when it is called.&lt;/p&gt;

&lt;h3&gt;
  
  
  A guard should inspect, not perform work
&lt;/h3&gt;

&lt;p&gt;Because both the read path and the write path evaluate guards, their behavior must be predictable.&lt;/p&gt;

&lt;p&gt;Our address guard reads one field and returns a result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;has_supported_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_address&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Izmir&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling it again with the same address produces the same answer. It does not change the order or contact another system.&lt;/p&gt;

&lt;p&gt;This is the contract we want for our guards: evaluate the condition without changing the condition or the world around it. SCXML similarly specifies side-effect-free conditional expressions for its data-model language.[1]&lt;/p&gt;

&lt;p&gt;Suppose the guard instead booked a shipment to discover whether shipping was possible.&lt;/p&gt;

&lt;p&gt;Simply displaying available actions could then book a shipment. Calling &lt;code&gt;ship_order()&lt;/code&gt; would evaluate the guard again and potentially book another.&lt;/p&gt;

&lt;p&gt;The question “May I do this?” would perform the thing being asked about.&lt;/p&gt;

&lt;p&gt;Likewise, a guard should not update the address to make its own condition pass. Address correction would be a separate operation with its own rules.&lt;/p&gt;

&lt;p&gt;Our callable annotation cannot prove that a guard is pure. That remains an implementation contract we must maintain and test. The small address predicate satisfies it; an arbitrary replacement might not.&lt;/p&gt;

&lt;p&gt;A guard failure also differs from a guard error. Returning &lt;code&gt;False&lt;/code&gt; means the condition was evaluated and was not satisfied. An exception means the evaluation failed. Our code does not catch arbitrary exceptions and pretend that the business simply rejected the request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where do command arguments and actions fit?
&lt;/h3&gt;

&lt;p&gt;Not all data used by an operation is already stored on the order.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order is the existing record. The &lt;code&gt;payment&lt;/code&gt; argument is input data supplied with the command. It becomes supporting data on the order only after the operation accepts it.&lt;/p&gt;

&lt;p&gt;That gives us three distinct inputs to the overall decision:&lt;/p&gt;

&lt;p&gt;![[lifecycle-command-execution-inputs.png]]&lt;/p&gt;

&lt;p&gt;Our current guard interface receives only the order because the new shipping condition needs only stored data. The payment-argument check remains in &lt;code&gt;capture_payment()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We should not claim that every condition has moved into the transition table. Lifecycle movement and the shipping guard have moved there. Command-specific input validation has not.&lt;/p&gt;

&lt;p&gt;After the checks pass, the operation performs its &lt;strong&gt;actions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For payment capture, those actions are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For shipping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are local data updates. A fuller state-machine notation may associate updates or other executable actions with transitions; SCXML, for example, separates transition conditions from executable content and data assignments.[1]&lt;/p&gt;

&lt;p&gt;We do not need an action registry to demonstrate that distinction. Our domain functions already show where checking ends and updating begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  What have we extended?
&lt;/h3&gt;

&lt;p&gt;We started with a finite control model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now allow supporting data to influence whether a transition can occur, and our operations update both lifecycle state and supporting data.&lt;/p&gt;

&lt;p&gt;This is the central idea of an &lt;strong&gt;extended finite state machine&lt;/strong&gt;, or &lt;strong&gt;EFSM&lt;/strong&gt;: finite control states combined with variables, conditions that enable transitions, and updates associated with accepted inputs.[3]&lt;/p&gt;

&lt;p&gt;In our model:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;EFSM role&lt;/th&gt;
&lt;th&gt;Existing implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Order.status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supporting data, or extended state&lt;/td&gt;
&lt;td&gt;Address, payment, and other relevant order fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Command and its arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Guard&lt;/td&gt;
&lt;td&gt;&lt;code&gt;has_supported_address()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update&lt;/td&gt;
&lt;td&gt;Changes performed by the accepted operation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The term &lt;em&gt;context&lt;/em&gt; is often used for the supporting data consulted by the machine. Here, it names a responsibility, not a new class we must create.&lt;/p&gt;

&lt;p&gt;We already have an &lt;code&gt;Order&lt;/code&gt; that contains that information. Moving every field into an &lt;code&gt;OrderContext&lt;/code&gt; object would not, by itself, improve this example.&lt;/p&gt;

&lt;p&gt;There is also an important qualification to the word &lt;em&gt;finite&lt;/em&gt;. The set of control states remains finite, but the complete configurations include data values. General EFSM definitions can permit unbounded data domains and therefore need not describe a finite total state space.[3]&lt;/p&gt;

&lt;p&gt;For our order, &lt;code&gt;PAID&lt;/code&gt; is a control state. &lt;code&gt;PAID&lt;/code&gt; together with a particular address and payment record is a more complete configuration.&lt;/p&gt;

&lt;p&gt;Keeping the diagram small does not make those data-dependent distinctions disappear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why keep values outside the state names?
&lt;/h3&gt;

&lt;p&gt;This separation was useful well before application workflow libraries.&lt;/p&gt;

&lt;p&gt;In their 1996 paper &lt;em&gt;Automatic Generation of Functional Vectors Using the Extended Finite State Machine Model&lt;/em&gt;, Kwang-Ting Cheng and A. S. Krishnakumar used EFSMs to derive tests from descriptions of sequential circuits. They kept data variables and their operations in a compact model rather than explicitly naming every combination as a control state.[3]&lt;/p&gt;

&lt;p&gt;Their problem was circuit testing, not shipping orders. The relevant connection is the representation: preserve explicit control flow while expressing value-dependent behavior through conditions and updates.&lt;/p&gt;

&lt;p&gt;The later SCXML standard makes a related separation visible through its data model, transition conditions, and executable content.[1]&lt;/p&gt;

&lt;p&gt;Neither reference requires us to adopt a particular framework. They help explain why extending the transition model is different from endlessly expanding the list of state names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the data-dependent cases
&lt;/h3&gt;

&lt;p&gt;Part III tested the six combinations formed by three states and two commands.&lt;/p&gt;

&lt;p&gt;Those cases still matter. But testing shipping once from &lt;code&gt;PAID&lt;/code&gt; is no longer enough.&lt;/p&gt;

&lt;p&gt;The address now divides valid paid orders into at least two relevant groups:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Valid starting record&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Expected result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;CREATED&lt;/code&gt;, supported address&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CAPTURE_PAYMENT&lt;/code&gt; with valid payment&lt;/td&gt;
&lt;td&gt;Become &lt;code&gt;PAID&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;CREATED&lt;/code&gt;, unsupported address&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CAPTURE_PAYMENT&lt;/code&gt; with valid payment&lt;/td&gt;
&lt;td&gt;Become &lt;code&gt;PAID&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;CREATED&lt;/code&gt;, either address category&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHIP_ORDER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PAID&lt;/code&gt;, supported address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHIP_ORDER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Become &lt;code&gt;SHIPPED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PAID&lt;/code&gt;, unsupported address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHIP_ORDER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SHIPPED&lt;/code&gt;, either address category&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHIP_ORDER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The second row is worth noticing. It confirms that we added a shipping restriction, not a payment restriction.&lt;/p&gt;

&lt;p&gt;Let’s exercise the new rejection path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deepcopy&lt;/span&gt;


&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit_card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment-81&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;120.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;blocked_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-68&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ankara&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocked_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocked_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocked_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocked_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocked_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An unsupported destination was allowed to ship.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;blocked_order&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;blocked_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validation succeeds because the order is internally consistent.&lt;/p&gt;

&lt;p&gt;The action listing offers nothing: payment capture is no longer permitted, and shipping is blocked by the guard.&lt;/p&gt;

&lt;p&gt;The shipping request raises an exception without changing the record.&lt;/p&gt;

&lt;p&gt;Calling the action listing twice also leaves it unchanged. That check would help expose a guard that mutates the order while answering an eligibility question.&lt;/p&gt;

&lt;p&gt;Now verify the accepted path using a separate order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;supported_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-69&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supported_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supported_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;supported_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;supported_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supported_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supported_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The existing invalid-record tests remain necessary. A paid order with no payment must still fail before any shipping guard is considered.&lt;/p&gt;

&lt;p&gt;We have added another dimension to the tests, not replaced the earlier ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  The machine is still deterministic
&lt;/h3&gt;

&lt;p&gt;Two paid orders can now produce different outcomes for the same command. Does that make the machine nondeterministic?&lt;/p&gt;

&lt;p&gt;No. We are considering more input to the decision.&lt;/p&gt;

&lt;p&gt;For the same valid order data, command, and fixed address policy, our selector produces the same target or rejection.&lt;/p&gt;

&lt;p&gt;There is still at most one transition definition for each state–command pair. Its guard either enables that transition or blocks it.&lt;/p&gt;

&lt;p&gt;If we later allow multiple candidate transitions for the same pair, we will need another explicit rule: their guards must distinguish the cases unambiguously, or the model must define how competing matches are resolved.&lt;/p&gt;

&lt;p&gt;We have not introduced that branching here.&lt;/p&gt;

&lt;p&gt;A rejected shipping request also does not mean that the order successfully transitioned from &lt;code&gt;PAID&lt;/code&gt; back to &lt;code&gt;PAID&lt;/code&gt;. No transition was taken. The request was refused, and the original configuration remained unchanged.&lt;/p&gt;

&lt;p&gt;That difference matters when we eventually attach work to transitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the richer model does—and does not—protect
&lt;/h3&gt;

&lt;p&gt;Our three-state lifecycle remains intact. The payment model, its consistency rules, and the simulated nature of both operations remain intact too.&lt;/p&gt;

&lt;p&gt;The change is that a declared transition can now inspect supporting data before it is taken. The write path and the action listing share that condition.&lt;/p&gt;

&lt;p&gt;We still rely on controlled operations. Directly assigning a status or changing the address can bypass those operations, just as it could in Part III.&lt;/p&gt;

&lt;p&gt;We also still assume one uninterrupted local decision. &lt;code&gt;next_state()&lt;/code&gt; does not lock an order, reserve a carrier, or commit a database transaction. Its returned target is not a reusable authorization token.&lt;/p&gt;

&lt;p&gt;The improvement is specific:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A valid order may take a declared transition only when that transition’s current data conditions also pass.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have moved beyond asking only where the order is. We can now ask whether the rest of the record permits the proposed movement.&lt;/p&gt;

&lt;h3&gt;
  
  
  But what if the condition cannot be answered locally?
&lt;/h3&gt;

&lt;p&gt;Our shipping guard can answer immediately because coverage is a fixed rule in the program.&lt;/p&gt;

&lt;p&gt;Now suppose the carrier must confirm whether it can accept a particular shipment. The answer might arrive later. The request might fail. The customer might send another command while we wait.&lt;/p&gt;

&lt;p&gt;Putting that interaction inside &lt;code&gt;has_supported_address()&lt;/code&gt; would break the boundary we established: inspecting available actions would perform external work.&lt;/p&gt;

&lt;p&gt;It would also expose a larger problem.&lt;/p&gt;

&lt;p&gt;The system would no longer make one immediate decision from information already available. It would need to request information, retain what it was waiting for, and continue when a result arrived.&lt;/p&gt;

&lt;p&gt;A sent request is not a confirmed shipment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But how does the machine wait for something that happens later without losing track of what it is allowed to do in the meantime?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;[1]&lt;/strong&gt; World Wide Web Consortium, &lt;em&gt;&lt;a href="https://www.w3.org/TR/2015/REC-scxml-20150901/" rel="noopener noreferrer"&gt;State Chart XML: State Machine Notation for Control Abstraction&lt;/a&gt;&lt;/em&gt;, W3C Recommendation, 2015. See §3.5, “Transition”; §4, “Executable Content”; and §5, “Data Model and Data Manipulation.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[2]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/dataclasses.html" rel="noopener noreferrer"&gt;dataclasses — Data Classes&lt;/a&gt;&lt;/em&gt;. Documentation for dataclass fields and the limitations of &lt;code&gt;frozen=True&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[3]&lt;/strong&gt; Kwang-Ting Cheng and A. S. Krishnakumar, &lt;a href="https://doi.org/10.1145/225871.225880" rel="noopener noreferrer"&gt;“Automatic Generation of Functional Vectors Using the Extended Finite State Machine Model”&lt;/a&gt;, &lt;em&gt;ACM Transactions on Design Automation of Electronic Systems&lt;/em&gt;, vol. 1, no. 1, pp. 57–79, 1996. An &lt;a href="https://www.researchgate.net/publication/2504858_Automatic_generation_of_functional_vectors_using_the_extended_finite_state_machine_model" rel="noopener noreferrer"&gt;author-uploaded manuscript&lt;/a&gt; includes the model’s enabling conditions, updates, and distinction between symbolic states and full configurations.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>systemdesign</category>
      <category>statemachines</category>
      <category>python</category>
    </item>
    <item>
      <title>Road to State Machines Part III - But How Do We Represent the Entire Lifecycle as One Behavioral Contract?</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Thu, 01 Oct 2026 09:03:58 +0000</pubDate>
      <link>https://dev.to/canburaks/road-to-state-machines-part-iii-but-how-do-we-represent-the-entire-lifecycle-as-one-behavioral-1mp0</link>
      <guid>https://dev.to/canburaks/road-to-state-machines-part-iii-but-how-do-we-represent-the-entire-lifecycle-as-one-behavioral-1mp0</guid>
      <description>&lt;p&gt;Our operations now reject invalid changes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;capture_payment()&lt;/code&gt; requires a valid &lt;code&gt;created&lt;/code&gt; order and a payment record. &lt;code&gt;ship_order()&lt;/code&gt; requires a valid &lt;code&gt;paid&lt;/code&gt; order. Both inspect the existing record before changing it.&lt;/p&gt;

&lt;p&gt;But suppose we ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What operations are available to a paid order?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We still have to inspect the functions.&lt;/p&gt;

&lt;p&gt;One function says that payment capture requires &lt;code&gt;created&lt;/code&gt;. Another says that shipping requires &lt;code&gt;paid&lt;/code&gt;. Their assignments tell us where the order goes afterward.&lt;/p&gt;

&lt;p&gt;The lifecycle exists, but we must reconstruct it from the implementation.&lt;/p&gt;

&lt;p&gt;How do we make that lifecycle explicit and make the operations use it?&lt;/p&gt;

&lt;h3&gt;
  
  
  Start by writing down the rules we already have
&lt;/h3&gt;

&lt;p&gt;We do not need more states yet. Our model still has three:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;created → paid → shipped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also has two operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a valid order, the status-based rules are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Current status&lt;/th&gt;
&lt;th&gt;Capture payment&lt;/th&gt;
&lt;th&gt;Ship order&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;created&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move to &lt;code&gt;paid&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;paid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;td&gt;Move to &lt;code&gt;shipped&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shipped&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This table contains six combinations. Only two permit a change.&lt;/p&gt;

&lt;p&gt;The payment argument still needs validation. The table does not claim that &lt;em&gt;every&lt;/em&gt; call to &lt;code&gt;capture_payment()&lt;/code&gt; from &lt;code&gt;created&lt;/code&gt; is valid, regardless of its arguments. It describes which operations are eligible from each lifecycle state.&lt;/p&gt;

&lt;p&gt;That distinction preserves the separation we established in Part II:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The current record must be consistent. The requested movement must also be permitted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Until now, this table was a summary we produced by reading the code. Let’s reverse that relationship.&lt;/p&gt;

&lt;p&gt;The table should define the lifecycle. The operations should consult it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give the vocabulary explicit names
&lt;/h3&gt;

&lt;p&gt;First, let’s replace the unrestricted status vocabulary with named values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;CREATED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;PAID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;SHIPPED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An enumeration defines a set of named members. Each member here retains the lowercase string we already use to represent the status.[1]&lt;/p&gt;

&lt;p&gt;We can distinguish the member from its external representation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;
&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;  &lt;span class="c1"&gt;# "paid"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need names for the inputs that request a change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;capture_payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ship_order&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will call these &lt;strong&gt;commands&lt;/strong&gt; because they request operations. They do not announce that the operations have already succeeded.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SHIP_ORDER&lt;/code&gt; means “attempt the shipping operation.” It does not mean that a carrier has confirmed shipment.&lt;/p&gt;

&lt;p&gt;Likewise, &lt;code&gt;CAPTURE_PAYMENT&lt;/code&gt; identifies our existing simulated operation, which records a supplied &lt;code&gt;Payment&lt;/code&gt;. We have not added a payment-provider call.&lt;/p&gt;

&lt;p&gt;These names give the lifecycle two distinct vocabularies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;States:
    Where is the order?

Commands:
    What operation is being requested?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update the model without changing its supporting data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Payment&lt;/code&gt; class remains unchanged. In &lt;code&gt;Order&lt;/code&gt;, only the status representation changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A newly constructed order now starts with &lt;code&gt;OrderState.CREATED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When loading a status from an external representation, we can convert it explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unknown spellings are rejected by the enum lookup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shiped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Raises ValueError.
&lt;/span&gt;&lt;span class="nc"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PAID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# Raises ValueError.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have not introduced case normalization or guessed what an unknown value means.[1]&lt;/p&gt;

&lt;p&gt;However, changing the annotation does not make arbitrary assignment impossible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;something_else&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A normal dataclass does not enforce field annotations at runtime.[2] The operation boundary must still validate incoming records.&lt;/p&gt;

&lt;p&gt;The enum gives us a defined vocabulary. Validation determines whether a particular record uses it correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Turn the transition table into executable data
&lt;/h3&gt;

&lt;p&gt;Each permitted transition needs three pieces of information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current state
requested command
next state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can represent the first two as a dictionary key and the third as its value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MappingProxyType&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;


&lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MappingProxyType&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MappingProxyType&lt;/code&gt; provides a read-only view of the mapping. Ordinary callers cannot insert another transition through &lt;code&gt;TRANSITIONS&lt;/code&gt;.[3]&lt;/p&gt;

&lt;p&gt;We have stored only the permitted changes. The rejected combinations remain absent.&lt;/p&gt;

&lt;p&gt;Now we need a function that interprets the table. We keep the exception types from Part II:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status must be an OrderState member.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;command must be an OrderCommand member.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;while the order is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function answers one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given this lifecycle state and this command, which next state is permitted?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is rejected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The missing entry is not an implementation omission. It expresses the business rule that an unpaid order must not be shipped.&lt;/p&gt;

&lt;p&gt;Notice what &lt;code&gt;next_state()&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; do.&lt;/p&gt;

&lt;p&gt;It does not modify an order. It does not store payment information. It does not call a provider or create a shipment.&lt;/p&gt;

&lt;p&gt;It selects a permitted destination or rejects the request.&lt;/p&gt;

&lt;h3&gt;
  
  
  We now have an explicit finite state machine
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;finite state machine&lt;/strong&gt; describes a finite set of states, an initial state, inputs, and rules that determine the next state from the current state and input.[4]&lt;/p&gt;

&lt;p&gt;Our example has each of those elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;States:
    CREATED, PAID, SHIPPED

Initial state:
    CREATED

Inputs:
    CAPTURE_PAYMENT, SHIP_ORDER

Permitted transitions:
    CREATED + CAPTURE_PAYMENT → PAID
    PAID + SHIP_ORDER → SHIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same relationship can be written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or, using conventional mathematical notation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;δ(current_state, command) = next_state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The symbol &lt;code&gt;δ&lt;/code&gt; names the transition function. It does not introduce another mechanism.&lt;/p&gt;

&lt;p&gt;Our transition model is &lt;strong&gt;deterministic&lt;/strong&gt;: for a particular state and command, there is one declared destination or a defined rejection.&lt;/p&gt;

&lt;p&gt;Mathematical treatments sometimes define a transition for every state–input pair. Our application uses a partial transition table: an absent pair means “reject without changing the order.” We do not silently treat rejection as success, nor move the order into a newly invented failure state.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SHIPPED&lt;/code&gt; is terminal &lt;strong&gt;within this model&lt;/strong&gt;, because no supported command leaves it. That does not mean the real order can never be delivered or returned. Those processes are outside the lifecycle we have implemented.&lt;/p&gt;

&lt;p&gt;“Finite” describes this control model. It does not mean that every possible customer name, delivery address, or payment record has been enumerated.&lt;/p&gt;

&lt;h3&gt;
  
  
  But the table does not replace the invariants
&lt;/h3&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transition table contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAID + SHIP_ORDER → SHIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this particular order is inconsistent. Its payment record is missing.&lt;/p&gt;

&lt;p&gt;The table cannot detect that because it receives only the lifecycle state and command.&lt;/p&gt;

&lt;p&gt;Let’s update the validator to use our enum while preserving both payment rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status must be an OrderState member.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A created order cannot contain a captured payment.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An order marked &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;must contain a Payment record.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;created&lt;/code&gt; order must still have no payment record. A &lt;code&gt;paid&lt;/code&gt; or &lt;code&gt;shipped&lt;/code&gt; order must still retain one.&lt;/p&gt;

&lt;p&gt;We are not adding validation of payment amounts, currencies, or provider-side capture. The scope remains the same as in Part II.&lt;/p&gt;

&lt;p&gt;We now have two deliberately separate functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;Is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="n"&gt;consistent&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;

&lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;Is&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;lifecycle&lt;/span&gt; &lt;span class="n"&gt;movement&lt;/span&gt; &lt;span class="n"&gt;permitted&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both are necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make the operations consult the table
&lt;/h3&gt;

&lt;p&gt;We can now replace their status-specific conditions with calls to &lt;code&gt;next_state()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment must be a Payment record.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare the new shipping operation with the previous version.&lt;/p&gt;

&lt;p&gt;It no longer contains its own declaration that shipping requires &lt;code&gt;paid&lt;/code&gt;, followed by an independent assignment to &lt;code&gt;shipped&lt;/code&gt;. Both facts come from the transition table.&lt;/p&gt;

&lt;p&gt;The same is true of payment capture. Its lifecycle rule comes from the table; the function remains responsible for checking and storing the payment argument.&lt;/p&gt;

&lt;p&gt;This is the separation we wanted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Existing-record consistency → validator

Lifecycle eligibility and destination → transition table

Operation-specific work → domain function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have not removed the domain functions. They still provide the meaningful interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nor have we introduced a generic function with several optional arguments whose meanings depend on which command was passed. For two operations, the explicit functions remain clearer.&lt;/p&gt;

&lt;p&gt;All expected rejection checks still happen before mutation.&lt;/p&gt;

&lt;p&gt;Payment capture still makes two assignments. As in Part II, this is a local, single-writer example not an atomic transaction or a crash-recovery mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let the read path use the same lifecycle
&lt;/h3&gt;

&lt;p&gt;Previously, code displaying available operations could repeat the status checks.&lt;/p&gt;

&lt;p&gt;Now it can consult the same table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;
        &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function validates the record first. An inconsistent order is not presented as though it were ready for normal processing.&lt;/p&gt;

&lt;p&gt;Let’s follow one order through the complete sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit_card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment-81&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;120.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;available_actions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The write path and the action listing now agree because they read the same lifecycle definition.&lt;/p&gt;

&lt;p&gt;But an available action is not a promise that a later call will succeed.&lt;/p&gt;

&lt;p&gt;The listing describes eligibility for the current record. It does not supply a valid &lt;code&gt;Payment&lt;/code&gt; argument, grant a user permission, or reserve the order against another change. The operation must still perform its checks when invoked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Displaying an action does not replace enforcing it.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the whole transition surface
&lt;/h3&gt;

&lt;p&gt;We now have a small, explicit surface to test: three states and two commands.&lt;/p&gt;

&lt;p&gt;Let’s write expected outcomes independently of &lt;code&gt;TRANSITIONS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;expected_transitions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAPTURE_PAYMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIP_ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIPPED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;OrderCommand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expected_transitions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These assertions are test code, not production validation.&lt;/p&gt;

&lt;p&gt;The test exercises all six combinations, including the four that must be rejected. Its expected outcomes describe our business specification rather than being calculated from the implementation table.&lt;/p&gt;

&lt;p&gt;Simply iterating over &lt;code&gt;TRANSITIONS&lt;/code&gt; and asserting that the lookup returns its stored values would be much weaker. That could confirm that the dictionary works while overlooking an incorrectly permitted transition.&lt;/p&gt;

&lt;p&gt;We must also keep the record-level tests from Part II.&lt;/p&gt;

&lt;p&gt;For example, rejecting an unpaid shipment must preserve the order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;unpaid_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-67&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unpaid_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An unpaid order was allowed to ship.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;unpaid_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;unpaid_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The matrix test does not replace tests for missing payments, captured payments on &lt;code&gt;created&lt;/code&gt; orders, invalid payment arguments, or raw strings assigned to &lt;code&gt;status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They test different obligations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing a state is not the same as producing an output
&lt;/h3&gt;

&lt;p&gt;Our implementation now makes another distinction visible.&lt;/p&gt;

&lt;p&gt;The transition function selects a destination. The domain operation performs the work needed to reach it. A reader may then display information derived from the resulting state.&lt;/p&gt;

&lt;p&gt;These are related responsibilities, but they are not identical.&lt;/p&gt;

&lt;p&gt;This distinction also appears in early sequential-machine research. George Mealy’s 1955 paper developed systematic methods for synthesizing sequential circuits. The model bearing his name associates output with the current state and input the transition being taken.[4, 5]&lt;/p&gt;

&lt;p&gt;Edward Moore’s 1956 paper examined what could be inferred about finite machines through external experiments. In the machines he defined, the next state depended on the previous state and input, while observable output depended on the current state.[6]&lt;/p&gt;

&lt;p&gt;The conventional distinction is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mealy:
    output = f(state, input)

Moore:
    output = f(state)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our application, consider two different outputs.&lt;/p&gt;

&lt;p&gt;A message reporting that a payment was just recorded belongs to the occurrence of that operation. A status label displaying “Paid” can be derived whenever someone reads the order.&lt;/p&gt;

&lt;p&gt;Reading the label must not record the payment again.&lt;/p&gt;

&lt;p&gt;These are application-level parallels, not a claim that our complete &lt;code&gt;Order&lt;/code&gt; object is a literal Mealy or Moore machine. Payment records and other supporting data remain outside the small control table.&lt;/p&gt;

&lt;p&gt;The useful historical lesson is to ask &lt;strong&gt;where an observable result belongs&lt;/strong&gt;: to handling an input, or to occupying a state.&lt;/p&gt;

&lt;p&gt;A state-derived display is also not automatically a one-time action executed on entry. Showing “Paid” repeatedly and capturing money repeatedly are very different behaviors.&lt;/p&gt;

&lt;h3&gt;
  
  
  What became authoritative?
&lt;/h3&gt;

&lt;p&gt;We can now point to one structure for the status-dependent lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TRANSITIONS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing its shipping entry changes both the destination selected by &lt;code&gt;ship_order()&lt;/code&gt; and the eligibility reported by &lt;code&gt;available_actions()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is a meaningful improvement.&lt;/p&gt;

&lt;p&gt;It does not make the table the sole source of every business rule. Payment consistency still lives in validation. Payment-argument checks still live in the operation. A future change to the lifecycle must remain compatible with both.&lt;/p&gt;

&lt;p&gt;A transition table can also contain the wrong rule. Adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED + SHIP_ORDER → SHIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;would not become correct merely because it was expressed declaratively.&lt;/p&gt;

&lt;p&gt;The benefit is that the rule is visible, shared, and directly testable.&lt;/p&gt;

&lt;p&gt;We also retain the mutation limitation from Part II. A caller can still assign &lt;code&gt;OrderState.SHIPPED&lt;/code&gt; directly and bypass the transition function. Using enum members does not establish an exclusive write boundary.&lt;/p&gt;

&lt;p&gt;For this implementation, the guarantee remains:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Through the controlled operations, a valid order follows a declared lifecycle transition or the request is rejected without changing it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is narrower than “the system can never be wrong.” It is also a guarantee we can inspect and test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Was the dictionary necessary?
&lt;/h3&gt;

&lt;p&gt;For three states and two operations, the earlier guarded functions remain a reasonable alternative.&lt;/p&gt;

&lt;p&gt;They may even be easier to read when no other component needs to inspect the lifecycle.&lt;/p&gt;

&lt;p&gt;The table becomes useful because we now have several consumers of the same rule: operations that change the order, code that reports available actions, and tests that examine the entire state–command surface.&lt;/p&gt;

&lt;p&gt;We have not replaced conditional logic because conditionals are bad. We have given shared lifecycle rules an explicit representation.&lt;/p&gt;

&lt;p&gt;The earlier functions already implemented state-machine behavior. This version makes that behavior a separate model.&lt;/p&gt;

&lt;h3&gt;
  
  
  But what happens when the next decision depends on more than status?
&lt;/h3&gt;

&lt;p&gt;Our table currently answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAID + SHIP_ORDER → SHIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose the business introduces a new requirement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ship only to supported delivery addresses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a proposed extension, not a rule our current code already enforces.&lt;/p&gt;

&lt;p&gt;Consider two internally consistent orders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order A:
    status = PAID
    payment = captured payment
    delivery_address = supported destination

Order B:
    status = PAID
    payment = captured payment
    delivery_address = unsupported destination
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both reach the same table entry.&lt;/p&gt;

&lt;p&gt;Yet the new rule requires different outcomes.&lt;/p&gt;

&lt;p&gt;We could create more states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAID_WITH_SUPPORTED_ADDRESS
PAID_WITH_UNSUPPORTED_ADDRESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then another rule arrives about a payment provider, a retry limit, or a customer restriction. Should each combination become another state?&lt;/p&gt;

&lt;p&gt;The lifecycle table has solved the visibility problem. It has not removed the need for supporting data to influence decisions.&lt;/p&gt;

&lt;p&gt;We can now see the next boundary:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A lifecycle state identifies a behavioral mode. It does not necessarily contain every value needed to choose a transition.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But how do we let those values influence the decision without turning every combination into another lifecycle state?&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;[1]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/enum.html" rel="noopener noreferrer"&gt;enum - Support for enumerations&lt;/a&gt;&lt;/em&gt;. Named members, values, and enum lookup behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[2]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/dataclasses.html" rel="noopener noreferrer"&gt;dataclasses - Data Classes&lt;/a&gt;&lt;/em&gt;. Dataclass fields, generated methods, and the treatment of type annotations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[3]&lt;/strong&gt; Python Software Foundation, &lt;em&gt;&lt;a href="https://docs.python.org/3/library/types.html#types.MappingProxyType" rel="noopener noreferrer"&gt;types.MappingProxyType&lt;/a&gt;&lt;/em&gt;. Read-only access to a mapping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[4]&lt;/strong&gt; Paul E. Black, &lt;a href="https://xlinux.nist.gov/dads/HTML/finiteStateMachine.html" rel="noopener noreferrer"&gt;“Finite State Machine”&lt;/a&gt;, NIST &lt;em&gt;Dictionary of Algorithms and Data Structures&lt;/em&gt;. State-machine components and the distinction between transition-associated and state-associated outputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[5]&lt;/strong&gt; George H. Mealy, &lt;a href="https://www.nokia.com/bell-labs/publications-and-media/publications/a-method-for-synthesizing-sequential-circuits/" rel="noopener noreferrer"&gt;“A Method for Synthesizing Sequential Circuits”&lt;/a&gt;, &lt;em&gt;Bell System Technical Journal&lt;/em&gt;, 1955.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[6]&lt;/strong&gt; Edward F. Moore, &lt;a href="https://www.cs.cmu.edu/~cdm/resources/Moore1956-gedanken-experiments.pdf" rel="noopener noreferrer"&gt;“Gedanken-Experiments on Sequential Machines”&lt;/a&gt;, in &lt;em&gt;Automata Studies&lt;/em&gt;, edited by Claude E. Shannon and John McCarthy, Princeton University Press, 1956.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>statemachines</category>
      <category>programming</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Road to State Machines Part II - How Do We Prevent Impossible Changes?</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Wed, 30 Sep 2026 12:47:16 +0000</pubDate>
      <link>https://dev.to/canburaks/road-to-state-machines-part-ii-how-do-we-prevent-impossible-changes-3jib</link>
      <guid>https://dev.to/canburaks/road-to-state-machines-part-ii-how-do-we-prevent-impossible-changes-3jib</guid>
      <description>&lt;p&gt;Our model can now describe an order’s lifecycle state and retain the payment information that supports it. What it cannot do is enforce the rules we established.&lt;/p&gt;

&lt;p&gt;The status must be created, paid, or shipped. Payment capture may move an order from created to paid; shipping may move it from paid to shipped. The status and payment record must also agree. These were the unresolved requirements at the end of &lt;a href="https://x.com/cbsofyalioglu/status/2102824786657177803" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;How do we move those rules from the explanation into the implementation?&lt;/p&gt;

&lt;p&gt;Let’s continue with the model we already have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operations are still simple assignments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both functions change the record without checking whether the change makes sense.&lt;br&gt;
We do not need a new framework to improve this. We need to make the first decision explicit.&lt;/p&gt;
&lt;h3&gt;
  
  
  Start by protecting the shipping operation
&lt;/h3&gt;

&lt;p&gt;Our shipping rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Only a paid order may be shipped.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The smallest change is to check the current status before assigning the next one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot ship an order while it is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now consider a newly created order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function raises InvalidOrderOperation. The assignment never runs, so the order remains in the created state.&lt;/p&gt;

&lt;p&gt;We have changed more than just the amount of code. The operation now has two possible outcomes: perform the permitted change, or reject the request without changing the order.&lt;/p&gt;

&lt;p&gt;The condition &lt;code&gt;order.status == "paid"&lt;/code&gt; is a precondition: something that must hold for this operation to complete successfully. The check in the function enforces it.[2]&lt;/p&gt;

&lt;p&gt;This protects one path. But does it protect the whole model?&lt;/p&gt;

&lt;h3&gt;
  
  
  A valid status can belong to an invalid order
&lt;/h3&gt;

&lt;p&gt;Let’s construct the inconsistent order we encountered in &lt;a href="https://x.com/cbsofyalioglu/status/2102824786657177803" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# shipped None
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function accepts it.&lt;/p&gt;

&lt;p&gt;Its condition asks whether the status is paid, and the answer is yes. It never asks whether a payment record exists.&lt;/p&gt;

&lt;p&gt;Our first check is correct but insufficient. The order is eligible by its label, yet inconsistent with our business rules.&lt;/p&gt;

&lt;p&gt;These are two different questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is the current order a valid record?&lt;br&gt;
Is this operation allowed from that valid record?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Checking the second does not automatically answer the first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make valid configurations explicit
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://x.com/cbsofyalioglu/status/2102824786657177803" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt;, we required a captured payment record for every paid or shipped order, and no captured payment record for a created order.&lt;/p&gt;

&lt;p&gt;That gives us a small set of combinations to consider:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;No payment record&lt;/th&gt;
&lt;th&gt;Captured payment record&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;created&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Valid&lt;/td&gt;
&lt;td&gt;Invalid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;paid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invalid&lt;/td&gt;
&lt;td&gt;Valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shipped&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invalid&lt;/td&gt;
&lt;td&gt;Valid&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An unknown status is invalid regardless of the payment field.&lt;/p&gt;

&lt;p&gt;Let’s put those checks in one function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown order status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A created order cannot contain a captured payment.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An order marked &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;must contain a Payment record.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first check enforces our vocabulary. In this implementation, the actual values are lowercase strings. &lt;code&gt;PAID&lt;/code&gt; is not silently converted to &lt;code&gt;paid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The other checks enforce agreement between lifecycle state and supporting data.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;isinstance()&lt;/code&gt; check also prevents a string such as "payment-81" from being accepted in place of a Payment object. The annotation &lt;code&gt;Optional[Payment]&lt;/code&gt; describes the intended type, but a plain dataclass does not enforce that annotation at runtime.&lt;/p&gt;

&lt;p&gt;These checks have a deliberately limited scope. They validate the relationship between the order’s status and its payment record. They do not validate every field inside Payment, compare the captured amount with an order total, or prove that a provider captured money.&lt;/p&gt;

&lt;p&gt;Our model still assumes one full payment in one currency. We haven't added an order total or a provider integration, so we shouldn't claim to verify either.&lt;/p&gt;

&lt;h3&gt;
  
  
  These consistency rules are invariants
&lt;/h3&gt;

&lt;p&gt;The rules in &lt;code&gt;validate_order()&lt;/code&gt; are not specific to shipping. They describe what we consider a valid order.&lt;/p&gt;

&lt;p&gt;Let’s call that kind of rule an invariant.&lt;/p&gt;

&lt;p&gt;For this implementation, an invariant is a condition that must hold whenever an order is accepted for processing and after a successful operation returns.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A created order has no captured payment record.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;A paid or shipped order retains its captured payment record.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The distinction from a precondition is useful:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Kind of rule&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Is this order valid?&lt;/td&gt;
&lt;td&gt;Invariant&lt;/td&gt;
&lt;td&gt;A paid order contains a payment record.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May this operation run now?&lt;/td&gt;
&lt;td&gt;Precondition&lt;/td&gt;
&lt;td&gt;Shipping requires a paid order.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What must successful execution establish?&lt;/td&gt;
&lt;td&gt;Postcondition&lt;/td&gt;
&lt;td&gt;Shipping leaves the order shipped and retains its payment.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A postcondition describes what must hold after successful execution.&lt;/p&gt;

&lt;p&gt;The payment record’s continued presence matters. Shipping should change the lifecycle state, not erase the supporting information that made the operation valid.&lt;/p&gt;

&lt;p&gt;Valid endpoints do not prove a valid transition&lt;/p&gt;

&lt;p&gt;Our validator has a subtle limit.&lt;/p&gt;

&lt;p&gt;These two configurations both satisfy it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:
    status = created
    payment = None

After:
    status = shipped
    payment = a Payment record
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nevertheless, moving directly between them would skip the payment transition we defined.&lt;/p&gt;

&lt;p&gt;The destination is valid in isolation. Our lifecycle does not permit the move.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;validate_order()&lt;/code&gt; cannot determine whether the previous state was created, paid, or something else. It receives one record, not a record of how it reached that condition.&lt;/p&gt;

&lt;p&gt;We therefore need both kinds of checks:&lt;/p&gt;

&lt;p&gt;Configuration checks determine whether the fields describe an allowed condition.&lt;/p&gt;

&lt;p&gt;Transition checks determine whether a particular operation may move the order from its current condition to another.&lt;/p&gt;

&lt;p&gt;Neither replaces the other.&lt;/p&gt;

&lt;h3&gt;
  
  
  Put the checks before the changes
&lt;/h3&gt;

&lt;p&gt;Let’s revise both operations.&lt;/p&gt;

&lt;p&gt;First, we validate the existing order. Then we will check whether the requested operation is permitted. Only after those checks pass will we change any fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot record a captured payment &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;while the order is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment must be a Payment record.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot ship an order while it is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These definitions replace the earlier unguarded functions.&lt;/p&gt;

&lt;p&gt;The distinction between the exceptions is intentional.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;InvalidOrderState&lt;/code&gt; means the existing record contradicts our model. A paid order with no payment record belongs in this category.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;InvalidOrderOperation&lt;/code&gt; means the order is valid, but the requested operation is not permitted. A correctly formed created order receiving a shipping request belongs in this category.&lt;/p&gt;

&lt;p&gt;Neither case should be repaired by inventing missing information.&lt;/p&gt;

&lt;p&gt;If payment is absent, shipping must not construct a placeholder payment to satisfy the validator. If the status is unknown, the operation must not guess which known status was intended.&lt;/p&gt;

&lt;p&gt;The request stops at the failed check.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why check the current record first?
&lt;/h3&gt;

&lt;p&gt;Suppose we receive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;status = created
payment = an existing captured payment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without validating the current record, &lt;code&gt;capture_payment()&lt;/code&gt; could accept another payment, overwrite the existing record, and change the status to paid.&lt;/p&gt;

&lt;p&gt;The result would look consistent. But the operation would have hidden an inconsistent input by replacing information.&lt;/p&gt;

&lt;p&gt;Our revised function rejects the order before that happens.&lt;/p&gt;

&lt;p&gt;This gives us a useful rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not use a normal lifecycle operation to silently repair a record that already violates the lifecycle.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A repair process may eventually be necessary. It should make its purpose explicit. We have not designed one here.&lt;/p&gt;

&lt;h3&gt;
  
  
  What successful operations now establish
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;capture_payment()&lt;/code&gt;, the reasoning is:&lt;/p&gt;

&lt;p&gt;A valid created order has no payment. The function accepts a Payment record, stores it, and marks the order as paid. The resulting combination satisfies our consistency rules.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;ship_order()&lt;/code&gt;, the reasoning is:&lt;/p&gt;

&lt;p&gt;A valid paid order already contains a payment. The function changes only the status to shipped. The payment remains attached, so the resulting combination also satisfies the rules.&lt;/p&gt;

&lt;p&gt;All expected rejection conditions occur before either operation mutates the order.&lt;/p&gt;

&lt;p&gt;That placement matters. Changing fields and then raising an exception does not, by itself, undo the assignments.&lt;/p&gt;

&lt;p&gt;Our payment function still performs two separate assignments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Between them, the object temporarily contains a payment while its status is still being created. Under our current assumptions, no other writer, callback, or reader observes the object during that operation. The invariant applies at the operation boundary.&lt;/p&gt;

&lt;p&gt;This is not an atomic transaction or a concurrency guarantee. If another process can observe intermediate writes, or an external operation can fail between them, we will need a stronger boundary.&lt;/p&gt;

&lt;p&gt;For now, we are solving the local problem we actually have.&lt;/p&gt;

&lt;h3&gt;
  
  
  An older way of asking the same correctness question
&lt;/h3&gt;

&lt;p&gt;Once we describe what must be true before and after an operation, we are using a form of reasoning that has a long history.&lt;/p&gt;

&lt;p&gt;In his 1969 paper An Axiomatic Basis for Computer Programming, C. A. R. Hoare developed an approach to reasoning about programs through assertions about their initial and resulting conditions. A common notation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{precondition} command {postcondition}    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For partial correctness, the claim is that when the precondition holds, a terminating execution establishes the postcondition.[2]&lt;/p&gt;

&lt;p&gt;Applied to our example, the intended contract is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{valid order, status is paid}
    ship_order(order)
{valid order, status is shipped, payment is retained}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This specifies what we want, not a formal proof of our Python implementation.&lt;/p&gt;

&lt;p&gt;Dijkstra’s later work on guarded commands made another relevant idea explicit: a command’s eligibility can depend on a Boolean condition placed before it.&lt;/p&gt;

&lt;p&gt;Our shipping check serves that limited purpose. It does not implement Dijkstra’s full calculus, but it follows the same useful discipline: describe when an action is eligible, rather than writing the action alone.&lt;/p&gt;

&lt;p&gt;The historical connection is practical. The important unit is not just the assignment. It is the assignment together with the conditions that make it correct.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check the behavior, including rejection
&lt;/h3&gt;

&lt;p&gt;Let’s run the intended sequence using the same kind of payment record as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit_card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment-81&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;120.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The assertions check more than the final label. They also check that both operations retain the supplied payment record.&lt;/p&gt;

&lt;p&gt;Now test rejection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;unpaid_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-67&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unpaid_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;InvalidOrderOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An unpaid order was allowed to ship.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;unpaid_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;unpaid_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final assertions matter.&lt;/p&gt;

&lt;p&gt;An operation that raises the expected exception after partially changing the record would still be wrong for this contract.&lt;/p&gt;

&lt;p&gt;For valid starting records, our two functions should behave as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Starting status&lt;/th&gt;
&lt;th&gt;capture_payment()&lt;/th&gt;
&lt;th&gt;ship_order()&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;created&lt;/td&gt;
&lt;td&gt;Record payment; become&lt;br&gt;&lt;br&gt;paid&lt;/td&gt;
&lt;td&gt;Reject without changing the order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;paid&lt;/td&gt;
&lt;td&gt;Reject without replacing the payment&lt;/td&gt;
&lt;td&gt;Become&lt;br&gt;&lt;br&gt;shipped&lt;br&gt;&lt;br&gt;; retain payment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shipped&lt;/td&gt;
&lt;td&gt;Reject without replacing the payment&lt;/td&gt;
&lt;td&gt;Reject without changing the order&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Reject without replacing the payment&lt;/p&gt;

&lt;p&gt;Reject without changing the order&lt;/p&gt;

&lt;p&gt;For duplicate shipping, this implementation chooses the rejection policy discussed in &lt;a href="https://x.com/cbsofyalioglu/status/2102824786657177803" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;. Returning an existing shipment would require a shipment result we do not yet store.&lt;/p&gt;

&lt;p&gt;Similarly, &lt;code&gt;capture_payment()&lt;/code&gt; remains a simulation that records the supplied payment. It does not call Stripe, despite the provider name in the example. Rejecting a second call protects this local record; it does not guarantee against external charges.&lt;/p&gt;

&lt;h3&gt;
  
  
  But can another caller still bypass the rules?
&lt;/h3&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;Our functions have improved. The dataclasses remain mutable, and their fields are still public.&lt;/p&gt;

&lt;p&gt;A caller can bypass both operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No validation runs automatically on that assignment. Nothing in our class definition invokes &lt;code&gt;validate_order()&lt;/code&gt;, either during construction or during later field changes.&lt;/p&gt;

&lt;p&gt;Calling the validator afterward will detect the missing payment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Raises InvalidOrderState.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But detection is not prevention.&lt;/p&gt;

&lt;p&gt;There is a second bypass that configuration validation cannot detect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nf"&gt;validate_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Passes: the resulting configuration is internally valid.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The record is valid, but the writer skipped the required transition through paid.&lt;/p&gt;

&lt;p&gt;This is the difference between protecting an operation and protecting every possible write.&lt;/p&gt;

&lt;p&gt;Our guarantee must therefore remain specific:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Through these two functions, a valid order either makes a permitted change or the request is rejected without changing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have not made arbitrary mutation impossible.&lt;/p&gt;

&lt;p&gt;To rely on that guarantee, application writes must pass through the controlled operations. Restricting field assignment or introducing immutable records can help establish that boundary, but neither technique alone decides which lifecycle transitions are legal.&lt;/p&gt;

&lt;p&gt;The rules and the write boundary are separate responsibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  What has improved and what is still implicit?
&lt;/h3&gt;

&lt;p&gt;We have now placed all three categories of rules into executable code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;validate_order()&lt;/code&gt; checks recognized status values and consistent data. &lt;code&gt;capture_payment()&lt;/code&gt; and &lt;code&gt;ship_order()&lt;/code&gt; check the allowed changes. &lt;br&gt;
The operations keep their original names, work with the same Order and Payment models, and still need no external service or framework.&lt;/p&gt;

&lt;p&gt;This is manageable for two operations.&lt;/p&gt;

&lt;p&gt;But look at where the lifecycle is described.&lt;/p&gt;

&lt;p&gt;The valid statuses appear in the validator. The permitted source state for payment capture appears in one function. The permitted source state for shipping appears in another. Their target states appear in assignments.&lt;/p&gt;

&lt;p&gt;To answer “What can happen while an order is paid?”, a reader must inspect the operations.&lt;/p&gt;

&lt;p&gt;A user interface deciding whether to display a shipping action might write another check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;can_ship&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That check describes only status-based eligibility; it does not establish that the record is valid. The actual operation must still validate and reject when necessary.&lt;/p&gt;

&lt;p&gt;More importantly, the interface has begun repeating part of the lifecycle rule. If the shipping rule changes, the write path and the displayed action can drift apart.&lt;/p&gt;

&lt;p&gt;This is not a reason to add a framework immediately. Our current design is small, readable, and already contains state-machine behavior.&lt;/p&gt;

&lt;p&gt;It does reveal the next question.&lt;/p&gt;

&lt;p&gt;The behavior exists, but its complete description is distributed across validation checks, operation checks, and assignments. We reconstructed the table above by reading the functions; the table does not yet govern them.&lt;/p&gt;

&lt;p&gt;We have made individual changes conditional. We have not yet made the entire lifecycle one explicit contract.&lt;/p&gt;

&lt;p&gt;But how do we express that lifecycle in one place so the operations, their tests, and the code displaying available actions don't each maintain their own version of it?&lt;/p&gt;

</description>
      <category>python</category>
      <category>systemdesign</category>
      <category>statemachines</category>
      <category>ai</category>
    </item>
    <item>
      <title>Road to State Machines Part I</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Wed, 23 Sep 2026 18:56:44 +0000</pubDate>
      <link>https://dev.to/canburaks/road-to-state-machines-part-i-2d9k</link>
      <guid>https://dev.to/canburaks/road-to-state-machines-part-i-2d9k</guid>
      <description>&lt;p&gt;Let's begin with a very fundamental question whose answer is not so obvious. &lt;/p&gt;

&lt;p&gt;How to design software that always takes the correct action?&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1 — Designing Systems When the Past Determines What Is Allowed Next
&lt;/h2&gt;

&lt;p&gt;Let's assume we are developing an e-commerce store and are just implementing the shipping feature.&lt;/p&gt;

&lt;p&gt;A single operation that acts on a specific order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ship_order(order)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What should it do?&lt;/p&gt;

&lt;p&gt;That depends on what has already happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the order has just been created, shipping should be rejected because the customer has not paid.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once payment has been captured, the system should create a shipment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the order has already shipped, it should return the existing shipment or reject the duplicate request rather than create another one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the customer has canceled the order, shipping must not happen at all.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;ship_order&lt;/code&gt; command remains the same, but its correct interpretation changes over time.&lt;/p&gt;

&lt;p&gt;This brings us to a situation where the command alone is therefore insufficient to determine the correct behavior. The system must also know something about what happened before.&lt;/p&gt;

&lt;p&gt;That is the basic problem from which state machines emerge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start with the smallest model
&lt;/h3&gt;

&lt;p&gt;Suppose we are building a basic order-fulfillment application.&lt;/p&gt;

&lt;p&gt;Let's start with the most basic implementation; Our very first model contains only an identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can create an order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the application receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can it proceed?&lt;/p&gt;

&lt;p&gt;The object cannot answer because it tells us only which order we are discussing. It does not tell us whether the order was paid, canceled, shipped, or delivered.&lt;/p&gt;

&lt;p&gt;The smallest useful improvement is to retain the order’s current condition.\&lt;br&gt;
Let's improve our model a bit by adding a &lt;code&gt;status&lt;/code&gt; field so that our basic system can distinguish several stages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Their intended progression is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED → PAID → SHIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can implement that progression directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We never captured payment, yet the order is marked as shipped.&lt;/p&gt;

&lt;p&gt;The status field records the order’s current stage. It does not enforce the rules for reaching that stage.&lt;/p&gt;

&lt;h3&gt;
  
  
  What code does not show?
&lt;/h3&gt;

&lt;p&gt;The model now has two fields. However, they do not do the same work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;id&lt;/code&gt; names the order. Change it, and you are talking about a different order. It does not change what &lt;code&gt;ship_order&lt;/code&gt; may do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;status&lt;/code&gt; sits next to it, as if it were the same kind of value. It is not. It bears a role the field does not show. Change &lt;code&gt;created&lt;/code&gt; to &lt;code&gt;paid&lt;/code&gt;, and the system is allowed to ship. Change it to &lt;code&gt;shipped&lt;/code&gt;, and the same command must stop.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That role is invisible in the class.&lt;/p&gt;

&lt;p&gt;Both fields are strings, but our business rules give them different responsibilities. The status should influence whether shipping is allowed; our current code does not check it.&lt;/p&gt;

&lt;p&gt;Both fields actually store data, but one of them has a different responsibility.&lt;/p&gt;

&lt;p&gt;Let's call that role &lt;strong&gt;state&lt;/strong&gt;, for now. That is the role that changes how the system acts next.&lt;/p&gt;

&lt;p&gt;Let's improve the model a bit by adding a &lt;code&gt;customer_name&lt;/code&gt; field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three fields. Two of them still haven't decided what happens next.&lt;/p&gt;

&lt;p&gt;Changing the &lt;code&gt;customer_name&lt;/code&gt; from &lt;code&gt;Alice&lt;/code&gt; to &lt;code&gt;Alice Russel&lt;/code&gt; does not necessarily affect whether the order may be shipped. However, changing the &lt;code&gt;status&lt;/code&gt; from &lt;code&gt;created&lt;/code&gt; to &lt;code&gt;shipped&lt;/code&gt; does.&lt;/p&gt;

&lt;p&gt;Change &lt;code&gt;status&lt;/code&gt; from &lt;code&gt;created&lt;/code&gt; to &lt;code&gt;shipped&lt;/code&gt;, and shipping does care. That field is still doing the other job. That is still state.&lt;/p&gt;

&lt;p&gt;The status changes the set of valid future operations. That makes it a &lt;strong&gt;behavioral state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A useful distinction is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ordinary data: describes the entity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Behavioral state: changes how the entity may respond&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But... Although it is useful, the boundaries of this distinction are not so rigid.&lt;/p&gt;

&lt;p&gt;Let me add one more field, &lt;code&gt;delivery_address&lt;/code&gt;, to our model to make my point clear.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A delivery address may initially be ordinary data. Once the package has been handed to a carrier, changing that address may become forbidden or require a separate process. The field itself has not changed, but its role in the system’s behavior has.&lt;/p&gt;

&lt;p&gt;State is therefore not an intrinsic property of a database column. It is a role information plays in deciding what may happen next.&lt;/p&gt;

&lt;p&gt;So the distinction is contextual.&lt;/p&gt;

&lt;h3&gt;
  
  
  A short name for a longer past
&lt;/h3&gt;

&lt;p&gt;The record says &lt;code&gt;status = "paid"&lt;/code&gt;. That is where the order is. It is not how the order got there.&lt;/p&gt;

&lt;p&gt;One order can be paid by card, while another can be paid by bank transfer.&lt;/p&gt;

&lt;p&gt;The paths differ, but both orders are marked as &lt;code&gt;PAID&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For shipping, the path may not matter. Paid is enough. The state hides the difference.&lt;/p&gt;

&lt;p&gt;Let's call the events we left behind &lt;strong&gt;history&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The state summarizes a relevant consequence of the past. It does not preserve everything that happened.&lt;/p&gt;

&lt;p&gt;We’ll use &lt;strong&gt;history&lt;/strong&gt; to mean the sequence of events that led to the current situation, whether or not we store that sequence explicitly.&lt;/p&gt;

&lt;p&gt;Whether a summary is sufficient depends on the decision we need to make. Consider a future refund operation. A &lt;code&gt;paid&lt;/code&gt; label alone would not give us the payment reference or amount needed to issue the refund.&lt;/p&gt;

&lt;p&gt;So, improve our system a bit more by adding a &lt;code&gt;Payment&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this example, each order has at most one payment that covers the full amount, and all amounts use the same currency. We use Decimal to represent monetary values.&lt;/p&gt;

&lt;p&gt;A paid order might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit_card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment-81&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;captured_amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;120.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the model includes payment details, our simulated payment function should store them too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;capture_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have three related concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lifecycle state&lt;/strong&gt; helps determine which operations are eligible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Supporting data&lt;/strong&gt; supplies details for those operations and may impose additional conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;History&lt;/strong&gt; describes the events that produced the current situation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What the model still allows
&lt;/h3&gt;

&lt;p&gt;We have already shown an invalid change: shipping an unpaid order. Adding more fields leaves two further problems unresolved.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inconsistent combinations
&lt;/h4&gt;

&lt;p&gt;For this simplified lifecycle, let’s require a captured payment record for every &lt;code&gt;paid&lt;/code&gt; or &lt;code&gt;shipped&lt;/code&gt; order, and no captured payment record for a &lt;code&gt;created&lt;/code&gt; order.&lt;/p&gt;

&lt;p&gt;The model does not enforce those rules. It accepts an order marked as paid without a payment record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also accepts an order marked as created with the captured payment we constructed earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-66&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delivery_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Istanbul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These combinations contradict our stated rules. The additional fields give us a richer record, but no checks ensure that their values agree.&lt;/p&gt;

&lt;h4&gt;
  
  
  Unknown status values
&lt;/h4&gt;

&lt;p&gt;Because &lt;code&gt;status&lt;/code&gt; is an unrestricted string, the model also accepts values outside our intended lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shiped&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some_unknown_status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python accepts both assignments. Neither value belongs to the vocabulary we intended to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  The record is our model of reality
&lt;/h3&gt;

&lt;p&gt;There is another boundary to keep in mind. A record marked &lt;code&gt;paid&lt;/code&gt; tells us what the application has stored. By itself, it does not prove that a payment provider captured the money.&lt;/p&gt;

&lt;p&gt;In a real integration, payment could succeed while the local update fails. Our records could then disagree with the provider.&lt;/p&gt;

&lt;p&gt;Those failures belong to later parts of the tutorial. Here, we are examining a simpler problem that already exists with one writer and no external services: the model accepts changes that violate our own rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remembering a condition and enforcing its rules
&lt;/h3&gt;

&lt;p&gt;The&amp;nbsp;&lt;code&gt;status&lt;/code&gt; field&amp;nbsp;can&amp;nbsp;tell&amp;nbsp;us&amp;nbsp;where&amp;nbsp;the&amp;nbsp;order&amp;nbsp;claims&amp;nbsp;to&amp;nbsp;be.&lt;/p&gt;

&lt;p&gt;It&amp;nbsp;cannot&amp;nbsp;say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Which&amp;nbsp;values&amp;nbsp;are&amp;nbsp;valid? (such as "created" or "CREATED")&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which&amp;nbsp;changes&amp;nbsp;are&amp;nbsp;allowed? (such as changing from "paid" to "shipped" requires a payment)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which&amp;nbsp;condition&amp;nbsp;must&amp;nbsp;come&amp;nbsp;first? (such as changing from "created" to "paid" is allowed)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which&amp;nbsp;operations&amp;nbsp;must&amp;nbsp;be&amp;nbsp;rejected? (such as changing from "created" to "shipped" must be forbidden)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's&amp;nbsp;call&amp;nbsp;this&amp;nbsp;the&amp;nbsp;difference&amp;nbsp;between&amp;nbsp;the&amp;nbsp;&lt;strong&gt;memory&amp;nbsp;problem&lt;/strong&gt;&amp;nbsp;and&amp;nbsp;the&amp;nbsp;&lt;strong&gt;correctness&amp;nbsp;problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We can now distinguish two problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The memory problem:&lt;/strong&gt; retain enough information from the past to inform the next decision.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The correctness problem:&lt;/strong&gt; enforce the business rules governing valid conditions and changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We still need to enforce three kinds of rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Valid values:&lt;/strong&gt; the status must be &lt;code&gt;created&lt;/code&gt;, &lt;code&gt;paid&lt;/code&gt;, or &lt;code&gt;shipped&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Allowed transitions:&lt;/strong&gt; a simulated successful payment moves an order from &lt;code&gt;created&lt;/code&gt; to &lt;code&gt;paid&lt;/code&gt;; shipping moves it from &lt;code&gt;paid&lt;/code&gt; to &lt;code&gt;shipped&lt;/code&gt;. Shipping directly from &lt;code&gt;created&lt;/code&gt; must be rejected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent data:&lt;/strong&gt; a &lt;code&gt;paid&lt;/code&gt; or &lt;code&gt;shipped&lt;/code&gt; order must retain its captured payment record.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A transition is a change from one state to another. Recording the current state does not tell our code which transitions to allow.&lt;/p&gt;

&lt;p&gt;Our intended status values give us a vocabulary. Transition rules give us a grammar.&lt;/p&gt;

&lt;p&gt;We can name the stages an order may occupy, but our implementation still accepts paths that the business forbids. The rules exist in our explanation; they are not yet enforced by the code.&lt;/p&gt;

&lt;p&gt;The next step is to make those rules explicit and enforce them whenever the order changes.&lt;/p&gt;

&lt;p&gt;That is where we begin building a state machine.&lt;/p&gt;

</description>
      <category>python</category>
      <category>statemachines</category>
      <category>systemdesign</category>
      <category>ai</category>
    </item>
    <item>
      <title>Python Decorators: A Comprehensive Guide</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Fri, 03 Jan 2025 07:55:37 +0000</pubDate>
      <link>https://dev.to/canburaks/python-decorators-a-comprehensive-guide-43ke</link>
      <guid>https://dev.to/canburaks/python-decorators-a-comprehensive-guide-43ke</guid>
      <description>&lt;p&gt;When I started programming with Python, if I am not mistaken, the version was 3.3. Therefore, when I started programming, decorators had been available to the Python community for a long time.&lt;/p&gt;

&lt;p&gt;Function decorators came to Python with version 2.2 and Class decorators came to Python with version 2.6.&lt;/p&gt;

&lt;p&gt;Personally, I see Python's Decorator feature as a very powerful feature of the language.&lt;/p&gt;

&lt;p&gt;Actually, my aim is to make a series of articles about the most difficult to understand topics in Python. I plan to cover these topics, which are a little more than ten, one by one.&lt;/p&gt;

&lt;p&gt;In this article, I will try to touch on every part of the Decorators topic as much as I can.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Historical Context
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Early Days (Pre-Python 2.2):&lt;/strong&gt; Before decorators, modifying functions or classes often involved manual wrapping or monkey-patching, which was cumbersome and less readable.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Metaclasses (Python 2.2):&lt;/strong&gt; Metaclasses provided a way to control class creation, offering some of the functionality that decorators would later provide, but they were complex for simple modifications.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;PEP 318 (Python 2.4):&lt;/strong&gt;  Decorators were formally introduced in Python 2.4 through &lt;a href="https://peps.python.org/pep-0318/" rel="noopener noreferrer"&gt;PEP 318&lt;/a&gt;. The proposal was inspired by annotations in Java and aimed to provide a cleaner, more declarative way to modify functions and methods.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Class Decorators (Python 2.6):&lt;/strong&gt; Python 2.6 extended decorator support to classes, further enhancing their versatility.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Widespread Adoption:&lt;/strong&gt; Decorators quickly became a popular feature, used extensively in frameworks like Flask and Django for routing, authentication, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. What are Decorators?
&lt;/h2&gt;

&lt;p&gt;In essence, &lt;a href="https://en.wikipedia.org/wiki/Decorator_pattern" rel="noopener noreferrer"&gt;a decorator is a design pattern&lt;/a&gt; in Python that allows you to modify the behavior of a function or a class without changing its core structure. Decorators are a form of metaprogramming, where you're essentially writing code that manipulates other code.&lt;/p&gt;

&lt;p&gt;You know &lt;a href="https://realpython.com/python-scope-legb-rule/" rel="noopener noreferrer"&gt;Python resolve names using the scope given in order below&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Local&lt;/li&gt;
&lt;li&gt;Enclosing&lt;/li&gt;
&lt;li&gt;Global&lt;/li&gt;
&lt;li&gt;Built-in&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Decorators are sit Enclosing scope, which is closely related to the &lt;a href="https://en.wikipedia.org/wiki/Closure_(computer_programming)" rel="noopener noreferrer"&gt;Closure concept&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Idea:&lt;/strong&gt; A decorator takes a function as input, adds some functionality to it, and returns a modified function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; Think of a decorator as a gift wrapper. You have a gift (the original function), and you wrap it with decorative paper (the decorator) to make it look nicer or add extra features (like a bow or a card). The gift inside remains the same, but its presentation or associated actions are enhanced.&lt;/p&gt;

&lt;h2&gt;
  
  
  A) Decorator Variations: Function-based vs. Class-based
&lt;/h2&gt;

&lt;p&gt;Most decorators in Python are implemented using functions, but you can also create decorators using classes.&lt;br&gt;
Function-based decorators are more common and simpler, while class-based decorators offer additional flexibility.&lt;/p&gt;
&lt;h3&gt;
  
  
  Function-based Basic Decorator Syntax
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Do something before calling the decorated function
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Before function call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Do something after calling the decorated function
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;After function call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@my_decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;my_decorator&lt;/code&gt; is the decorator function. It takes the function func to be decorated as input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wrapper&lt;/code&gt; is an inner function that wraps the original function's call. It can execute code before and after the original function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@my_decorator&lt;/code&gt; is the decorator syntax. It's equivalent to &lt;code&gt;say_hello = my_decorator(say_hello)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Class-based Basic Decorator Syntax
&lt;/h3&gt;

&lt;p&gt;These use classes instead of functions to define decorators.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDecorator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Do something before calling the decorated function
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Before function call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Do something after calling the decorated function
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;After function call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="nd"&gt;@MyDecorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MyDecorator&lt;/code&gt; is a class that acts as a decorator.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;__init__&lt;/code&gt; method stores the function to be decorated.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;__call__&lt;/code&gt; method makes the class instance callable, allowing it to be used like a function.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  B) &lt;strong&gt;Implementing a Simple Decorator&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The fundamental concept of decorators is that they are functions that take another function as an argument and extend its behavior without explicitly modifying it.&lt;br&gt;
Here's the simplest form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Something is happening before the function is called.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Something is happening after the function is called.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="c1"&gt;# Using the decorator with @ syntax
&lt;/span&gt;&lt;span class="nd"&gt;@my_decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# When we call say_hello()
&lt;/span&gt;&lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# This is equivalent to:
# say_hello = my_decorator(say_hello)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  C) Implementing a Decorator with Arguments
&lt;/h2&gt;

&lt;p&gt;Let's create a decorator that logs the execution time of a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator_with_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;    &lt;span class="c1"&gt;# Accept any number of arguments
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Arguments received: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Pass arguments to the original function
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@decorator_with_args&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Prints arguments then "Hi, Alice!"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  D) Implementing a Parameterized Decorator
&lt;/h2&gt;

&lt;p&gt;These are decorators that can accept their own parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="nd"&gt;@repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bob&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Prints "Hello Bob" three times
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  E) Implementing a Class Decorator
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;singleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;get_instance&lt;/span&gt;

&lt;span class="nd"&gt;@singleton&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Initializing database connection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Creating multiple instances actually returns the same instance
&lt;/span&gt;&lt;span class="n"&gt;db1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Prints initialization
&lt;/span&gt;&lt;span class="n"&gt;db2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# No initialization printed
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db1&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;db2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  F) Implementing Method Decorators
&lt;/h2&gt;

&lt;p&gt;These are specifically designed for class methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;debug_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Calling method &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@debug_method&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  G) Implementing Decorator Chaining
&lt;/h2&gt;

&lt;p&gt;Multiple decorators can be applied to a single function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;b&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/b&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@bold&lt;/span&gt;
&lt;span class="nd"&gt;@italic&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;  &lt;span class="c1"&gt;# Outputs: &amp;lt;b&amp;gt;&amp;lt;i&amp;gt;Hello!&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Decorators are applied from bottom to top.&lt;/li&gt;
&lt;li&gt;  It is more like in what we do in math: &lt;code&gt;f(g(x))&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;italic&lt;/code&gt; is applied first, then &lt;code&gt;bold&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  H) What happens if we don't use @functools.wraps ?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;functools.wraps&lt;/code&gt; decorator, &lt;a href="https://docs.python.org/3/library/functools.html#functools.wraps" rel="noopener noreferrer"&gt;See docs&lt;/a&gt;, is a helper function that preserves the metadata of the original function (like its name, docstring, and signature) when you wrap it with a decorator. If you don't use it, you'll lose this important information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Wrapper docstring&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@my_decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_function&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;My function docstring&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__doc__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wrapper
Wrapper docstring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The original function's name (&lt;code&gt;my_function&lt;/code&gt;) and docstring ("My function docstring") are lost.&lt;/li&gt;
&lt;li&gt;  This can make debugging and introspection difficult.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution: Use &lt;code&gt;functools.wraps&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@functools.wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Wrapper docstring&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@my_decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_function&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;My function docstring&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__doc__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_function
My function docstring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Benefits of &lt;code&gt;functools.wraps&lt;/code&gt;:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Preserves function metadata.&lt;/li&gt;
&lt;li&gt;  Improves code readability and maintainability.&lt;/li&gt;
&lt;li&gt;  Makes debugging easier.&lt;/li&gt;
&lt;li&gt;  Helps with introspection tools and documentation generators.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I) Decorators with State
&lt;/h2&gt;

&lt;p&gt;Decorators can also maintain state between function calls. This is particularly useful for scenarios like caching or counting function calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;count_calls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Call &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;calls&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@count_calls&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Call 1 of say_hello
&lt;/span&gt;&lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Call 2 of say_hello
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call 1 of say_hello
Hello!
Call 2 of say_hello
Hello!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;p&gt;The wrapper function maintains a counter (calls) that increments each time the decorated function is called.&lt;br&gt;
This is a simple example of how decorators can be used to maintain state.&lt;/p&gt;

&lt;h2&gt;
  
  
  J) Best Practices for Python Decorators
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Use &lt;code&gt;functools.wraps&lt;/code&gt;:&lt;/strong&gt; Always use &lt;code&gt;@functools.wraps&lt;/code&gt; in your decorators to preserve the original function's metadata.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Keep Decorators Simple:&lt;/strong&gt; Decorators should ideally do one specific thing and do it well. This makes them more reusable and easier to understand.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Document Your Decorators:&lt;/strong&gt; Explain what your decorator does, what arguments it takes, and what it returns.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Test Your Decorators:&lt;/strong&gt; Write unit tests to ensure your decorators work as expected in various scenarios.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Consider the Order of Chaining:&lt;/strong&gt; Be mindful of the order when chaining multiple decorators, as it affects the execution flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  K) Bad Implementations (Anti-Patterns)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Overly Complex Decorators:&lt;/strong&gt; Avoid creating decorators that are too complex or try to do too many things. This makes them hard to understand, maintain, and debug.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Ignoring &lt;code&gt;functools.wraps&lt;/code&gt;:&lt;/strong&gt; Forgetting to use &lt;code&gt;@functools.wraps&lt;/code&gt; leads to loss of function metadata, which can cause issues with introspection and debugging.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Side Effects:&lt;/strong&gt; Decorators should ideally not have unintended side effects outside of modifying the decorated function.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hardcoding Values:&lt;/strong&gt; Avoid hardcoding values within decorators. Instead, use decorator factories to make them configurable.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Not Handling Arguments Properly:&lt;/strong&gt; Ensure your &lt;code&gt;wrapper&lt;/code&gt; function can handle any number of positional and keyword arguments using &lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt; if the decorator is meant to be used with a variety of functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  L) 10. Real-World Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Logging:&lt;/strong&gt; Recording function calls, arguments, and return values for debugging or auditing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Timing:&lt;/strong&gt; Measuring the execution time of functions for performance analysis.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Caching:&lt;/strong&gt; Storing the results of expensive function calls to avoid redundant computations (memoization).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Authentication and Authorization:&lt;/strong&gt; Verifying user credentials or permissions before executing a function.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Input Validation:&lt;/strong&gt; Checking if the arguments passed to a function meet certain criteria.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Rate Limiting:&lt;/strong&gt; Controlling the number of times a function can be called within a specific time period.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Retry Logic:&lt;/strong&gt; Automatically retrying a function call if it fails due to a temporary error.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Framework-Specific Tasks:&lt;/strong&gt; Frameworks like Flask and Django use decorators for routing (mapping URLs to functions), registering plugins, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  M) Curated Lists of Python Decorators
&lt;/h2&gt;

&lt;p&gt;You can find a curated lists of Python decorators below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lord63/awesome-python-decorator" rel="noopener noreferrer"&gt;Awesome Python Decorators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.python.org/moin/PythonDecoratorLibrary" rel="noopener noreferrer"&gt;Python Decorator Library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  N) 11. Conclusion
&lt;/h2&gt;

&lt;p&gt;Decorators are a powerful and elegant feature in Python that allows you to enhance functions and classes in a clean and declarative way.&lt;br&gt;
By understanding the principles, best practices, and potential pitfalls, you can effectively leverage decorators to write more modular, maintainable, and expressive code.&lt;br&gt;
They are a valuable tool in any Python programmer's arsenal, especially when working with frameworks or building reusable components.&lt;/p&gt;

</description>
      <category>python</category>
      <category>backend</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Beginner's Guide to Structure SEO-friendly URLs</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Thu, 28 Dec 2023 13:05:38 +0000</pubDate>
      <link>https://dev.to/canburaks/a-beginners-guide-to-structure-blog-post-urls-leg</link>
      <guid>https://dev.to/canburaks/a-beginners-guide-to-structure-blog-post-urls-leg</guid>
      <description>&lt;h1&gt;
  
  
  A Beginner's Guide to Structure Blog Post URLs
&lt;/h1&gt;

&lt;p&gt;Before sharing your first blog post, one of the things you should definitely pay attention to is how your blog posts and their URLs should be organized. I will talk about &lt;a href="https://bloggingplatforms.app/blog/beginners-guide-to-structure-blog-post-urls" rel="noopener noreferrer"&gt;how you should structure your blog posts URLs&lt;/a&gt;, best practices and the things you should avoid.&lt;/p&gt;

&lt;p&gt;Please do not skip this article if your intent is ranking on search engines. I have learned these lessons in a hard way. I wasted a great deal of time to fix my mistakes.&lt;/p&gt;

&lt;p&gt;Therefore, I definitely recommend reading this article before writing your first blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Beginner’s Guide for an SEO-Friendly URL Structure
&lt;/h2&gt;

&lt;p&gt;Let's get started with the essential questions that clarify the importance of having a proper URL structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when you don't have a proper URL structure?
&lt;/h3&gt;

&lt;p&gt;If you don't follow the practices here, it may be possible for Google to index a page differently than you thought. (We’ll discuss that later)&lt;/p&gt;

&lt;p&gt;You link to another article in one of your posts. Later, you realize the link targets a URL other than Google has indexed.&lt;/p&gt;

&lt;p&gt;If rankings on search engines are your concern, you should either change the link’s address to the address of what Google indexed or manually remove that page from Google search results. If you are dealing with many pages, such as an e-commerce website, it would take you many hours to fix that.&lt;/p&gt;

&lt;p&gt;You can watch &lt;a href="https://www.youtube.com/watch?v=FHjVmi1tkEw" rel="noopener noreferrer"&gt;the official answer of Google&lt;/a&gt; that mentions the potential adverse effects when you change your URL structure later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Analogy to Understand a URL and a Domain Name
&lt;/h3&gt;

&lt;p&gt;Maybe an analogy explains better what a URL and a domain name are.&lt;/p&gt;

&lt;p&gt;URL is the abbreviation of Uniform Resource Locator (URL), colloquially known as a web page’s unique address.&lt;/p&gt;

&lt;p&gt;A URL has different parts, such as protocol, domain, TLD, subdirectory, slug, and URL parameters.&lt;/p&gt;

&lt;p&gt;The part after the TLD (Top Level Domain)  is customizable by you (if you are the registrant of that domain) and the main topic of this article is how you should customize that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzv53llhawt8j2whr41vd.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzv53llhawt8j2whr41vd.webp" alt="URL Parts" width="798" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Almost all of us have mobile phones. A mobile phone has a unique phone number similar to a website’s URL. It is difficult to remember phone numbers; thus, we save a phone number with a proper name, such as whose it belongs. After, when we try to call a friend in the contact list, the mobile device calls the number of that friend.&lt;/p&gt;

&lt;p&gt;This is similar to a website such as the one you are reading.  A website's actual address consists of several numbers that we call IP numbers.  IP numbers are also difficult to remember, like mobile phone numbers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5tstg45cdqs7mutpqfn8.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5tstg45cdqs7mutpqfn8.webp" alt="Mobile numbers and IP numbers" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wouldn’t it be nice if we could save those IP numbers with a proper name?&lt;/p&gt;

&lt;p&gt;Yes, and we are doing that. Browsers do that for us in the background.&lt;/p&gt;

&lt;p&gt;The main difference between those two situations is to whom those records are available and accessible.&lt;/p&gt;

&lt;p&gt;A contact with a name and a phone number exists only on the registered device.&lt;/p&gt;

&lt;p&gt;On the other hand, when you buy (!) a domain name, you actually rent it for a limited time. More specifically, you become the domain holder and have the right to which IP address that domain name should point out.&lt;/p&gt;

&lt;p&gt;Moreover, the record that holds the domain name and the IP number it points out is globally available.&lt;/p&gt;

&lt;p&gt;How browsers know the IP number of any domain is the topic of &lt;a href="https://en.wikipedia.org/wiki/Public_recursive_name_server" rel="noopener noreferrer"&gt;public DNS (Domain Name System) resolver&lt;/a&gt; and it is out of the scope of this article.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part I: Make A Blog URL structure as SEO-friendly
&lt;/h2&gt;

&lt;p&gt;The first thing to understand is the ideal pattern for a blog post URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which URL structure is Better: Flat or Hierarchical?
&lt;/h3&gt;

&lt;p&gt;At a higher level, you have two options to structure your blog post URLs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Flat URL structure&lt;/li&gt;
&lt;li&gt;Hierarchical URL structure (Top-down or Pyramid)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm5e6zerqlu4bb7v8hekn.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm5e6zerqlu4bb7v8hekn.webp" alt="URL Structures" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to an &lt;a href="https://youtu.be/GAZ6j00geMk?si=xJpkTPwULiy2PQOf&amp;amp;t=98" rel="noopener noreferrer"&gt;official answer from Google&lt;/a&gt;, using a hierarchical URL rather than a flat one seems more beneficial.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the Benefits of Using a Hierarchical URL structure
&lt;/h3&gt;

&lt;p&gt;It helps you to keep semantically related content together. By doing that, you signal a message to the crawlers. &lt;a href="https://youtu.be/wsrL6l2Fxvo?si=11AF5zOwaipc8GDf&amp;amp;t=3525" rel="noopener noreferrer"&gt;This helps search engines understand the context of the post better&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moreover, separating blog posts according to their categories allows you to create different content silos for different topics.  Even &lt;a href="https://bloggingplatforms.app/blog/best-free-platforms-for-blogging" rel="noopener noreferrer"&gt;free blogging platforms&lt;/a&gt; support that feature.&lt;/p&gt;

&lt;p&gt;But what that means?  Let me explain.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is a Content Silo?
&lt;/h4&gt;

&lt;p&gt;A content silo is a method of grouping related content together on your website to establish the site's keyword-based topical areas or themes. Think of it as organizing your website into different sections or "silos," each dedicated to a specific topic.&lt;/p&gt;

&lt;p&gt;This structure helps search engines understand the themes of your site, and it also enhances user experience by making navigation easier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzz3fbd7sbu9ag6t9mx10.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzz3fbd7sbu9ag6t9mx10.webp" alt="Content Silos" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In other words, content silos may play a role in being an authority on different topics.&lt;/p&gt;

&lt;p&gt;Another question is coming.&lt;/p&gt;

&lt;h4&gt;
  
  
  What does being an authority on a topic means?
&lt;/h4&gt;

&lt;p&gt;One of &lt;a href="https://developers.google.com/search/docs/fundamentals/creating-helpful-content#eat" rel="noopener noreferrer"&gt;the four pillars of search engine optimization (E-E-A-T) is being an authority (A)&lt;/a&gt; on the topic you want to rank for.  It means more than just knowledge. People with authority on a specific topic are trusted and influential people on that topic. They consistently provide value to others through their expertise.&lt;/p&gt;

&lt;p&gt;This concept is also known as topical authority.&lt;/p&gt;

&lt;h4&gt;
  
  
  What does topical authority mean?
&lt;/h4&gt;

&lt;p&gt;The term refers to the level of expertise or credibility a website or content creator has on a specific subject matter. It's like being the go-to source for information on that particular topic. The concept is rooted in the idea that search engines, like Google, favor sites that provide comprehensive and reliable information on specific topics.&lt;/p&gt;

&lt;p&gt;By consistently grouping related content under specific category slugs, you're showing search engines that you have multiple pieces of content revolving around this topic. This can help to establish your site as an authoritative source on that subject.&lt;/p&gt;

&lt;p&gt;If you need a deeper knowledge about that, I can suggest you to read these two articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://inlinks.com/insight/inlinks-a-tool-for-building-topical-authority/" rel="noopener noreferrer"&gt;Topical Authority for SEO: What it is and How to Build It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.holisticseo.digital/theoretical-seo/topical-authority/" rel="noopener noreferrer"&gt;Importance of Topical Authority for SEO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considering the benefits I mentioned above, I can say that using a hierarchical URL structure is better.&lt;/p&gt;

&lt;p&gt;This means you should categorize your blog posts and insert the category’s slug between a&amp;nbsp; post slug and the domain, separated by a slash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preventing Duplicate Content
&lt;/h3&gt;

&lt;p&gt;However, if you are using the URL structure that follows &lt;code&gt;/category/post-slug&lt;/code&gt;, it is possible that you will have duplicate content issues.  Let me clarify.&lt;/p&gt;

&lt;p&gt;It is not a rare scenario for a post with multiple categories.&lt;/p&gt;

&lt;p&gt;This causes content duplication.&lt;/p&gt;

&lt;p&gt;To prevent this,  you must use &lt;a href="https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls" rel="noopener noreferrer"&gt;the canonical address method&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a given post with multiple categories, you choose one of them as the canonical address and use that one in all versions of that post. By doing that, you tell Google to index only the canonical address and ignore others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4keydeea5rhv8meub9io.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4keydeea5rhv8meub9io.webp" alt="Post with Multiple Categories" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we can proceed to the next part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part II: Making Blog Post URLs as SEO-friendly
&lt;/h2&gt;

&lt;p&gt;Keyword research is the first step in search engine optimization.&amp;nbsp; However, it is not the scope of this article.&lt;/p&gt;

&lt;p&gt;For the sake of the continuity of this article, I’ll assume that you did keyword research and decided to rank one of those keywords from the research.&lt;/p&gt;

&lt;p&gt;So, we have a keyword that we want to rank for.&lt;/p&gt;

&lt;p&gt;Before proceeding, I must mention one very important term: slug.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a slug?
&lt;/h3&gt;

&lt;p&gt;Slug is a part of the URL and makes a page distinct from another. The human-readable and URL-normalized version of the given text can be a category name or a post title.&amp;nbsp; The blogging platform you choose generally automates this text process but can be changed manually.&lt;/p&gt;

&lt;p&gt;For instance, in &lt;code&gt;www.example.com/books/fiction&lt;/code&gt;, the slug, 'books/fiction', is composed of the slugified version of category and the product names.&lt;/p&gt;

&lt;p&gt;This is the most important part of structuring your blog post URLs, and it must be applied to both the category and the post part of a URL.&lt;/p&gt;

&lt;p&gt;We have already decided which keyword we want to rank for.&lt;/p&gt;

&lt;p&gt;One of the best practices for search engine optimization is using the keyword in the URL. But why?&lt;/p&gt;

&lt;h3&gt;
  
  
  Does using keywords in URLs Affect Rankings?
&lt;/h3&gt;

&lt;p&gt;Yes, using keywords in URLs is a ranking factor. On the other hand, according to Google Search Advocate John Mueller, &lt;a href="https://youtu.be/kzM7fi43cMc?si=fngCc0it4QSiEHxF&amp;amp;t=3096" rel="noopener noreferrer"&gt;it has a very lightweight effect&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This means we will mention the keyword in the slug.&lt;/p&gt;

&lt;p&gt;In general, the post slug is auto-generated by your blogging platform. If it is auto-generated, you’ll see that the slug of the post is based on the title of the post. It is a common practice also.&lt;/p&gt;

&lt;p&gt;The more important part is how you customize that slug, either based on the title or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Best Practices for Structuring Blog Post URLs
&lt;/h3&gt;

&lt;p&gt;When structuring the URLs of your blog posts for optimal performance in search engine optimization (SEO), it is important to follow a set of best practices that make your URLs more readable and relevant to both users and search engines.&lt;/p&gt;

&lt;p&gt;To apply these practices, your blogging platform must support a category and tag system. Otherwise, you can check &lt;a href="https://bloggingplatforms.app/features/category-tag-system" rel="noopener noreferrer"&gt;the blogging platforms that support the category system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are some guidelines to structure your blog post URLs effectively:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Descriptive Keywords&lt;/strong&gt;: Incorporate the primary keyword related to your blog post into the URL to explain what the post is about. This helps with SEO and gives users an idea of what to expect before they click the link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it Simple and Specific&lt;/strong&gt;: Aim to keep your URL structure simple, short, and precise. Although &lt;a href="https://youtu.be/DVdOUqaBQ00?si=tZvBvk8nXONir4XV" rel="noopener noreferrer"&gt;the URL length does not affect rankings&lt;/a&gt;, it would be nice to avoid long and complex URLs. By following this practice, you can focus on the most important keywords that capture the essence of your blog post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Hyphens to Separate Words&lt;/strong&gt;: Even though it doesn't affect rankings which one do you prefer, to enhance readability, use hyphens rather than underscores to separate words within your URL. You&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Unnecessary Words&lt;/strong&gt;: Trim stop words like "and," "or," "but," "the," etc., as they add unnecessary length and don't contribute much to search engine understanding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Utilize Lowercase Letters&lt;/strong&gt;: URLs are case-sensitive by definition. Although it is possible to use all upper case, all lowercase, or maybe mixed case, it's a standard practice to use all lowercase letters in URLs to avoid confusion. &lt;a href="https://youtu.be/d1xb84T0olI?si=kKbR0DGGBx4u5acL" rel="noopener noreferrer"&gt;Google says its crawler can handle those variations&lt;/a&gt;, but it needs to be figured out first. Therefore, please follow all lowercase practice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omit Special Characters&lt;/strong&gt;: Special characters and symbols can make URLs look cluttered and can cause issues with some browsers and servers. Use letters without the diacritical version. Stick to letters and numbers only if that number makes sense where possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exclude Dates and Numbers&lt;/strong&gt;: Unless they're integral to the content, avoid including dates and excessive numbers, which can make your URL unnecessarily long and less evergreen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Keyword Repetition&lt;/strong&gt;: Don't overuse keywords in the URL as this can look spammy and may not be beneficial for SEO.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foa7wneov5e5ib70mb41w.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foa7wneov5e5ib70mb41w.webp" alt="Slugifying" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows an example slug of a post with a title "What types of Kyber Crystals Exists?" located under "Star Wars" category.&lt;/p&gt;

&lt;p&gt;You can also read the official guideline: &lt;a href="https://developers.google.com/search/docs/crawling-indexing/url-structure" rel="noopener noreferrer"&gt;URL structure best practices for Google&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By adhering to these practices, your blog post URLs will be well-optimized for search engines, contributing to a better user experience and potentially improving the visibility and ranking of your content in search results.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>beginners</category>
      <category>contentwriting</category>
      <category>writing</category>
    </item>
    <item>
      <title>How to Generate Income from Your Blog</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Mon, 01 May 2023 22:10:37 +0000</pubDate>
      <link>https://dev.to/canburaks/how-to-generate-income-from-your-blog-26cl</link>
      <guid>https://dev.to/canburaks/how-to-generate-income-from-your-blog-26cl</guid>
      <description>&lt;p&gt;In this article, I shared my findings and personal experiences about &lt;strong&gt;generating income with your blog&lt;/strong&gt; from a general perspective. I mentioned different monetization strategies and different useful tools that make your blogging journey easier.&lt;/p&gt;

&lt;p&gt;Suppose you have no idea how to generate revenue from your blog. In that case, this article gives you a general understanding of monetization methods which are also independent of the type of blog.&lt;/p&gt;

&lt;p&gt;If you have decided which platforms to use for your publishing, it is time to create remarkable content and generate revenue. &lt;/p&gt;

&lt;p&gt;If you didn't decide on the blogging platform, I suggest you check these options: &lt;a href="https://www.cbsofyalioglu.com/blogging/best-blogging-sites/" rel="noopener noreferrer"&gt;Best Blog Building Sites&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Quality Content Creation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8b98wvn7l716bl56w1yk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8b98wvn7l716bl56w1yk.jpg" alt="Quality content creation" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The value you realize from your published content depends on several variables, the most important of which is blog traffic. The more traffic your blog receives, the more value you realize. Consider it like having a billboard on a busy street. &lt;/p&gt;

&lt;p&gt;It can be said that it will be a billboard in the desert when you publish your first post. Therefore, it is vital to promote your content through Twitter, Facebook groups, Reddit, Medium etc.&lt;/p&gt;

&lt;p&gt;But… Even though promoting your content through social media is a necessary condition, it is not a sufficient one. &lt;/p&gt;

&lt;p&gt;The most critical factor that determines your income is providing good value to your audiences. In the year 2023, content is still king.&lt;/p&gt;

&lt;p&gt;In the long run, quality always beats quantity, and blogging is a long-run process.&lt;/p&gt;

&lt;p&gt;But…&lt;/p&gt;

&lt;h3&gt;
  
  
  What does quality content mean?
&lt;/h3&gt;

&lt;p&gt;Valuable, or quality content, is content that provides significant &lt;strong&gt;benefits to readers by addressing their needs, solving their problems, answering their questions, or entertaining them in a meaningful way&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Creating valuable content should be a priority for bloggers and content creators, as it helps build trust, credibility, and loyalty among readers, leading to increased engagement, social shares, and return visits.&lt;/p&gt;

&lt;p&gt;It is a fact that all of these returns will eventually comprise your income.&lt;/p&gt;

&lt;p&gt;To provide valuable content to your readers, consider the following tips:&lt;/p&gt;

&lt;h4&gt;
  
  
  Understand your audience
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Research and identify your target audience's needs, preferences, and pain points
&lt;/h5&gt;

&lt;p&gt;Create reader personas to help you better understand and address their needs through your content. &lt;/p&gt;

&lt;p&gt;Contrary to average practice, Prioritize creating high-quality, well-researched, and in-depth content rather than churning out a large volume of superficial articles.&lt;/p&gt;

&lt;p&gt;Although this strategy consumes more time, it will put you in front of thousands of bloggers in the long-run. This may grow the size of your loyal readers.&lt;/p&gt;

&lt;p&gt;One of the best ways to understand your audience is by creating user personas.&lt;/p&gt;

&lt;h6&gt;
  
  
  What is a user persona?
&lt;/h6&gt;

&lt;p&gt;A persona is a fictional representation of your ideal customers. They give a clue about how they look, what they need, and what they want. &lt;br&gt;
A user persona is a combination of all the characteristics your audiences would possess. &lt;/p&gt;

&lt;p&gt;For instance, you can clone this Notion template to see a very basic representation of &lt;a href="https://webmeister.notion.site/simple-persona-template-5616b54268934611ab30a9a09fa6732e" rel="noopener noreferrer"&gt;a simple user persona&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In different words, It helps you to create empathy for the real people and help you to put yourself in the shoes of your readers.&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://answerthepublic.com/" rel="noopener noreferrer"&gt;Answer The Public&lt;/a&gt; to know which questions your audience asks. &lt;/p&gt;

&lt;h5&gt;
  
  
  Be informative and educational and create easily consumable content
&lt;/h5&gt;

&lt;p&gt;Sharing your knowledge and expertise in your niche topic is not an easy task. It can be improved with lots of practice.&lt;/p&gt;

&lt;p&gt;Moreover, providing insights, tips, and actionable advice that helps your readers solve problems or improve their lives is the key point of a successful blog. &lt;/p&gt;

&lt;p&gt;Use short paragraphs and concise sentences to make your content more readable and scannable. Include visuals such as images, infographics, and videos to break up text and enhance your content's appeal. &lt;/p&gt;

&lt;p&gt;Offer step-by-step guides, tutorials, or case studies to illustrate your points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trends.google.com/trends/?geo=US" rel="noopener noreferrer"&gt;Google Trends&lt;/a&gt; and  &lt;a href="https://explodingtopics.com/" rel="noopener noreferrer"&gt;Exploding Topics&lt;/a&gt; are useful for trendy topics. Analyze the competition of your keywords and their monthly search volume.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.researchrabbitapp.com/" rel="noopener noreferrer"&gt;Research Rabbit&lt;/a&gt; is another useful tool for research papers if your niche is an academic topic. &lt;/p&gt;

&lt;p&gt;You may also find useful browser extensions to create step-by-step guides like &lt;a href="https://www.tango.us/" rel="noopener noreferrer"&gt;Tango&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Be original, authentic and create novel content
&lt;/h5&gt;

&lt;p&gt;Create unique content that showcases your voice, perspective, and experiences. Avoiding grammatical errors is also critical for your users. Avoid rehashing or duplicating content found elsewhere. &lt;/p&gt;

&lt;p&gt;Share personal stories and anecdotes to connect with your readers and make your content relatable. &lt;/p&gt;

&lt;p&gt;If you are not a native English writer, using tools like &lt;a href="https://languagetool.org/" rel="noopener noreferrer"&gt;LanguageTool&lt;/a&gt; could help a lot.&lt;/p&gt;

&lt;h5&gt;
  
  
  Promote your content through social media and optimize it for search engines
&lt;/h5&gt;

&lt;p&gt;Hyperlinks are great. It navigates your audiences to where you want. Share a tweet and navigate your users to your money page. &lt;/p&gt;

&lt;p&gt;Implementing search engine optimization best practices is crucial for successful bloggers. Organic search traffic is the most significant source of traffic for most blogs.&lt;/p&gt;

&lt;p&gt;It brings users without marketing such as keyword research, proper use of title tags and meta descriptions, and internal and external linking, to make your content more discoverable and accessible to potential readers. &lt;/p&gt;

&lt;p&gt;Google Ads has a very useful tool called &lt;a href="https://ads.google.com/" rel="noopener noreferrer"&gt;Keywords Planner&lt;/a&gt;. Extensively use it for your keyword research. &lt;br&gt;
&lt;a href="https://buffer.com/" rel="noopener noreferrer"&gt;Buffer&lt;/a&gt; like tools allow you to publish your work to multiple channels.&lt;/p&gt;

&lt;p&gt;If you are interested, you may check the &lt;a href="https://www.cbsofyalioglu.com/productivity/content-creation-tools/" rel="noopener noreferrer"&gt;list of content creation tools&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Generating Revenue
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuvn0iexcy9o1bz62jmv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuvn0iexcy9o1bz62jmv.jpg" alt="Generate income from your blog" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the ways of earning from your blog?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ads&lt;/li&gt;
&lt;li&gt;Affiliations&lt;/li&gt;
&lt;li&gt;Subscriptions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Income from Ads
&lt;/h3&gt;

&lt;p&gt;Ad revenue depends on site traffic, and site traffic depends on making the blog visible. Numerous platforms are eager to show ads on your blog site if your site has a considerable amount of traffic. In other words, at the very beginning of your blogging days, it is difficult to be accepted as a publisher on those ad platforms.&lt;/p&gt;

&lt;p&gt;Even though you get income for impressions, the real income comes with user interactions for ads you show. In other words, you mostly earn by the number of clicks your ads get.  &lt;/p&gt;

&lt;p&gt;The income by click depends on many factors such as purchasing power, a product that appears in ads etc… It is reasonable to get more when you show an ad to a U.S. citizen rather than a citizen of a country where its citizens have much lower income.&lt;/p&gt;

&lt;p&gt;Here, the most popular ad platforms you can apply with your blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://adsense.google.com/i" rel="noopener noreferrer"&gt;Google AdSense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mediavine.com/" rel="noopener noreferrer"&gt;Media Vine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.media.net/" rel="noopener noreferrer"&gt;Media.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.carbonads.net/" rel="noopener noreferrer"&gt;Carbon Ads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Affiliate Income
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What is affiliate marketing?
&lt;/h4&gt;

&lt;p&gt;One of the most used ways to get income from your content is affiliations. Basically, you review some products and link to those products.&lt;/p&gt;

&lt;p&gt;The links have special fragments which detect new coming users that are acquired from your platform. &lt;/p&gt;

&lt;p&gt;In this way, honest reviews will be rewarded as growing audiences. Growing audiences increase your visibility and so your income. &lt;/p&gt;

&lt;p&gt;YouTube video reviews and other product reviews are examples of affiliation type of income. Those video links generally include Amazon affiliate links.&lt;/p&gt;

&lt;p&gt;In this type of income, in other words, partnership, the affiliate (you) earns a commission for generating sales, leads, or other desired actions for the merchant through their unique referral link.&lt;/p&gt;

&lt;p&gt;Let me draw a sample process for an affiliate marketing process. &lt;/p&gt;

&lt;h4&gt;
  
  
  How does affiliate marketing work?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Affiliates sign up for an affiliate program&lt;/strong&gt;: Affiliates join an affiliate network or an individual company's affiliate program that offers products or services relevant to their niche.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Affiliates receive unique referral links&lt;/strong&gt;: Once they've joined the program, affiliates receive unique referral links, which they can use to promote the merchant's products or services on their websites, blogs, social media platforms, or email campaigns.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Affiliates promote the products or services&lt;/strong&gt;: Affiliates create content, such as blog posts, reviews, tutorials, or social media posts, to promote the merchant's products or services using their referral links.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Customers click on the referral links&lt;/strong&gt;: When potential customers click on an affiliate's referral link and make a purchase or complete another desired action (e.g., signing up for a newsletter), the transaction is tracked and attributed to the affiliate.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Affiliates earn a commission&lt;/strong&gt;: Based on the agreed-upon commission structure, affiliates earn a percentage of the sale or a fixed amount for each lead or action generated through their referral links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Affiliate marketing benefits both the merchant and the affiliate. Merchants gain access to a wider audience and only pay for results, while affiliates can generate passive income by promoting products or services they believe in.&lt;/p&gt;

&lt;p&gt;The most popular affiliate marketing program, affiliation platform, and curated lists are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://affiliate-program.amazon.com/" rel="noopener noreferrer"&gt;Amazon Associates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://partnernetwork.ebay.com/" rel="noopener noreferrer"&gt;eBay Partner Network&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://partnerstack.com" rel="noopener noreferrer"&gt;Partner Stack&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bestaffiliateprograms.io/" rel="noopener noreferrer"&gt;Best Affiliate Programs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Income from Subscriptions
&lt;/h3&gt;

&lt;p&gt;We are living in a micro-creators era. If you believe that you have novel things to share, then subscription-based income would be a suitable option. &lt;/p&gt;

&lt;p&gt;When you specialize in your niche, you'll have a laser-targeted audience. This not only allows you to earn by subscriptions, but also with targeted ads.&lt;/p&gt;

&lt;p&gt;Furthermore, if you are writing on a profitable niche, then it means you'll have predictable income streams which is a must for full-time blogging.&lt;/p&gt;

&lt;p&gt;Putting your content behind a paywall is getting more popular in these days. &lt;/p&gt;

&lt;p&gt;Moreover, there are platforms to provide you with all the things you need, and they just cut a small portion of your monthly subscription income.&lt;/p&gt;

&lt;p&gt;If you are planning to earn by this way, the content you create would generally be blog posts or email newsletters. &lt;/p&gt;

&lt;p&gt;The most popular platforms to earn income by paywall are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ghost.org/" rel="noopener noreferrer"&gt;Ghost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://substack.com/" rel="noopener noreferrer"&gt;Substack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://convertkit.com/" rel="noopener noreferrer"&gt;ConvertKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.patreon.com/" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you charge your audience with a relatively low price, it would be important to treat them well and provide them with unique and valuable content.&lt;/p&gt;

&lt;p&gt;As a bonus, here is another tool to add a membership feature to your blog.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.memberstack.com/" rel="noopener noreferrer"&gt;Memberstack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.memberspace.com/" rel="noopener noreferrer"&gt;Member Space&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I said before, generating revenue is a long-run process. It is better to improve it iteratively. &lt;/p&gt;

&lt;p&gt;Typically, it is unclear that which action causes what due to the nature of abundance of factors. Thus, the iterative process makes you aware of your decisions.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>tooling</category>
      <category>devjournal</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Exploring SolidJS - The Reactive Primitives (1)</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Wed, 06 Oct 2021 15:14:37 +0000</pubDate>
      <link>https://dev.to/canburaks/introduction-to-solidjs-and-reactive-primitives-1o6h</link>
      <guid>https://dev.to/canburaks/introduction-to-solidjs-and-reactive-primitives-1o6h</guid>
      <description>&lt;p&gt;SolidJS is a true reactive library that allows you to use JSX for your frontend projects. In this blog post, I'll share my first impressions on the &lt;em&gt;SolidJS UI library&lt;/em&gt; and its reactive primitives. The original article can be found here: &lt;a href="https://www.cbsofyalioglu.com/code/solidjs-and-reactive-primitives/" rel="noopener noreferrer"&gt;"Introduction to SolidJS"&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I like the concept of reactivity when building frontend projects. Despite its name, React is not a truly reactive library. I also like the Svelte because of its reactivity. I previously wrote a tutorial about &lt;a href="https://www.cbsofyalioglu.com/post/django-and-modern-js-libraries-svelte/" rel="noopener noreferrer"&gt;Django and Svelte&lt;/a&gt;. However, I realized that writing projects with Svelte are not so scalable like React projects because React and JSX provide great modularity.&lt;/p&gt;

&lt;p&gt;However, SolidJS offers the best of both worlds.&lt;/p&gt;

&lt;h4&gt;
  
  
  Shameless promotion
&lt;/h4&gt;

&lt;p&gt;I'm currently not planning to do a real project with SolidJS until I become fluent in it. Currently, I'm building an e-commerce store, &lt;a href="https://www.filizguvenlik.com.tr/" rel="noopener noreferrer"&gt;İzmir Güvenlik Kamerası&lt;/a&gt; (Security Camera Systems) and &lt;a href="https://www.opendigitalgallery.com" rel="noopener noreferrer"&gt;Fine Art Print Store&lt;/a&gt;, and I would work with SolidJS for small projects. You can also check &lt;a href="https://www.cbsofyalioglu.com/blogging/best-blogging-sites/" rel="noopener noreferrer"&gt;the list of blogging sites&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;OK, let's dive into the topic. Before reviewing SolidJS, it is better to get familiar with the concepts. I'll shortly talk about &lt;em&gt;What are reactive systems?&lt;/em&gt; and &lt;em&gt;what are those reactive primitives?&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are reactive systems?
&lt;/h3&gt;

&lt;p&gt;According to &lt;a href="https://www.reactivemanifesto.org/" rel="noopener noreferrer"&gt;The Reactive Manifesto&lt;/a&gt;,  reactive systems are responsive, resilient, elastic, and message-driven. We call these Reactive Systems.&lt;/p&gt;

&lt;p&gt;Systems built as Reactive Systems are more flexible, loosely coupled, and scalable. This makes them easier to develop and amenable to change.&lt;/p&gt;

&lt;p&gt;They are significantly more tolerant of failure, and when failure does occur they meet it with elegance rather than a disaster.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Reactive Systems do
&lt;/h3&gt;

&lt;p&gt;There are numerous reactive libraries in many programming languages like SolidJS in JS.&lt;/p&gt;

&lt;p&gt;Reactive systems must react to data changes. Generally, these changes occur when new data is received or the old one is updated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Characteristics of Reactive Programming
&lt;/h3&gt;

&lt;p&gt;The reactive manifesto defines the key characteristics of it, like that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responsive: Those systems respond on time. Here, of course, timely will differ depending upon the application and domain.&lt;/li&gt;
&lt;li&gt;Resilient. Reactive systems stay responsive in the face of failure.&lt;/li&gt;
&lt;li&gt;Elastic. As the workload grows, the system should continue to be responsive.&lt;/li&gt;
&lt;li&gt;Message Driven. Information is exchanged between elements of a reactive system using messages. This ensures loose coupling, isolation, and location transparency between these components.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What are the reactive primitives of SolidJS?
&lt;/h3&gt;

&lt;p&gt;In  SolidJS, the author of the library &lt;a href="https://dev.to/ryansolid/a-hands-on-introduction-to-fine-grained-reactivity-3ndf"&gt;Ryan Carniato&lt;/a&gt; defines them as much like network primitives rather than JavaScript's primitives.  As you will see later, Signals are basically observables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation of SolidJS Template
&lt;/h2&gt;

&lt;p&gt;You can easily install a starter &lt;em&gt;SolidJS&lt;/em&gt; template with degit. You can also check other official templates from here: &lt;a href="https://github.com/solidjs/templates" rel="noopener noreferrer"&gt;SolidJS Official Templates&lt;/a&gt;. I prefer a JS template rather than a TypeScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Javascript template&lt;/span&gt;
npx degit solidjs/templates/js solid
&lt;span class="nb"&gt;cd &lt;/span&gt;solid

&lt;span class="c"&gt;# install the dependencies&lt;/span&gt;
yarn &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The template uses Vite as a development tool. Also, this is the first time I have used Vite. Vite is so super fast that I had to check twice that if it reloaded the rendered page. When the installation is done, the project directory looks like that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-starter-template-direcotry.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-starter-template-direcotry.webp" alt="SolidJS directory" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is very similar to React in many cases. I will check some component rendering processes'.&lt;/p&gt;

&lt;p&gt;In this post, I am going to explore SolidJS in an introductory manner. I'll also create a Counter component first and check its re-render process.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Reactive JavaScript Library: SolidJS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A) Reactive primitives: createSignal
&lt;/h3&gt;

&lt;p&gt;SolidJS has some basic reactive primitives, and Signals are one of them. It looks like it is a "useState" alternative of React Hooks. One difference to the "useState" hook is that a Signal returns two functions: a getter and a setter. Here is the official example of creating a signal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;createSignal function takes an initial value and returns an array with an access and update function.&lt;/li&gt;
&lt;li&gt;You should execute the getter function (access) in order to get the value.&lt;/li&gt;
&lt;li&gt;You can pass function to update function (set function). In this function, you can access the previous state also.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// read value&lt;/span&gt;
&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// set value&lt;/span&gt;
&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// set value with a function setter&lt;/span&gt;
&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-Create-Signal-Component-2-1270x762.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-Create-Signal-Component-2-1270x762.webp" alt="Solid JS createSignal" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSignal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solid-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Notice the usage of count! It is a function*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1) Component State Access and Update
&lt;/h4&gt;

&lt;p&gt;SolidJS call the state elements as signals. However, I prefer to use state rather than signal.  Let's make a Counter component within the App component. Fill the &lt;code&gt;App.jsx&lt;/code&gt; file as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-Component-State-Change-1-1270x681.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-Component-State-Change-1-1270x681.webp" alt="SolidJS change state" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;logo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./logo.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSignal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solid-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * CHECKPOINT
     * if the App component renders
     * it will print to console
     */&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App component rendered.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Edit&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jsx&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/code&amp;gt; and save to reload&lt;/span&gt;&lt;span class="err"&gt;.
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
                    &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/solidjs/solid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noopener noreferrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;Solid&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * CHECKPOINT
     * if the Counter component renders. it will print to console.
     * Also, I put another print statement for the count function.
     */&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Counter component rendered.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Counter component count value: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Notice the usage of count! It is a function*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Decrease&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's check the browser and the first render of SolidJS. As you see, there is no extra component render. If it were React, we should have seen many times "Counter component rendered" text on the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-reactivity.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-reactivity.gif" alt="SolidJS's Reactivity" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2) Parent Component State Access and Update
&lt;/h4&gt;

&lt;p&gt;Let's make it further and pass the signal setter to the child component and use it from there. Change both App and Counter components like that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-Changing-State-of-the-Parent-Component-1-1270x681.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-Changing-State-of-the-Parent-Component-1-1270x681.webp" alt="SolidJS change parent state" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * CHECKPOINT
     * if the App component renders
     * it will print to console
     */&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAppCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App: count: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App component rendered.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Edit&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jsx&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/code&amp;gt; and save to reload&lt;/span&gt;&lt;span class="err"&gt;.
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
                    &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/solidjs/solid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noopener noreferrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;Solid&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* NEW */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;
                    &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
                    &lt;span class="nx"&gt;setAppCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setAppCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// NEW&lt;/span&gt;
                &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAppCount&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * CHECKPOINT
     * if the Counter component renders. it will print to console.
     * Also, I put another print statement for the count function.
     */&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Counter component rendered.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Counter component count value: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Notice the usage of count! It is a function*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Decrease&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;hr&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Buttons changes the signal value of its parent component */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setAppCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nx"&gt;AppCount&lt;/span&gt; &lt;span class="nx"&gt;Increase&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setAppCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nx"&gt;AppCount&lt;/span&gt; &lt;span class="nx"&gt;Decrease&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there is not any component re-rendering. It's awesome.🥳&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-change-state-of-parent-component.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-change-state-of-parent-component.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  B) Reactive primitives: createEffect
&lt;/h3&gt;

&lt;p&gt;As you might expect, &lt;code&gt;createEffect&lt;/code&gt; is the equivalent of the &lt;code&gt;useEffect&lt;/code&gt; hook in React. The official explanation and example are as follows:&lt;/p&gt;

&lt;p&gt;Creates a new computation that automatically tracks dependencies and runs after each render where a dependency has changed. Ideal for using&amp;nbsp;&lt;code&gt;ref&lt;/code&gt;s and managing other side effects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [a, setA] = createSignal(initialValue);

// effect that depends on signal `a`
createEffect(() =&amp;gt; doSideEffect(a()));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's time to play with this function. The official example returns a function (doSideEffect) that takes state value as its argument. Even if the returning function doesn't take the state value as its argument but as an inner value, the &lt;code&gt;createEffect&lt;/code&gt; function successfully makes a side-effect.&lt;/p&gt;

&lt;p&gt;Let's add those to the &lt;code&gt;App&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// The function creates side-effect&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changeTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`#App: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// effect that depends on signal `a`&lt;/span&gt;
    &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;changeTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We created a function (changeTitle) responsible for the side-effect. It takes a value and changes the document title according to that. It also takes the state value of the App component which is appCount. Your app component should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAppCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App: count: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App component rendered.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// The function creates side-effect&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changeTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`#App: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// effect that depends on signal `a`&lt;/span&gt;
    &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;changeTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Edit&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jsx&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/code&amp;gt; and save to reload&lt;/span&gt;&lt;span class="err"&gt;.
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
                    &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/solidjs/solid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noopener noreferrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;Solid&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* NEW */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;
                    &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
                    &lt;span class="nx"&gt;setAppCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setAppCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// NEW&lt;/span&gt;
                &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll easily differentiate that when the app renders the first time, the document title was &lt;code&gt;App: 0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After, when I clicked and increased the appCount value, the document title also changed to the corresponding value. You'll also notice that there will be no component re-render.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-create-effect.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2Fsolidjs-create-effect.gif" alt="SolidJS createEffect" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  C) Reactive primitives: createMemo
&lt;/h3&gt;

&lt;p&gt;This reactive primitive returns a function that returns a read-only derived signal. Its value is recalculated whenever dependencies are updated. &lt;code&gt;createMemo&lt;/code&gt; primitive is the equivalent of &lt;code&gt;useMemo&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;Edt the App component according to those:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Add those to the App component&lt;/span&gt;
    &lt;span class="c1"&gt;// It recalculate the value whenever the dependencies are updates.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeDouble&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubleCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;makeDouble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;appCount&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;doubleCount &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;doubleCount&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, update the content of the App component. By doing this, we can see the &lt;code&gt;doubleCount&lt;/code&gt; signal in work. You can also check the code location from the image below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Double&lt;/span&gt; &lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;doubleCount&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-createMemo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F09%2FSolidJS-createMemo.gif" alt="SolidJS createMemo function" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  D) Reactive primitives: createResource
&lt;/h3&gt;

&lt;p&gt;This function creates a signal that is responsible for async requests. The official explanation and example are here:&lt;/p&gt;

&lt;p&gt;Creates a signal that can manage async requests. The&amp;nbsp;&lt;code&gt;fetcher&lt;/code&gt;&amp;nbsp;is an async function that accepts the return value of the&amp;nbsp;source&amp;nbsp;if provided, and returns a Promise whose resolved value is set in the resource. The fetcher is not reactive, so use the optional first argument if you want it to run more than once. If the source resolves to false, null, or undefined will not fetch. Also, &lt;code&gt;loading&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;error&lt;/code&gt;&amp;nbsp;are reactive getters and can be tracked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refetch&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// read value&lt;/span&gt;
&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// check if loading&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// check if errored&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// directly set value without creating promise&lt;/span&gt;
&lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;optimisticValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// refetch last request just because&lt;/span&gt;
&lt;span class="nf"&gt;refetch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My first impressions of SolidJS are amazing. Up to this point, there is no overhead that you always face with React. I will be watching the development of SolidJS with interest.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Awesome Content Creation Tools</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Sun, 19 Sep 2021 19:00:13 +0000</pubDate>
      <link>https://dev.to/canburaks/awesome-content-creation-tools-2705</link>
      <guid>https://dev.to/canburaks/awesome-content-creation-tools-2705</guid>
      <description>&lt;p&gt;(Note: This post was updated on 15 December 2021)&lt;/p&gt;

&lt;p&gt;Creating quality content is a demanding and complex process. It is better to have a wide range of applications in your toolbox. Even though there is no one solution to fix it all, one can increase your productivity and save you time. Considering this, I will share my favorite content creation tools. These are both written content and visual content.&lt;/p&gt;

&lt;p&gt;You can also check the original post for updated resources: &lt;a href="https://www.cbsofyalioglu.com/productivity/content-creation-tools/" rel="noopener noreferrer"&gt;Content creation tools&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Great Content Creation Tools
&lt;/h2&gt;

&lt;p&gt;Using the appropriate tools can make &lt;strong&gt;content creation&lt;/strong&gt; so much easier and more successful. After the introduction, it is time to share the &lt;strong&gt;useful content marketers tools&lt;/strong&gt;. I hope those tools will make you more productive during your content creation process. Here are the super-useful &lt;strong&gt;content development tools&lt;/strong&gt;. You may also want to check &lt;a href="https://www.cbsofyalioglu.com/blogging/best-blogging-sites/" rel="noopener noreferrer"&gt;the ultimate list of blogging sites which includes more than 50 publishing sites&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content Research Tools
&lt;/h3&gt;

&lt;p&gt;Research plays a huge role in what your readers think of your business, products, services, and website. Content creation can be as easy as digging up information or digging around on the internet.&lt;/p&gt;

&lt;p&gt;In this section, I’ll take you through some of the most useful tools out there so that you can get started on creating great content for your blog or website.&lt;/p&gt;

&lt;p&gt;Content research tools are essential when creating content because the internet is vast, and there’s hardly any limit to what you can find out about a subject matter.&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://search.carrot2.org/"&gt;Carrot&lt;/a&gt;: The short demo you watched above is from Carrot. It organizes your search results into topics. It clusters, categorizes and show them in different formats.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.occamm.com/"&gt;Occamm&lt;/a&gt;: Occam is another SERP organizer. It refines your search result and allows you to select based on the tags.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://entityexplorer.com/"&gt;Entity Explorer&lt;/a&gt;: Entity explorer finds related entities in a graph map. It makes easier to see connections between entities.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.researchrabbitapp.com/"&gt;Research Rabbit&lt;/a&gt;: This is one of my favorite research tools. A research and relationship visualization tool.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.semanticscholar.org/"&gt;Semantic Scholar&lt;/a&gt;: A free, AI-powered research tool for scientific literature.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://paperpanda.app/"&gt;Paper Panda&lt;/a&gt; and &lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://unpaywall.org/"&gt;Unpaywall&lt;/a&gt;: They both allow you to access millions of academic papers and researches for free.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://trends.google.com/trends/?geo=US"&gt;Google Trends&lt;/a&gt;: You probably know this tool. Google Trends shows the popularity of a term among Google Searchers.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://answerthepublic.com/"&gt;Answer The Public&lt;/a&gt;: Another useful tool to research people’s questions.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://miro.com/"&gt;Miro&lt;/a&gt;: Miro is actually a whiteboard app. It allows collaboratively working on your content ideas. There are plenty of project management frameworks that make your ideation process easier.&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Fcontent-saving-tools.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Fcontent-saving-tools.webp" alt="Content saving tools" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Content Management Tools
&lt;/h3&gt;

&lt;p&gt;You need comprehensive document and knowledge management tools to get the most out of your content research. You can clip, capture, and annotate the content with these creation tools. There are a bunch of apps that you can use for this purpose. Most of those tools have browser extensions.&lt;/p&gt;

&lt;p&gt;Annotating is an excellent way to get your creative juices flowing. It allows you to take notes on what you’re reading or thinking, making it easy to revise later.&lt;/p&gt;

&lt;p&gt;I love using various notes apps or knowledge-saving tools and would recommend them to anyone looking to improve their writing skills.&lt;/p&gt;

&lt;p&gt;These content creation tools allow anyone to collect ideas, quotes, share knowledge and other content in an easy and intuitive way. These content saving/management tools save you time looking for relevant information while creating your blog posts and videos. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://bloggingplatforms.app/blog/best-free-platforms-for-blogging" rel="noopener noreferrer"&gt;Free Blogging Platforms&lt;/a&gt;: An article that mentions the best free blogging platforms.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://getpolarized.io/"&gt;Polar&lt;/a&gt;: You can manage and save your content from PDFs, EPUBs, and web pages in one place. It allows tagging, shows reading progress, and shows detailed document information.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.weavatools.com/"&gt;Weava&lt;/a&gt;: You can highlight, annotate, and organize the content in one place.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://getmemex.com/"&gt;Memex&lt;/a&gt;: It is a bookmark manager. It is an open-source tool that allows you to annotate, organize and share.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://justclip.co/"&gt;JustClip&lt;/a&gt;: A tool for collecting content that is suitable for individuals and teams. You can capture information and annotate content. You can easily build your knowledge connections and stay organized. &lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://wakelet.com/"&gt;Wakelet&lt;/a&gt;: Wakelet is a tool for collecting and curating content. It is particularly used by the education industry.It is one of my favorite tools. You can create a  &lt;a rel="nofollow noopener noreferrer" href="https://wakelet.com/wake/pdGmNjZditc00ivmmZscZ"&gt;Wakelet profile and a collection&lt;/a&gt; and publish your curated lists in various formats.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://getliner.com/en"&gt;Liner&lt;/a&gt;: Liner is another productivity tool that helps you find and learn reliable information faster. You can highlight web pages and PDF files. It suggests trusted content from other Liner users. &lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://obsidian.md/"&gt;Obsidian MD&lt;/a&gt;: It is also my favorite tool that I dumped every piece of note into it. It is offline-first meaning that your notes stay on your PC. It is a markdown editor and has a wiki-style backlink feature with built-in graph view options. There are other popular options for an alternative to Obsidian are &lt;a rel="nofollow noopener noreferrer" href="https://www.notion.so/"&gt;Notion&lt;/a&gt;, &lt;a rel="nofollow noopener noreferrer" href="https://nimbusweb.me/"&gt;Nimbus Note&lt;/a&gt;, and &lt;a rel="nofollow noopener noreferrer" href="https://roamresearch.com/"&gt;Roam Research&lt;/a&gt; and &lt;a href="https://monograph.notesnook.com/0eb6c655076e1a720f2a9a43" rel="noopener noreferrer"&gt;Notesnook&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://raindrop.io/"&gt;Raindrop&lt;/a&gt;: Raindrop is one of the best bookmark manager in the market. It has cross-platform apps/extensions, intuitive user-interface and a generous plan.&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Freadability-checker-tools.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Freadability-checker-tools.webp" alt="Readability checker tools" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Readability Score Tools
&lt;/h3&gt;

&lt;p&gt;Readability is the ease with which a reader can understand a written text.&lt;/p&gt;

&lt;p&gt;It is an essential parameter for the user as well as for SEO.&lt;/p&gt;

&lt;p&gt;It is also known that artificial intelligence, and thus the Google crawler, is better at distinguishing short sentences than long ones.&lt;/p&gt;

&lt;p&gt;As a result, short sentences are easier to understand for both the reader and the Googlebot. Of course, you have to consider your readers.&lt;/p&gt;

&lt;p&gt;There will be no problem for them in writing complex articles on relatively tricky subjects if your readers are experts on your case.&lt;/p&gt;

&lt;p&gt;The content creation software in this section are applications that measure at least which age group can understand your articles. It is called &lt;em&gt;the readability score&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are some popular formulas and metrics calculating the readability score of your text.&lt;/p&gt;

&lt;p&gt;However, creating short and concise content can be hard to create. With the tools below, you can make your copy more readable and quickly shorten sentences. Run your written copy through the web app and you’ll see the opportunities to make it better for your readers in seconds.&lt;/p&gt;

&lt;p&gt;It should also be noted that most of them are either free or freemium with a generous plan.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://hemingwayapp.com/"&gt;Hemingway Editor&lt;/a&gt;: It is one of the most well-known content readability improvers. This popular readability tool judges the “grade level” of your text using the &lt;a rel="nofollow noopener noreferrer" href="https://en.wikipedia.org/wiki/Automated_readability_index"&gt;Automated Readability Index&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://typewipe.com/app"&gt;Typewipe&lt;/a&gt;: This helpful content creation program offers both readability analysis and helps you improve your content according to your keyword.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.twinword.com/writer/"&gt;Twinword Writer&lt;/a&gt;: Twinword Writer is a tool that analyzes the tone of your content. It highlights the words that have negative and positive impacts on the tone of your text.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Grammar and Punctuation Checker Tools
&lt;/h3&gt;

&lt;p&gt;The content creation tools in this section are handy for creating content in English. Those can be classified as &lt;strong&gt;grammar correction and punctuation checker tools&lt;/strong&gt;. Using these tools will help you write better content about topics that matter to you.&lt;br&gt; The tools in this section are awesome &lt;em&gt;grammar and punctuation checker&lt;/em&gt; tools. Those will help you finish your sentences, spot typos, and get the words right no matter how much time you have.&lt;br&gt; The most popular grammar tool on this list is Grammarly. It offers a good user experience along with rich suggestions.&lt;/p&gt;

&lt;p&gt;However, it should also be noted that Grammarly doesn’t improve its tool and features. There are various alternatives to that provide different writing features that Grammarly doesn’t provide.&lt;/p&gt;

&lt;p&gt;You can also read The &lt;a href="https://bloggingplatforms.app/blog/best-grammar-tools" rel="noopener noreferrer"&gt;Best Grammar Tools&lt;/a&gt; article, which reviews different tools for this purpose.&lt;/p&gt;

&lt;p&gt;Here are the best grammar and punctuation checker tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://app.grammarly.com/"&gt;Grammarly&lt;/a&gt;: It  is one of the most well-known grammar tools. Grammarly is the best tool for this task. It has a really intuitive interface and a lot of fun features. It has a desktop and mobile application. Those apps exist both for macOS and Windows.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://linguix.com/"&gt;Linguix&lt;/a&gt;: Another Grammarly alternative, this English content creation assistant also stands out with its paraphrase feature.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://prowritingaid.com/"&gt;ProWritingAid&lt;/a&gt;: Although this content creation software does not offer as good a user experience as Grammarly and Linguix, it has much more advanced features.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.atomicreach.com/atomic-ai-editor"&gt;Atomic Editor&lt;/a&gt;: It is an AI-assisted editor that boosts your writing productivity.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.slickwrite.com/"&gt;SlickWrite&lt;/a&gt;: A tool that shows grammatical corrections and useful statistics.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://ludwig.guru/"&gt;Ludwig&lt;/a&gt;: A search engine for sentences. You can find your sentence in the best contexts, get definitions, synonyms, and examples. Also, you can paraphrase your sentence.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.gingersoftware.com/"&gt;Ginger&lt;/a&gt;: Another Grammarly alternative tool that helps you correct grammar and punctuation.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://writer.com/"&gt;Writer&lt;/a&gt;: I just discovered the app. First, it has a great design. Moreover, Writer provides many useful features comparing its competitors like a more customizable style guide and a bunch of many other things. It also has a free plan. You can use its web app, browser extension, or outlook app.&lt;/li&gt;
&lt;/ul&gt;





&lt;h3&gt;
  
  
  Search Engine Optimized Content Creation Tools
&lt;/h3&gt;

&lt;p&gt;It is not easy to find both budget-friendly and skilled tools. Of course, I’m speaking particularly about marketing tools. Anyway, I’ll share my relatively budget-friendly and search-engine-optimized content creation tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://copywritely.com/"&gt;SEO Content Analyzer&lt;/a&gt;: It has a bunch of tools for copywriting.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.frase.io/"&gt;Frase&lt;/a&gt;: This is one of my favorite tools. An AI-based content creation tool. Moreover, advanced paraphrasing and question-based features.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.canirank.com/"&gt;CanIRank&lt;/a&gt;: My other favorite SEO content tool that optimizes your content for search engines. When the first analysis is complete, it shows pretty useful keyword opportunities. &lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://inkforall.com/"&gt;Ink&lt;/a&gt;: Another SEO web content writing editing tool that you can download.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Fvisual-content-creation-tools.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Fvisual-content-creation-tools.webp" alt="Visual content creation tools" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Content Creation Tools
&lt;/h3&gt;

&lt;p&gt;I don’t remember who said it but it is true: “If content is king, then design is queen”. Whether you are creating visual content or written content, visually appealing content is preferable to the other. You can easily find the visual content creation tools you need such as:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;
        Image Creation Tools/ Social Media Tools
    &lt;/li&gt;
    &lt;li&gt;Video Creation Tools&lt;/li&gt;
    &lt;li&gt;
        Infographic Creation Tools
    &lt;/li&gt;
    &lt;li&gt;
        Presentation Creation Tools
    &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are more interested in visual design resources, you can check my other curated list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.cbsofyalioglu.com/design/free-design-resources/" rel="noopener noreferrer"&gt;Free design resources&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s start our list of digital content creation with some tools focused on creating and editing visual content elements.&lt;/p&gt;

&lt;h4&gt;
  
  
  Image creation/editing tools
&lt;/h4&gt;

&lt;p&gt;There are a lot of free image editing tools out there. Some offer advanced editing features and others are more casual apps. But if you’re looking for a basic set of image editing tools that can help you get your job done, then here are some of our favorites.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://figma.com/"&gt;Figma&lt;/a&gt;: Oh great Figma. It is one of the greatest apps of the decade.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.canva.com/"&gt;Canva&lt;/a&gt;: Canva is the most popular and the most used image creation tool. It has both free and premium plans. If you need quick visual content for your social media marketing operations, Canva is one of the best design tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also many image tools similar to Canva. Those are- &lt;a rel="nofollow noopener noreferrer" href="https://crello.com/"&gt;Crello&lt;/a&gt;,- &lt;a rel="nofollow noopener noreferrer" href="https://www.artify.co/"&gt;Artify&lt;/a&gt;,- &lt;a rel="nofollow noopener noreferrer" href="https://projector.com/"&gt;Projector&lt;/a&gt;,- &lt;a rel="nofollow noopener noreferrer" href="https://www.taler.app/"&gt;Taler&lt;/a&gt;,- &lt;a rel="nofollow noopener noreferrer" href="https://designs.ai/en"&gt;Design AI&lt;/a&gt;, etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.photopea.com/"&gt;Photopea&lt;/a&gt; is one of my favorite tools. It is a minified version of photoshop and it is working on a browser.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.remove.bg/"&gt;Remove.bg&lt;/a&gt; and- &lt;a rel="nofollow noopener noreferrer" href="https://www.erase.bg/en/"&gt;Erase.bg&lt;/a&gt;: A well-known background remover. You can extract people from an image.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Presentation tools
&lt;/h4&gt;

&lt;p&gt;Presentations are the core engine of any persuasive speaker. They establish credibility, inspire others, and move audiences emotionally. That’s why the first step in any persuasive presentation is to select the right tools.&lt;/p&gt;

&lt;p&gt;Presentations are a fundamental tool for any professional, whether they want to build a reputation or just sell products.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://pitch.com/"&gt;Pitch&lt;/a&gt;: This presentation creation tool allows you to collaboratively create your design asset.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://ludus.one/"&gt;Ludus&lt;/a&gt;: It is a collaborative presentation tool for creative teams&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://ludus.one/"&gt;Premast Plus&lt;/a&gt;: You can use its professional templates to design better presentations and with a faster way. Even if you don’t have any design experience. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Finfographic-tools.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Finfographic-tools.webp" alt="Infographic tools" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Infographic tools
&lt;/h4&gt;

&lt;p&gt;A well-designed infographic can go a long way towards convincing people to click through from a website or social media channel. Infographics are powerful, flexible, and can be used to achieve a wide range of results.&lt;/p&gt;

&lt;p&gt;They’re an effective tool for getting immediate attention – without creating an overwhelming feeling. If it is done correctly, infographics can be a backlink magnet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.visme.co/"&gt;Visme&lt;/a&gt;: Visme is an online tool that allows you to easily create infographics. Those are very useful for visual explanations and building backlinks.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://infogram.com/"&gt;Infogram&lt;/a&gt;: Infogram is a visual creation tool that allows you to create infographics and visual stories with data.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://piktochart.com/"&gt;Piktochart&lt;/a&gt;: Piktochart is another super functional tool for the visual content creation process. It helps you to make gorgeous infographics, presentations, and reports.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://venngage.com/"&gt;Venngage&lt;/a&gt;: An infographic design solution.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://graficto.com/"&gt;Graficto&lt;/a&gt;: Graficto is an infographic maker tool that is recently launched&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Fvideo-creation-tools.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fposts%2Fvideo-creation-tools.webp" alt="Video content creation tools" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Video creation tools
&lt;/h4&gt;

&lt;p&gt;Video content is consumed super-fast compared to written one. Therefore, it is widely popular among the mass. Having a useful instrument will definitely make your life easier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel="nofollow noopener noreferrer" href="https://animoto.com/"&gt;Animoto&lt;/a&gt;: Animoto is a video creation tool with a drag-and-drop interface. It has templates that allows you start with pre-made graphics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel="nofollow noopener noreferrer" href="https://biteable.com/"&gt;Biteable&lt;/a&gt;: One of the favorite video creation tools of content marketers. Express any concept. Personalize colors to match your brand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel="nofollow noopener noreferrer" href="https://www.renderforest.com/"&gt;RenderForest&lt;/a&gt;: Another tools for creating video content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel="nofollow noopener noreferrer" href="https://runwayml.com/sequel/"&gt;Runway ML&lt;/a&gt;: This tool is literally amazing. However, it has a steep learning curve because Runway has many features that use machine learning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel="nofollow noopener noreferrer" href="https://www.hitpaw.com/"&gt;Powtoon&lt;/a&gt;: A suit of video creation tools. You can crop, rotate your videos. Powtoon also has a unique feature that &lt;strong&gt;removes watermarks from videos&lt;/strong&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;





&lt;h3&gt;
  
  
  Miscellaneous Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://www.hubspot.com/make-my-persona"&gt;Buyer Persona&lt;/a&gt;: You should know who you are speaking if you have an intention to make your reader comfortable. This tool allows you to create a buyer persona. &lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://otter.ai/"&gt;Otter&lt;/a&gt;: A tool for generating notes from audio records.&lt;/li&gt;
&lt;li&gt;
&lt;a rel="nofollow noopener noreferrer" href="https://giphy.com/"&gt;Giphy&lt;/a&gt;: Who doesn’t love GIFs. You can search and use millions of GIFs.&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;As I said before, this post is a growing list of content creation tools. I’m trying to add great content development and content creation tools to here. Therefore, it is better to bookmark and come back later. &lt;/p&gt;

</description>
      <category>tooling</category>
      <category>design</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Exploring the Nx Framework: Next JS Development</title>
      <dc:creator>Can Burak Sofyalioglu</dc:creator>
      <pubDate>Mon, 30 Aug 2021 05:22:11 +0000</pubDate>
      <link>https://dev.to/canburaks/exploring-the-nx-framework-next-js-development-c5l</link>
      <guid>https://dev.to/canburaks/exploring-the-nx-framework-next-js-development-c5l</guid>
      <description>&lt;h2&gt;
  
  
  NX Workspace Introduction
&lt;/h2&gt;

&lt;p&gt;In this blog post series, I am going to explore the features that NX workspace that provides. The original post can be found on  &lt;a href="https://www.cbsofyalioglu.com/code/next-js-development-within-nx-workspace/" rel="noopener noreferrer"&gt;NextJS Tutorial with Nx Framework&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;In this blog post series, I am going to explore the features that NX workspace provides. I'm going to build a simple &lt;strong&gt;Next JS&lt;/strong&gt; web app with &lt;strong&gt;Tailwind CSS&lt;/strong&gt; styling within the &lt;strong&gt;Nx workspace&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Shameless promototion
&lt;/h4&gt;

&lt;p&gt;This post was written during the research process of Alarm systems guide (&lt;a href="https://alarmsistemleri.org/" rel="noopener noreferrer"&gt;Alarm sistemleri&lt;/a&gt; in Turkish). You can also check &lt;a href="https://www.cbsofyalioglu.com/blogging/best-blogging-sites/" rel="noopener noreferrer"&gt;the list of blogging sites&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NX&lt;/strong&gt;&amp;nbsp;is an advanced set of extensible dev tools for mono repositories, with a strong emphasis on modern full-stack web technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Setup NextJS App on Nx Workspace
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; nx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install and create workspace&lt;/span&gt;
npx create-nx-workspace nx-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Choose project types&lt;/span&gt;
✔ Workspace name &lt;span class="o"&gt;(&lt;/span&gt;e.g., org name&lt;span class="o"&gt;)&lt;/span&gt;     · nx-tutorial
? What to create &lt;span class="k"&gt;in &lt;/span&gt;the new workspace … 
❯ empty             &lt;span class="o"&gt;[&lt;/span&gt;an empty workspace with a layout that works best &lt;span class="k"&gt;for &lt;/span&gt;building apps]
  react             &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a single React application]
  angular           &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a single Angular application]
  next.js           &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a single Next.js application]
  gatsby            &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a single Gatsby application]
  nest              &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a single Nest application]
  express           &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a single Express application]
  web components    &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a single app built using web components]
  react-express     &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a full stack application &lt;span class="o"&gt;(&lt;/span&gt;React + Express&lt;span class="o"&gt;)]&lt;/span&gt;
  angular-nest      &lt;span class="o"&gt;[&lt;/span&gt;a workspace with a full stack application &lt;span class="o"&gt;(&lt;/span&gt;Angular + Nest&lt;span class="o"&gt;)]&lt;/span&gt;
  oss               &lt;span class="o"&gt;[&lt;/span&gt;an empty workspace with a layout that works best &lt;span class="k"&gt;for &lt;/span&gt;open-source projects]

&lt;span class="c"&gt;# Choose whether you'll use Nx Cloud or not&lt;/span&gt;
✔ Use Nx Cloud? &lt;span class="o"&gt;(&lt;/span&gt;It&lt;span class="s1"&gt;'s free and doesn'&lt;/span&gt;t require registration.&lt;span class="o"&gt;)&lt;/span&gt; · Yes
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  NX  Nx is creating your workspace.

&lt;span class="c"&gt;# get into the workspace&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;nx-tutorial

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

&lt;/div&gt;



&lt;p&gt;Nx Workspace directory structure&lt;/p&gt;




&lt;h3&gt;
  
  
  1.1) See the available plugins
&lt;/h3&gt;

&lt;p&gt;You can see all of the available plugins with nx list  command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# See the available plugins&lt;/span&gt;
nx list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  NX  Installed plugins:

  @nrwl/jest &lt;span class="o"&gt;(&lt;/span&gt;builders,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/linter &lt;span class="o"&gt;(&lt;/span&gt;builders&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/workspace &lt;span class="o"&gt;(&lt;/span&gt;builders,generators&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  NX  Also available:

  @nrwl/angular &lt;span class="o"&gt;(&lt;/span&gt;generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/cypress &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/express &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/nest &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/next &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/node &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/nx-plugin &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/react &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/storybook &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;
  @nrwl/web &lt;span class="o"&gt;(&lt;/span&gt;executors,generators&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  NX  Community plugins:

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.2) Installation of the Next plugin
&lt;/h3&gt;

&lt;p&gt;Now, install the Next plugin and see the options of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the plugin&lt;/span&gt;
yarn add @nrwl/next 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.3) See the plugin options
&lt;/h3&gt;

&lt;p&gt;Let's see what we can do with the plugin. You'll see the available options for the plugin you choose. I am going to generate an application but first I need to see all options. We have options four options to generate and 3 to execute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# See the options for the plugin&lt;/span&gt;
&lt;span class="c"&gt;# nx list [plugin]&lt;/span&gt;
nx list @nrwl/next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  NX  Capabilities &lt;span class="k"&gt;in&lt;/span&gt; @nrwl/next:

  GENERATORS

  init : Initialize the @nrwl/next plugin
  application : Create a Next.js application
  page : Create a Next.js page component
  component : Create a React component

  EXECUTORS/BUILDERS

  build : Build a Next.js app
  server : Serve a Next.js app
  &lt;span class="nb"&gt;export&lt;/span&gt; : Export a Next.js app. The exported application is located at dist/&lt;span class="nv"&gt;$outputPath&lt;/span&gt;/exported.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.4) See the options for generating a Next application
&lt;/h3&gt;

&lt;p&gt;Before generating the Next application, It will be better to see initial configuration options for generating an app. To do this, I must append help flag to the end of the command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# See the options for generating a Next application&lt;/span&gt;
nx generate @nrwl/next:application &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx generate @nrwl/next:application &lt;span class="o"&gt;[&lt;/span&gt;name] &lt;span class="o"&gt;[&lt;/span&gt;options,...]

Options:
  &lt;span class="nt"&gt;--name&lt;/span&gt;                  The name of the application.
  &lt;span class="nt"&gt;--directory&lt;/span&gt;             The directory of the new application.
  &lt;span class="nt"&gt;--style&lt;/span&gt;                 The file extension to be used &lt;span class="k"&gt;for &lt;/span&gt;style files. &lt;span class="o"&gt;(&lt;/span&gt;default: css&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;--server&lt;/span&gt;                The server script path to be used with next.
  &lt;span class="nt"&gt;--linter&lt;/span&gt;                The tool to use &lt;span class="k"&gt;for &lt;/span&gt;running lint checks. &lt;span class="o"&gt;(&lt;/span&gt;default: eslint&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;--skipFormat&lt;/span&gt;            Skip formatting files
  &lt;span class="nt"&gt;--skipWorkspaceJson&lt;/span&gt;     Skip updating workspace.json with default options based on values provided to this app &lt;span class="o"&gt;(&lt;/span&gt;e.g. babel, style&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;--unitTestRunner&lt;/span&gt;        Test runner to use &lt;span class="k"&gt;for &lt;/span&gt;unit tests &lt;span class="o"&gt;(&lt;/span&gt;default: jest&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;--e2eTestRunner&lt;/span&gt;         Test runner to use &lt;span class="k"&gt;for &lt;/span&gt;end to end &lt;span class="o"&gt;(&lt;/span&gt;e2e&lt;span class="o"&gt;)&lt;/span&gt; tests &lt;span class="o"&gt;(&lt;/span&gt;default: cypress&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;--tags&lt;/span&gt;                  Add tags to the application &lt;span class="o"&gt;(&lt;/span&gt;used &lt;span class="k"&gt;for &lt;/span&gt;linting&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;--js&lt;/span&gt;                    Generate JavaScript files rather than TypeScript files.
  &lt;span class="nt"&gt;--setParserOptionsProjecWhether&lt;/span&gt; or not to configure the ESLint &lt;span class="s2"&gt;"parserOptions.project"&lt;/span&gt; option. We &lt;span class="k"&gt;do &lt;/span&gt;not &lt;span class="k"&gt;do &lt;/span&gt;this by default &lt;span class="k"&gt;for &lt;/span&gt;lint performance reasons.
  &lt;span class="nt"&gt;--standaloneConfig&lt;/span&gt;      Split the project configuration into &amp;lt;projectRoot&amp;gt;/project.json rather than including it inside workspace.json
  &lt;span class="nt"&gt;--dryRun&lt;/span&gt;                Runs through and reports activity without writing to disk.
  &lt;span class="nt"&gt;--skip-nx-cache&lt;/span&gt;         Skip the use of Nx cache.
  &lt;span class="nt"&gt;--help&lt;/span&gt;                  Show available options &lt;span class="k"&gt;for &lt;/span&gt;project target.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.5) Generating a Next JS application
&lt;/h3&gt;

&lt;p&gt;It is better to use —dryRun flag on generating an application. Also, I need to give a name to my app. When I execute the command, some configuration options will be available to me. I'll stick with CSS styling option&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# I'll also choose the name of the app as "store"&lt;/span&gt;
nx generate @nrwl/next:application store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;? Which stylesheet format would you like to use? … 
❯ CSS
  SASS&lt;span class="o"&gt;(&lt;/span&gt;.scss&lt;span class="o"&gt;)&lt;/span&gt;       &lt;span class="o"&gt;[&lt;/span&gt; http://sass-lang.com          &lt;span class="o"&gt;]&lt;/span&gt;
  Stylus&lt;span class="o"&gt;(&lt;/span&gt;.styl&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="o"&gt;[&lt;/span&gt; http://stylus-lang.com        &lt;span class="o"&gt;]&lt;/span&gt;
  LESS              &lt;span class="o"&gt;[&lt;/span&gt; http://lesscss.org            &lt;span class="o"&gt;]&lt;/span&gt;
  styled-components &lt;span class="o"&gt;[&lt;/span&gt; https://styled-components.com &lt;span class="o"&gt;]&lt;/span&gt;
  emotion           &lt;span class="o"&gt;[&lt;/span&gt; https://emotion.sh            &lt;span class="o"&gt;]&lt;/span&gt;
  styled-jsx        &lt;span class="o"&gt;[&lt;/span&gt; https://www.npmjs.com/package/styled-jsx &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.6) Start Next JS Application
&lt;/h3&gt;

&lt;p&gt;After setting up the Next application, let's open workspace.json file. In the file, you will see the target list under the store application. Those are the actions that I can do with the Next JS application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"version"&lt;/span&gt;: 2,
  &lt;span class="s2"&gt;"projects"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"store"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"root"&lt;/span&gt;: &lt;span class="s2"&gt;"apps/store"&lt;/span&gt;,
            &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt;
      &lt;span class="s2"&gt;"targets"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"build"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"serve"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"export"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"lint"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt; &lt;span class="nt"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I can start serving the app by the run command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Serving the app&lt;/span&gt;
&lt;span class="c"&gt;# nx run [project]:[target]&lt;/span&gt;
nx run store:serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, open your browser and navigate to &lt;a href="http://localhost:4200/" rel="noopener noreferrer"&gt;http://localhost:4200/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F08%2F00-nx-directory-squashed.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.cbsofyalioglu.com%2Fwp-content%2Fuploads%2F2021%2F08%2F00-nx-directory-squashed.jpg" alt="01-nx-next-serving.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Installing Dependencies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1) TailwindCSS Setup
&lt;/h3&gt;

&lt;p&gt;I am going to style the web app with Tailwind CSS. Let's add the dependencies of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Tailwind CSS dependencies&lt;/span&gt;
yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; tailwindcss@latest postcss@latest autoprefixer@latest

&lt;span class="c"&gt;# Other styling libs&lt;/span&gt;
yarn add @heroicons/react @headlessui/react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Put tailwind config file in the app dir&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;apps/store
npx tailwindcss init &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/store/postcss.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;tailwindcss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./apps/store/tailwind.config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;autoprefixer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://nx.dev/latest/react/guides/using-tailwind-css-in-react#introducing-nx-utility-for-better-tailwind-purging" rel="noopener noreferrer"&gt;According to the docs&lt;/a&gt;, Nx utility function should be used for purge property. This eliminates additional manual maintenance as your workspace progresses. Also, it should be noted that Nx only purges on production build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/site/tailwind.config.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// available since Nx v 12.5&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createGlobPatternsForDependencies&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nrwl/next/tailwind&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;purge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pages/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;createGlobPatternsForDependencies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;darkMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// or 'media' or 'class'&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.2) Import TailwindCSS Styles
&lt;/h3&gt;

&lt;p&gt;When I'm in the root folder, I'll create separate style file for tailwind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# create tailwind.css file on pages dir&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;apps/store/pages/tailwind.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* apps/store/pages/tailwind.css */&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* apps/store/pages/styles.css */&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"./tailwind.css"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* The rest of styles.css file */&lt;/span&gt;
&lt;span class="c"&gt;/* ----------------------------*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3) Create a  library
&lt;/h2&gt;

&lt;p&gt;Nx framework allows you to structure your project with apps and libs. In other words, we don't need to create app libraries specifically in the app directory. We can also create separate and publishable libraries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh6cfbq2pkwhvl56ordit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh6cfbq2pkwhvl56ordit.png" alt="CleanShot 2021-08-29 at 01.23.25.png" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are different types of libraries you can create:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/3d06489a603e4aa3be4e3de33dfa5e09" rel="noopener noreferrer"&gt;Nx Library types&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can easily move the libraries using the @nrwl/workspace:move generator command&lt;/p&gt;

&lt;p&gt;We have two options for building libraries either —buildable or —publishable. Those are valid for Angular, React, NestJS and Node. Therefore, I am going to use React libraries as a separate standalone publishable library.&lt;/p&gt;

&lt;p&gt;You will also find useful options flag that you can pass to the CLI command.  You can find &lt;a href="https://nx.dev/latest/react/react/library" rel="noopener noreferrer"&gt;the full list of the react:library options&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/88c3e7b9ba3e4bdbb1d676a73f586bfc" rel="noopener noreferrer"&gt;@nrwl/react:library flags&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a library wiht @nrwl/react package&lt;/span&gt;
&lt;span class="c"&gt;# See which files will be written to the disk &lt;/span&gt;
&lt;span class="c"&gt;# (output is not produced)&lt;/span&gt;
nx g @nrwl/react:lib tailwind-ui &lt;span class="nt"&gt;--dry-run&lt;/span&gt; 

&lt;span class="c"&gt;# Now create the library as publishable&lt;/span&gt;
&lt;span class="c"&gt;# publishable flag requires importPath=npmusername/libraryname &lt;/span&gt;
nx g @nrwl/react:lib tailwind-ui  &lt;span class="nt"&gt;--publishable&lt;/span&gt; &lt;span class="nt"&gt;--importPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@canburaks/tailwind-ui &lt;span class="nt"&gt;--globalCss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;--component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;

&lt;span class="c"&gt;# Also you can remove the library as like this&lt;/span&gt;
&lt;span class="c"&gt;# nx g remove tailwind-ui&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# You'll see the ouput like that&lt;/span&gt;
✔ Which stylesheet format would you like to use? · css
UPDATE workspace.json
UPDATE nx.json
CREATE libs/tailwind-ui/.eslintrc.json
CREATE libs/tailwind-ui/.babelrc
CREATE libs/tailwind-ui/README.md
CREATE libs/tailwind-ui/package.json
CREATE libs/tailwind-ui/src/index.ts
CREATE libs/tailwind-ui/tsconfig.json
CREATE libs/tailwind-ui/tsconfig.lib.json
UPDATE tsconfig.base.json
CREATE libs/tailwind-ui/jest.config.js
CREATE libs/tailwind-ui/tsconfig.spec.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4) Create a components
&lt;/h2&gt;

&lt;p&gt;Now, I generated a publishable user interface component library. I'm planning to populate this library with tailwind components.&lt;/p&gt;

&lt;p&gt;Additionally, style=none flag is added because components styling will be done by tailwind classes and there is no need to create extra style file. &lt;/p&gt;

&lt;p&gt;Also, the library will not include tailwindcss library, meaning that the library has a peer dependency of tailwindcss.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/cc6fbe1cb65e4da197a637aca804ed2e" rel="noopener noreferrer"&gt;@nrwl/react:components flags&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1) Generate components for the library
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Navbar component&lt;/span&gt;
nx g @nrwl/next:component Navbar &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tailwind-ui &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="nt"&gt;--export&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;  

&lt;span class="c"&gt;# Footer component&lt;/span&gt;
nx g @nrwl/next:component Footer &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tailwind-ui &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="nt"&gt;--export&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2) Generate components for the app
&lt;/h3&gt;

&lt;p&gt;I generated the required files for the library components. It is a good practice to create Layou component for the NextJS apps. Let's create it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx g @nrwl/next:component Layout &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;store &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, fill those files likes these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/store/components/layout/layout.tsx&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Navbar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./navbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./footer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navbar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// libs/tailwind-ui/src/lib/navbar/navbar.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Navbar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"w-full px-8 text-gray-700 bg-white "&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container flex flex-col flex-wrap items-center justify-between py-5 mx-auto md:flex-row max-w-7xl"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"relative flex flex-col md:flex-row"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
            &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center mb-5 font-medium text-gray-900 lg:w-auto lg:items-center lg:justify-center md:mb-0"&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mx-auto text-xl font-black leading-none text-gray-900 select-none"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              cbsofyalioglu&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-indigo-600"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-wrap items-center mb-5 text-base md:mb-0 md:pl-8 md:ml-8 md:border-l md:border-gray-200"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
              &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mr-5 font-medium leading-6 text-gray-600 hover:text-gray-900"&lt;/span&gt;
              &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/contact"&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              Contact
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"inline-flex items-center ml-5 space-x-6 lg:justify-end"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
            &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-teal-600 px-8 py-2 border-teal-600  font-medium leading-6 border-2 rounded-lg transition ease-out duration-300 hover:text-blueGray-100 hover:bg-teal-600"&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Login
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// libs/tailwind-ui/src/lib/footer/footer.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-700 bg-white body-font border-t-4 border-teal-800"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container flex flex-col items-center px-8 py-8 mx-auto max-w-7xl sm:flex-row"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
          &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://www.filizguvenlik.com.tr"&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-black leading-none text-gray-900 select-none logo"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          cbsofyalioglu&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-indigo-600"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-4 text-sm text-gray-500 sm:ml-4 sm:pl-4 sm:border-l sm:border-gray-200 sm:mt-0"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          © 2021 -&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://webmeister.org"&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xs"&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noreferrer"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Webmeister
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// libs/tailwind-ui/src/index.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./lib/navbar/navbar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lib/footer/footer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I must build the library. By doing this, I'll be able to import the components to the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# build library&lt;/span&gt;
nx run tailwind-ui:build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/store/pages/_app.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layout/layout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// // apps/store/pages/index.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"min-h-screen"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, restart the server.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) Generate pages
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generate a contact page&lt;/span&gt;
&lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="nx"&gt;Contact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/store/pages/contact.tsx&lt;/span&gt;
&lt;span class="cm"&gt;/* eslint-disable react/no-unescaped-entities */&lt;/span&gt;
&lt;span class="cm"&gt;/* eslint-disable @next/next/no-img-element */&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container mx-auto mt-8 md:mt-0 md:space-x-10 md:grid grid-cols-3 justify-center md:py-40"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"grid justify-center items-center order-1 col-span-1"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"lg:h-80 md:h-64 h-40 rounded-full"&lt;/span&gt;
          &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://cbsofyalioglu.fra1.cdn.digitaloceanspaces.com/cbs/cbsofyalioglu-black.png"&lt;/span&gt;
          &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-8 md:mt-0 lg:justify-end col-span-2"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-4xl text-gray-800 text-center md:text-left font-bold mb-6"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Hi, I am Can Burak Sofyalioglu.
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xl text-gray-800 text-center md:text-left"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          I'm an engineer.
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






</description>
      <category>nextjs</category>
      <category>node</category>
      <category>react</category>
    </item>
  </channel>
</rss>
