<?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: Mina Golzari Dalir</title>
    <description>The latest articles on DEV Community by Mina Golzari Dalir (@mina_golzari_dalir).</description>
    <link>https://dev.to/mina_golzari_dalir</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%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png</url>
      <title>DEV Community: Mina Golzari Dalir</title>
      <link>https://dev.to/mina_golzari_dalir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mina_golzari_dalir"/>
    <language>en</language>
    <item>
      <title>From State Machines to Configurable Workflows</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Fri, 09 Oct 2026 13:55:03 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/from-state-machines-to-configurable-workflows-34hj</link>
      <guid>https://dev.to/mina_golzari_dalir/from-state-machines-to-configurable-workflows-34hj</guid>
      <description>&lt;p&gt;There is a stage in software development where the hardest problem is no longer writing the code.&lt;/p&gt;

&lt;p&gt;It is deciding whether the architecture you chose six months ago is still the right architecture today.&lt;/p&gt;

&lt;p&gt;Recently, I found myself dealing with exactly this situation while designing a workflow-heavy .NET system.&lt;/p&gt;

&lt;p&gt;The initial problem looked like a perfect use case for a state machine.&lt;/p&gt;

&lt;p&gt;An entity had a lifecycle.&lt;/p&gt;

&lt;p&gt;It moved from one state to another.&lt;/p&gt;

&lt;p&gt;Some transitions were allowed, some were not.&lt;/p&gt;

&lt;p&gt;The rules could be expressed clearly in code.&lt;/p&gt;

&lt;p&gt;So we implemented a state-machine-oriented design.&lt;/p&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;And that is important.&lt;/p&gt;

&lt;p&gt;The state machine was not a bad decision.&lt;/p&gt;

&lt;p&gt;In fact, it was the right decision for the problem we had at that time.&lt;/p&gt;

&lt;p&gt;The problem appeared later, when the business scenarios started changing.&lt;/p&gt;

&lt;p&gt;New scenarios appeared.&lt;/p&gt;

&lt;p&gt;Different customers needed different processes.&lt;/p&gt;

&lt;p&gt;Some steps became optional.&lt;/p&gt;

&lt;p&gt;Some steps were conditional.&lt;/p&gt;

&lt;p&gt;Some processes needed additional approval.&lt;/p&gt;

&lt;p&gt;Existing running processes had to continue using their original rules.&lt;br&gt;
At that point, the question changed from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What state is this entity in?"&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"Which business process should this entity follow?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction completely changed my view of the architecture.&lt;/p&gt;

&lt;p&gt;This article explains that evolution.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;1. The Original Problem&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let's use a fictional example.&lt;/p&gt;

&lt;p&gt;Imagine we are building an Order Fulfillment Platform for an e-commerce company.&lt;/p&gt;

&lt;p&gt;An order goes through a process like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Created
   ↓
Payment Verified
   ↓
Inventory Reserved
   ↓
Packed
   ↓
Shipped
   ↓
Delivered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initially, this looks like a textbook state machine.&lt;/p&gt;

&lt;p&gt;We can define:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&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;PaymentVerified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InventoryReserved&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Packed&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;Delivered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Cancelled&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&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;VerifyPayment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReserveInventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Pack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Ship&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Deliver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Cancel&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then transitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Created
   ├── VerifyPayment → PaymentVerified
   └── Cancel → Cancelled

PaymentVerified
   ├── ReserveInventory → InventoryReserved
   └── Cancel → Cancelled

InventoryReserved
   └── Pack → Packed

Packed
   └── Ship → Shipped

Shipped
   └── Deliver → Delivered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is clean.&lt;/p&gt;

&lt;p&gt;It is easy to understand.&lt;/p&gt;

&lt;p&gt;It is easy to test.&lt;/p&gt;

&lt;p&gt;And most importantly, it protects the business rules.&lt;/p&gt;

&lt;p&gt;An order cannot simply jump from:&lt;/p&gt;

&lt;p&gt;Created → Delivered&lt;/p&gt;

&lt;p&gt;because that transition doesn't exist.&lt;/p&gt;

&lt;p&gt;For a stable process, this is exactly what we want.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Why We Initially Chose a State Machine&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A state machine gave us several useful properties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicit states&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The possible lifecycle states were clearly defined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicit transitions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We could see exactly which transitions were legal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Centralized rules&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of scattering conditions throughout controllers and services, transition rules were concentrated in one place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type safety&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The compiler knew about states and events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We could easily test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="nf"&gt;Given &lt;/span&gt;Created
&lt;span class="nf"&gt;When &lt;/span&gt;VerifyPayment
&lt;span class="nf"&gt;Then &lt;/span&gt;PaymentVerified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="nf"&gt;Given &lt;/span&gt;Created
&lt;span class="nf"&gt;When &lt;/span&gt;Deliver
&lt;span class="nf"&gt;Then &lt;/span&gt;Reject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is much safer than having arbitrary status updates throughout the application.&lt;/p&gt;

&lt;p&gt;At this point, choosing a state machine was a reasonable engineering decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Then the Business Changed&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The first new requirement was simple:&lt;/p&gt;

&lt;p&gt;Premium customers should have priority packing.&lt;/p&gt;

&lt;p&gt;We added a condition.&lt;/p&gt;

&lt;p&gt;Then another requirement appeared:&lt;/p&gt;

&lt;p&gt;Orders above $1,000 require manual fraud review.&lt;/p&gt;

&lt;p&gt;So the process became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Created
   ↓
Payment Verified
   ↓
Fraud Review
   ↓
Inventory Reserved
   ↓
Packed
   ↓
Shipped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But only for some orders.&lt;/p&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;p&gt;Digital products don't need shipping.&lt;/p&gt;

&lt;p&gt;Now we had:&lt;/p&gt;

&lt;p&gt;Physical Order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment
 ↓
Inventory
 ↓
Packing
 ↓
Shipping
 ↓
Delivery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while:&lt;/p&gt;

&lt;p&gt;Digital Order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment
 ↓
Fulfillment
 ↓
Completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then another customer introduced:&lt;/p&gt;

&lt;p&gt;Orders containing regulated products require compliance verification.&lt;/p&gt;

&lt;p&gt;And another:&lt;/p&gt;

&lt;p&gt;Enterprise customers require account-manager approval before fulfillment.&lt;/p&gt;

&lt;p&gt;The process was no longer one fixed sequence.&lt;/p&gt;

&lt;p&gt;It had become a collection of possible processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. The State Machine Started Growing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The state machine itself could still handle these requirements.&lt;/p&gt;

&lt;p&gt;That is important.&lt;/p&gt;

&lt;p&gt;A state machine is not incapable of handling conditional logic.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&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;IsDigital&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Skip physical fulfillment&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalAmount&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Require fraud review&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContainsRegulatedProducts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Require compliance&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CustomerType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enterprise&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Require account manager approval&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But something started bothering me.&lt;/p&gt;

&lt;p&gt;The state machine was increasingly responsible for understanding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customer type
product type
order value
risk level
geography
compliance requirements
approval policies
fulfillment strategy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The question was no longer simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What state is the order in?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The state machine was starting to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which business process should this order follow?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a different responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. The Real Problem: State vs Process&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This became the key architectural insight.&lt;/p&gt;

&lt;p&gt;A state describes the current condition of something.&lt;/p&gt;

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

&lt;p&gt;PaymentVerified&lt;/p&gt;

&lt;p&gt;A workflow describes how something should progress through a business process.&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 plaintext"&gt;&lt;code&gt;Payment
 → Fraud Review
 → Inventory
 → Packing
 → Shipping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are related, but they are not the same concept.&lt;/p&gt;

&lt;p&gt;A state machine is excellent at answering:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can this entity move from state A to state B?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A workflow engine needs to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which steps should this business process execute, in what order, under which conditions?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once we recognized this distinction, the architecture became much clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;6. What We Actually Needed&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We needed the process itself to become configurable.&lt;/p&gt;

&lt;p&gt;Instead of hard-coding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment
 → Fraud Review
 → Inventory
 → Packing
 → Shipping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we wanted to define:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Workflow
    ↓
Version
    ↓
Steps
    ↓
Conditions
    ↓
Handlers

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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderFulfillment
Version 1

1. VerifyPayment
2. ReserveInventory
3. Pack
4. Ship
5. Deliver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another version could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderFulfillment
Version 2

1. VerifyPayment
2. FraudReview
3. ReserveInventory
4. Pack
5. Ship
6. Deliver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a digital-product workflow could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DigitalOrderFulfillment
Version 1

1. VerifyPayment
2. PrepareDownload
3. CompleteOrder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow itself is now data.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;7. But We Didn't Want a "Everything Is JSON" System&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This was an important design constraint.&lt;/p&gt;

&lt;p&gt;A configurable workflow can easily become dangerous.&lt;/p&gt;

&lt;p&gt;It is tempting to put everything into JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"order.amount &amp;gt; 1000 &amp;amp;&amp;amp; customer.type == 'Enterprise'"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a generic interpreter.&lt;/p&gt;

&lt;p&gt;Eventually, you have effectively invented your own programming language.&lt;/p&gt;

&lt;p&gt;That creates a different class of problems:&lt;/p&gt;

&lt;p&gt;difficult debugging&lt;br&gt;
weak type safety&lt;br&gt;
difficult refactoring&lt;br&gt;
runtime failures&lt;br&gt;
complicated validation&lt;br&gt;
security concerns&lt;br&gt;
difficult IDE support&lt;/p&gt;

&lt;p&gt;We wanted configurability without abandoning normal .NET engineering practices.&lt;/p&gt;

&lt;p&gt;That led us to the handler-based model.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;8. The Handler-Based Workflow&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The workflow defines what should happen.&lt;/p&gt;

&lt;p&gt;The handler defines how it happens.&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 plaintext"&gt;&lt;code&gt;Workflow Step
      ↓
Handler Key
      ↓
Handler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A workflow might contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VerifyPayment
ReserveInventory
FraudReview
PackOrder
ShipOrder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These map to handlers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VerifyPayment
      ↓
VerifyPaymentHandler

ReserveInventory
      ↓
ReserveInventoryHandler

FraudReview
      ↓
FraudReviewHandler

PackOrder
      ↓
PackOrderHandler

ShipOrder
      ↓
ShipOrderHandler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple interface could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IWorkflowHandler&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&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;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WorkflowStepResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;WorkflowContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&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;An implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VerifyPaymentHandler&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"VerifyPayment"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WorkflowStepResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;WorkflowContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Payment verification logic&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WorkflowStepResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Success&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 workflow engine doesn't need to know how payment verification works.&lt;/p&gt;

&lt;p&gt;It only knows:&lt;/p&gt;

&lt;p&gt;Execute "VerifyPayment"&lt;/p&gt;

&lt;p&gt;The handler contains the actual business/application logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;9. Handler Resolution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The application can register handlers using normal .NET dependency injection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VerifyPaymentHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ReserveInventoryHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FraudReviewHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PackOrderHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ShipOrderHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A resolver can then find a handler by its key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkflowHandlerResolver&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_handlers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WorkflowHandlerResolver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_handlers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IWorkflowHandler&lt;/span&gt; &lt;span class="nf"&gt;Resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&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="n"&gt;_handlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&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;=&amp;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;Key&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;$"Handler '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;' was not found."&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;This gives us a useful boundary.&lt;/p&gt;

&lt;p&gt;The workflow is configurable.&lt;/p&gt;

