<?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>Forem: Davi Orlandi</title>
    <description>The latest articles on Forem by Davi Orlandi (@dvorlandi).</description>
    <link>https://forem.com/dvorlandi</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%2F1730896%2Fa4867ff8-3636-4f5e-8580-4d0a3c651593.jpg</url>
      <title>Forem: Davi Orlandi</title>
      <link>https://forem.com/dvorlandi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dvorlandi"/>
    <language>en</language>
    <item>
      <title>GO profiling using pprof</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Mon, 15 Dec 2025 02:07:42 +0000</pubDate>
      <link>https://forem.com/dvorlandi/go-profilling-using-pprof-93i</link>
      <guid>https://forem.com/dvorlandi/go-profilling-using-pprof-93i</guid>
      <description>&lt;p&gt;Have you ever spent nights trying to understand why your application is using so many resources? Your CPU is on fire, memory keeps growing, latency goes up… and the code looks fine. Probably, you're &lt;strong&gt;guessing instead of verifying&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In this article, we'll see how to verify possible memory leaks, unused resources and bad optimized code using the Go built-in profiling tool &lt;code&gt;pprof&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is pprof?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pprof&lt;/code&gt; is Go builtin profiling tool that allows you to collect and analyze runtime data from your application, such as CPU usage, memory allocations, goroutines, and blocking operations.&lt;/p&gt;

&lt;p&gt;In simple terms, pprof answers questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why is my application slow?&lt;/li&gt;
&lt;li&gt;Where is CPU time being spent?&lt;/li&gt;
&lt;li&gt;What is allocating so much memory?&lt;/li&gt;
&lt;li&gt;Are goroutines leaking?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Spoiler:&lt;/em&gt; pprof does not magically optimize your code. It just tells you &lt;strong&gt;where you messed up&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How pprof works
&lt;/h2&gt;

&lt;p&gt;pprof works in two steps, &lt;strong&gt;collect&lt;/strong&gt; (where we can collect metrics from our applicaton) and &lt;strong&gt;analyze&lt;/strong&gt; (where we analyze the collected metrics using the &lt;code&gt;go tool pprof&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;At runtime, Gosamples execution and records metrics. These samples are aggregated into profiles that can be visualized and explored using &lt;code&gt;pprof&lt;/code&gt;commands. &lt;/p&gt;

&lt;p&gt;You might think this is a lot like &lt;a href="https://en.wikipedia.org/wiki/Tracing_(software)" rel="noopener noreferrer"&gt;traces&lt;/a&gt;, but under the hood, Go does &lt;a href="https://en.algorithmica.org/hpc/profiling/events" rel="noopener noreferrer"&gt;statistical profiling&lt;/a&gt;, that means your program is periodically interrupted and the runtime records what was running at that exact moment. Overtime these snapshots form a accurate picture of resources use.&lt;/p&gt;

&lt;p&gt;A simple way to enable proffiling in you app is using an http server, take an example:&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%2Fyy2cqwh6c7mg5bgppfwt.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%2Fyy2cqwh6c7mg5bgppfwt.png" alt="main.go" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This exposes profiling endpoints under &lt;code&gt;/debug/pprof/&lt;/code&gt;, such as &lt;code&gt;/debug/pprof/profile&lt;/code&gt; (CPU), &lt;code&gt;/debug/pprof/heap&lt;/code&gt; (Memory), etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Collecting profiles
&lt;/h3&gt;

&lt;p&gt;When you hit a pprof endpoint like &lt;code&gt;/debug/pprof/profile&lt;/code&gt;, what you get back is not a report, it’s a binary blob. If you try to open it in the browser, you’ll download a file and see what looks like complete garbage. &lt;/p&gt;

&lt;p&gt;At first, that's correct, this endpoint returns a serialized pprof profile (a protobuf, usually gzip-compressed) that contains raw sampled data collected by Go runtime, stack traces, counters, timestamps. Not charts. Not tables. Not answers. This binary mess is not meant for humans.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that’s where &lt;code&gt;pprof&lt;/code&gt; comes in.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pprof&lt;/code&gt; is the tool that takes this raw, unreadable data and decodes, aggregates, correlates and turns it in a human readable output. &lt;/p&gt;

&lt;h3&gt;
  
  
  Analyzing profiles
&lt;/h3&gt;

&lt;p&gt;Well, let's start to analyze our profilling output. The first step is install the &lt;code&gt;pprof&lt;/code&gt; cli using this command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/google/pprof@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcckye3gqz8zqse41kmv3.gif" 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%2Fcckye3gqz8zqse41kmv3.gif" alt="pprof install" width="902" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we'll need the web server running and try to get a profiling with this command below (CPU Profile, 10 seconds):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof http://localhost:8080/debug/pprof/profile?seconds&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you made everything right and waited for 10 seconds, you should get interactive shell. This is where the raw profile data becomes actionable. Once inside pprof, you can execute many commands, such as &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;web&lt;/code&gt;, etc. (check the options &lt;a href="https://github.com/google/pprof/blob/main/doc/README.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Bad Boy
&lt;/h2&gt;

&lt;p&gt;Imagine we have an endpoint using a lot of CPU, the "Big Bad Boy", for study proposal, i'll use a &lt;code&gt;/work&lt;/code&gt; endpoint.&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%2Fqpexowixfuybenay9s5c.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%2Fqpexowixfuybenay9s5c.png" alt="main.go" width="800" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With our app running, hit the &lt;code&gt;/work&lt;/code&gt; endpoint from another terminal or using curl, trigger some CPU load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can repeat it a few times or use a load tool like &lt;a href="https://github.com/rakyll/hey" rel="noopener noreferrer"&gt;hey&lt;/a&gt; or &lt;a href="https://httpd.apache.org/docs/trunk/programs/ab.html" rel="noopener noreferrer"&gt;ab&lt;/a&gt; to generate more pressure.&lt;/p&gt;

&lt;p&gt;Now, collect a 10-second CPU profile from the running server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof http://localhost:6060/debug/pprof/profile?seconds&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the pprof shell, you can show top functions consuming CPU using &lt;code&gt;top&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7d4s8zo8s5c4syvfvcfs.gif" 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%2F7d4s8zo8s5c4syvfvcfs.gif" alt="top" width="800" height="832"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You wi'll se an output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;pprof&lt;span class="o"&gt;)&lt;/span&gt; top 
Showing nodes accounting &lt;span class="k"&gt;for &lt;/span&gt;7470ms, 92.45% of 8080ms total
Dropped 2 nodes &lt;span class="o"&gt;(&lt;/span&gt;cum &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; 40.40ms&lt;span class="o"&gt;)&lt;/span&gt;
Showing top 10 nodes out of 35
      flat  flat%   &lt;span class="nb"&gt;sum&lt;/span&gt;%        cum   cum%
    2030ms 25.12% 25.12%     2030ms 25.12%  math.archExp
    1570ms 19.43% 44.55%     1570ms 19.43%  math.IsInf &lt;span class="o"&gt;(&lt;/span&gt;inline&lt;span class="o"&gt;)&lt;/span&gt;
    1500ms 18.56% 63.12%     2830ms 35.02%  math.log
     560ms  6.93% 70.05%     5800ms 71.78%  math.pow
     430ms  5.32% 75.37%     1050ms 13.00%  math.sin
     330ms  4.08% 79.46%      330ms  4.08%  runtime.pthread_cond_signal
     320ms  3.96% 83.42%     1560ms 19.31%  math.frexp
     290ms  3.59% 87.00%      290ms  3.59%  math.Float64frombits &lt;span class="o"&gt;(&lt;/span&gt;inline&lt;span class="o"&gt;)&lt;/span&gt;
     220ms  2.72% 89.73%      220ms  2.72%  math.IsNaN &lt;span class="o"&gt;(&lt;/span&gt;inline&lt;span class="o"&gt;)&lt;/span&gt;
     220ms  2.72% 92.45%      230ms  2.85%  math.normalize &lt;span class="o"&gt;(&lt;/span&gt;inline&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can se a lot of &lt;code&gt;math&lt;/code&gt; packages operations right now, but we don't know where those operations are used. So, let's run &lt;code&gt;top&lt;/code&gt; command again with &lt;code&gt;-cum&lt;/code&gt; (cumulative) flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;pprof&lt;span class="o"&gt;)&lt;/span&gt; top &lt;span class="nt"&gt;-cum&lt;/span&gt;
Showing nodes accounting &lt;span class="k"&gt;for &lt;/span&gt;2170ms, 26.86% of 8080ms total
Dropped 2 nodes &lt;span class="o"&gt;(&lt;/span&gt;cum &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; 40.40ms&lt;span class="o"&gt;)&lt;/span&gt;
Showing top 10 nodes out of 35
      flat  flat%   &lt;span class="nb"&gt;sum&lt;/span&gt;%        cum   cum%
     110ms  1.36%  1.36%     7750ms 95.92%  main.heavyComputation
         0     0%  1.36%     7750ms 95.92%  main.main.func1
         0     0%  1.36%     7750ms 95.92%  net/http.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;ServeMux&lt;span class="o"&gt;)&lt;/span&gt;.ServeHTTP
         0     0%  1.36%     7750ms 95.92%  net/http.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;conn&lt;span class="o"&gt;)&lt;/span&gt;.serve
         0     0%  1.36%     7750ms 95.92%  net/http.HandlerFunc.ServeHTTP
         0     0%  1.36%     7750ms 95.92%  net/http.serverHandler.ServeHTTP
         0     0%  8.29%     2830ms 35.02%  math.Log &lt;span class="o"&gt;(&lt;/span&gt;inline&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spotted! The &lt;code&gt;main.heavyComputation&lt;/code&gt; consuming 95.92% of the total CPU, well, that is our “Big Bad Boy.”&lt;/p&gt;




&lt;h3&gt;
  
  
  You can do the same for memory, block, mutex, and goroutine profiles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Memory (heap) – see allocations and leaks:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof http://localhost:6060/debug/pprof/heap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Goroutines – detect leaks or deadlocks:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof http://localhost:6060/debug/pprof/goroutine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Block – see time spent waiting on channels, mutexes, etc.:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof http://localhost:6060/debug/pprof/block
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Mutex – see contention hotspots:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof http://localhost:6060/debug/pprof/mutex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of these can be analyzed in the same way (&lt;code&gt;top&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;web&lt;/code&gt;, &lt;code&gt;svg&lt;/code&gt;). The &lt;code&gt;web&lt;/code&gt; and &lt;code&gt;svg&lt;/code&gt; commands produce &lt;strong&gt;graphical visualizations&lt;/strong&gt; (requires Graphviz), making it much easier to spot hotspots.&lt;/p&gt;




&lt;h3&gt;
  
  
  Visualization (Graphviz required)
&lt;/h3&gt;

&lt;p&gt;Graphical visualizations make it much easier to spot CPU or memory hotspots quickly, for that, we need install &lt;a href="https://graphviz.org/" rel="noopener noreferrer"&gt;Graphviz&lt;/a&gt; and open source graph visualization software.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;web&lt;/code&gt;: opens a call graph in your browser&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;svg&lt;/code&gt;: outputs an SVG call graph&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pdf&lt;/code&gt;: outputs a PDF graph&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Don’t spray and pray
&lt;/h3&gt;

&lt;p&gt;pprof has multiple profile types because performance problems love to hide in different places. Each type answers a different question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU – where time is spent&lt;/li&gt;
&lt;li&gt;Heap – memory usage and leaks&lt;/li&gt;
&lt;li&gt;Goroutines – leaks or deadlocks&lt;/li&gt;
&lt;li&gt;Block – wait times&lt;/li&gt;
&lt;li&gt;Mutex – contention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always choose the profile that matches the problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  ADDITIONAL: Profiling in Kubernetes
&lt;/h3&gt;

&lt;p&gt;If your app runs in a Kubernetes cluster, you can port-forward the pprof port from your pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward deploy/my-app 6060:6060
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access pprof locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof http://localhost:6060/debug/pprof/profile?seconds&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analyze interactively as usual (&lt;code&gt;top&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful Links &amp;amp; References
&lt;/h3&gt;

&lt;p&gt;Go pprof docs: &lt;a href="https://pkg.go.dev/net/http/pprof" rel="noopener noreferrer"&gt;https://pkg.go.dev/net/http/pprof&lt;/a&gt;&lt;br&gt;
Runtime profiling: &lt;a href="https://pkg.go.dev/runtime/pprof" rel="noopener noreferrer"&gt;https://pkg.go.dev/runtime/pprof&lt;/a&gt;&lt;br&gt;
go tool pprof guide: &lt;a href="https://go.dev/doc/diagnostics#profiling" rel="noopener noreferrer"&gt;https://go.dev/doc/diagnostics#profiling&lt;/a&gt;&lt;br&gt;
Official Go blog post about pprof: &lt;a href="https://go.dev/blog/pprof" rel="noopener noreferrer"&gt;https://go.dev/blog/pprof&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  So, Thanks!
&lt;/h2&gt;

&lt;p&gt;If this article saved you even one late night of guessing and blaming the garbage collector, it already did its job 😄. Thanks for reading! &lt;/p&gt;

&lt;h2&gt;
  
  
  See you soon ;)
