<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Optivem Journal: Clean Architecture]]></title><description><![CDATA[Clean Architecture]]></description><link>https://journal.optivem.com/s/clean-architecture</link><image><url>https://substackcdn.com/image/fetch/$s_!0CjJ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9abead4c-3f54-46b1-96aa-7033849416df_200x200.png</url><title>Optivem Journal: Clean Architecture</title><link>https://journal.optivem.com/s/clean-architecture</link></image><generator>Substack</generator><lastBuildDate>Wed, 20 May 2026 21:03:13 GMT</lastBuildDate><atom:link href="https://journal.optivem.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Valentina Jemuović, Optivem]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[optivem@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[optivem@substack.com]]></itunes:email><itunes:name><![CDATA[Valentina Jemuović]]></itunes:name></itunes:owner><itunes:author><![CDATA[Valentina Jemuović]]></itunes:author><googleplay:owner><![CDATA[optivem@substack.com]]></googleplay:owner><googleplay:email><![CDATA[optivem@substack.com]]></googleplay:email><googleplay:author><![CDATA[Valentina Jemuović]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Clean Architecture: Do NOT Inject Loggers Everywhere]]></title><description><![CDATA[Code Example]]></description><link>https://journal.optivem.com/p/clean-architecture-do-not-inject-loggers-everywhere</link><guid isPermaLink="false">https://journal.optivem.com/p/clean-architecture-do-not-inject-loggers-everywhere</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 07 May 2026 06:01:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/79b41787-cb3a-4231-8d5c-25c0cd0285a2_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Logging injected directly into use cases, services and handlers is justified as:</p><ul><li><p>&#8220;we need debugging&#8221;</p></li><li><p>&#8220;we need traceability&#8221;</p></li><li><p>&#8220;we need observability&#8221;</p></li></ul><p>But&#8230;</p><h2>&#10060;Logger in every use case</h2><ul><li><p>every use case now knows about logging</p></li><li><p>business logic is mixed with runtime reporting</p></li><li><p>logs become part of how code is &#8220;explained&#8221;</p></li></ul><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;425f953c-ab2e-49cb-a093-2a839d031481&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">class CreateOrderUseCase {

    private final Logger logger;

    public CreateOrderUseCase(Logger logger) {
        this.logger = logger;
    }

    public OrderResult execute(CreateOrderCommand cmd) {

        logger.info("CreateOrder started");

        Order order = new Order(cmd.userId());

        logger.info("Order created", Map.of(
            "orderId", order.getId()
        ));

        return new OrderResult(order.getId());
    }
}</code></pre></div><h2>&#9888;&#65039;Structured logging doesn&#8217;t fix the real issue</h2><p>After a while, debugging becomes painful, so you switch to structured logging:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;37f17337-3ff0-4a17-bb19-7a01b9d983c0&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">logger.info("OrderCreated", Map.of(
    "userId", cmd.userId(),
    "orderId", order.getId()
));</code></pre></div><p>This is better:</p><ul><li><p>easier to search</p></li><li><p>consistent format</p></li><li><p>better for tools</p></li></ul><p>But the real problem doesn&#8217;t change.</p><p>You still have logging calls inside every use case.</p><p>You&#8217;ve just improved <em>how logs look</em>.</p><div><hr></div><p>&#128640; <strong>Register now</strong>: <a href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop">ATDD &#8211; Acceptance Testing Workshop</a><br>Get 100 EUR off with code <strong>DISCOUNT_100</strong></p><div><hr></div><h2>&#9989;Infrastructure Layer: Logging outside the use case</h2>
      <p>
          <a href="https://journal.optivem.com/p/clean-architecture-do-not-inject-loggers-everywhere">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[DDD + Clean Architecture: Where to Put Validation Logic]]></title><description><![CDATA[Should validation go in the API, application layer, or domain?]]></description><link>https://journal.optivem.com/p/ddd-clean-architecture-where-to-put-validation-logic</link><guid isPermaLink="false">https://journal.optivem.com/p/ddd-clean-architecture-where-to-put-validation-logic</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 16 Apr 2026 06:00:41 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b4f9ba38-8408-4028-99d3-03025707f349_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><blockquote><p>&#8220;Where should validation go?&#8221;</p></blockquote><p>You&#8217;ve seen:</p><ul><li><p>validation in controllers</p></li><li><p>validation in services</p></li><li><p>validation duplicated in multiple places</p></li></ul><p>And no one is really sure what&#8217;s &#8220;correct&#8221;.</p><p>So let&#8217;s make it concrete.</p><h2>1. Validation at the API layer (input checks)</h2><p>This is the first place data enters your system.</p><p>Here you check things like:</p><ul><li><p>required fields exist</p></li><li><p>types are correct</p></li><li><p>format is valid (email, date, UUID, etc.)</p></li></ul><p>Example:</p><ul><li><p><code>email</code> is missing &#8594; reject request</p></li><li><p><code>age</code> is a string &#8594; reject request</p></li><li><p><code>orderDate</code> is <code>"not-a-date"</code> &#8594; reject request</p></li></ul><p>The API layer&#8217;s job is to <strong>fail fast with clear errors</strong> for malformed input, so the application and domain layers can work with clean, well-typed data.</p><h2>2. Validation in the Application Layer (policies - use case rules)</h2><p>This is where most real mistakes happen.</p><p>This layer handles rules like:</p><ul><li><p>cannot create shipment if stock is insufficient</p></li><li><p>order cannot be placed if cart is empty</p></li><li><p>cannot refund payment if transaction is already settled beyond refund window</p></li><li><p>cannot process payment if currency is not supported for merchant</p></li><li><p>cannot cancel order after it has been shipped</p></li><li><p>cannot apply discount code if it is expired or not eligible</p></li></ul><p>These are not input checks anymore.</p><p>They are <strong>policies</strong>. A policy is a rule about whether an action is allowed right now, given the current state of the world.</p><p>Every one of these needs <strong>something outside the aggregate itself</strong> to evaluate &#8212; inventory, the clock, a merchant config, a discount catalog. In DDD terms, they cross the aggregate boundary.</p><p>That&#8217;s why they don&#8217;t belong in the domain object. An <code>Order</code> alone doesn&#8217;t know whether stock exists. The application layer orchestrates: it fetches what&#8217;s needed, evaluates the policy, and either proceeds or rejects.</p><p>Example flow:</p><ul><li><p>API sends a valid, well-formed request</p></li><li><p>application checks the relevant policies</p></li><li><p>if a policy fails &#8594; reject here, before touching the domain</p></li></ul><p>This is where you stop things that are technically valid, but not allowed in this situation.</p><div><hr></div><p>&#9889; <strong>Register now</strong>: <a href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop">ATDD &#8211; Acceptance Testing Workshop</a><br>Get 100 EUR off with code <strong>EARLYBIRD100</strong></p><div><hr></div><h2>3. Validation in the Domain Layer (invariants)</h2><p>This is the strictest level.</p><p>These are rules that must <em>never</em> be broken, no matter where the code is called from.</p><p>An invariant is a rule that must <strong>always</strong> hold for a given object, no matter who calls it, from where, at what time.</p><p>Examples:</p><ul><li><p>order must always have at least one line item</p></li><li><p>order total cannot be negative</p></li><li><p>payment cannot be &#8220;SUCCESSFUL&#8221; without a transaction reference</p></li><li><p>reserved quantity cannot exceed available stock</p></li><li><p>order status must follow valid transitions: <code>CREATED &#8594; PAID &#8594; SHIPPED &#8594; DELIVERED</code></p></li><li><p>order cannot have <code>SHIPPED</code> status without a tracking number</p></li></ul><p>If this is broken, your system is already inconsistent.</p><p>So this validation:</p><ul><li><p>is enforced when creating or modifying core objects</p></li><li><p>is tied directly to the business model itself</p></li></ul><p><strong>The key principle: the domain never trusts its callers.</strong></p><p>Even if the API already checked something, the domain re-checks any invariant. Why? Because the domain can be invoked from anywhere &#8212; a job, an event, a test, another bounded context. It cannot assume a well-behaved API sits in front of it.</p><h2>What you should NOT do</h2><p>This is where most real-world code goes wrong:</p>
      <p>
          <a href="https://journal.optivem.com/p/ddd-clean-architecture-where-to-put-validation-logic">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Clean Architecture: DTOs Are NOT Just Wrappers]]></title><description><![CDATA[Code Example]]></description><link>https://journal.optivem.com/p/clean-architecture-dtos-are-not-just-wrappers</link><guid isPermaLink="false">https://journal.optivem.com/p/clean-architecture-dtos-are-not-just-wrappers</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 03 Apr 2026 06:01:42 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/983a1287-3fd1-45a2-8765-55c7ffe65c66_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Developers like DTOs. And wrappers. And more wrappers.</p><p>Until your &#8220;simple&#8221; API layer turns into <strong>a tower of classes no one can read</strong>, tests become painful, and adding a new field feels like a chore.</p><p>DTOs and mappers are tools &#8212; not dogma. Clean Architecture doesn&#8217;t say &#8220;wrap everything 5 times.&#8221; It says: be intentional about what crosses boundaries.</p><h2>The Problem</h2><p>Many codebases follow a pattern like this:</p><pre><code><code>Domain objects
   &#8595;
