<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="179073" data-post-id="179073">
  <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>I think you are suffering from analysis paralysis… or have too much free time. <img src="https://forum.elixirforum.com/uploads/default/original/2X/6/6c3193d1dd46244da3c8c6f719c9f5e2abdd5ae8.gif?v=15" title=":003:" class="emoji emoji-custom" alt=":003:" loading="lazy" width="20" height="20"></p>
<p>Filter everything you do through practical concerns <em>first and foremost</em>:</p>
<ol>
<li>Erlang/Elixir are not that great for CLI apps: slow startup time, potentially superfluous OTP baggage.</li>
<li>Your tool is a simple relay. It has no functional core as it has been pointed out.</li>
<li>Hexagonal is kinda sorta implemented already by Phoenix: it isolates the web stuff through Endpoint / Router and macros injecting code in various places so your code can be mostly purely functional (minus DB and session state). Additionally, you are expected to achieve Hexagonal architecture through contexts: your business code should be completely unaware of how the data is stored: it receives primitive parameters and/or structs, does something with them, and returns other primitive values and/or structs. It shouldn’t contain any calls to Ecto functions, for example. <em>(Although I do make an exception for <code>Changeset</code> whose functionality has come very handy many times.)</em></li>
</ol>
<hr>
<p>Hexagonal is quite simple to summarise for everyday work even if that omits some important details: use purely functional code absolutely everywhere you can (<strong>no side effects</strong>: meaning no DB, no file changes, etc.) and then only use imperative code (i.e. the one that mutates state) where you absolutely can’t avoid it – like when you have to store stuff in the DB or change the user’s session.</p>
<hr>
<p>As a general advice: when you have a practical goal you should get more done and think less until you arrive at the point where you feel a refactoring should be done because you find yourself fighting with your code when you need to add new features or fix a bug.</p>
<p>The process you are trying to follow now is setting you up to become an academic: you are overthinking, having an analysis paralysis and almost nothing will get done as a result.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179073" 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/hexagonal-architecture-in-elixir/32225/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-179073" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179073"
                     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 #11"></div>
  </section>
</div>
    <div class="postbit" id="179092" data-post-id="179092">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Fl4m3Ph03n1x" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Fl4m3Ph03n1x/120/11709_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Fl4m3Ph03n1x
                    <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="dimitarvp" data-post="12" data-topic="32225">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>or have too much free time.</p>
</blockquote>
</aside>
<p>As a father of a hyperactive baby who has to conciliate remote work with chores, taking care of him and working, while also having to do an active effort to keep my mental sanity from exploding after being confined for over 3 months, I genuinely wish “Having too much free time” was the case here <img src="https://forum.elixirforum.com/images/emoji/apple/stuck_out_tongue.png?v=15" title=":stuck_out_tongue:" class="emoji" alt=":stuck_out_tongue:" loading="lazy" width="20" height="20"></p>
<p>Truth be told, I want to go on vacations, but if I can’t leave my home, then there is no point. No matter what everyone says, that physic guy who is charging you 50 bucks so your soul can have a nice trip to Yellow Stone and you can experience it is kinda ripping you off. Don’t trust shady psychics man!  Everyone knows a soul trip to Yellow Stone should be at least <em>half</em> of that. <img src="https://forum.elixirforum.com/images/emoji/apple/smiley.png?v=15" title=":smiley:" class="emoji" alt=":smiley:" loading="lazy" width="20" height="20"></p>
<aside class="quote no-group" data-username="dimitarvp" data-post="12" data-topic="32225">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>I think you are suffering from analysis paralysis</p>
</blockquote>
</aside>
<p>I like to think this is the case. Makes me feel smart <img src="https://forum.elixirforum.com/images/emoji/apple/smiley.png?v=15" title=":smiley:" class="emoji" alt=":smiley:" loading="lazy" width="20" height="20"></p>
<aside class="quote no-group" data-username="dimitarvp" data-post="12" data-topic="32225">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>The process you are trying to follow now is setting you up to become an academic: you are overthinking, having an analysis paralysis and almost nothing will get done as a result.</p>
</blockquote>
</aside>
<p>Funny you mention that because for a great part of my life I was one.</p>
<p>Anyway, I have a very quick and dirty app that does what I want. I am not trying to refactor it to fit the architecture.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179092" 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/hexagonal-architecture-in-elixir/32225/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-179092" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179092"
                     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="179489" data-post-id="179489">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I had a period when I studied Hexagonal, onion and other architectures and London vs Detroit schools. I find them all different ways to achieve the same thing: split business logic from implementation details.</p>
