<?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: Bnaya Eshet</title>
    <description>The latest articles on DEV Community by Bnaya Eshet (@bnayae).</description>
    <link>https://dev.to/bnayae</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F332919%2F2dee1bb4-8376-4579-8115-f2d60d602641.png</url>
      <title>DEV Community: Bnaya Eshet</title>
      <link>https://dev.to/bnayae</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bnayae"/>
    <language>en</language>
    <item>
      <title>Proactive Architecture Guarding</title>
      <dc:creator>Bnaya Eshet</dc:creator>
      <pubDate>Sat, 04 May 2024 19:46:01 +0000</pubDate>
      <link>https://dev.to/bnayae/proactive-architecture-guarding-43la</link>
      <guid>https://dev.to/bnayae/proactive-architecture-guarding-43la</guid>
      <description>&lt;blockquote&gt;
&lt;h2&gt;
  
  
  Architecture Guarding with Static Code Analyzer and Code Fix
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ever worked on a codebase where the original architecture seems like a distant myth?&lt;/p&gt;

&lt;p&gt;In large organizations, it’s easy for software architecture to drift as documentation becomes outdated and implicit knowledge fades. This wastes valuable knowledge and makes onboarding new developers a nightmare.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem of Architecture Drift
&lt;/h2&gt;

&lt;p&gt;In medium to large organizations, software architecture tends to drift away from its intended design over time. Documentation like wikis gets neglected or forgotten. The cognitive load on developers’ minds is too high to remember all architectural decisions. New developers are often unaware of the intended architecture.&lt;/p&gt;

&lt;p&gt;Using Static Code Analysis integrated into the IDE &amp;amp; CI pipelines is the remedy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbxmpd01x6ovb2wxqifk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbxmpd01x6ovb2wxqifk.jpg" alt="Image description" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Code Analysis
&lt;/h2&gt;

&lt;p&gt;Static code analysis is the process of analyzing source code to detect potential issues, vulnerabilities, or deviations from coding rules and best practices without actually executing the program. It helps enforce quality standards and architectural guidelines early in the development lifecycle.&lt;/p&gt;

&lt;p&gt;There are different types of static analyzers ranging from simple linting tools to sophisticated data flow analyzers that can detect complex coding issues, security vulnerabilities, and architectural violations.&lt;/p&gt;

&lt;h2&gt;
  
  
  .NET Roslyn Analyzers
&lt;/h2&gt;

&lt;p&gt;For .NET projects, Roslyn Analyzers leverage a deep understanding of the .NET codebase to identify architectural violations.&lt;br&gt;
These analyzers can dissect the code’s syntax tree and scrutinize code declarations to uncover even subtle architectural rule drifts. This fine-grained analysis makes Roslyn Analyzers, coupled with Roslyn Code Fix, incredibly powerful tools. By enforcing architectural best practices and automatically correcting common mistakes, they significantly improve the system quality. Furthermore, integrating seamlessly with developer IDEs like Visual Studio and VS Code shortens the issue-fixing cycle. Developers receive real-time feedback as they write code, allowing them to address problems before they reach the code repository. This proactive approach minimizes the number of issues that make it into the codebase, ultimately leading to cleaner, more maintainable software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Static Code Analysis into CI/CD
&lt;/h2&gt;

&lt;p&gt;Once you’ve established your architectural rules within static code analyzers like Roslyn Analyzers, the next step is to integrate them seamlessly into your CI/CD pipeline. This ensures that architectural violations are caught early in the development process, preventing them from reaching production.&lt;/p&gt;