Domain DTO
   &#8595;
Application DTO
   &#8595;
API DTO
   &#8595;
JSON</code></code></pre><p>That&#8217;s 3&#8211;4 layers of wrapping <strong>for the same data</strong>, plus mappers everywhere.</p><p>To be clear &#8212; sometimes multiple layers <em>are</em> justified. If you're serving both GraphQL and REST from the same domain, or maintaining a published API contract that must change independently from your domain, extra DTOs earn their keep. The problem isn't layers &#8212; it's layers that exist "just in case."</p><p><strong>The result:</strong></p><ul><li><p>Lots of boilerplate</p></li><li><p>Hard to understand what actually changes the domain</p></li><li><p>Fragile tests because every layer must be mocked</p></li><li><p>Accidental complexity: devs can&#8217;t tell which layer matters for business rules</p></li></ul><div><hr></div><p>&#128640; <strong>Register now</strong>: <a href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop">Acceptance Testing Workshop</a><br>Get 100 EUR off with code <strong>EARLYBIRD100</strong></p><div><hr></div><h1>&#128161;Code Example</h1><h2>Over-Wrapping Everything &#10060;</h2>
      <p>
          <a href="https://journal.optivem.com/p/clean-architecture-dtos-are-not-just-wrappers">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[DDD + Clean Architecture: Stop Putting Business Logic in the Application Layer]]></title><description><![CDATA[Your Clean Architecture isn&#8217;t clean if the domain is empty]]></description><link>https://journal.optivem.com/p/ddd-clean-architecture-dont-put-business-logic-in-application-layer</link><guid isPermaLink="false">https://journal.optivem.com/p/ddd-clean-architecture-dont-put-business-logic-in-application-layer</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 27 Feb 2026 07:01:53 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e4338280-54a0-4076-9ab2-e0613f86fdee_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>When people try Clean Architecture&#8230; they often end up with bloated application layers and empty domain layers.</p><pre><code><code>Application Layer:
   - Validate input
   - Load entities
   - Perform business logic
   - Call repositories
   - Call gateways
   - Publish events

Domain Layer:
   - Entity with getters and setters</code></code></pre><p>That&#8217;s an anemic domain, not a rich domain.</p><p>The <strong>domain doesn&#8217;t actually do anything</strong>. All the rules are in the application layer.</p><p>In Clean Architecture, we&#8217;re supposed to have a rich domain, which fits in with DDD.</p><h2>&#10060;Empty Domain</h2><p>If you&#8217;re used to CRUD, you probably see entities as simple data structures with public getters and setters.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;7171367a-d899-48c1-b8e3-74dc3dbae677&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">class Order {
    private int id;
    private List&lt;Item&gt; items;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public List&lt;Item&gt; getItems() {
        return items;
    }

    public void setItems(List&lt;Item&gt; items) {
        this.items = items;
    }
}</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;151262ff-fbf1-414f-94f2-6640ae6cbe20&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">class Item {
    private String sku;
    private int quantity;
    private boolean expired;

    public String getSku() {
        return sku;
    }

    public void setSku(String sku) {
        this.sku = sku;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public boolean isExpired() {
        return expired;
    }

    public void setExpired(boolean expired) {
        this.expired = expired;
    }
}</code></pre></div><p>Looks fine&#8230; but the business rules live elsewhere (application layer).</p><p>Your application service does this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;7d18ff13-2e49-4f84-9741-b01afe415658&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">public void addItemToOrder(Order order, Item item) {
    if (item.isExpired()) {
        throw new ExpiredException();
    }

    List&lt;Item&gt; items = order.getItems();
    if (items == null) {
        items = new ArrayList&lt;&gt;();
    }

    if (items.size() &gt; 10) {
        throw new LimitExceededException();
    }

    items.add(item);
    order.setItems(items);
    orderRepository.save(order);
}</code></pre></div><p>All the rules (expiration check, limit check) live in the <strong>application layer</strong>.</p><p>The entity is just a data container.</p><p>Basically, you&#8217;ve moved all the complexity into a layer that&#8217;s supposed to orchestrate, not decide.</p><h2>&#10060;Bloated Application Layer</h2>
      <p>
          <a href="https://journal.optivem.com/p/ddd-clean-architecture-dont-put-business-logic-in-application-layer">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Clean Architecture: Use Cases Are NOT Services]]></title><description><![CDATA[Code Example]]></description><link>https://journal.optivem.com/p/clean-architecture-use-cases-are-not-services</link><guid isPermaLink="false">https://journal.optivem.com/p/clean-architecture-use-cases-are-not-services</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 22 Jan 2026 07:02:09 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/449d2cd4-6960-4674-b109-3f4dfcea1290_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join me for <strong><a href="https://optivem.thinkific.com/products/live_events/2026-02-25-acceptance-testing-live-training">Acceptance Testing (Live Training)</a></strong> on Wed 25th Feb (17:00 - 19:00 CET) <em>(100% discount for Optivem Journal members)</em></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Most &#8220;Clean Architecture&#8221; codebases still revolve around <code>SomethingService</code>.</p><ul><li><p><code>UserService</code></p></li><li><p><code>OrderService</code></p></li><li><p><code>PaymentService</code></p></li></ul><p>And inside those services?</p><ul><li><p>business rules</p></li><li><p>orchestration</p></li><li><p>validation</p></li><li><p>database calls</p></li><li><p>sometimes HTTP logic too</p></li></ul><p>Everything&#8230; everywhere&#8230; with multiple use cases all in one file.</p><h2>Why &#8220;Services&#8221; Are a Dead End</h2><p>Services usually start like this:</p><blockquote><p>&#8220;We&#8217;ll put business logic in services so controllers stay thin.&#8221;</p></blockquote><p>And for a while, it works.</p><p>But over time:</p><ul><li><p>Services grow without a clear responsibility</p></li><li><p>Methods multiply</p></li><li><p>Everything depends on everything</p></li><li><p>Tests become slow, fragile, and heavily mocked</p></li></ul><p>You don&#8217;t know <em>what</em> the system actually does.</p><p>Only <em>what data it has</em>.</p><h2>What a Use Case Actually Is</h2><p>A <strong>use case</strong> represents <strong>one business functionality</strong>.</p><p>Not a resource.<br>Not an entity.<br>Not a technical operation.</p><p>Examples:</p><ul><li><p><code>RegisterUser</code></p></li><li><p><code>PlaceOrder</code></p></li><li><p><code>ApproveLoan</code></p></li><li><p><code>CancelSubscription</code></p></li><li><p><code>GenerateInvoice</code></p></li></ul><p>Each use case answers one question:</p><blockquote><p><em>What does the business want to achieve in this scenario?</em></p></blockquote><h2>Services vs Use Cases</h2><p>Services (group data):</p><ul><li><p>Organized around entities</p></li><li><p>Grow horizontally</p></li></ul><p>Use Cases (express behavior)</p><ul><li><p>Organized around behavior</p></li><li><p>Stay focused</p></li></ul><p>If you have a <code>UserService</code>, ask yourself:</p><blockquote><p>What is the <em>use case</em> here?</p></blockquote><p>Because <strong>&#8220;user&#8221; is not a behavior</strong>.</p><h1>&#128161;Code Example</h1>
      <p>
          <a href="https://journal.optivem.com/p/clean-architecture-use-cases-are-not-services">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Clean Architecture: The Dependency Rule Isn’t Optional]]></title><description><![CDATA[Why your domain logic keeps breaking (and how to fix it)]]></description><link>https://journal.optivem.com/p/clean-architecture-on-the-backend-dependency-rule</link><guid isPermaLink="false">https://journal.optivem.com/p/clean-architecture-on-the-backend-dependency-rule</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 18 Dec 2025 07:02:20 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/73456eaa-ae23-46e3-9cce-d63d3101d7df_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128073; Reserve Your Spot for the <strong><a href="https://atdd.optivem.com/">2026 ATDD Accelerator</a></strong></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>I was trying to add a small feature to our order system.</p><p>Simple, right? Just a validation: &#8220;Orders over $10,000 require manager approval.&#8221;</p><p>Two hours later, I was <strong>deep in a mess</strong>:</p><ul><li><p>Domain entities glued to JPA annotations.</p></li><li><p>Use cases directly calling repositories.</p></li><li><p>Controllers scattered across three packages.</p></li></ul><p>I thought: <strong>&#8220;How is anyone supposed to change this without breaking everything?&#8221;</strong></p><p>Dependencies were everywhere, pointing the wrong way. Every small change became a massive headache.</p><p><strong>The Daily Pain</strong></p><ul><li><p>Changing a business rule? Better hope no one touched your domain logic with a framework dependency.</p></li><li><p>Writing a test? Say hello to spinning up DBs, mocking everything, or manually handling try/catch just to check if something works.</p></li><li><p>Refactoring? One wrong move and the system falls apart.</p></li></ul><p>I realized: <strong>if your core logic depends on infrastructure or frameworks, everything else becomes fragile</strong>.</p><h2>What Does &#8220;Depend&#8221; Mean?</h2><p>You&#8217;ve got a dependency anytime you:</p><ul><li><p>Import a class</p></li><li><p>Call a method</p></li><li><p>Reference a concrete implementation</p></li><li><p>Require a framework to compile</p></li></ul><p>Red flags I see all the time:</p><ul><li><p>A use case importing Spring annotations &#10060;</p></li><li><p>Domain entities referencing ORM &#10060;</p></li><li><p>REST controllers sneaking into inner layers &#10060;</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4jWB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4jWB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 424w, https://substackcdn.com/image/fetch/$s_!4jWB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 848w, https://substackcdn.com/image/fetch/$s_!4jWB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!4jWB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4jWB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png" width="1025" height="1067" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1067,&quot;width&quot;:1025,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:113005,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/177321063?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4jWB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 424w, https://substackcdn.com/image/fetch/$s_!4jWB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 848w, https://substackcdn.com/image/fetch/$s_!4jWB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!4jWB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6cbf5c1-8611-46f2-92c6-a459c15fbf39_1025x1067.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Use Case Depends on Infrastructure &#10060;</h3>
      <p>
          <a href="https://journal.optivem.com/p/clean-architecture-on-the-backend-dependency-rule">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Clean Architecture on the Backend: Data Flow]]></title><description><![CDATA[How does data flow through the system?]]></description><link>https://journal.optivem.com/p/clean-architecture-on-the-backend</link><guid isPermaLink="false">https://journal.optivem.com/p/clean-architecture-on-the-backend</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 31 Oct 2025 07:01:09 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/21fa073d-f09e-4873-a9b3-c98f46817c93_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128640; Join the <strong><a href="https://atdd.optivem.com/">ATDD Accelerator waitlist</a></strong></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Data flows from external sources (like the UI) to the core logic and back out:</p><p><strong>1. Frontend: Send request to Backend</strong></p><p>The user enters the SKU and quantity, then clicks &#8220;Place Order.&#8221; The frontend sends this data to the backend as a REST API request.</p><p><strong>2. Backend: Presentation Layer &#8594; Use Case</strong></p><p>The REST API receives the JSON request, converts it into a Request DTO, and delegates the work to the Use Case. The controller stays minimal and doesn&#8217;t contain any business logic.</p><p><strong>3. Backend: Use Case &#8594; Domain Layer</strong></p><p>The Use Case performs basic validation of the Request DTO, and calls repositories to retrieve entities. The Use Case may create or save entities via repositories and can call methods on those entities to execute business logic.</p><p><strong>4. Backend: Domain Layer &#8594; Use Case</strong></p><p>The Domain Layer returns entities and computed results &#8212; such as the product details, total order price, and order status &#8212; back to the Use Case.</p><p><strong>5. Backend: Use Case &#8594; Presentation Layer</strong></p><p>The Use Case prepares a Response DTO with the processed results from the Domain Layer and sends it to the REST API.</p><p><strong>6. Backend: Presentation Layer &#8594; Client</strong></p><p>The REST API formats the response and returns it to the client (Frontend) for display.</p><p><strong>7. Frontend: Present to user</strong></p><p>The frontend receives the backend response and displays the order confirmation, showing details like the product, quantity, total price, and order status.</p><h2>Data Flow</h2><p>Data flow defines how information moves between the layers of your system &#8212; from the user interface, through the business logic, and back out again.</p><ul><li><p>Each layer has a <strong>single responsibility</strong>.</p></li><li><p>Dependencies always point <strong>inward</strong>, toward the core logic.</p></li><li><p>You can change external details (UI, database, frameworks) without breaking your domain rules.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ioo3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ioo3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 424w, https://substackcdn.com/image/fetch/$s_!Ioo3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 848w, https://substackcdn.com/image/fetch/$s_!Ioo3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!Ioo3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ioo3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png" width="1025" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1025,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:90677,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/177269159?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ioo3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 424w, https://substackcdn.com/image/fetch/$s_!Ioo3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 848w, https://substackcdn.com/image/fetch/$s_!Ioo3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!Ioo3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e70013f-a78c-492b-9412-afa9548ac4b7_1025x1086.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Real-life Example: Ordering System</h2><p>Applying Clean Architecture on the backend (for an e-commerce system).</p><h2>1. Frontend: Send request to Backend</h2><p>On the Frontend, user inputs the SKU and quantity, and clicks button to &#8220;Place Order&#8220;. Then Frontend calls the Backend REST API. </p><p>Let&#8217;s see what are the Clean Architecture Layers are on the Backend.</p><h2>2. Backend: Presentation Layer &#8594; Use Case</h2><p>On the Backend, the Presentation Layer is generally the REST API (or it might be SOAP Service, or Message Consumer, etc.).</p><p>The REST API has received the request as JSON. We have frameworks that automatically convert the JSON into a Request DTO. In the example below, the Request DTO is the PlaceOrderRequest.</p><p>We keep the REST API controller minimal. We just pass the Request DTO to the use case. In this case, we pass the PlaceOrderRequest to the PlaceOrderUseCase. </p><p><em>The reason is because the REST API controller should not have knowledge of application/business logic, it just delegates.</em></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;3a5a38bb-4f4f-4a54-80c8-d9cb5cae59d4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @PostMapping
    public ResponseEntity&lt;PlaceOrderResponse&gt; placeOrder(@RequestBody PlaceOrderRequest request) {
        var response = placeOrderUseCase.execute(request);
        ...
    }
}</code></pre></div>
      <p>
          <a href="https://journal.optivem.com/p/clean-architecture-on-the-backend">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>