&lt;p&gt;The executable business capabilities remain strongly typed.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;10. Workflow Configuration&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A workflow definition might conceptually look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WorkflowDefinition
-------------------------
Key
Name
Version
Status

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

&lt;/div&gt;



&lt;p&gt;And its steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WorkflowStep
-------------------------
WorkflowVersionId
Key
Order
Configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WorkflowTransition
-------------------------
FromStep
ToStep
Condition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderFulfillment v3

VerifyPayment
      ↓
FraudReview
      ↓
ReserveInventory
      ↓
PackOrder
      ↓
ShipOrder
      ↓
DeliverOrder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that the workflow engine doesn't need to be changed when we rearrange these existing capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;11. Versioning Changes Everything&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This was one of the strongest reasons to move toward a versioned workflow.&lt;/p&gt;

&lt;p&gt;Imagine that version 1 is currently being used by thousands of orders.&lt;/p&gt;

&lt;p&gt;Then the business introduces mandatory fraud screening.&lt;/p&gt;

&lt;p&gt;We don't want to modify the meaning of an existing order's process.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;p&gt;OrderFulfillment v1&lt;/p&gt;

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

&lt;p&gt;We publish:&lt;/p&gt;

&lt;p&gt;OrderFulfillment v2&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VerifyPayment
    ↓
FraudReview
    ↓
ReserveInventory
    ↓
PackOrder
    ↓
ShipOrder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New orders use v2.&lt;/p&gt;

&lt;p&gt;Existing orders continue using v1.&lt;/p&gt;

&lt;p&gt;This gives us historical reproducibility.&lt;/p&gt;

&lt;p&gt;We can answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which process governed this order?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;with:&lt;/p&gt;

&lt;p&gt;Order #12345&lt;br&gt;
Workflow: OrderFulfillment&lt;br&gt;
Version: 1&lt;/p&gt;

&lt;p&gt;rather than trying to reconstruct the rules from the current application code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. The Most Important Rule: A Workflow Instance Has a Version&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I would strongly recommend that a running workflow instance stores its workflow version.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WorkflowInstance
-------------------------
Id
WorkflowDefinitionId
WorkflowVersionId
BusinessEntityId
CurrentStep
Status
StartedAt
CompletedAt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order #1001 → Fulfillment v1
Order #1002 → Fulfillment v1
Order #1003 → Fulfillment v2
Order #1004 → Fulfillment v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The active workflow can evolve without rewriting history.&lt;/p&gt;

&lt;p&gt;This becomes especially important for systems involving:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;regulations
financial processes
approvals
contracts
compliance
long-running operations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;13. What Happens When the Business Changes Again?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Suppose we currently have:&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment
 ↓
Fraud Review
 ↓
Inventory
 ↓
Packing
 ↓
Shipping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the business says:&lt;/p&gt;

&lt;p&gt;Orders above $5,000 require manager approval.&lt;/p&gt;

&lt;p&gt;We can create:&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment
 ↓
Fraud Review
 ↓
Inventory
 ↓
Manager Approval
 ↓
Packing
 ↓
Shipping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow engine remains unchanged.&lt;/p&gt;

&lt;p&gt;If ManagerApprovalHandler already exists, this can potentially be configuration-only.&lt;/p&gt;

&lt;p&gt;That is the key advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;14. Three Levels of Change&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This led me to a useful way of thinking about the architecture.&lt;/p&gt;

&lt;p&gt;Level 1 — Change the process&lt;/p&gt;

&lt;p&gt;Existing handlers are sufficient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A → B → C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes:&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;A&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No application code needs to change.&lt;/p&gt;

&lt;p&gt;Only the workflow definition changes.&lt;/p&gt;

&lt;p&gt;Level 2 — Change handler configuration&lt;/p&gt;

&lt;p&gt;The capability already exists, but its behavior needs parameters.&lt;/p&gt;

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

&lt;p&gt;FraudReviewHandler&lt;/p&gt;

&lt;p&gt;could receive configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"riskThreshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"manualReviewRequired"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different workflow versions can configure the same handler differently.&lt;/p&gt;

&lt;p&gt;Level 3 — Introduce a new capability&lt;/p&gt;

&lt;p&gt;The business introduces something that doesn't exist.&lt;/p&gt;

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

&lt;p&gt;GovernmentComplianceCheck&lt;/p&gt;

&lt;p&gt;There is no existing handler.&lt;/p&gt;

&lt;p&gt;We implement:&lt;/p&gt;

&lt;p&gt;GovernmentComplianceCheckHandler&lt;/p&gt;

&lt;p&gt;After that, the handler becomes another reusable building block for future workflows.&lt;/p&gt;

&lt;p&gt;This is the boundary I find most useful.&lt;/p&gt;

&lt;p&gt;Configuration should compose capabilities. Code should create new capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15. Conditional Branching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The workflow can also represent conditional paths.&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 plaintext"&gt;&lt;code&gt;                 Payment
                    ↓
               Fraud Check
                    ↓
              Risk Level?
              /          \
           Low            High
            ↓               ↓
       Inventory        Manual Review
            │               │
            └───────┬───────┘
                    ↓
                  Packing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow definition can reference a rule:&lt;/p&gt;

&lt;p&gt;HighRiskOrder&lt;/p&gt;

&lt;p&gt;rather than embedding arbitrary code into configuration.&lt;/p&gt;

&lt;p&gt;The rule itself can remain strongly typed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IWorkflowRule&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&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;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;EvaluateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;WorkflowContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This keeps the dynamic part controlled.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;16. Parallel Steps&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Another situation where the workflow abstraction becomes attractive is parallel execution.&lt;/p&gt;

&lt;p&gt;Suppose after payment verification we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Payment
                ↓
        ┌───────┼────────┐
        ↓       ↓        ↓
      Fraud   Inventory  Compliance
        │       │        │
        └───────┼────────┘
                ↓
              Packing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These checks are conceptually independent.&lt;/p&gt;

&lt;p&gt;A workflow engine can represent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parallel
   ├── Fraud
   ├── Inventory
   └── Compliance
        ↓
       Join
        ↓
      Packing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A state machine can also model this.&lt;/p&gt;

&lt;p&gt;But as the number of parallel activities increases, a state machine often starts requiring composite states, flags, guards, and synchronization logic.&lt;/p&gt;

&lt;p&gt;At that point, we're gradually building a workflow engine inside the state machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;17. Human Tasks and Long-Running Processes&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Another difference appears when the process needs human interaction.&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 plaintext"&gt;&lt;code&gt;Fraud Review
      ↓
Manual Approval
      ↓
Wait for Manager
      ↓
Continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The manager may approve it:&lt;/p&gt;

&lt;p&gt;in 30 seconds&lt;/p&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;p&gt;in 3 days&lt;/p&gt;

&lt;p&gt;A workflow instance can persist:&lt;/p&gt;

&lt;p&gt;Status = Waiting&lt;br&gt;
CurrentStep = ManagerApproval&lt;br&gt;
AssignedTo = Manager&lt;br&gt;
DueAt = ...&lt;/p&gt;

&lt;p&gt;and resume later.&lt;/p&gt;

&lt;p&gt;Again, a state machine can support this, but now we need to build persistence, resumption, scheduling, timeout handling, and related infrastructure around it.&lt;/p&gt;

&lt;p&gt;The workflow abstraction naturally starts to fit the problem better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;18. So Is a Configurable Workflow Always Better?&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;This is probably the most important conclusion of this whole exercise.&lt;/p&gt;

&lt;p&gt;A configurable workflow introduces significant complexity.&lt;/p&gt;

&lt;p&gt;You now need to think about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;workflow definitions
versions
instance persistence
step execution
retries
idempotency
concurrency
conditions
failure handling
timeouts
audit history
authorization
migrations
debugging
configuration validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple state machine does not need all of this.&lt;/p&gt;

&lt;p&gt;If the process is:&lt;/p&gt;

&lt;p&gt;Created&lt;br&gt;
 ↓&lt;br&gt;
Approved&lt;br&gt;
 ↓&lt;br&gt;
Completed&lt;/p&gt;

&lt;p&gt;building a workflow engine would be overengineering.&lt;/p&gt;

&lt;p&gt;A state machine is probably the better solution.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;19. State Machine vs Configurable Workflow&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The comparison I now use is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which one is more powerful?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which type of change does the system need to optimize for?"&lt;/p&gt;
&lt;/blockquote&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%2F5ngd606fufksakgzt9ly.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%2F5ngd606fufksakgzt9ly.png" alt=" " width="585" height="565"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;20. The Architectural Lesson&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The biggest lesson for me was not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"State machines are bad."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They aren't.&lt;/p&gt;

&lt;p&gt;The lesson was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We had initially modeled the problem as state transitions, but the problem eventually became process orchestration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a very different problem.&lt;/p&gt;

&lt;p&gt;A state machine asks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What state am I in?
What transitions are legal?

A configurable workflow asks:

Which process applies?
Which version applies?
Which step comes next?
Which conditions apply?
Which handler executes it?
Can this step run in parallel?
Should we wait?
Can we retry?
How do we resume?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the business starts asking those questions, a workflow abstraction becomes much more appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;21. The Architecture I Would Choose&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The resulting architecture looks roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 ┌───────────────────────┐
                 │ Workflow Definition   │
                 │       Version         │
                 └───────────┬───────────┘
                             │
                             ↓
                 ┌───────────────────────┐
                 │    Workflow Engine    │
                 └───────────┬───────────┘
                             │
              ┌──────────────┼──────────────┐
              ↓              ↓              ↓
           Steps        Conditions       Rules
              │              │              │
              ↓              ↓              ↓
       Handler Keys      Rule Keys       Rule Handlers
              │
              ↓
       Handler Resolver
              │
      ┌───────┼────────┐
      ↓       ↓        ↓
   Payment  Fraud   Inventory
   Handler  Handler  Handler
      │       │        │
      └───────┼────────┘
              ↓
        Domain/Application
            Services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The responsibilities are separated:&lt;/p&gt;

&lt;p&gt;Workflow&lt;/p&gt;

&lt;p&gt;Defines:&lt;/p&gt;

&lt;p&gt;What, when, order, branching, version.&lt;/p&gt;

&lt;p&gt;Handler&lt;/p&gt;

&lt;p&gt;Defines:&lt;/p&gt;

&lt;p&gt;How a specific capability is executed.&lt;/p&gt;

&lt;p&gt;Domain/Application services&lt;/p&gt;

&lt;p&gt;Define:&lt;/p&gt;

&lt;p&gt;Actual business behavior and invariants.&lt;/p&gt;

&lt;p&gt;Database&lt;/p&gt;

&lt;p&gt;Stores:&lt;/p&gt;

&lt;p&gt;Definitions, versions, instances, history, and execution state.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;22. The Most Important Design Principle&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If I had to summarize the entire architectural decision in one sentence:&lt;/p&gt;

&lt;p&gt;Configuration should compose existing capabilities; code should create new capabilities.&lt;/p&gt;

&lt;p&gt;That gives us a useful balance.&lt;/p&gt;

&lt;p&gt;We don't need to deploy the application every time the business rearranges an existing process.&lt;/p&gt;

&lt;p&gt;But we also don't pretend that every possible future behavior can magically be represented by configuration.&lt;/p&gt;

&lt;p&gt;When a genuinely new capability appears, we write code.&lt;/p&gt;

&lt;p&gt;Then that capability becomes available to future workflow versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;23. Final Takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I would still happily use a state machine in a new .NET project.&lt;/p&gt;

