<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="373747" data-post-id="373747">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jallum" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jallum/120/38850_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jallum
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jstimps" data-post="51" data-topic="72038" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jstimps/48/37213_2.png" class="avatar"> jstimps:</div>
<blockquote>
<p>Cheers! Always happy to be involved in exciting projects!</p>
<p>Some minor feedback on the API. As a new user, I would be confused by using the <code>Key</code> module to encode a value. An excerpt from the tutorial:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">      key = Subspace.pack(course, class)
      value = Key.pack(@total_seats_available)
      Repo.put(tx, key, value)
</code></pre>
</blockquote>
</aside>
<p>Yeah. That’s been pinching me, too. It’s awkward… but the system already has a <code>Tuple</code> module as part of the runtime, so there’s some name clash at least. It’s not a difficult thing to move or rename… but a good module name… anyone got ideas?</p>
<p>It will happily pack <code>binary() | number() | list() | tuple()</code></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373747" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/52">Post #51</a>
	                </div>
	            </div>
              <div id="likers-container-373747" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373747"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #51"></div>
  </section>
</div>
    <div class="postbit" id="373748" data-post-id="373748">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jallum" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jallum/120/38850_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jallum
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jstimps" data-post="50" data-topic="72038" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jstimps/48/37213_2.png" class="avatar"> jstimps:</div>
<blockquote>
<p>This is a good point, but instead of removing the <code>tx</code> I do wonder how it would feel to lean in to it, and make the RYW tx immutable data. If it can be done with still an ergonomic API, you could get one of the benefits of nested transactions, the ability to abandon a subset of operations in the tx, without the IMO confusing semantics that would come from true nesting. The ergonomics might not be there though, since the <code>get</code> would have to return <code>{value, tx}</code> or similar. I could understand going either way. Immutability has served us well though.</p>
</blockquote>
</aside>
<p>I’m <em>not</em> mad at it… there’s a ton of internal task management that would somehow need to be dealt with… I wouldn’t be able to do anything with timers… right now I can expect to have handlers on the process loop for things like that, but if we went pure functions, that wouldn’t be an option. Hrm…</p>
<aside class="quote no-group" data-username="jstimps" data-post="50" data-topic="72038" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jstimps/48/37213_2.png" class="avatar"> jstimps:</div>
<blockquote>
<p>In a new system like Bedrock, I agree that <code>transact</code> is the way. However, <code>{:ok, {:error, _}}</code> as an idiomatic pattern is not ideal.</p>
</blockquote>
</aside>
<p>I just sketched <code>transact</code> semantics out <a href="https://github.com/jallum/bedrock/pull/51/commits/4600fd987f12464285768a0cf33547f212e8454d" rel="noopener nofollow ugc">over here</a>. I reworked the tutorials, too, on that branch to give an idea of what it’d look like. I’m not opposed to the idea of letting anything <em>but</em> an <code>{:error, reason}</code> commit… which would give you a little more flexibility to use other result shapes. As it was, in my sketch, I couldn’t <em>resist</em> allowing plain <code>:ok</code></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373748" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/53">Post #52</a>
	                </div>
	            </div>
              <div id="likers-container-373748" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373748"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #52"></div>
  </section>