&lt;/h2&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>distributedsystems</category>
      <category>programming</category>
    </item>
    <item>
      <title>Getting Started With Linux</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Sun, 14 Dec 2025 22:36:44 +0000</pubDate>
      <link>https://forem.com/dvorlandi/getting-started-with-linux-4n7f</link>
      <guid>https://forem.com/dvorlandi/getting-started-with-linux-4n7f</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is intended as a study-oriented, introductory overview of Linux. It intentionally covers very basic concepts and simplifies some topics to help beginners build an initial mental model. It is not meant to be exhaustive or deeply technical, but rather a starting point for further exploration.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base needed knowledge:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GNU:&lt;/strong&gt; GNU is a predecessor of Linux and a free open-source unix-like operating system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kernel:&lt;/strong&gt; Kernel is the core system of an operational system, it acts as a bridge through software and hardware, managing system resources (CPU, memory, peripheral devices). Although we use the same Linux to describe the whole operating system, it's only refers to the kernel.&lt;/p&gt;




&lt;h3&gt;
  
  
  Whats is Linux?
&lt;/h3&gt;

&lt;p&gt;Linux is an open-source operating system kernel originally created by Linus Torvalds. In practice, when people say “Linux,” they are usually referring to a complete operating system made of the Linux kernel combined with tools, libraries, and others softwares from the GNU project.&lt;/p&gt;

&lt;h3&gt;
  
  
  A linux system is divided in three layers:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Hardware&lt;/strong&gt;: This includes the physical resources of your machine, such as CPU, memory, peripheral devices, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux Kernel&lt;/strong&gt;: Is the core of the operating system, managing the hardware and facilitates communication between software and hardware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User Space&lt;/strong&gt;: This is the environment where the users interacts with the system, using applications and command line interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Linux distribution?
&lt;/h3&gt;

&lt;p&gt;A distribution is a bundle of the Linux kernel with some specific softwares, tools, system utilities, libraries and applications. Essentially a distro is a complete, ready-to-use operating system built around the Linux Kernel.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debian:
&lt;/h2&gt;

&lt;p&gt;Debian is an operating system composed entirely of free and open-source software, it's one of the most respected projects in community.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package Management
&lt;/h3&gt;

&lt;p&gt;Debians uses a powerful package management tool called &lt;code&gt;apt&lt;/code&gt; (Advanced Package Tool). The system maintain a massive repository of pre-compiled software packages.&lt;/p&gt;




&lt;h2&gt;
  
  
  Red Hat Enterprise Linux (RHEL)
&lt;/h2&gt;

&lt;p&gt;RHEL is a commercial linux distribution developed by the Red Hat Team, build to provide long-term stability, security and professional support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package Management
&lt;/h3&gt;

&lt;p&gt;RHEL uses RPM (Red Hat Package Manager) format for its software packages, for managing this packages, it provides powerful package managers like YUM (Yellowdog Updater, Modifier) and its sucessor, DNF (Dandified YUM).&lt;/p&gt;




&lt;h2&gt;
  
  
  Ubuntu
&lt;/h2&gt;

&lt;p&gt;Ubuntu is probably the most famous famous linux distribution, it's and excellent entry point for anyone looking to get started with Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package Management
&lt;/h3&gt;

&lt;p&gt;As a Debian-based operating system, Ubuntu utilizes the core Debian package management system. This means it uses the &lt;code&gt;apt&lt;/code&gt; (Advanced Package Tool) command-line utility to handle software installation, updates, and removal, giving users access to a vast repository of free and open-source software.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fedora
&lt;/h2&gt;

&lt;p&gt;Fedora is and equivalent to Ubuntu but developed by Red Hat team, built on our foundation instead of Debian.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package Management
&lt;/h3&gt;

&lt;p&gt;Fedora utilizes the RPM package format and manages software with the DNF (Dandified YUM) package manager. DNF is a powerful and easy-to-use command-line tool for installing, updating, and removing software packages on the system.&lt;/p&gt;




&lt;h2&gt;
  
  
  The shell
&lt;/h2&gt;

&lt;p&gt;The is a program that accepts you typed commands and passes them to the operating system. If you i've used a GUI (Graphical User Interface), you might have encountered applications like "Terminal" or "Console." the are simply programs that open a shell session for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  BASH (Bourne Again Shell)
&lt;/h2&gt;

&lt;p&gt;Bash is the default shell for most Linux distros. While other shells like &lt;code&gt;ksh&lt;/code&gt;, &lt;code&gt;zsh&lt;/code&gt;, and &lt;code&gt;tsch&lt;/code&gt; exist, mastering Bash provides a solid foundation for working with any Linux system.&lt;/p&gt;

&lt;p&gt;When you open a terminal, you'll see the shell prompt, Its appearance can vary between distros but it typically follows this format: &lt;code&gt;username@hostname:current_directory$&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Yeah, i used a MacOS Terminal screenshot, don't care its not relevant.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fze0ry3m720zrst23dyul.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%2Fze0ry3m720zrst23dyul.png" alt="Terminal" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;$&lt;/code&gt; symbol at the end indicates that the shell is ready to accept commands, you do not type this symbol when entering commands, it is purely informational!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the hell does this work?&lt;/strong&gt;&lt;br&gt;
Well, just paste this command &lt;code&gt;echo "I love Linux"&lt;/code&gt; and you'll see "I love Linux" as the output into console.&lt;/p&gt;


&lt;h2&gt;
  
  
  Filesystem basics
&lt;/h2&gt;

&lt;p&gt;Linux uses single root filesystem, meaning everything starts from &lt;code&gt;/&lt;/code&gt; (root). There are no drive letters like &lt;code&gt;C:&lt;/code&gt; or &lt;code&gt;D:&lt;/code&gt;, all storage devices are mounted into the same tree.&lt;/p&gt;
&lt;h3&gt;
  
  
  Common directories
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; — root of the filesystem&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/home&lt;/code&gt; — user home directories&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/etc&lt;/code&gt; — system configuration files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/var&lt;/code&gt; — variable data (logs, cache, spool)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/usr&lt;/code&gt; — user-installed software and libraries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/bin&lt;/code&gt; and &lt;code&gt;/sbin&lt;/code&gt; — essential system binaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Linux, &lt;strong&gt;everything is treated as a file&lt;/strong&gt;, including devices, processes, and sockets.&lt;/p&gt;
&lt;h3&gt;
  
  
  Paths
&lt;/h3&gt;

&lt;p&gt;A path is the location of a file or directory inside the filesystem. It tells the system where something is in the directory tree.&lt;/p&gt;

&lt;p&gt;Absolute paths starts from &lt;code&gt;/&lt;/code&gt; like &lt;code&gt;/home/user/projects&lt;/code&gt; and relative paths without as like &lt;code&gt;projects/my-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Useful navigation commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;   &lt;span class="c"&gt;# show current directory&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt;    &lt;span class="c"&gt;# list files&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;    &lt;span class="c"&gt;# change directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Permissions &amp;amp; users
&lt;/h2&gt;

&lt;p&gt;Linux is a multi user operating system, built with security in mind from the start, so, every file and directory has an owner, a group, and a set of permissions.&lt;/p&gt;

&lt;p&gt;You can permissions in you computer with &lt;code&gt;ls -l&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzesqx4zls5b3kyh6wpv.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%2Fgzesqx4zls5b3kyh6wpv.png" alt="Terminal" width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Root is the superuser, with full-access, otherwise, normal users have limited permissions. You can run some commands as root user using &lt;code&gt;sudo&lt;/code&gt; before any command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Permissions are a core concept in Linux and one of the main reasons servers are secure by default.&lt;/p&gt;




&lt;h2&gt;
  
  
  Networking basics
&lt;/h2&gt;

&lt;p&gt;Linux provides powerful built-in tools to inspect, debug, and interact with networks. Networking is a fundamental skill, especially for servers, containers, and cloud environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network concepts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IP address&lt;/strong&gt;: identifies a machine on a network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ports&lt;/strong&gt;: identify services running on a machine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocols&lt;/strong&gt;: rules for communication (HTTP, TCP, UDP)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common networking commands:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ping "url.com"&lt;/code&gt;&lt;br&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%2Fb2km21hge9lbfrtxbddr.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%2Fb2km21hge9lbfrtxbddr.png" alt="Terminal" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl "url.com"&lt;/code&gt;&lt;br&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%2F3i1hkhdg4k3cpkq3y7ms.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%2F3i1hkhdg4k3cpkq3y7ms.png" alt="Terminal" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wget "url.com/file.zip"&lt;/code&gt;&lt;br&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%2Fn44hgh2o8qg54c5ce6kx.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%2Fn44hgh2o8qg54c5ce6kx.png" alt="Terminal" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ip a&lt;/code&gt;&lt;br&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%2Fd5r9lgg73gwrb58ghjha.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%2Fd5r9lgg73gwrb58ghjha.png" alt="Terminal" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Useful links &amp;amp; references
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GNU&lt;/strong&gt; project: &lt;a href="https://www.gnu.org" rel="noopener noreferrer"&gt;https://www.gnu.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux Kernel&lt;/strong&gt; documentation: &lt;a href="https://www.kernel.org/doc/html/latest/" rel="noopener noreferrer"&gt;https://www.kernel.org/doc/html/latest/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filesystem Hierarchy Standard (FHS)&lt;/strong&gt;: &lt;a href="https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html" rel="noopener noreferrer"&gt;https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debian&lt;/strong&gt; official docs: &lt;a href="https://www.debian.org/doc/" rel="noopener noreferrer"&gt;https://www.debian.org/doc/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APT&lt;/strong&gt; documentation: &lt;a href="https://wiki.debian.org/Apt" rel="noopener noreferrer"&gt;https://wiki.debian.org/Apt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red Hat Enterprise Linux&lt;/strong&gt; docs: &lt;a href="https://access.redhat.com/documentation" rel="noopener noreferrer"&gt;https://access.redhat.com/documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNF&lt;/strong&gt; documentation: &lt;a href="https://dnf.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;https://dnf.readthedocs.io/en/latest/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu&lt;/strong&gt; documentation: &lt;a href="https://help.ubuntu.com/" rel="noopener noreferrer"&gt;https://help.ubuntu.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fedora&lt;/strong&gt; documentation: &lt;a href="https://docs.fedoraproject.org/" rel="noopener noreferrer"&gt;https://docs.fedoraproject.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bash&lt;/strong&gt; manual: &lt;a href="https://www.gnu.org/software/bash/manual/" rel="noopener noreferrer"&gt;https://www.gnu.org/software/bash/manual/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux permissions&lt;/strong&gt; reference: &lt;a href="https://www.redhat.com/sysadmin/linux-file-permissions" rel="noopener noreferrer"&gt;https://www.redhat.com/sysadmin/linux-file-permissions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux networking&lt;/strong&gt; overview: &lt;a href="https://www.kernel.org/doc/html/latest/networking/index.html" rel="noopener noreferrer"&gt;https://www.kernel.org/doc/html/latest/networking/index.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading this article. I hope it helped clarify the core concepts behind Linux and gave you a starter foundation to keep exploring the ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  See you soon ;)
&lt;/h2&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>webdev</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>RAG with MongoDB Vector Search PART 1</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Thu, 11 Dec 2025 23:24:54 +0000</pubDate>
      <link>https://forem.com/dvorlandi/rag-with-mongodb-vector-search-part-1-297e</link>
      <guid>https://forem.com/dvorlandi/rag-with-mongodb-vector-search-part-1-297e</guid>
      <description>&lt;h2&gt;
  
  
  What is RAG?