&lt;p&gt;If I know the lifecycle is stable, I would probably prefer it.&lt;/p&gt;

&lt;p&gt;It is simple, explicit, strongly typed, testable, and easy to reason about.&lt;/p&gt;

&lt;p&gt;But if I discover that:&lt;/p&gt;

&lt;p&gt;the sequence of steps changes frequently,&lt;br&gt;
different customers need different processes,&lt;br&gt;
business rules evolve independently of deployments,&lt;br&gt;
old processes must remain reproducible,&lt;br&gt;
steps can be conditional or parallel,&lt;br&gt;
human approval is involved,&lt;br&gt;
processes can run for days or weeks,&lt;/p&gt;

&lt;p&gt;then I would stop trying to make the state machine handle everything.&lt;/p&gt;

&lt;p&gt;At that point, I would consider a versioned configurable workflow composed of strongly typed handlers.&lt;/p&gt;

&lt;p&gt;Not because it is more sophisticated.&lt;/p&gt;

&lt;p&gt;Because it models the problem more accurately.&lt;/p&gt;

&lt;p&gt;And that is perhaps the most important lesson in system design:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best architecture is not the one with the most features. It is the one whose abstractions match the kind of change the system is expected to absorb.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>state</category>
      <category>machines</category>
      <category>configurable</category>
      <category>workflows</category>
    </item>
    <item>
      <title>Benchmarking EF Core LINQ, Dapper Raw SQL, and Stored Procedures in .NET: A Real-World Performance Comparison (2026)</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Sat, 31 Jan 2026 07:12:58 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/benchmarking-ef-core-linq-dapper-raw-sql-and-stored-procedures-in-net-a-real-world-performance-jp2</link>
      <guid>https://dev.to/mina_golzari_dalir/benchmarking-ef-core-linq-dapper-raw-sql-and-stored-procedures-in-net-a-real-world-performance-jp2</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/mina_golzari_dalir" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" alt="mina_golzari_dalir"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/mina_golzari_dalir/benchmarking-ef-core-linq-dapper-raw-sql-and-stored-procedures-in-net-a-real-world-performance-54e4" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Benchmarking EF Core LINQ, Dapper Raw SQL, and Stored Procedures in .NET: A Real-World Performance Comparison (2026)&lt;/h2&gt;
      &lt;h3&gt;Mina Golzari Dalir ・ Jan 5&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#benchmark&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#linq&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#dapper&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#storedprocedure&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>benchmark</category>
      <category>linq</category>
      <category>dapper</category>
      <category>storedprocedure</category>
    </item>
    <item>
      <title>Benchmarking EF Core LINQ, Dapper Raw SQL, and Stored Procedures in .NET: A Real-World Performance Comparison (2026)</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Mon, 05 Jan 2026 12:40:37 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/benchmarking-ef-core-linq-dapper-raw-sql-and-stored-procedures-in-net-a-real-world-performance-54e4</link>
      <guid>https://dev.to/mina_golzari_dalir/benchmarking-ef-core-linq-dapper-raw-sql-and-stored-procedures-in-net-a-real-world-performance-54e4</guid>
      <description>&lt;p&gt;In .NET development, selecting the right data access strategy is crucial for balancing performance, maintainability, and developer productivity. Entity Framework Core (EF Core) with LINQ provides a powerful full ORM experience, Dapper offers lightweight micro-ORM speed with raw SQL control, and Stored Procedures deliver database-level optimization and security.&lt;br&gt;
This post explores a practical benchmark comparing these approaches on a real-world query: calculating team performance summaries (total tasks, completed tasks, and completion rate) with optional date range and team filters. The test uses a database with over 50,000 tasks, executed via BenchmarkDotNet in .NET (likely .NET 8+).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding BenchmarkDotNet Results: A Quick Guide&lt;/strong&gt;&lt;br&gt;
BenchmarkDotNet produces detailed statistical reports to ensure reliable comparisons. Here's how to interpret the key columns in the results table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mean&lt;/strong&gt;: The average (arithmetic mean) execution time across all iterations. Lower is better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error&lt;/strong&gt;: Half of the 99.9% confidence interval—indicates the uncertainty in the Mean value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StdDev&lt;/strong&gt; (Standard Deviation): Measures variability in measurements. Low StdDev means consistent results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ratio&lt;/strong&gt;: The performance ratio relative to the baseline (here, EF Core LINQ marked as baseline).

&lt;ul&gt;
&lt;li&gt;1.00 = same as baseline&lt;/li&gt;
&lt;li&gt;&amp;lt;1.00 = faster (e.g., 0.50 = 2x faster)&lt;/li&gt;
&lt;li&gt;1.00 = slower (e.g., 1.34 = 34% slower)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RatioSD&lt;/strong&gt;: Standard deviation of the ratio—shows how stable the relative performance is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allocated&lt;/strong&gt;: Managed memory allocated per operation (in KB or bytes). Lower means less GC pressure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alloc Ratio&lt;/strong&gt;: Memory allocation ratio relative to the baseline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These metrics come from multiple warm-up and actual iterations, eliminating noise and providing statistically sound data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Technologies&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;EF Core with LINQ&lt;/strong&gt;&lt;br&gt;
EF Core translates LINQ queries to SQL, handling change tracking, migrations, and complex mappings.&lt;br&gt;
Example from the benchmark:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var result = await (from task in tasksQuery
                    join team in _context.Teams on task.TeamId equals team.Id
                    group task by new { team.Id, team.Name } into g
                    select new TeamPerformanceSummaryResponseDto
                    {
                        TeamId = g.Key.Id,
                        TeamName = g.Key.Name,
                        TotalTasks = g.Count(),
                        CompletedTasks = g.Count(t =&amp;gt; t.Status == "Completed" || t.CompletedAt != null),
                        CompletionRate = g.Count() &amp;gt; 0 ? (decimal)g.Count(t =&amp;gt; t.Status == "Completed" || t.CompletedAt != null) * 100 / g.Count() : 0
                    }).ToListAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dapper with Raw SQL&lt;/strong&gt;&lt;br&gt;
Dapper maps raw SQL results to objects with minimal overhead and full SQL control.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var sql = @"
    SELECT t.Id AS TeamId, t.Name AS TeamName,
           COUNT(task.Id) AS TotalTasks,
           SUM(CASE WHEN task.Status = 'Completed' OR task.CompletedAt IS NOT NULL THEN 1 ELSE 0 END) AS CompletedTasks,
           CASE WHEN COUNT(task.Id) &amp;gt; 0 
                THEN CAST(SUM(CASE WHEN task.Status = 'Completed' OR task.CompletedAt IS NOT NULL THEN 1 ELSE 0 END) * 100.0 / COUNT(task.Id) AS DECIMAL(18,2))
                ELSE 0 END AS CompletionRate
    FROM Teams t
    INNER JOIN Tasks task ON t.Id = task.TeamId
    WHERE 1 = 1 [optional filters]
    GROUP BY t.Id, t.Name
    ORDER BY t.Id";
var result = await connection.QueryAsync&amp;lt;TeamPerformanceSummaryResponseDto&amp;gt;(sql, parameters);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stored Procedures&lt;/strong&gt;&lt;br&gt;
Pre-compiled SQL in the database, called via Dapper here for fairness.&lt;br&gt;
Example Procedure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE PROCEDURE sp_GetTeamPerformanceSummary
    @StartDate DATETIME2 = NULL,
    @EndDate DATETIME2 = NULL,
    @TeamId INT = NULL
AS
BEGIN
    SELECT t.Id AS TeamId, t.Name AS TeamName, ... [same aggregation logic]
    FROM Teams t INNER JOIN Tasks task ON t.Id = task.TeamId
    WHERE (@StartDate IS NULL OR task.CreatedAt &amp;gt;= @StartDate) ...
    GROUP BY t.Id, t.Name
    ORDER BY t.Id;
END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling with Dapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var result = await connection.QueryAsync&amp;lt;TeamPerformanceSummaryResponseDto&amp;gt;(
    "sp_GetTeamPerformanceSummary", parameters, commandType: CommandType.StoredProcedure);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real Benchmark Results (50,000+ Tasks)&lt;/strong&gt;&lt;br&gt;
The benchmark ran on modern hardware (Intel Core i7-7500U equivalent) with warm-up and multiple iterations.&lt;br&gt;
Results Table:&lt;/p&gt;

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

&lt;p&gt;Key Insights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EF Core LINQ is the fastest here (baseline), likely due to optimized query translation and connection management in this aggregation scenario.&lt;/li&gt;
&lt;li&gt;Dapper Raw SQL is ~34% slower but allocates less than half the memory.&lt;/li&gt;
&lt;li&gt;Stored Procedure is the slowest (~62% over EF) but uses the least memory 
(~22% of EF).&lt;/li&gt;
&lt;li&gt;High error/stddev in Dapper/SP suggests variability—possibly from connection handling or plan caching.&lt;/li&gt;
&lt;li&gt;Recent 2024-2025 benchmarks show EF Core closing the gap significantly, often outperforming or matching Dapper in complex queries when tuned (e.g., no tracking).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These results contrast with many older benchmarks where Dapper dominated simple reads, but for aggregations/joins with large data, EF Core's optimizations shine.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Overall Insights:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;EF Core often leads or ties in speed for complex aggregations, thanks to modern optimizations in .NET 8+.&lt;br&gt;
Dapper and Stored Procedures consistently use less memory.&lt;br&gt;
Variability (higher Error/StdDev in some runs) points to factors like connection pooling and query plan caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and Cons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;EF Core LINQ&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High productivity with type-safe LINQ.&lt;/li&gt;
&lt;li&gt;Excellent for complex domains and rapid development.&lt;/li&gt;
&lt;li&gt;Strong migrations and change tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Higher memory usage.&lt;/li&gt;
&lt;li&gt;Potential for suboptimal SQL if not careful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dapper Raw SQL&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low memory footprint.&lt;/li&gt;
&lt;li&gt;Full SQL control for tuning.&lt;/li&gt;
&lt;li&gt;Great for read-heavy or high-throughput apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More boilerplate (manual SQL, parameters).&lt;/li&gt;
&lt;li&gt;No built-in migrations or tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stored Procedures&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimal client-side allocation.&lt;/li&gt;
&lt;li&gt;Pre-compiled plans and security benefits.&lt;/li&gt;
&lt;li&gt;Ideal for regulated or legacy environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logic in database → harder versioning/maintenance.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Less flexible for dynamic queries.&lt;br&gt;
&lt;strong&gt;When to Choose Each (2026 Perspective)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EF Core LINQ → Default for most apps. Productivity wins, and performance is now excellent (especially .NET 8+). Use for CRUD, complex models.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dapper → Performance hotspots, APIs with massive reads, or when you need precise SQL control. Hybrid approach common.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stored Procedures → Security-critical ops, heavy DB logic, or when DBAs own optimizations. Call via Dapper for best results.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recent discussions (2025) confirm: EF Core is the go-to unless extreme performance demands raw SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
No universal winner—EF Core offers the best balance for most modern .NET apps in 2026, with surprising speed in aggregations. Dapper excels in memory efficiency, and Stored Procedures in allocation/security.&lt;br&gt;
Always benchmark your specific workload!&lt;/p&gt;