<p>There are two main benefits that I see:</p>
<ul>
<li>your business code usually changes more often than implementation details, so it is a less mental burden to change it when it doesn’t touch DB, HTTP params and what-not</li>
<li>if you decide to change the database (a rather rare occurrence, but sometimes scaling requires this), stuff is less tangled, and you don’t break the business logic</li>
</ul>
<p>What they don’t tell you is how are you going to pay for it.<br>
Doing everything via the interface is another layer of abstraction. It is also easy to miss the rule and use the direct call in the code. Elixir doesn’t have interfaces. The closest thing is behaviours. They have quite a lot of boilerplate because it is a separate module usually in a separate file.</p>
<p>Plus, you need another layer of configuration for specifying which implementation to use (config.exs is a bad fit for that).</p>
<p>That’s why I like an approach described by Rafał Studnicki in this talk: <a href="https://www.youtube.com/watch?v=XGeK9q6yjsg" rel="noopener nofollow ugc">https://www.youtube.com/watch?v=XGeK9q6yjsg</a> He splits every use case into three sets of files: Model - pure business logic, IO - external dependencies like DB, and service - which coordinates. The rules are:</p>
<p>Models can’t use anything in IO or Service to not pollute business logic.<br>
IO can use Models (mainly, if you read something from DB, you translate it to Model instead of returning raw schemas)<br>
Services call IO and Model functions and can be the place to choose proper implementation (if there is one, direct calls are sufficient).</p>
<p>For projects I worked on, it is the lightest approach with the least amount of trade-offs.</p>
<p>There are, of course, trade-offs:</p>
<ul>
<li>typically, the web layer can extract information from Ecto.Schema and use it (have you wondered how Phoenix.Form decides on which form it should use PUT and POST?), if you use this approach, you need to distinguish yourself</li>
<li>you define schemas for your DB and often define an almost identical struct for your Model</li>
</ul>
<p>Any architectural patterns can pay off in more significant projects where you often jump between implementing different parts of business logic.</p>
<p>As for TDD with or without mocks. The SQL.Sandbox abstraction makes running tests asynchronously and in isolation so straightforward that not using real DB in tests seems wrong. There is no downside to doing it the simple way. I only use mocks for calling external services.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179489" data-batch-url="/posts/batch_likers">
                        17
                      </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/hexagonal-architecture-in-elixir/32225/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-179489" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179489"
                     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="179713" data-post-id="179713">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I worked for the better part of a year on a Phoenix Application that ended up being something like a GraphQL - DDD - CQRS - Hexagonal like architecture.</p>
<p>It started a small innocent Phoenix HTML server but well thing got complex very fast and we had to structure it better than with contexts, plus we ended up needing a separate front-end app.</p>
<p>I quit last month to work elsewhere, but it was a good architecture. I now work on a node.js mess, and I regret it every day.</p>
<p>I do not know what exactly where I can help, but here is where the architecture ended up when I left. (the app is named Kairos)</p>
<p>(I did leave out some very specific and legacy stuff for clarity)</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">/kairos_domain  &lt;-- where the business logic lives
	/aggregates   &lt;-- the aggregate modules + structs per DDD teachings
	/services     &lt;-- other domain relatated logic
/kairos_command &lt;-- the "write" part of the application
	/commands     &lt;-- the commands dispatched from the GraphQL mutations mostly
	/ports        &lt;-- the interfaces for the commands to interact with dependencies
/kairos_query   &lt;-- the "read" part of the application
	/queries      &lt;-- the queries dispatched from the GraphQL query resolvers 
	/models       &lt;-- read structs
/kairos_infra   &lt;-- the infrastructure
	/repositories &lt;-- the repositories, getting data from the database, and adapting to domain aggregates
	/tables       &lt;-- ecto structs
	/adapters     &lt;-- the adapter modules to go from aggregates to ecto struct and the otherway around
	/dataloaders  &lt;-- the dataloaders to read ecto structs with caching for better request with absinthe
/kairos_web     &lt;-- the application part
	endpoint.ex   &lt;-- phoenix endpoint
	router.ex     &lt;-- phoenix router
	schema.ex     &lt;-- absinthe graphql schema
	/schema       &lt;-- absinthe graphql types
  /adapters     &lt;-- adapters between mutations and commands, or between query models and graphql objects