&lt;/h2&gt;

&lt;p&gt;Retrieval-augmented generation (RAG) is a technique that enables large language models (LLMs) to retrieve and incorporate new information. RAG feeds contextual data to the LLM to deliver more accurate and grounded answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Vector Search Matters in RAG?
&lt;/h2&gt;

&lt;p&gt;Traditional keyword search breaks down when queries are vague, paraphrased, or semantically rich. Vector search solves this by representing text as high-dimensional embeddings that encode meaning rather than literal wording.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedding&lt;/strong&gt; converts documents and user queries into high-dimensional vectors that capture their semantic meaning.&lt;br&gt;
&lt;strong&gt;Indexing&lt;/strong&gt; then uses these vectors to build an approximate nearest-neighbor (ANN) structure such as HNSW, IVF-Flat, or PQ, enabling efficient similarity search.&lt;br&gt;
&lt;strong&gt;Retrieval&lt;/strong&gt; embeds the incoming query and compares it against the indexed vectors, returning the closest matches based on semantic similarity.&lt;/p&gt;
&lt;h3&gt;
  
  
  Let's think about it:
&lt;/h3&gt;

&lt;p&gt;Imagine we have these sources of data:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source 1&lt;/strong&gt;&lt;br&gt;
"Hono is a fast, lightweight JavaScript framework built on Web Standards. It focuses on low overhead, edge-friendly execution, and a minimal API surface."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source 2&lt;/strong&gt;&lt;br&gt;
"Elysia is a Bun-optimized web framework that provides strong typing, schema validation, and excellent performance. It is designed for building scalable HTTP services with good developer ergonomics."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source 3&lt;/strong&gt;&lt;br&gt;
"Express is a minimalistic and widely adopted Node.js framework. It is commonly used to build REST APIs because of its simplicity, extensive ecosystem, and flexible middleware model."&lt;/p&gt;

&lt;p&gt;Now imagine a user searches for the following query:&lt;br&gt;
&lt;strong&gt;"How can I build a backend service in JavaScript, with better Bun runtime integration?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When this query is &lt;strong&gt;embedded&lt;/strong&gt;, the resulting vector represents concepts such as backend service, API development, HTTP frameworks, and JavaScript server-side technologies.&lt;/p&gt;

&lt;p&gt;Most modern embedding models (Voyage, OpenAI, HuggingFace, etc.) generate vectors between 512 and 3072 dimensions. See an example:&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="mf"&gt;0.0182&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0925&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0441&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0107&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0713&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0089&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0562&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mf"&gt;-0.0041&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0977&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0229&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0335&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1412&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0611&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0054&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0883&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mf"&gt;-0.0122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0745&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.1099&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0671&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0144&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0528&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0995&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0173&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mf"&gt;0.0811&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0442&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0368&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1210&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0075&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0932&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0661&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0152&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mf"&gt;0.0473&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0891&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1329&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0287&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0174&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0721&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0554&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1012&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mf"&gt;0.0069&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0312&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1184&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0251&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0526&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0903&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mf"&gt;0.0110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0782&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0433&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0271&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0622&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0148&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0711&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mf"&gt;0.0835&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0222&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0579&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0384&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;Vector search then compares this query vector with the vectors generated from the sources above using the &lt;strong&gt;index&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The similarity search identifies which sources are semantically closest to the intent of the query and &lt;strong&gt;retrieves&lt;/strong&gt; them. In this case:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source 2 (Elysia)&lt;/strong&gt; is likely to rank highest because it explicitly mentions Bun optimization and scalable HTTP services—concepts directly aligned with building a backend service in JavaScript with strong Bun runtime integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source 3 (Express)&lt;/strong&gt; would typically appear next, as it strongly relates to backend development and REST API construction, even though it is not tailored to Bun.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source 1 (Hono)&lt;/strong&gt; remains relevant but ranks lower because its description emphasizes minimalism and edge-friendly execution rather than Bun-specific integration or backend-focused features.&lt;/p&gt;

&lt;p&gt;A vector search result might look like this:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Elysia is a Bun-optimized web framework that provides strong typing, schema validation, and excellent performance. It is designed for building scalable HTTP services with good developer ergonomics."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.91&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Express is a minimalistic and widely adopted Node.js framework. It is commonly used to build REST APIs because of its simplicity, extensive ecosystem, and flexible middleware model."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.78&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hono is a fast, lightweight JavaScript framework built on Web Standards. It focuses on low overhead, edge-friendly execution, and a minimal API surface."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.61&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;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;h2&gt;
  
  
  Why use MongoDB Atlas Vector Search?
&lt;/h2&gt;

&lt;p&gt;MongoDB Atlas Vector Search brings vector similarity, metadata filtering, and document storage into a &lt;strong&gt;single, unified system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of splitting your stack between a vector database and an operational database, Atlas lets you keep embeddings, raw documents, and application data side-by-side. This removes the overhead of synchronizing two systems, reduces latency, and simplifies your architecture.&lt;/p&gt;

&lt;p&gt;For RAG pipelines, this matters: you can store the original sources, their embeddings, and any contextual metadata (tags, timestamps, access rules, versions) all in one place and query everything in a single round trip.&lt;/p&gt;

&lt;h3&gt;
  
  
  How MongoDB Vector Search Works
&lt;/h3&gt;

&lt;p&gt;MongoDB stores your embeddings inside collections as arrays of numbers, just like any other field. When you enable vector search on that field, Atlas builds an ANN index optimized for fast semantic similarity lookup.&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%2Ftchtfwyspxpuwwfzwtgp.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%2Ftchtfwyspxpuwwfzwtgp.png" alt=" " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a query comes in, Atlas uses your embedded input (usually through your app or an LLM workflow), compares the query vector against the indexed vectors, and returns the documents with the smallest distance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Vector Search Index in MongoDB Atlas
&lt;/h2&gt;

&lt;p&gt;To enable vector search in MongoDB Atlas, you start by defining a vector index on the field that stores your embeddings. This index tells Atlas how to structure the ANN graph (HNSW) and what similarity metric to use. A typical index definition looks like this:&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;"mappings"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"dynamic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"embedding"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"knnVector"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dimensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"similarity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cosine"&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;span class="p"&gt;}&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;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;Here, &lt;code&gt;embedding&lt;/code&gt; is the field where each document stores its vector representation. The &lt;code&gt;dimensions&lt;/code&gt; value must match the size of the embedding model you use, and &lt;code&gt;similarity&lt;/code&gt; defines how distance is calculated during retrieval.&lt;/p&gt;

&lt;p&gt;Once indexed, MongoDB can perform vector search queries through the &lt;code&gt;$vectorSearch&lt;/code&gt; stage. A minimal example looks like this:&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;"$vectorSearch"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"frameworks_vector_index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"embedding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"queryVector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;embedding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"numCandidates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&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;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;Behind the scenes, Atlas takes your &lt;code&gt;queryVector&lt;/code&gt;, traverses the HNSW graph, and identifies the closest nodes based on the configured similarity metric.&lt;/p&gt;

&lt;p&gt;For the earlier query, Atlas would receive the embed user input, compare it against all stored embeddings, and return the most semantically aligned frameworks, just like in the example shown above. Because the retrieval happens inside the same database where your documents and metadata live, your RAG pipeline can immediately assemble the final context to feed into the LLM.&lt;/p&gt;

&lt;p&gt;A critical requirement: your embedding model must be the same for both stored documents and incoming queries. Mixing models or versions breaks vector compatibility and degrades similarity search. Always embed with the same model.&lt;/p&gt;

&lt;p&gt;This was a brief overview of how RAG, vector search, and MongoDB Atlas fit together in a practical workflow. I will continue publishing more articles exploring RAG architectures, vector indexing strategies, hybrid search, retrieval optimization, and real-world patterns using MongoDB Atlas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;MongoDB Atlas Vector Search&lt;br&gt;
&lt;a href="https://www.mongodb.com/docs/atlas/atlas-search/vector-search/" rel="noopener noreferrer"&gt;https://www.mongodb.com/docs/atlas/atlas-search/vector-search/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB University (free courses)&lt;br&gt;
&lt;a href="https://learn.mongodb.com/" rel="noopener noreferrer"&gt;https://learn.mongodb.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voyage AI&lt;br&gt;
&lt;a href="https://docs.voyageai.com/" rel="noopener noreferrer"&gt;https://docs.voyageai.com/&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  See you soon ;)
&lt;/h1&gt;

</description>
      <category>mongodb</category>
      <category>rag</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Como implementar um Ledger em sístemas distribuídos</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Sun, 21 Sep 2025 15:09:59 +0000</pubDate>
      <link>https://forem.com/dvorlandi/como-implementar-um-ledger-em-sistemas-distribuidos-1kbo</link>
      <guid>https://forem.com/dvorlandi/como-implementar-um-ledger-em-sistemas-distribuidos-1kbo</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;O que é um ledger?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Considere um &lt;strong&gt;Ledger&lt;/strong&gt; como um "livro da verdade", por exemplo, uma planilha contábil de uma empresa, onde são registradas todas as transações que aconteceram. Assim como em uma planilha contábil, não editamos ou removemos registros, apenas adicionamos novas entradas. Isso nos garante a &lt;strong&gt;imutabilidade&lt;/strong&gt;, que é um ótimo princípio em sistemas financeiros. A forma mais comum de tratar isso é por meio de eventos de entrada e saída, junto ao montante de valor correspondente para cada transação.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Como fazer?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Primeiramente, é uma prática essencial manter um &lt;strong&gt;Ledger distinto para cada tipo de moeda&lt;/strong&gt;, como BRL ou USD, para simplificar radicalmente a lógica de negócio e os cálculos. Além disso, para prevenir o processamento duplicado em um sistema distribuído, cada operação deve ser acompanhada de uma &lt;strong&gt;chave de idempotência&lt;/strong&gt; única.&lt;/p&gt;

&lt;p&gt;O gerenciamento da &lt;strong&gt;concorrência&lt;/strong&gt; é outro pilar para evitar inconsistências no saldo. Uma abordagem é o &lt;strong&gt;lock otimista&lt;/strong&gt;, que utiliza um campo de versionamento como &lt;code&gt;version&lt;/code&gt; ou &lt;code&gt;last_sequence&lt;/code&gt;. A alternativa é o &lt;strong&gt;lock pessimista&lt;/strong&gt;, que garante acesso exclusivo ao Ledger através de um serviço externo como Redis.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Persistência e Concorrência&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A persistência do Ledger pode ser implementada em um banco de dados como o &lt;strong&gt;MongoDB&lt;/strong&gt;. Para lidar com bloqueios otimistas, utilizamos um campo como &lt;code&gt;last_sequence&lt;/code&gt; no próprio documento do Ledger. Para o bloqueio pessimista, a recomendação é um serviço de cache distribuído onde a latência seja a menor possível, como o Redis.&lt;/p&gt;