&lt;p&gt;The full code (including interface, DTOs, and benchmark setup) is shared above for easy replication.&lt;br&gt;
The complete benchmark project is available on GitHub:&lt;br&gt;
&lt;a href="https://github.com/Productive-Build-Cycle/Reporting/tree/perf/benchmark-query" rel="noopener noreferrer"&gt;https://github.com/Productive-Build-Cycle/Reporting/tree/perf/benchmark-query&lt;/a&gt;&lt;br&gt;
I invite you to star the repo, fork it, run the benchmarks on your setup, add more scenarios (e.g., bulk inserts, different data sizes), or share your results! Open issues for discussions or pull requests for improvements contributions are very welcome!&lt;br&gt;
_&lt;br&gt;
What’s your experience? Share in the comments!&lt;br&gt;
What do your benchmarks show? Comment here or on GitHub!_&lt;/p&gt;

&lt;h1&gt;
  
  
  dotnet #efcore #dapper #performance #benchmark.
&lt;/h1&gt;

</description>
      <category>benchmark</category>
      <category>linq</category>
      <category>dapper</category>
      <category>storedprocedure</category>
    </item>
    <item>
      <title>The Evolution of Angular</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Fri, 12 Dec 2025 16:12:05 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/the-evolution-of-angular-2o0a</link>
      <guid>https://dev.to/mina_golzari_dalir/the-evolution-of-angular-2o0a</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/mina_golzari_dalir" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" alt="mina_golzari_dalir"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/mina_golzari_dalir/the-evolution-of-angular-key-features-and-benefits-from-version-12-to-21-12a" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;The Evolution of Angular: Key Features and Benefits from Version 12 to 21&lt;/h2&gt;
      &lt;h3&gt;Mina Golzari Dalir ・ Dec 12&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#performance&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#architecture&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#typescript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>The Evolution of Angular: Key Features and Benefits from Version 12 to 21</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Fri, 12 Dec 2025 16:11:17 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/the-evolution-of-angular-key-features-and-benefits-from-version-12-to-21-12a</link>
      <guid>https://dev.to/mina_golzari_dalir/the-evolution-of-angular-key-features-and-benefits-from-version-12-to-21-12a</guid>
      <description>&lt;p&gt;Over the past several years, Angular has undergone one of the most significant transformations in its history, shifting from a module-heavy, change-detection–driven framework into a modern, high-performance, developer-focused platform. From version 12 through version 21, Angular has introduced major architectural advancements such as standalone components, signals, the new template control flow, an ESBuild-powered build system, and advanced SSR hydration. These changes not only simplify development and reduce boilerplate but also deliver measurable improvements in rendering speed, scalability, and user experience. Whether you are maintaining an older application or preparing to adopt the latest version, understanding this evolution is essential for making informed technical decisions and maximizing Angular’s capabilities.&lt;/p&gt;

&lt;p&gt;Below is a professional, business-friendly, technical explanation of the main Angular features across versions 12 → 16 → 18 → 21, along with what each feature does and the measurable benefits (performance, maintainability, architectural quality).&lt;/p&gt;