&lt;p&gt;Several popular tools facilitate integrating static code analysis into your CI/CD workflow. Here are a few examples, including both dedicated static code analyzers and platforms that manage them:&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Code Analyzers:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Roslyn Analyzers&lt;/strong&gt; (for .NET): As mentioned previously, offer a powerful way to enforce architectural best practices specifically for .NET projects. They integrate directly with developer IDEs and can be configured to fail builds in CI/CD pipelines upon detecting violations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CI/CD Integration Platforms:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SonarQube&lt;/strong&gt;: This popular platform goes beyond basic static code analysis. It aggregates the results from various static code analyzers, including Roslyn Analyzers, providing a consolidated view of code quality across your entire codebase. SonarQube integrates seamlessly with most major CI/CD tools and allows you to set quality gates within your pipelines. Builds will fail if these quality gates, which can include architectural compliance metrics, are not met.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions, Jenkins, Azure DevOps&lt;/strong&gt;: While these are primarily CI/CD platforms, they offer extensive plugin support for integrating various static code analyzers. These plugins allow you to configure analysis jobs within your pipelines and often integrate with platforms like SonarQube for centralized reporting and quality gate management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By choosing the tools that best suit your CI/CD platform, development environment, and desired level of analysis depth, you can establish a robust system for enforcing architectural compliance throughout the development lifecycle. This proactive approach ensures that your software adheres to its intended design, leading to a more maintainable and reliable codebase in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complementary Tools for a Holistic Code Quality Approach
&lt;/h2&gt;

&lt;p&gt;Static code analysis backed into the IDE &amp;amp; C/CD pipelines are foundational elements for enforcing architectural best practices within your .NET projects. However, a well-rounded code quality strategy encompasses a broader range of considerations. Here are some complementary tools you can integrate with your CI/CD pipeline to address various aspects of code quality:&lt;/p&gt;

&lt;h3&gt;
  
  
  Security-Focused Tools:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SAST (Static Application Security Testing) tools&lt;/strong&gt;: These tools analyze code to identify potential security vulnerabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SCA (Software Composition Analysis) tools&lt;/strong&gt;:
These tools scan your codebase for known third-party library vulnerabilities.
Check this blog post for deeper insights.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By incorporating these tools alongside static code analysis, you can significantly enhance your security posture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Practices and Code Style Enforcement&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NDepend&lt;/strong&gt;: offers advanced code analysis capabilities, including code metrics, dependency visualization, and rule-based code inspections. It integrates seamlessly with CI/CD pipelines for .NET development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By incorporating these complementary tools alongside static code analysis and SonarQube, you can establish a comprehensive approach to code quality that safeguards your .NET projects from security vulnerabilities, promotes code maintainability, and fosters a well-structured codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Get Our Hands Dirty
&lt;/h2&gt;

&lt;p&gt;Don’t be intimidated by the idea of creating your own static code analyzer , it’s more approachable than it may seem at first glance. The process is relatively simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new Analyzer with Code Fix (.NET Standard) project, and you'll have a working sample right off the box.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The real challenge lies in translating your analysis logic into Roslyn syntax, but even that can be made easier with the help of tools like GitHub Copilot. While Copilot won’t provide a complete, ready-to-use solution, it can guide you through the process and suggest code snippets to build upon. You’ll likely still need to refine and debug Copilot’s suggestions, but it can streamline the development process significantly.&lt;/p&gt;

&lt;p&gt;So don’t hesitate — roll up your sleeves and dive into creating your very own static code analyzer! With the right tools and a bit of persistence, you’ll be analyzing code like a pro in no time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Building a Strong Code Foundation
&lt;/h2&gt;

&lt;p&gt;Enforcing architectural best practices and fostering a culture of code quality are essential for building secure, maintainable, and well-structured software. By leveraging static code analysis and CI/CD guards like SonarQube, plus a strategic selection of complementary tools, you can establish a robust system for safeguarding your .NET projects throughout the development lifecycle.&lt;/p&gt;