&lt;p&gt;A chave de idempotência, por sua vez, depende da estrutura do sistema, mas geralmente é composta por uma combinação de dados como &lt;code&gt;timestamp + from + to + amount&lt;/code&gt;. Essa chave pode ser armazenada em um cache distribuído com um TTL (Time To Live).&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Lidando com Dinheiro em Sistemas Distribuídos&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Por que usar &lt;code&gt;int&lt;/code&gt; e não &lt;code&gt;float&lt;/code&gt;?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Nunca use tipos de ponto flutuante (&lt;code&gt;float&lt;/code&gt;) para armazenar dinheiro. A solução padrão é trabalhar com &lt;strong&gt;inteiros&lt;/strong&gt;, armazenando o valor na &lt;strong&gt;menor unidade da moeda&lt;/strong&gt; (ex: R$ 123,45 é armazenado como o inteiro &lt;code&gt;12345&lt;/code&gt;). Todas as operações matemáticas são feitas com esses inteiros, eliminando erros de precisão.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Estrutura para Múltiplas Moedas&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Valores monetários devem ser representados por uma estrutura que combine o montante e a moeda, seguindo o padrão &lt;strong&gt;ISO 4217&lt;/strong&gt;. Essa estrutura deve conter o &lt;code&gt;amount&lt;/code&gt; (inteiro) e a &lt;code&gt;currency&lt;/code&gt; (ex: "BRL"), prevenindo erros como somar diretamente dólares com reais.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Aplicando o Lock Otimista e Transações&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Para garantir a consistência, o processo de registrar uma transação deve ser atômico. Aqui está um passo a passo mais detalhado de como implementar o fluxo completo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verificação de Idempotência (Fail Fast)&lt;/strong&gt;: Antes de iniciar a transação no banco de dados, verifique a chave de idempotência em um cache rápido como o Redis. Se a chave já existir, significa que a operação já foi processada, e você pode retornar o sucesso imediatamente, evitando trabalho desnecessário.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Início do Loop de Tentativa (Retry Loop)&lt;/strong&gt;: Como o lock otimista pode falhar, toda a lógica de negócio deve rodar dentro de um loop que tentará a operação algumas vezes (ex: 3 tentativas) antes de desistir.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Leitura do Estado Atual&lt;/strong&gt;: Dentro do loop e de uma nova transação do MongoDB, leia o documento do &lt;code&gt;Ledger&lt;/code&gt; para obter seu &lt;code&gt;balance&lt;/code&gt; e &lt;code&gt;last_sequence&lt;/code&gt; atuais.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cálculo em Memória&lt;/strong&gt;: Calcule o novo saldo na sua aplicação. &lt;code&gt;novo_saldo = saldo_atual + valor_da_transação&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Execução da Escrita Atômica&lt;/strong&gt;: Execute as duas operações de escrita dentro da mesma transação:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;insertOne&lt;/code&gt;&lt;/strong&gt; na coleção &lt;code&gt;transactions&lt;/code&gt; com os dados da nova movimentação.&lt;br&gt;
&lt;strong&gt;&lt;code&gt;updateOne&lt;/code&gt;&lt;/strong&gt; na coleção &lt;code&gt;ledgers&lt;/code&gt;. Este update é a chave do lock otimista: ele deve buscar pelo &lt;code&gt;_id&lt;/code&gt; &lt;strong&gt;e&lt;/strong&gt; pela &lt;code&gt;last_sequence&lt;/code&gt; que você leu no passo 3. A atualização irá então modificar o &lt;code&gt;balance&lt;/code&gt; e incrementar o &lt;code&gt;last_sequence&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Resultado&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Sucesso&lt;/strong&gt;: Se o &lt;code&gt;updateOne&lt;/code&gt; encontrar o documento e a transação for concluída (commit), significa que não houve conflito. Você pode sair do loop e retornar o sucesso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Falha&lt;/strong&gt;: Se a transação falhar porque o &lt;code&gt;last_sequence&lt;/code&gt; não correspondeu, significa que outro processo alterou o Ledger. O loop de tentativa continuará para a próxima iteração, reiniciando o processo a partir do passo 3. É uma boa prática adicionar um pequeno tempo de espera (backoff) entre as tentativas.&lt;/p&gt;