</code></pre>
<p>Port were implemented this way :</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule KairosCommand.Ports.ShiftAggregateRepository do
  defmodule Behaviour do
    alias KairosDomain.ShiftAggregate

    @type uuid :: String.t()

    @callback get(id :: uuid) ::
                {:ok, ShiftAggregate.t()}
                | {:error, {:resource_not_found, [name: :shift_aggregate, id: String.t()]}}
                | {:error, term}

    @callback save(ShiftAggregate.t()) ::
                {:ok, ShiftAggregate.t()}
                | {:error, {:validation_error, [KairosDomain.ValidationError.t()]}}
                | {:error, {:resource_not_found, [name: :shift_aggregate, id: String.t()]}}
                | {:error, term}

    @callback delete(ShiftAggregate.t()) ::
                {:ok, :deleted}
                | {:error, {:resource_not_found, [name: :shift_aggregate, id: String.t()]}}
                | {:error, term}
  end

  @behaviour Behaviour

  @impl_module Application.get_env(
                 :kairos,
                 :shift_aggregate_repository,
                 KairosInfra.ShiftAggregateRepository
               )

  @impl Behaviour
  defdelegate get(id), to: @impl_module

  @impl Behaviour
  defdelegate save(shift_aggregate), to: @impl_module

  @impl Behaviour
  defdelegate delete(shift_aggregate), to: @impl_module
end

</code></pre>
<p>For the tests, in the test config you can specify a mock module (using mox for example, we used a fork of mox named erzats for the job) to use only unit tests. It simlifies immensly your life when your database model is quite complexe as was ours. You can than return whatever you want from the repositories, and not having to insert tens of ecto structs in the right order.</p>
<p>We did nice things with the command module, structs that represented the command, and a protocol implementation for the command handler. But it is a bit out of scope.</p>
<p>Feel free to ask any questions you want. I do not know to help you on your discovery, but would love to help <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" 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="179713" data-batch-url="/posts/batch_likers">
                        8
                      </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/hexagonal-architecture-in-elixir/32225/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-179713" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179713"
                     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="179715" data-post-id="179715">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Fl4m3Ph03n1x" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Fl4m3Ph03n1x/120/11709_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Fl4m3Ph03n1x
                    <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>I see you took inspiration in Commands and Queries. Perhaps you followed this pattern?</p><aside class="onebox allowlistedgeneric" data-onebox-src="https://martinfowler.com/bliki/CQRS.html">
  <header class="source">

      <a href="https://martinfowler.com/bliki/CQRS.html" target="_blank" rel="noopener nofollow ugc">martinfowler.com</a>
  </header>

  <article class="onebox-body">
    <div class="aspect-image" style="--aspect-ratio:637/464;"><img src="https://martinfowler.com/bliki/images/cqrs/cqrs.png" class="thumbnail" alt="" width="637" height="464"></div>

<h3><a href="https://martinfowler.com/bliki/CQRS.html" target="_blank" rel="noopener nofollow ugc">bliki: CQRS</a></h3>

  <p>CQRS (Command Query Responsibility Segregation) is the notion that you can use a different model to update information than the model you use to read information</p>


  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>

<p>The way I see it, my code has a similar structure in the sense where I also make ports (the interfaces) and adapters (their impls) explicit and I also use behaviours to model interfaces.</p>
<p>I don’t use however the notion of Commands and Queries, Martin Fowler does mention it adds risky complexity so I wonder how you dealt with 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="179715" 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/hexagonal-architecture-in-elixir/32225/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-179715" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179715"
                     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 #15"></div>
  </section>
</div>
    <div class="postbit" id="179729" data-post-id="179729">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The fact is we did not indent from the start to use Commands and Queries, but as we used GraphQL, it kinda appeared naturally.<br>
GraphQL mutations are natural commands. It added a lot of clarity for us to separate mutation/command from queries. Because for the query part we had to use the dataloader lib, which has a very specific way of working.</p>
<p>This is the protocol used to dispatch the commands :</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defprotocol KairosCommand do
  @moduledoc """
  KairosCommand is the modules in which the usecase / commands that define your applications
  actions are.

  All Commands should implement this protocol to ease the call and the formatting of the parameters
  """

  alias KairosCommand.Context

  @type result :: term
  @type reason :: term

  @doc "modify the builder data with the opts (keyword list of the params)"
  @spec run(KairosCommand.t(), Context.t()) ::
          {:ok, result}
          | {:error, :forbidden}
          | {:error, :unauthorized}
          | {:error, {:validation_error, [KairosDomain.ValidationError.t()]}}
          | {:error, {:impossible_action, reason}}
          | {:error, {:argument_missing, missing_argument :: atom}}
          | {:error, {:resource_not_found, [name: atom, id: String.t()]}}
          | {:error, term}
  def run(command_data, command_context)
end


</code></pre>
<p>And here is the command definition (one of the most simple command we have) and the protocol implementation for the command handler.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule KairosCommand.DeleteOneShift do
  alias KairosCommand.DeleteOneShift

  @type uuid() :: String.t()

  @type t() :: %DeleteOneShift{id: uuid() | nil}

  defstruct [
    :id
  ]
end