&lt;p&gt;This proactive approach yields significant benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Architectural Drift&lt;/strong&gt;: Explicitly defined architectural rules baked into the development process prevent deviations from the intended design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Code Security&lt;/strong&gt;: SAST and SCA tools proactively identify and mitigate security vulnerabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Code Maintainability&lt;/strong&gt;: Consistent code style, best practice enforcement, and code duplication reduction lead to cleaner, more maintainable code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Development Cycles&lt;/strong&gt;: Catching issues early in the development process minimizes rework and accelerates delivery timelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By prioritizing code quality, you empower your development team to deliver high-performing, reliable applications that meet the evolving needs of your organization, and ship faster.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting Started with Event Sourcing and EventSourcing.Backbone</title>
      <dc:creator>Bnaya Eshet</dc:creator>
      <pubDate>Mon, 29 May 2023 05:28:10 +0000</pubDate>
      <link>https://dev.to/bnayae/getting-started-with-event-sourcing-and-eventsourcingbackbone-5afc</link>
      <guid>https://dev.to/bnayae/getting-started-with-event-sourcing-and-eventsourcingbackbone-5afc</guid>
      <description>&lt;h2&gt;
  
  
  Getting Started with Event Sourcing and EventSourcing.Backbone
&lt;/h2&gt;

&lt;p&gt;This post is the first of a series about event sourcing and an exciting framework called &lt;strong&gt;&lt;em&gt;EventSourcing.Backbone&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore the fundamentals of event sourcing and a Hello World sample of the framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Event Sourcing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Event sourcing&lt;/strong&gt; is an architectural pattern that &lt;strong&gt;captures and persists state changes as a sequence of events&lt;/strong&gt;. It provides a historical log of events that can be used to &lt;strong&gt;reconstruct the current state&lt;/strong&gt; of an application at &lt;strong&gt;any given point in time&lt;/strong&gt;. This approach offers various benefits, such as auditability, scalability, and building complex workflows.&lt;/p&gt;

&lt;p&gt;Event sourcing, when combined with the Command Query Responsibility Segregation (&lt;strong&gt;CQRS&lt;/strong&gt;) pattern, offers even more advantages. CQRS &lt;strong&gt;separates&lt;/strong&gt; the &lt;strong&gt;read&lt;/strong&gt; and &lt;strong&gt;writes&lt;/strong&gt; concerns of an application, enabling the generation of dedicated databases optimized for specific read or write needs. This separation of concerns allows for more agile and &lt;strong&gt;flexible database schema designs&lt;/strong&gt;, as they are less critical to set up in advance.&lt;/p&gt;

&lt;p&gt;By leveraging &lt;em&gt;EventSourcing.Backbone&lt;/em&gt;, developers can implement event sourcing and CQRS together, resulting in a powerful architecture that promotes scalability, flexibility, and maintainability.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can check &lt;a href="https://www.eventstore.com/event-sourcing"&gt;this &lt;/a&gt;article in order to learn more about event sourcing.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing EventSourcing.Backbone
&lt;/h2&gt;

&lt;p&gt;One notable aspect of &lt;strong&gt;EventSourcing.Backbone&lt;/strong&gt; is its &lt;strong&gt;unique approach&lt;/strong&gt; to event sourcing, instead of inventing a new event source database, &lt;em&gt;EventSourcing.Backbone&lt;/em&gt; leverages a combination of existing &lt;strong&gt;message streams&lt;/strong&gt; like Kafka, Redis Stream, or similar technologies, along with &lt;strong&gt;key-value databases&lt;/strong&gt; or services like Redis.&lt;/p&gt;

&lt;p&gt;This architecture enables several benefits. Message streams, while excellent for handling event sequences and ensuring reliable message delivery, may not be optimal for heavy payloads. By combining key-value databases with message streams, &lt;em&gt;EventSourcing.Backbone&lt;/em&gt; allows for message payload to be stored in the key-value database while the stream holds the sequence and metadata. This approach &lt;strong&gt;improves performance&lt;/strong&gt; and facilitates compliance with &lt;strong&gt;GDPR&lt;/strong&gt; standards by allowing the splitting of the personal data aspects of the messages into different keys easily.&lt;/p&gt;

