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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="apog" data-post="12" data-topic="16315">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/a/7cd45c/48.png" class="avatar"> apog:</div>
<blockquote>
<p>I was hoping there was some sort of convention in the phoenix community around where to access the database and was the general structure should be.</p>
</blockquote>
</aside>
<p><a href="https://youtu.be/rI8tNMsozo0?t=744" rel="noopener nofollow ugc">Programmers know the benefit of everything and the tradeoffs of nothing.</a></p>
<p>Phoenix gives you a range of choices and the different choices are about different sets of tradeoffs - so it is ultimately up to the developer to choose the tradeoffs that are most beneficial to the situation at hand.</p>
<ul>
<li>“Phoenix is your application” is easy to learn and a fast <em>initial</em> development style; i.e. has a short time-to-initial-success but tends to sacrifice maintainability.</li>
<li>“Phoenix contexts” and “umbrella projects” attempt to improve maintainability at the cost of slowing you down with refactoring to maintain the appropriate level of separation and boundaries which tend to introduce a a bit more code and possibly complexity required for the improved decoupling.</li>
<li>Bare path dependencies maximize decoupling (if done correctly) but also introduces <a href="https://forum.elixirforum.com/t/is-phoenix-reactive-like-the-play-framework/1504/8" rel="nofollow">more overhead</a>.</li>
</ul>
<blockquote>
<p>why wouldn’t you still be able to use <a href="https://hexdocs.pm/ecto/Ecto.Changeset.html" rel="noopener nofollow ugc"><code>Ecto.Changeset</code></a> for data validation?</p>
</blockquote>
<p>Because the idea behind <code>Ecto</code> hiding behind <code>Todo.Database</code> is to not let the fact that <code>Ecto</code> is being used <em>leak</em> out - otherwise what is the point in encapsulating it, it is supposed to be an implementation detail.</p>
<p>That being said there are plans to <a href="https://forum.elixirforum.com/t/how-to-keep-ecto-out-of-web-layer/12714/8" rel="nofollow">move the SQL and migration functionality into separate packages</a> so that core <code>Ecto</code> is about data, not databases. However even having a canonical data schema throughout the <em>entire system</em> can lead to problems with unnecessary coupling.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="95196" data-batch-url="/posts/batch_likers">
                        2
                      </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/design-pattern-for-a-genserver-that-needs-to-get-state-from-the-database/16315/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-95196" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="95196"
                     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 #12"></div>
  </section>
</div>
    <div class="postbit" id="95200" data-post-id="95200">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="apog" data-post="12" data-topic="16315">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/a/7cd45c/48.png" class="avatar"> apog:</div>
<blockquote>
<p>For your second bullet, why wouldn’t you still be able to use <a href="https://hexdocs.pm/ecto/Ecto.Changeset.html" rel="noopener nofollow ugc"> <code>Ecto.Changeset</code> </a>for data validation? The database module would still check the validity of the data before calling repo to persist.</p>
</blockquote>
</aside>
<p>Say you go the path of using a GenServer to handle your commands and mutate state of your entity (e.g. <code>%Todo{}</code>). The reason for doing so is to decouple your business logic of managing Todo’s from the database implementation details. (There’s a good discussion <a href="https://forum.elixirforum.com/t/ecto-is-not-your-application-how-to-register-your-persistence-application/16090" rel="nofollow">here</a>).</p>
<p>If you use <code>Ecto.Changeset</code> and/or <code>Ecto.Schema</code> in your GenServer, or the state uses the database schema / changesets you lose that decoupling.</p>
<p>Here’s a rule of thumb: <em>if your entities are simple like a <code>Todo</code> or a <code>Post</code> where pretty much all the logic is captured by create, read, update, and delete, just use Ecto to represent your entity</em>. If CRUD is fine, build  your functions and changesets as you see in the Phoenix/Ecto docs. Think about your context boundaries and you’ll be served well.</p>
<p>But what if your entity is not simply represented by CRUD? Here are some things to consider using other patterns like you described:</p>
<ul>
<li>Run-time characteristics: Maybe your entity encapsulates a business process. It has a <code>Status</code> field. You’ve got state-machine use cases to consider. You can still use CRUD here, but you’ll need more domain specific commands than CRUD.</li>
<li>You have a persistence layer that isn’t as nice as Ecto. Your persistence/query layers are nasty enough you plan to switch out the database later. You really don’t want to do anything else other than change a config to switch the persistence strategy you’re using.</li>
<li>Your business logic calls for <a href="https://martinfowler.com/bliki/OrmHate.html" rel="noopener nofollow ugc">a representation of state that is different from what your well-designed relational database looks like</a>.</li>
</ul>
<p>Like what <a class="mention" href="/u/peerreynders" rel="nofollow">@peerreynders</a> said, it’s about trade-offs and knowing what they are and when to use them. Using a behavior to decouple your database in a config is extra development. Using a GenServer as a command handler and persisting when necessary also has overhead in development time and complexity. In many cases the trade-offs aren’t worth 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="95200" 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/design-pattern-for-a-genserver-that-needs-to-get-state-from-the-database/16315/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-95200" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="95200"
                     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 #13"></div>
  </section>