&lt;p&gt;Se o loop se esgotar sem sucesso, a operação falhou e um erro deve ser retornado ao cliente.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Como ficam meus dados?&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ledgers
&lt;/h3&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;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ObjectId()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"balance"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BRL"&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;span class="nl"&gt;"last_sequence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"last_transactions"&lt;/span&gt;&lt;span class="p"&gt;:[&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;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ObjectId()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"ledger_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ObjectId()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;UnixTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"sequence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"change"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BRL"&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;span class="nl"&gt;"idempotency_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timestamp-from-to-amount"&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;span class="p"&gt;]&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;h3&gt;
  
  
  transactions
&lt;/h3&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;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ObjectId()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"ledger_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ObjectId()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;UnixTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"sequence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"change"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BRL"&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;span class="nl"&gt;"idempotency_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timestamp-from-to-amount"&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;h2&gt;
  
  
  &lt;strong&gt;Considerações Finais&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Construir um Ledger confiável se baseia em quatro pilares essenciais: &lt;br&gt;
&lt;strong&gt;Imutabilidade&lt;/strong&gt;, garantindo um histórico de transações que é apenas de adição (append-only); &lt;br&gt;
&lt;strong&gt;Precisão&lt;/strong&gt;, usando inteiros para cálculos monetários e evitando erros de ponto flutuante; &lt;br&gt;
&lt;strong&gt;Consistência&lt;/strong&gt;, através de transações atômicas com controle de concorrência como o lock otimista; &lt;br&gt;
&lt;strong&gt;Idempotência&lt;/strong&gt;, para proteger o sistema contra operações duplicadas.&lt;/p&gt;

&lt;p&gt;Uma vez que esses fundamentos estão sólidos, o próximo passo na evolução do sistema é pensar em &lt;strong&gt;escalabilidade&lt;/strong&gt;. Para Ledgers com milhões de transações, técnicas como &lt;strong&gt;Snapshots&lt;/strong&gt; (fotos periódicas do saldo) para otimizar a performance de leitura e o &lt;strong&gt;arquivamento&lt;/strong&gt; de transações antigas tornam-se cruciais para manter o sistema performático a longo prazo.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Arquitetura Baseada em Espaço (SBA - Space-Based Architecture)</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Sat, 23 Aug 2025 20:22:37 +0000</pubDate>
      <link>https://forem.com/dvorlandi/arquitetura-baseada-em-espaco-sba-space-based-architecture-306c</link>
      <guid>https://forem.com/dvorlandi/arquitetura-baseada-em-espaco-sba-space-based-architecture-306c</guid>
      <description>&lt;p&gt;A &lt;strong&gt;Arquitetura Baseada em Espaço (SBA)&lt;/strong&gt; é uma abordagem de design de software que organiza o sistema em torno do conceito de "espaços", que são unidades de funcionalidade isoladas e autônomas. Contrasta com as abordagens mais comuns de serviços de enfileiramento de mensagens, onde os componentes interagem trocando mensagens através de um &lt;em&gt;message broker&lt;/em&gt;. Em vez disso, a SBA utiliza um paradigma de &lt;strong&gt;espaço de tuplas&lt;/strong&gt;, onde os componentes interagem trocando tuplas ou entradas através de um ou mais &lt;strong&gt;espaços compartilhados&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine que, enquanto um &lt;em&gt;message broker&lt;/em&gt; é como uma conferência acadêmica onde os apresentadores falam em ordem, um espaço de tuplas é como uma &lt;em&gt;unconference&lt;/em&gt;, onde todos os participantes podem escrever em um quadro branco comum simultaneamente e ver tudo ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;O objetivo principal da SBA é alcançar a &lt;strong&gt;escalabilidade linear&lt;/strong&gt; de aplicações &lt;em&gt;stateful&lt;/em&gt; e de alto desempenho. Isso é feito construindo aplicações a partir de um conjunto de &lt;strong&gt;unidades de processamento (PUs - Processing Units)&lt;/strong&gt; auto-suficientes e independentes, permitindo que a aplicação escale com a adição de mais unidades. A SBA segue princípios de REST, SOA e EDA, e incorpora elementos de &lt;em&gt;grid computing&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Componentes Essenciais da SBA
&lt;/h3&gt;

&lt;p&gt;A SBA é composta por três partes fundamentais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Unidades de Processamento (PUs - Processing Units)&lt;/strong&gt;: São os blocos de construção básicos do sistema. Cada PU contém sua própria lógica e dados necessários para as tarefas. Elas são independentes, escaláveis e projetadas para serem replicadas, garantindo que outras unidades possam assumir se uma falhar.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Espaço (Space)&lt;/strong&gt;: É onde todos os dados são mantidos, atuando como uma grande &lt;strong&gt;grade de memória distribuída&lt;/strong&gt; onde as informações são armazenadas e compartilhadas. Todas as PUs podem acessar este espaço, garantindo a operação contínua do sistema mesmo com falhas em partes individuais.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Roteador (Router)&lt;/strong&gt;: Funciona como um diretor de tráfego, assegurando que as requisições dos usuários cheguem à PU correta para serem processadas, mantendo o balanceamento e a eficiência das tarefas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Princípios da Arquitetura Baseada em Espaço
&lt;/h3&gt;

&lt;p&gt;A SBA é construída sobre alguns princípios-chave que garantem sua eficácia:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Distribuição&lt;/strong&gt;: Dados e tarefas de processamento são espalhados por múltiplos nós, otimizando a alocação de recursos e acomodando cargas de trabalho variáveis. Isso permite &lt;strong&gt;escalabilidade horizontal&lt;/strong&gt;, onde mais nós podem ser adicionados para gerenciar o crescimento da carga.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Desacoplamento&lt;/strong&gt;: Os componentes operam independentemente uns dos outros, permitindo escalabilidade e tolerância a falhas, pois cada elemento pode ser escalado sem afetar o resto do sistema.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Assincronia&lt;/strong&gt;: Nós se comunicam e coordenam sem esperar por respostas instantâneas, o que aumenta a responsividade e a escalabilidade ao liberar recursos.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resiliência&lt;/strong&gt;: O sistema é capaz de tolerar falhas e manter a funcionalidade através da replicação de dados e tarefas de processamento. Isso garante que funções críticas não sejam afetadas e que o sistema se recupere rapidamente.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Orientada a Eventos&lt;/strong&gt;: Frequentemente, a SBA utiliza arquiteturas orientadas a eventos para promover comunicação e coordenação assíncrona entre os componentes, permitindo que eles reajam a mudanças em tempo real.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vantagens da SBA
&lt;/h3&gt;

&lt;p&gt;As principais vantagens da SBA incluem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Alto grau de isolamento e autonomia&lt;/strong&gt;: Cada "espaço" é independente, o que facilita o teste, a implantação e a evolução do sistema. Desenvolvedores podem trabalhar em diferentes espaços concorrentemente.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Escalabilidade e desempenho aprimorados&lt;/strong&gt;: A capacidade de escalar cada espaço independentemente permite um melhor controle dos recursos e um desempenho otimizado para lidar com grandes volumes de dados e interações de usuários.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resiliência e tolerância a falhas&lt;/strong&gt;: Através da replicação de dados e tarefas, os sistemas SBA podem continuar operando mesmo se nós individuais falharem, garantindo um tempo de atividade contínuo.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Mitigação de gargalos de banco de dados&lt;/strong&gt;: Ao carregar grandes blocos de dados na memória (cache) na inicialização do "espaço", a SBA pode reduzir significativamente a carga no banco de dados, que é frequentemente o gargalo em sistemas escaláveis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Desafios da SBA
&lt;/h3&gt;

&lt;p&gt;Apesar de suas muitas vantagens, a SBA não está isenta de desafios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Complexidade&lt;/strong&gt;: Introduz complexidade adicional relacionada à distribuição de dados, sincronização e tolerância a falhas, o que pode aumentar o custo de desenvolvimento e manutenção.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Consistência dos dados&lt;/strong&gt;: Manter a consistência dos dados em nós distribuídos pode ser difícil. A SBA frequentemente se alinha com o &lt;strong&gt;Teorema CAP&lt;/strong&gt;, priorizando &lt;strong&gt;Disponibilidade&lt;/strong&gt; e &lt;strong&gt;Tolerância a Partições&lt;/strong&gt; em detrimento da &lt;strong&gt;Consistência forte&lt;/strong&gt;, levando a modelos de &lt;strong&gt;consistência eventual&lt;/strong&gt;. Isso significa que as réplicas podem ficar fora de sincronia por um tempo, mas eventualmente se atualizarão. É crucial gerenciar cuidadosamente a possibilidade de perda de dados em caso de falhas.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Gerenciamento de concorrência&lt;/strong&gt;: Acesso concorrente a dados compartilhados em sistemas SBA exige mecanismos robustos de controle de concorrência para evitar conflitos.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Latência de comunicação&lt;/strong&gt;: A latência de comunicação entre nós distribuídos pode impactar o desempenho, exigindo estratégias de otimização como localidade de dados e &lt;em&gt;caching&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SBA na Prática: O Papel da Grade de Dados em Memória (IMDG) com Hazelcast
&lt;/h3&gt;

&lt;p&gt;O conceito de "espaço" na Arquitetura Baseada em Espaço encontra sua realização mais eficaz em uma &lt;strong&gt;Grade de Dados em Memória (IMDG)&lt;/strong&gt;. Uma IMDG é um conjunto de computadores em rede/cluster que agrupam sua RAM para permitir que as aplicações compartilhem dados em alta velocidade. Elas são projetadas para processamento de dados em velocidades extremamente altas e para construir aplicações em larga escala que precisam de mais RAM do que um único servidor pode oferecer.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Hazelcast&lt;/strong&gt; é um excelente exemplo de uma solução IMDG distribuída em memória. Ele suporta uma variedade de estruturas de dados como &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;MultiMap&lt;/code&gt;, &lt;code&gt;RingBuffer&lt;/code&gt; e &lt;code&gt;HyperLogLog&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Como Hazelcast se encaixa na SBA:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;"Espaço" como uma Camada de Dados Operacionais Rápida&lt;/strong&gt;: No contexto da SBA, o Hazelcast atua como a &lt;strong&gt;camada de dados operacionais rápida&lt;/strong&gt; (Fast Operational Data Layer), onde os dados são armazenados e processados em memória para latência ultra-baixa e alto &lt;em&gt;throughput&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sincronização Automática&lt;/strong&gt;: Uma das grandes vantagens do Hazelcast é a capacidade de gerenciar automaticamente a sincronização entre o banco de dados de origem e o cache, aliviando o desenvolvedor da responsabilidade de propagar atualizações manualmente.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Alta Performance e Escalabilidade Elástica&lt;/strong&gt;: Hazelcast é projetado para alto desempenho, com latências que variam de microssegundos a milissegundos, e pode atingir milhões de transações por segundo (TPS). Ele permite escalar de forma elástica e automática, adicionando ou removendo nós conforme a carga de trabalho muda.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Resiliência e Tempo de Atividade (Uptime)&lt;/strong&gt;: O Hazelcast oferece alta resiliência e a capacidade de operar continuamente (Always-On), sendo capaz de garantir 99.999% de tempo de atividade em arquiteturas com replicação &lt;em&gt;cross-cluster&lt;/em&gt; geográfica.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Ampla Variedade de Casos de Uso&lt;/strong&gt;: Hazelcast é ideal para:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Processamento de transações de aplicações *multicloud&lt;/strong&gt;*, como detecção de fraudes em tempo real e processamento de pagamentos.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Modernização de infraestruturas &lt;em&gt;multicloud&lt;/em&gt; para *mainframe&lt;/strong&gt;*, otimizando o desempenho e reduzindo custos.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sistemas de e-commerce e experiência do cliente omni-channel&lt;/strong&gt;, fornecendo visibilidade de inventário em tempo real e alta capacidade de resposta em picos de demanda.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Aplicações de IoT/IIoT e *Edge Computing&lt;/strong&gt;&lt;em&gt;, processando fluxos de dados massivos na borda para *insights&lt;/em&gt; em tempo real.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sistemas de &lt;em&gt;trading&lt;/em&gt; financeiro&lt;/strong&gt;, suportando processamento de transações de alto &lt;em&gt;throughput&lt;/em&gt; e comunicação de baixa latência.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Jogos online&lt;/strong&gt;, onde a baixa latência e a capacidade de acomodar populações flutuantes de jogadores são cruciais.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O Hazelcast IMDG permite que os microsserviços armazenem o resultado de cada tarefa na grade, funcionando como um &lt;em&gt;event bus&lt;/em&gt; clusterizado e um &lt;em&gt;data store&lt;/em&gt; de baixa latência. Isso, juntamente com a capacidade de implantar modelos de Machine Learning gerenciados pelo cluster Hazelcast, o torna uma plataforma de computação operacional em memória completa e poderosa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;A Arquitetura Baseada em Espaço, impulsionada por soluções como o Hazelcast, oferece uma maneira eficaz de construir sistemas que exigem alta &lt;strong&gt;escalabilidade, autonomia, resiliência e desempenho&lt;/strong&gt;. Ao aproveitar a velocidade das grades de dados em memória e a independência das unidades de processamento, as empresas podem lidar com cargas de trabalho massivas, processar dados em tempo real e garantir a continuidade dos negócios em ambientes distribuídos, desde a borda até a nuvem híbrida.&lt;/p&gt;

&lt;p&gt;Embora introduza alguma complexidade no design e na gestão da consistência, os benefícios de um sistema que pode se adaptar dinamicamente ao crescimento e a falhas são inegáveis para as exigências do mundo digital atual. A SBA é, portanto, uma ferramenta valiosa no arsenal de qualquer arquiteto de software que busca construir sistemas de alto desempenho.&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>microservices</category>
      <category>architecture</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Bloom Filters: Variações e Casos de Uso Reais</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Tue, 24 Jun 2025 15:14:56 +0000</pubDate>
      <link>https://forem.com/dvorlandi/bloom-filters-variacoes-e-casos-de-uso-reais-g29</link>
      <guid>https://forem.com/dvorlandi/bloom-filters-variacoes-e-casos-de-uso-reais-g29</guid>
      <description>&lt;p&gt;Você já precisou verificar rapidamente se um elemento pertence a um conjunto gigantesco, sem gastar muita memória? Ou já quis evitar consultas desnecessárias ao banco de dados, acelerando seu sistema? Se sim, está na hora de conhecer (ou aprofundar) o uso dos &lt;strong&gt;Bloom Filters&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Neste artigo, vou explicar o que são Bloom Filters, suas principais variações, mostrar exemplos de empresas que usam essa estrutura e apresentar casos de uso reais para inspirar sua próxima solução.&lt;/p&gt;




&lt;h4&gt;
  
  
  O que é um Bloom Filter?
&lt;/h4&gt;

&lt;p&gt;Um &lt;strong&gt;Bloom Filter&lt;/strong&gt; é uma estrutura de dados probabilística criada por Burton Howard Bloom em 1970. Ele serve para testar se um elemento pertence a um conjunto, com uma característica interessante: pode haver &lt;em&gt;falsos positivos&lt;/em&gt; (dizer que um elemento está no conjunto quando não está), mas nunca &lt;em&gt;falsos negativos&lt;/em&gt; (nunca diz que um elemento não está se ele realmente está).&lt;/p&gt;

&lt;h5&gt;
  
  
  Como funciona?
&lt;/h5&gt;

&lt;p&gt;O Bloom Filter utiliza um array de bits de tamanho fixo e múltiplas funções hash. Para adicionar um elemento, ele é processado por todas as funções hash, e os bits correspondentes no array são marcados como 1. Para verificar se um elemento está presente, basta checar se todos os bits nas posições indicadas pelas funções hash estão em 1. Se algum estiver em 0, o elemento definitivamente não está no conjunto.&lt;/p&gt;

&lt;h5&gt;
  
  
  Principais características
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Eficiência espacial:&lt;/strong&gt; ocupa pouca memória, mesmo para conjuntos enormes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Probabilístico:&lt;/strong&gt; permite falsos positivos, mas nunca falsos negativos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operações rápidas:&lt;/strong&gt; inserção e consulta em tempo constante.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tamanho fixo:&lt;/strong&gt; o array de bits não cresce após a criação.&lt;/li&gt;
&lt;/ul&gt;




&lt;h5&gt;
  
  
  Sobre a taxa de falsos positivos
&lt;/h5&gt;

&lt;p&gt;A taxa de falsos positivos depende de alguns fatores: o tamanho do filtro (quantos bits ele tem), o número de funções hash que você usa e quantos elementos você adiciona ao filtro.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tamanho do filtro:&lt;/strong&gt; Quanto maior o filtro (mais bits), menor a probabilidade de falsos positivos. Um filtro maior tem mais espaço para distribuir os elementos, reduzindo a chance de colisões.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Número de funções hash:&lt;/strong&gt; Usar mais funções hash pode reduzir a taxa de falsos positivos até certo ponto. No entanto, usar funções hash demais pode sobrecarregar o filtro e aumentar a taxa de falsos positivos novamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Número de elementos:&lt;/strong&gt; Quanto mais elementos você adiciona ao filtro, maior a probabilidade de falsos positivos. Isso ocorre porque mais elementos significam mais bits sendo ativados, aumentando a chance de que uma consulta aleatória encontre todos os bits necessários ativados, mesmo que o elemento não esteja realmente no conjunto.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Variações e Evoluções
&lt;/h4&gt;

&lt;p&gt;Com o tempo, surgiram variações para superar limitações do Bloom Filter tradicional:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Counting Bloom Filter:&lt;/strong&gt; Permite remoção de elementos, usando contadores em vez de bits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable Bloom Filter:&lt;/strong&gt; Cresce dinamicamente para suportar conjuntos de tamanho desconhecido, mantendo a taxa de falsos positivos sob controle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cuckoo Filter:&lt;/strong&gt; Usa a técnica de hashing cuckoo, permite remoção eficiente e tem taxa de falsos positivos ainda menor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compressed Bloom Filter:&lt;/strong&gt; Otimizado para transmissão de dados em redes, reduzindo o uso de banda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada variação atende a cenários específicos, como necessidade de remoção, escalabilidade ou transmissão eficiente.&lt;/p&gt;




&lt;h4&gt;
  
  
  Empresas que usam Bloom Filters
&lt;/h4&gt;

&lt;p&gt;Bloom Filters não são apenas teoria – grandes empresas usam essa estrutura em produção:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft (Azure Databricks):&lt;/strong&gt; Otimiza consultas em grandes volumes de dados, descartando rapidamente dados irrelevantes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Chrome:&lt;/strong&gt; Verifica localmente se URLs são maliciosas, reduzindo o tráfego de rede e acelerando a navegação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facebook e Redis:&lt;/strong&gt; Evitam consultas desnecessárias ao banco de dados, melhorando a performance de sistemas de cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bancos e fintechs:&lt;/strong&gt; Validam rapidamente CPFs ou identificadores em listas de fraude, acelerando transações e reduzindo custos.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Casos de Uso Reais
&lt;/h4&gt;

&lt;p&gt;Veja alguns cenários práticos onde Bloom Filters brilham:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filtragem de URLs maliciosas:&lt;/strong&gt; Navegadores usam Bloom Filters para checar se um site é perigoso antes de consultar servidores remotos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validação de cupons:&lt;/strong&gt; E-commerces verificam se um cupom já foi usado sem precisar de listas gigantescas em memória.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache em sistemas distribuídos:&lt;/strong&gt; Antes de buscar um item no banco, verifica-se no Bloom Filter se ele pode estar no cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controle de mensagens processadas:&lt;/strong&gt; Sistemas de filas rastreiam mensagens já processadas, evitando retrabalho.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validação de senhas comuns:&lt;/strong&gt; Serviços de autenticação checam se uma senha está em uma lista de senhas fracas sem armazenar a lista completa.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Limitações e Cuidados
&lt;/h4&gt;

&lt;p&gt;Apesar das vantagens, Bloom Filters têm limitações:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Falsos positivos:&lt;/strong&gt; Não são indicados para cenários que exigem precisão absoluta.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Imutabilidade:&lt;/strong&gt; O filtro tradicional não permite remoção de elementos (a não ser com variações como Counting Bloom Filter).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tamanho fixo:&lt;/strong&gt; É preciso estimar o tamanho do conjunto e a taxa de falsos positivos desejada antes de criar o filtro.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Conclusão
&lt;/h4&gt;

&lt;p&gt;Bloom Filters são ferramentas poderosas para desenvolvedores que precisam de verificações rápidas e eficientes em grandes conjuntos de dados. Seja para otimizar caches, proteger usuários ou acelerar sistemas, essa estrutura pode ser o diferencial de performance que seu projeto precisa.&lt;/p&gt;

&lt;p&gt;Se você ainda não usou Bloom Filters, experimente! E se já usa, compartilhe nos comentários como eles ajudaram no seu projeto.&lt;/p&gt;




&lt;h5&gt;
  
  
  Referências e Leitura Recomendada
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/pt-br/azure/databricks/optimizations/bloom-filters" rel="noopener noreferrer"&gt;Microsoft Learn – Bloom Filters no Azure Databricks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Bloom_filter" rel="noopener noreferrer"&gt;Wikipedia – Bloom Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://42bits.medium.com/analisando-estrutura-de-dados-bloom-filter-a488cd96e2b5" rel="noopener noreferrer"&gt;Medium – Analisando estrutura de dados Bloom Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eximia.co/como-bloom-filter-pode-ser-utilizada-para-melhorar-a-performance/" rel="noopener noreferrer"&gt;EximiaCo – Como Bloom Filter pode ser utilizada para melhorar a performance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Curtiu o artigo? Deixe seu feedback ou dúvidas nos comentários! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Progressive JSON em TypeScript: Carregando e Processando Dados de Forma Incremental</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Tue, 24 Jun 2025 15:10:12 +0000</pubDate>
      <link>https://forem.com/dvorlandi/progressive-json-em-typescript-carregando-e-processando-dados-de-forma-incremental-1464</link>
      <guid>https://forem.com/dvorlandi/progressive-json-em-typescript-carregando-e-processando-dados-de-forma-incremental-1464</guid>
      <description>&lt;p&gt;A partir da necessidade de lidar com grandes volumes de dados e melhorar a experiência do usuário, surgiu a abordagem do Progressive JSON. Inspirada no conceito de imagens progressivas, essa técnica permite transmitir e processar dados JSON em fragmentos, fazendo com que partes importantes da informação sejam exibidas antes do recebimento completo do arquivo. Neste artigo, será apresentada uma visão detalhada do Progressive JSON, com exemplos práticos em TypeScript e orientações para sua implementação tanto no cliente quanto no servidor.&lt;/p&gt;

&lt;h4&gt;
  
  
  O Conceito de Progressive JSON
&lt;/h4&gt;

&lt;p&gt;O Progressive JSON pode ser comparado a um Progressive JPEG, onde as informações são carregadas em “camadas”. Em vez de enviar um JSON completo de uma só vez, o servidor distribui os dados em chunks (pedaços) que possibilitam ao cliente iniciar o processamento e renderização imediatamente. Essa abordagem reduz a latência percebida e melhora a responsividade, especialmente em cenários como dashboards dinâmicos, redes sociais e aplicações de e-commerce.&lt;/p&gt;

&lt;p&gt;Imagine, por exemplo, uma API que retorna um arquivo JSON grande contendo metadados, conteúdo do artigo e comentários de usuários. Com o carregamento progressivo, o cabeçalho e o corpo principal podem ser renderizados imediatamente, enquanto os comentários ou outros dados secundários são carregados posteriormente.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cenários de Uso
&lt;/h4&gt;

&lt;p&gt;Em aplicações modernas, o Progressive JSON se aplica a diversas situações, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dashboards e sistemas de monitoramento, em que dados críticos são exibidos instantaneamente e os detalhes são carregados em background.&lt;/li&gt;
&lt;li&gt;Redes sociais, onde posts e textos principais são renderizados imediatamente e dados adicionais, como comentários e reações, são carregados progressivamente.&lt;/li&gt;
&lt;li&gt;E-commerces, que podem exibir as informações básicas do produto primeiro e carregar avaliações ou recomendações posteriormente.&lt;/li&gt;
&lt;li&gt;Sistemas de conteúdo, permitindo que o texto principal do artigo seja exibido sem esperar por imagens de alta resolução ou conteúdos multimídia adicionais.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa abordagem não só aprimora a experiência final do usuário, mas também distribui melhor a carga no lado do cliente e do servidor, especialmente quando os dados totais são extensos.&lt;/p&gt;

&lt;h4&gt;
  
  
  Funcionamento: Enviando e Consumindo Dados em Fragmentos
&lt;/h4&gt;

&lt;p&gt;No envio de um Progressive JSON, o servidor utiliza mecanismos como “Transfer-Encoding: chunked” para enviar os dados em partes. Cada fragmento pode ser um JSON parcial ou conter placeholders que serão substituídos progressivamente à medida que novos dados chegam.&lt;/p&gt;

&lt;p&gt;No lado do cliente, o uso de streams possibilita a leitura incremental dos dados. Ao utilizar APIs como Fetch com suporte a ReadableStream, o cliente pode decodificar cada chunk recebido e processar os dados conforme chegam.&lt;/p&gt;

&lt;p&gt;Considere o exemplo a seguir, que ilustra um cliente TypeScript lendo Progressive JSON a partir de um endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProgressiveJSONClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetchProgressive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onProgress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;reader&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="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Stream não disponível&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&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="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Preserva dados incompletos&lt;/span&gt;

      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;onProgress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Erro no parsing do trecho:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Processa o que sobrou no buffer&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Erro final de parsing:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código acima, cada linha recebida do stream é decodificada e processada. O método “onProgress” é chamado para cada objeto JSON completo, permitindo que a interface seja atualizada de maneira incremental.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo de Implementação no Servidor com Node.js
&lt;/h4&gt;

&lt;p&gt;Para enviar um Progressive JSON, o servidor pode utilizar o Express e configurar os headers adequados. No exemplo a seguir, o servidor envia os dados em três fragmentos, simulando um cenário real de carregamento progressivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/progressive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transfer-Encoding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chunked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Primeiro chunk: Conteúdo inicial com placeholders&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Simulação de delay para enviar dados progressivamente&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/* $1 */ "Bem-vindo ao blog"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/* $2 */ { "text": "Este é o conteúdo do artigo", "comments": "$3" }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/* $3 */ ["Comentário 1", "Comentário 2"]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Servidor rodando na porta 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo, o servidor inicia enviando um JSON com placeholders. Em seguida, com delays simulados, substitui esses placeholders pelos dados reais, possibilitando que o cliente comece a renderizar o cabeçalho e o conteúdo principal sem precisar esperar a finalização completa do envio.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bibliotecas e Ferramentas para Parsing Progressivo
&lt;/h4&gt;

&lt;p&gt;Para aplicações que exigem o processamento eficiente de grandes volumes de dados JSON, diversas bibliotecas podem facilitar o trabalho. Algumas das mais populares incluem:&lt;/p&gt;

&lt;h5&gt;
  
  
  stream-json
&lt;/h5&gt;

&lt;p&gt;Projetada especificamente para processar grandes arquivos JSON em streams, a biblioteca stream-json permite a leitura e manipulação incremental dos dados. Ela é ideal para situações em que o JSON é grande demais para ser carregado integralmente na memória.&lt;/p&gt;

&lt;p&gt;Exemplo de uso com stream-json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stream-json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;streamValues&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stream-json/streamers/StreamValues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;large-file.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;streamValues&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Valor lido:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Processamento concluído.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  JSONStream
&lt;/h5&gt;

&lt;p&gt;JSONStream é uma biblioteca leve que permite filtrar e transformar dados JSON em tempo real. Ela facilita a propagação de dados para sistemas que trabalham com streams.&lt;/p&gt;

&lt;p&gt;Exemplo de uso com JSONStream (em TypeScript ou JavaScript):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;JSONStream&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JSONStream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;large-file.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSONStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items.*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Processamento do JSON concluído.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  fast-json-parse e jsonparse
&lt;/h5&gt;

&lt;p&gt;Essas bibliotecas oferecem parsing de JSON de forma rápida e com tratamento de erros aprimorado. Enquanto fast-json-parse foca em desempenho e segurança – inclusive com validação de esquemas – o jsonparse é minimalista e útil para parsing baseado em eventos, permitindo tratar dados conforme eles chegam.&lt;/p&gt;

&lt;p&gt;Exemplo simples com fast-json-parse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fast-json-parse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"name": "John", "age": 30}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonString&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Erro no parsing:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JSON parseado:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;Essas ferramentas possibilitam a criação de pipelines de dados robustos, diminuindo o uso de memória e o tempo de resposta, o que é fundamental para aplicações em tempo real.&lt;/p&gt;