defimpl KairosCommand, for: KairosCommand.DeleteOneShift do
  alias KairosCommand.Policy
  alias KairosCommand.Context
  alias KairosCommand.DeleteOneShift
  alias KairosCommand.Ports.ShiftAggregateRepository

  @spec run(DeleteOneShift.t(), Context.t()) ::
          {:ok, :deleted}
          | {:error, :forbidden}
          | {:error, :unauthorized}
          | {:error, {:argument_missing, :id}}
          | {:error, {:resource_not_found, [name: atom, id: String.t()]}}
          | {:error, term}
  def run(%DeleteOneShift{id: shift_id}, ctx) do
    data = %{shift_id: shift_id}

    data
    |&gt; Chain.new()
    |&gt; Chain.next(&amp;verify_is_authorized(&amp;1, ctx))
    |&gt; Chain.next(&amp;load_shift_aggregate/1)
    |&gt; Chain.next(&amp;ShiftAggregateRepository.delete(&amp;1.shift_aggregate))
    |&gt; Chain.run()
  end
  
  ... (private functions are missing for clarity)
end
</code></pre>
<p>The mutation resolver creates the command and the context (with user permissions mainly) and calls <code>KairosCommand.run(command, context)</code></p>
<p>Having one way to call commands and a standard response helped us mutualise and standardise the mutation resolver logic, and thus clarify the web/http part of the application. Quite a bit of plumbing in the end, but it happened over the course of 6 months, if we had to recreate that plumbing from scratch that would suck.<br>
(Error handling, especially the form errors were automatically filled from the domain logic, translated and filled in the react form. Quite satisfying. Quite a bit of work for something Rails or Phoenix give for free… But Ecto.Changesets caused quite a bit of headaches so happy it ended up only in the infra, and business rules validations are free from 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="179729" data-batch-url="/posts/batch_likers">
                        7
                      </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/hexagonal-architecture-in-elixir/32225/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-179729" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179729"
                     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 #16"></div>
  </section>
</div>
    <div class="postbit" id="179787" data-post-id="179787">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/apemb" rel="nofollow">@Apemb</a> this is really awesome. Thank you for sharing!</p>
<p>I’m curious where you put integrations with 3rd party API’s if you dealt with that.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179787" 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/hexagonal-architecture-in-elixir/32225/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-179787" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179787"
                     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 #17"></div>
  </section>
</div>
    <div class="postbit" id="179789" data-post-id="179789">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks, I appreciate it.</p>
<p>Concerning 3rd party API, we had none when I left, but I guess it would be the same more or less that the repositories. But in a different folder in the infra.</p>
<p>It should be in the infra, as it is a “driven” part of the “technical details” - as in not Core Domain nor Command/Query logic.<br>
The “driver” part being in the Web modules, which really should be named app. But Phoenix naming stuck.</p>
<p>For a GitHub API integration for example:</p>
<ul>
<li>A port like <code>Command.Ports.GithubService</code></li>
<li>The corresponding <code>Infra.GithubService</code> module implementing <code>Command.Ports.GithubService.Behaviour</code></li>
</ul>
<p>And the <code>Infra.GithubService</code> would be in the <code>/infra/services</code> folder.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179789" 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/hexagonal-architecture-in-elixir/32225/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-179789" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179789"
                     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 #18"></div>
  </section>
</div>
    <div class="postbit" id="179817" data-post-id="179817">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Hello.<br>
I’m working also with some kind of hexagonal architecture with Phoenix, NoSQL Databases, TCP endpoints, Crypto , where all those parts are adapter to some ports using behaviors.<br>
One article which helped me is coming from Aaron Renner <a href="https://aaronrenner.io/2019/09/18/application-layering-a-pattern-for-extensible-elixir-application-design.html" class="inline-onebox" rel="noopener nofollow ugc">Application Layering - A Pattern for Extensible Elixir Application Design | Aaron Renner’s Blog</a></p>
<p>Hopefully it may helps you</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179817" 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/hexagonal-architecture-in-elixir/32225/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-179817" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179817"
                     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 #19"></div>
  </section>
</div>
    <div class="postbit" id="180158" data-post-id="180158">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/apemb" rel="nofollow">@Apemb</a> I’ve tried hexagonal implementations before and working with the Ecto/database presented challenges. I felt like I had to either a) implement an interface on top of Ecto to query data in a way that doesn’t couple Ecto to the core or b) create functions for every piece of data I needed. We also never really figured out a good way to handle transactions. Curious if you have any experience/thoughts on this.</p>
<p>In more recent hexagonal-ish builds I opted to use Ecto directly in the core and deal with the testing/coupling consequences.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="180158" 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/hexagonal-architecture-in-elixir/32225/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-180158" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="180158"
                     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 #20"></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/32225/load_more?page=3">Load more posts (15 remaining)</a>
</div></template></turbo-stream>