<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Solo</title>
    <description>The latest articles on DEV Community by Solo (@__solo__).</description>
    <link>https://dev.to/__solo__</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%2F3805065%2F53428a3d-7b1f-4dd7-ac62-a466216ca695.jpg</url>
      <title>DEV Community: Solo</title>
      <link>https://dev.to/__solo__</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/__solo__"/>
    <language>en</language>
    <item>
      <title>I used Gossip Glomers to learn distributed systems from zero (and got humbled fast)</title>
      <dc:creator>Solo</dc:creator>
      <pubDate>Wed, 04 Mar 2026 05:14:36 +0000</pubDate>
      <link>https://dev.to/__solo__/i-used-gossip-glomers-to-learn-distributed-systems-from-zero-and-got-humbled-fast-3oj</link>
      <guid>https://dev.to/__solo__/i-used-gossip-glomers-to-learn-distributed-systems-from-zero-and-got-humbled-fast-3oj</guid>
      <description>&lt;p&gt;I started &lt;a href="https://fly.io/dist-sys/1/" rel="noopener noreferrer"&gt;Fly.io’s Gossip Glomers&lt;/a&gt; because I wanted a practical way into distributed systems.&lt;/p&gt;

&lt;p&gt;Books were useful, but I wasn’t &lt;em&gt;feeling&lt;/em&gt; the problems. Gossip Glomers fixed that.&lt;br&gt;&lt;br&gt;
It gave me tiny problems that looked simple, then failed in very non-obvious ways.&lt;/p&gt;

&lt;p&gt;I’m still early in this journey, but here are the lessons that finally clicked for me.&lt;/p&gt;


&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I solved the challenges in Go:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Echo&lt;/li&gt;
&lt;li&gt;Broadcast&lt;/li&gt;
&lt;li&gt;G-Counter&lt;/li&gt;
&lt;li&gt;Unique IDs&lt;/li&gt;
&lt;li&gt;Kafka-style log&lt;/li&gt;
&lt;li&gt;Transactional key-value (eventually consistent sync)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My stack was intentionally boring: Go + Maelstrom’s Go node library + JSON handlers.&lt;br&gt;
&lt;a href="https://github.com/Mukul-svg/Gossip-Glomers-Challenge" rel="noopener noreferrer"&gt;Code&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Aha #1: “Works locally” means nothing without retries + idempotency
&lt;/h2&gt;

&lt;p&gt;Broadcast was my first real slap in the face.&lt;/p&gt;

&lt;p&gt;My first thought was:&lt;br&gt;&lt;br&gt;
“Receive message → forward to neighbors → done.”&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;messages can be duplicated&lt;/li&gt;
&lt;li&gt;RPCs can fail&lt;/li&gt;
&lt;li&gt;peers can miss updates&lt;/li&gt;
&lt;li&gt;clients can race with propagation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern was the turning point:&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="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;alreadySeen&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&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;message_list&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;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;alreadySeen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="k"&gt;break&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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;alreadySeen&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;message_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&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;alreadySeen&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BroadcastResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"broadcast_ok"&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;Why this mattered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;alreadySeen&lt;/code&gt; check made rebroadcast safe.&lt;/li&gt;
&lt;li&gt;I could retry RPCs without fear of corrupting state.&lt;/li&gt;
&lt;li&gt;“At-least-once delivery” became manageable because handlers were idempotent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was my first &lt;strong&gt;real distributed systems instinct&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Retries are useless unless duplicate handling is correct.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Aha #2: CAS loops are the backbone of safe shared updates
&lt;/h2&gt;

&lt;p&gt;In G-Counter and Kafka-style log, I used compare-and-swap loops.&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;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;curr&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;kv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadInt&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="n"&gt;key&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;keyMissing&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;curr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;curr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delta&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;kv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompareAndSwap&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="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;curr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&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="k"&gt;break&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;Why it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read current value&lt;/li&gt;
&lt;li&gt;Compute new value&lt;/li&gt;
&lt;li&gt;Write only if nobody changed it since your read&lt;/li&gt;
&lt;li&gt;Retry if there was contention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This taught me something I’d only heard before:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Concurrency bugs are not fixed by optimism; they’re fixed by atomicity + retry.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Aha #3: topology is not an implementation detail
&lt;/h2&gt;

&lt;p&gt;I used neighbor forwarding in broadcast and skipped sending back to the source.&lt;br&gt;&lt;br&gt;
Even that one small decision noticeably reduces message noise.&lt;/p&gt;

&lt;p&gt;Tradeoff became obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more fanout → faster propagation, more network traffic&lt;/li&gt;
&lt;li&gt;less fanout → cheaper traffic, more staleness risk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before this challenge, topology felt theoretical.&lt;br&gt;&lt;br&gt;
Now it feels like a direct lever on latency and cost.&lt;/p&gt;


&lt;h2&gt;
  
  
  Aha #4: consistency model changes everything you’re allowed to do
&lt;/h2&gt;

&lt;p&gt;In my txn challenge, I used local writes + periodic state sync:&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;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;txn&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;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Txn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;txn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;txn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readLocal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"w"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&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="kt"&gt;float64&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;And sync:&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;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&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;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&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;currVal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;currVal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is great for availability and eventual convergence, but it’s not strict serializable behavior.&lt;br&gt;&lt;br&gt;
And that’s the lesson: &lt;strong&gt;your merge strategy defines your guarantees&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I used to treat consistency labels as abstract terms.&lt;br&gt;&lt;br&gt;
Now I see them as implementation consequences.&lt;/p&gt;




&lt;h2&gt;
  
  
  Things I messed up (so you don’t have to)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I underestimated how often duplicate messages show up.&lt;/li&gt;
&lt;li&gt;I initially treated network failures like exceptional cases, not normal flow.&lt;/li&gt;
&lt;li&gt;I used a slice for dedupe in broadcast (fine early, but not ideal at scale).&lt;/li&gt;
&lt;li&gt;I learned the hard way that “read then write” without CAS is a race factory.&lt;/li&gt;
&lt;li&gt;I replied too early in some flows before thinking through visibility/staleness.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I’d improve next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Replace linear dedupe scan with a &lt;code&gt;map[int]struct{}&lt;/code&gt; in broadcast.&lt;/li&gt;
&lt;li&gt;Add bounded retry/backoff instead of hot retry loops.&lt;/li&gt;
&lt;li&gt;Make txn merge semantics explicit (version vectors / timestamps / CRDT-style merge depending on workload).&lt;/li&gt;
&lt;li&gt;Capture and compare Maelstrom result artifacts more systematically between iterations.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why this challenge was perfect for a beginner like me
&lt;/h2&gt;

&lt;p&gt;Gossip Glomers gave me small, runnable problems where each “tiny” bug taught a core distributed systems rule.&lt;/p&gt;

&lt;p&gt;Not by theory first.&lt;br&gt;&lt;br&gt;
By breaking first.&lt;/p&gt;

&lt;p&gt;That worked really well for me.&lt;/p&gt;

&lt;p&gt;If you’ve done Gossip Glomers too:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;which challenge changed how you think the most — broadcast, counters, or txn?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>programming</category>
      <category>beginners</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