&lt;p&gt;It’s worth noting that &lt;em&gt;EventSourcing.Backbone&lt;/em&gt; currently provides an SDK for the .NET ecosystem. While the framework may expand to other programming languages and frameworks in the future, at present, it is specifically focused on the .NET platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leveraging Existing Infrastructure
&lt;/h2&gt;

&lt;p&gt;One of the major advantages of &lt;em&gt;EventSourcing.Backbone&lt;/em&gt; is its compatibility with widely adopted message streaming platforms like &lt;strong&gt;Kafka or Redis Stream&lt;/strong&gt;. These platforms provide robust message delivery guarantees and high throughput, making them ideal for handling event streams at scale.&lt;/p&gt;

&lt;p&gt;Furthermore, &lt;em&gt;EventSourcing.Backbone&lt;/em&gt; seamlessly integrates with popular key-value databases such as &lt;strong&gt;Redis, Couchbase, or Amazon DynamoDB&lt;/strong&gt;. This integration allows developers to leverage the strengths of these databases for efficient storage and retrieval of auxiliary data related to events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behind the scenes
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;EventSourcing.Backbone&lt;/em&gt; is taking a &lt;strong&gt;somewhat different approach&lt;/strong&gt;. It defines messages &lt;strong&gt;contract via interfaces&lt;/strong&gt; (rather than data classes). This approach is friendly for versioning and easier for handling diverse message types. It can also help with GDPR by segregating personal data into different method parameters. In a nutshell, a message type build-out of each method parameter in a way that is transparent to the developer.&lt;/p&gt;

&lt;p&gt;Each &lt;strong&gt;producer&lt;/strong&gt; method &lt;strong&gt;call&lt;/strong&gt; gets &lt;strong&gt;serialized&lt;/strong&gt; as &lt;strong&gt;key-value&lt;/strong&gt; pairs based on the &lt;strong&gt;method parameters&lt;/strong&gt; (by default) and &lt;strong&gt;stored&lt;/strong&gt; in the &lt;strong&gt;key-value storage&lt;/strong&gt; (Redis Hash in our case). Then the &lt;strong&gt;metadata&lt;/strong&gt; of the message is &lt;strong&gt;pushed into&lt;/strong&gt; the &lt;strong&gt;stream&lt;/strong&gt; (Redis Stream in our case).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;consumer&lt;/strong&gt; is &lt;strong&gt;listening&lt;/strong&gt; to the &lt;strong&gt;stream&lt;/strong&gt; and &lt;strong&gt;reconstructing&lt;/strong&gt; the &lt;strong&gt;message into a method call&lt;/strong&gt; right into the subscriber interface.&lt;/p&gt;