&lt;p&gt;This will help you clearly understand why each Angular generation matters and how they improve both developer experience and application performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Standalone Components&lt;/strong&gt;&lt;br&gt;
A component that works without NgModule.&lt;br&gt;
You no longer need &lt;code&gt;app.module.ts&lt;/code&gt;, &lt;code&gt;product.module.ts&lt;/code&gt;, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'user-card',
  standalone: true,
  template: `&amp;lt;h3&amp;gt;{{ user().name }}&amp;lt;/h3&amp;gt;`
})
export class UserCard {
  user = signal({ name: 'Mina' });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates unnecessary boilerplate&lt;/li&gt;
&lt;li&gt;Reduces architectural complexity&lt;/li&gt;
&lt;li&gt;Faster onboarding for developers&lt;/li&gt;
&lt;li&gt;Smaller codebase, fewer files&lt;/li&gt;
&lt;li&gt;Better tree-shaking → smaller final bundle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Introduced&lt;/strong&gt;: Angular 14&lt;br&gt;
&lt;strong&gt;Default&lt;/strong&gt;: Angular 18&lt;br&gt;
&lt;strong&gt;Fully enforced&lt;/strong&gt;: Angular 21&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Signals (Reactive State System)&lt;/strong&gt;&lt;br&gt;
A new built-in reactivity model that tracks data changes synchronously and efficiently, similar to SolidJS or React’s state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const counter = signal(0);

function increment() {
  counter.update(n =&amp;gt; n + 1);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates ChangeDetection complexity&lt;/li&gt;
&lt;li&gt;Minimal re-renders → massive performance improvement&lt;/li&gt;
&lt;li&gt;Avoids RxJS boilerplate where not needed&lt;/li&gt;
&lt;li&gt;Makes code more predictable and easier to debug&lt;/li&gt;
&lt;li&gt;Works perfectly with Angular’s new template system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Preview&lt;/strong&gt;: Angular 16&lt;br&gt;
&lt;strong&gt;Stable&lt;/strong&gt;: Angular 18&lt;br&gt;
&lt;strong&gt;Recommended&lt;/strong&gt;: Angular 21&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. New Control Flow (@if, &lt;a class="mentioned-user" href="https://dev.to/for"&gt;@for&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/switch"&gt;@switch&lt;/a&gt;)&lt;/strong&gt;&lt;br&gt;
Modern template syntax replacing &lt;code&gt;*ngIf&lt;/code&gt; and &lt;code&gt;*ngFor&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;@if (loading()) {
  &amp;lt;p&amp;gt;Loading…&amp;lt;/p&amp;gt;
} @else {
  @for (item of items(); track item.id) {
    &amp;lt;div&amp;gt;{{ item.title }}&amp;lt;/div&amp;gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster runtime (because Angular compiles these more efficiently)&lt;/li&gt;
&lt;li&gt;Much cleaner templates&lt;/li&gt;
&lt;li&gt;Better type checking&lt;/li&gt;
&lt;li&gt;Built for signal reactivity&lt;/li&gt;
&lt;li&gt;Supports better tracking with track keyword&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Introduced&lt;/strong&gt;: Angular 17&lt;br&gt;
&lt;strong&gt;Fully optimized&lt;/strong&gt;: Angular 18–21&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. ESBuild-Based Build System&lt;/strong&gt;&lt;br&gt;
Angular replaced Webpack with ESBuild for compilation and bundling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;angular.json

{
  "builder": "@angular-devkit/build-angular:browser-esbuild"
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Up to 10x faster builds&lt;/li&gt;
&lt;li&gt;Instant hot reload (almost zero refresh time in dev mode)&lt;/li&gt;
&lt;li&gt;Smaller output bundles&lt;/li&gt;
&lt;li&gt;Less configuration headaches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Introduced&lt;/strong&gt;: Angular 15–16&lt;br&gt;
&lt;strong&gt;Default&lt;/strong&gt;: Angular 18+&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. SSR Hydration + Partial Hydration&lt;/strong&gt;&lt;br&gt;
SSR = Server-Side Rendering&lt;br&gt;
Hydration = Reconnecting server-rendered HTML to client-side Angular&lt;br&gt;
Partial Hydration = Only hydrate the parts that require interaction&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provideClientHydration()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster page load + better SEO&lt;/li&gt;
&lt;li&gt;First Contentful Paint (FCP) drastically improved&lt;/li&gt;
&lt;li&gt;Angular feels more like Next.js or Remix&lt;/li&gt;
&lt;li&gt;Lower memory usage on the client&lt;/li&gt;
&lt;li&gt;Perfect for e-commerce and blogs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Early version&lt;/strong&gt;: Angular 16&lt;br&gt;
&lt;strong&gt;Non-destructive hydration&lt;/strong&gt;: Angular 18&lt;br&gt;
&lt;strong&gt;Partial hydration + advanced SSR&lt;/strong&gt;: Angular 21&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Deferrable Views (&lt;a class="mentioned-user" href="https://dev.to/defer"&gt;@defer&lt;/a&gt;)&lt;/strong&gt;&lt;br&gt;
Lazy-rendering of parts of a page based on conditions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'analytics-widget',
  standalone: true,
  hydration: { mode: 'client' },
  template: `&amp;lt;dashboard-chart /&amp;gt;`
})
export class AnalyticsWidget {}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce initial load time&lt;/li&gt;
&lt;li&gt;Render heavy components only when user needs them&lt;/li&gt;
&lt;li&gt;Move expensive logic out of the critical path&lt;/li&gt;
&lt;li&gt;Very useful for large dashboards or media-heavy pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stable&lt;/strong&gt;: Angular 17+&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Required Inputs&lt;/strong&gt;&lt;br&gt;
A Component Input must be set or Angular will show an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@defer (on idle) {
  &amp;lt;chart-dashboard&amp;gt;&amp;lt;/chart-dashboard&amp;gt;
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevents undefined bugs&lt;/li&gt;
&lt;li&gt;Stronger API contract between components&lt;/li&gt;
&lt;li&gt;Better maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Introduced&lt;/strong&gt;: Angular 16&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Modern Angular Material (Material 3)&lt;/strong&gt;&lt;br&gt;
Complete redesign of Angular Material based on Google’s M3 spec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;mat-card appearance="outlined"&amp;gt;
  &amp;lt;mat-card-header&amp;gt;
    &amp;lt;mat-card-title&amp;gt;Product Details&amp;lt;/mat-card-title&amp;gt;
  &amp;lt;/mat-card-header&amp;gt;
&amp;lt;/mat-card&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More modern UI&lt;/li&gt;
&lt;li&gt;Better accessibility&lt;/li&gt;
&lt;li&gt;More customizable themes&lt;/li&gt;
&lt;li&gt;More consistent spacing, typography, and layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Default&lt;/strong&gt;: Angular 18–21&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Better TypeScript Support&lt;/strong&gt;&lt;br&gt;
Each Angular version moves TS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function logMessage&amp;lt;T extends string&amp;gt;(msg: T): T {
  return msg;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better IntelliSense&lt;/li&gt;
&lt;li&gt;Stricter type checking&lt;/li&gt;
&lt;li&gt;Renaming, refactoring, and autocomplete improvements&lt;/li&gt;
&lt;li&gt;Faster compilation&lt;/li&gt;
&lt;li&gt;Support for decorators, generics, async functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;10. Web Test Runner (instead of Karma/Jasmine)&lt;/strong&gt;&lt;br&gt;
A faster, modern test runner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { test, expect } from '@angular/testing';

test('price should be greater than zero', () =&amp;gt; {
  const price = 120;
  expect(price).toBeGreaterThan(0);
});

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~15x faster test runs&lt;/li&gt;
&lt;li&gt;Better debugging&lt;/li&gt;
&lt;li&gt;Cleaner test environment setup&lt;/li&gt;
&lt;li&gt;Supports modern ES modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Introduced&lt;/strong&gt;: Angular 17&lt;br&gt;
&lt;strong&gt;Default&lt;/strong&gt;: Angular 18+&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Improved Runtime Performance&lt;/strong&gt;&lt;br&gt;
Angular removed almost all heavy, legacy ChangeDetection logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster rendering&lt;/li&gt;
&lt;li&gt;Less CPU usage&lt;/li&gt;
&lt;li&gt;Better battery life on mobile devices&lt;/li&gt;
&lt;li&gt;Higher scalability (tens of thousands of DOM nodes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optimized&lt;/strong&gt;: Angular 16–21&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PROJECT EXAMPLE: “Product Management Module”&lt;/strong&gt;&lt;br&gt;
Features included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List products&lt;/li&gt;
&lt;li&gt;Add new product&lt;/li&gt;
&lt;li&gt;Loading state&lt;/li&gt;
&lt;li&gt;API service integration
We will show how this same feature looks in Angular 12, 16, 18, and 21.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ANGULAR 12 — Legacy Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Folder Structure&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;/src/app/
   app.module.ts
   product/
      product.module.ts
      product-list/
          product-list.component.ts
          product-list.component.html
      product-add/
          product-add.component.ts
          product-add.component.html
      product.service.ts
      product.model.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Module-Based Architecture&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;// product.module.ts
@NgModule({
  declarations: [
    ProductListComponent,
    ProductAddComponent
  ],
  imports: [CommonModule, FormsModule],
  providers: [ProductService]
})
export class ProductModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Component (Angular 12 style)&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;export class ProductListComponent implements OnInit {
  products: Product[] = [];

  constructor(private srv: ProductService) {}

  ngOnInit() {
    this.srv.getAll().subscribe(res =&amp;gt; this.products = res);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Template&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;&amp;lt;div *ngFor="let p of products"&amp;gt;
  {{ p.name }} - {{ p.price }}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ANGULAR 16 — Transition Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Folder Structure&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;/src/app/
   product/
      product-list.component.ts
      product-add.component.ts
      product.service.ts

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Standalone Component (Optional)&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;@Component({
  selector: 'product-list',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './product-list.component.html'
})
export class ProductListComponent {
  products = signal&amp;lt;Product[]&amp;gt;([]);

  constructor(private srv: ProductService) {
    this.srv.getAll().subscribe(r =&amp;gt; this.products.set(r));
  }
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Template (Still using *ngFor)&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;&amp;lt;div *ngFor="let p of products()"&amp;gt;
  {{ p.name }} - {{ p.price }}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ANGULAR 18 — Modern Angular&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Folder Structure (Modular by Feature)&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;/src/app/
   product/
      list/
         product-list.component.ts
      add/
         product-add.component.ts
      product.service.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Signal-Based Component (Modern)&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;@Component({
  selector: 'product-list',
  standalone: true,
  template: `
    @for (p of products(); track p.id) {
      &amp;lt;div&amp;gt;
        {{ p.name }} - {{ p.price }}
      &amp;lt;/div&amp;gt;
    }
  `
})
export class ProductListComponent {
  products = signal&amp;lt;Product[]&amp;gt;([]);
  loading = signal(true);

  constructor(srv: ProductService) {
    srv.getAll().subscribe(res =&amp;gt; {
      this.products.set(res);
      this.loading.set(false);
    });
  }
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ANGULAR 21 — Latest Architecture (Full Signal Components + Modern Control Flow)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Folder Structure (Modern Clean)&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;/src/app/product/
   list.component.ts
   add.component.ts
   product.service.ts

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Full Signal Component&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;@Component({
  selector: 'product-list',
  standalone: true,
  template: `
    @if (loading()) {
      &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;
    } @else {
      @for (p of products(); track p.id) {
        &amp;lt;div&amp;gt;{{ p.name }} - {{ p.price }}&amp;lt;/div&amp;gt;
      }
    }
  `
})
export class ProductListComponent {
  loading = signal(true);
  products = signal&amp;lt;Product[]&amp;gt;([]);

  constructor(srv: ProductService) {
    srv.getAll().subscribe(data =&amp;gt; {
      this.products.set(data);
      this.loading.set(false);
    });
  }
}

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

&lt;/div&gt;



</description>
      <category>performance</category>
      <category>architecture</category>
      <category>typescript</category>
      <category>angular</category>
    </item>
    <item>
      <title>Docker for Developers</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Wed, 26 Nov 2025 14:15:23 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/docker-for-developers-1emk</link>
      <guid>https://dev.to/mina_golzari_dalir/docker-for-developers-1emk</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mina_golzari_dalir/docker-for-developers-from-zero-to-running-your-first-production-grade-nextjs-app-in-1-hour-4if7" class="crayons-story__hidden-navigation-link"&gt;Docker for Developers: From Zero to Running Your First Production-Grade Next.js App in 1 Hour&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/mina_golzari_dalir" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" alt="mina_golzari_dalir profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mina_golzari_dalir" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mina Golzari Dalir
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mina Golzari Dalir
                
              
              &lt;div id="story-author-preview-content-3051137" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mina_golzari_dalir" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mina Golzari Dalir&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/mina_golzari_dalir/docker-for-developers-from-zero-to-running-your-first-production-grade-nextjs-app-in-1-hour-4if7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 26 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mina_golzari_dalir/docker-for-developers-from-zero-to-running-your-first-production-grade-nextjs-app-in-1-hour-4if7" id="article-link-3051137"&gt;
          Docker for Developers: From Zero to Running Your First Production-Grade Next.js App in 1 Hour
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nextjs"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nextjs&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/docker"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;docker&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/mina_golzari_dalir/docker-for-developers-from-zero-to-running-your-first-production-grade-nextjs-app-in-1-hour-4if7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;6&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/mina_golzari_dalir/docker-for-developers-from-zero-to-running-your-first-production-grade-nextjs-app-in-1-hour-4if7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              2&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




</description>
      <category>nextjs</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>docker</category>
    </item>
    <item>
      <title>Docker for Developers: From Zero to Running Your First Production-Grade Next.js App in 1 Hour</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Wed, 26 Nov 2025 14:03:31 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/docker-for-developers-from-zero-to-running-your-first-production-grade-nextjs-app-in-1-hour-4if7</link>
      <guid>https://dev.to/mina_golzari_dalir/docker-for-developers-from-zero-to-running-your-first-production-grade-nextjs-app-in-1-hour-4if7</guid>
      <description>&lt;p&gt;Hey there! Welcome to the only &lt;code&gt;Next.js + Docker&lt;/code&gt; guide you’ll ever need in 2025.&lt;br&gt;
By the end of this single post (and ~60 minutes of your time), you will:&lt;/p&gt;

&lt;p&gt;Ship a real Next.js 15 app in a container smaller than 90 MB&lt;br&gt;
Run it exactly the same way on Mac, Windows, Linux, or even in the cloud&lt;br&gt;
Make your entire team happy (no more “it works on my machine”)&lt;br&gt;
Be ready to deploy to Railway, Render, Fly.io, or Kubernetes with zero changes&lt;/p&gt;

&lt;p&gt;Let’s go – coffee ready?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What You’ll Build Today&lt;/strong&gt;&lt;br&gt;
A production-grade Next.js 15 (App Router) app that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;lt; 90 MB Docker image&lt;/li&gt;
&lt;li&gt;Multi-stage build (no dev dependencies in production)&lt;/li&gt;
&lt;li&gt;Non-root user + health checks&lt;/li&gt;
&lt;li&gt;Hot reload for development&lt;/li&gt;
&lt;li&gt;One-command workflow for the whole team&lt;/li&gt;
&lt;li&gt;Works everywhere: local, CI, GitHub Codespaces, Gitpod&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;br&gt;
Make sure you have these installed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Node.js ≥ 18 (preferably 20 or 22) → &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;https://nodejs.org&lt;/a&gt; 
Check with: &lt;code&gt;node -v&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Git → &lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;https://git-scm.com/downloads&lt;/a&gt;
Check with: &lt;code&gt;git --version&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Docker Desktop (Windows/Mac) or Docker Engine (Linux) → &lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;https://www.docker.com/products/docker-desktop&lt;/a&gt;
Check with: &lt;code&gt;docker --version&lt;/code&gt; and &lt;code&gt;docker compose version&lt;/code&gt; (Compose V2 is now built-in)
If any of these are missing, install them first.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;** Step 1: Create the Next.js App **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 1. Create the project
npx create-next-app@latest my-nextjs-app --ts --app --eslint --tailwind --src-dir --import-alias "@/*"
# 2. Go into the folder
cd my-nextjs-app
# 3. Open it in your editor
code .    # if you use VS Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we just chose and why (important for Docker later):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--app&lt;/code&gt;→ App Router (new standard, better for Docker + Server Actions)&lt;br&gt;
&lt;code&gt;--src-dir&lt;/code&gt; → Keeps everything clean inside &lt;code&gt;/src&lt;/code&gt;&lt;br&gt;
&lt;code&gt;--turbo&lt;/code&gt; → Uses Turbopack in dev (faster than webpack)&lt;br&gt;
&lt;code&gt;--import-alias&lt;/code&gt; "@/*" → Clean imports like &lt;code&gt;@/components/Button&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Test it quickly: &lt;code&gt;npm run dev&lt;/code&gt; → &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;br&gt;
your &lt;code&gt;package.json&lt;/code&gt; scripts should look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "dev": "next dev --turbo",
  "build": "next build",
  "start": "next start",
  "lint": "next lint"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize Git + create GitHub repo + first commit&lt;/strong&gt;&lt;br&gt;
Run these commands one by one in your project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 1. Initialize git
git init

# 2. Create a nice .gitignore (Next.js already has one, but we make it perfect for Docker)

# Docker
.dockerignore
Dockerfile
docker-compose.yml

# Node
node_modules/
.env.local
EOF

# 3. First commit
git add .
git commit -m "feat: initial commit - Next.js app ready for Docker"

# 4. Create the GitHub repo (do this in your browser)
# → Go to https://github.com/new
# Name: my-nextjs-docker-app (or whatever you want)
# Keep it Public or Private — your choice
# DO NOT initialize with README (we already have one)
# Click "Create repository"

# 5. Link and push (replace YOUR_USERNAME with your GitHub username)
git remote add origin https://github.com/YOUR_USERNAME/my-nextjs-docker-app.git
git branch -M main
git push -u origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: The 2025 Production Dockerfile (The One Everyone Copies)&lt;/strong&gt;&lt;br&gt;
Create &lt;code&gt;Dockerfile&lt;/code&gt;(root of project):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Build stage -&amp;gt; we name this stage so we can copy from it later
FROM node:22-alpine AS builder 
# All following commands run inside /app folder
WORKDIR /app
# Copy ONLY dependency files first → Docker can cache this layer
COPY package*.json ./
#clean install (faster + reproducible, perfect for Docker)
RUN npm ci
# Now copy the rest of your code
COPY . .
# Runs next build → creates the optimized .next folder + standalone server
RUN npm run build

# Prune dev dependencies
FROM node:22-alpine AS pruner
WORKDIR /app
COPY --from=builder /app ./
RUN npm ci --omit=dev &amp;amp;&amp;amp; npm cache clean --force

# Final tiny image
FROM node:22-alpine AS runtime
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=pruner --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=pruner --chown=nextjs:nodejs /app/package.json ./
COPY --from=pruner --chown=nextjs:nodejs /app/public ./public
COPY --from=pruner --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=pruner --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget -qO- http://localhost:3000/api/health || exit 1

CMD ["node", "server.js"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Magic Line You Must Add (next.config.js)&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;/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone', // This makes Next.js create server.js
};

module.exports = nextConfig;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tiny Health Check (app/api/health/route.ts)&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;import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ 
    status: 'ok', 
    timestamp: new Date().toISOString() 
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;.dockerignore (Speeds Up Builds 5x)&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;node_modules
.next
.env*.local
.git
.gitignore
README.md
Dockerfile
docker-compose*.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Build &amp;amp; Run It (The Moment of Truth)&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;docker build -t nextjs-prod .
docker run -d -p 3000:3000 --name prod nextjs-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3000&lt;/code&gt; → It just works.&lt;br&gt;
Check image size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker images nextjs-prod
# → ~84 MB (vs 1 GB+ the "wrong" way)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Removing Container and Image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker rm -f nextjs-prod 
docker rm -f nextjs-prod-app

docker rmi nextjs-prod 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;docker-compose.yml (new file in root)-Two services explained&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;services:
nextjs-dev:                     # ← Development container
    build: .                      # Use the same Dockerfile
    ports:
      - "3000:3000"               # Host port 3000 → container port 3000
    environment:
      NODE_ENV: development       # Enables hot reload
    volumes:
      - .:/app                    # Your code changes instantly appear inside container
      - /app/node_modules         # Don’t let host node_modules override container ones
      - /app/.next                # Keep build cache on host (faster restarts)
    command: npm run dev          # Override CMD from Dockerfile

  nextjs-prod:                    # ← Real production preview
    build: .
    ports:
      - "3001:3000"               # Different host port so you can run both at once
    environment:
      NODE_ENV: production
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"]
      interval: 30s
      timeout: 10s
      retries: 3


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

&lt;/div&gt;



&lt;p&gt;Now run in your terminal (PowerShell or cmd):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see it build and start on &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; with hot reload.&lt;br&gt;
Then open a second terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up --build nextjs-prod
docker compose up --build nextjs-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if you want both at the same time in one terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up nextjs-dev nextjs-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;→ &lt;a href="http://localhost:3001" rel="noopener noreferrer"&gt;http://localhost:3001&lt;/a&gt; will show the real production version (super fast and tiny image ~90MB).&lt;/p&gt;

&lt;p&gt;A common super common on Windows with WSL2 + Docker Desktop when it’s still configured to use Linux containers but somehow tries to pull a Windows image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;no matching manifest for windows/amd64 10.0.26100 in the manifest list entries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right-click the Docker Desktop whale icon in your system tray → make sure it says “Linux containers” (not “Windows containers”).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DesktopLinuxEngine: The system cannot find the file specified.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This error means Docker Desktop’s Linux engine is not running right now (it probably stopped or crashed after the long prod build).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look at your system tray (bottom-right near the clock)&lt;/li&gt;
&lt;li&gt;Find the Docker whale icon&lt;/li&gt;
&lt;li&gt;If it’s gray or has a red dot → Docker is stopped&lt;/li&gt;
&lt;li&gt;Just double-click the whale icon → Docker Desktop will restart automatically&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Rebuild and run&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;# Remove old broken images
docker compose down --rmi all

# Build &amp;amp; start dev (this time it WILL have the next binary)
docker compose up --build nextjs-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stop / Start only the dev container&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;# Stop dev only
docker compose stop nextjs-dev

# Start dev again (instant, no rebuild)
docker compose start nextjs-dev

# Or restart dev in one command
docker compose restart nextjs-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stop BOTH at once&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;docker compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When hot-reload feels weird or .next is corrupted&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;docker compose down -v
docker compose up nextjs-dev          # fresh .next cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When you changed Dockerfile or node_modules&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;docker compose down --rmi all
docker compose up --build nextjs-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When your PC is crying for disk space&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;docker system prune -a               # frees gigabytes in 10 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Start BOTH at once&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;docker compose up
# or in background (like a real server)
docker compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Rebuild + start only one&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;docker compose up --build nextjs-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;List running containers&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;docker compose ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;stops + removes containers + removes YOUR volumes&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;docker compose down -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Delete ALL volumes created by this docker-compose file (100% safe)&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;docker compose down --volumes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Volumes from other projects&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;docker volume ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** See logs (super useful!)**&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker logs nextjs-dev -f          # -f = follow live
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tag an existing image with multiple tags&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;docker tag nextjs-docker-app-nextjs-prod username/nextjs-docker-app:latest
docker tag nextjs-docker-app-nextjs-prod username/nextjs-docker-app:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;See all your local images + their tags&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;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Folder Structure&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-nextjs-app/
├── .dockerignore
├── .gitignore
├── Dockerfile
├── docker-compose.yml
├── next.config.js
├── package.json
├── app/
│   └── api/health/route.ts
└── public/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you have a perfect Docker setup, here are the real-world ways to share the exact same image with your team (or with CI/CD, hosting, etc.):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Push to Docker Hub&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;# 1. Log in to Docker Hub (create account at `hub.docker.com` if you don't have one)
docker login

# 2. Tag your prod image with your username
docker tag nextjs-docker-app-nextjs-prod username/nextjs-docker-app:latest

# 3. Push it
docker push username/nextjs-docker-app:latest

# Then your entire team (or any server in the world) can start your exact production app in 5 seconds with:

docker run -d -p 3000:3000 username/nextjs-docker-app:latest

# Only download the image (no container starts)
docker pull username/nextjs-docker-app:latest

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;You just graduated from “Docker curious” to “Docker professional” in under an hour.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’ve personally used this exact setup on every new Next.js projects.&lt;br&gt;
If this guide saves even one hour of your life, drop a comment below and tell me how it went — I read every single one.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>docker</category>
    </item>
    <item>
      <title>Technical SEO for Developers: A Comprehensive Guide to Building Search-Friendly Applications</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Sun, 16 Nov 2025 13:40:54 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-4d87</link>
      <guid>https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-4d87</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-36pn" class="crayons-story__hidden-navigation-link"&gt;Technical SEO for Developers: A Comprehensive Guide to Building Search-Friendly Applications&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/mina_golzari_dalir" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" alt="mina_golzari_dalir profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mina_golzari_dalir" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mina Golzari Dalir
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mina Golzari Dalir
                
              
              &lt;div id="story-author-preview-content-3028177" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mina_golzari_dalir" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mina Golzari Dalir&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-36pn" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 16 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-36pn" id="article-link-3028177"&gt;
          Technical SEO for Developers: A Comprehensive Guide to Building Search-Friendly Applications
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/technicalseo"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;technicalseo&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/seo"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;seo&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nextjs"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nextjs&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-36pn" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;4&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-36pn#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              2&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




</description>
      <category>technicalseo</category>
      <category>seo</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Technical SEO for Developers: A Comprehensive Guide to Building Search-Friendly Applications</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Sun, 16 Nov 2025 13:39:38 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-36pn</link>
      <guid>https://dev.to/mina_golzari_dalir/technical-seo-for-developers-a-comprehensive-guide-to-building-search-friendly-applications-36pn</guid>
      <description>&lt;p&gt;As developers, we often focus on writing clean code and optimizing performance, but one critical aspect that's frequently overlooked is technical SEO. In this article, using a real-world plastic injection factory example, we'll explore how you can implement SEO at the code level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Technical SEO Matters&lt;/strong&gt;&lt;br&gt;
Technical SEO forms the foundation of any successful SEO strategy. Even if you create the best content in the world, without proper technical structure, search engines cannot properly index and understand it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Business Impact&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;60% of organic clicks go to the first three results&lt;/li&gt;
&lt;li&gt;    53% of website traffic comes from organic search&lt;/li&gt;
&lt;li&gt;    Proper technical SEO can increase conversion rates by 30%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-World Code Analysis: Plastic Injection Factory Example&lt;/strong&gt;&lt;br&gt;
Let's break down the provided metadata code and extract valuable SEO lessons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const metadata: Metadata = {
  // Strategic title tag
  title: "Products &amp;amp; Services | Plastic Injection Factory",
  description: "Comprehensive plastic injection services • Precision mold making • Plastic parts manufacturing for automotive, medical, electronics, and consumer goods industries • Guaranteed quality",

  // Targeted keywords (though less important for Google, still valuable)
  keywords: "plastic injection products, mold services, automotive plastic parts, medical plastic components, electronic parts manufacturing, industrial mold making, Hamedan plastic injection",

  // Authority and ownership signals
  authors: [{ name: "Plastic Injection Factory" }],
  creator: "Plastic Injection Factory",
  publisher: "Plastic Injection Factory",

  // Crawler instructions
  robots: "index, follow, max-image-preview:large",

  // URL management
  metadataBase: new URL('https://hamedan-plastic-injection.ir'),
  alternates: {
    canonical: 'https://hamedan-plastic-injection.ir/products',
  },

  // Social media optimization
  openGraph: {
    title: "Products &amp;amp; Services | Plastic Injection Factory",
    description: "Comprehensive plastic injection services • Precision mold making • Custom plastic parts for various industries",
    images: [
      {
        url: '/og-products.jpg',
        width: 1200,
        height: 630,
        alt: 'Products and Services - Plastic Injection Factory',
      },
    ],
    locale: 'fa_IR', // Crucial for local SEO
    type: 'website',
  },

  // Twitter-specific optimization
  twitter: {
    card: 'summary_large_image',
    title: "Products &amp;amp; Services | Plastic Injection Factory",
    description: "Comprehensive plastic injection services • Precision mold making • Custom plastic parts",
    images: ['/og-products.jpg'],
  },
};

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common Developer SEO Mistakes to Avoid&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ignoring URL Structure
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ❌ Poor SEO practice
/products?id=123&amp;amp;category=plastic

// ✅ SEO-friendly approach
/products/plastic-injection-molds

// ✅ Even better with hierarchy
/services/plastic-injection/automotive-parts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Forgetting Canonical Tags&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;// Always set canonical URLs to prevent duplicate content
alternates: {
  canonical: 'https://example.com/correct-url',
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Neglecting Image Optimization&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;images: [
  {
    url: '/og-image.jpg',
    width: 1200,    // Specify dimensions
    height: 630,    // Specify dimensions
    alt: 'Meaningful image description', // Descriptive alt text
  },
],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Overlooking International SEO&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;// For multilingual sites
alternates: {
  languages: {
    'en': 'https://example.com/en/products',
    'fa': 'https://example.com/fa/products',
    'de': 'https://example.com/de/products',
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SEO-Friendly Coding Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Semantic HTML Implementation&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;// ❌ Poor semantics
&amp;lt;div onClick={handleClick}&amp;gt;Products&amp;lt;/div&amp;gt;

// ✅ SEO-friendly
&amp;lt;button onClick={handleClick} aria-label="Browse our products"&amp;gt;
  Products
&amp;lt;/button&amp;gt;

// ✅ Even better with proper heading structure
&amp;lt;section&amp;gt;
  &amp;lt;h2&amp;gt;Our Manufacturing Services&amp;lt;/h2&amp;gt;
  &amp;lt;button onClick={handleClick}&amp;gt;Explore Products&amp;lt;/button&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Structured Data Implementation&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;// JSON-LD for rich snippets
const productSchema = {
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Plastic Injection Mold",
  "description": "High-precision plastic injection mold for automotive industry",
  "brand": {
    "@type": "Brand",
    "name": "Plastic Injection"
  },
  "offers": {
    "@type": "Offer",
    "availability": "https://schema.org/InStock",
    "priceCurrency": "USD",
    "price": "2500"
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Performance Optimization for SEO&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;// Next.js example with ISR for better SEO
export const dynamic = 'auto';
export const dynamicParams = true;
export const revalidate = 3600; // Incremental Static Regeneration

// Image optimization
import Image from 'next/image';

&amp;lt;Image
  src="/manufacturing-process.jpg"
  alt="Plastic injection manufacturing process"
  width={800}
  height={600}
  priority={true} // For above-the-fold images
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;International SEO Considerations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local SEO Implementation&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;openGraph: {
  locale: 'en_US', // Important for geographic targeting
  siteName: 'Plastic Injection Factory',
  // ...
},

// For multi-regional targeting
metadataBase: new URL('https://hamedan-plastic-injection.ir'),
alternates: {
  canonical: 'https://hamedan-plastic-injection.ir/en/products',
  languages: {
    'en': 'https://hamedan-plastic-injection.ir/en/products',
    'fa': 'https://hamedan-plastic-injection.ir/fa/products',
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Essential SEO Tools for Developers&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Validation Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Google Rich Results Test - Structured data validation&lt;/li&gt;
&lt;li&gt;    Schema Markup Validator - Schema.org testing&lt;/li&gt;
&lt;li&gt;    Lighthouse SEO Audit - Comprehensive SEO auditing&lt;/li&gt;
&lt;li&gt;    Google Search Console - Performance monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Development &amp;amp; Monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Screaming Frog SEO Spider - Technical SEO auditing&lt;/li&gt;
&lt;li&gt;    Ahrefs Site Audit - Comprehensive SEO analysis&lt;/li&gt;
&lt;li&gt;    PageSpeed Insights - Performance monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Metrics to Track&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;// SEO metrics monitoring structure
const seoMetrics = {
  coreWebVitals: {
    lcp: '2.5s',    // Largest Contentful Paint (target: &amp;lt;2.5s)
    fid: '100ms',   // First Input Delay (target: &amp;lt;100ms)
    cls: '0.1',     // Cumulative Layout Shift (target: &amp;lt;0.1)
  },
  crawlability: {
    indexedPages: 150,
    crawlErrors: 0,
    robotsTxt: 'valid',
    sitemapStatus: 'healthy',
  },
  performance: {
    pageSpeed: 85,
    timeToInteractive: '3.2s',
    firstContentfulPaint: '1.8s',
  },
  businessMetrics: {
    organicTraffic: '45%',
    conversionRate: '3.2%',
    bounceRate: '42%',
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Actionable Checklist for Development Teams&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-Launch SEO Checklist&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Semantic HTML structure implemented&lt;/li&gt;
&lt;li&gt;    All images have descriptive alt text&lt;/li&gt;
&lt;li&gt;    XML sitemap generated and submitted&lt;/li&gt;
&lt;li&gt;    robots.txt properly configured&lt;/li&gt;
&lt;li&gt;    Canonical tags set for all pages&lt;/li&gt;
&lt;li&gt;    Structured data implemented&lt;/li&gt;
&lt;li&gt;    Page speed optimized (LCP &amp;lt; 2.5s)&lt;/li&gt;
&lt;li&gt;    Mobile-responsive design tested&lt;/li&gt;
&lt;li&gt;    SSL certificate installed&lt;/li&gt;
&lt;li&gt;    404 pages customized&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ongoing SEO Maintenance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Regular performance monitoring&lt;/li&gt;
&lt;li&gt;    Broken link checks&lt;/li&gt;
&lt;li&gt;    Schema markup validation&lt;/li&gt;
&lt;li&gt;    Core Web Vitals tracking&lt;/li&gt;
&lt;li&gt;    Search Console error monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Advanced Technical SEO Techniques&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Dynamic Rendering for JavaScript-Heavy Apps&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;// For SPAs that need SEO support
// Use server-side rendering or dynamic rendering
export async function getServerSideProps(context) {
  // Fetch data for SEO
  const productData = await fetchProductData(context.params.id);

  return {
    props: {
      product: productData,
      seo: {
        title: productData.seoTitle,
        description: productData.seoDescription,
        canonical: `https://example.com/products/${productData.slug}`
      }
    }
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. API Route for Dynamic Sitemaps&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;// pages/api/sitemap.xml.js
export default function handler(req, res) {
  const sitemap = generateSitemap();
  res.setHeader('Content-Type', 'text/xml');
  res.write(sitemap);
  res.end();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pro Tips for Development Teams&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; SEO-First Development - Integrate SEO requirements from sprint planning&lt;/li&gt;
&lt;li&gt;    Collaborate with Content Teams - Align on keywords and URL structures&lt;/li&gt;
&lt;li&gt;    Performance as Priority - Fast sites rank better and convert better&lt;/li&gt;
&lt;li&gt;    Mobile-First Mindset - Over 60% of searches happen on mobile&lt;/li&gt;
&lt;li&gt;    Structured Data Foundation - Implement schema.org from the beginning&lt;/li&gt;
&lt;li&gt;    International from Day One - Plan for global expansion from the start&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Technical SEO is a long-term investment that should be at the core of your development process. By implementing these practices, you'll not only achieve better search rankings but also provide a superior user experience.&lt;/p&gt;

</description>
      <category>technicalseo</category>
      <category>seo</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Ultimate Guide to Becoming a Full-Stack Developer</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Sat, 15 Nov 2025 11:32:49 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/the-ultimate-guide-to-becoming-a-full-stack-developer-4p6e</link>
      <guid>https://dev.to/mina_golzari_dalir/the-ultimate-guide-to-becoming-a-full-stack-developer-4p6e</guid>
      <description>&lt;p&gt;Full-stack development is a dynamic career that combines backend logic, data persistence, frontend design, and user experience. By mastering ASP.NET Core for robust APIs, Entity Framework Core (EF Core) for seamless data access, ReactJS for dynamic interfaces, SQL for database optimization, and Figma for prototyping, you can build end-to-end solutions that power modern applications. This guide covers the responsibilities, project structure, roadmap, professional tips, and challenges of becoming a full-stack developer, equipping you to excel in this high-demand field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Does a Full-Stack Developer Do?&lt;/strong&gt;&lt;br&gt;
A full-stack developer delivers complete applications by working across the tech stack. Here’s a breakdown of responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    &lt;strong&gt;Backend (ASP.NET Core)&lt;/strong&gt;: Build scalable RESTful APIs to handle business logic, authentication, and data processing. For example, creating endpoints for a task management system to manage tasks.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Data Access (EF Core)&lt;/strong&gt;: Use EF Core to interact with databases, mapping objects to relational data and optimizing queries for performance.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Database (SQL)&lt;/strong&gt;: Design schemas and write efficient SQL queries for data retrieval and analytics, ensuring scalability with indexing and partitioning.&lt;/li&gt;
&lt;li&gt;   ** Frontend (ReactJS)**: Develop responsive, interactive UIs using ReactJS and tools like Next.js, leveraging state management and React 18 features for performance.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;UI/UX (Figma)&lt;/strong&gt;: Prototype interfaces and collaborate with stakeholders to align designs with user needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Impact on Projects&lt;/strong&gt;: Full-stack developers drive measurable outcomes. In a task management app, you might reduce API latency by 20% with ASP.NET Core, cut query times by 30% with EF Core optimizations, improve UI load times by 15% with React, and boost user satisfaction by 10% through Figma-driven design iterations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structuring a Full-Stack Project&lt;/strong&gt;&lt;br&gt;
A well-organized project ensures scalability, maintainability, and team collaboration. Below is a recommended structure for a task management app, emphasizing EF Core for data access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Backend Structure (ASP.NET Core + EF Core)&lt;/strong&gt;&lt;br&gt;
Adopt **clean architecture **to separate concerns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TaskManagementApp/
├── src/
│   ├── Core/                  # Entities, Interfaces
│   ├── Infrastructure/        # EF Core DbContext, Repositories
│   ├── Application/           # Business logic, Services, DTOs
│   ├── Api/                   # Controllers, Middleware
├── tests/                     # Unit and integration tests
├── TaskManagement.Frontend/   # ReactJS/Next.js frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Core Layer (Entities)&lt;/strong&gt;&lt;br&gt;
Define the Task entity for the task management system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Core/Entities/Task.cs
namespace TaskManagement.Core.Entities
{
    public class Task
    {
        public int Id { get; set; }
        public string Title { get; set; } = string.Empty;
        public string? Description { get; set; }
        public bool IsCompleted { get; set; }
        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Infrastructure Layer (EF Core)&lt;/strong&gt;&lt;br&gt;
Configure EF Core for SQL Server and define the DbContext.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Infrastructure/Data/TaskDbContext.cs
using Microsoft.EntityFrameworkCore;
using TaskManagement.Core.Entities;

namespace TaskManagement.Infrastructure.Data
{
    public class TaskDbContext : DbContext
    {
        public TaskDbContext(DbContextOptions&amp;lt;TaskDbContext&amp;gt; options) : base(options) { }
        public DbSet&amp;lt;Task&amp;gt; Tasks { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity&amp;lt;Task&amp;gt;()
                .Property(t =&amp;gt; t.Title)
                .IsRequired()
                .HasMaxLength(100);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a repository for data access to keep the code clean.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Infrastructure/Repositories/TaskRepository.cs
using TaskManagement.Core.Entities;
using TaskManagement.Infrastructure.Data;
using TaskManagement.Application.Interfaces;

namespace TaskManagement.Infrastructure.Repositories
{
    public class TaskRepository : ITaskRepository
    {
        private readonly TaskDbContext _context;

        public TaskRepository(TaskDbContext context)
        {
            _context = context;
        }

        public async Task&amp;lt;List&amp;lt;Task&amp;gt;&amp;gt; GetAllAsync()
        {
            return await _context.Tasks.ToListAsync();
        }

        public async Task&amp;lt;Task?&amp;gt; GetByIdAsync(int id)
        {
            return await _context.Tasks.FindAsync(id);
        }

        public async Task AddAsync(Task task)
        {
            await _context.Tasks.AddAsync(task);
            await _context.SaveChangesAsync();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Application Layer (Services, DTOs)&lt;/strong&gt;&lt;br&gt;
Define a service to handle business logic and a DTO for API responses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Application/Interfaces/ITaskService.cs
using TaskManagement.Core.Entities;

namespace TaskManagement.Application.Interfaces
{
    public interface ITaskService
    {
        Task&amp;lt;List&amp;lt;Task&amp;gt;&amp;gt; GetAllTasksAsync();
        Task&amp;lt;Task?&amp;gt; GetTaskByIdAsync(int id);
        Task CreateTaskAsync(Task task);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Application/DTOs/TaskDto.cs
namespace TaskManagement.Application.DTOs
{
    public class TaskDto
    {
        public int Id { get; set; }
        public string Title { get; set; } = string.Empty;
        public string? Description { get; set; }
        public bool IsCompleted { get; set; }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Application/Services/TaskService.cs
using TaskManagement.Core.Entities;
using TaskManagement.Application.Interfaces;
using TaskManagement.Application.DTOs;

namespace TaskManagement.Application.Services
{
    public class TaskService : ITaskService
    {
        private readonly ITaskRepository _repository;

        public TaskService(ITaskRepository repository)
        {
            _repository = repository;
        }

        public async Task&amp;lt;List&amp;lt;Task&amp;gt;&amp;gt; GetAllTasksAsync()
        {
            return await _repository.GetAllAsync();
        }

        public async Task&amp;lt;Task?&amp;gt; GetTaskByIdAsync(int id)
        {
            return await _repository.GetByIdAsync(id);
        }

        public async Task CreateTaskAsync(Task task)
        {
            if (string.IsNullOrEmpty(task.Title))
                throw new ArgumentException("Title is required.");
            await _repository.AddAsync(task);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;API Layer (Controller)&lt;/strong&gt;&lt;br&gt;
Expose REST endpoints using ASP.NET Core.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Api/Controllers/TasksController.cs
using Microsoft.AspNetCore.Mvc;
using TaskManagement.Application.Interfaces;
using TaskManagement.Application.DTOs;
using TaskManagement.Core.Entities;

namespace TaskManagement.Api.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TasksController : ControllerBase
    {
        private readonly ITaskService _taskService;

        public TasksController(ITaskService taskService)
        {
            _taskService = taskService;
        }

        [HttpGet]
        public async Task&amp;lt;ActionResult&amp;lt;IEnumerable&amp;lt;Task&amp;gt;&amp;gt;&amp;gt; GetTasks()
        {
            return Ok(await _taskService.GetAllTasksAsync());
        }

        [HttpGet("{id}")]
        public async Task&amp;lt;ActionResult&amp;lt;Task&amp;gt;&amp;gt; GetTask(int id)
        {
            var task = await _taskService.GetTaskByIdAsync(id);
            if (task == null) return NotFound();
            return Ok(task);
        }

        [HttpPost]
        public async Task&amp;lt;ActionResult&amp;gt; CreateTask(TaskDto taskDto)
        {
            var task = new Task { Title = taskDto.Title, Description = taskDto.Description, IsCompleted = taskDto.IsCompleted };
            await _taskService.CreateTaskAsync(task);
            return CreatedAtAction(nameof(GetTask), new { id = task.Id }, task);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Program.cs (Dependency Injection and EF Core Setup)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Api/Program.cs
using Microsoft.EntityFrameworkCore;
using TaskManagement.Infrastructure.Data;
using TaskManagement.Infrastructure.Repositories;
using TaskManagement.Application.Interfaces;
using TaskManagement.Application.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddDbContext&amp;lt;TaskDbContext&amp;gt;(options =&amp;gt;
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped&amp;lt;ITaskRepository, TaskRepository&amp;gt;();
builder.Services.AddScoped&amp;lt;ITaskService, TaskService&amp;gt;();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add to appsettings.json:&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;{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=TaskDb;Trusted_Connection=True;TrustServerCertificate=True;"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run migrations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet ef migrations add InitialCreate
dotnet ef database update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Database (SQL Server)&lt;/strong&gt;&lt;br&gt;
Design a simple schema with indexing for performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE Tasks (
    Id INT PRIMARY KEY IDENTITY(1,1),
    Title NVARCHAR(100) NOT NULL,
    Description NVARCHAR(MAX),
    IsCompleted BIT NOT NULL DEFAULT 0,
    CreatedAt DATETIME2 NOT NULL
);
CREATE INDEX idx_tasks_id ON Tasks(Id);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Frontend Structure (ReactJS/Next.js)&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;
TaskManagement.Frontend/
├── components/    # Reusable components (e.g., TaskCard)
├── pages/         # Next.js pages (e.g., /dashboard)
├── hooks/         # Custom hooks
├── styles/        # Tailwind CSS
├── lib/           # API calls

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

&lt;/div&gt;



&lt;p&gt;Sample Component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// components/TaskCard.jsx
import { useState } from 'react';

const TaskCard = ({ task, onUpdate }) =&amp;gt; {
  const [isCompleted, setIsCompleted] = useState(task.isCompleted);

  const handleToggle = async () =&amp;gt; {
    await fetch(`/api/tasks/${task.id}`, {
      method: 'PUT',
      body: JSON.stringify({ ...task, isCompleted: !isCompleted }),
      headers: { 'Content-Type': 'application/json' },
    });
    setIsCompleted(!isCompleted);
    onUpdate();
  };

  return (
    &amp;lt;div className="p-4 border rounded shadow"&amp;gt;
      &amp;lt;h3&amp;gt;{task.title}&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;{task.description}&amp;lt;/p&amp;gt;
      &amp;lt;input type="checkbox" checked={isCompleted} onChange={handleToggle} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default TaskCard;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Figma Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   &lt;strong&gt;Wireframes&lt;/strong&gt;: Create low-fidelity layouts for task lists and dashboards.&lt;/li&gt;
&lt;li&gt;   ** Prototypes**: Build high-fidelity, interactive designs for stakeholder feedback.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Design System&lt;/strong&gt;: Define reusable components (e.g., buttons, cards) for UI consistency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This structure ensures modularity. For example, adding a “Task Categories” feature requires minimal changes due to the decoupled layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Roadmap to Becoming a Full-Stack Developer&lt;/strong&gt;&lt;br&gt;
Follow this 12–18 month roadmap to master the stack:&lt;br&gt;
&lt;strong&gt;Months 1–3: Foundations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learn C# and ASP.NET Core&lt;/strong&gt;: Study MVC, REST APIs, and dependency injection (Microsoft Learn).&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Master EF Core&lt;/strong&gt;: Learn migrations, LINQ queries, and repository patterns (EF Core docs).&lt;/li&gt;
&lt;li&gt;   ** Understand SQL**: Practice schema design, joins, and indexing (SQLShack tutorials).&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Learn ReactJS&lt;/strong&gt;: Focus on components, hooks, and state management (React.dev).&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Explore Figma&lt;/strong&gt;: Create basic wireframes and learn design principles (Figma Community tutorials).&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Project&lt;/strong&gt;: Build a simple CRUD app (e.g., to-do list) with ASP.NET Core, EF Core, and React.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Months 4–8: Intermediate Skills&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    &lt;strong&gt;ASP.NET Core&lt;/strong&gt;: Build microservices-ready APIs with clean architecture.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;EF Core&lt;/strong&gt;: Optimize queries with indexing and eager/lazy loading.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;SQL&lt;/strong&gt;: Write complex queries (e.g., window functions) and design data warehouses.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;ReactJS&lt;/strong&gt;: Learn Next.js for SSR and Zustand for state management.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Figma&lt;/strong&gt;: Create interactive prototypes and collaborate with teams.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Project&lt;/strong&gt;: Develop a task management app with real-time updates (e.g., SignalR) and deploy to Azure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Months 9–12: Advanced Skills&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    &lt;strong&gt;ASP.NET Core + EF Core&lt;/strong&gt;: Implement authentication (JWT) and containerize with Docker.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;SQL&lt;/strong&gt;: Optimize for big data with partitioning and sharding.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;ReactJS&lt;/strong&gt;: Use React 18’s Concurrent Rendering and Server Components.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Figma&lt;/strong&gt;: Build a design system for scalable UI development.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Project&lt;/strong&gt;: Create a production-ready app with CI/CD pipelines and share on GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Months 13–18: Specialization and Leadership&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Contribute to open-source&lt;/strong&gt;: Add features to ASP.NET Core or React projects.&lt;/li&gt;
&lt;li&gt;   ** Write tutorials**: Publish on Medium to establish thought leadership.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Lead projects&lt;/strong&gt;: Mentor juniors and drive end-to-end delivery.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Portfolio&lt;/strong&gt;: Showcase 3–5 projects with measurable impact (e.g., “Reduced API latency by 20%”).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Professional Tips&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;    Write Clean Code: Follow SOLID principles and use tools like SonarQube for code quality.&lt;/li&gt;
&lt;li&gt;    Optimize Performance: Use EF Core’s query profiling and React’s useMemo to boost efficiency.&lt;/li&gt;
&lt;li&gt;    Leverage Cloud Tools: Deploy to Azure or AWS for scalability. Use Azure DevOps for CI/CD.&lt;/li&gt;
&lt;li&gt;    Document Everything: Maintain clear API docs (Swagger) and Figma handoff notes.&lt;/li&gt;
&lt;li&gt;    Engage with Communities: Share projects on X, Reddit (r/dotnet, r/reactjs), and Dev.to to gain visibility.&lt;/li&gt;
&lt;li&gt;    Test Rigorously: Write unit tests for ASP.NET Core services and React components using xUnit and Jest.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Challenges and Solutions&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Challenge&lt;/strong&gt;: Managing EF Core performance with large datasets.&lt;br&gt;
    &lt;strong&gt;Solution&lt;/strong&gt;: Use indexing, eager loading, and query splitting. Profile queries with EF Core’s logging&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Coordinating backend and frontend state in React.&lt;br&gt;
    &lt;strong&gt;Solution&lt;/strong&gt;: Use Zustand or Redux Toolkit for predictable state management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Aligning Figma designs with coded UIs.&lt;br&gt;
    &lt;strong&gt;Solution&lt;/strong&gt;: Use Figma’s Dev Mode and CSS frameworks like Tailwind for consistency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Balancing multiple roles in tight deadlines.&lt;br&gt;
    &lt;strong&gt;Solution&lt;/strong&gt;: Prioritize tasks with Agile methodologies and automate repetitive tasks (e.g., CI/CD).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Keeping up with tech updates (e.g., ASP.NET Core 8.0, React 18).&lt;br&gt;
    &lt;strong&gt;Solution&lt;/strong&gt;: Follow blogs (e.g., Microsoft Learn, React.dev) and experiment with new features in side projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Essential and Helpful Soft Skills&lt;/strong&gt;&lt;br&gt;
Essential Soft Skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    &lt;strong&gt;Communication&lt;/strong&gt;: Explain technical concepts to non-technical stakeholders, e.g., presenting Figma prototypes in sprint reviews.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Problem-Solving&lt;/strong&gt;: Debug EF Core query issues or React rendering bugs efficiently.&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;Adaptability&lt;/strong&gt;: Switch between backend, frontend, and design tasks seamlessly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Helpful Soft Skills:&lt;br&gt;
    &lt;strong&gt;Empathy&lt;/strong&gt;: Understand user needs to design intuitive UIs in Figma.&lt;br&gt;
    &lt;strong&gt;Time Management&lt;/strong&gt;: Balance coding, designing, and testing under tight deadlines.&lt;br&gt;
    &lt;strong&gt;Leadership&lt;/strong&gt;: Guide teams through code reviews and mentor juniors.&lt;/p&gt;

&lt;p&gt;These skills enhance teamwork. For example, clear communication ensures alignment on project goals, while empathy improves UI usability, leading to better user feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Becoming a full-stack developer with ASP.NET Core, EF Core, ReactJS, SQL, and Figma is a journey of technical mastery and collaboration. By following the roadmap, structuring projects effectively, and honing soft skills, you can build impactful applications — like a task management app that boosts team productivity. Start small, iterate often, and share your work on platforms like Medium or X to inspire others. The future of full-stack development is yours to shape — get coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>aspnet</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Thu, 13 Nov 2025 10:05:36 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/-20m1</link>
      <guid>https://dev.to/mina_golzari_dalir/-20m1</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/mina_golzari_dalir" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" alt="mina_golzari_dalir"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/mina_golzari_dalir/build-a-modern-contact-us-page-with-nextjs-tailwind-css-component-based-seo-ready-3jc3" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Build a Modern Contact Us Page with Next.js + Tailwind CSS (Component-Based + SEO-Ready)&lt;/h2&gt;
      &lt;h3&gt;Mina Golzari Dalir ・ Nov 8&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#tailwindcss&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#component&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#seo&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>tailwindcss</category>
      <category>component</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A well-structured contact page is a must-have for any website. In this tutorial we’ll:</title>
      <dc:creator>Mina Golzari Dalir</dc:creator>
      <pubDate>Sat, 08 Nov 2025 13:29:30 +0000</pubDate>
      <link>https://dev.to/mina_golzari_dalir/-27i9</link>
      <guid>https://dev.to/mina_golzari_dalir/-27i9</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/mina_golzari_dalir" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F3584428%2F6df38dce-0d67-4823-8833-9b9a5e1f7369.png" alt="mina_golzari_dalir"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/mina_golzari_dalir/build-a-modern-contact-us-page-with-nextjs-tailwind-css-component-based-seo-ready-3jc3" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Build a Modern Contact Us Page with Next.js + Tailwind CSS (Component-Based + SEO-Ready)&lt;/h2&gt;
      &lt;h3&gt;Mina Golzari Dalir ・ Nov 8&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#tailwindcss&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#component&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#seo&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>tailwindcss</category>
      <category>component</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
