<?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: Khashayar Nourian</title>
    <description>The latest articles on DEV Community by Khashayar Nourian (@knourian).</description>
    <link>https://dev.to/knourian</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%2F3176094%2F30886680-a94a-45d8-a8ba-b17e07549877.jpeg</url>
      <title>DEV Community: Khashayar Nourian</title>
      <link>https://dev.to/knourian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/knourian"/>
    <language>en</language>
    <item>
      <title>CQRS with a separate read store: useful projections, new guarantees</title>
      <dc:creator>Khashayar Nourian</dc:creator>
      <pubDate>Mon, 07 Sep 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/knourian/cqrs-with-a-separate-read-store-useful-projections-new-guarantees-5b6k</link>
      <guid>https://dev.to/knourian/cqrs-with-a-separate-read-store-useful-projections-new-guarantees-5b6k</guid>
      <description>&lt;p&gt;A separate read store is not the next mandatory CQRS step. It is useful when a screen, report, or read workload needs a shape that the transactional write model should not own.&lt;/p&gt;

&lt;p&gt;For an order-tracking screen, a projection can keep one denormalized row with an order number, customer name, status, last-updated time, and total. That can remove repeated joins and let read traffic scale separately from command handling.&lt;/p&gt;

&lt;p&gt;The trade-off is visible behavior. A command can commit before the projection updates, so the next read can be stale. Treat the write side as authoritative, make projections rebuildable, and state what the user should expect after a successful command. If a shared database and direct projection already work, keep them.&lt;/p&gt;

</description>
      <category>engineering</category>
      <category>architecture</category>
      <category>cqrs</category>
    </item>
    <item>
      <title>Minimal CQRS: separate code paths, keep one application and one database</title>
      <dc:creator>Khashayar Nourian</dc:creator>
      <pubDate>Thu, 03 Sep 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/knourian/minimal-cqrs-separate-code-paths-keep-one-application-and-one-database-kf1</link>
      <guid>https://dev.to/knourian/minimal-cqrs-separate-code-paths-keep-one-application-and-one-database-kf1</guid>
      <description>&lt;p&gt;CQRS does not have to begin with a second database, a queue, or a separate service.&lt;/p&gt;

&lt;p&gt;A useful first step is much smaller: keep one application and one database, but give commands and queries separate code paths. A command such as &lt;code&gt;PlaceOrder&lt;/code&gt; loads the state it needs, checks business rules, and commits a change. A query such as &lt;code&gt;GetOrderSummary&lt;/code&gt; can project exactly the fields a screen needs without rebuilding a domain aggregate.&lt;/p&gt;

&lt;p&gt;The database is shared. The responsibilities are not.&lt;/p&gt;

&lt;p&gt;This keeps transactions, immediate reads after a successful command, and a simple deployment model. It does not create independent read scaling or reporting projections for free. Those are later decisions, not a starting requirement.&lt;/p&gt;

</description>
      <category>engineering</category>
      <category>architecture</category>
      <category>cqrs</category>
    </item>
    <item>
      <title>CQS and commands: make the application understand intent</title>
      <dc:creator>Khashayar Nourian</dc:creator>
      <pubDate>Wed, 26 Aug 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/knourian/cqs-and-commands-make-the-application-understand-intent-4hp3</link>
      <guid>https://dev.to/knourian/cqs-and-commands-make-the-application-understand-intent-4hp3</guid>
      <description>&lt;p&gt;&lt;code&gt;SetStatus(itemId, Deactivated)&lt;/code&gt; tells an application what a field should contain. &lt;code&gt;DeactivateInventoryItem(itemId, reason)&lt;/code&gt; tells it what the user wants to do.&lt;/p&gt;

&lt;p&gt;That difference matters when the action has rules. A deactivation may require a reason, permission, a valid state transition, and a transaction that saves the result. With a behavior-focused command, those concerns have one natural home instead of being inferred from changed fields or scattered between the UI and a generic update handler.&lt;/p&gt;

&lt;p&gt;The UI can still help by explaining obvious failures early. It cannot be the final authority because another client, a retry, or a concurrent request can reach the same operation.&lt;/p&gt;

&lt;p&gt;A command is also not an event. A command asks for work and may be rejected. An event describes something that already happened after the command succeeded.&lt;/p&gt;

</description>
      <category>engineering</category>
      <category>architecture</category>
      <category>cqrs</category>
      <category>cqs</category>
    </item>
    <item>
      <title>When CRUD stops describing the work</title>
      <dc:creator>Khashayar Nourian</dc:creator>
      <pubDate>Mon, 24 Aug 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/knourian/when-crud-stops-describing-the-work-479</link>
      <guid>https://dev.to/knourian/when-crud-stops-describing-the-work-479</guid>
      <description>&lt;p&gt;CRUD is not the enemy. It is often the smallest correct design for a profile, a team setting, or a simple lookup table.&lt;/p&gt;

&lt;p&gt;The trouble starts when a changed object hides a business action. An API that receives an updated inventory DTO can see that &lt;code&gt;Status&lt;/code&gt; became &lt;code&gt;Deactivated&lt;/code&gt;, but it still has to infer why that happened, whether a reason is required, who is allowed to do it, and what should happen next.&lt;/p&gt;

&lt;p&gt;That is where Command-Query Separation helps. A query returns information. A command asks the system to change something. &lt;code&gt;DeactivateInventoryItem(id, reason)&lt;/code&gt; says more than a generic update ever can.&lt;/p&gt;

&lt;p&gt;This does not require two databases, a message broker, or microservices. It starts with making the request visible where the rules belong.&lt;/p&gt;

</description>
      <category>engineering</category>
      <category>architecture</category>
      <category>cqrs</category>
      <category>cqs</category>
    </item>
  </channel>
</rss>