</div>
    <div class="postbit" id="373753" data-post-id="373753">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jallum" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jallum/120/38850_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jallum
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>…and here’s what it would look like if <a href="https://github.com/jallum/bedrock/pull/51/commits/d7ac8959925c4bae173515eb4fdfcb27517b289f" rel="noopener nofollow ugc"><em>everything</em> were implicit</a>, like ecto:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Scheduling do
  @total_seats_available 100

  def signup(attends, course, student, class) do
    Repo.transact(fn -&gt;
      rec = Subspace.pack(attends, {student, class})

      case Repo.get(rec) do
        nil -&gt;
          # Not signed up yet, proceed with signup
          class_key = Subspace.pack(course, class)
          seats_data = Repo.get(class_key)
          seats_left = Key.unpack(seats_data)

          if seats_left == 0 do
            {:error, "No remaining seats"}
          else
            # Decrement seats and record signup
            Repo.put(class_key, Key.pack(seats_left - 1))
            Repo.put(rec, &lt;&lt;&gt;&gt;)
          end

        _existing -&gt;
          # Already signed up
          :ok
      end
    end)
  end

  def drop(attends, course, student, class) do
    Repo.transact(fn -&gt;
      rec = Subspace.pack(attends, {student, class})

      case Repo.get(rec) do
        nil -&gt;
          # Not taking this class
          :ok

        _existing -&gt;
          # Increment seats and remove signup
          class_key = Subspace.pack(course, class)
          seats_data = Repo.get(class_key)
          seats_left = Key.unpack(seats_data)

          Repo.put(class_key, Key.pack(seats_left + 1))
          Repo.clear(rec)
      end
    end)
  end

  def available_classes(course) do
    course_range = Subspace.range(course)

    Repo.transact(fn -&gt;
      classes = Repo.get_range(course_range)
        |&gt; Stream.map(fn {packed_class, packed_seats} -&gt;
          class = Subspace.unpack(course, packed_class)
          availability = Key.unpack(packed_seats)
          {class, availability}
        end)
        |&gt; Stream.filter(fn {_class, availability} -&gt; availability &gt; 0 end)
        |&gt; Stream.map(fn {class, _availability} -&gt; class end)
        |&gt; Enum.to_list()
      {:ok, classes}
    end)
  end

  def init(scheduling, course, class_names) do
    scheduling_range = scheduling |&gt; Directory.get_subspace() |&gt; Subspace.range()

    Repo.transact(fn -&gt;
      # Clear the directory
      Repo.clear_range(scheduling_range)

      # Add all classes
      for class_name &lt;- class_names do
        add_class(course, class_name)
      end

      :ok
    end)
  end

  def add_class(course, class) do
    Repo.transact(fn -&gt;
      key = Subspace.pack(course, class)
      value = Key.pack(@total_seats_available)
      Repo.put(key, value)
    end)
  end
end
</code></pre>
<p>…and…</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def switch(attends, course, student, old_class, new_class) do
  Repo.transact(fn -&gt;
    with :ok &lt;- signup(attends, course, student, new_class),
         :ok &lt;- drop(attends, course, student, old_class) do
      {:ok, :switched}
    end
  end)
end
</code></pre>
<p>…other than the <code>Key.pack</code> for values naming pinchpoint that <a class="mention" href="/u/jstimps" rel="nofollow">@jstimps</a> called out, that’s all of of the feedback integrated. If any of the implicit functions are used outside of a <code>transact</code>, they’ll raise.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373753" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/54">Post #53</a>
	                </div>
	            </div>
              <div id="likers-container-373753" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373753"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #53"></div>
  </section>
</div>
    <div class="postbit" id="373769" data-post-id="373769">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jallum" data-post="49" data-topic="72038">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jallum/48/38850_2.png" class="avatar"> jallum:</div>
<blockquote>
<p>The old <code>transaction</code> behaved the same way with respect to <code>rollback/1</code>, but <em>annoyingly wrapped</em> whatever you returned from your transaction function with an <code>:ok</code> tuple, so return <code>your_result</code> and you get <code>{:ok, your_result}</code>… (return <code>:ok</code> and you get <code>{:ok, :ok}</code>).</p>
<p>The fact that the new <code>transact</code> function <em>just leaves your result alone</em> is kind of a cause for joy, though it seems that there’s no (documented) way to just return <code>:ok</code> to commit without a whole tuple.</p>
</blockquote>
</aside>
<p>FINALLY. Now I understand one of the benefits of the new thing. Thanks! <img src="https://forum.elixirforum.com/images/emoji/apple/heart.png?v=15" title=":heart:" class="emoji" alt=":heart:" loading="lazy" width="20" height="20"></p>
<p>Finally an actual objective observable tidbit.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373769" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/55">Post #54</a>
	                </div>
	            </div>
              <div id="likers-container-373769" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373769"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #54"></div>
  </section>
</div>
    <div class="postbit" id="373816" data-post-id="373816">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jstimps" data-post="50" data-topic="72038">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jstimps/48/37213_2.png" class="avatar"> jstimps:</div>