&lt;p&gt;The framework is capable of handling different message patterns and different strategies, more on this will be posted in future posts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s have a taste of it.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NuPpbucn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4096/1%2A_RMxa-iJrV0yKTKGuQgfRg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NuPpbucn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4096/1%2A_RMxa-iJrV0yKTKGuQgfRg.jpeg" alt="[Taken by Asaf Cohen](https://www.carmel-law.co.il/)" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;:&lt;br&gt;
In order to run the sample you need &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.docker.com/products/docker-desktop/"&gt;&lt;em&gt;Docker Desktop&lt;/em&gt;&lt;/a&gt; (for hosting REDIS)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/core/install/"&gt;&lt;em&gt;.NET 7 SDK&lt;/em&gt;&lt;/a&gt; (or higher)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get Redis up &amp;amp; running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 6379:6379 &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; redis-event-source-sample redislabs/rejson:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a solution with 3 projects (Producer, Consumer, Common Abstraction). or clone the following repo as a starting point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/bnayae/HelloEventSourcing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Defining mutual interest codes like the common contracts:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add the following NuGet packages into the project of the common abstraction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/EventSourcing.Backbone.SrcGen/"&gt;&lt;em&gt;EventSourcing.Backbone.SrcGen&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/EventSourcing.Backbone.Abstractions/"&gt;&lt;em&gt;EventSourcing.Backbone.Abstractions&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step is to define the &lt;strong&gt;events schema&lt;/strong&gt;.&lt;br&gt;
“&lt;a href="https://www.nuget.org/packages/EventSourcing.Backbone.Abstractions/"&gt;&lt;em&gt;EventSourcing.Backbone&lt;/em&gt;&lt;/a&gt;” is taking the approach of defining an interface for the event’s data structuring.&lt;/p&gt;

&lt;p&gt;Put the following code into the &lt;em&gt;event abstraction&lt;/em&gt; project.&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;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Backbone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;EventsContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventsContractType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Producer&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;EventsContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventsContractType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Consumer&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IShipmentTracking&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OrderPlacedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;PackingAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OnDeliveryAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OnReceivedAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;EventsContract&lt;/em&gt; attribute is where the &lt;strong&gt;magic&lt;/strong&gt; begins.&lt;br&gt;
By decorating the interface with &lt;em&gt;EventsContract _a &lt;strong&gt;compile-time source generator&lt;/strong&gt; will generate the code necessary for producing and consuming events (you don’t have to write boilerplate code).&lt;br&gt;
And in a result will generate the code of the _IShipmentTrackingProducer&lt;/em&gt; interface for the producer and &lt;em&gt;IShipmentTrackingConsumer&lt;/em&gt; for the consumer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: all methods should return &lt;em&gt;ValueTask&lt;/em&gt; (this is the convention), yet &lt;em&gt;void _will be fine but will result in _ValueTask _on the generated version of the interface (producer/consumer). furthermore, all generated methods will have the _Async&lt;/em&gt; suffix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Creating a producer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add the following Nuget for using a &lt;strong&gt;Redis-based producer&lt;/strong&gt; (using Redis Stream + Redis Hash).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.nuget.org/packages/EventSourcing.Backbone.Channels.RedisProducerProvider"&gt;&lt;em&gt;EventSourcing.Backbone.Channels.RedisProducerProvider&lt;/em&gt;&lt;/a&gt;
&lt;em&gt;And don’t forget to add a reference to the common abstraction project we created earlier.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Backbone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IShipmentTrackingProducer&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RedisProducerBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello.event-sourcing"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BuildShipmentTrackingProducer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someone@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someone"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Something you must have"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderPlacedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's all you need to have a working producer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Take a look at &lt;em&gt;BuildShipmentTrackingProducer&lt;/em&gt; which is an extension method generated from the &lt;em&gt;IShipmentTracking&lt;/em&gt; interface and returns an &lt;em&gt;IShipmentTrackingProducer&lt;/em&gt; .&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Creating a consumer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add the following Nuget for using a &lt;strong&gt;Redis-based consumer&lt;/strong&gt; (using Redis Stream + Redis Hash).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.nuget.org/packages/EventSourcing.Backbone.Channels.RedisConsumerProvider"&gt;&lt;em&gt;EventSourcing.Backbone.Channels.RedisConsumerProvider&lt;/em&gt;&lt;/a&gt;
&lt;em&gt;And don’t forget to add a reference to the common abstraction project we created earlier.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add a class that implements the consumer (generated) interface:&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;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IShipmentTrackingConsumer&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Subscription&lt;/span&gt; &lt;span class="n"&gt;Instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Subscription&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;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OrderPlacedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Order Placed: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;ValueTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;PackingAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Packing: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;ValueTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OnDeliveryAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"On Delivery: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;ValueTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OnReceivedAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"On Received: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;ValueTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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 final step is to attach this class to the event stream.&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;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Backbone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IConsumerLifetime&lt;/span&gt; &lt;span class="n"&gt;subscription&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RedisConsumerBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                                          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;URIs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SubscribeShipmentTrackingConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Completion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you recall the producer was sending a single event of &lt;em&gt;OrderPlacedAsync&lt;/em&gt;, &lt;br&gt;
To complete the picture we’ll add a combination of consumer &amp;amp; producer which will change the state along the shipping flow.&lt;/p&gt;

&lt;p&gt;Create a new project and add both the &lt;strong&gt;Redis-based&lt;/strong&gt; producer &amp;amp; consumer NuGets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/EventSourcing.Backbone.Channels.RedisConsumerProvider"&gt;&lt;em&gt;EventSourcing.Backbone.Channels.RedisConsumerProvider&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/EventSourcing.Backbone.Channels.RedisProducerProvider"&gt;&lt;em&gt;EventSourcing.Backbone.Channels.RedisProducerProvider&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add an implementation of &lt;em&gt;IShipmentTrackingConsumer&lt;/em&gt;.&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;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Backbone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IShipmentTrackingConsumer&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Subscription&lt;/span&gt; &lt;span class="n"&gt;Instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Subscription&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;IShipmentTrackingProducer&lt;/span&gt; &lt;span class="n"&gt;_producer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RedisProducerBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;URIs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BuildShipmentTrackingProducer&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;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OrderPlacedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PackingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;PackingAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OnDeliveryAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OnDeliveryAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OnReceivedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&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;ValueTask&lt;/span&gt; &lt;span class="nf"&gt;OnReceivedAsync&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt; &lt;span class="n"&gt;time&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;ValueTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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 way we can handle the state’s transition.&lt;/p&gt;

&lt;p&gt;The last step is to plug it into the stream:&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;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;EventSourcing.Backbone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Consuming and Producing Events"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;IConsumerLifetime&lt;/span&gt; &lt;span class="n"&gt;subscription&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RedisConsumerBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                                                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;URIs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"transit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SubscribeShipmentTrackingConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Completion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the &lt;em&gt;Group(“transit”)&lt;/em&gt; this one is important for separating the consumer group which deals with the state transition from the one that reports the current state.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Consumer groups distribute the workload of processing messages among multiple consumers, allowing parallel processing while ensuring each message is handled only once. This ensures efficient and reliable message processing, scalability, and fault tolerance when dealing with large volumes of data or high-throughput message streams.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Putting both consumers in the same consumer group (or under the default one) will result in messages either handled by the transit or by the reporter and lead to a mess.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The full code is available at:&lt;br&gt;
&lt;a href="https://github.com/bnayae/HelloEventSourcing/tree/HelloWorld"&gt;https://github.com/bnayae/HelloEventSourcing/tree/HelloWorld&lt;/a&gt;&lt;br&gt;
&lt;em&gt;notice that it is under the &lt;strong&gt;HelloWorld&lt;/strong&gt; branch&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;In this introductory post, we’ve explored the concept of &lt;strong&gt;event sourcing&lt;/strong&gt; and introduced the unique aspects of &lt;em&gt;EventSourcing.Backbone&lt;/em&gt;. This framework stands out by leveraging a combination of message streams and key-value databases to achieve better performance, support GDPR standards, and provide flexibility in event-sourcing implementations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;EventSourcing.Backbone&lt;/em&gt; integrates seamlessly with popular message-streaming platforms and key-value databases, enabling developers to leverage their strengths for scalable and efficient event sourcing.&lt;/p&gt;

&lt;p&gt;When combined with CQRS, event sourcing can enhance database schema design, making it more agile and flexible, and enabling the generation of dedicated databases optimized for specific needs.&lt;/p&gt;

&lt;p&gt;In future posts, we’ll drill down to more advanced patterns, concerns, pros &amp;amp; cons, and best practices.&lt;/p&gt;

</description>
      <category>eventsourcing</category>
      <category>cqrs</category>
      <category>redis</category>
      <category>kafka</category>
    </item>
  </channel>
</rss>