&lt;h4&gt;
  
  
  Melhores Práticas no Uso de Progressive JSON
&lt;/h4&gt;

&lt;p&gt;Para garantir que a implementação do Progressive JSON seja eficiente e segura, é importante adotar algumas boas práticas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilizar streams para o processamento de arquivos ou fluxos de dados grandes, evitando o carregamento completo em memória.&lt;/li&gt;
&lt;li&gt;Validar o JSON recebido, principalmente quando há fontes externas ou dados não confiáveis. Ferramentas como AJV podem ser integradas para validar esquemas.&lt;/li&gt;
&lt;li&gt;Definir interfaces e tipos no TypeScript para assegurar a integridade dos dados e evitar erros de tipagem.&lt;/li&gt;
&lt;li&gt;Implementar tratamento robusto de erros, envolvendo operações de parsing com blocos try-catch para capturar e lidar com exceções.&lt;/li&gt;
&lt;li&gt;Garantir que tanto o servidor quanto o cliente tenham mecanismos para lidar com dados incompletos ou corrompidos. O uso de placeholders e identificadores de fragmentos pode simplificar a reconciliação dos dados.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Considerações Finais
&lt;/h4&gt;

&lt;p&gt;O Progressive JSON representa uma técnica valiosa para aplicações modernas, onde a experiência do usuário e a performance são prioridades. Ao transmitir dados em fragmentos, é possível renderizar partes críticas da interface sem esperar pelo carregamento completo, resultando numa sensação de maior agilidade e reatividade.&lt;/p&gt;

&lt;p&gt;A implementação dessa abordagem em projetos TypeScript/Node.js é facilitada pelas diversas bibliotecas e ferramentas disponíveis, como stream-json e JSONStream. Além disso, a adoção de melhores práticas – como a validação dos dados e o tratamento de erros – garante que a aplicação permaneça robusta mesmo sob alto volume de dados.&lt;/p&gt;

&lt;p&gt;O Progressive JSON pode ser a solução ideal em cenários onde a latência e o desempenho são desafios críticos. Se você trabalha com dashboards dinâmicos, aplicações em tempo real ou qualquer sistema que lida com grandes quantidades de dados, vale a pena experimentar essa abordagem e ajustar seu fluxo de dados para oferecer uma experiência aprimorada aos usuários.&lt;/p&gt;

&lt;p&gt;Curtiu o conteúdo? Deixe seus comentários, compartilhe suas experiências e explore ainda mais esse recurso para otimizar suas aplicações!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Entendendo Back Pressure: O Semáforo dos Seus Sistemas Distribuídos</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Fri, 20 Jun 2025 18:45:25 +0000</pubDate>
      <link>https://forem.com/dvorlandi/entendendo-back-pressure-o-semaforo-dos-seus-sistemas-distribuidos-3d7p</link>
      <guid>https://forem.com/dvorlandi/entendendo-back-pressure-o-semaforo-dos-seus-sistemas-distribuidos-3d7p</guid>
      <description>&lt;p&gt;Seu sistema está lento, travando sob carga ou apresentando falhas em cascata? Um dos culpados pode ser a ausência de um mecanismo crucial: &lt;strong&gt;Back Pressure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em sistemas distribuídos, componentes se comunicam constantemente. Um &lt;em&gt;producer&lt;/em&gt; (upstream) envia dados para um &lt;em&gt;consumer&lt;/em&gt; (downstream) processar. Mas o que acontece quando o producer é muito mais rápido que o consumer? O consumer fica sobrecarregado, sua fila de processamento explode, a memória estoura e o sistema inteiro pode cair.&lt;/p&gt;

&lt;p&gt;É aqui que entra o Back Pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é Back Pressure?
&lt;/h2&gt;

&lt;p&gt;Back Pressure é um mecanismo de feedback que permite ao componente &lt;em&gt;consumer&lt;/em&gt; (sobrecarregado) sinalizar ao &lt;em&gt;producer&lt;/em&gt; (rápido demais) para que ele diminua o ritmo ou pare de enviar dados temporariamente.&lt;/p&gt;

&lt;p&gt;Pense nisso como um controle de tráfego. Em vez de deixar os dados fluírem sem controle e causarem um congestionamento, o sistema se autorregula para garantir um fluxo suave e estável.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Analogia do Rio e da Barragem
&lt;/h3&gt;