<blockquote>
<p><code>{:ok, {:error, _}}</code> as an idiomatic pattern is not ideal.</p>
</blockquote>
</aside>
<p>It’s not <em>beautiful</em>, no.</p>
<p>I’m beginning to wonder if the underlying problem here is the <em>concept</em> of rolling back. What do we actually use rollbacks for? I suppose they <em>are</em> inherently kinda exception-coded.</p>
<p>Maybe this is a bit avant-garde but I’m wondering if maybe it’s better to think in terms of retries rather than rollbacks. I.e. the same argument as “let it heal” over “let it crash”. Ecto has rollbacks (crashes) but it doesn’t have retries (supervisors).</p>
<p>I have begun to doubt my own argument in favor of <code>transact()</code> here I think. Gonna have to spend more time on this one.</p>
<aside class="quote no-group" data-username="jstimps" data-post="50" data-topic="72038">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jstimps/48/37213_2.png" class="avatar"> jstimps:</div>
<blockquote>
<p>This is a good point, but instead of removing the <code>tx</code> I do wonder how it would feel to lean in to it, and make the RYW tx immutable data.</p>
</blockquote>
</aside>
<p>I have been doing exactly this for my internal transaction API for a while now and I don’t really like it. The problem is that it’s way too easy to accidentally “lose” the transaction struct (even on reads) and violate consistency guarantees.</p>
<p>Fundamentally interacting with the DB is a side-effect and trying to pretend that it’s not seems to make things dangerous. A pure transaction API allows you to observe the side-effect of reading the data while forgetting to write down that you’ve read it.</p>
<p>I feel like I’m walking on eggshells using it and <em>I wrote the entire database</em>. Given that, there is no way I’m exposing it to anyone else.</p>
<p>It’s funny because this is one of very few cases I’ve ever come across where a pure-functional API is less safe than one which mutates global state. Another one is Plug’s <code>get_csrf_token()</code>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373816" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/56">Post #55</a>
	                </div>
	            </div>
              <div id="likers-container-373816" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373816"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #55"></div>
  </section>
</div>
    <div class="postbit" id="373821" data-post-id="373821">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jstimps" data-post="51" data-topic="72038">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jstimps/48/37213_2.png" class="avatar"> jstimps:</div>
<blockquote>
<p>As a new user, I would be confused by using the <code>Key</code> module to encode a value.</p>
</blockquote>
</aside>
<p>Hah, I ran into this exact problem and after much consternation landed on <code>Encoding.Keyset</code>. I did consider both <code>Tuple</code> and <code>Key</code> and didn’t like either for the same reasons. I’m still not sure the compromise is any better though (perhaps I am Solomon).</p>
<p>The real problem is that for the value encodings I <em>desperately</em> want to use <code>Record</code>…</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373821" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/57">Post #56</a>
	                </div>
	            </div>
              <div id="likers-container-373821" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373821"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #56"></div>
  </section>
</div>
    <div class="postbit" id="373832" data-post-id="373832">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jstimps" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jstimps/120/37213_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jstimps
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="56" data-topic="72038">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>A pure transaction API allows you to observe the side-effect of reading the data while forgetting to write down that you’ve read it.</p>
</blockquote>
</aside>
<p>Yes, this convinced me. I can see why the immutable approach isn’t right here. The get is not a get, it’s a get+add_read_conflict. However this is an implementation detail, so in a pure API it becomes a leaky abstraction. Very weird! Thanks for the insight!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373832" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/58">Post #57</a>
	                </div>
	            </div>
              <div id="likers-container-373832" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373832"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #57"></div>
  </section>
</div>
    <div class="postbit" id="373834" data-post-id="373834">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Asd" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Asd
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>19 files changed +2160 -616 lines changed</p>
</blockquote>
<p>Average commit above. I think that average is about 2k lines of code change a day. Too bad they didn’t invent vibe reading, cause I definitely can’t keep up with this to read and understand all the changes <img src="https://forum.elixirforum.com/images/emoji/apple/grin.png?v=15" title=":grin:" class="emoji" alt=":grin:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373834" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/59">Post #58</a>
	                </div>
	            </div>
              <div id="likers-container-373834" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373834"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #58"></div>
  </section>