</div>
    <div class="postbit" id="95204" data-post-id="95204">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="apog" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  apog
                    <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="MrDoops" data-post="14" data-topic="16315">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mrdoops/48/7118_2.png" class="avatar"> MrDoops:</div>
<blockquote>
<p>Think about your context boundaries and you’ll be served well.</p>
</blockquote>
</aside>
<p>This is essentially what I was trying to figure out. I don’t know what the boundaries are supposed to be and wanted to avoid any code-smells around how I was using my ecto repo. But it sounds like what I am doing now (calling the database through repo from within my genserver) is an acceptable thing to do, but that there are other high level design choices I should be aware of (like umbrella apps, and what <a class="mention" href="/u/peerreynders" rel="nofollow">@peerreynders</a> calls  bare path dependencies).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="95204" 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/design-pattern-for-a-genserver-that-needs-to-get-state-from-the-database/16315/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-95204" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="95204"
                     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 #14"></div>
  </section>
</div>
    <div class="postbit" id="97850" data-post-id="97850">
  <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">
								<p>IMO accepting Ecto as a dependency even in your domain modules is quite fine. In my eyes the point is not to achieve 100% isolation; the point is to achieve agnosticism about storage details in your higher-level code.</p>
<p>I have successfully used <code>Ecto.Changeset</code> and <code>Ecto.Multi</code> to carry around changes, validation and an accumulated transaction (to be executed later when a certain user workflow finishes, say when finalizing a cart and actually making an order) in my business methods. The idea of those business methods for me was to not care what queries, updates and inserts are needed to get the job done, <strong><em>and not that underneath there might be no DB at all</em></strong>. This is further supported by the fact that you can use <code>Ecto.Changeset</code> without any database if you so desire. (As <a class="mention" href="/u/peerreynders" rel="nofollow">@peerreynders</a> mentioned, Ecto will be split in two: a DB-specific and a DB-agnostic library.)</p>
<p>And finally, if you have a business method that uses your storage-knowing methods and only depends on <code>Ecto.Changeset</code> and <code>Ecto.Multi</code>, decoupling those is a minor-to-moderate refactoring effort. And that would only ever be necessary if your app(s) evolve to the point of needing a fully storage-agnostic code; not something you see every day (most corporations would sooner finance a Mars exploration campaign before switching away from their DB engine of choice). It’s a good tradeoff between productivity now and less refactoring pain later.</p>
<p>Fixating too much on academic purity can and will hurt productivity and velocity. Do what your future self will thank you for.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="97850" 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/design-pattern-for-a-genserver-that-needs-to-get-state-from-the-database/16315/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-97850" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="97850"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>