&lt;p&gt;Para entender de forma intuitiva, imagine um rio (fluxo de dados) e uma barragem (consumer).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em um fluxo normal, a barragem mantém suas comportas abertas, permitindo que a água passe. Se chuvas intensas aumentam drasticamente o volume do rio, a barragem começa a fechar suas comportas. Essa resistência criada é a &lt;strong&gt;back pressure&lt;/strong&gt;. A barragem força o rio a desacelerar, evitando uma inundação na área abaixo dela. Assim que o nível da água se estabiliza, as comportas podem ser abertas novamente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nossos sistemas funcionam da mesma forma: aplicamos resistência (back pressure) para sinalizar que o fluxo precisa ser reduzido, evitando que o serviço a jusante seja "inundado".&lt;/p&gt;

&lt;h2&gt;
  
  
  Como Funciona na Prática?
&lt;/h2&gt;

&lt;p&gt;A implementação de back pressure geralmente envolve alguns conceitos-chave:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Loop de Feedback:&lt;/strong&gt; O consumer monitora sua própria capacidade (CPU, memória, tamanho da fila). Ao se aproximar do limite, ele envia um sinal "desacelere!" para o producer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controle de Fluxo:&lt;/strong&gt; Protocolos como o &lt;strong&gt;TCP&lt;/strong&gt; já possuem mecanismos de controle de fluxo nativos. Em nível de aplicação, podemos usar algoritmos como &lt;em&gt;Leaky Bucket&lt;/em&gt; ou &lt;em&gt;Token Bucket&lt;/em&gt; para limitar a taxa de processamento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gerenciamento de Buffers:&lt;/strong&gt; Em vez de buffers ilimitados que podem causar &lt;code&gt;OutOfMemoryError&lt;/code&gt;, sistemas com back pressure usam buffers limitados ou ajustáveis, que, quando cheios, ativam o sinal de feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processamento Assíncrono:&lt;/strong&gt; Frameworks reativos modernos implementam back pressure de forma assíncrona e não-bloqueante, o que é fundamental para a eficiência de recursos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Por Que Back Pressure é Essencial?
&lt;/h2&gt;

&lt;p&gt;Ignorar o back pressure é uma receita para o desastre em sistemas de alta carga. Implementá-lo corretamente traz benefícios diretos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Previne Sobrecarga e Falhas:&lt;/strong&gt; É a principal linha de defesa contra o efeito dominó, onde a falha de um componente derruba outros em sequência.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Aumenta a Estabilidade:&lt;/strong&gt; O sistema se torna mais previsível e resiliente, operando dentro de limites seguros.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Otimiza Recursos:&lt;/strong&gt; Evita o desperdício de CPU e memória com tentativas de processar uma carga impossível, liberando recursos para operar de forma eficiente.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reduz a Perda de Dados:&lt;/strong&gt; Ao evitar que buffers estourem, garante que os dados enviados sejam de fato processados.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Back Pressure em Ação: Akka Streams
&lt;/h2&gt;

&lt;p&gt;Um excelente exemplo prático é o &lt;strong&gt;Akka Streams&lt;/strong&gt;, um dos membros fundadores da especificação &lt;a href="https://www.reactive-streams.org/" rel="noopener noreferrer"&gt;Reactive Streams&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Em Akka Streams, a comunicação entre os estágios de um fluxo (os &lt;em&gt;operators&lt;/em&gt;) é feita por mensagens assíncronas. Um consumer solicita ao producer um número exato de elementos que ele consegue processar (ex: &lt;code&gt;request(16)&lt;/code&gt;). O producer envia no máximo essa quantidade e depois para, aguardando um novo pedido.&lt;/p&gt;

&lt;p&gt;O ponto principal é que essa espera é &lt;strong&gt;non-blocking&lt;/strong&gt;. O thread do producer não fica parado esperando; ele é liberado para um pool de threads e pode ser usado para outras tarefas. Essa é uma abordagem extremamente eficiente e amigável aos recursos do sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflexão
&lt;/h2&gt;

&lt;p&gt;Ao projetar seu próximo serviço, pergunte-se: "O que acontece se o serviço do qual dependo ficar lento? E o que acontece se meu serviço ficar mais rápido que seus consumidores?". Se a resposta envolver falhas, é hora de implementar uma estratégia de back pressure.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>eventdriven</category>
      <category>programming</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Entendendo Outbox Pattern</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Tue, 10 Jun 2025 19:00:58 +0000</pubDate>
      <link>https://forem.com/dvorlandi/entendendo-outbox-pattern-2jm6</link>
      <guid>https://forem.com/dvorlandi/entendendo-outbox-pattern-2jm6</guid>
      <description>&lt;h2&gt;
  
  
  O que é o Outbox Pattern?
&lt;/h2&gt;

&lt;p&gt;O Outbox Pattern é um padrão arquitetural que garante a consistência entre operações de banco de dados e a publicação de eventos em sistemas distribuídos. O nome "Outbox" não é à toa: a ideia central desse padrão é registrar eventos de domínio em uma tabela especial (a outbox), deixando para um componente externo — chamado de Outbox Publisher — a responsabilidade de processar e publicar esses eventos para outros sistemas.&lt;/p&gt;




&lt;h2&gt;
  
  
  Por que o Outbox Pattern é necessário?
&lt;/h2&gt;

&lt;p&gt;Imagine um cenário em que temos uma ordem de pedido, que pode ser confirmada ou cancelada. Quando um pedido é confirmado ou cancelado, normalmente precisamos não só atualizar o banco de dados, mas também avisar outros sistemas — por exemplo, para atualizar o estoque, enviar e-mails ou notificar o financeiro. Surge então um problema clássico: como garantir que, se o banco de dados foi atualizado, o evento também será publicado? E se a publicação do evento falhar depois que o pedido já foi confirmado no banco?&lt;/p&gt;




&lt;h2&gt;
  
  
  Como o Outbox Pattern funciona na prática?
&lt;/h2&gt;

&lt;p&gt;É aí que entra o Outbox Pattern. Em vez de tentar atualizar o banco e publicar o evento ao mesmo tempo (correndo o risco de uma das operações falhar), fazemos tudo em uma única transação: salvamos o pedido e registramos o evento na tabela de outbox. Essa tabela funciona como uma fila local de eventos que precisam ser processados. Nada é enviado para fora ainda.&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%2F6pkon8lljkzltmf7a9m4.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%2F6pkon8lljkzltmf7a9m4.png" alt=" " width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo prático de uso
&lt;/h2&gt;

&lt;p&gt;Por exemplo, ao confirmar um pedido, você faz algo assim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Atualiza o status do pedido para "CONFIRMADO" no banco de dados.&lt;/li&gt;
&lt;li&gt;Cria um registro na tabela de outbox, dizendo: "Pedido X foi confirmado".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tudo isso acontece dentro da mesma transação. Se der erro, nada é salvo. Se der certo, tanto o pedido quanto o evento ficam registrados de forma atômica.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo de registro na tabela de outbox
&lt;/h2&gt;

&lt;p&gt;Para ilustrar, imagine que o registro na tabela de outbox poderia ter o seguinte formato 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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a1b2c3d4-e5f6-7890-1234-567890abcdef"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aggregate_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pedido-123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aggregate_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pedido"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PedidoConfirmado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"pedido_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pedido-123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cliente_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cliente-456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data_confirmacao"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-06-10T10:00:00Z"&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;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-06-10T09:59:59Z"&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;Nesse exemplo, o &lt;code&gt;payload&lt;/code&gt; contém os dados específicos do evento, como o ID do pedido, o ID do cliente e a data de confirmação.&lt;/p&gt;




&lt;h2&gt;
  
  
  O papel do Outbox Publisher
&lt;/h2&gt;

&lt;p&gt;Depois, entra em cena o Outbox Publisher. Ele é um processo separado, que fica monitorando a tabela de outbox. Periodicamente, ele busca os eventos pendentes, publica cada um deles para um message broker (como Kafka, RabbitMQ, SQS, etc.) e, só então, marca o evento como processado. Se a publicação falhar, o evento permanece na tabela e será tentado novamente depois, garantindo que nada se perca.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo de evento processado
&lt;/h2&gt;

&lt;p&gt;Após a publicação bem-sucedida, o status do evento na tabela de outbox é atualizado:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a1b2c3d4-e5f6-7890-1234-567890abcdef"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aggregate_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pedido-123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aggregate_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pedido"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PedidoConfirmado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"pedido_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pedido-123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cliente_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cliente-456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data_confirmacao"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-06-10T10:00:00Z"&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;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"processed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-06-10T09:59:59Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"processed_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-06-10T10:00:01Z"&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;O campo &lt;code&gt;status&lt;/code&gt; agora é "processed", e o campo &lt;code&gt;processed_at&lt;/code&gt; indica quando o evento foi publicado.&lt;/p&gt;

&lt;p&gt;Se a publicação falhar, o evento pode ser retentado um número limitado de vezes antes de ser movido para uma "dead letter queue" para análise posterior.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vantagens do Outbox Pattern
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistência garantida:&lt;/strong&gt; O pedido só é confirmado se o evento também for registrado, evitando inconsistências entre o banco de dados e os sistemas externos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resiliência:&lt;/strong&gt; Se o broker estiver fora do ar, os eventos ficam guardados na tabela de outbox e serão enviados assim que possível, sem perda de informação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desacoplamento:&lt;/strong&gt; O serviço de pedidos não precisa saber quem vai consumir o evento. Ele só registra o que aconteceu, e o Outbox Publisher cuida do resto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalabilidade e observabilidade:&lt;/strong&gt; É possível monitorar, reprocessar ou até mesmo auditar eventos que ficaram pendentes ou falharam, facilitando a manutenção e a evolução do sistema.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;No fim das contas, o Outbox Pattern é uma forma elegante e robusta de garantir que nada se perde no caminho entre o banco de dados e o mundo externo, mesmo em cenários de falha. Ele é amplamente utilizado em sistemas modernos, principalmente quando você precisa de confiabilidade, rastreabilidade e consistência em ambientes distribuídos.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>eventdriven</category>
      <category>ddd</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Desvendando Event-Driven Architecture e Mensageria em Go com Watermill</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Thu, 29 May 2025 18:34:36 +0000</pubDate>
      <link>https://forem.com/dvorlandi/desvendando-event-driven-architecture-e-mensageria-em-go-com-watermill-387h</link>
      <guid>https://forem.com/dvorlandi/desvendando-event-driven-architecture-e-mensageria-em-go-com-watermill-387h</guid>
      <description>&lt;h4&gt;
  
  
  O que é o Watermill?
&lt;/h4&gt;

&lt;p&gt;O Watermill é uma biblioteca open-source para Go, criada para facilitar o desenvolvimento de aplicações baseadas em eventos e mensagens. Ele abstrai a complexidade dos principais brokers do mercado (Kafka, RabbitMQ, NATS, Google Pub/Sub, Redis Streams, entre outros), oferecendo uma API unificada, simples e extensível. Com o Watermill, você pode construir pipelines de mensagens robustos, escaláveis e resilientes, sem se preocupar com os detalhes de cada sistema de mensageria.&lt;/p&gt;




&lt;h4&gt;
  
  
  Por que usar Watermill?
&lt;/h4&gt;

&lt;p&gt;Sistemas baseados em eventos trazem vantagens como desacoplamento, escalabilidade horizontal e facilidade para implementar padrões como CQRS e Event Sourcing. O Watermill resolve problemas comuns desse tipo de arquitetura, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstração dos brokers: troque Kafka por RabbitMQ (ou vice-versa) sem reescrever sua lógica.&lt;/li&gt;
&lt;li&gt;Middleware plugável: adicione logging, retries, métricas e outras funcionalidades de forma simples.&lt;/li&gt;
&lt;li&gt;Performance: processa centenas de milhares de mensagens por segundo, aproveitando o modelo concorrente do Go.&lt;/li&gt;
&lt;li&gt;Testabilidade: suporte a brokers em memória para testes locais rápidos.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Principais Componentes do Watermill
&lt;/h4&gt;