</div>
    <div class="postbit" id="373853" data-post-id="373853">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jallum" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jallum/120/38850_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jallum
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>*It’s made with Autism, so you <em>know it’s good.</em> <img src="https://forum.elixirforum.com/images/emoji/apple/grin.png?v=15" title=":grin:" class="emoji" alt=":grin:" loading="lazy" width="20" height="20"></p>
<p>Seriously, though. I <em>love</em> to talk about this stuff, and I’m more than happy to info dump about any aspect of the code, how it works, why I made a particular choice, etc.</p>
<p>FoundationDB’s design is <em>wonderful</em>, but they’re <em>horrible</em> at explaining how their own system works – and <em>my</em> docs aren’t that much better, <em>yet</em>. There’s a lot to take in… and a lot of interesting ideas in this space… so, ask on this thread, start another one, the <a href="https://elixir-lang.slack.com/join/shared_invite/zt-2bo9jdbz8-rpKM2~paQkDOSFFljTdzzg#/shared-invite/email" rel="noopener nofollow ugc">elixir slack</a>, dm, whatever.</p>
<p>Every time I’ve had a conversation about this beast, I’ve come away with new ideas, better perspectives and things I’ve learned from the person I’m talking to. There are a lot of smart people here that think differently than I do, and it’s fun and interesting to see this project from their point of view. So, if you have a question, don’t hold on to it!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373853" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/60">Post #59</a>
	                </div>
	            </div>
              <div id="likers-container-373853" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373853"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #59"></div>
  </section>
</div>
    <div class="postbit" id="373981" data-post-id="373981">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jallum" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jallum/120/38850_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jallum
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Hey folks <img src="https://forum.elixirforum.com/images/emoji/apple/wave.png?v=15" title=":wave:" class="emoji" alt=":wave:" loading="lazy" width="20" height="20"></p>
<p>Quick update on Bedrock! Just released v0.3.0-rc4 with some major API improvements based on community feedback.</p>
<p><strong>What changed:</strong></p>
<p>The transaction API got much cleaner. Instead of threading a transaction handle everywhere:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># Before - explicit transaction threading
transaction(fn tx -&gt;
  put(tx, "user:123", user_data)
  get(tx, "config:app")
end)

# After - implicit context + Ecto-style returns
{:ok, config} = transact(fn -&gt;
  put("user:123", user_data)
  config = get("config:app")
  {:ok, config}
end)
</code></pre>
<p>Subspaces are no more! The new <em>Keyspace</em> system replaces the old Subspace concept and features built-in encoding support:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># Works great with the directory layer
{:ok, app_dir} = Directory.create_or_open(["app"])
users = Keyspace.partition(app_dir, "users", key_encoding: Tuple, value_encoding: BERT)

# Familiar things are still here
alice_key = users |&gt; Keyspace.pack({"alice", 42}) # still makes keys, but you get more control over *how*

# gets / puts / etc. use the Keyspace as context for understanding how to encode and decode your data
%{name: "John", age: 23} = Repo.get(users, 42)

:ok = Repo.put(users, 42, %{name: "John", age: 23})

# Range operations will decode and values for you, too, if you want:
Repo.get_range(users) |&gt; Enum.to_list()
[
  {42, %{name: "John", age: 23}}
  {63, %{name: "Jane", age: 25}}
]
</code></pre>
<p>Also simplified conflict management, improved error handling, and streamlined the range operations.</p>
<h2><a name="p-373981-why-this-matters-1" class="anchor" href="#p-373981-why-this-matters-1" aria-label="Heading link" rel="nofollow"></a>Why this matters:</h2>
<p>These changes make Bedrock much more ergonomic for daily use while keeping all the other goodness intact. The API now feels more “Elixir-native” rather than being a direct port of FoundationDB patterns.</p>
<p>The encoding system is particularly nice - you can plug in custom serialization for keys/values while the keyspace handles encoding automatically. Great for when you want structured data but it gets out of your way if want to manage binary keys and values directly. It’s made the class scheduling example <em>very</em> succinct.</p>
<p>This version focuses on the concrete improvements users will see, shows before/after code examples, and explains why the changes matter for real applications. The suggestions here have been phenomenal, and I’ve tried my best to integrate them all.</p>
<p>Always interested in <em>more</em> feedback, especially if you’ve worked with FoundationDB or other distributed stores!</p>
<p><a href="https://livebook.dev/run?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjallum%2Fbedrock%2Frefs%2Fheads%2Fdevelop%2Flivebooks%2Fclass_scheduling.livemd" rel="noopener nofollow ugc"><img src="https://livebook.dev/badge/v1/blue.svg" alt="Run in Livebook" width="170" height="40"></a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="373981" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/bedrock-a-scaleable-distributed-key-value-database-with-better-than-acid-guarantees/72038/61">Post #60</a>
	                </div>
	            </div>
              <div id="likers-container-373981" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="373981"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #60"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/72038/load_more?page=7">Load more posts (7 remaining)</a>
</div></template></turbo-stream>