&lt;p&gt;O Watermill é construído em torno de quatro conceitos principais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Publisher&lt;/strong&gt;: responsável por publicar mensagens em um tópico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscriber&lt;/strong&gt;: consome mensagens de um tópico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Router&lt;/strong&gt;: roteia mensagens entre publishers e subscribers, aplicando middlewares e handlers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Middleware&lt;/strong&gt;: adiciona funcionalidades transversais, como logging, retries, limitação de taxa, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esses componentes se conectam de forma flexível, permitindo criar desde fluxos simples até pipelines complexos de processamento de eventos.&lt;/p&gt;




&lt;h4&gt;
  
  
  Protocolos e Brokers Suportados
&lt;/h4&gt;

&lt;p&gt;O Watermill suporta, de forma oficial, os principais sistemas de mensageria do mercado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;RabbitMQ (AMQP)&lt;/li&gt;
&lt;li&gt;Google Cloud Pub/Sub&lt;/li&gt;
&lt;li&gt;AWS SNS/SQS&lt;/li&gt;
&lt;li&gt;Redis Streams&lt;/li&gt;
&lt;li&gt;SQL (PostgreSQL, MySQL)&lt;/li&gt;
&lt;li&gt;GoChannel (in-memory, ótimo para testes)&lt;/li&gt;
&lt;li&gt;HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isso significa que você pode começar com um broker simples e migrar para algo mais robusto conforme sua aplicação cresce, sem grandes mudanças no código.&lt;/p&gt;




&lt;h4&gt;
  
  
  Exemplo Prático: Publicando e Consumindo Mensagens com Kafka
&lt;/h4&gt;

&lt;p&gt;Vamos ver um exemplo básico de como publicar e consumir mensagens usando Watermill com Kafka. O mesmo padrão vale para outros brokers, mudando apenas a configuração.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pré-requisitos:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go instalado
&lt;/li&gt;
&lt;li&gt;Docker rodando Kafka localmente (veja &lt;a href="https://github.com/ThreeDotsLabs/watermill/blob/master/docker/docker-compose-kafka.yml" rel="noopener noreferrer"&gt;docker-compose aqui&lt;/a&gt;)
&lt;/li&gt;
&lt;li&gt;Dependências instaladas:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  go get github.com/ThreeDotsLabs/watermill
  go get github.com/ThreeDotsLabs/watermill-kafka/v3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Publisher:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/ThreeDotsLabs/watermill"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/ThreeDotsLabs/watermill-kafka/v3/pkg/kafka"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/ThreeDotsLabs/watermill/message"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;watermill&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewStdLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPublisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PublisherConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Brokers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;Marshaler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultMarshaler&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;watermill&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewUUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Olá, Watermill!"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exemplo.topico"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mensagem publicada!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Subscriber:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/ThreeDotsLabs/watermill"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/ThreeDotsLabs/watermill-kafka/v3/pkg/kafka"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/ThreeDotsLabs/watermill/message"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;watermill&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewStdLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSubscriber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubscriberConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Brokers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;Unmarshaler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultMarshaler&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
            &lt;span class="n"&gt;ConsumerGroup&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"exemplo-grupo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;subscriber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"exemplo.topico"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mensagem recebida: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dica:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Para testar localmente, rode o Kafka com Docker, execute o subscriber e depois o publisher. Você verá as mensagens fluindo entre eles.&lt;/p&gt;




&lt;h4&gt;
  
  
  Casos de Uso e Vantagens
&lt;/h4&gt;

&lt;p&gt;O Watermill é ideal para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsserviços que precisam se comunicar de forma assíncrona e desacoplada.&lt;/li&gt;
&lt;li&gt;Sistemas de processamento de eventos em tempo real (monitoramento, analytics, notificações).&lt;/li&gt;
&lt;li&gt;Implementação de padrões como CQRS e Event Sourcing.&lt;/li&gt;
&lt;li&gt;Projetos que exigem escalabilidade horizontal e resiliência.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Entre as vantagens, destacam-se a flexibilidade (suporte a múltiplos brokers), performance, API intuitiva e facilidade de integração com middlewares e métricas (Prometheus).&lt;/p&gt;




&lt;h4&gt;
  
  
  Conclusão
&lt;/h4&gt;

&lt;p&gt;O Watermill é uma excelente escolha para quem quer adotar event-driven architecture e mensageria em Go. Ele abstrai a complexidade dos brokers, oferece uma API poderosa e flexível, e permite construir sistemas modernos, escaláveis e resilientes. Se você quer dar o próximo passo na arquitetura do seu projeto Go, vale muito a pena experimentar o Watermill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links úteis:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://watermill.io/docs/" rel="noopener noreferrer"&gt;Documentação oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ThreeDotsLabs/watermill" rel="noopener noreferrer"&gt;Repositório no GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ThreeDotsLabs/watermill/tree/master/_examples" rel="noopener noreferrer"&gt;Exemplos práticos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se ficou com dúvidas ou quer compartilhar sua experiência com Watermill, deixe um comentário!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>eventdriven</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Tipagem segura e Eficiência com next-safe-action no Next.js</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Fri, 07 Mar 2025 02:14:36 +0000</pubDate>
      <link>https://forem.com/dvorlandi/seguranca-e-eficiencia-com-next-safe-action-no-nextjs-4kna</link>
      <guid>https://forem.com/dvorlandi/seguranca-e-eficiencia-com-next-safe-action-no-nextjs-4kna</guid>
      <description>&lt;h1&gt;
  
  
  Segurança e Eficiência com &lt;code&gt;next-safe-action&lt;/code&gt; no Next.js
&lt;/h1&gt;

&lt;p&gt;O &lt;code&gt;next-safe-action&lt;/code&gt; é uma biblioteca poderosa para fortalecer a segurança e eficiência das Server Actions no Next.js, garantindo tipagem consistente e validação robusta para aplicações que utilizam o &lt;strong&gt;App Router&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  📌 O que é o &lt;code&gt;next-safe-action&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Essa biblioteca foi criada para evitar problemas comuns ao trabalhar com Server Actions, como &lt;strong&gt;dados não validados&lt;/strong&gt;, &lt;strong&gt;erros silenciosos&lt;/strong&gt; e &lt;strong&gt;tipagem inconsistente&lt;/strong&gt; entre o backend e o frontend.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔥 Principais Benefícios:
&lt;/h3&gt;

&lt;p&gt;✅ &lt;strong&gt;API simples e intuitiva&lt;/strong&gt; – fácil de integrar e usar.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Segurança de tipos de ponta a ponta&lt;/strong&gt; – evita erros de tipagem na comunicação entre cliente e servidor.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Validação com Zod e outras bibliotecas&lt;/strong&gt; – garante que apenas dados corretos sejam processados.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Suporte a formulários (Form Actions)&lt;/strong&gt; – facilita a submissão e tratamento de formulários.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Middleware para autenticação e logs&lt;/strong&gt; – permite adicionar camadas de segurança adicionais.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Tratamento avançado de erros&lt;/strong&gt; – fornece um fluxo estruturado para capturar erros e notificá-los corretamente.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Otimizações na UI (atualizações otimistas)&lt;/strong&gt; – melhora a experiência do usuário ao refletir mudanças instantaneamente.&lt;/p&gt;


&lt;h2&gt;
  
  
  🚀 Como Usar o &lt;code&gt;next-safe-action&lt;/code&gt; no Next.js
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1️⃣ Instalando a Biblioteca
&lt;/h3&gt;

&lt;p&gt;Se você usa &lt;strong&gt;Zod&lt;/strong&gt; para validação (recomendado), instale os pacotes necessários:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;next-safe-action zod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2️⃣ Criando um Cliente de Ação
&lt;/h3&gt;

&lt;p&gt;No seu projeto, crie um cliente para centralizar as Server Actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/safe-action.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSafeActionClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-safe-action&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actionClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSafeActionClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3️⃣ Definindo uma Server Action com Validação
&lt;/h3&gt;

&lt;p&gt;Aqui criamos uma ação que atualiza um usuário, garantindo que os dados estejam corretos antes do processamento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;actionClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/safe-action&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nome muito curto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E-mail inválido&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateUserAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actionClient&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;parsedInput&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsedInput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Simulando uma atualização no banco&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Atualizando usuário &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Usuário atualizado com sucesso!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4️⃣ Consumindo a Server Action no Frontend
&lt;/h3&gt;

&lt;p&gt;Agora, utilizamos essa ação em um formulário React.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useAction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-safe-action&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;updateUserAction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/actions/user-actions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateUserAction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ID do usuário&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nome&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;E-mail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Atualizar&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;validationErrors&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validationErrors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💡 Conclusão
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;next-safe-action&lt;/code&gt; facilita o uso seguro e eficiente das Server Actions no Next.js, garantindo &lt;strong&gt;tipagem forte&lt;/strong&gt;, &lt;strong&gt;validação confiável&lt;/strong&gt; e &lt;strong&gt;experiência do usuário aprimorada&lt;/strong&gt;. Se você está construindo aplicações modernas, essa biblioteca é uma excelente adição ao seu stack! 🚀&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>Understanding CQRS and Event Sourcing.</title>
      <dc:creator>Davi Orlandi</dc:creator>
      <pubDate>Mon, 15 Jul 2024 18:04:14 +0000</pubDate>
      <link>https://forem.com/dvorlandi/understanding-cqrs-and-event-sourcing-61m</link>
      <guid>https://forem.com/dvorlandi/understanding-cqrs-and-event-sourcing-61m</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In modern software architecture, ensuring scalability, maintainability, and performance is crucial. Two patterns that help achieve these goals are CQRS (Command Query Responsibility Segregation) and Event Sourcing. This article explores these concepts, their benefits, and how they can be implemented.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CQRS?
&lt;/h2&gt;

&lt;p&gt;CQRS stands for Command Query Responsibility Segregation. It is a pattern that separates read and write operations for a data store. Traditionally, CRUD (Create, Read, Update, Delete) operations are performed on a single model, which can lead to complexity and inefficiency, especially in large-scale systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of CQRS
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: By separating reads and writes, each can be scaled independently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Read models can be optimized for queries, and write models can be optimized for updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Models&lt;/strong&gt;: Separation of concerns makes the codebase cleaner and easier to maintain.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Implementing CQRS
&lt;/h3&gt;

&lt;p&gt;In a CQRS system, commands (writes) and queries (reads) are handled by different models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Command Model&lt;/strong&gt;: Handles state-changing operations (e.g., create, update, delete).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Model&lt;/strong&gt;: Handles read-only operations (e.g., fetch data).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a basic example using TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Command Model&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateUserCommand&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCommandHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateUserCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Logic to handle user creation&lt;/span&gt;
        &lt;span class="c1"&gt;// e.g., save to database&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Query Model&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserQuery&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserQueryHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserQuery&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Logic to fetch user data&lt;/span&gt;
        &lt;span class="c1"&gt;// e.g., retrieve from database&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is Event Sourcing?
&lt;/h2&gt;

&lt;p&gt;Event Sourcing is a pattern where state changes are captured as a sequence of events. Instead of storing the current state, the system stores a series of events that describe state transitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Event Sourcing
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Auditability&lt;/strong&gt;: Every change is recorded, providing a complete audit trail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Replay&lt;/strong&gt;: System state can be reconstructed by replaying events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling&lt;/strong&gt;: Events can be used to integrate with other systems asynchronously.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Implementing Event Sourcing
&lt;/h3&gt;

&lt;p&gt;In an event-sourced system, state changes are represented as events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Event&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCreatedEvent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Event Store&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EventStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getEvents&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Aggregate&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventStore&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserCreatedEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserCreatedEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;user&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEvents&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Combining CQRS and Event Sourcing
&lt;/h2&gt;

&lt;p&gt;CQRS and Event Sourcing complement each other well. Event Sourcing naturally fits the write side of CQRS, where commands result in events that are stored and processed. The read side can use these events to build query models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Command Model (Event Sourced)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCommandHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventStore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateUserCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserCreatedEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Query Model&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserReadModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

    &lt;span class="nf"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserCreatedEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userCommandHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserCommandHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userReadModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserReadModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;userCommandHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CreateUserCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEvents&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;userReadModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userReadModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
